2Dの4点で定義された4辺の凸ポリゴンがあり、その中にランダムな点を生成できるようにしたいと考えています。
それが本当に問題を単純化するなら、私は多角形を平行四辺形に制限することができますが、より一般的な答えが好まれます。
ポリゴン内にランダムなポイントが生成されるまでは、実際にかかる時間を予測できないため、機能しません。
A.入力を平行四辺形に制限できる場合、これは非常に簡単です。
u
とv
を呼び出します。平行四辺形がABB点で定義され、AB、BC、CD、DAが辺である場合は、次の点として考えます。
p = A + (u * AB) + (v * AD)
ここで、AB
はAからBへのベクトルであり、AD
はAからDへのベクトルです。
B.できない場合でも、重心座標を使用できます。クワッドの場合、重心座標は(a,b,c,d)
となる4つの座標a+b+c+d=1
に対応します。次に、クワッド内の任意のポイントP
は、次のような4倍数で記述できます。
P = a A + b B + c C + d D
あなたのケースでは、4つの乱数を引き、それらを合計して1になるように正規化することができます。その場合、ポイントの分布は均一ではないことに注意してください。
C.他の場所で提案されているように、四角形を2つの三角形に分解し、半平行四辺形メソッドを使用することもできます(つまり、平行四辺形として、ただし条件u+v=1
)または三角形の重心座標を追加します。ただし、均一な分布が必要な場合は、三角形の1つに点がある確率は、三角形の面積を四角形の面積で割った値と等しくなければなりません。
OPによる質問は少しあいまいなので、私が答える質問は次のとおりです:任意の四辺形内の均一分布からポイントを生成する方法、これは実際にはの一般化です任意の(凸)ポリゴン内の均一分布からポイントを生成する方法。答えは、三角形の均一分布からサンプルを生成する場合に基づいています(非常に良い説明がある http://mathworld.wolfram.com/TrianglePointPicking.html を参照してください)。
これを達成するために:
ポリゴンを三角形化します(つまり、ポリゴンをカバーする重複しない三角形領域のコレクションを生成します)。四辺形の場合は、隣接していない2つの頂点にまたがってエッジを作成します。その他のポリゴンについては、開始点について http://en.wikipedia.org/wiki/Polygon_triangulation を参照してください。または、 http://www.cgal.org/ を参照してください。ライブラリが必要です。
三角形の1つをランダムに選択するには、各三角形にインデックスを割り当てます(つまり、0、1、2、...)。四辺形の場合、それらは0,1になります。三角形ごとに、次のように等しい重みを割り当てます。
次に、重みが与えられたインデックスの有限分布からランダムなインデックスiを生成します。四辺形の場合、これはベルヌーイ分布です。
V0、v1、v2を三角形の頂点(それらの点の位置で表されるため、v0 =(x0、y0)など)とします。次に、間隔[0,1 ]。次に、x = a0(v1-v0)+ a1(v2-v0)によってランダムポイントxを計算します。
確率0.5では、xは三角形の外側にありますが、そうである場合、(v1、v2)(破線)の中点を中心にpiを回転させた後、画像と三角形の和集合で構成される平行四辺形の内側にあります。画像)。その場合、新しい点x '= v0 + R(pi)(x-v3)を生成できます。ここでR(pi)はpi(180度)の回転です。)点x 'は三角形の内側になります。
さらに、四辺形がすでに平行四辺形であった場合、ランダムに三角形を選択する必要はありません。決定論的にいずれか1つを選択してから、点xを選択することができます。
均一な分布が必要な場合:ポリゴンから2つの三角形を形成します。面積比に従ってポイントを生成する三角形を選択します。
三角形A、B、Cのコーナー、サイドベクトルAB、BC、ACを呼び出し、[0,1]に2つの乱数uおよびvを生成します。p= u * AB + v * ACとします。
A + pが三角形の内側にある場合は、A + pを返します
A + pが三角形の外にある場合、A + AB + AC-pを返します
(これは基本的に、前処理と、ポイントを三角形に折り返す最後のステップを除いて、平行四辺形以外の形状を処理できるため、PierreBdRの式です)。
ポリゴンは2つの三角形なので、それらの1つをランダムに選択してから、三角形のランダムな点を見つけてください。
おそらく最良の解決策ではありませんが、うまくいきます。
「一般的」とは、一般にすべての非平行四辺形の4辺ポリゴンまたはすべての可能なポリゴンを意味しますか?
四辺を結ぶランダムな線を引いてみませんか?これがあれば:
.BBBB.
A C
A C
.DDDD.
次に、単位正方形上にランダムな点を生成し、X軸上の距離のパーセンテージで線BおよびD上の点をマークします。 Y軸の値を使用して、ラインAとCでも同じことを行います。
次に、ラインA上のポイントをラインCに、ラインBをラインDに接続し、交点をランダムポイントとして使用します。
丸め誤差は特定の点を補助するため、均一ではありませんが、浮動小数点値で作業している場合は、近いはずです。
すでにポリゴンで作業しているので、実装もかなり簡単です。これらの単純なタスクを実行するコードが既にあるはずです。
ここに簡単な疑似コードがあります:
void GetRandomPoint(Polygon p, ref float x, ref float y) {
float xrand = random();
float yrand = random();
float h0 = p.Vertices[0] + xrand * p.Vertices[1];
float h1 = p.Vertices[2] + yrand * p.Vertices[3];
float v0 = p.Vertices[0] + xrand * p.Vertices[2];
float v1 = p.Vertices[1] + yrand * p.Vertices[3];
GetLineIntersection(h0, h1, v0, v1, x, y);
}
これは、一般的な凸型四辺形で機能します。
有限要素法からいくつかの概念を借りることができます。具体的には、四辺形(4辺)要素( ここのセクション16.5を参照してください =)。基本的に、uv空間の正方形(この場合、u、v\in [-1、1]の場合)を点p_i(i = 1,2,3,4の場合)で構成される四辺形にマッピングする双一次パラメーター化があります。 )。提供されているリファレンスでは、パラメーターは\ etaおよび\ xiと呼ばれていることに注意してください。
基本的なレシピ:
唯一の問題は、u-v空間内の均一に分散されたポイントが、四角形内に均一に分散されたポイントを生成しないことです(ユークリッドの意味で)。それが重要な場合は、クワッドのバウンディングボックス内で2Dで直接作業し、ポイントインクワッド(問題をトリスで2つのポイントに分割することによる)テストを記述して、外側のランダムなポイントをカリングできます。
「 naïve 」というやや少ないアプローチは、 ポリゴン塗りつぶしアルゴリズム を使用し、塗りつぶし線からランダムにポイントを選択することです。
// public-domain code by Darel Rex Finley, 2007
int nodes, nodeX[MAX_POLY_CORNERS], pixelX, pixelY, i, j, swap ;
// Loop through the rows of the image.
for (pixelY=IMAGE_TOP; pixelY<IMAGE_BOT; pixelY++) {
// Build a list of nodes.
nodes=0; j=polyCorners-1;
for (i=0; i<polyCorners; i++) {
if (polyY[i]<(double) pixelY && polyY[j]>=(double) pixelY
|| polyY[j]<(double) pixelY && polyY[i]>=(double) pixelY) {
nodeX[nodes++]=(int) (polyX[i]+(pixelY-polyY[i])/(polyY[j]-polyY[i])
*(polyX[j]-polyX[i])); }
j=i; }
// Sort the nodes, via a simple “Bubble” sort.
i=0;
while (i<nodes-1) {
if (nodeX[i]>nodeX[i+1]) {
swap=nodeX[i]; nodeX[i]=nodeX[i+1]; nodeX[i+1]=swap; if (i) i--; }
else {
i++; }}
// Fill the pixels between node pairs.
// Code modified by SoloBold 27 Oct 2008
// The flagPixel method below will flag a pixel as a possible choice.
for (i=0; i<nodes; i+=2) {
if (nodeX[i ]>=IMAGE_RIGHT) break;
if (nodeX[i+1]> IMAGE_LEFT ) {
if (nodeX[i ]< IMAGE_LEFT ) nodeX[i ]=IMAGE_LEFT ;
if (nodeX[i+1]> IMAGE_RIGHT) nodeX[i+1]=IMAGE_RIGHT;
for (j=nodeX[i]; j<nodeX[i+1]; j++) flagPixel(j,pixelY); }}}
// TODO pick a flagged pixel randomly and fill it, then remove it from the list.
// Repeat until no flagged pixels remain.
MATLAB関数 cprnd は、一般的な凸型ポリトープ上の均一分布からポイントを生成します。あなたの質問には、四辺形を三角形に分解することに基づくより専門的なアルゴリズムがより効率的です。
ポイントは均一に分布する必要がありますか、それとも分布に問題はありませんか?
多角形は凹形にすることができますか、それとも凸形にすることが保証されますか?
上記の両方に対する答えが「いいえ」の場合、頂点のいずれか2つを選択し、それらの間の線分上のランダムな点を選択します。これは、頂点を結ぶ線分に限定されます(つまり、非常に不均一です)。 3番目の頂点を選択してから、その頂点と最初の点の間の点を選択することで、少し不規則になります。ただし、不均一ですが、少なくともポリゴン内の任意の点が可能です。
2つの点の間の線上のランダムな点を選択するのは簡単です。A+ p(B-A)で、AとBは点で、pは0.0と1.0の間の乱数です。
ポイントにどのような分布を持たせたいですか?気にしない場合は、上記の方法で問題なく動作します。均一な分布が必要な場合は、次の手順が機能します。ポリゴンを2つの三角形aとbに分割します。 A(a)およびA(b)をそれらの面積とします。0とA(a)の間の均一分布から点pをサンプリングします+ A(b)。p <A(a)の場合は、三角形aを選択します。それ以外の場合は、三角形bを選択します。選択した三角形の頂点vを選択し、cとdを三角形の辺に対応するベクトルとします。単位平均の指数分布からの2つの数値xとy次に、点(xc + yd)/(x + y)は、ポリゴン上の均一分布からのサンプルです。
PostGISの場合、これは私が使用しているものです(無限ループの可能性がある場合は、ワードが必要になる場合があります)。アルゴリズムをプログラミング言語にエクスポートできます。
CREATE or replace FUNCTION random_point(geometry)
RETURNS geometry
AS $$
DECLARE
env geometry;
corner1 geometry;
corner2 geometry;
minx real;
miny real;
maxx real;
maxy real;
x real;
y real;
ret geometry;
begin
select ST_Envelope($1) into env;
select ST_PointN(ST_ExteriorRing(env),1) into corner1;
select ST_PointN(ST_ExteriorRing(env),3) into corner2;
select st_x(corner1) into minx;
select st_x(corner2) into maxx;
select st_y(corner1) into miny;
select st_y(corner2) into maxy;
loop
select minx+random()*(maxx-minx) into x;
select miny+random()*(maxy-miny) into y;
select ST_SetSRID(st_point(x,y), st_srid($1)) into ret;
if ST_Contains($1,ret) then
return ret ;
end if;
end loop;
end;
$$
LANGUAGE plpgsql
volatile
RETURNS NULL ON NULL INPUT;