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


11

ฉันกำลังดิ้นรนกับปัญหาสองสามวันและตระหนักว่าหลายคนก็ติดเมื่อหัวข้อเป็นจุดตัดใน PostGIS (v2.5) นั่นเป็นเหตุผลที่ฉันตัดสินใจถามคำถามทั่วไปที่มีรายละเอียดและทั่วไปมากขึ้น

ฉันมีตารางต่อไปนี้:

DROP TABLE IF EXISTS tbl_foo;
CREATE TABLE tbl_foo (
    id bigint NOT NULL,
    geom public.geometry(MultiPolygon, 4326),
    att_category character varying(15),
    att_value integer
);
INSERT INTO tbl_foo (id, geom, att_category, att_value) VALUES 
    (1, ST_SetSRID('MULTIPOLYGON (((0 6, 0 12, 8 9, 0 6)))'::geometry,4326) , 'cat1', 2 );
INSERT INTO tbl_foo (id, geom, att_category, att_value) VALUES 
    (2, ST_SetSRID('MULTIPOLYGON (((5 0, 5 12, 9 12, 9 0, 5 0)))'::geometry,4326), 'cat1', 1 );
INSERT INTO tbl_foo (id, geom, att_category, att_value) VALUES 
    (3, ST_SetSRID('MULTIPOLYGON (((4 4, 3 8, 4 12, 7 14,10 12, 11 8, 10 4, 4 4)))'::geometry,4326) , 'cat2', 5 );

ดูเหมือนว่านี้:

เริ่มต้น

ฉันต้องการให้รูปหลายเหลี่ยมเด็กทั้งหมดขึ้นอยู่กับจุดตัดของรูปหลายเหลี่ยมแม่ สำหรับผลลัพธ์มันคาดหวัง:

  • รูปหลายเหลี่ยมของเด็กโดยไม่ทับซ้อนกัน
  • คอลัมน์ที่มีผลรวมของค่าของรูปหลายเหลี่ยมแม่ของพวกเขา
  • คอลัมน์ที่มีการนับจำนวนรูปหลายเหลี่ยมหลักของหมวดหมู่เดียว
  • คอลัมน์ที่มีการนับหมวดหมู่อื่น
  • คอลัมน์ที่มีหมวดหมู่ของรูปหลายเหลี่ยมลูกขึ้นอยู่กับกฎต่อไปนี้: - หากรูปหลายเหลี่ยมแม่ทั้งหมดมาจากชั้นหนึ่งรูปหลายเหลี่ยมเด็กยังมีชั้นนี้ อื่นประเภทของรูปหลายเหลี่ยมเด็กเป็นประเภทที่สาม

ดังนั้นมันดูเหมือนว่า:

เอาท์พุต

ดังนั้นในท้ายที่สุดตารางผลลัพธ์ที่เกิดขึ้น (เช่นนี้) จะมี 7 แถว (ทั้งหมด 7 ไม่ทับซ้อนกันหลายเหลี่ยมเด็ก) ที่มีคอลัมน์ของcategory, sum_value, ct_overlap_cat1,ct_overlap_cat2

รหัสต่อไปนี้ที่ฉันเริ่มให้การแยกแต่ละรายการแก่ฉันเปรียบเทียบผู้ปกครองคนหนึ่งกับอีกคนหนึ่ง

SELECT
(ST_Dump(
    ST_SymDifference(a.geom, b.geom) 
)).geom
FROM tbl_foo a, tbl_foo b
WHERE a.ID < b.ID AND ST_INTERSECTS(a.geom, b.geom)
UNION ALL
SELECT
ST_Intersection(a.geom, b.geom) as geom
FROM tbl_foo a, tbl_foo b
WHERE a.ID < b.ID AND ST_INTERSECTS(a.geom, b.geom);

ฉันจะวนซ้ำผลลัพธ์ของรหัสที่กล่าวถึงนี้ได้อย่างไรซึ่งเป็นอิสระจากจำนวนของรูปหลายเหลี่ยมที่ทับซ้อนกันฉันจะได้รับ 'รูปหลายเหลี่ยมที่เล็กที่สุด' (เด็ก) รูปหลายเหลี่ยม (รูปที่ 2) เสมอ

คำตอบ:


8

ลองสิ่งนี้:

ดาวน์โหลด PostGIS Addons จากลิงค์นี้: https://github.com/pedrogit/postgisaddons

ติดตั้งโดยเรียกใช้ไฟล์ postgis_addons.sql เพื่อรับฟังก์ชั่น ST_SplitAgg ()

ทดสอบโดยรันไฟล์ postgis_addons_test.sql

นี่คือคำถามของคุณ:

WITH  result_table AS (
    WITH  parts AS (
      SELECT a.att_value val,
             CASE WHEN a.att_category = 'cat1' THEN 1 ELSE 0 END cat1,
             CASE WHEN a.att_category = 'cat2' THEN 1 ELSE 0 END cat2,
             unnest(ST_SplitAgg(a.geom, b.geom, 0.00001)) geom
      FROM tbl_foo a,
           tbl_foo b
      WHERE ST_Equals(a.geom, b.geom) OR
            ST_Contains(a.geom, b.geom) OR
            ST_Contains(b.geom, a.geom) OR
            ST_Overlaps(a.geom, b.geom)
      GROUP BY a.id, a.att_category , ST_AsEWKB(a.geom), val
    )
    SELECT CASE WHEN sum(cat2) = 0 THEN 'cat1'
                WHEN sum(cat1) = 0 THEN 'cat2'
                ELSE 'cat3'
           END category, 
           sum(val*1.0) sum_value, 
           sum(cat1) ct_overlap_cat1, 
           sum(cat2) ct_overlap_cat2, 
           ST_Union(geom) geom
    FROM parts
    GROUP BY ST_Area(geom)
)
SELECT category, sum_value, ct_overlap_cat1, ct_overlap_cat2,
(ST_Dump(result_table.geom)).geom as geom
FROM result_table

ฉันได้ดู repons คอมไพล์ addons ของคุณก่อน สิ่งที่แรงบันดาลใจ
John Powell

ว้าวทางออกที่ดี คุณทำผลงานได้ยอดเยี่ยมมากในการสร้างส่วนเสริมนี้เช่นกัน ก่อนที่ฉันจะคลิกเพื่อให้รางวัลคำตอบนี้ฉันเพียงคนเดียวที่จะทำให้แน่ใจเกี่ยวกับสิ่งหนึ่งที่หลอกฉัน การเรียกใช้รหัสที่คุณระบุ 'รูปหลายเหลี่ยม 5' (จากรูปที่สองของคำถาม) ดูเหมือนจะไม่รู้จักการซ้อนทับกับรูปหลายเหลี่ยมอื่น ('ct_overlap_cat2 = 1'; 'ct_overlap_cat2 = 0') ดังนั้นรูปหลายเหลี่ยมนี้จึงถูกจัดประเภทเป็น 'cat1' และ 'sum = 2' แทนที่จะเป็น 'cat3' และ 'sum = 7' ฉันกำลังเผชิญกับความยากลำบากเล็กน้อยในการแก้ไขปัญหาเล็กน้อยนี้ คุณช่วยฉันได้ไหม
Matt_Geo

1
ปัญหาเดียวของการแก้ปัญหานี้คือคำสั่ง case ถูกฮาร์ดโค้ด โดยหลักการแล้วมันอาจจะสามารถจัดการกับจำนวนหมวดหมู่โดยพลการ
John Powell

@Matt_Geo ฉันรับ 6 รูปหลายเหลี่ยมในตารางผลลัพธ์ รูปสามเหลี่ยมเหลี่ยมแบ่งออกเป็นสามส่วน หนึ่งที่มีผลรวม = 2, หนึ่งที่มีผลรวม = 7 และอีกอันที่มีผลรวม = 8 เช่นเดียวกับในรูปที่คุณต้องการ
Pierre Racine

1
ถ้าคุณแทนที่ ST_Centroid (geom) ด้วย ST_Area (geom)
Pierre Racine

1

ฉันคิดว่าถ้าคุณใช้รูปทรงเรขาคณิตหลายเหลี่ยมแทนที่จะเป็น MultiPolygon ทุกอย่างจะเข้าที่:

DROP TABLE IF EXISTS tbl_foo;
CREATE TABLE tbl_foo (
    id bigint NOT NULL,
    geom public.geometry(Polygon, 4326),
    att_category character varying(15),
    att_value integer
);

INSERT INTO tbl_foo (id, geom, att_category, att_value) VALUES 
    (1, ST_SetSRID('POLYGON ((0 6, 0 12, 8 9, 0 6))'::geometry,4326) , 'cat1', 2 );
INSERT INTO tbl_foo (id, geom, att_category, att_value) VALUES 
    (2, ST_SetSRID('POLYGON ((5 0, 5 12, 9 12, 9 0, 5 0))'::geometry,4326), 'cat1', 1 );
INSERT INTO tbl_foo (id, geom, att_category, att_value) VALUES 
    (3, ST_SetSRID('POLYGON ((4 4, 3 8, 4 12, 7 14,10 12, 11 8, 10 4, 4 4))'::geometry,4326) , 'cat2', 5 );

ผลลัพธ์คือ 9 รายการที่ตรงกับตัวเลือกการตัดกันที่แตกต่างกันในตัวอย่างที่คุณกำหนด

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