ฉันมีคุณสมบัติรูปหลายเหลี่ยมและต้องการสร้างคะแนนภายใน ฉันต้องการสิ่งนี้สำหรับงานการจัดหมวดหมู่เดียว
การสร้างคะแนนแบบสุ่มจนกว่าจะมีใครอยู่ภายในรูปหลายเหลี่ยมจะไม่ทำงานเพราะมันไม่สามารถคาดเดาได้จริง ๆ ว่าเวลาที่ใช้
ฉันมีคุณสมบัติรูปหลายเหลี่ยมและต้องการสร้างคะแนนภายใน ฉันต้องการสิ่งนี้สำหรับงานการจัดหมวดหมู่เดียว
การสร้างคะแนนแบบสุ่มจนกว่าจะมีใครอยู่ภายในรูปหลายเหลี่ยมจะไม่ทำงานเพราะมันไม่สามารถคาดเดาได้จริง ๆ ว่าเวลาที่ใช้
คำตอบ:
โดยเริ่มจากการย่อยสลายของรูปหลายเหลี่ยมเป็นรูปสามเหลี่ยมแล้วสร้างจุดภายในเหล่านั้น (สำหรับการกระจายแบบสม่ำเสมอให้น้ำหนักแต่ละสามเหลี่ยมตามพื้นที่)
เมื่อคุณใส่แท็ก QGIS ในคำถามนี้: เครื่องมือคะแนนสุ่มสามารถใช้กับเลเยอร์ขอบเขต
หากคุณกำลังมองหาโค้ดซอร์สโค้ดปลั๊กอินที่เกี่ยวข้องควรเป็นประโยชน์
คุณสามารถกำหนดขอบเขตของรูปหลายเหลี่ยมจากนั้น จำกัด การสร้างตัวเลขสุ่มสำหรับค่า 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;
}
มีห้องสมุดดีๆอยู่ที่นั่นซึ่งเป็นการยกระดับอย่างหนักสำหรับคุณ
ตัวอย่างการใช้ [shapely] [1] ใน python
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/…
หาก R เป็นตัวเลือกให้ดู?spsample
ในsp
แพ็คเกจ รูปหลายเหลี่ยมสามารถอ่านได้จากรูปแบบที่รองรับ GDAL ใด ๆ ที่สร้างไว้ในแพ็คเกจ rgdal จากนั้นspsample
ทำงานโดยตรงบนวัตถุที่นำเข้าด้วยตัวเลือกการสุ่มตัวอย่างที่หลากหลาย
ฉันต้องการนำเสนอโซลูชันที่ต้องใช้การวิเคราะห์ GIS น้อยมาก โดยเฉพาะอย่างยิ่งมันไม่จำเป็นต้องมีการวิเคราะห์รูปหลายเหลี่ยมใด ๆ
อัลกอริทึมต่อไปนี้ที่ให้ใน pseudocode อ้างถึงการดำเนินการอย่างง่าย ๆ นอกเหนือจากความสามารถในการจัดการรายการพื้นฐาน (สร้าง, ค้นหาความยาว, ผนวก, เรียงลำดับ, แยกรายการย่อยและเชื่อมต่อ) และการสร้างลอยสุ่มในช่วงเวลา [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
เมื่อรูปหลายเหลี่ยมของคุณไม่นูนมากนักคุณอาจต้องพิจารณาแปลงเป็นฮัลล์นูนก่อน อย่างน้อยควร จำกัด จำนวนจุดที่อยู่นอกรูปหลายเหลี่ยมของคุณในระดับสูง
งานเป็นเรื่องง่ายมากที่จะแก้ปัญหาในระบบสารสนเทศภูมิศาสตร์ GRASS (หนึ่งคำสั่ง) โดยใช้v.random
ด้านล่างตัวอย่างเกี่ยวกับวิธีเพิ่มจุดสุ่ม 3 จุดในรูปหลายเหลี่ยมที่เลือก (ที่นี่พื้นที่รหัสไปรษณีย์ของเมือง Raleigh, NC) จากหน้าคู่มือ โดยการปรับเปลี่ยนคำสั่ง SQL โดยที่ "" สามารถเลือกรูปหลายเหลี่ยม
ลิงก์คำตอบ
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;
ส่งผลให้เกิด ================================================= =====================
ฟังก์ชั่นที่สองขึ้นอยู่กับอัลกอริทึมของNicklas Avé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;
ส่งผลให้เกิด ================================================= =========================