Ich habe 2 Datensätze, die aus Katasterpaketdaten bestehen - jeweils ungefähr 125.000 Zeilen. Die Geometriespalte besteht aus WKB-Polygonen, die Paketgrenzen darstellen. Alle Daten sind geometrisch gültig (die Polygone sind geschlossen usw.).
Einige neuere Daten kamen in einer anderen Projektion an als die Basisdaten, die für einen Vergleichsjob verwendet wurden. Daher habe ich die neuere neu projiziert (Basis war 4326; die andere war WGA94, die als 900914 in PostGIS aufgenommen wurde ... ich habe sie auf 4326 projiziert). .
Die erste Stufe der Analyse bestand darin, nicht übereinstimmende Pakete zu finden und zu speichern. Dazu gehört die Identifizierung und Lagerung von Paketen mit identischer Geometrie.
Also habe ich eine sehr standardmäßige Abfrage ausgeführt (der folgende Codeblock abstrahiert Schemadetails usw.):
create table matchdata as
select a.*
from gg2014 a, gg2013 b
where ST_Equals(a.g1,b.g1)
NULL Ergebnisse.
"Seltsam ..." dachte ich. "Vielleicht gab es winzige Scheitelpunktverschiebungen, die durch die Reprojektion verursacht wurden: Das wäre ärgerlich und sollte wirklich nicht passieren."
Glücklicherweise gibt es reichlich aspatiale Daten (5 Identifizierungsspalten), mit denen ich Pakete erstellen kann, die räumlich identisch sein sollten: solche mit derselben ID, deren Änderungsdatum in der Tabelle 2014 vor dem maximalen Änderungsdatum in den Daten 2013 lag. Das waren 120.086 verschiedene Zeilen.
Ich habe die Bezeichner und Geometrien in einer separaten Tabelle ( match_id
) gespeichert und die folgende Abfrage ausgeführt:
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
Die ersten 16 Werte für inta
und intb
waren identisch Null, die nächsten 456 waren 0,99999999-ish (min 0,99999999999994, max 0,999999999999999) und die Zeilen ab 473 waren 1 - bis Zeile 120050, als die Fläche des Schnittpunkts größer als jede der Geometrien war (die größte Wert für inta
und intb
war 1.00000000000029, aber immer noch).
Hier ist mein Rätsel: Wenn sich zwei Geometrien räumlich zwischen 99,999999999994% und 100,000000000029% ihrer jeweiligen Bereiche schneiden, möchte ich, dass "ST_Equals" "Ja ... ich gebe Ihnen diese. Nah genug" sagt.
Immerhin entspricht dies einem Ausfall von etwa 1 Teil von 16 Billionen ... dh als ob die US-Staatsverschuldung um weniger als 93 Cent gesunken wäre.
Im Zusammenhang mit dem Erdumfang (bei ~ 40.000 km) ist es so, als wäre man um 0,0000000025 km oben (da dies zu einem so kleinen Flächendifferenz führen muss, muss jede Scheitelpunktverschiebung noch kleiner sein).
Laut TFD (für das ich R'd habe) beträgt die Toleranz ST_Intersects()
fiktiv 0,00001 m (1 mm), sodass die impliziten Änderungen in den Eckpunkten (von denen ich gestehe, dass ich sie nicht überprüft habe: Ich werde ST_Dump()
sie tun und dies tun) kleiner zu sein scheinen als die Toleranz. (Mir ist klar ST_Intersects !== ST_Intersection()
, aber es ist die einzige erwähnte Toleranz).
Ich konnte die entsprechende Toleranz für den von ST_Equals()
... durchgeführten Scheitelpunktvergleich nicht herausfinden, aber es scheint wirklich seltsam, dass mindestens 120.000 meiner Zeilen eine vernünftige Bewertung der räumlichen Identität bestehen sollten, aber nicht.
(Hinweis: Ich habe dieselbe Übung auch mit durchgeführt ::geography
- mit Ergebnissen, die variabler waren, aber immer noch mehr als 110.000 Einträge mit einer schönen sauberen '1').
Gibt es eine Möglichkeit, die Toleranz von ST_Equals zu lockern, ohne in die Zwischenräume des Codes zu graben? Darauf bin ich nicht scharf.
Wenn nicht, gibt es einen Kludge, den jemand kennt?
Hinweis: Es wäre gut, wenn der 'Kludge' keinen bilateralen Vergleich wie machen würde
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).
Ich kann das umgehen, aber das Schreiben der 20 Seiten zur Dokumentation der Problemumgehung - die nur dann wieder auftaucht, wenn wir zweifelhafte Daten erhalten - ist eine PITA, die ich lieber nicht tun müsste, da es sich wahrscheinlich um eine einmalige handelt .
(Versionen: Postgresql 9.3.5; PostGIS 2.1.3)
ST_Equals
Wird nur zurückgegeben, true
wenn die Geometrien gleich sind - Geometrietyp, Anzahl der Scheitelpunkte, SRID und Scheitelpunktwerte (in allen Dimensionen in derselben Reihenfolge). Bei Abweichungen wird der Vergleich gestoppt und false
zurückgegeben.
ST_Equals()
ignoriert die Direktionalität. Ich habe das so verstanden, dass es für ein geschlossenes 2D-Polygon keinen Unterschied macht, ob die Punkte im Uhrzeigersinn oder gegen den Uhrzeigersinn aufgezählt werden. ST_OrderingEquals()
ist der engere Test. Nachdem wir die Scheitelpunkte untersucht haben ( ST_Dump()
Deltas für jeden Scheitelpunkt verwenden und berechnen), ist klar, dass @John Barças großartige Antwort auf dem Geld liegt. ST_equals()
ist selbst für Ex-ante -Daten mit identischen Daten kontraindiziert, wenn eine Geometrie neu projiziert wird - es sei denn, der Vergleich erfolgt mit ST_SnapToGrid ().
(100*(ST_Area(ST_Intersection(a.g1, b.g1))/ST_Area(a.g1)))::int as int_pca
und (100*(ST_Area(ST_Intersection(a.g1, b.g1))/ST_Area(b.g1)))::int as int_pcb
(stellen Sie sicher, dass Ihre JOIN
enthält ST_Intersects(a.g1,b.g1)
). Testen Sie, ob (int_pca, int_pcb)=(100,100)
(oder ein anderer Satz von Grenzwerten). Kludgy, aber es werden 2,6 Millionen Pakete in ~ 30 Minuten erledigt (solange g1 GIST-indiziert ist).