Saya memiliki 2 dataset yang terdiri dari data paket kadaster - masing-masing sekitar 125.000 baris. Kolom geometri adalah poligon WKB yang mewakili batas parsel; semua data secara geometris valid (poligon ditutup dll).
Beberapa data baru-baru ini tiba dalam proyeksi yang berbeda dengan data dasar yang digunakan untuk pekerjaan perbandingan - jadi saya memproyeksikan yang baru (basis adalah 4326; yang lain adalah WGA94 yang dibawa ke PostGIS sebagai 900.914 ... Saya memproyeksikan ulang ke 4326) .
Tahap pertama analisis adalah menemukan dan menyimpan paket yang tidak cocok; bagian dari itu adalah untuk mengidentifikasi dan menyimpan parsel dengan geometri yang identik.
Jadi saya menjalankan query yang sangat standar (blok kode di bawah ini meringkas detail skema dll):
create table matchdata as
select a.*
from gg2014 a, gg2013 b
where ST_Equals(a.g1,b.g1)
Hasil NOL.
"Aneh ..." pikirku. "Mungkin ada pergeseran vertex kecil yang disebabkan oleh proyeksi ulang: itu akan mengganggu, dan benar-benar tidak boleh terjadi."
Untungnya ada banyak data aspalal (5 kolom pengidentifikasi) yang memungkinkan saya membuat paket yang harus identik secara spasial: mereka yang memiliki pengidentifikasi yang sama, yang tanggal perubahannya di tabel 2014 adalah sebelum tanggal perubahan maksimal pada data 2013. Itu berjumlah 120.086 baris berbeda.
Saya menyimpan pengidentifikasi dan geometri dalam tabel terpisah ( match_id
), dan menjalankan kueri berikut:
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 nilai pertama untuk inta
dan intb
identik nol, 456 berikutnya adalah 0,99999999-ish (min 0,99999999999994, maks 0,99999999999999999), dan baris 473 dan seterusnya adalah 1 - hingga baris 120050, ketika area persimpangan lebih besar daripada geometri (terbesar) nilai untuk inta
dan intb
1,00000000000029, tetapi masih).
Jadi inilah teka-teki saya: jika dua geometri berpotongan secara spasial antara 99,999999999994% dan 100,000000000029% dari daerah masing-masing, saya ingin "ST_Equals" untuk mengatakan "Yap .... Saya akan memberi Anda yang satu. Cukup dekat".
Bagaimanapun, itu setara dengan keluar sekitar 1 bagian dalam 16 triliun ... yaitu, seolah-olah utang nasional AS turun kurang dari 93 sen.
Dalam konteks keliling Bumi (pada ~ 40.000 km), rasanya seperti berada di ketinggian 0,0000000025 km, (karena menghasilkan perbedaan area yang kecil, setiap pergeseran titik harus lebih kecil).
Menurut TFD (yang saya punya R'd) toleransi untuk ST_Intersects()
adalah 0,00001m (1mm), jadi perubahan tersirat dalam simpul (yang saya akui saya belum memeriksa: Saya akan ST_Dump()
melakukannya dan melakukannya) akan tampak lebih kecil selain toleransi. (Saya menyadari itu ST_Intersects !== ST_Intersection()
, tapi itu satu-satunya toleransi yang disebutkan).
Saya belum dapat menemukan toleransi yang sesuai untuk perbandingan titik yang dilakukan oleh ST_Equals()
... tetapi tampaknya benar-benar aneh bahwa setidaknya 120.000 dari baris saya harus melewati penilaian yang masuk akal tentang identitas spasial, tetapi tidak.
(Catatan: Saya juga melakukan latihan yang sama menggunakan ::geography
- dengan hasil yang memiliki lebih banyak variabilitas, tetapi masih lebih dari 110.000 entri dengan '1' bersih yang bagus).
Apakah ada cara untuk melonggarkan toleransi ST_Equals, yang tidak perlu menggali celah-celah kode? Saya tidak tertarik melakukan itu.
Jika tidak, adakah kludge yang diketahui orang?
Catatan: akan lebih baik jika 'kludge' tidak melakukan perbandingan bilateral seperti
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).
Saya dapat mengatasi ini, tetapi menulis 20 halaman untuk mendokumentasikan penyelesaiannya - yang hanya akan muncul lagi jika kita mendapatkan data yang cerdik - adalah PITA yang saya lebih suka tidak harus melakukannya mengingat bahwa itu kemungkinan hanya sekali saja .
(Versi: Postgresql 9.3.5; PostGIS 2.1.3)
ST_Equals
hanya mengembalikan true
ketika geometri sama - tipe geometri, jumlah simpul, SRID, dan nilai simpul (dalam semua dimensi, dalam urutan yang sama). Jika ada varian, perbandingan berhenti, dan false
dikembalikan.
ST_Equals()
mengabaikan directionality. Saya menganggap itu berarti bahwa untuk poligon 2-D tertutup, tidak ada bedanya jika titik-titiknya dihitung searah jarum jam vs berlawanan arah jarum jam. ST_OrderingEquals()
adalah tes yang lebih ketat. Yang mengatakan, setelah memeriksa titik (menggunakan ST_Dump()
dan menghitung delta untuk setiap titik) jelas bahwa jawaban luar biasa @John Barca adalah pada uang. ST_equals()
dikontraindikasikan, bahkan untuk data identik-identik ex-ante , jika satu geometri diproyeksikan ulang - kecuali jika perbandingan dibuat dengan ST_SnapToGrid ().
(100*(ST_Area(ST_Intersection(a.g1, b.g1))/ST_Area(a.g1)))::int as int_pca
dan (100*(ST_Area(ST_Intersection(a.g1, b.g1))/ST_Area(b.g1)))::int as int_pcb
(pastikan Anda JOIN
menyertakan ST_Intersects(a.g1,b.g1)
). Tes jika (int_pca, int_pcb)=(100,100)
(atau beberapa set cutoff lainnya). Kludgy, tapi itu akan melakukan 2,6 juta paket dalam ~ 30 menit (selama g1 diindeks GIST).