Preciso de uma função básica para encontrar a menor distância entre um ponto e um segmento de linha. Sinta-se livre para escrever a solução em qualquer idioma que desejar; Posso traduzi-lo para o que estou usando (Javascript).
EDIT: Meu segmento de linha é definido por dois pontos de extremidade. Então meu segmento de linha AB
é definido pelos dois pontos A (x1,y1)
e B (x2,y2)
. Estou tentando encontrar a distância entre este segmento de linha e um ponto C (x3,y3)
. Minhas habilidades de geometria estão enferrujadas, então os exemplos que vi são confusos, desculpe-me por admitir.
language-agnostic
geometry
distance
line-segment
Eli Courtwright
fonte
fonte
Respostas:
Eli, o código que você escolheu está incorreto. Um ponto próximo à linha na qual o segmento se encontra, mas distante de uma extremidade do segmento, seria julgado incorretamente perto do segmento.Atualização: a resposta incorreta mencionada não é mais a aceita.Aqui está um código correto, em C ++. Ele pressupõe um vetor 2D de classe
class vec2 {float x,y;}
, essencialmente, com operadores para adicionar, subtrair, dimensionar, etc, e uma função de distância e ponto do produto (ou sejax1 x2 + y1 y2
).Edição: Eu precisava de uma implementação Javascript, então aqui está, sem dependências (ou comentários, mas é uma porta direta do acima). Os pontos são representados como objetos com
x
ey
atributos.EDIÇÃO 2: Eu precisava de uma versão Java, mas mais importante, eu precisava dela em 3d em vez de 2D.
fonte
p
em uma linha é o ponto na linha mais próximap
. (E uma perpendicular à linha na projeção passaráp
.) O númerot
é o quão longe ao longo do segmento de linhav
até ow
qual a projeção cai. Portanto, set
for 0, a projeção cai diretamentev
; se for 1, está ativadow
; se for 0,5, por exemplo, está no meio do caminho. Set
for menor que 0 ou maior que 1, ele cai na linha após uma extremidade ou a outra do segmento. Nesse caso, a distância para o segmento será a distância até a extremidade mais próxima.Aqui está o código completo mais simples em Javascript.
x, y é o seu ponto alvo e x1, y1 a x2, y2 é o seu segmento de linha.
ATUALIZADO: corrija o problema da linha de comprimento 0 dos comentários.
fonte
Esta é uma implementação feita para SEGMENTOS DE LINHA FINITA, não linhas infinitas como a maioria das outras funções aqui parecem ser (foi por isso que fiz isso).
Implementação da teoria por Paul Bourke .
Pitão:
AS3:
Java
fonte
distAnother(0, 0, 4, 0, 2, 2)
dá 2.8284271247461903 (incorreto).distAnother(0., 0., 4., 0., 2., 2.)
dá 2,0 (correto). Por favor, esteja ciente disto. Eu acho que o código pode ser melhorado para ter a conversão flutuante em algum lugar.No meu próprio segmento de pergunta, como calcular a menor distância 2D entre um ponto e um segmento de linha em todos os casos em C, C # / .NET 2.0 ou Java? Me pediram para colocar uma resposta em C # aqui quando eu encontrar uma: então aqui está, modificada em http://www.topcoder.com/tc?d1=tutorials&d2=geometry1&module=Static :
Eu sou @SO para não responder, mas fazer perguntas, por isso espero não obter milhões de votos negativos por alguns motivos, mas construir um crítico. Eu só queria (e fui encorajado) a compartilhar as idéias de outras pessoas, já que as soluções neste segmento são com alguma linguagem exótica (Fortran, Mathematica) ou rotuladas como defeituosas por alguém. O único útil (por Grumdrig) para mim é escrito com C ++ e ninguém marcou com defeito. Mas faltam os métodos (ponto etc.) que são chamados.
fonte
Em F #, a distância do ponto
c
ao segmento de linha entrea
eb
é dada por:O vetor
d
aponta dea
parab
ao longo do segmento de linha. O produto escalar ded/s
comc-a
fornece o parâmetro do ponto de aproximação mais próximo entre a linha infinita e o pontoc
. A funçãomin
emax
é usada para fixar esse parâmetro no intervalo, de0..s
modo que o ponto fique entrea
eb
. Por fim, o comprimento dea+p-c
é a distância doc
ponto mais próximo no segmento de linha.Exemplo de uso:
fonte
(a + p - c).Length
lambda
ep
comolet lambda = (c - a) * d / (s * s)
elet p = a + (lambda |> max 0.0 |> min 1.0) * d
, respectivamente. Depois disso, a função retorna a distância correta, por exemplo, para o caso em quea = (0,1)
,b = (1,0)
ec = (1,1)
.Para quem estiver interessado, aqui está uma conversão trivial do código Javascript de Joshua em Objective-C:
Eu precisava dessa solução para trabalhar,
MKMapPoint
então a compartilharei caso alguém precise dela. Apenas algumas pequenas alterações e isso retornará a distância em metros:fonte
No Mathematica
Ele usa uma descrição paramétrica do segmento e projeta o ponto na linha definida pelo segmento. Como o parâmetro vai de 0 a 1 no segmento, se a projeção estiver fora desses limites, calculamos a distância até o ponto correspondente, em vez da linha reta normal ao segmento.
Resultado da plotagem:
Plote os pontos mais perto do que a distância de corte :
Gráfico de contorno:
fonte
Ei, acabei de escrever isso ontem. Está no Actionscript 3.0, que é basicamente Javascript, embora você possa não ter a mesma classe Point.
Além disso, há uma discussão bastante completa e legível sobre o problema aqui: notejot.com
fonte
Para os preguiçosos, aqui está minha porta Objective-C da solução do @ Grumdrig acima:
fonte
return dist2(p, CGPointMake(v.x + t * (w.x - v.x), v.y + t * (w.y - v.y)))
sqrtf(x) = x*x
.Não resisti a codificá-lo em python :)
O mesmo vale para o fortran :)
fonte
Aqui está uma grafia mais completa da solução de Grumdrig. Esta versão também retorna o ponto mais próximo em si.
fonte
Solução de uma linha usando arco-tangentes:
A idéia é mover A para (0, 0) e girar o triângulo no sentido horário para colocar C no eixo X, quando isso acontecer, By será a distância.
C #
Uma linha C # (a ser convertida em SQL)
fonte
Considere esta modificação na resposta de Grumdrig acima. Muitas vezes, você verá que a imprecisão de ponto flutuante pode causar problemas. Estou usando dobros na versão abaixo, mas você pode facilmente mudar para carros alegóricos. A parte importante é que ele usa um epsilon para lidar com o "slop". Além disso, muitas vezes você deseja saber ONDE ocorreu o cruzamento ou se aconteceu. Se o t retornado for <0,0 ou> 1,0, nenhuma colisão ocorreu. No entanto, mesmo que nenhuma colisão tenha ocorrido, muitas vezes você desejará saber onde está o ponto mais próximo do segmento de P e, portanto, uso qx e qy para retornar esse local.
fonte
Estou assumindo que você deseja encontrar o menordistância entre o ponto e um segmento de linha; para fazer isso, você precisa encontrar a linha (linha A) que é perpendicular ao seu segmento de linha (linha B) que passa pelo seu ponto, determinar a interseção entre essa linha (linha A) e sua linha que passa pelo seu segmento de linha (linha B) ; se esse ponto estiver entre os dois pontos do seu segmento de linha, a distância será a distância entre o seu ponto e o ponto que você acabou de encontrar, que é a interseção da linha A e da linha B; se o ponto não estiver entre os dois pontos do seu segmento de linha, você precisará obter a distância entre seu ponto e a mais próxima das duas extremidades do segmento de linha; isso pode ser feito facilmente, tomando a distância quadrada (para evitar uma raiz quadrada) entre o ponto e os dois pontos do segmento de linha; o que estiver mais próximo, pegue a raiz quadrada daquele.
fonte
A implementação C ++ / JavaScript de Grumdrig foi muito útil para mim, por isso forneci uma porta direta Python que estou usando. O código completo está aqui .
fonte
Código Matlab, com "autoteste" interno, se eles chamarem a função sem argumentos:
fonte
E agora minha solução também ...... (Javascript)
É muito rápido, porque eu tento evitar qualquer função Math.pow.
Como você pode ver, no final da função, tenho a distância da linha.
código é da lib http://www.draw2d.org/graphiti/jsdoc/#!/example
fonte
codificado em t-sql
o ponto é (@px, @py) e o segmento de linha vai de (@ax, @ay) a (@bx, @by)
fonte
Parece que quase todo mundo no StackOverflow contribuiu com uma resposta (23 respostas até agora), então aqui está minha contribuição para o C #. Isso se baseia principalmente na resposta de M. Katz, que por sua vez se baseia na resposta de Grumdrig.
E aqui está um pequeno programa de teste.
Como você pode ver, tentei medir a diferença entre usar a versão que evita o método Sqrt () e a versão normal. Meus testes indicam que você pode economizar cerca de 2,5%, mas nem tenho certeza disso - as variações nas várias execuções de teste foram da mesma ordem de magnitude. Também tentei medir a versão postada por Matti (além de uma otimização óbvia), e essa versão parece ser cerca de 4% mais lenta que a versão baseada no código Katz / Grumdrig.
Edit: Aliás, eu também tentei medir um método que encontra a distância de uma linha infinita (não um segmento de linha) usando um produto cruzado (e um Sqrt ()), e é cerca de 32% mais rápido.
fonte
Aqui está a versão C ++ do devnullicus convertida em C #. Para minha implementação, eu precisava conhecer o ponto de interseção e encontrar sua solução para funcionar bem.
fonte
Aqui está usando Swift
fonte
C #
Adaptado de @Grumdrig
fonte
Uma solução 2D e 3D
Considere uma mudança de base para que o segmento de linha se torne
(0, 0, 0)-(d, 0, 0)
o ponto(u, v, 0)
. A menor distância ocorre nesse plano e é dada por(a distância de um dos pontos finais ou da linha de suporte, dependendo da projeção da linha. O local da iso-distância é composto por dois semicírculos e dois segmentos de linha.)
Na expressão acima, d é o comprimento do segmento AB, e u, v são, respectivamente, o produto escalar e (módulo do) produto cruzado de AB / d (vetor unitário na direção de AB) e AC. Portanto, vectorialmente,
fonte
consulte a caixa de ferramentas Matlab GEOMETRY no seguinte site: http://people.sc.fsu.edu/~jburkardt/m_src/geometry/geometry.html
ctrl + f e digite "segmento" para encontrar funções relacionadas ao segmento de linha. as funções "segment_point_dist_2d.m" e "segment_point_dist_3d.m" são o que você precisa.
Os códigos de GEOMETRIA estão disponíveis nas versões C e C ++ e FORTRAN77 e FORTRAN90 e MATLAB.
fonte
Versão do AutoHotkeys baseada no Javascript de Joshua:
fonte
Não vi uma implementação Java aqui, então traduzi a função Javascript da resposta aceita para o código Java:
fonte
Versão WPF:
fonte
Aqui está o código que acabei escrevendo. Este código assume que um ponto é definido na forma de
{x:5, y:7}
. Observe que essa não é a maneira absolutamente mais eficiente, mas é o código mais simples e fácil de entender que eu poderia criar.fonte
A função acima não está funcionando em linhas verticais. Aqui está uma função que está funcionando bem! Linha com os pontos p1, p2. e CheckPoint é p;
fonte
Aqui está a mesma coisa que a resposta C ++, mas portada para pascal. A ordem do parâmetro point mudou para se adequar ao meu código, mas é a mesma coisa.
fonte