Wie berechne ich den Winkel, unter dem sich zwei Linien in PostGIS schneiden?

19

Ich möchte den Winkel zwischen zwei Linien berechnen, in denen sie sich in PostGIS schneiden.

Der Ausgangspunkt für Winkelberechnungen in PostGIS scheint ST_Azimuth zu sein - aber dafür werden Punkte als Eingabe verwendet. Mein erster Gedanke war, die Endpunkte der Schnittlinien zu nehmen und eine Azimutberechnung an diesen durchzuführen. Das ist nicht gut genug, da die meisten Linienmerkmale nicht gerade sind und mich der Winkel am Schnittpunkt interessiert. Ich habe mir also eine verschachtelte Operation ausgedacht, die folgende Schritte durchläuft:

  1. Identifizieren Sie alle Schnittpunkte zwischen den beiden Linien-Feature-Tabellen.
  2. Erstellen Sie einen sehr kleinen Puffer um den Schnittpunkt
  3. Identifizieren Sie die Punkte, an denen die Linienmerkmale die Pufferaußenseite schneiden (nehmen Sie den ersten Punkt, wenn es mehr als einen gibt - es interessiert mich wirklich nur, ob der Winkel in der Nähe von 0, 90 oder 180 Grad liegt).
  4. Berechnen Sie ST_Azimuth für diese beiden Punkte.

Das vollständige SQL ist ein bisschen lang, um es hier zu veröffentlichen, aber ich habe es hier aufgelistet, wenn Sie interessiert sind. (Übrigens, gibt es einen besseren Weg, als alle Felder der WITH-Anweisungen zu übernehmen?)

Die Ergebnisse sehen nicht richtig aus, also mache ich eindeutig etwas falsch:

Ausgabebeispiel 1 Ausgabebeispiel 2

BEARBEITEN Ich habe die Berechnungen in EPSG: 3785 überarbeitet und die Ergebnisse sind etwas anders, aber immer noch nicht richtig:

Ausgabe in 3785 # 1 Ausgabe in 3785 # 2

Meine Frage ist, wo die Mängel in diesem Prozess liegen. Verstehe ich falsch, was ST_Azimuth tut? Gibt es ein CRS-Problem? Sonst noch was? Oder gibt es einen viel einfacheren Weg, dies zu tun?

mvexel
quelle
1
Was war das ursprüngliche CRS? Winkelberechnungen sollten mit einer konformen Projektion durchgeführt werden - nicht mit nicht projiziertem Lat / Long (SRID = 4326).
Mike T
Ursprünglich waren es EPSG: 4326-Koordinaten. Ich habe ST_Translate einbezogen, um 100% sicher zu sein, dass die gesamte Verarbeitung im selben CRS erfolgt. Ich werde eine konforme Projektion versuchen, danke.
MVEXEL
Ich habe die Berechnungen mit EPSG: 3785 überarbeitet und es macht einen Unterschied - ich werde die Frage ändern, um die neuen Ergebnisse anzuzeigen - aber das Ergebnis spiegelt immer noch nicht den tatsächlichen Winkel wider.
MVEXEL

Antworten:

12

Ich hatte die Offenbarung. Es ist ziemlich banal. Ich habe eine wichtige Information für PostGIS ausgelassen, um den richtigen Winkel zu berechnen.

Was ich berechnet habe, war der Winkel zwischen nur den zwei Punkten, die das kleine Pufferäußere schneiden. Um den Schnittwinkel zu berechnen, muss ich beide Winkel zwischen den beiden Punkten auf der Pufferaußenseite und dem Schnittpunkt der beiden Linienmerkmale berechnen und diese subtrahieren.

Ich habe die vollständige SQL aktualisiert , aber hier ist das Wesentliche:

SELECT
    ...
    abs
    (
        round
        (
            degrees
            (
            ST_Azimuth
            (
                points.point2,
                points.intersection
            )
            -
            ST_Azimuth
            (
                points.point1,
                points.intersection
            )
        )::decimal % 180.0
        ,2
    )
)
AS angle
...
FROM
points 
mvexel
quelle
1
Ich habe über den Winkel des gepufferten Punkts auf der Schnittmenge nachgedacht, aber ich habe keine Zeit, um näher darauf einzugehen. Ein weiterer Aspekt sind die Winkeleinheiten. Sie müssen das Ergebnis im Bogenmaß von ST_Azimuth mit 180,0 / pi () multiplizieren, um Ergebnisse in Grad zu erhalten.
Mike T
Ja danke, ich benutze dafür die PostgreSQL degrees () Funktion.
MVEXEL
Hackmesser. (Ich wusste bis jetzt nicht einmal, dass es eine Gradfunktion gibt.) Es wäre schön, all diese Logik in einen Funktionsaufruf zu packen, aber ich habe Schwierigkeiten, mir vorzustellen, wie das funktionieren würde, dh ST_IntersectionAngle(...?
Mike T
Ich war tatsächlich überrascht, dass es sich nicht um eine PostGIS-Funktion handelt. Vielen Dank für Ihr Feedback.
MVEXEL
2

Ich musste kürzlich dasselbe berechnen, entschied mich jedoch für einen einfacheren und wahrscheinlich schnelleren Ansatz.

Um die zusätzlichen Punkte für die Azimutberechnung zu finden, überprüfe ich einfach mit ST_Line_Locate_Point und ST_Line_Interpolate_Point eine Permyriade der Länge hinter dem Schnittpunkt (oder in dem seltenen Fall, dass sie ganz am Anfang der Linie auftritt) :

abs(degrees( 
  ST_Azimuth (
    intersection, 
    ST_Line_Interpolate_Point(
      line1, 
      abs(ST_Line_Locate_Point(line1, intersection) - 0.0001)
    )
  )
  -
  ST_Azimuth (
    intersection, 
    ST_Line_Interpolate_Point(
      line2, 
      abs(ST_Line_Locate_Point(line2, intersection) - 0.0001)
    )
  )
))

Die Permyriade war willkürlich und für konsistentere Ergebnisse wäre es besser, einen absoluten Offset zu verwenden. Um 20m Beispiel Scheck im Voraus, dann würden Sie 0,0001 ändern 20/ST_Length(line1)und 20/ST_Length(line2)jeweils.

lynxlynxlynx
quelle