Thực hiện thao tác khoan / phủ đa giác trong PostGIS?


8

Tôi đối mặt với một thách thức với PostGIS mà dường như tôi không thể quấn lấy đầu mình. Tôi biết tôi có thể giải quyết vấn đề này bằng ngôn ngữ lập trình (và đó là kế hoạch dự phòng của tôi), nhưng tôi thực sự muốn giải quyết vấn đề này trong PostGIS. Tôi đã thử tìm kiếm, nhưng không thể tìm thấy bất kỳ câu trả lời nào phù hợp với vấn đề của tôi, điều này có thể là do tôi không chắc chắn về các thuật ngữ tìm kiếm của mình, vì vậy xin vui lòng xin lỗi và chỉ cho tôi đi đúng hướng có câu trả lời.

Vấn đề của tôi là:

  • Tôi có một bảng với Đa giác hỗn hợp / MultiPolygons
  • Mỗi đa giác (đa) có một thuộc tính xếp hạng nó (ưu tiên)
  • Mỗi đa giác cũng có một giá trị tôi muốn biết
  • Tôi có một khu vực tìm kiếm (đa giác)
  • Đối với khu vực truy vấn của tôi, tôi muốn tìm khu vực được bao phủ bởi mỗi giá trị đa giác

Thí dụ:

Nói rằng tôi có ba đa giác được mô tả bằng màu đỏ, xanh lá cây và màu chàm ở đây: Thí dụ

Và hình chữ nhật nhỏ hơn, màu xanh là đa giác truy vấn của tôi

Ngoài ra, các thuộc tính là

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

Điều tôi muốn là chọn những hình học này, sao cho thứ hạng cao nhất (màu xanh lá cây) lấp đầy tất cả các khu vực có thể (tức là giao điểm giữa geom truy vấn của tôi và geom đó), sau đó cao nhất tiếp theo (màu chàm) lấp đầy giao điểm giữa geom truy vấn và geom MINUS đã được bảo hiểm) vv

Một cái gì đó như thế này: nhập mô tả hình ảnh ở đây

Tôi đã tìm thấy câu hỏi này: Sử dụng ST_Difference để xóa các tính năng chồng chéo? nhưng nó dường như không làm những gì tôi muốn.

Tôi có thể tự mình tìm ra cách tính các khu vực và như vậy, vì vậy một truy vấn cung cấp cho tôi ba hình học như được mô tả trong hình ảnh thứ hai là tốt!

Thông tin bổ sung: - Đây không phải là một bảng lớn (~ 2000 hàng) - có thể có 0 hoặc nhiều chồng chéo (không chỉ ba) - có thể không có bất kỳ đa giác nào trong khu vực truy vấn của tôi (hoặc chỉ trong các phần của nó) - i ' m đang chạy postgis 2.3 trên postgres 9.6.6

Giải pháp dự phòng của tôi là thực hiện một truy vấn như thế này:

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

Và sau đó lặp đi lặp lại "chặt" các phần của hình học trong mã. Nhưng, như tôi đã nói, tôi thực sự muốn làm điều này trong PostGIS


2
không thể cho bạn câu trả lời ngay bây giờ, nhưng nếu bạn sẵn sàng tự bắn: bạn đang tìm WITH RECURSIVE ...CTE ( tài liệuhướng dẫn chung )
Geozelot

1
oh và kiểm tra cái này
Geozelot

Cảm ơn! Tôi sẽ thử điều này vào ngày mai nếu không ai khác cảm thấy bắt buộc phải cung cấp một giải pháp hoàn chỉnh.
atlefren

Câu trả lời:


7

Tôi nghĩ rằng điều này làm việc.

Đây là một chức năng cửa sổ, nhận được sự khác biệt giữa giao điểm của mỗi giao điểm hình học với hộp truy vấn và liên kết của hình học trước đó.

Sự kết hợp là cần thiết vì sự kết hợp của các hình học trước cho hình học đầu tiên là null mang lại kết quả null, thay vì những gì mong muốn.

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

Tôi không chắc chắn làm thế nào nó thực hiện mặc dù. Nhưng vì cả ST_Union và ST_Intersection đều được đánh dấu là bất biến nên nó có thể không tệ đến vậy.


Điều này làm việc như một nét duyên dáng! Chỉ cần bọc truy vấn của bạn trong một truy vấn khác để xóa các hình học trống
atlefren

5

Một chút của một cách tiếp cận khác nhau về điều này. Có một cảnh báo mà tôi không biết làm thế nào nó sẽ tăng quy mô hiệu suất một cách khôn ngoan, nhưng trên một bảng được lập chỉ mục thì nó sẽ ổn. Nó thực hiện gần giống như truy vấn của Nicklas (chậm hơn một chút?), Nhưng phép đo trên một mẫu nhỏ như vậy là đầy đủ.

Nó trông xấu hơn nhiều so với truy vấn của Nicklas, nhưng nó tránh được đệ quy trong truy vấn.

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

Vì tôi bập bẹ về tôi, tôi WITH RECURSIVEsẽ thêm một câu trả lời nhanh và bẩn bằng cách sử dụng nó.

Điều này thực hiện tốt như giải pháp của @ NicklasAvén trên ba Đa giác, không thể kiểm tra khi được nâng cấp.
Khi cả hai giải pháp đều đứng vững, giải pháp này có một lợi ích nhỏ hơn so với giải pháp khác: ví dụ, nếu Đa giác có thứ hạng = 2 được chứa bởi xếp hạng = 1 , các ...WHERE GeometryType = 'POLYGON'bộ lọc sẽ xuất hiện trong khi nếu không sẽ có một GEOMETRYCOLLECTION EMPTY(tôi đã thay đổi hình học của Đa giác tương ứng trong giải pháp của tôi tương ứng để đưa ra một ví dụ, điều này cũng đúng với các trường hợp khác khi không tìm thấy giao điểm với sự khác biệt). Điều này dễ dàng được bao gồm trong các giải pháp khác, mặc dù, và thậm chí có thể không quan tâm.

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'
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.