Detectando se o ponto está no lado esquerdo ou direito da linha no PostGIS?

16

Eu tenho uma tabela de cadeia de linhas e uma tabela de pontos no postgis.

Eu sei a linha mais próxima de qualquer ponto. O que eu preciso saber é de qual "lado" dessa linha é o ponto. Acho que tenho que fazer isso criando uma linha perpendicular de um ponto a outro (ponto mais próximo da linha) e depois comparando as coordenadas, mas não sei exatamente como fazer isso, e se for da maneira correta, já que a linha muda de direção.

Eu fiz uma foto para ilustrar minha tarefa.

insira a descrição da imagem aqui

A linha em si é preta, sua direção é mostrada com setas verdes. Eu preciso adicionar uma coluna "lateral" à tabela de pontos, para que os pontos vermelhos tenham valor "right" e os pontos azuis tenham valor "left".

Alguém pode dar um exemplo de código SQL para calcular o valor "lateral" de um ponto?

mofoyoda
fonte

Respostas:

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

Portanto, a idéia é calcular o ângulo entre o segmento de linha mais próximo e o vetor do ponto mais próximo da linha ao seu ponto.

obter um ponto mais próximo em uma linha

select ST_ClosestPoint(line.geom, point.geom)

crie o vetor do ponto mais próximo ao seu ponto

ST_MakeLine(cp.p, point.geom) vec

crie um vetor entre sua linha

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

obtenha a diferença entre as direções

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

Então, direita e esquerda serão maiores que zero e menores que zero.

dmitry.v.kiselev
fonte
Obrigado, parece uma boa solução, mas não gosto da parte * 1.01. O próximo ponto mais próximo da linha pode ser selecionado para tornar essa consulta mais confiável?
Mofoyoda 31/07/2015
Eu estava pensando em obter o segmento mais próximo, mas não existe essa função. Mas essa é uma solução mais confiável, porque ST_LineInterpolate é direcionado para que você obtenha o próximo ponto na direção da linha, e não apenas o mais próximo. É possível obter o próximo nó real, mas recomendamos que você repita todos os nós e descubra se eles são os próximos ao longo da linha ou antes do ponto mais próximo da linha.
31415 Dmitry.v.kiselev
Oi Dmitry. Isso funcionará para um ponto que está além da linha, se você entende o que quero dizer. Por exemplo, o ponto superior esquerdo mais vermelho, se fosse 1 cm mais alto. Nesse caso, o ponto mais próximo e o ponto não farão um ângulo reto com a linha original. Esse algoritmo funcionará nesse caso?
Jenia Ivanov
3
ST_Azimuth(h.vec)- é um pseudocódigo. h.vece h.segsão linhas, por isso para ser mais preciso, deve ser algo comoST_Azimuth(ST_StartPoint(h.vec), ST_EndPoint(h.vec))
dmitry.v.kiselev
2
a solução acima parece não funcionar nos casos em que a linha é leste-oeste, tendo um rumo de exatamente 90 graus por algum motivo.
user7543032