PostGISでポリゴンフィーチャ間の違いを視覚化するためにラインを作成する方法は?


15

polygon_bいくつかのポリゴンフィーチャを備えたPostGISテーブルがあります。テーブルもあり、polygon_a同じポリゴンが含まれていますpolygon_bが、軽微な変更には。次に、ポリゴンフィーチャ間の違いを視覚化するラインを作成します。

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

私はそれをして仕事ST_ExteriorRingST_Differenceするだろうと思うが、WHERE句は非常に難しいようだ。

CREATE VIEW line_difference AS SELECT
row_number() over() AS gid,
g.geom::geometry(LineString, yourSRID) AS geom
FROM 
    (SELECT
    (ST_Dump(COALESCE(ST_Difference(ST_ExteriorRing(polygon_a.geom), ST_ExteriorRing(polygon_b.geom))))).geom AS geom
    FROM polygon_a, polygon_b
    WHERE 
    -- ?
    ) AS g;

誰も私を助けることができますか?

編集1

「tilt」によって投稿されST_Overlaps(polygon_a.geom, polygon_b.geom) AND NOT ST_Touches(polygon_a.geom, polygon_b.geom)たように、私は試しましたが、結果は期待通りではありません。

CREATE VIEW line_difference AS SELECT
row_number() over() AS gid,
g.geom::geometry(LineString, your_SRID) AS geom
FROM 
    (SELECT
    (ST_Dump(COALESCE(ST_Difference(ST_ExteriorRing(polygon_a.geom), ST_ExteriorRing(polygon_b.geom))))).geom AS geom
    FROM polygon_a, polygon_b
    WHERE 
    ST_Overlaps(polygon_a.geom, polygon_b.geom) AND NOT ST_Touches(polygon_a.geom, polygon_b.geom))
     AS g;

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

編集2

workupload.com/file/J0WBvRBb(データセットの例)


ST_Differenceを使用する前にポリゴンをマルチラインに変換しようとしましたが、結果はまだ奇妙です。

CREATE VIEW multiline_a AS SELECT
row_number() over() as gid,
ST_Union(ST_ExteriorRIng(polygon_a.geom))::geometry(multilinestring, 4326) AS geom
FROM
polygon_a;

CREATE VIEW multiline_b AS SELECT
row_number() over() as gid,
ST_Union(ST_ExteriorRIng(polygon_b.geom))::geometry(multilinestring, 4326) AS geom
FROM
polygon_b;

CREATE VIEW line_difference AS SELECT
row_number() over() as gid,
g.geom
FROM
    (SELECT
    (ST_Dump(COALESCE(ST_Difference(multiline_a.geom, multiline_b.geom)))).geom::geometry(linestring, 4326) AS geom
    FROM
    multiline_a, multiline_b)
As g;

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


トポロジーの質問のように見えます。他のレイヤーで覆われていないセグメントを特定したい場合。私はPostGISトポロジをあまり使用しておらず、直接的な回答を提供することはできませんが、これをさらに検討することをお勧めします。
トーマス

興味深いことに、ダウンロード用のデータセットの例はありますか?
ハックフィン

回答:


10

以下に、新しいトリックをいくつか示します。

  • EXCEPTどちらかのテーブルから同じジオメトリを削除するため、各テーブルに固有のジオメトリ(A_onlyおよびB_only)のみに注目できます。
  • ST_Snap オーバーレイ演算子の正確なノードを取得します。
  • ST_SymDifferenceオーバーレイ演算子を使用して、2つのジオメトリセット間の対称差を見つけて、差を表示します。更新ST_Differenceこの例でも同じ結果が表示されます。どちらの機能を試して、何が得られるかを確認できます。

これにより、期待どおりの結果が得られます。

-- CREATE OR REPLACE VIEW polygon_SymDifference AS
SELECT row_number() OVER () rn, *
FROM (
  SELECT (ST_Dump(ST_SymDifference(ST_Snap(A, B, tol), ST_Snap(B, A, tol)))).*
  FROM (
    SELECT ST_Union(DISTINCT A_only.geom) A, ST_Union(DISTINCT B_only.geom) B, 1e-5 tol
    FROM (
      SELECT ST_Boundary(geom) geom FROM polygon_a
      EXCEPT SELECT ST_Boundary(geom) geom FROM polygon_b
    ) A_only,
    (
      SELECT ST_Boundary(geom) geom FROM polygon_b
      EXCEPT SELECT ST_Boundary(geom) geom FROM polygon_a
    ) B_only
  ) s
) s;

 rn |                                        geom
----+-------------------------------------------------------------------------------------
  1 | LINESTRING(206.234028204842 -92.0360704110685,219.846021625456 -92.5340701703592)
  2 | LINESTRING(18.556700448873 -36.4496098325257,44.44438533894 -40.5104231486146)
  3 | LINESTRING(-131.974995802602 -38.6145334122719,-114.067738329597 -39.0215165366584)
(3 rows)

三行


この答えをもう少しアンパックするには、最初のステップでST_Boundary、外側だけでなく各ポリゴンの境界を取得します。たとえば、穴があった場合、これらは境界によってトレースされます。

このEXCEPTは、Bの一部であるAからジオメトリを削除し、Aの一部であるBから行を削除するために使用されます。これにより、Aのみの一部およびBのみの一部の行数が削減されます。たとえば、A_onlyを取得するには:

SELECT ST_Boundary(geom) geom FROM polygon_a
EXCEPT SELECT ST_Boundary(geom) geom FROM polygon_b

A_onlyの6行とB_onlyの3行は次のとおりです。 A_only B_only

次に、ST_Union(DISTINCT A_only.geom)ラインワークを単一のジオメトリ(通常はMultiLineString)に結合するために使用されます。

ST_Snapは、あるジオメトリから別のジオメトリにノードをスナップするために使用されます。たとえばST_Snap(A, B, tol)、Aジオメトリを取得し、Bジオメトリからノードを追加するか、tol距離内にある場合はBジオメトリに移動します。これらの関数を使用する方法はおそらくいくつかありますが、アイデアは各ジオメトリから相互に正確な座標を取得することです。そのため、スナップ後の2つのジオメトリは次のようになります。

スナップ Bスナップ

また、違いを示すために、ST_SymDifferenceまたはのいずれかを使用することもできますST_Difference。この例では、どちらも同じ結果を示しています。


いい答え。中間クエリの結果を視覚化するために何を使用したのか疑問に思いました。それはすぐにqgisのように見えませんでした。
-RoperMaps

1
JTS Testbuilderを使用して、ジオメトリを表示および処理します。GEOSおよびShapelyに関連するジオメトリエンジンですが、JavaベースのGUIを備えています。
マイクT

「LINESTRING間の非ノード交差」問題を無視/スキップする方法はありますか?すべての入力ポリゴンに問題はないようです(QGISジオメトリチェッカーで確認)。
eclipsed_by_the_moon

1
「ST_Boundary(geom)」ではなく「ST_Boundary(ST_SnapToGrid(geom、0.001))」が問題を解決します。
eclipsed_by_the_moon

6

両方のポリゴンのノードセットが異なるため(緑のポリゴンA、赤の異なるポリゴンBのセグメント)、少し注意が必要だと思います。両方のポリゴンのセグメントを比較すると、ポリゴンBのどのセグメントが修正されるかがわかります。

ノードポリゴンA

ポリA

「異なる」セグメントポリゴンBのノード

seg diff

残念ながら、これはセグメント構造の違いのみを示していますが、それが出発点であり、次のように機能することを願っています:

ダウンロードして解凍した後、Debian Linux JessieでPostgrSQL 9.46、PostGIS 2.1を使用してコマンドを使用してデータセットをインポートしました。

$ createdb gis-se
$ psql gis-se < /usr/share/postgis-2.1/postgis.sql
$ psql gis-se < /usr/share/postgis-2.1/spatial_ref_sys.sql
$ shp2pgsql -S polygon_a | psql gis-se
$ shp2pgsql -S polygon_b | psql gis-se

ポリゴンAのセグメントがBではなく、その逆であると仮定して、各グループ(AまたはB)のポリゴンへのセグメントメンバーシップを無視して、両方のポリゴンセットのセグメント間の差を構築しようとします。教訓的な理由から、いくつかのビューでSQLを作成します。

これに対応GIS-SEポスト、私は、セグメントテーブルにポリゴンの両方を分解segments_aし、segments_b

-- Segments of the polygon A
CREATE VIEW segments_a AS SELECT sp, ep
FROM
   -- extract the endpoints for every 2-point line segment for each linestring
   (SELECT
      ST_PointN(geom, generate_series(1, ST_NPoints(geom)-1)) as sp,
      ST_PointN(geom, generate_series(2, ST_NPoints(geom)  )) as ep
    FROM
    -- extract the individual linestrings
     (SELECT (ST_Dump(ST_Boundary(geom))).geom
      FROM polygon_a
     ) AS linestrings
    -- be sure that nothing is scrambled
    ORDER BY sp, ep
) AS segments;

セグメントテーブルポリゴンA:

SELECT 
  st_astext(sp) AS sp, 
  st_astext(ep) AS ep 
FROM segments_a 
LIMIT 3;
                    sp                     |                 ep
-------------------------------------------+--------------------------------------------
POINT(-292.268907321861 95.0342877387557)  | POINT(-287.118411917425 99.4165242769195)
POINT(-287.118411917425 99.4165242769195)  | POINT(-264.62129248575 93.2470010145007)
POINT(-277.459563916327 -44.5629543976138) | POINT(-292.268907321861 95.03428773875

同じ手順がポリゴンBに適用されました。

-- Segments of the polygon B
CREATE VIEW segments_b AS SELECT sp, ep
FROM
   -- extract the endpoints for every 2-point line segment for each linestring
   (SELECT
      ST_PointN(geom, generate_series(1, ST_NPoints(geom)-1)) as sp,
      ST_PointN(geom, generate_series(2, ST_NPoints(geom)  )) as ep
    FROM
    -- extract the individual linestrings
     (SELECT (ST_Dump(ST_Boundary(geom))).geom
      FROM polygon_b
     ) AS linestrings
    -- be sure that nothing is scrambled
    ORDER BY sp, ep
) AS segments;

セグメントテーブルポリゴンB

SELECT
  st_astext(sp) AS sp, 
  st_astext(ep) AS ep 
FROM segments_b 
LIMIT 3;
                    sp                     |                    ep
-------------------------------------------+-------------------------------------------
POINT(-292.268907321861 95.0342877387557)  | POINT(-287.118411917425 99.4165242769195)
POINT(-287.118411917425 99.4165242769195)  | POINT(-264.62129248575 93.2470010145007)
POINT(-277.459563916327 -44.5629543976138) | POINT(-292.268907321861 95.0342877387557)
...                        

という名前の差分テーブルビューを作成できますsegments_diff_{a,b}。違いは、セグメントセットAおよびBでソートされた開始点または終了点が発生しないことによって与えられます。

CREATE VIEW segments_diff_a AS
SELECT st_makeline(b.sp, b.ep) as geom
FROM segments_b as b
LEFT JOIN segments_a as a ON (a.sp=b.sp and a.ep = b.ep)
-- filter segments without corresponding stuff in polygon A
WHERE a.sp IS NULL;

segs diff b

そして補足的なもの:

CREATE VIEW segments_diff_b AS
SELECT st_makeline(a.sp, a.ep) as geom
FROM segments_a as a
LEFT JOIN segments_b as b ON (a.sp=b.sp and a.ep = b.ep)
-- filter segments without corresponding stuff in polygon B
WHERE b.sp IS NULL;

segs diff a

結論:赤い矢印でマークした小さな小さなセグメントに対して適切な結果を得るには、両方のポリゴンのノード構造が同じである必要があり、ノードレベルでの交差ステップ(BにポリゴンAの頂点を挿入)が必要です。交差点は次の方法で実行できます。

CREATE VIEW segments_bi AS 
SELECT distinct sp, ep
FROM (
 SELECT
      ST_PointN(geom, generate_series(1, ST_NPoints(geom)-1)) as sp,
      ST_PointN(geom, generate_series(2, ST_NPoints(geom)  )) as ep
 FROM (
   SELECT st_difference(b.seg, a.seg) as geom FROM 
      segments_diff_a as a, segments_diff_b as b 
      WHERE st_intersects(a.seg, b.seg)
    ) as cut
  ) as segments
  WHERE sp IS NOT NULL AND ep IS NOT NULL
ORDER BY sp, ep;

しかし、奇妙な結果が...

カット版


あなたの努力に感謝します。さて、結果は奇妙です。:ST_HausdorffDistanceは()の質問に答えるのに役立つ可能性がある場合、私はちょうど疑問に思うgis.stackexchange.com/questions/180593/...
ルナ海

ええと、st_haudorffdistanceは、必要なセグメントではなく、類似性の尺度を示します(赤い矢印が指す)。
huckfinn

これは単なるアイデアです。ST_HausdorffDistanceを使用して、両方のテーブルのジオメトリを比較できます。ポリゴンが空間的に等しくない場合、ラインを作成します。これを行う方法がわかりません。
月の海

精度とトポロジ(の問題であるように思わgis.stackexchange.com/a/182838/26213webhelp.esri.com/arcgisdesktop/9.2/...
huckfinn

1

この例を見ると、変更は、変更された新しいテーブルの機能が常に古いテーブルの機能と重複することを意味します。したがって、あなたはで行われます

ST_Overlaps(geoma、geomb)AND!ST_Touches(geoma、geomb)

タッチの否定は、境界のみが同じ頂点位置を共有する場合、フィーチャも重複するためです。

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