隣接するすべてのポリゴンをマージする


22

パーセル(ポリゴン)レイヤーで隣接関係のテストを行い、特定の基準(サイズなど)に適合する場合はそれらをマージします。次の図では、ポリゴン1、2、3、4をマージしますが 5はマージしません

私には2つの問題があります:

  1. ST_TOUCHES線分ではなく、角だけが接触している場合にTRUEを返します。共有ラインセグメントをチェックするには、ST_RELATEが必要だと思います。
  2. 理想的には、隣接するすべてのポリゴンを1つにマージしたいと思いますが、1ラウンドで1、2、3、4(および実際のデータでさらに)をマージするなど、2つを超えてスケ​​ーリングする方法がわかりません。

私が今持っている構造は自己結合に基づいていST_TOUCHESます。

ここに画像の説明を入力してください

玩具データ

CREATE TABLE testpoly AS 
SELECT 
1 AS id, ST_PolyFromText('POLYGON ((0 0, 10 0, 10 20, 00 20, 0 0 ))') AS geom UNION SELECT
2 AS id, ST_PolyFromText('POLYGON ((10 0, 20 0, 20 20, 10 20, 10 0 ))') AS geom UNION SELECT
3 AS id, ST_PolyFromText('POLYGON ((10 -20, 20 -20, 20 0, 10 0, 10 -20 ))') AS geom UNION SELECT
4 AS id, ST_PolyFromText('POLYGON ((20 -20, 30 -20, 30 0, 20 0, 20 -20 ))') AS geom  UNION SELECT 
5 AS id, ST_PolyFromText('POLYGON ((30 0, 40 0, 40 20, 30 20, 30 0 ))') AS geom ;

選択

SELECT 
    gid, adj_gid,
    st_AStext(st_union(l2.g1,l2.g2)) AS geo_combo
from (
    --level 2
    SELECT
      t1.id AS gid,
      t1.geom AS g1,
      t2.id AS adj_gid,
      t2.geom AS g2
     from
      testpoly  t1,
      testpoly  t2
     where
      ST_Touches( t1.geom, t2.geom ) 
      AND t1.geom && t2.geom 
) 
l2

出力は次のとおりです。

+-----+---------+-------------------------------------------------------------------------------+
| gid | adj_gid | geo_combo                                                                     |
+-----+---------+-------------------------------------------------------------------------------+
| 1   | 2       | POLYGON((10 0,0 0,0 20,10 20,20 20,20 0,10 0))                                |
+-----+---------+-------------------------------------------------------------------------------+
| 1   | 3       | MULTIPOLYGON(((10 0,0 0,0 20,10 20,10 0)),((10 0,20 0,20 -20,10 -20,10 0)))   |
+-----+---------+-------------------------------------------------------------------------------+
| 2   | 1       | POLYGON((10 20,20 20,20 0,10 0,0 0,0 20,10 20))                               |
+-----+---------+-------------------------------------------------------------------------------+
| 2   | 3       | POLYGON((10 0,10 20,20 20,20 0,20 -20,10 -20,10 0))                           |
+-----+---------+-------------------------------------------------------------------------------+
| 2   | 4       | MULTIPOLYGON(((20 0,10 0,10 20,20 20,20 0)),((20 0,30 0,30 -20,20 -20,20 0))) |
+-----+---------+-------------------------------------------------------------------------------+
| 3   | 1       | MULTIPOLYGON(((10 0,20 0,20 -20,10 -20,10 0)),((10 0,0 0,0 20,10 20,10 0)))   |
+-----+---------+-------------------------------------------------------------------------------+
| 3   | 2       | POLYGON((20 0,20 -20,10 -20,10 0,10 20,20 20,20 0))                           |
+-----+---------+-------------------------------------------------------------------------------+
| 3   | 4       | POLYGON((20 -20,10 -20,10 0,20 0,30 0,30 -20,20 -20))                         |
+-----+---------+-------------------------------------------------------------------------------+
| 4   | 2       | MULTIPOLYGON(((20 0,30 0,30 -20,20 -20,20 0)),((20 0,10 0,10 20,20 20,20 0))) |
+-----+---------+-------------------------------------------------------------------------------+
| 4   | 3       | POLYGON((20 0,30 0,30 -20,20 -20,10 -20,10 0,20 0))                           |
+-----+---------+-------------------------------------------------------------------------------+
| 4   | 5       | MULTIPOLYGON(((30 0,30 -20,20 -20,20 0,30 0)),((30 0,30 20,40 20,40 0,30 0))) |
+-----+---------+-------------------------------------------------------------------------------+
| 5   | 4       | MULTIPOLYGON(((30 0,30 20,40 20,40 0,30 0)),((30 0,30 -20,20 -20,20 0,30 0))) |
+-----+---------+-------------------------------------------------------------------------------+

ポリゴンid = 3はid = 1とポイントを共有するため、肯定的な結果として返されることに注意してください。WHERE句をに変更すると、ST_Touches( t1.geom, t2.geom ) AND t1.geom && t2.geom AND ST_Relate(t1.geom, t2.geom ,'T*T***T**');レコードがまったく取得されません。

  1. だから、最初に、どのように私は確信して線分を共有するだけで小包が考慮されていることを確認するためにST_Relateを指定してください。

  2. それから、ポリゴン1、2、3、4を1ラウンドでマージし、上記の呼び出しの結果を折り畳みながら、隣接関係1から2が逆と同じであることを認識しますか?

更新

これをwhere句に追加すると、明らかにポリゴンのみが取得され、マルチポリゴンは取得されないため、誤検知を取り除くために、コーナータッチは無視されます。

GeometryType(st_union(t1.geom,t2.geom)) != 'MULTIPOLYGON'

これは理想的ではありませんが(ST_RELATEより一般的な解決策としてトポロジチェックを使用したい)、これは将来の方法です。その後、これらの重複排除と結合の問題が残ります。おそらく、タッチしているポリゴンのみのシーケンスを生成できれば、それを結合できます。

アップデートII

これは、ラインを共有するポリゴン(コーナーではない)を選択するために機能するようで、上記のMULTIPOLYGONテストよりも一般的なソリューションです。私のwhere句は次のようになります。

WHERE
              ST_Touches( t1.geom, t2.geom ) 
              AND t1.geom && t2.geom 

              -- 'overlap' relation
              AND ST_Relate(t1.geom, t2.geom)='FF2F11212') t2 

残っているのは、ポリゴンのペアだけでなく、基準に適合する任意の数のマージを一度に行う方法です。


2
ST_Relateが正しい方法であると確信しています。交差点の長さがゼロよりも大きいことを確認して、単一点の交差点を除外することで、同様の問題を解決しました。ハックですが、動作します。
ジョンパウエル14

連続するポリゴンを配列にグループ化する方法がある場合は、ST_IntersectionArray[関数] [1]を変更してST_Union [1]で動作するようにすることができます。gis.stackexchange.com/ a
60295

2
グループ化一緒に連続したポリゴンについて、あなたは私がここに書いたボトムアップクラスタリングアルゴリズム(修正することができるgis.stackexchange.com/a/115715/36886を隣接のではなくスペースをテストするために)、次いで得られたcluster_idsにグループ化している間にST_Unionを使用します
ラファエル14

3
また、必要なことを行うST_ClusterIntersectimgもあります。Postgis 2.2が必要です
ジョンパウエル

回答:


3

あなたの例が実際にラスターであると考えることは仕方がありませんでしたが、「特定の基準(サイズである可能性があります)」に基づいてマージしたいと述べましたが、ラスター変換のショットを与えたいと思います。

あなたの特定の例では、これはうまくいくでしょう:

WITH rast AS (
  SELECT 
  ST_UNION(ST_AsRaster(geom,10, 20, '2BUI')) r
  FROM testpoly 
)
,p AS (
    SELECT (ST_DumpAsPolygons(r)).geom FROM rast
)
SELECT t.id,p.* 
FROM p
LEFT JOIN testpoly  t ON ST_Equals(p.geom, t.geom)

何が起こるかというと、ポリゴンは完全に整列したセルであるため、ラスタにうまく変換されます(10x20セルサイズ)。dumpaspolygonsは、隣接するすべてのセルを1つにマージし、元のポリゴンと比較することで、マージされていないポリゴンのIDを取得することもできます。

これを説明してきたので、これがどのようにスケーリングし、データセットがどれくらい大きいかについて非常に興味があります:D


賢いアイデア。これはおもちゃの例ですが、私の実際のデータは、ラスターにきちんとマッピングされないパーセルレイヤーです。
赤穂

3

これは、フードの下で複数のパスを使用して手続き型でこれを行う方法の例です。

CREATE TABLE joined_testpoly AS SELECT array[id] ids, geom FROM testpoly; 

LIMIT 1以下の選択がどのように機能するかを変更することで、より多くの列を実行し、追加の追加基準を適用できるはずです。

CREATE OR REPLACE FUNCTION reduce_joined_testpoly()
RETURNS void
AS $$
DECLARE
  joined_row joined_testpoly%ROWTYPE;
BEGIN
  LOOP
     SELECT array_cat(a.ids, b.ids), st_union(a.geom, b.geom)
         INTO joined_row 
     FROM joined_testpoly a INNER JOIN joined_testpoly b
           on a.ids != b.ids
              and ST_Touches(a.geom, b.geom) and a.geom && b.geom 
              and ST_Relate(a.geom, b.geom)='FF2F11212'
         LIMIT 1;
     IF NOT FOUND THEN
           EXIT;
     END IF;
     INSERT INTO joined_testpoly VALUES (joined_row.ids, joined_row.geom);
     DELETE FROM joined_testpoly
         WHERE joined_testpoly.ids <@ joined_row.ids 
           AND joined_testpoly.ids != joined_row.ids;
  END LOOP;
  RETURN;
END;
$$ LANGUAGE plpgsql;

実行します:

SELECT reduce_joined_testpoly();

適切な結合、マルチポリゴンなし:

SELECT ids, st_geometrytype(geom), st_area(geom), st_numgeometries(geom) 
FROM joined_testpoly;
    ids    | st_geometrytype | st_area | st_numgeometries 
-----------+-----------------+---------+------------------
 {5}       | ST_Polygon      |     200 |                1
 {1,2,3,4} | ST_Polygon      |     800 |                1

2

参照用の別の(機能しない)戦略を次に示します(単一の接触点のケースを除外することができませんでした)。「1パス」だけで済むため、他の回答よりも高速です。

SELECT st_numgeometries(g), (SELECT st_union(x.geom) FROM st_dump(g) x GROUP BY g)
FROM (
    SELECT unnest(st_clusterintersecting(geom)) g, id < 100 as other_arbitrary_grouping 
    FROM testpoly
    GROUP BY other_arbitrary_grouping) c;

(独自のグループでid = 5ジオメトリを取得できる場合は、自由に修正して別の回答を投稿してください)

あなたが使用する必要があるだろう、IDSなどのリストを取り戻すためにst_contains、次の答えで説明するようにtestpolyテーブルの上に再度参加することを:/programming//a/37486732/6691 が、私は仕事にそれを得ることができませんでした何らかの理由でポリゴンの場合。


2

少し調整した元のクエリを使用して、簡単に確認します。

with gr as (SELECT 
    gid, adj_gid,
    st_AStext(st_union(l2.g1,l2.g2)) AS geo_combo
from (
    --level 2
    SELECT
      t1.id AS gid,
      t1.geom AS g1,
      t2.id AS adj_gid,
      t2.geom AS g2
     from
      testpoly  t1,
      testpoly  t2
     where
      ST_Touches( t1.geom, t2.geom ) 
      AND ST_Relate(t1.geom,t2.geom, '****1****')
      AND t1.geom && t2.geom 
) 
l2) select ST_AsText(st_union(gr.geo_combo)) from gr;

参照:https : //postgis.net/docs/using_postgis_dbmanagement.html#DE-9IM

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.