PostGIS: ST_Equals sai khi ST_Intersection = 100% hình học?


9

Tôi có 2 bộ dữ liệu bao gồm dữ liệu bưu kiện địa chính - khoảng 125.000 hàng mỗi bộ. Cột hình học là đa giác WKB đại diện cho ranh giới bưu kiện; tất cả dữ liệu có giá trị hình học (đa giác được đóng, v.v.).

Một số dữ liệu gần đây xuất hiện trong một phép chiếu khác với dữ liệu cơ sở đang được sử dụng cho một công việc so sánh - vì vậy tôi đã loại bỏ dữ liệu mới hơn (cơ sở là 4326; cái còn lại là WGA94 được đưa vào PostGIS là 900914 ... Tôi đã đăng lại thành 4326) .

Giai đoạn đầu tiên của phân tích là tìm và lưu trữ các bưu kiện không phù hợp; một phần trong đó là xác định và lưu trữ các bưu kiện có hình dạng giống hệt nhau.

Vì vậy, tôi đã chạy một truy vấn rất chuẩn (khối mã bên dưới tóm tắt chi tiết lược đồ, v.v.):

create table matchdata as
  select  a.*
  from gg2014 a, gg2013 b
  where ST_Equals(a.g1,b.g1)

Kết quả KHÔNG.

"Lạ ..." Tôi nghĩ. "Có lẽ đã có những thay đổi đỉnh nhỏ gây ra bởi sự từ chối: điều đó sẽ gây phiền nhiễu, và thực sự không nên xảy ra."

May mắn thay, có dữ liệu khao khát dồi dào (5 cột định danh) cho phép tôi thiết lập các bưu kiện giống hệt nhau về mặt không gian: những cột có cùng số nhận dạng, có ngày thay đổi trong bảng 2014 trước ngày thay đổi tối đa trong dữ liệu 2013. Con số đó lên tới 120.086 hàng khác nhau.

Tôi đã lưu trữ các định danh và hình học trong một bảng riêng biệt ( match_id) và chạy truy vấn sau:

select apid, 
       bpid, 
       ST_Area(ag::geometry) as aa, 
       ST_Area(bg::geometry) as ab,
       ST_Area(ST_Intersection(ag,bg)::geometry)/ST_Area(ag::geometry) as inta,
       ST_Area(ST_Intersection(ag,bg)::geometry)/ST_Area(ag::geometry) as intb
from match_id
order by inta

16 giá trị đầu tiên cho intaintbcó giá trị bằng 0, 456 tiếp theo là 0,99999999-ish (tối thiểu 0,999999999999994, tối đa 0,99999999999999) và các hàng 473 trở đi là 1 - cho đến hàng 120050, khi diện tích của giao lộ lớn hơn cả hình học (lớn nhất) giá trị cho intaintblà 1.00000000000029, nhưng vẫn).

Vì vậy, đây là câu hỏi hóc búa của tôi: nếu hai hình học giao nhau về mặt không gian giữa 99.999999999994% và 100.000000000029% các khu vực tương ứng của chúng, tôi muốn "ST_Equals" nói "Yep .... Tôi sẽ cung cấp cho bạn cái đó. Đóng đủ".

Rốt cuộc, nó tương đương với việc thoát ra khoảng 1 phần trong 16 nghìn tỷ ... tức là, như thể nợ quốc gia của Hoa Kỳ đã giảm dưới 93 cent.

Trong bối cảnh chu vi của Trái đất (ở mức ~ 40.000km), nó giống như bị tắt bởi 0,0000000025km, ngọn (do dẫn đến sự khác biệt về diện tích nhỏ, bất kỳ sự dịch chuyển đỉnh nào cũng phải nhỏ hơn).

Theo TFD (mà tôi có R'd), dung sai cho không phải ST_Intersects()là 0,00001m (1mm), do đó, những thay đổi ngụ ý ở các đỉnh (mà tôi thú nhận là tôi đã không kiểm tra: tôi sẽ làm ST_Dump()chúng và làm như vậy) dường như nhỏ hơn Hơn cả sự bao dung. (Tôi nhận ra điều đó ST_Intersects !== ST_Intersection(), nhưng đó là sự khoan dung duy nhất được đề cập).

Tôi chưa thể tìm ra dung sai tương ứng cho so sánh đỉnh được thực hiện bởi ST_Equals()... nhưng có vẻ thực sự kỳ lạ khi ít nhất 120.000 hàng của tôi phải vượt qua bất kỳ đánh giá hợp lý nào về nhận dạng không gian, nhưng không.

(Lưu ý: Tôi cũng đã thực hiện bài tập tương tự bằng cách sử dụng ::geography- với kết quả có nhiều thay đổi hơn, nhưng vẫn còn hơn 110.000 mục với độ sạch đẹp '1').

Có cách nào để nới lỏng dung sai của ST_Equals, mà không cần phải đào sâu vào các kẽ của mã không? Tôi không quan tâm đến việc đó.

Nếu không, có một loại bùn mà bất cứ ai cũng biết?

Lưu ý: sẽ tốt hơn nếu 'bùn' không thực hiện so sánh song phương như

where ST_within(g1, ST_Buffer(g2, 0.0000001))
  and ST_within(g2, ST_Buffer(g1, 0.0000001))


   - I've done that: sure, it works... but it's a gigantic documentation PITA).

Tôi có thể giải quyết vấn đề này, nhưng viết 20 trang để ghi lại cách giải quyết - sẽ chỉ xuất hiện trở lại nếu chúng tôi nhận được dữ liệu tinh ranh - là một PITA mà tôi không muốn phải làm vì nó có khả năng là một lần .

(Phiên bản: Postgresql 9.3.5; PostGIS 2.1.3)


Chỉ là một suy nghĩ ở đây, nhưng bạn đã cố gắng hợp thức hóa các bưu kiện mới thành một lưới phù hợp với dữ liệu hiện có bằng cách sử dụng st_snaptogrid?
biệt danh

Tôi có thể hiểu không muốn xem mã nguồn, nhưng câu hỏi của bạn đã khiến tôi phải làm như vậy (mặc dù C ++ của tôi rất tệ), vì vậy tôi cảm ơn bạn vì điều đó. Nếu bạn quan tâm tôi có thể đăng các phần có liên quan, tất cả đều có trong github.com/libgeos .
John Powell

ST_Equalschỉ trả về truekhi hình học bằng nhau - loại hình học, số đỉnh, SRID và giá trị đỉnh (trong tất cả các kích thước, theo cùng một thứ tự). Nếu có bất kỳ phương sai nào, so sánh dừng lại và falseđược trả về.
Vince

@Vince: theo tôi hiểu (từ các tài liệu), ST_Equals()bỏ qua tính định hướng. Tôi lấy điều đó có nghĩa là đối với đa giác 2 chiều đóng, sẽ không có gì khác biệt nếu các điểm được liệt kê theo chiều kim đồng hồ so với ngược chiều kim đồng hồ. ST_OrderingEquals()là bài kiểm tra chặt chẽ hơn. Điều đó nói rằng, đã kiểm tra các đỉnh (sử dụng ST_Dump()và tính toán đồng bằng cho mọi đỉnh) thì rõ ràng câu trả lời tuyệt vời của @John Barça là về tiền. ST_equals()được chống chỉ định, ngay cả đối với ex ante dữ liệu được biết đến như giống hệt, nếu một hình học được chiếu lại - trừ khi so sánh được thực hiện với ST_SnapToGrid ().
GT.

Trở lại vấn đề này: cách nhanh chóng tốt đẹp để có được một bài kiểm tra chấp nhận được cho sự bằng nhau về không gian [gần-] là kiểm tra tỷ lệ của mỗi hình học là một phần của giao điểm. Đó là một chút gánh nặng tính toán; tính toán (100*(ST_Area(ST_Intersection(a.g1, b.g1))/ST_Area(a.g1)))::int as int_pca(100*(ST_Area(ST_Intersection(a.g1, b.g1))/ST_Area(b.g1)))::int as int_pcb(đảm bảo JOINbao gồm của bạn ST_Intersects(a.g1,b.g1)). Kiểm tra nếu (int_pca, int_pcb)=(100,100)(hoặc một số bộ cắt khác). Kydgy, nhưng nó sẽ thực hiện 2,6 triệu bưu kiện trong ~ 30 phút (miễn là g1 được lập chỉ mục GIST).
GT.

Câu trả lời:


20

Tôi đoán là bạn phối hợp các phép biến đổi đã đưa ra các lỗi làm tròn nhỏ (xem một ví dụ bên dưới). Vì không có cách nào để đặt dung sai trong ST_Equals, điều này khiến ST_Equals trả về sai cho một số hình học chỉ khác nhau ở vị trí thập phân thứ n, vì hình học phải giống hệt nhau ở mọi khía cạnh - xem định nghĩa ma trận giao nhau trong libgeos . Bạn có thể kiểm tra điều này với một ví dụ thực sự cực đoan,

SELECT ST_Equals(
      ST_MakePoint(0,0),
      ST_MakePoint(0,0.000000000000000000000000000000000000000000000000000000000001));

Trả về sai .

Nếu bạn sử dụng ST_SnapToGrid, bạn có thể áp đặt độ chính xác nhất định, ví dụ, đến mười chữ số thập phân,

SELECT ST_Equals(
      ST_MakePoint(0,0),
      ST_SnapToGrid(
             ST_MakePoint(0,0.00000000000000000000000000000000000000000000001),
      10));

bây giờ trở về đúng .

Nếu bạn định chạy

CREATE table matchdata AS
SELECT  a.*
FROM gg2014 a, gg2013 b
WHERE ST_Equals(ST_SnapToGrid(a.g1, 5), ST_SnapToGrid(b.g1, 5));

thiết lập một dung sai thích hợp, tôi nghi ngờ vấn đề của bạn sẽ biến mất.

Dưới đây là một liên kết đến một cuộc thảo luận của nhà phát triển Postgis về sự khoan dung cho thấy nó ít hơn tầm thường để thực hiện.

Tôi đã thực hiện một vài chuyển đổi giữa Lưới quốc gia Anh (EPSG: 27700) và lat / lon để minh họa cho quan điểm về độ chính xác làm tròn, lấy một điểm ở đâu đó ở Luân Đôn,

SELECT ST_AsText(ST_Transform(ST_SetSrid(ST_MakePoint(525000, 190000),27700),4326));

trả lại POINT(-0.19680497282746 51.5949871603888)

và đảo ngược điều này,

SELECT ST_AsText(ST_Transform(ST_SetSrid(ST_MakePoint(-0.19680497282746, 51.5949871603888),4326),27700));

trả lại POINT(525000.000880007 189999.999516211)

được tắt dưới một milimet, nhưng quá đủ để khiến ST_Equals trả về sai.


Câu trả lời của John Barca là chính xác - rằng các lỗi làm tròn nhỏ có thể loại bỏ ST_Equals. Trải nghiệm (khó chịu) của tôi là khi làm việc với hai bộ dữ liệu - cả hai được chiếu từ EPSG 4326 đến EPSG 3857 - một qua ArcCatalog (ArcToolbox -> Công cụ quản lý dữ liệu -> Dự đoán và chuyển đổi) , trong khi bộ kia thông qua GDAL ogr2ogr.
Ralph Tee

Câu trả lời này đã giúp tôi rất nhiều. Nhưng tôi nhận thấy rằng các chỉ mục địa lý không còn được sử dụng và các truy vấn diễn ra quá lâu. Cách giải quyết của tôi là tạo các bảng tạm thời với các hình học được chụp và thêm các chỉ mục cho chúng trước khi chạy truy vấn. Có cách nào tốt hơn để tăng tốc mọi thứ?
hfs

1
@hfs. Tôi tin rằng bạn có thể tạo một chỉ mục chức năng bằng ST_SnapToGrid. Bạn đã đúng rằng việc sử dụng một lệnh gọi hàm bên trong một hàm bằng / giao nhau / chứa vv hoạt động không gian sẽ làm cho chỉ mục không được sử dụng và tạo một chỉ mục chức năng sẽ giải quyết điều này. Hoặc bạn có thể cập nhật vĩnh viễn dữ liệu của mình nếu bạn cho rằng độ chính xác là giả và sau đó không phải sử dụng ST_SnapToGrid trong truy vấn. Nó phụ thuộc vào dữ liệu của bạn và trường hợp sử dụng, tất nhiên.
John Powell

2

Bạn đã chạy kiểm tra ST_IsValid trên hình học của bạn? Nếu chúng không hợp lệ, tất cả các cược đã tắt. ST_Intects và các họ khác của các hàm quan hệ không gian GEOS thường sẽ trả về false vì khu vực này không được xác định rõ từ quan điểm ma trận giao nhau. Lý do làm ST_Buffer có thể hoạt động là vì nó chuyển đổi hình học không hợp lệ của bạn thành hình học hợp lệ. ST_Buffer (..., tinybit) là công cụ "người nghèo cố gắng làm cho hình học của tôi hợp lệ".


Bước đầu tiên với bất kỳ tập dữ liệu mới nào là chỉ chọn hình học hợp lệ bằng cách sử dụng ST_isValid(g1)- được đề cập (xiên) "cột hình học là đa giác WKB đại diện cho ranh giới bưu kiện; tất cả dữ liệu đều có giá trị hình học (đa giác được đóng, v.v.) ."
GT.

0

Câu trả lời của tôi đến hơi muộn, nhưng có lẽ nó sẽ giúp được ai đó có cùng vấn đề. Theo kinh nghiệm của tôi, khi hai hình học thực sự bằng nhau nhưng ST_Equals trả về Sai hai điều có thể giúp:

  1. đảm bảo rằng so sánh hình học là hình học đơn (Không có MultiLinesting, MultiPoin, v.v.)
  2. cố gắng ST_Equals(st_astext(a.geom), st_astext(b.geom)) thay vìST_Equals(a.geom , b.geom)

Cái đầu tiên đã được đề cập trong tài liệu . Cái thứ hai có vẻ phi lý nhưng hoạt động. Tôi không biết, nhưng đoán nó phải làm với định dạng nhị phân của hình học postGIS mặc đị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.