Çakışma olmayan en küçük (alt) çokgenleri elde etmek için üst çokgenler kavşaklarında özyinelemeli olarak nasıl döngü yapılır?


11

Birkaç gün boyunca bir sorunla mücadele ediyorum ve konu PostGIS (v2.5) 'de kavşaklar olduğunda birçok insanın da takıldığını fark ettim. Bu yüzden daha ayrıntılı ve genel, ortak bir soru sormaya karar verdim.

Aşağıdaki tablo var:

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 );

Şöyle görünüyor:

Başlat

Tüm çokgenleri ana çokgenlerin kesişimine dayanarak almak istiyorum. Sonuç için beklenen:

  • Aralarında çakışma olmayan çocuk çokgenler.
  • Üst çokgenlerinin değerlerinin toplamını içeren bir sütun,
  • Bir kategorideki ana çokgen sayısını içeren bir sütun
  • Başka bir kategorinin sayısını içeren bir sütun
  • Aşağıdaki kurala göre alt çokgenin kategorisini içeren bir sütun: -TÜM ana çokgenler bir sınıftan geliyorsa, alt çokgenin de bu sınıfı vardır. Aksi takdirde, çocuk poligonunun kategorisi üçüncü bir kategoridir.

Yani şöyle görünür:

çıktı

Yani, sonunda, (bu örneğin) üretilen çıktı tablosu sütunları içeren 7 satır (7, örtüşmeyen, çocuk çokgen) sahip olacak category, sum_value, ct_overlap_cat1,ct_overlap_cat2

Başladığım aşağıdaki kod, bir ebeveyn ile diğerini karşılaştırarak bireysel kavşakları veriyor.

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);

Örtüşen çokgenlerin sayısından bağımsız olarak her zaman onun en küçük (alt) çokgenlerini elde ettiğim bu kodun sonucunu özyinelemeli olarak nasıl değiştirebilirim (Şekil 2)?

Yanıtlar:


8

Bunu dene:

PostGIS Eklentilerini şu bağlantıdan indirin: https://github.com/pedrogit/postgisaddons

ST_SplitAgg () işlevini almak için postgis_addons.sql dosyasını çalıştırarak yükleyin.

Postgis_addons_test.sql dosyasını çalıştırarak test edin.

Sorgunuz:

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

Daha önce eklentilerine git repo'ya baktım. Inspirstionsl şeyler.
John Powell

Harika bir çözüm. Bu eklentileri oluşturmak için de oldukça şaşırtıcı bir iş yaptınız. Bu cevabı vermek için tıklamadan önce, beni rahatsız eden bir şeyden emin olmak için sadece bir tane. Sağladığınız kodu çalıştırdığınızda, 'çokgen 5' (sorunun ikinci figüründen) başka bir çokgenin ('ct_overlap_cat2 = 1'; 'ct_overlap_cat2 = 0') çakışmasını tanımıyor gibi görünüyor. Bu nedenle, bu çokgen 'cat3' ve 'sum = 7' yerine 'cat1' ve 'sum = 2' olarak sınıflandırılır. Bu küçük sorunu ayıklamakta biraz zorlanıyorum. Bana yardım eder misin?
Matt_Geo

1
Bu çözümle ilgili tek sorun, vaka ifadelerinin sabit kodlanmış olmasıdır. Prensip olarak, muhtemelen rastgele sayıda kategoriyi işleyebilmelidir.
John Powell

@Matt_Geo Ortaya çıkan tabloda 6 çokgen elde ediyorum. Üçgen poligon üçe bölünür. Biri toplam = 2, biri toplam = 7 ve biri toplam = 8 ile istediğiniz şekildeki gibi.
Pierre Racine

1
ST_Centroid'i (geom) ST_Area (geom) ile değiştirirseniz ne olur?
Pierre Racine

1

MultiPolygon yerine çokgen geometrisi türü kullanırsanız her şeyin yerine geçeceğini düşünüyorum:

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 );

Sonuç, sizin tarafınızdan verilen örnekteki farklı kavşak seçeneklerine karşılık gelen 9 giriştir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.