ポリゴンフィーチャがあり、その中にポイントを生成できるようにします。これは1つの分類タスクに必要です。
ポリゴン内にランダムポイントを生成するのは、時間がかかるので予測できないため、機能しません。
ポリゴンフィーチャがあり、その中にポイントを生成できるようにします。これは1つの分類タスクに必要です。
ポリゴン内にランダムポイントを生成するのは、時間がかかるので予測できないため、機能しません。
回答:
ポリゴンを三角形に分解してから、それらの内部にポイントを生成します。(均一な分布の場合、各三角形に面積で重み付けします。)
ポリゴンの範囲を決定し、その範囲内でXおよびY値の乱数生成を制限できます。
基本プロセス:1)多角形の頂点のmaxx、maxy、minx、minyを決定します。2)これらの値を境界として使用してランダムポイントを生成しますテスト
交差テストのアルゴリズム(C#)は次のとおりです。
bool PointIsInGeometry(PointCollection points, MapPoint point)
{
int i;
int j = points.Count - 1;
bool output = false;
for (i = 0; i < points.Count; i++)
{
if (points[i].X < point.X && points[j].X >= point.X || points[j].X < point.X && points[i].X >= point.X)
{
if (points[i].Y + (point.X - points[i].X) / (points[j].X - points[i].X) * (points[j].Y - points[i].Y) < point.Y)
{
output = !output;
}
}
j = i;
}
return output;
}
ほとんどの面倒な作業を行う優れたライブラリがいくつかあります。
Pythonで[shapely] [1]を使用した例。
import random
from shapely.geometry import Polygon, Point
def get_random_point_in_polygon(poly):
minx, miny, maxx, maxy = poly.bounds
while True:
p = Point(random.uniform(minx, maxx), random.uniform(miny, maxy))
if poly.contains(p):
return p
p = Polygon([(0, 0), (0, 2), (1, 1), (2, 2), (2, 0), (1, 1), (0, 0)])
point_in_poly = get_random_point_in_polygon(mypoly)
または.representative_point()
、オブジェクト内のポイントを取得するために使用します(dainによると)。
ジオメトリックオブジェクト内にあることが保証されている、安価に計算されたポイントを返します。
poly.representative_point().wkt
'POINT (-1.5000000000000000 0.0000000000000000)'
[1]: https://shapely.readthedocs.io
representative_point
:メソッドshapely.readthedocs.io/en/latest/...を
GIS分析の点でほとんど必要としないソリューションを提供したいと思います。特に、ポリゴンを三角形分割する必要はありません。
擬似コードで指定された次のアルゴリズムは、基本的なリスト処理機能(作成、長さの検索、追加、並べ替え、サブリストの抽出、および連結)と間隔[0、1)でのランダムフロートの生成に加えて、いくつかの簡単な操作を指します:
Area: Return the area of a polygon (0 for an empty polygon).
BoundingBox: Return the bounding box (extent) of a polygon.
Width: Return the width of a rectangle.
Height: Return the height of a rectangle.
Left: Split a rectangle into two halves and return the left half.
Right: ... returning the right half.
Top: ... returning the top half.
Bottom: ... returning the bottom half.
Clip: Clip a polygon to a rectangle.
RandomPoint: Return a random point in a rectangle.
Search: Search a sorted list for a target value. Return the index
of the last element less than the target.
In: Test whether a point is inside a polygon.
これらはすべて、ほぼすべてのGISまたはグラフィックスプログラミング環境で利用できます(そうでない場合はコーディングが簡単です)。 Clip
縮退したポリゴン(つまり、面積がゼロのポリゴン)を返してはなりません。
手順SimpleRandomSample
は、多角形内にランダムに分布するポイントのリストを効率的に取得します。これは、のラッパーでありSRS
、各ピースが十分にコンパクトになり、効率的にサンプリングされるまで、ポリゴンを小さなピースに分割します。これを行うには、事前に計算された乱数のリストを使用して、各ピースに割り当てるポイント数を決定します。
パラメーターを変更することで、SRSを「調整」できますt
。これは、許容できる最大の境界ボックス:ポリゴン面積比です。小さく(ただし1より大きい)すると、ほとんどのポリゴンが多数の断片に分割されます。大きくすると、いくつかのポリゴンで多くの試行ポイントが拒否される可能性があります(連続、スライバー、または穴がいっぱい)。これにより、元のポリゴンをサンプリングする最大時間が予測可能になります。
Procedure SimpleRandomSample(P:Polygon, N:Integer) {
U = Sorted list of N independent uniform values between 0 and 1
Return SRS(P, BoundingBox(P), U)
}
次のプロシージャは、必要に応じて自分自身を再帰的に呼び出します。不思議な表現t*N + 5*Sqrt(t*N)
は、必要なポイント数の上限を控えめに見積もっており、偶然の変動を考慮しています。これが失敗する可能性は、100万プロシージャコールあたり0.3だけです。必要に応じて、この可能性を減らすために5から6または7まで増やします。
Procedure SRS(P:Polygon, B:Rectangle, U:List) {
N = Length(U)
If (N == 0) {Return empty list}
aP = Area(P)
If (aP <= 0) {
Error("Cannot sample degenerate polygons.")
Return empty list
}
t = 2
If (aP*t < Area(B)) {
# Cut P into pieces
If (Width(B) > Height(B)) {
B1 = Left(B); B2 = Right(B)
} Else {
B1 = Bottom(B); B2 = Top(B)
}
P1 = Clip(P, B1); P2 = Clip(P, B2)
K = Search(U, Area(P1) / aP)
V = Concatenate( SRS(P1, B1, U[1::K]), SRS(P2, B2, U[K+1::N]) )
} Else {
# Sample P
V = empty list
maxIter = t*N + 5*Sqrt(t*N)
While(Length(V) < N and maxIter > 0) {
Decrement maxIter
Q = RandomPoint(B)
If (Q In P) {Append Q to V}
}
If (Length(V) < N) {
Error("Too many iterations.")
}
}
Return V
}
多角形が凸であり、すべての頂点を知っている場合、頂点の「ランダムな」凸重み付けを行って、凸包(この場合は多角形)内にあることが保証される新しいポイントをサンプリングすることを検討できます。
たとえば、頂点を持つN面の凸ポリゴンがあるとします
V_i, i={1,..,N}
次に、ランダムにN個の凸重みを生成します
w_1,w_2,..,w_N such that ∑ w_i = 1; w_i>=0
ランダムにサンプリングされたポイントは、次のように与えられます
Y= ∑ w_i*V_i
N個の凸の重みをサンプリングする別の方法があります。
多角形がそれほど非凸状でない場合は、まず凸包に変換することを検討してください。これにより、少なくともポリゴンの外側にあるポイントの数を大幅に制限する必要があります。
タスクはv.randomを使用してGRASS GIS(1つのコマンド)で非常に簡単に解決できます。
マニュアルページから選択したポリゴン(ここではノースカロライナ州ローリー市の郵便番号エリア)に3つのランダムポイントを追加する方法の例を以下に示します。SQLの「where」ステートメントを変更することにより、ポリゴンを選択できます。
回答リンク
https://gis.stackexchange.com/a/307204/103524
異なるアプローチを使用する3つのアルゴリズム。
機能================================================ ==================
CREATE OR REPLACE FUNCTION public.I_Grid_Point_Distance(geom public.geometry, x_side decimal, y_side decimal)
RETURNS public.geometry AS $BODY$
DECLARE
x_min decimal;
x_max decimal;
y_max decimal;
x decimal;
y decimal;
returnGeom public.geometry[];
i integer := -1;
srid integer := 4326;
input_srid integer;
BEGIN
CASE st_srid(geom) WHEN 0 THEN
geom := ST_SetSRID(geom, srid);
----RAISE NOTICE 'No SRID Found.';
ELSE
----RAISE NOTICE 'SRID Found.';
END CASE;
input_srid:=st_srid(geom);
geom := st_transform(geom, srid);
x_min := ST_XMin(geom);
x_max := ST_XMax(geom);
y_max := ST_YMax(geom);
y := ST_YMin(geom);
x := x_min;
i := i + 1;
returnGeom[i] := st_setsrid(ST_MakePoint(x, y), srid);
<<yloop>>
LOOP
IF (y > y_max) THEN
EXIT;
END IF;
CASE i WHEN 0 THEN
y := ST_Y(returnGeom[0]);
ELSE
y := ST_Y(ST_Project(st_setsrid(ST_MakePoint(x, y), srid), y_side, radians(0))::geometry);
END CASE;
x := x_min;
<<xloop>>
LOOP
IF (x > x_max) THEN
EXIT;
END IF;
i := i + 1;
returnGeom[i] := st_setsrid(ST_MakePoint(x, y), srid);
x := ST_X(ST_Project(st_setsrid(ST_MakePoint(x, y), srid), x_side, radians(90))::geometry);
END LOOP xloop;
END LOOP yloop;
RETURN
ST_CollectionExtract(st_transform(ST_Intersection(st_collect(returnGeom), geom), input_srid), 1);
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE;
単純なクエリで関数を使用します。ジオメトリは有効で、ポリゴン、マルチポリゴン、またはエンベロープである必要があります
SELECT I_Grid_Point_Distance(geom, 50, 61) from polygons limit 1;
結果================================================ ======================
NicklasAvénアルゴリズムに基づく2番目の関数。SRIDを処理しようとしました。
アルゴリズムに次の変更を適用しました。
機能================================================ ==================
CREATE OR REPLACE FUNCTION I_Grid_Point(geom geometry, x_side decimal, y_side decimal, spheroid boolean default false)
RETURNS SETOF geometry AS $BODY$
DECLARE
x_max decimal;
y_max decimal;
x_min decimal;
y_min decimal;
srid integer := 4326;
input_srid integer;
BEGIN
CASE st_srid(geom) WHEN 0 THEN
geom := ST_SetSRID(geom, srid);
RAISE NOTICE 'SRID Not Found.';
ELSE
RAISE NOTICE 'SRID Found.';
END CASE;
CASE spheroid WHEN false THEN
RAISE NOTICE 'Spheroid False';
srid := 4326;
x_side := x_side / 100000;
y_side := y_side / 100000;
else
srid := 900913;
RAISE NOTICE 'Spheroid True';
END CASE;
input_srid:=st_srid(geom);
geom := st_transform(geom, srid);
x_max := ST_XMax(geom);
y_max := ST_YMax(geom);
x_min := ST_XMin(geom);
y_min := ST_YMin(geom);
RETURN QUERY
WITH res as (SELECT ST_SetSRID(ST_MakePoint(x, y), srid) point FROM
generate_series(x_min, x_max, x_side) as x,
generate_series(y_min, y_max, y_side) as y
WHERE st_intersects(geom, ST_SetSRID(ST_MakePoint(x, y), srid))
) select ST_TRANSFORM(ST_COLLECT(point), input_srid) from res;
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE STRICT;
単純なクエリで使用します。
SELECT I_Grid_Point(geom, 22, 15, false) from polygons;
結果================================================ ==================
機能================================================ =================
CREATE OR REPLACE FUNCTION I_Grid_Point_Series(geom geometry, x_side decimal, y_side decimal, spheroid boolean default false)
RETURNS SETOF geometry AS $BODY$
DECLARE
x_max decimal;
y_max decimal;
x_min decimal;
y_min decimal;
srid integer := 4326;
input_srid integer;
x_series DECIMAL;
y_series DECIMAL;
BEGIN
CASE st_srid(geom) WHEN 0 THEN
geom := ST_SetSRID(geom, srid);
RAISE NOTICE 'SRID Not Found.';
ELSE
RAISE NOTICE 'SRID Found.';
END CASE;
CASE spheroid WHEN false THEN
RAISE NOTICE 'Spheroid False';
else
srid := 900913;
RAISE NOTICE 'Spheroid True';
END CASE;
input_srid:=st_srid(geom);
geom := st_transform(geom, srid);
x_max := ST_XMax(geom);
y_max := ST_YMax(geom);
x_min := ST_XMin(geom);
y_min := ST_YMin(geom);
x_series := CEIL ( @( x_max - x_min ) / x_side);
y_series := CEIL ( @( y_max - y_min ) / y_side );
RETURN QUERY
SELECT st_collect(st_setsrid(ST_MakePoint(x * x_side + x_min, y*y_side + y_min), srid)) FROM
generate_series(0, x_series) as x,
generate_series(0, y_series) as y
WHERE st_intersects(st_setsrid(ST_MakePoint(x*x_side + x_min, y*y_side + y_min), srid), geom);
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE STRICT;
単純なクエリで使用します。
SELECT I_Grid_Point_Series(geom, 22, 15, false) from polygons;
結果================================================ =========================