원 (이미지) 내 임의의 포인트 (픽셀)을 계산


19

특정 위치와 특정 직경의 원이 포함 된 이미지가 있습니다. 내가해야 할 일은 원 내 임의의 점을 계산 한 다음 해당 점과 관련된 픽셀을 조작하는 것입니다. 다음 코드가 이미 있습니다.

private Point CalculatePoint()
{
    var angle = _random.NextDouble() * ( Math.PI * 2 );
    var x = _originX + ( _radius * Math.Cos( angle ) );
    var y = _originY + ( _radius * Math.Sin( angle ) );
    return new Point( ( int )x, ( int )y );
}

그리고 그것은 원의 원주에서 모든 점을 찾는 데 잘 작동하지만 원의 어느 곳에서나 모든 점이 필요합니다. 이것이 이해가되지 않으면 알려 주시면 최선을 다해 설명하겠습니다.


업데이트를 확인하십시오.
David Gouveia

3
가중 분포를 실수로 생성하는 것은 일반적인 오류라는 점에서 좋은 질문입니다.
Tim Holt

답변:


35

간단한 해결책을 원한다면 반경을 무작위로 지정하십시오.

private Point CalculatePoint()
{
    var angle = _random.NextDouble() * Math.PI * 2;
    var radius = _random.NextDouble() * _radius;
    var x = _originX + radius * Math.Cos(angle);
    var y = _originY + radius * Math.Sin(angle);
    return new Point((int)x,(int)y);
}

그러나 점이 원의 중심을 향하여 더 집중됩니다.

enter image description here

균일 한 분포를 얻으려면 알고리즘을 다음과 같이 변경하십시오.

var radius = Math.Sqrt(_random.NextDouble()) * _radius;

결과는 다음과 같습니다.

enter image description here

자세한 내용은 다음 링크를 확인하십시오. MathWorld-디스크 포인트 피킹 .

마지막으로 두 버전의 알고리즘을 비교 하는 간단한 JsFiddle 데모가 있습니다.


1
훌륭한 답변입니다. 한 가지 추가 할 사항 : 난수 생성기를 시드하는 것을 잊지 마십시오 :)
kevintodisco

당신이 이길 만났어요-내가 게시 할 때이 게시물을 보지 못했습니다. 볼프람 사이트는 이런 종류의 일을위한 훌륭한 자료입니다.
Tim Holt

1
@TimHolt는 항상 일어납니다 :)
David Gouveia

원 중심이 0,0이라고 가정합니까?
jjxtra

(_originX, _originY) 될 것이다 원의 중심을 @PsychoDad
데이비드 Gouveia의

5

무작위 r과 세타 만 사용하지 마십시오! 그러면 중심에 더 많은 점이있는 가중 분포가 만들어집니다. 이 페이지는 그것을 잘 보여줍니다 ...

http://mathworld.wolfram.com/DiskPointPicking.html

비가 중 분포를 만드는 방법은 다음과 같습니다.

var r = rand(0,1)
var theta = rand(0,360)

var x = sqrt(r) * cos(theta)
var y = sqrt(r) * sin(theta)

선택된 답변의 중복 항목 : P
Tim Holt

가중 분포를 생성 할 때 임의의 r과 theta를 사용하지 말라고 말했기 때문에 혼란스러워합니다. 그런 다음 가중치를 적용하지 않는 분포를 생성한다고 주장하는 코드는 범위 [0,1] 내에 r을 생성합니다. 난수를 제곱근으로 하시겠습니까?
PeteUK

네, 반지름의 제곱근 (0-1 일 경우)은 중간에 예상치 못한 점의 농도를 줄입니다. 내가 게시 한 Wolfram 링크를 참조하십시오.
Tim Holt

내 잘못이야. x와 y를 계산할 때 sqrt (r)를 수행하는 것을 볼 수 있습니다.
PeteUK

4

당신은 반쯤 있습니다. 임의의 각도를 생성하는 것 외에도 반경보다 작거나 같은 임의의 거리를 가중하여 균일 한 분포를 얻습니다.

private Point CalculatePoint()
{
    var angle = _random.NextDouble() * Math.PI * 2;
    var distance = Math.Sqrt(_random.NextDouble()) * _radius;
    var x = _originX + (distance * Math.Cos(angle));
    var y = _originY + (distance * Math.Sin(angle));
    return new Point((int)x, (int)y);
}

이제 polar로 생각하고 있습니다.

제곱근을 피하기 위해 거리에 가중치를 부여 할 수도 있습니다.

var distance = _random.NextDouble() + _random.NextDouble();
distance = (distance <= 1 ? distance : 2 - distance) * _radius;

자, 우리는 몇 초 만에 똑같은 대답을했습니다. 이제 뭐? :)
David Gouveia

@DavidGouveia 우리 둘 다 옳은 것에 대한 공감대를 얻습니다. 모두가 이긴다! : D
Jon Purdy

두 답변 모두 대단히 감사합니다 (그리고 링크도!). 나는 나 자신을 보지 못해서 바보입니다. -1 : 나에게 다시 한번 감사합니다!
DMills

이것은 임의의 포인트를 생성하지만 디스크에 균일하게 분산되지 않습니다. 오히려 그들은 중심쪽으로 가중 될 것이다. 내가 빠진 것이 없는지 확인하십시오.
PeteUK

1
@PeteUK : 당신 말이 맞아요. 거리는 가중되어야합니다. 업데이트하겠습니다.
Jon Purdy 2016

3

성능이 문제인 경우 대안의 한 가지 해결책은 원의 너비 / 높이로 상자에 임의의 위치를 ​​생성 한 다음 원의 영역에 있지 않은 점을 버리는 것입니다.

이 방법의 장점은 cos / sin / sqrt 기능을 수행하지 않는다는 것입니다. 플랫폼에 따라 속도가 크게 절약 될 수 있습니다.

var x = _random.NextDouble();
var y = _random.NextDouble();
if (x*x + y*y < 1.0f)
{
    // we have a usable point inside a circle
    x = x * diameter - _radius + _OriginX;
    y = y * diameter - _radius + _OriginY;
    // use the point(x,y)
}

나는 그것을 시도하고 그것이 속도가 빠른지 알아볼 것입니다. 성능 문제가 있는지 확실하지 않지만 어쨌든 시도해 보겠습니다. 감사합니다!
DMills

0

나열된 의견 중 하나에 접근하여 기능을 확장하여 도넛 모양의 포인트 생성 시스템을 만들었습니다.

            private Vector2 CalculatePosition()
            {
                double angle = _rnd.NextDouble() * Math.PI * 2;
                double radius = InnerCircleRadius + (Math.Sqrt(_rnd.NextDouble()) * (OuterCircleRadius - InnerCircleRadius));
                double x = (_context.ScreenLayout.Width * 0.5f) + (radius * Math.Cos(angle));
                double y = (_context.ScreenLayout.Height * 0.5f) + (radius * Math.Sin(angle));
                return new Vector2((int)x, (int)y);
            }

이전에 언급 한 것과 비슷한 접근 방법이지만 다른 결과를 제공했습니다. 원의 안쪽 부분은 점없이 비워집니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.