PostGISでポリゴンのドリルダウン/オーバーレイを実行しますか?


8

PostGISで頭を一周できないような課題に直面しています。私はプログラミング言語を使用してこれを解決できることを知っています(そしてそれは私のバックアップ計画です)が、私はPostGISでこれを解決したいのです。検索を試みましたが、問題と一致する回答が見つかりませんでした。これは、検索語句がわからないことが原因である可能性があります。そのため、申し訳ありませんが、正しい方向に向けてください。

私の問題はこれです:

  • ポリゴン/マルチポリゴンが混在するテーブルがあります
  • 各(マルチ)ポリゴンには、ランク付けする属性(優先度)があります。
  • 各ポリゴンには、知りたい値もあります。
  • 検索エリア(ポリゴン)があります
  • 私のクエリ領域では、各ポリゴン値によってカバーされる領域を見つけたい

例:

ここに赤、緑、藍で描かれた3つのポリゴンがあるとします。 例

そして、小さな青い長方形は私のクエリポリゴンです

さらに、属性は

geom   | rank | value
-------|------|----  
red    |  3   | 0.1
green  |  1   | 0.2
indigo |  2   | 0.2

私が欲しいのは、これらのジオメトリを選択して、最高ランク(緑)が可能なすべての領域(つまり、クエリgeomとそのgeomの交点)を埋め、次に次に高い(インディゴ)がクエリジオメトリの交点を埋めるようにすることです。およびgeom MINUSはすでにカバーされています)など。

このようなもの: ここに画像の説明を入力してください

私はこの質問を見つけました:ST_Differenceを使用して重複するフィーチャを削除しますか?しかし、それは私が望んでいるようには見えません。

エリアなどの計算方法を自分で理解できるので、2番目の画像に示されている3つのジオメトリを取得するクエリは問題ありません。

追加情報:-これは大きなテーブルではありません(〜2000行)-重複がゼロまたは複数(3つだけではない)の可能性があります-クエリ領域(またはその一部)にポリゴンがない可能性があります-私はm postgres 9.6.6でpostgis 2.3を実行

私のフォールバックソリューションは、次のようなクエリを実行することです。

SELECT 
ST_Intersection(geom, querygeom) as intersection, rank, value
FROM mytable
WHERE ST_Intersects(geom, querygeom)
ORDER by rank asc

そして、コードのジオメトリの一部を繰り返し「切り落とす」。しかし、私が言ったように、私は本当にこれをPostGISで実行したいと思います


2
現時点では答えを出すことはできませんが、自分で試してみたい場合は、WITH RECURSIVE ...CTE(ドキュメントと一般的なチュートリアル)を探しています
geozelot

1
ああ、これ
geozelot 2018

ありがとう!完全な解決策を提供することを強いられる人が他にいないと感じた場合は、明日これを試します。
atlefren

回答:


7

これはうまくいくと思います。

これはウィンドウ関数であり、クエリボックスとの各ジオメトリの交差の交差と、先行するジオメトリの結合の差を取得します。

最初のジオメトリの先行するジオメトリの結合はnullであり、希望するものではなくnullの結果が得られるため、合体が必要です。

WITH a(geom, rank, val) AS
(
    VALUES
    ('POLYGON((1 1, 1 5, 5 5, 5 1, 1 1))'::geometry,3,0.1),
    ('POLYGON((2 3, 2 8, 4 8, 5 3,2 3))'::geometry,1,0.2),
    ('POLYGON((4 4, 4 6, 6 6, 6 4,4 4))'::geometry,2,0.2)
)
,q AS
(
    SELECT 'POLYGON((3 3, 3 4.5, 12 4.5,12 3, 3 3))'::geometry geom
) 
SELECT 
  ST_Difference(
    ST_Intersection(a.geom, q.geom), 
    COALESCE(ST_Union(a.geom) 
           OVER (ORDER BY rank ROWS BETWEEN UNBOUNDED PRECEDING and 1 PRECEDING),
       'POLYGON EMPTY'::geometry)
  ) geom 
FROM a,q
WHERE ST_Intersects(a.geom, q.geom);

それがどのように機能するかはわかりません。ただし、ST_UnionとST_Intersectionの両方が不変としてマークされているため、それほど悪くはないかもしれません。


これは魅力のように働きました!空のgeometrycollectionsを削除するには、クエリを別のクエリでラップする必要があります
atlefren

5

これに対する少し異なるアプローチ。パフォーマンスがどのように向上するかはわかりませんが、インデックス付きのテーブルでは問題ないという警告があります。Nicklasのクエリとほぼ同じように動作します(少し遅いですか?)。ただし、このような小さなサンプルの測定には問題があります。

Nicklasのクエリよりも醜く見えますが、クエリの再帰は回避されます。

WITH 
    a(geom, rank, val) AS
    (
        VALUES
        ('POLYGON((1 1, 1 5, 5 5, 5 1, 1 1))'::geometry,3,0.1),
        ('POLYGON((2 3, 2 8, 4 8, 5 3, 2 3))'::geometry,1,0.2),
        ('POLYGON((4 4, 4 6, 6 6, 6 4, 4 4))'::geometry,2,0.2)
    ),
    polygonized AS (
        -- get the basic building block polygons
        SELECT (ST_Dump(         -- 5. Dump out the polygons
            ST_Polygonize(line)) -- 4. Polygonise the linework
            ).geom AS mypoly
        FROM (
            SELECT 
                ST_Node(                  -- 3. Node lines on intersection
                    ST_Union(             -- 2. Union them for noding
                        ST_Boundary(geom) -- 1. Change to linestrings
                    ) 
                ) 
                AS line
            FROM a
        ) line
    ),
    overlayed AS ( 
        -- Overlay with original polygons and get minimum rank.
        -- Union and dissolve interior boundaries for like ranks.
        SELECT (ST_Dump(ST_UnaryUnion(geom))).geom, rank 
        FROM ( 
            -- union up the polygons by rank, unary union doesn't count as an aggregate function?
            SELECT ST_Union(mypoly) geom, rank 
            FROM ( 
                -- get the minimum rank for each of the polygons
                SELECT p.mypoly, min(rank) rank
                FROM polygonized p 
                    INNER JOIN a ON ST_Contains(a.geom,ST_PointOnSurface(p.mypoly))
                GROUP BY p.mypoly
                ) g
            GROUP BY rank
            ) r
    )
-- get the intersection of the query area with the overlayed polygons
SELECT ST_Intersection(o.geom,'POLYGON((3 3, 3 4.5, 12 4.5,12 3, 3 3))'::Geometry), rank
FROM overlayed o
WHERE ST_Intersects(o.geom,'POLYGON((3 3, 3 4.5, 12 4.5,12 3, 3 3))'::Geometry) and
    -- Intersection can do funky things
    GeometryType(ST_Intersection(o.geom,'POLYGON((3 3, 3 4.5, 12 4.5,12 3, 3 3))'::Geometry)) like '%POLYGON';

1

私はバブリングしたので、それをWITH RECURSIVE使って素早く汚い答えを追加します。

これは、3つのポリゴンで@NicklasAvénのソリューションとほぼ同じように実行され、アップスケールされたときにテストできませんでした。
両方の溶液が立つように、この一方が他方の上に一つの小さな利点を有する:例えば、ポリゴンを用いている場合、ランク= 2のものに含まれるランク= 1...WHERE GeometryType = 'POLYGON'そうでない場合はしばらくそこになることフィルタがGEOMETRYCOLLECTION EMPTY(私は、ジオメトリを変更しました例として、私のソリューション内のそれぞれのポリゴンの例を示します。これは、差異との交差が見つからない他の場合にも当てはまります)。ただし、これは他のソリューションに簡単に組み込むことができ、問題になることもありません。

WITH RECURSIVE
    a(geom, rank, val) AS (
        VALUES
           ('POLYGON((1 1, 1 5, 5 5, 5 1, 1 1))'::geometry,3,0.1),
           ('POLYGON((2 3, 2 8, 4 8, 5 3,2 3))'::geometry,1,0.2),
           ('POLYGON((2.1 3.1, 2.1 7.9, 3.9 7.9, 4.9 3.1,2.1 3.1))'::geometry,2,0.2)
    ),
    q AS (
        SELECT 'POLYGON((3 3, 3 4.5, 12 4.5,12 3, 3 3))'::geometry geom
    ),
    src AS (
        SELECT ROW_NUMBER() OVER(ORDER BY rank) AS rn,
               ST_Intersection(q.geom, a.geom) AS geom,
               rank,
               val
        FROM a
        JOIN q
           ON ST_Intersects(a.geom, q.geom)
    ),
    res AS (
        SELECT s.geom AS its,
               ST_Difference(q.geom, s.geom) AS dif,
               s.rank,
               s.val,
               2 AS icr
        FROM src AS s,
             q
        WHERE s.rn = 1
        UNION ALL
        SELECT ST_Intersection(s.geom, r.dif) AS its,
               ST_Difference(r.dif, s.geom) AS dif,
               s.rank,
               s.val,
               icr + 1 AS icr
        FROM src AS s,
             res AS r
        WHERE s.rank = r.icr
    )

SELECT its AS geom,
       rank,
       val
FROM res
WHERE GeometryType(its) = 'POLYGON'
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.