Sử dụng ST_Difference để xóa các tính năng chồng chéo?


11

Tôi đang cố gắng sử dụng ST_Difference để tạo một tập hợp đa giác (process.trimmedparcelsnew) không chứa bất kỳ khu vực nào được bao phủ bởi một tập hợp đa giác khác (test.single_geometry_1) bằng PostGis 2.1 (và Postgres SQL 9.3). Đây là truy vấn của tôi:

CREATE TABLE processing.trimmedparcelsnew AS
SELECT
    orig.id, ST_Difference(orig.geom, cont.geom) AS difference
FROM 
    test.single_geometry_1 cont,
    test.multi_geometry_1 orig;

Nhưng các đa giác kết quả đã không được cắt, thay vào đó chúng dường như đã bị phân tách ở nơi chúng giao nhau với lớp khác. Tôi đã cố gắng chỉ chạy lựa chọn mà không đặt kết quả vào một bảng và mọi thứ khác tôi có thể nghĩ ra, nhưng dường như tôi không thể làm cho chức năng này hoạt động.

Tôi đã đính kèm một hình ảnh của kết quả

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


Sau khi nhận xét, tôi đã thử thêm mệnh đề WHERE. Tôi muốn các bưu kiện không có giao lộ và các khu vực giao nhau của các bưu kiện khác bị xóa (lớp test.single_geometry thể hiện sự ô nhiễm mà tôi muốn xóa khỏi bưu kiện của mình). Tôi đã thử một giao lộ nhưng tất nhiên tôi thực sự muốn các giao lộ không vì vậy bây giờ tôi đang thử một giao điểm. Tôi cũng đã thử thêm orig vào bảng của mình nhưng tài liệu về ST_Difference ( http://postgis.net/docs/ST_Difference.html ) không nói nó trả về hình học chính xác mà tôi cần (một hình học đại diện cho phần hình học A đó không giao nhau với hình học B), vì vậy tôi bối rối không biết tại sao tôi lại muốn đa giác ban đầu trong bảng của mình. Dù sao, đây là mã sửa đổi của tôi:

CREATE TABLE processing.trimmedparcelsnew AS
SELECT
    orig.id, ST_Difference(orig.geom, cont.geom) AS difference, orig.geom AS geom
FROM 
    test.single_geometry_1 cont,
    test.multi_geometry_1 orig
WHERE ST_Disjoint(orig.geom, cont.geom);

Theo câu trả lời của dbaston, giờ tôi đã thử:

CREATE TABLE processing.parcels_trimmed AS
SELECT id, COALESCE(ST_Difference(geom, (SELECT ST_Union(b.geom) 
                                         FROM test.single_geometry_1 b
                                         WHERE ST_Intersects(a.geom, b.geom)
                                         AND a.id != b.id)), a.geom)
FROM test.multi_geometry_1 a;

Kết quả của việc này chỉ là một bản sao của test.multi_geometry_1. Mặc dù bây giờ việc chia tách không còn xảy ra.

Tôi đã thử phiên bản trước, nhưng một lần nữa chỉ nhận được một bản sao của test.multi_geometry_1:

CREATE TABLE processing.parcels_trimmed_no_coalesce AS
SELECT id, COALESCE(ST_Difference(geom, (SELECT ST_Union(b.geom) 
                                         FROM test.single_geometry_1 b
                                         WHERE ST_Intersects(a.geom, b.geom)
                                         AND a.id != b.id)), a.geom)
FROM test.multi_geometry_1 a;

Tôi bắt đầu tự hỏi liệu có điều gì khác tôi đang làm sai không? Tuyên bố tố tụng là:

DROP TABLE IF EXISTS processing.parcels_trimmed_no_coalesce;

Và tôi đang chạy các truy vấn từ cửa sổ truy vấn SQL PostgreQuery và Openjump.

Câu lệnh tôi sử dụng để xem bảng là:

SELECT * FROM processing.parcels_trimmed_no_coalesce;

Để đơn giản hóa, bây giờ tôi đã giảm truy vấn này xuống chỉ còn:

SELECT id, COALESCE(ST_Difference(geom, (SELECT ST_Union(b.geom) 
                                         FROM test.geometriestocutagainst b
                                         WHERE ST_Intersects(a.geom, b.geom)
                                         AND a.id != b.id)), a.geom)
FROM test.geometriestocut a;

Điều này vẫn chỉ dẫn đến các đa giác ban đầu (test.geometriestocut) khi kết quả mong muốn là kết quả ban đầu được cắt bớt so với test.geometriestocutagainst.


Bạn đã không chỉ định một WHEREmệnh đề, vì vậy bạn có thể mở rộng đa thức trong bảng kết quả. Có bao nhiêu hàng trong trimmedparcelsnew?
Vince

Nếu bạn chỉ muốn sự khác biệt nơi chúng giao nhau, bạn có thể thử thêm WHERE ST_Intersects (orig.geom, cont.geom). Mặt khác, sự khác biệt của hai đa giác không giao nhau, là đa giác ban đầu.
John Powell

Có 24 hàng trong bưu kiện được cắt mới, tôi muốn sự khác biệt ngay cả khi chúng không giao nhau, vì vậy tôi có thể sửa rằng tôi cần sử dụng orig.geom trong bảng thay vì khác biệt không?
Mart

Một thử nghiệm rời rạc sẽ tạo ra sự mở rộng đa thức - mỗi tính năng trong cont xuất hiện một lần cho mỗi tính năng trong orig không trùng nhau và sự khác biệt sẽ không bao giờ thay đổi hình dạng đầu vào
Vince

Ok cảm ơn đã làm rõ, nhưng tôi vẫn không chắc tại sao mã gốc không hoạt động. Nếu ST_Difference (orig.geom, cont.geom) trả về hình học trong một không giao nhau với b, thì tại sao bảng chứa hình học phân chia thay vì hình học trong a không giao nhau b.
Mart

Câu trả lời:


14

Tự tham gia cho phép bạn hoạt động dựa trên mối quan hệ giữa các cặp của hai tính năng. Nhưng tôi không nghĩ rằng bạn quan tâm đến các cặp: đối với mỗi tính năng, bạn muốn vận hành mối quan hệ giữa tính năng đó và tất cả các tính năng khác trong tập dữ liệu của bạn. Bạn có thể thực hiện điều này với một biểu thức truy vấn con:

CREATE TABLE parcels_trimmed AS
SELECT id, ST_Difference(geom, (SELECT ST_Union(b.geom) 
                                FROM parcels b
                                WHERE ST_Intersects(a.geom, b.geom)
                                  AND a.id != b.id))
FROM parcels a;

Bạn có thể thấy một cái gì đó kỳ lạ trong kết quả, mặc dù. Bưu kiện không có bất kỳ sự chồng chéo nào đang bị bỏ hoàn toàn! Đó là bởi vì ST_Uniontổng hợp trên một tập bản ghi trống sẽ có NULL, và ST_Difference(geom, NULL)NULL. Để giải quyết vấn đề này, bạn cần phải thực hiện ST_Differencecuộc gọi của mình trong COALESCE:

CREATE TABLE parcels_trimmed AS
SELECT id, COALESCE(ST_Difference(geom, (SELECT ST_Union(b.geom) 
                                         FROM parcels b
                                         WHERE ST_Intersects(a.geom, b.geom)
                                         AND a.id != b.id)), a.geom)
FROM parcels a;

Điều này có nghĩa là nếu kết quả ST_DifferenceNULL, biểu thức kết hợp sẽ đánh giá về hình dạng ban đầu.

Truy vấn trên sẽ loại bỏ hoàn toàn các khu vực chồng chéo khỏi miền của bạn. Thay vào đó, nếu bạn muốn chọn một người chiến thắng, bạn có thể làm a.id < b.id, hoặc một số tiêu chí khác, thay vì a.id != b.id.


Cảm ơn đã phản hồi, thật không may, tôi gặp khó khăn khi làm việc này cho tôi, thay vào đó chỉ kết thúc với đa giác ban đầu (a). Tôi sẽ chỉnh sửa câu hỏi của tôi với nhiều thông tin hơn. Cảm ơn một lần nữa.
Mart

2

Tôi đã có vấn đề tương tự như bạn. Tôi không biết nếu bạn đã tìm thấy giải pháp cho vấn đề của mình, nhưng tôi đã sửa đổi câu trả lời được chấp nhận ở trên và tôi đã có được điều mình muốn.

CREATE TABLE parcels_trimmed AS
SELECT id, COALESCE(ST_Difference(geom, (SELECT ST_Collect(b.geom) 
                                         FROM parcels b
                                         WHERE ST_Intersects(a.geom, b.geom)
                                         )), a.geom)
FROM parcels a;

1

Tôi sử dụng ST_DifferenceAgg () từ các Addon PostGIS . Bạn phải hợp nhất hai bảng lại với nhau, có một mã định danh duy nhất và một chỉ mục trên cột hình học. Đây là một ví dụ ngắn:

WITH overlappingtable AS (
  SELECT 1 id, ST_GeomFromText('POLYGON((0 1, 3 2, 3 0, 0 1), (1.5 1.333, 2 1.333, 2 0.666, 1.5 0.666, 1.5 1.333))') geom
  UNION ALL
  SELECT 2 id, ST_GeomFromText('POLYGON((1 1, 3.8 2, 4 0, 1 1))')
  UNION ALL
  SELECT 3 id, ST_GeomFromText('POLYGON((2 1, 4.6 2, 5 0, 2 1))')
  UNION ALL
  SELECT 4 id, ST_GeomFromText('POLYGON((3 1, 5.4 2, 6 0, 3 1))')
  UNION ALL
  SELECT 5 id, ST_GeomFromText('POLYGON((3 1, 5.4 2, 6 0, 3 1))')
)
SELECT a.id, ST_DifferenceAgg(a.geom, b.geom) geom
FROM overlappingtable a,
     overlappingtable b
WHERE a.id = b.id OR -- Make sure to pass at least once the polygon with itself
      ((ST_Contains(a.geom, b.geom) OR -- Select all the containing, contained and overlapping polygons
        ST_Contains(b.geom, a.geom) OR
        ST_Overlaps(a.geom, b.geom)) AND
       (ST_Area(a.geom) < ST_Area(b.geom) OR -- Make sure bigger polygons are removed from smaller ones
        (ST_Area(a.geom) = ST_Area(b.geom) AND -- If areas are equal, arbitrarily remove one from the other but in a determined order so it's not done twice.
         a.id < b.id)))
GROUP BY a.id
HAVING ST_Area(ST_DifferenceAgg(a.geom, b.geom)) > 0 AND NOT ST_IsEmpty(ST_DifferenceAgg(a.geom, b.geom));

Điều này sẽ hợp nhất các phần chồng chéo với đa giác chồng chéo lớn nhất. Nếu bạn muốn tách riêng phần chồng lấp, hãy xem ví dụ ST_splitAgg ().

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.