ฉันมีคุณสมบัติรูปหลายเหลี่ยมและต้องการสร้างคะแนนภายใน ฉันต้องการสิ่งนี้สำหรับงานการจัดหมวดหมู่เดียว
การสร้างคะแนนแบบสุ่มจนกว่าจะมีใครอยู่ภายในรูปหลายเหลี่ยมจะไม่ทำงานเพราะมันไม่สามารถคาดเดาได้จริง ๆ ว่าเวลาที่ใช้
ฉันมีคุณสมบัติรูปหลายเหลี่ยมและต้องการสร้างคะแนนภายใน ฉันต้องการสิ่งนี้สำหรับงานการจัดหมวดหมู่เดียว
การสร้างคะแนนแบบสุ่มจนกว่าจะมีใครอยู่ภายในรูปหลายเหลี่ยมจะไม่ทำงานเพราะมันไม่สามารถคาดเดาได้จริง ๆ ว่าเวลาที่ใช้
คำตอบ:
โดยเริ่มจากการย่อยสลายของรูปหลายเหลี่ยมเป็นรูปสามเหลี่ยมแล้วสร้างจุดภายในเหล่านั้น (สำหรับการกระจายแบบสม่ำเสมอให้น้ำหนักแต่ละสามเหลี่ยมตามพื้นที่)
เมื่อคุณใส่แท็ก 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.iorepresentative_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;
ส่งผลให้เกิด ================================================= =========================