Làm cách nào để tạo các dòng để trực quan hóa sự khác biệt giữa các tính năng đa giác trong PostGIS?


15

Tôi có một bảng PostGIS polygon_bvới một số tính năng đa giác. Ngoài ra còn có một bảng polygon_achứa các đa giác giống như polygon_bnhưng với những thay đổi nhỏ. Bây giờ tôi muốn tạo các dòng để hình dung sự khác biệt giữa các tính năng đa giác.

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

Tôi cho rằng ST_ExteriorRingST_Differencesẽ thực hiện công việc nhưng mệnh đề WHERE có vẻ khá khó khăn.

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;

Ai giúp tôi với?

CHỈNH SỬA 1

Như được đăng bởi 'tilt' tôi đã thử ST_Overlaps(polygon_a.geom, polygon_b.geom) AND NOT ST_Touches(polygon_a.geom, polygon_b.geom)nhưng kết quả không như mong đợi.

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;

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

CHỈNH SỬA 2

workupload.com/file/J0WBvRBb (tập dữ liệu mẫu)


Tôi đã cố gắng biến đa giác thành đa tuyến trước khi sử dụng ST_Difference, nhưng kết quả vẫn còn lạ.

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;

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


Trông giống như một câu hỏi tô pô. Bạn muốn xác định các phân đoạn không được bao phủ bởi lớp khác. Tôi đã không làm việc nhiều với cấu trúc liên kết PostGIS và không thể cho bạn câu trả lời trực tiếp nhưng tôi khuyên bạn nên tìm hiểu thêm về vấn đề này.
Thomas

Thật thú vị, bạn có một tập dữ liệu mẫu để tải xuống không?
huckfinn

Câu trả lời:


10

Dưới đây là một vài thủ thuật mới, sử dụng:

  • EXCEPTđể xóa hình học khỏi một trong hai bảng giống nhau, vì vậy chúng ta chỉ có thể tập trung vào hình học duy nhất cho mỗi bảng ( A_onlyB_only ).
  • ST_Snap để có được mã hóa chính xác cho các toán tử lớp phủ.
  • Sử dụng ST_SymDifferencetoán tử lớp phủ để tìm sự khác biệt đối xứng giữa hai bộ hình học để hiển thị sự khác biệt. Cập nhật : ST_Differencehiển thị kết quả tương tự cho ví dụ này. Bạn có thể thử một trong hai chức năng để xem những gì họ nhận được.

Điều này sẽ nhận được những gì bạn mong đợi:

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

ba dòng


Để giải nén câu trả lời này thêm một chút, bước đầu tiên với ST_Boundaryranh giới của mỗi đa giác, thay vì chỉ bên ngoài. Ví dụ, nếu có lỗ hổng, chúng sẽ được vạch ra bởi ranh giới.

Các EXCEPTkhoản được sử dụng để loại bỏ hình học từ A là một phần của B, và các hàng từ B là một phần của A. Điều này làm giảm số lượng hàng là một phần của A mà thôi, và một phần của chỉ B. Ví dụ: để nhận A_only:

SELECT ST_Boundary(geom) geom FROM polygon_a
EXCEPT SELECT ST_Boundary(geom) geom FROM polygon_b

Dưới đây là 6 hàng A_only và 3 hàng B_only: A_only B_only

Kế tiếp, ST_Union(DISTINCT A_only.geom) được sử dụng để kết hợp các đường kẻ thành một hình học duy nhất, điển hình là MultiLineString.

ST_Snap được sử dụng để chụp các nút từ hình này sang hình khác. Chẳng hạn, ST_Snap(A, B, tol)sẽ lấy hình học A và thêm nhiều nút từ hình học B hoặc di chuyển chúng sang hình dạng B, nếu chúng nằm trong tolkhoảng cách. Có thể có một số cách để sử dụng các hàm này, nhưng ý tưởng là lấy tọa độ từ mỗi hình học chính xác với nhau. Vì vậy, hai hình học sau khi chụp trông như thế này:

Một cái búng tay B gãy

Và để thấy sự khác biệt, bạn có thể chọn để sử dụng một trong hai ST_SymDifferencehoặc ST_Difference. Cả hai đều cho thấy kết quả tương tự cho ví dụ này.


Câu trả lời tốt đẹp. Tôi tự hỏi những gì bạn đã sử dụng để hình dung kết quả của các truy vấn trung gian của bạn. Nó không giống như qgis ngay lập tức, và có lẽ tôi là thứ gì đó nhanh hơn một chút?
RoperMaps

1
Tôi sử dụng JTS Testbuilder để xem và xử lý hình học. Đây là một công cụ hình học có liên quan đến GEOS và Shapely, nhưng có GUI dựa trên Java.
Mike T

Có cách nào để bỏ qua / bỏ qua 'Giao lộ không gật đầu giữa các vấn đề LINESTRING' không? Tất cả các đa giác đầu vào dường như đều ổn (được kiểm tra bằng trình kiểm tra hình học QGIS).
lu mờ_by_the_moon

1
'ST_Boundary (ST_SnapToGrid (geom, 0,001))' thay vì 'ST_Boundary (geom)' giải quyết vấn đề.
lu

6

Tôi nghĩ rằng nó là một chút khó khăn, bởi vì các tập hợp nút khác nhau của cả hai đa giác của bạn (đa giác màu xanh lá cây A, các phân đoạn đa giác B màu đỏ khác nhau). So sánh các phân đoạn của cả hai đa giác cho một manh mối mà các phân đoạn của đa giác B sẽ được sửa đổi.

Nút đa giác A

nhiều a

Các nút của đa giác phân đoạn "khác nhau"

khác biệt

Thật không may, điều này chỉ cho thấy sự khác biệt trong cấu trúc phân khúc, nhưng tôi hy vọng nó là điểm khởi đầu và nó hoạt động như thế này:

Sau quá trình tải xuống và giải nén, tôi đã nhập bộ dữ liệu bằng PostgrSQL 9.46, PostGIS 2.1 trong Debian Linux Jessie với các lệnh.

$ 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

Giả sử rằng các phân đoạn của đa giác A không nằm trong B và ngược lại, tôi cố gắng xây dựng sự khác biệt giữa các phân đoạn của cả hai tập hợp đa giác, bỏ qua tư cách thành viên phân đoạn cho đa giác trong mỗi nhóm (A hoặc B). Vì các lý do mô phạm, tôi xây dựng các công cụ SQL trong một số khung nhìn.

Tương ứng với bài viết về GIS-SE này , tôi phân tách cả hai đa giác thành các bảng phân đoạn segments_asegments_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;

Bảng phân đoạn đa giác 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

Quy trình tương tự đã được áp dụng cho đa giác 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ảng phân đoạn đa giác 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)
...                        

Tôi có thể xây dựng một khung nhìn bảng khác biệt được đặt tên segments_diff_{a,b}. Sự khác biệt được đưa ra bởi sự không xuất hiện của điểm bắt đầu hoặc điểm kết thúc được sắp xếp trong phân đoạn A và 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;

khác biệt b

Và các công cụ bổ sung:

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;

khác biệt a

Kết luận: Để có được kết quả phù hợp cho các phân đoạn nhỏ mà bạn đã đánh dấu bằng mũi tên màu đỏ, cả hai đa giác phải có cùng cấu trúc nút và bước giao nhau trên cấp độ nút (chèn đỉnh của đa giác A trong B) là bắt buộc. Giao lộ có thể được thực hiện bởi:

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;

Nhưng với kết quả kỳ lạ ...

phiên bản cắt


Cảm ơn những nỗ lực của bạn. Chà, kết quả thật lạ. Tôi chỉ tự hỏi liệu ST_HausdorffDistance () có thể giúp trả lời câu hỏi không: gis.stackexchange.com/questions/180593/ Lỗi
Biển Lunar

Hừm, st_haudorffdistance cung cấp cho bạn một thước đo tương tự không phải là các phân đoạn mong muốn (mũi tên đỏ chỉ vào).
huckfinn

Đó chỉ là một ý tưởng, ST_HausdorffDistance có thể được sử dụng để so sánh hình học của cả hai bảng. Các đa giác không bằng nhau về mặt không gian tôi sẽ tạo các dòng. Tôi chỉ không biết làm thế nào để làm điều này.
Biển âm lịch

Nó dường như là một vấn đề về độ chính xác và cấu trúc liên kết ( gis.stackexchange.com/a/182838/26213webhelp.esri.com/arcgisdesktop/9.2/ .)
huckfinn

1

Nhìn vào ví dụ, thay đổi ngụ ý rằng các tính năng từ bảng mới đã được thay đổi sẽ luôn là các tính năng chồng chéo từ bảng cũ. Vì vậy, bạn sẽ được thực hiện với

ST_Overlaps (geoma, geomb) VÀ! ST_Touches (geoma, geomb)

Sự phủ định khi chạm là bởi vì các tính năng cũng chồng lấp nếu chỉ đường viền của chúng có cùng vị trí đỉnh.

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.