親ポリゴンの交差を再帰的にループして、オーバーラップのない最小の(子)ポリゴンを取得する方法は?


11

私は2日間問題に取り組んでいますが、トピックが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 );

次のようになります。

開始

親ポリゴンの交差に基づいてすべての子ポリゴンを取得したい。結果については、次のことが予想されます。

  • それらの間にオーバーラップのない子ポリゴン。
  • 親ポリゴンの値の合計を含む列、
  • 1つのカテゴリの親ポリゴンの数を含む列
  • 別のカテゴリの数を含む列
  • 次のルールに基づく、子ポリゴンのカテゴリを含む列。-すべての親ポリゴンが1つのクラスからのものである場合、子ポリゴンにもこのクラスがあります。それ以外の場合、子ポリゴンのカテゴリは3番目のカテゴリです。

したがって、次のようになります。

出力

だから、最終的には、(この例で)生成された出力テーブルにはの列を含む、7行(全7、非重複、子ポリゴン)を持つことになりますcategorysum_valuect_overlap_cat1ct_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アドオンをダウンロードします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

私は以前あなたのアドオンgit repoを見てきました。Inspirstionslのもの。
John Powell

素晴らしいソリューションです。あなたもこのアドオンを作成するためにかなり素晴らしい仕事をしました。私がクリックしてこの回答を授与する前に、私を悩ませている1つのことについて確認するために1つだけです。指定したコードを実行すると、(質問の2番目の図の) 'polygon 5'は別のポリゴン( 'ct_overlap_cat2 = 1'; 'ct_overlap_cat2 = 0')との重複を認識しないようです。したがって、このポリゴンは、「cat3」と「sum = 7」ではなく、「cat1」と「sum = 2」に分類されます。この小さな問題をデバッグするのは少し困難です。私たちを手伝ってくれますか?
Matt_Geo

1
このソリューションの唯一の問題は、caseステートメントがハードコーディングされていることです。原則として、任意の数のカテゴリを処理できるはずです。
John Powell

@Matt_Geo結果のテーブルに6つのポリゴンが表示されます。三角形ポリゴンは3つに分割されます。1つはsum = 2で、もう1つはsum = 7で、もう1つは希望の図のようにsum = 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.