ระบุรูปหลายเหลี่ยมที่“ ยาวและแคบ” ด้วย PostGIS


10

ฉันมีชุดรูปหลายเหลี่ยมแสดงพื้นที่ขนาดใหญ่พูดย่านที่อยู่อาศัยของเมือง ฉันต้องการระบุพื้นที่ทับซ้อนขนาดใหญ่ระหว่างพื้นที่เหล่านั้น

แต่มีปัญหา: บางครั้งรูปหลายเหลี่ยมเหล่านี้จะทับซ้อนกันตามเส้นรอบวงของพวกเขา (เพราะวาดด้วยความแม่นยำน้อย) สิ่งนี้จะสร้างการทับซ้อนที่ยาวและแคบซึ่งฉันไม่สนใจ

แต่ในบางครั้งจะมีการทับซ้อนกันของรูปหลายเหลี่ยมที่แข็งแกร่งซึ่งหมายถึงพื้นที่ขนาดใหญ่ที่รูปหลายเหลี่ยมของพื้นที่ใกล้เคียงซ้อนทับกัน ฉันต้องการเลือกเหล่านี้เท่านั้น

ดูภาพด้านล่างของแค่เหลื่อมกัน ลองนึกภาพฉันต้องการเลือกรูปหลายเหลี่ยมสีฟ้าที่มุมซ้ายล่าง

คาบเกี่ยวกัน

ฉันสามารถดูพื้นที่ได้ แต่บางครั้งพื้นที่แคบ ๆ ก็ยาวพอที่จะมีพื้นที่ใหญ่พอ ๆ กับรูปหลายเหลี่ยมสีฟ้า ฉันพยายามทำอัตราส่วนพื้นที่ / เส้นรอบวง แต่นั่นก็ให้ผลที่หลากหลายเช่นกัน

ฉันได้ลองใช้ST_MinimumClearanceแต่บางครั้งพื้นที่ขนาดใหญ่จะมีส่วนที่แคบติดอยู่หรือสองจุดยอดที่ใกล้เคียง

ความคิดของวิธีการอื่น ๆ ?


ในที่สุดสิ่งที่ดีที่สุดสำหรับฉันคือการใช้บัฟเฟอร์เชิงลบตามที่ @Cyril และ @FGreg แนะนำด้านล่าง

ฉันใช้สิ่งที่ชอบ:

ST_Area(ST_Buffer(geom, -10)) as neg_buffer_area

ในกรณีของฉันหน่วยเป็นเมตรดังนั้นบัฟเฟอร์ลบ 10 ม.

สำหรับรูปหลายเหลี่ยมแคบ ๆ พื้นที่นี้กลับเป็นศูนย์ (เช่นเรขาคณิตจะว่างเปล่า) จากนั้นฉันใช้คอลัมน์นี้เพื่อกรองรูปหลายเหลี่ยมแคบ ๆ


4
แน่นอนอัตราส่วนพื้นที่ / ปริมณฑลสามารถใช้สำหรับการนี้
วินซ์

เป็นการยากที่จะบอกว่ารูปหลายเหลี่ยมที่แตกต่างกันมาจากภาพ แต่ทำอะไรแบบนี้gis.stackexchange.com/a/265233/64838อาจทำงานได้อย่างไร คำนวณกล่องขอบหมุนต่ำสุดแล้วทิ้งกล่องที่มีความกว้างหรือความสูงเล็กน้อย
FGreg

คุณสามารถลองใช้บัฟเฟอร์เชิงลบตามที่อธิบายไว้ที่นี่: ฉันจะระบุรูปหลายเหลี่ยมบาง ๆ ในไฟล์รูปร่างของฉันได้อย่างไร
FGreg

คำตอบ:


5

ฉันจะพยายามสร้างบัฟเฟอร์เชิงลบถ้ามันกินรูปหลายเหลี่ยมบางแล้วก็ดีถ้ามันไม่กินรูปหลายเหลี่ยมมันก็เป็นของฉัน ... :-)

เรียกใช้สคริปต์นี้โดยมีการตั้งค่า 2/3 ของความกว้างของรูปหลายเหลี่ยมเชิงเส้น ...

create table name_table as
SELECT ST_Buffer(
(ST_Dump(
(ST_Union(
ST_Buffer(
(geom),-0.0001))))).geom,
0.0001)) as geom from source_table

ระบบปฏิบัติการ: -) ...


ในที่สุดคำแนะนำของคุณคือสิ่งที่ดีที่สุดสำหรับฉัน ฉันสิ้นสุดการใช้บางอย่างเช่นST_Area(ST_Buffer(geom, -10))-10 ความยาว -10 เมตรในกรณีของฉัน หากมีสิ่งใดคืนค่า 0 จากนิพจน์นั้นฉันก็สามารถกรองได้
bplmp

9

แทนที่จะใช้พื้นที่ / รอบปริมณฑลจะดีกว่าถ้าใช้พื้นที่หารด้วยสี่เหลี่ยมของเส้นรอบวง (หรือผกผัน)

สิ่งนี้เรียกว่า "ดัชนีรูปทรง" สี่เหลี่ยมจัตุรัสของเส้นรอบวงหารด้วยพื้นที่มีค่าต่ำสุดคือ 4 * Pi () (ในกรณีของดิสก์ซึ่งเป็นรูปทรงเรขาคณิต 2D ขนาดกะทัดรัดที่สุด) ดังนั้นจึงสามารถทำให้ปกติเป็น 4 * Pi () ได้อย่างง่ายดาย การตีความ (ค่าปกติใกล้กับ 1 หมายความว่าคุณมีวัตถุขนาดเล็กมากและกำลังสองมีค่าประมาณ 1.27)

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


ขอบคุณ! แต่ฉันไม่แน่ใจว่า ST_Snap จะช่วยได้อย่างไรในกรณีนี้ ... ถ้าฉันเข้าใจถูกต้องคุณจะแนะนำอะไรเช่นนี้(o.overlap_perimeter^2 / o.overlap_area) / (4 * Pi()) as overlap_ratio? นี่คือผลลัพธ์ที่แย่กว่าสำหรับฉันมากกว่าแค่พื้นที่ / ปริมณฑล
bplmp

ตอนนี้ใช้o.overlap_perimeter / (4 * sqrt(o.overlap_area)) as overlap_ratioอ้างอิงจากบทความนี้ แต่ก็ยังมีผลลัพธ์ที่แย่ลง (แม้ว่ามันจะยากที่จะหาปริมาณสิ่งที่ฉันหมายถึงแย่ลง) isprs-ann-photogramm-remote-sens-spatial-inf-sci.net/I-7/135/ … , หน้า 183.
bplmp

2
ขอบคุณสำหรับสิ่งนี้ฉันไม่เคยได้ยิน "ดัชนีรูปทรง" ฉันคิดอยู่เสมอว่าการใช้สี่เหลี่ยมมุมต่ำสุดเป็นวิธีที่ดีที่สุดในการตอบคำถามประเภทนี้ ฉันพบสิ่งนี้repository.asu.edu/attachments/111230/content/…ซึ่งน่าสนใจ
John Powell

@JohnPowell intersting กระดาษขอบคุณ ฉันเห็นว่าสิ่งที่ฉันรู้ในขณะที่ดัชนีรูปร่างเรียกว่าดัชนีความกลมในกระดาษ ปัญหาของฉันกับสี่เหลี่ยมมุมฉากต่ำสุดคือมันไม่ทำงานกับวัตถุเว้ามาก (เช่นรูปตัวยู)
radouxju

@bplmp ST_Snap จะช่วยให้คุณยึดจุดยอดของรูปหลายเหลี่ยมที่อยู่ติดกัน "เกือบ" เพื่อไม่ให้ซ้อนทับกันอีกต่อไป ไม่มีมาตราส่วนบนร่างของคุณ แต่สิ่งประดิษฐ์ของคุณมีลักษณะเหมือนเส้นดังนั้นฉันเดาว่าคุณสามารถใช้ค่าความอดทนได้เพียงพอที่จะหลีกเลี่ยงสิ่งประดิษฐ์ แต่ไม่ส่งผลกระทบต่อรูปหลายเหลี่ยมขนาดใหญ่
radouxju

5

ทางเลือกหนึ่งคือการใช้อัตราส่วนของพื้นที่ของรูปหลายเหลี่ยมต่อเส้นที่ยาวที่สุดที่สามารถวาดได้โดยใช้แขนขาของมัน การระบุรูปหลายเหลี่ยมแคบ ๆ ยาว

select * from polygons where ST_Length(ST_LongestLine(geom, geom)) < ST_Area(geom) * 4

วิธีนี้ใช้งานได้ดีกับรูปหลายเหลี่ยมแบบเศษไม้ คุณสามารถปรับอัตราส่วน (สิ่งที่คุณคูณพื้นที่ด้วย) เพื่อให้เหมาะกับความต้องการและการฉายภาพของคุณ


1

ดูเหมือนว่านี่จะตรงกับกรณีการใช้งานของคุณ: กำจัดรูปหลายเหลี่ยมที่เลือก

รวมรูปหลายเหลี่ยมที่เลือกของชั้นข้อมูลเข้ากับรูปหลายเหลี่ยมที่อยู่ติดกันโดยการลบขอบเขตทั่วไป รูปหลายเหลี่ยมที่อยู่ติดกันสามารถเป็นได้ทั้งที่มีพื้นที่ที่ใหญ่ที่สุดหรือเล็กที่สุดหรือหนึ่งที่ใช้ร่วมกันขอบเขตที่ใหญ่ที่สุดกับรูปหลายเหลี่ยมที่จะถูกกำจัด

โดยทั่วไปแล้วการกำจัดจะใช้ในการกำจัดเศษไม้รูปหลายเหลี่ยมเช่นรูปหลายเหลี่ยมขนาดเล็กที่เป็นผลมาจากกระบวนการแยกรูปหลายเหลี่ยมที่ขอบเขตของอินพุตมีความคล้ายคลึง แต่ไม่เหมือนกัน

ดูเหมือนว่าคุณต้องการลองใช้ตัวเลือก "ขอบเขตทั่วไปที่ใหญ่ที่สุด"


ฉันรู้แล้วว่าตอนนี้คุณกำลังขอคำตอบจาก postgis ไม่ใช่ qgis คำขอโทษของฉันฉันไม่คิดว่า postgis มีฟังก์ชั่นที่เทียบเท่า แต่ฉันจะทิ้งเรื่องนี้ไว้เพื่อลูกหลาน
FGreg

0

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

ในระยะสั้นกลยุทธ์คือ:

1. เปิดใช้งานส่วนขยายโทโพโลยี

CREATE EXTENSION postgis_topology;

2. สร้างทอพอโลยีใหม่ที่ว่างเปล่า

SELECT topology.CreateTopology('neighborhoods_topo', 4326, 1e-7);

พารามิเตอร์ที่สามคือความอดทนในหน่วยของ CRS; เลือกอย่างชาญฉลาด เป็นการดีที่คุณต้องการ CRS ที่หน่วยเป็นเมตร หากหน่วย CRS ไม่ใช่เมตรเช่นเดียวกับ WGS 84 aka 4326 ให้ใช้ST_Transformเพื่อปฏิเสธรูปหลายเหลี่ยมของคุณ

3. เพิ่มคอลัมน์ TopoGeometry ลงในตารางรูปหลายเหลี่ยม

SELECT topology.AddTopoGeometryColumn('neighborhoods_topo', 'public', 'neighborhoods', 'topogeom', 'POLYGON');

layer_idนี้จะส่งกลับใหม่ บันทึกมันจะมีความจำเป็นในภายหลัง มันจะเป็นเลเยอร์1ถ้าคุณเริ่มต้นจากศูนย์และเพิ่มขึ้นทุกครั้งที่โทรเข้า

4. เพิ่มรูปหลายเหลี่ยมทั้งหมดในโทโพโลยี

UPDATE public.neighborhoods
SET topogeom = topology.toTopoGeom(geom, 'neighborhoods_topo', 1, 1e-7);

การดำเนินการนี้อาจใช้เวลาหลายชั่วโมงสำหรับชุดข้อมูลขนาดใหญ่ที่ต้องอดทน 1เป็น layer_id ส่งกลับก่อนหน้านี้

5. ค้นหาใบหน้าที่ปรากฏในพื้นที่ใกล้เคียงหลายแห่ง

ค้นหาใบหน้าทั้งหมดจากโทโพโลยีที่มีอยู่ใน 2 หรือมากกว่าโทโพโลจี ฉันจะปล่อยให้แบบสอบถามเป็นแบบฝึกหัด ที่ง่ายที่สุดน่าจะเป็นด้วยGetTopoGeomElementsฟังก์ชั่นจากนั้นจัดกลุ่มตามรหัสใบหน้าและดูคนที่มีจำนวน 2 หรือมากกว่า อีกทางหนึ่งคุณสามารถสร้างตารางใหม่ที่มีรูปทรงเรขาคณิตที่ทำความสะอาดจากคอลัมน์ topogeom เพียงแค่โยนมันไปที่รูปทรงเรขาคณิตมาตรฐานtopogeom::geometryและทำซ้ำสิ่งที่คุณมีอยู่ในขณะนี้ แต่ตอนนี้มีชุดข้อมูลใหม่ทั้งหมด

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