Wykrywanie, czy punkt znajduje się po lewej czy po prawej stronie linii w PostGIS?

16

Mam stół z liniami i stół punktowy w postgis.

Znam najbliższą linię do dowolnego punktu. Muszę wiedzieć, po której „stronie” tej linii jest sedno. Chyba muszę to zrobić, tworząc linię prostopadłą z danego punktu do linii (najbliższy punkt na linii), a następnie porównując współrzędne, ale nie wiem dokładnie, jak to zrobić, a jeśli to jest właściwy sposób, ponieważ linia zmienia swój kierunek.

Zrobiłem zdjęcie, aby zilustrować moje zadanie.

wprowadź opis zdjęcia tutaj

Sama linia jest czarna, jej kierunek pokazuje zielone strzałki. Muszę dodać kolumnę „boczną” do tabeli punktów, aby czerwone punkty miały wartość „prawa”, a niebieskie punkty miały wartość „lewa”.

Czy ktoś może podać przykład kodu SQL obliczania „bocznej” wartości punktu?

mofoyoda
źródło

Odpowiedzi:

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

Pomysł polega więc na obliczeniu kąta między najbliższym odcinkiem linii i wektorem od najbliższego punktu linii do twojego punktu.

dostać najbliższy punkt na linii

select ST_ClosestPoint(line.geom, point.geom)

utwórz wektor od najbliższego punktu do swojego punktu

ST_MakeLine(cp.p, point.geom) vec

utwórz wektor wśród swojej linii

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

uzyskać różnicę między kierunkami

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

Więc prawo i lewo będą większe od zera i niższe od zera.

dmitry.v.kiselev
źródło
Dzięki, wydaje się, że to dobre rozwiązanie, ale nie podoba mi się część * 1.01. Czy można wybrać następny najbliższy punkt linii, aby uczynić to zapytanie bardziej wiarygodnym?
mofoyoda
Myślałem o zdobyciu najbliższego segmentu, ale nie ma takiej funkcji. Jest to jednak bardziej niezawodne rozwiązanie, ponieważ ST_LineInterpolate jest skierowane, dzięki czemu uzyskasz następny punkt w kierunku linii, nie tylko najbliższy. Możliwe jest uzyskanie rzeczywistego następnego węzła, ale zachęciłoby cię to do iteracji po wszystkich węzłach i sprawdzenia, czy są one następne wzdłuż linii lub przed najbliższym punktem na linii.
dmitry.v.kiselev
Cześć Dmitry. Czy to zadziała dla punktu, który jest poza linią, jeśli wiesz, co mam na myśli. Na przykład w lewym górnym rogu najbardziej czerwona kropka, jeśli byłaby o 1 cm wyższa. W takim przypadku najbliższy punkt i punkt nie utworzą kąta prostego z oryginalną linią. Czy ten algorytm zadziała w takim przypadku?
Jenia Iwanow
3
ST_Azimuth(h.vec)- to pseudokod. h.veci h.segsą liniami, a ST_Azimuth(ST_StartPoint(h.vec), ST_EndPoint(h.vec))
ściślej
2
powyższe rozwiązanie wydaje się nie działać w przypadkach, w których linia z jakiegoś powodu ma kierunek dokładnie 90 stopni.
user7543032