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 토폴로지를 많이 사용하지 않았으며 직접 답변을 줄 수는 없지만 더 자세히 살펴볼 것을 제안합니다.
토마스

흥미롭게도 다운로드 할 데이터 세트의 예가 있습니까?
Huckfinn

답변:


10

다음을 사용하여 몇 가지 새로운 트릭이 있습니다.

  • EXCEPT동일한 테이블 중 하나에서 형상을 제거하기 위해 각 테이블 ( A_onlyB_only)에 고유 한 형상에만 초점을 맞출 수 있습니다 .
  • ST_Snap 오버레이 연산자에 대한 정확한 고개를 끄덕입니다.
  • ST_SymDifference오버레이 연산자를 사용하여 두 형상 세트 간의 대칭 차이 를 찾아 차이 를 표시하십시오. 업데이트 : 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 지오메트리로 이동합니다 . 이러한 기능을 사용하는 방법에는 여러 가지가있을 수 있지만 각 형상에서 서로 정확한 좌표를 얻는 것이 좋습니다. 스냅 후 두 도형은 다음과 같습니다.

스냅 B 스냅

그리고 차이보기에, 당신이 중 하나를 선택하여 사용할 수 있습니다 ST_SymDifference또는 ST_Difference. 둘 다이 예제에서 동일한 결과를 보여줍니다.


좋은 대답입니다. 중개 쿼리 결과를 시각화하는 데 사용한 것이 궁금합니다. 그것은 즉시 qgis처럼 보이지 않았으며, 아마도 조금 더 빨리 렌더링되는 것일까 요?
RoperMaps

1
JTS Testbuilder를 사용하여 지오메트리를보고 처리합니다. GEOS 및 Shapely와 관련된 지오메트리 엔진이지만 Java 기반 GUI가 있습니다.
Mike 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

폴리

"다른"세그먼트의 노드 다각형 B

세그 디프

불행히도 이것은 세그먼트 구조의 차이점 만 보여 주지만 이것이 출발점이며 다음과 같이 작동하기를 바랍니다.

다운로드 및 압축 해제 프로세스 후 데비안 리눅스 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/…
Lunar Sea

흠, st_haudorffdistance는 원하는 세그먼트 (빨간색 화살표가 가리키는)가 아닌 유사성 측정을 제공합니다.
huckfinn

ST_HausdorffDistance를 사용하여 두 테이블의 형상을 비교할 수 있습니다. 다각형이 공간적으로 동일하지 않은 경우 선을 만들어야합니다. 나는 이것을하는 법을 모른다.
Lunar Sea

정확성과 토폴로지의 문제인 것 같습니다 ( gis.stackexchange.com/a/182838/26213webhelp.esri.com/arcgisdesktop/9.2/… )
huckfinn

1

예를 보면 변경 사항은 변경된 새 테이블의 기능이 항상 이전 테이블의 기능과 겹치는 것을 의미합니다. 따라서 당신은 함께 할 것입니다

ST_Overlaps (geoma, geomb) 및! ST_Touches (geoma, geomb)

접촉에 대한 부정은 경계가 동일한 정점 위치를 공유하는 경우 형상도 겹치기 때문입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.