ใช้ ST_Difference เพื่อลบคุณลักษณะที่ทับซ้อนกันหรือไม่


11

ฉันกำลังพยายามใช้ ST_Difference เพื่อสร้างชุดรูปหลายเหลี่ยม (การประมวลผล trimmedparcelsnew) ที่ไม่มีพื้นที่ใด ๆ ที่ครอบคลุมโดยรูปหลายเหลี่ยมชุดอื่น (test.single_geometry_1) โดยใช้ PostGis 2.1 (และ Postgres SQL 9.3) นี่คือคำถามของฉัน:

CREATE TABLE processing.trimmedparcelsnew AS
SELECT
    orig.id, ST_Difference(orig.geom, cont.geom) AS difference
FROM 
    test.single_geometry_1 cont,
    test.multi_geometry_1 orig;

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

ฉันแนบรูปภาพผลลัพธ์แล้ว

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


หลังจากความคิดเห็นฉันได้ลองเพิ่มส่วนคำสั่ง WHERE แล้ว ฉันต้องการพัสดุที่ไม่มีทางแยกและบริเวณที่ตัดกันของพัสดุอื่นถูกลบ (layer test.single_geometry แสดงถึงการปนเปื้อนที่ฉันต้องการลบออกจากพัสดุของฉัน) ฉันลองทางแยก แต่แน่นอนว่าฉันต้องการทางแยกที่ไม่ใช่จริงดังนั้นตอนนี้ฉันจึงลองแยกกัน ฉันได้ลองเพิ่มต้นกำเนิดลงในตารางของฉันแล้ว แต่เอกสารสำหรับ ST_Difference ( http://postgis.net/docs/ST_Difference.html ) นั้นบอกว่ามันคืนค่าเรขาคณิตที่แน่นอนที่ฉันต้องการ (เรขาคณิตที่แสดงถึงส่วนหนึ่งของเรขาคณิต A ที่ ไม่ตัดกับเรขาคณิต B) ดังนั้นฉันจึงสับสนว่าทำไมฉันจึงต้องการรูปหลายเหลี่ยมต้นฉบับในตารางของฉันแทน อย่างไรก็ตามนี่คือรหัสการแก้ไขของฉัน:

CREATE TABLE processing.trimmedparcelsnew AS
SELECT
    orig.id, ST_Difference(orig.geom, cont.geom) AS difference, orig.geom AS geom
FROM 
    test.single_geometry_1 cont,
    test.multi_geometry_1 orig
WHERE ST_Disjoint(orig.geom, cont.geom);

ต่อไปนี้จากคำตอบของ dbaston ฉันได้ลองแล้ว:

CREATE TABLE processing.parcels_trimmed AS
SELECT id, COALESCE(ST_Difference(geom, (SELECT ST_Union(b.geom) 
                                         FROM test.single_geometry_1 b
                                         WHERE ST_Intersects(a.geom, b.geom)
                                         AND a.id != b.id)), a.geom)
FROM test.multi_geometry_1 a;

ผลลัพธ์ของสิ่งนี้เป็นเพียงสำเนาของ test.multi_geometry_1 แม้ว่าตอนนี้การแยกจะไม่เกิดขึ้นอีกต่อไป

ฉันลองรุ่นก่อนหน้านี้ แต่ได้รับสำเนาของ test.multi_geometry_1 อีกครั้ง:

CREATE TABLE processing.parcels_trimmed_no_coalesce AS
SELECT id, COALESCE(ST_Difference(geom, (SELECT ST_Union(b.geom) 
                                         FROM test.single_geometry_1 b
                                         WHERE ST_Intersects(a.geom, b.geom)
                                         AND a.id != b.id)), a.geom)
FROM test.multi_geometry_1 a;

ฉันเริ่มสงสัยว่ามีสิ่งอื่นที่ฉันทำผิดหรือเปล่า? คำสั่งการดำเนินการคือ:

DROP TABLE IF EXISTS processing.parcels_trimmed_no_coalesce;

และฉันกำลังเรียกใช้แบบสอบถามจากหน้าต่างแบบสอบถาม PostgreSQL SQL และ Openjump

คำสั่งที่ฉันใช้เพื่อดูตารางคือ:

SELECT * FROM processing.parcels_trimmed_no_coalesce;

เพื่อประโยชน์ในการทำให้เข้าใจง่ายฉันได้ลดแบบสอบถามนี้ลงเหลือเพียงแค่:

SELECT id, COALESCE(ST_Difference(geom, (SELECT ST_Union(b.geom) 
                                         FROM test.geometriestocutagainst b
                                         WHERE ST_Intersects(a.geom, b.geom)
                                         AND a.id != b.id)), a.geom)
FROM test.geometriestocut a;

สิ่งนี้ยังคงให้ผลลัพธ์เป็นรูปหลายเหลี่ยมดั้งเดิมเท่านั้น (test.geometriestocut) เมื่อผลลัพธ์ที่ต้องการนั้นถูกตัดแต่งแบบดั้งเดิมเทียบกับ test.geometriestocutagainst


คุณไม่ได้ระบุWHEREประโยคดังนั้นคุณอาจมีการขยายพหุนามในตารางผลลัพธ์ วิธีการหลายแถวอยู่ในtrimmedparcelsnew?
วินซ์

หากคุณต้องการความแตกต่างที่พวกเขาตัดกันคุณสามารถลองเพิ่ม WHERE ST_Intersects (orig.geom, cont.geom) มิฉะนั้นความแตกต่างของรูปหลายเหลี่ยมสองรูปที่ไม่ตัดกันคือรูปหลายเหลี่ยมดั้งเดิม
John Powell

มี 24 แถวในหีบห่อที่ตัดใหม่ฉันต้องการความแตกต่างแม้ว่าพวกเขาจะไม่ตัดกันดังนั้นฉันจะแก้ไขให้ถูกต้องว่าฉันต้องใช้ orig.geom ในตารางแทนความแตกต่างหรือไม่
Mart

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

โอเคขอบคุณสำหรับคำอธิบาย แต่ฉันก็ยังไม่แน่ใจว่าทำไมรหัสต้นฉบับไม่ทำงาน ถ้า ST_Difference (orig.geom, cont.geom) ส่งกลับรูปทรงเรขาคณิตในจุดที่ไม่ตัดกับ b มากกว่าสาเหตุที่ตารางมีรูปทรงเรขาคณิตแยกมากกว่ารูปทรงเรขาคณิตในรูปแบบที่ไม่ตัด b
Mart

คำตอบ:


14

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

CREATE TABLE parcels_trimmed AS
SELECT id, ST_Difference(geom, (SELECT ST_Union(b.geom) 
                                FROM parcels b
                                WHERE ST_Intersects(a.geom, b.geom)
                                  AND a.id != b.id))
FROM parcels a;

คุณอาจเห็นบางสิ่งแปลก ๆ ในผลลัพธ์ พัสดุที่ไม่มีการทับซ้อนจะถูกทิ้งอย่างสิ้นเชิง! นั่นเป็นเพราะST_Unionการรวมในระเบียนที่ว่างเปล่าเป็นไปได้NULLและเป็นST_Difference(geom, NULL) NULLเพื่อให้การดำเนินการเป็นไปอย่างราบรื่นคุณต้องปิดการST_DifferenceโทรในCOALESCE:

CREATE TABLE parcels_trimmed AS
SELECT id, COALESCE(ST_Difference(geom, (SELECT ST_Union(b.geom) 
                                         FROM parcels b
                                         WHERE ST_Intersects(a.geom, b.geom)
                                         AND a.id != b.id)), a.geom)
FROM parcels a;

ซึ่งหมายความว่าหากผลลัพธ์ของST_DifferenceคือNULLการแสดงออกรวมกันจะประเมินให้กับรูปทรงเรขาคณิตเดิม

ข้อความค้นหาด้านบนจะลบพื้นที่ที่ทับซ้อนกันออกจากโดเมนของคุณทั้งหมด หากคุณแทนต้องการที่จะเลือกผู้ชนะคุณจะทำหรือบางเกณฑ์อื่นแทนa.id < b.ida.id != b.id


ขอบคุณสำหรับการตอบกลับขออภัยที่ฉันมีปัญหาในการทำให้สิ่งนี้ใช้งานได้สำหรับฉันแทนที่จะจบด้วยรูปหลายเหลี่ยมดั้งเดิม (a) ฉันจะแก้ไขคำถามด้วยข้อมูลเพิ่มเติม ขอบคุณอีกครั้ง.
Mart

2

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

CREATE TABLE parcels_trimmed AS
SELECT id, COALESCE(ST_Difference(geom, (SELECT ST_Collect(b.geom) 
                                         FROM parcels b
                                         WHERE ST_Intersects(a.geom, b.geom)
                                         )), a.geom)
FROM parcels a;

1

ผมใช้ ST_DifferenceAgg () จากPostGIS Addons คุณต้องรวมสองตารางเข้าด้วยกันมีตัวระบุเฉพาะและดัชนีในคอลัมน์รูปทรงเรขาคณิต นี่เป็นตัวอย่างสั้น ๆ :

WITH overlappingtable AS (
  SELECT 1 id, ST_GeomFromText('POLYGON((0 1, 3 2, 3 0, 0 1), (1.5 1.333, 2 1.333, 2 0.666, 1.5 0.666, 1.5 1.333))') geom
  UNION ALL
  SELECT 2 id, ST_GeomFromText('POLYGON((1 1, 3.8 2, 4 0, 1 1))')
  UNION ALL
  SELECT 3 id, ST_GeomFromText('POLYGON((2 1, 4.6 2, 5 0, 2 1))')
  UNION ALL
  SELECT 4 id, ST_GeomFromText('POLYGON((3 1, 5.4 2, 6 0, 3 1))')
  UNION ALL
  SELECT 5 id, ST_GeomFromText('POLYGON((3 1, 5.4 2, 6 0, 3 1))')
)
SELECT a.id, ST_DifferenceAgg(a.geom, b.geom) geom
FROM overlappingtable a,
     overlappingtable b
WHERE a.id = b.id OR -- Make sure to pass at least once the polygon with itself
      ((ST_Contains(a.geom, b.geom) OR -- Select all the containing, contained and overlapping polygons
        ST_Contains(b.geom, a.geom) OR
        ST_Overlaps(a.geom, b.geom)) AND
       (ST_Area(a.geom) < ST_Area(b.geom) OR -- Make sure bigger polygons are removed from smaller ones
        (ST_Area(a.geom) = ST_Area(b.geom) AND -- If areas are equal, arbitrarily remove one from the other but in a determined order so it's not done twice.
         a.id < b.id)))
GROUP BY a.id
HAVING ST_Area(ST_DifferenceAgg(a.geom, b.geom)) > 0 AND NOT ST_IsEmpty(ST_DifferenceAgg(a.geom, b.geom));

วิธีนี้จะรวมส่วนที่ทับซ้อนกันกับรูปหลายเหลี่ยมที่ซ้อนกันที่ใหญ่ที่สุด หากคุณต้องการแยกส่วนที่ทับซ้อนกันให้ดูตัวอย่าง ST_splitAgg ()

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