我具有多边形特征,并希望能够在其中生成点。我需要一项分类任务。
生成随机点直到多边形中的某个点不起作用,因为这确实花费了很多时间。
我具有多边形特征,并希望能够在其中生成点。我需要一项分类任务。
生成随机点直到多边形中的某个点不起作用,因为这确实花费了很多时间。
Answers:
首先将多边形分解为三角形,然后在这些内生成点。(要获得均匀的分布,请按其面积对每个三角形加权。)
您可以确定多边形的范围,然后在这些范围内限制X和Y值的随机数生成。
基本过程:1)确定多边形顶点的maxx,maxy,minx,miny,2)使用这些值作为边界生成随机点3)测试与多边形相交的每个点,4)当有足够的点满足交点时停止生成测试
这是相交测试的算法(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()
获取对象内的一个点(如戴恩所说):
返回保证在几何对象内的廉价计算点。
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)
保守地估计了需要多少点的上限,并考虑了机会的可变性。失败的可能性仅为每百万个过程调用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(一个命令)中解决该任务非常容易。
下面的示例说明了如何在手册页中将3个随机点添加到选定的多边形(此处为北卡罗来纳州罗利市的邮政编码区域)中。通过修改SQL“ where”语句,可以选择多边形。
答案链接
https://gis.stackexchange.com/a/307204/103524
三种算法使用不同的方法。
功能================================================== ==================
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算法。尝试处理任何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;
结果================================================= ========================