ST_Intersects mit entartetem LINESTRING

9

Ich habe in PostGIS eine Reihe von LINESTRING Z-Objekten (die Pole darstellen), und ich möchte herausfinden, welche sich in einem Bereich befinden (dargestellt durch ein POLYGON). Für diese Übung können wir mit Sicherheit davon ausgehen, dass ein Pol ziemlich vertikal ist, sodass er die Grenze des Bereichs nicht schneidet.

Das Problem ist, dass die Stange manchmal genau vertikal ist.

Diese Abfrage, die ich gerne machen würde, ist nicht erfolgreich:

SELECT ST_Intersects(ST_GeomFromText('LINESTRING Z (544483.525 6849134.28 104.1098,544483.525 6849134.28 114.6)',28356),
ST_GeomFromText('POLYGON((543907.636214323 6848710.84802846,543909.787417164 6849286.92923919,544869.040437688 6849283.30837091,544866.842236582 6848707.22673193,543907.636214323 6848710.84802846))',28356));

Dies ist erfolgreich, wenn einige Varianten untersucht werden:

SELECT ST_Intersects(ST_GeomFromText('POINT (544483.525 6849134.28)',28356),
ST_GeomFromText('POLYGON((543907.636214323 6848710.84802846,543909.787417164 6849286.92923919,544869.040437688 6849283.30837091,544866.842236582 6848707.22673193,543907.636214323 6848710.84802846))',28356));

Dies gelingt nicht:

SELECT ST_Intersects(ST_GeomFromText('LINESTRING (544483.525 6849134.28,544483.525 6849134.28)',28356),
ST_GeomFromText('POLYGON((543907.636214323 6848710.84802846,543909.787417164 6849286.92923919,544869.040437688 6849283.30837091,544866.842236582 6848707.22673193,543907.636214323 6848710.84802846))',28356));

Wenn Sie eine 3DIntersects-Abfrage durchführen, ist dies erfolgreich:

SELECT ST_3DIntersects(ST_GeomFromText('LINESTRING Z (544483.525 6849134.28 104.1098,544483.525 6849134.28 114.6)',28356),
ST_GeomFromText('POLYGON((543907.636214323 6848710.84802846,543909.787417164 6849286.92923919,544869.040437688 6849283.30837091,544866.842236582 6848707.22673193,543907.636214323 6848710.84802846))',28356));

Es wird jedoch darauf hingewiesen, dass:

One or both of the geometries is missing z-value. The unknown z-value will be regarded as "any value"

Das funktioniert also irgendwie, aber es füllt meine Protokolle mit Rauschen und ich würde es vorziehen, Warnungen nicht auszuschalten.

Ich habe den OpenGIS Simple-Standard für den Zugriff auf Funktionen (siehe Teil 1, Abschnitt 4.14) gelesen und festgestellt, dass LINESTRING zwar entartet ist, aber dennoch als topologisch geschlossen interpretiert werden sollte, sodass sie sich überschneiden sollten.

Ist das richtig?

BEARBEITEN

Nach einigen Experimenten kann ich einen Teil meiner eigenen Frage beantworten. Der Grund, warum die obigen Abfragen false zurückgeben, ist folgender, weil angenommen wird, dass LINESTRING Z nicht gültig ist:

SELECT ST_IsValidReason(ST_GeomFromText('LINESTRING Z (544483.525 6849134.28 104.1098,544483.525 6849134.28 114.6)',28356));
                           st_isvalidreason                           
----------------------------------------------------------------------
 Too few points in geometry component[544483.525 6849134.28 104.1098]
(1 row)

Dies ist eine höfliche Art zu sagen, dass OGC 3D nicht unterstützt, und GDAL / PostGIS unterstützt es daher nur irgendwie.

Ich kann das akzeptieren, obwohl ich in der OGC-Spezifikation noch nichts gefunden habe, was darauf hinweist, dass der entsprechende LINESTRING nicht gültig ist.

Ich denke also, meine Frage ist wirklich: Gibt es eine offiziell gesegnete Möglichkeit, den Fußabdruck eines Stücks 3D-Geometrie zu finden, das immer eine gültige 2D-Geometrie zurückgibt?

Pseudonym
quelle

Antworten:

6

Eine wirklich einfache Lösung für die erste Abfrage besteht darin, mit ST_MakeValid eine "gültige" Geometrie zu erstellen, um true zurückzugeben:

SELECT ST_Intersects(ST_MakeValid(A), B), ST_AsText(ST_MakeValid(A)) AS ST_MakeValid
FROM (
  SELECT ST_GeomFromText('LINESTRING Z (544483.525 6849134.28 104.1098,544483.525 6849134.28 114.6)',28356) AS A,
         ST_GeomFromText('POLYGON((543907.636214323 6848710.84802846,543909.787417164 6849286.92923919,544869.040437688 6849283.30837091,544866.842236582 6848707.22673193,543907.636214323 6848710.84802846))',28356) AS B
) AS d;

-[ RECORD 1 ]-+-----------------------------------------
st_intersects | t
st_makevalid  | POINT Z (544483.525 6849134.28 104.1098)

Die ursprüngliche Abfrage ist fehlgeschlagen, da das LineString-Objekt ungültig war, wie entweder von ST_IsValid oder ST_IsValidReason festgestellt . Dies liegt daran, dass ST_Intersects ein 2D-Operator ist, sodass die Geometrie auf zwei Dimensionen gezwungen wurde LINESTRING(544483.525 6849134.28,544483.525 6849134.28), was ungültig ist.

ST_MakeValid entfernt die wiederholte Koordinate (im 2D-Raum) und ändert sie in einen Punkttyp, da die resultierende Geometrie nur eine Koordinate hat.

Sie können sehen, dass die Z-Koordinate teilweise noch vorhanden ist, aber ignoriert wird. Wenn Sie dies stört, können Sie ST_Force2D auch verwenden, um nur 2D-Geometrien für Dinge wie ST_Intersects zu verwenden:

SELECT ST_Intersects(ST_MakeValid(ST_Force2D(A)), B),
  ST_AsText(ST_Force2D(A)) AS ST_Force2D,
  ST_AsText(ST_MakeValid(ST_Force2D(A))) AS ST_MakeValid
FROM (
  SELECT ST_GeomFromText('LINESTRING Z (544483.525 6849134.28 104.1098,544483.525 6849134.28 114.6)',28356) AS A,
         ST_GeomFromText('POLYGON((543907.636214323 6848710.84802846,543909.787417164 6849286.92923919,544869.040437688 6849283.30837091,544866.842236582 6848707.22673193,543907.636214323 6848710.84802846))',28356) AS B
) AS d;

-[ RECORD 1 ]-+--------------------------------------------------------
st_intersects | t
st_force2d    | LINESTRING(544483.525 6849134.28,544483.525 6849134.28)
st_makevalid  | POINT(544483.525 6849134.28)
Mike T.
quelle
Vielen Dank! Dies war eine gute Erklärung dafür, was los ist, und die Problemumgehung ist auch gut.
Pseudonym