인접한 다각형을 모두 병합


22

필지 (폴리곤) 레이어에서 인접성 테스트를 수행하고 특정 기준 (크기 일 수 있음)에 맞으면 병합합니다. 아래 그림에 따라 다각형 1, 2, 3 및 4는 병합하지만 5는 병합 하지 않습니다 .

두 가지 문제가 있습니다.

  1. ST_TOUCHES모서리 만 터치하고 선 세그먼트가 아닌 경우 TRUE를 반환합니다. 공유 선 세그먼트를 확인하려면 ST_RELATE가 필요하다고 생각합니다.
  2. 이상적으로는 인접한 모든 다각형을 하나로 병합하고 싶지만 한 라운드에서 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를 한 라운드에 병합하여 위의 호출 결과를 접는 방법은 무엇입니까?

최신 정보

이것을 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가 올바른 방법이라고 확신합니다. 단일 점 교차를 제외하기 위해 교차 길이가 0보다 큰지 확인하여 비슷한 문제를 해결했습니다. 해킹이지만 작동합니다.
John Powell

연속 다각형을 배열로 그룹화하는 방법이 있다면 ST_IntersectionArrayST_Union [1]과 함께 작동 하도록 [function] [1]을 수정할 수 있습니다 . gis.stackexchange.com/a/60295/36886
raphael

2
그룹화 함께 연속 다각형에 관해서는, 당신은 내가 여기에 쓴 상향식 (bottom-up) 클러스터링 알고리즘 (수정할 수 gis.stackexchange.com/a/115715/36886을 인접보다는 공간을 테스트) 후 결과 cluster_ids 그룹화 동안 ST_Union은을 사용하여
raphael

3
ST_ClusterIntersectimg도있어 원하는 작업을 수행 할 수 있습니다. Postgis 2.2
John Powell

답변:


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는 인접한 모든 셀을 하나로 병합하고 원래 다각형과 비교하여 병합되지 않은 폴리의 ID를 다시 가져올 수도 있습니다.

이것을 설명하면서, 이것이 어떻게 확장되고 데이터 세트가 얼마나 큰지 궁금합니다. : D


영리한 아이디어. 실제 장난감은 래스터에 깔끔하게 매핑되지 않는 소포 레이어입니다.
ako

3

다음은 후드 아래에 여러 패스가있는 절차 스타일로이를 수행하는 방법의 예입니다.

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

LIMIT 1아래 의 select가 작동 하는 방식을 수정하여 더 많은 열을 수행하고 추가 결합 기준을 적용 할 수 있어야 합니다.

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

다음은 참조 용으로 작동하지 않는 다른 전략입니다 (단일 터치 포인트 사례를 제외 할 수 없음). '한 번의 통과'만으로 다른 답변보다 빠릅니다.

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 지오메트리를 얻을 수 있다면 다른 답변을 수정하고 게시하십시오)

ID 목록 등을 다시 얻으려면 st_contains다음 답변에 설명 된대로 testpoly 테이블에 다시 참여해야합니다 : https : //.com/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.