Erkennen, ob sich der Punkt in PostGIS auf der linken oder rechten Seite der Linie befindet?

16

Ich habe eine Linestring-Tabelle und eine Punktetabelle in Postgis.

Ich kenne die nächstgelegene Linie zu einem bestimmten Punkt. Was ich wissen muss, ist, auf welcher "Seite" dieser Linie der Punkt liegt. Ich denke, ich muss das tun, indem ich eine senkrechte Linie von einem gegebenen Punkt zu einer Linie (nächstgelegener Punkt auf der Linie) erstelle und dann die Koordinaten vergleiche, aber ich weiß nicht genau, wie das geht und ob es der richtige Weg ist. Da die Linie ihre Richtung ändert.

Ich habe ein Bild gemacht, um meine Aufgabe zu veranschaulichen.

Bildbeschreibung hier eingeben

Die Linie selbst ist schwarz, ihre Richtung wird mit grünen Pfeilen angezeigt. Ich muss der Punktetabelle eine Spalte "Seite" hinzufügen, damit rote Punkte den Wert "rechts" und blaue Punkte den Wert "links" haben.

Kann jemand ein SQL-Codebeispiel für die Berechnung eines Nebenwerts eines Punkts geben?

mofoyoda
quelle

Antworten:

12
select (ST_Azimuth(h.vec) - ST_Azimuth(h.seg))
from (
    select 
        ST_MakeLine(cp.p, point.geom) vec,
        ST_MakeLine(cp.p, 
            ST_LineInterpolatePoint(
                line.geom, 
                ST_LineLocatePoint(line.geom, cp.p) * 1.01)
        ) seg
        from (
            select 
                ST_ClosestPoint(line.geom, point.geom)
        ) p as cp
    ) as h

Die Idee ist also, den Winkel zwischen dem nächstgelegenen Liniensegment und dem Vektor vom nächstgelegenen Punkt auf der Linie zu Ihrem Punkt zu berechnen.

Holen Sie sich einen nächstgelegenen Punkt auf einer Linie

select ST_ClosestPoint(line.geom, point.geom)

Erstellen Sie den Vektor vom nächstgelegenen Punkt zu Ihrem Punkt

ST_MakeLine(cp.p, point.geom) vec

Erstellen Sie einen Vektor aus Ihrer Linie

ST_MakeLine(
    --original point
    cp.p, 
    --find a point next to the closest point on line
    ST_LineInterpolatePoint(line.geom, 
         ST_LineLocatePoint(line.geom, cp.p) * 1.01)) seg

Ermitteln Sie den Unterschied zwischen den Richtungen

ST_Azimuth(h.vec) - ST_Azimuth(h.seg)

Also werden rechts und links größer als null und kleiner als null sein.

dmitry.v.kiselev
quelle
Danke, es scheint eine gute Lösung zu sein, aber ich mag den Teil * 1.01 nicht. Kann der nächstgelegene Punkt der Linie ausgewählt werden, um diese Abfrage zuverlässiger zu machen?
Mofoyoda
Ich habe darüber nachgedacht, das nächstgelegene Segment zu finden, aber da haben wir keine solche Funktion. Dies ist jedoch eine zuverlässigere Lösung, da ST_LineInterpolate so ausgerichtet ist, dass Sie den nächsten Punkt nicht nur in der nächstgelegenen Richtung, sondern auch in der Richtung der Linie erhalten. Es ist möglich, den tatsächlichen nächsten Knoten zu erhalten, aber Sie werden aufgefordert, alle Knoten zu durchlaufen und herauszufinden, ob sie sich entlang der Linie oder vor dem nächstgelegenen Punkt auf der Linie befinden.
dmitry.v.kiselev
Hallo Dmitry. Funktioniert das für einen Punkt, der jenseits der Grenze liegt, wenn Sie wissen, was ich meine? Zum Beispiel der oberste linke rote Punkt, wenn er 1 cm höher wäre. In diesem Fall bilden der nächstgelegene Punkt und der Punkt keinen rechten Winkel zur ursprünglichen Linie. Funktioniert dieser Algorithmus in diesem Fall?
Jenia Ivanov
3
ST_Azimuth(h.vec)- ist ein Pseudocode. h.vecund h.segsind Linien, um genau zu sein sollte es so etwas wieST_Azimuth(ST_StartPoint(h.vec), ST_EndPoint(h.vec))
dmitry.v.kiselev
2
Die obige Lösung scheint in Fällen nicht zu funktionieren, in denen die Linie von Ost nach West verläuft und aus irgendeinem Grund eine Peilung von genau 90 Grad aufweist.
user7543032