円(画像)内のランダムポイント(ピクセル)を計算する


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 );
}

そして、それは円の円周上のすべての点を見つけるのにうまく機能しますが、円のどこからでもすべての点が必要です。これが意味をなさない場合はお知らせください。明確にするために最善を尽くします。


アップデートを確認してください。
デヴィッドゴーベイア

3
加重分布を不注意に作成することはよくあるエラーであるという意味での良い質問です。
ティム・ホルト

回答:


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);
}

ただし、その結果、ポイントは円の中心により集中します。

ここに画像の説明を入力してください

均一な分布を得るには、アルゴリズムに次の変更を加えます。

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

次の結果が得られます。

ここに画像の説明を入力してください

詳細については、MathWorld-Disk Point Pickingのリンクを確認してください。

そして最後に、両方のバージョンのアルゴリズムを比較する簡単なJsFiddleのデモがあります。


1
素晴らしい答え。ひとつだけ追加してください:乱数ジェネレーターをシードすることを忘れないでください:)
kevintodisco

おっと、あなたはそれに会いました-私が私の投稿したとき、この投稿を見ませんでした。wolframサイトは、この種の素晴らしいリソースです。
ティム・ホルト

1
@TimHoltは、すべての時間に発生:)
デビッド・Gouveiaの

これは、円の中心が0,0にあると仮定していますか?
jjxtra

@PsychoDad円の中心は(_originX、_originY)
David Gouveia

5

ランダムなrとthetaを使用しないでください!これにより、中心により多くのポイントがある加重分布が作成されます。このページはそれをよく示しています...

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:おっと選択した回答の複製
ティム・ホルト

ランダムなrとthetaを使用して重み付け分布を作成すると言っているので、あなたが主張する非重み付け分布を作成するコードは範囲[0,1]内のrを生成するため、混乱します。乱数を平方根するつもりでしたか?
PeteUK

はい、半径の平方根を実行すると(0-1である限り)、中央に予期しないポイントの集中が減少します。私が投稿したWolframリンクを参照してください。それはそれを説明し、数学よりも上手く説明しています。
ティム・ホルト

私の悪い。xとyを計算するときにsqrt(r)を実行するのがわかります。
PeteUK 16

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;

さて、数秒以内にまったく同じ答えを出しました。それで?:)
デヴィッド・グーヴェイア

@DavidGouveia私たちは両方とも正しいことを支持しています。みんなが勝つ!:D
ジョン・パーディ

どちらも非常に高く評価されています(そしてリンクも!)。男私は自分自身を見ていないのはばかですが、私には-1です:(あなたの両方に再び感謝します!
-DMills

これによりランダムなポイントが生成されますが、それらはディスク上に均一に分散されませんよね?むしろ、中心に向かって重み付けされます。確認するだけで、何かが足りません。
PeteUK

1
@PeteUK:そのとおりです。距離に重みを付ける必要があります。更新させてください。
ジョンパーディ

3

パフォーマンスが問題となる場合、別の解決策の1つは、円の幅/高さでボックス内のランダムな位置を生成し、円の領域にないポイントをすべて破棄することです。

この方法の利点は、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.