สร้างจุดที่อยู่ภายในรูปหลายเหลี่ยม


30

ฉันมีคุณสมบัติรูปหลายเหลี่ยมและต้องการสร้างคะแนนภายใน ฉันต้องการสิ่งนี้สำหรับงานการจัดหมวดหมู่เดียว

การสร้างคะแนนแบบสุ่มจนกว่าจะมีใครอยู่ภายในรูปหลายเหลี่ยมจะไม่ทำงานเพราะมันไม่สามารถคาดเดาได้จริง ๆ ว่าเวลาที่ใช้


3
ในทางตรงกันข้ามเวลาที่คาดการณ์ได้ มันเป็นสัดส่วนกับอัตราส่วนของพื้นที่ขอบเขตของรูปหลายเหลี่ยมหารด้วยพื้นที่ของรูปหลายเหลี่ยมคูณด้วยเวลาที่จำเป็นในการสร้างและทดสอบจุดเดียว เวลาแตกต่างกันเล็กน้อย แต่ความแปรผันเป็นสัดส่วนกับสแควร์รูทของจำนวนคะแนน สำหรับตัวเลขจำนวนมากสิ่งนี้จะไม่สำคัญ แบ่งรูปหลายเหลี่ยมคดเคี้ยวเป็นชิ้นเล็ก ๆ ถ้าจำเป็นเพื่อให้อัตราส่วนพื้นที่นี้ลดลงเป็นค่าต่ำ รูปหลายเหลี่ยมเศษส่วนเท่านั้นที่จะทำให้คุณมีปัญหา แต่ฉันสงสัยว่าคุณมีพวกเขา!
whuber



@Pablo: พบที่ดี อย่างไรก็ตามคำถามเหล่านี้เป็นคำถามเฉพาะสำหรับซอฟต์แวร์และทั้งสองข้อกังวลเกี่ยวกับการวางอาร์เรย์ตามปกติภายในรูปหลายเหลี่ยมไม่ใช่จุดสุ่ม
whuber

เห็นด้วยกับความแตกต่าง whuber คือจุดสุ่มเทียบกับการสร้างจุดปกติภายในรูปหลายเหลี่ยม
Mapperz

คำตอบ:


20

โดยเริ่มจากการย่อยสลายของรูปหลายเหลี่ยมเป็นรูปสามเหลี่ยมแล้วสร้างจุดภายในเหล่านั้น (สำหรับการกระจายแบบสม่ำเสมอให้น้ำหนักแต่ละสามเหลี่ยมตามพื้นที่)


2
+1 ง่ายและมีประสิทธิภาพ มันมีค่าที่ชี้ให้เห็นว่าสามารถสร้างจุดสุ่มอย่างสม่ำเสมอในรูปสามเหลี่ยมโดยไม่มีการปฏิเสธเลยเนื่องจากมีการแมป (คำนวณง่าย) รักษาพื้นที่ระหว่างสามเหลี่ยมใด ๆ กับสามเหลี่ยมมุมฉากหน้าจั่วซึ่งเป็นครึ่งสี่เหลี่ยมพูดครึ่งที่ พิกัด y เกินพิกัด x สร้างพิกัดสุ่มสองค่าและเรียงลำดับเพื่อให้ได้จุดสุ่มในสามเหลี่ยมหน้าจั่วจากนั้นทำแผนที่ที่กลับไปที่สามเหลี่ยมเดิม
whuber

+1 ฉันชอบการสนทนาของพิกัด trilinear ที่อ้างอิงโดยบทความที่คุณอ้างถึง ฉันคิดว่านี่น่าจะคลาดเคลื่อนไปกับทรงกลมซึ่งพื้นผิวถูกแทนด้วยเทสเซเลชันของสามเหลี่ยม บนระนาบที่ฉายไว้มันจะไม่เป็นการกระจายแบบสุ่มอย่างแท้จริงใช่ไหม
Kirk Kuykendall

@whuber - +1 กลับมาหาคุณ อีกวิธีหนึ่ง (ในลิงค์ แต่มันโบกมือให้มัน) คือการสะท้อนให้เห็นถึงจุดที่ถูกปฏิเสธจากรูปสี่เหลี่ยมขนมเปียกปูนที่มีรูปตัวอย่างสม่ำเสมอข้ามขอบที่แบ่งปันและกลับเข้าไปในรูปสามเหลี่ยม
Dan S.

@ เคิร์ก - ลิงก์การอ้างอิงเป็นการสัมผัสที่มีประโยชน์ซึ่งจะแสดงวิธีการสุ่มตัวอย่างที่ไม่ถูกต้อง (ไม่เหมือนกัน) รวมถึงพิกัด trilinear ก่อนวิธี "ขวา" ดูเหมือนว่าจะมีวิธีโดยตรงในการรับชุดตัวอย่างที่มีพิกัด w / trilinear ฉันจะเข้าใกล้การสุ่มตัวอย่างทั่วทั้งทรงกลมโดยการแปลงเวกเตอร์หน่วยสุ่มในแบบ 3 มิติให้เทียบเท่ากับ lat / lon ของพวกเขา แต่นั่นเป็นเพียงฉัน (ไม่แน่ใจเกี่ยวกับการสุ่มตัวอย่างที่ จำกัด กับรูปสามเหลี่ยมทรงกลม / รูปหลายเหลี่ยม) (เช่นไม่แน่ใจเกี่ยวกับการสุ่มตัวอย่างที่เหมือนกันอย่างแท้จริงในตัวอย่างเช่น wgs84: การเลือกมุมจะทำให้อคติไปทางขั้วเลย)
Dan S.

1
@Dan สำหรับการสุ่มตัวอย่างทรงกลมอย่างสม่ำเสมอให้ใช้การฉายภาพพื้นที่เท่ากับทรงกระบอก (พิกัดเป็นลองจิจูดและโคไซน์ของละติจูด) หากคุณต้องการตัวอย่างโดยไม่ต้องใช้การฉายภาพมีเคล็ดลับที่สวยงาม: สร้างตัวแปรมาตรฐานอิสระสามตัว (x, y, z) และฉายภาพไปยังจุด (R x / n, R y / n, R * z / n ) โดยที่ n ^ 2 = x ^ 2 + y ^ 2 + z ^ 2 และ R คือรัศมีของโลก แปลงเป็น (lat, lon) หากจำเป็นต้องใช้ (ใช้ latitude latitudes เมื่อทำงานกับ spheroid) มันใช้งานได้เพราะการกระจายตัวแบบธรรมดาขนาดเล็กนี้มีความสมมาตรเป็นทรงกลม สำหรับการสุ่มตัวอย่างรูปสามเหลี่ยมให้ใช้การฉายภาพ
whuber

14

เมื่อคุณใส่แท็ก QGIS ในคำถามนี้: เครื่องมือคะแนนสุ่มสามารถใช้กับเลเยอร์ขอบเขต

ป้อนคำอธิบายรูปภาพที่นี่

หากคุณกำลังมองหาโค้ดซอร์สโค้ดปลั๊กอินที่เกี่ยวข้องควรเป็นประโยชน์


1
แม้ 5 ปีต่อมาก็ยังมีประโยชน์จริงๆ!
เด็กติดค้าง

10

คุณสามารถกำหนดขอบเขตของรูปหลายเหลี่ยมจากนั้น จำกัด การสร้างตัวเลขสุ่มสำหรับค่า 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;
}

10

มีห้องสมุดดีๆอยู่ที่นั่นซึ่งเป็นการยกระดับอย่างหนักสำหรับคุณ

ตัวอย่างการใช้ [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

2
ไม่ควรมาจากการนำเข้า shapely.geometry ... ?
PyMapr

1
คุณสามารถใช้representative_pointวิธีนี้: shapely.readthedocs.io/en/latest/…
dain

6

หาก R เป็นตัวเลือกให้ดู?spsampleในspแพ็คเกจ รูปหลายเหลี่ยมสามารถอ่านได้จากรูปแบบที่รองรับ GDAL ใด ๆ ที่สร้างไว้ในแพ็คเกจ rgdal จากนั้นspsampleทำงานโดยตรงบนวัตถุที่นำเข้าด้วยตัวเลือกการสุ่มตัวอย่างที่หลากหลาย


+1 - เนื่องจาก R เป็นโอเพ่นซอร์สหากใครต้องการทำซ้ำคุณสามารถเข้าไปในแหล่งข้อมูลเพื่อดูว่ามันเสร็จสิ้นแล้วได้เสมอ สำหรับรูปแบบจุดหนึ่งอาจสนใจเครื่องมือจำลองในแพ็คเกจ spatstat
Andy W

5

ฉันต้องการนำเสนอโซลูชันที่ต้องใช้การวิเคราะห์ 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
}

2

หากรูปหลายเหลี่ยมของคุณนูนออกมาและคุณรู้จุดยอดทั้งหมดคุณอาจต้องการพิจารณาน้ำหนักจุดนูนแบบ "สุ่ม" ของจุดยอดเพื่อสุ่มตัวอย่างจุดใหม่ที่รับประกันว่าจะอยู่ภายในตัวนูน (รูปหลายเหลี่ยมในกรณีนี้)

ตัวอย่างเช่นสมมติว่าคุณมีรูปหลายเหลี่ยมด้าน 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

  • เลือกตัวเลข N-1 อย่างสม่ำเสมอในช่วง (โดยไม่ต้องเปลี่ยนใหม่) เรียงลำดับและทำให้ช่วง N เป็นมาตรฐานระหว่างกันเพื่อให้ได้น้ำหนัก
  • นอกจากนี้คุณยังสามารถสุ่มตัวอย่างจากการแจกแจง Dirichlet ซึ่งมักใช้เป็นคอนจูเกตก่อนหน้าการแจกแจงพหุนามซึ่งคล้ายกับตุ้มน้ำหนักนูนในกรณีของคุณ

เมื่อรูปหลายเหลี่ยมของคุณไม่นูนมากนักคุณอาจต้องพิจารณาแปลงเป็นฮัลล์นูนก่อน อย่างน้อยควร จำกัด จำนวนจุดที่อยู่นอกรูปหลายเหลี่ยมของคุณในระดับสูง


2

งานเป็นเรื่องง่ายมากที่จะแก้ปัญหาในระบบสารสนเทศภูมิศาสตร์ GRASS (หนึ่งคำสั่ง) โดยใช้v.random

ด้านล่างตัวอย่างเกี่ยวกับวิธีเพิ่มจุดสุ่ม 3 จุดในรูปหลายเหลี่ยมที่เลือก (ที่นี่พื้นที่รหัสไปรษณีย์ของเมือง Raleigh, NC) จากหน้าคู่มือ โดยการปรับเปลี่ยนคำสั่ง SQL โดยที่ "" สามารถเลือกรูปหลายเหลี่ยม

การสร้างคะแนนสุ่มในรูปหลายเหลี่ยมที่เลือก


1
เตือนความจำว่ารหัสไปรษณีย์เป็นเส้นไม่ใช่รูปหลายเหลี่ยม
Richard

คุณสามารถทำอย่างละเอียด? สำหรับฉันที่นี่ยังหมายถึงพื้นที่: en.wikipedia.org/wiki/ZIP_Code#Primary_state_prefixes
markusN

แน่นอน: รหัสไปรษณีย์อ้างอิงที่ทำการไปรษณีย์โดยเฉพาะและเส้นทางการส่งจดหมาย เป็นผลให้รหัสไปรษณีย์เป็นเส้นไม่ใช่รูปหลายเหลี่ยม พวกเขาสามารถทับซ้อนกันมีหลุมและไม่จำเป็นต้องครอบคลุมทั้งสหรัฐอเมริกาหรือรัฐที่กำหนด ใช้พวกเขาเพื่อแบ่งพื้นที่เป็นอันตรายด้วยเหตุผลนี้ หน่วยสำรวจสำมะโนประชากร (เช่นกลุ่มบล็อก) เป็นตัวเลือกที่ดีกว่า ดูเพิ่มเติม: นี้และนี้
Richard

1
ขอบคุณ! มันอาจขึ้นอยู่กับประเทศด้วยดูตัวอย่างen.wikipedia.org/wiki/Postal_codes_in_Germany - อย่างไรก็ตามรหัสไปรษณีย์ไม่ใช่หัวข้อหลักของฉันแค่ต้องการแสดงและตอบคำถามเดิม "สร้างจุดที่อยู่ภายในรูปหลายเหลี่ยม" แทนที่จะเป็น หารือเกี่ยวกับคำจำกัดความของรหัสไปรษณีย์ซึ่งเป็น OT ที่นี่ :-)
markusN

1
ระบุไว้เมื่อทั้งสองนับ ฉันควรทำบล็อกเล็กน้อยเพื่อให้ฉันสามารถพูดได้ทั้งหมดในครั้งต่อไป :-)
ริชาร์ด

1

ลิงก์คำตอบ

https://gis.stackexchange.com/a/307204/103524

สามอัลกอริทึมที่ใช้วิธีการที่แตกต่างกัน

Git Repo Link

  1. นี่เป็นวิธีที่ง่ายและดีที่สุดโดยใช้ระยะทางจริงของพิกัดจากทิศทาง x และ y อัลกอริทึมภายในใช้ WGS 1984 (4326) และเปลี่ยนผลลัพธ์เป็นแทรก SRID

ฟังก์ชั่น ================================================= ==================

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;

ส่งผลให้เกิด ================================================= ===================== ป้อนคำอธิบายรูปภาพที่นี่

  1. ฟังก์ชั่นที่สองขึ้นอยู่กับอัลกอริทึมของNicklas Avén ได้พยายามจัดการ SRID ใด ๆ

    ฉันใช้การเปลี่ยนแปลงต่อไปนี้ในอัลกอริทึม

    1. แยกตัวแปรสำหรับทิศทาง x และ y สำหรับขนาดพิกเซล
    2. ตัวแปรใหม่สำหรับการคำนวณระยะทางในรูปทรงกลมหรือทรงรี
    3. ใส่ SRID ใด ๆ , ฟังก์ชั่นแปลง Geom เป็นสภาพแวดล้อมการทำงานของ Spheroid หรือ Ellipsoid Datum จากนั้นใช้ระยะทางกับแต่ละด้านรับผลลัพธ์และแปลงเป็นอินพุต 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;

ส่งผลให้เกิด ================================================= ==================ป้อนคำอธิบายรูปภาพที่นี่

  1. ฟังก์ชั่นขึ้นอยู่กับชุดเครื่องกำเนิดไฟฟ้า

ฟังก์ชั่น ================================================= =================

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; ส่งผลให้เกิด ================================================= =========================

ป้อนคำอธิบายรูปภาพที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.