Hợp nhất bất kỳ và tất cả các đa giác liền kề


22

Tôi muốn thực hiện các thử nghiệm kề trên một lớp bưu kiện (đa giác) và hợp nhất chúng nếu chúng phù hợp với các tiêu chí nhất định (có thể là kích thước). Theo hình dưới đây, tôi muốn hợp nhất các đa giác 1,2,3 và 4, nhưng không phải là 5.

Tôi có hai vấn đề:

  1. ST_TOUCHEStrả về TRUE nếu chỉ các góc chạm và không phải là một đoạn thẳng. Tôi nghĩ rằng tôi cần ST_RELATE để kiểm tra các phân đoạn dòng được chia sẻ.
  2. Lý tưởng nhất, tôi muốn hợp nhất TẤT CẢ các đa giác liền kề thành một, nhưng tôi không chắc chắn làm thế nào để vượt quá hai - như trong, hợp nhất 1,2,3 và 4 (và có thể nhiều hơn trên dữ liệu thực tế) trong một vòng.

Cấu trúc tôi có bây giờ dựa trên tự tham gia ST_TOUCHES.

nhập mô tả hình ảnh ở đây

Dữ liệu đồ chơi

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 ;

Lựa chọn

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

Đây là đầu ra:

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

Lưu ý rằng đa giác id = 3 chia sẻ một điểm với id = 1 và do đó được trả về là kết quả dương. Nếu tôi thay đổi mệnh đề WHERE thành ST_Touches( t1.geom, t2.geom ) AND t1.geom && t2.geom AND ST_Relate(t1.geom, t2.geom ,'T*T***T**');tôi không nhận được hồ sơ nào cả.

  1. Vì vậy, trước tiên , làm cách nào để chỉ định ST_Relate để đảm bảo chỉ các bưu kiện chia sẻ một đoạn đường được xem xét.

  2. Và sau đó, làm cách nào để hợp nhất các đa giác 1,2,3,4 trong một vòng, thu gọn kết quả từ cuộc gọi trên, tất cả trong khi nhận ra rằng kề 1 đến 2 giống như ngược lại?

Cập nhật

Nếu tôi thêm điều này vào wheremệnh đề, rõ ràng tôi chỉ nhận được đa giác chứ không phải đa bội, do đó loại bỏ các kết quả dương tính giả cho mục đích của tôi - các góc chạm sẽ bị bỏ qua.

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

Mặc dù điều này không lý tưởng (tôi muốn sử dụng kiểm tra cấu trúc liên kết với ST_RELATEtư cách là một giải pháp tổng quát hơn), nhưng đó là một cách tiến về phía trước. Sau đó, vẫn là vấn đề khử và hợp nhất những điều này. Có thể, nếu tôi có thể tạo ra một chuỗi chỉ chạm vào đa giác, tôi có thể kết hợp với nó.

Cập nhật II

Cái này dường như hoạt động để chọn các đường chia sẻ đa giác (nhưng không phải là các góc) và do đó là một giải pháp tổng quát hơn so với MULTIPOLYGONthử nghiệm trên . Mệnh đề where của tôi bây giờ trông như thế này:

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

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

Bây giờ, những gì còn lại vẫn là làm thế nào để hợp nhất không chỉ là một cặp đa giác, mà là một con số tùy ý phù hợp với tiêu chí, trong một lần.


2
Tôi chắc chắn ST_Relate là cách chính xác. Tôi đã giải quyết một vấn đề tương tự bằng cách kiểm tra xem độ dài của các giao điểm lớn hơn 0 để loại trừ các giao điểm đơn lẻ. Một hack, nhưng hoạt động.
John Powell

Nếu có một cách để nhóm các đa giác liền kề nhau thành các mảng, thì bạn có thể sửa đổi ST_IntersectionArray[hàm] [1] để hoạt động với ST_Union [1]: gis.stackexchange.com/a/60295/38886
raphael

2
Về việc nhóm các đa giác liền kề nhau, bạn có thể sửa đổi thuật toán phân cụm từ dưới lên mà tôi đã viết ở đây ( gis.stackexchange.com/a/115715/36886 ) để kiểm tra tính phụ thuộc thay vì không gian và sau đó sử dụng ST_Union trong khi nhóm trên cụm kết quả
raphael

3
Ngoài ra còn có ST_ClusterIntersectimg có thể làm những gì bạn cần. Bạn cần Postgis 2.2
John Powell

Câu trả lời:


3

Tôi không thể nghĩ rằng ví dụ của bạn thực sự là một raster và mặc dù bạn đã đề cập rằng bạn muốn hợp nhất dựa trên "các tiêu chí nhất định (có thể là kích thước)" Tôi muốn đưa ra một cú đánh với chuyển đổi raster.

Đối với ví dụ cụ thể của bạn, điều này sẽ làm việc:

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)

Điều gì xảy ra là vì đa giác của bạn là các ô được căn chỉnh hoàn hảo, chúng sẽ chuyển đổi độc đáo thành raster (kích thước 10 x20). Các dumpaspolygons giúp bạn ở đây bằng cách hợp nhất tất cả các ô liền kề thành một và bằng cách so sánh với các đa giác ban đầu, bạn thậm chí sẽ có thể lấy lại id cho các poly không hợp nhất.

Đã giải thích điều này, tôi rất tò mò làm thế nào điều này sẽ mở rộng quy mô và dữ liệu của bạn lớn như thế nào: D


Ý tưởng thông minh. Tuy nhiên, đây là một ví dụ về đồ chơi - dữ liệu thực tế của tôi là một lớp bưu kiện sẽ không được ánh xạ gọn gàng đến các trình quét.
ako

3

Dưới đây là một ví dụ về cách thực hiện việc này theo kiểu thủ tục với nhiều đường chuyền dưới mui xe.

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

Bạn sẽ có thể mang theo nhiều cột hơn và áp dụng các tiêu chí bổ sung để tham gia bằng cách sửa đổi cách LIMIT 1chọn bên dưới hoạt động:

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;

Chạy điều:

SELECT reduce_joined_testpoly();

Công đoàn phù hợp, không có đa nhân cách:

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

Đây là một chiến lược khác (không hoạt động) để tham khảo (mà tôi không thể loại trừ trường hợp điểm chạm đơn lẻ). Nó sẽ nhanh hơn câu trả lời khác của tôi vì nó chỉ mất 'một lần'.

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;

(vui lòng sửa đổi và đăng câu trả lời khác nếu bất kỳ ai cũng có thể nhận id = 5 hình học trong nhóm riêng của mình)

Để lấy lại danh sách id, v.v. bạn phải sử dụng st_containsđể tham gia lại trên bảng testpoly như chi tiết trong câu trả lời sau: /programming//a/37486732/6691 nhưng tôi không thể làm việc đó cho đa giác vì một số lý do.


2

Đây là một cú đâm nhanh vào nó bằng cách sử dụng truy vấn ban đầu của bạn được điều chỉnh một chút:

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;

Tài liệu tham khảo: https://postgis.net/docs/USE_postgis_dbmanloyment.html#DE-9IM

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.