Digamos que você tenha um plano bidimensional com 2 pontos (chamados de aeb) representados por um inteiro x e um inteiro y para cada ponto.
Como você pode determinar se outro ponto c está no segmento de linha definido por a e b?
Eu uso python mais, mas exemplos em qualquer linguagem seriam úteis.
Respostas:
Verifique se o produto vetorial de (ba) e (ca) é 0, como diz Darius Bacon, informa se os pontos a, bec estão alinhados.
Mas, como você quer saber se c está entre aeb, você também deve verificar se o produto escalar de (ba) e (ca) é positivo e é menor que o quadrado da distância entre a e b.
Em pseudocódigo não otimizado:
fonte
-epsilon < crossproduct < epsilon and min(a.x, b.x) <= c.x <= max(a.x, b.x) and min(a.y, b.y) <= c.y <= max(a.y, b.y)
é suficiente, não é?É assim que eu faria:
fonte
-epsilon < (distance(a, c) + distance(c, b) - distance(a, b)) < epsilon
==
é uma coisa errada para flutuadores na maioria dos casos .math.isclose()
poderia ser usado em seu lugar. Não houvemath.isclose()
em 2008 e, portanto, forneci a desigualdade explícita comepsilon
(abs_tol
namath.isclose()
fala).Verifique se o produto vetorial de
b-a
ec-a
é0
: isso significa que todos os pontos são colineares. Se estiverem, verifique sec
as coordenadas de 's estão entrea
' seb
's. Use as coordenadas x ou y, desde quea
eb
sejam separados nesse eixo (ou sejam iguais em ambos).Essa resposta costumava ser uma confusão de três atualizações. As informações valiosas deles: o capítulo de Brian Hayes em Beautiful Code cobre o espaço de design para uma função de teste de colinearidade - um histórico útil. A resposta de Vincent ajudou a melhorar este. E foi Hayes quem sugeriu testar apenas uma das coordenadas x ou y; originalmente o código tinha
and
no lugar deif a.x != b.x else
.fonte
Aqui está outra abordagem:
O ponto C (x3, y3) ficará entre A e B se:
fonte
O comprimento do segmento não é importante, portanto, o uso de uma raiz quadrada não é obrigatório e deve ser evitado, pois podemos perder alguma precisão.
Algum exemplo aleatório de uso:
fonte
==
emis_between()
poderia falhar (btw é uma CrossProduct disfarçado).is_between()
:a, b = self.a, self.b
Aqui está uma maneira diferente de fazer isso, com código fornecido em C ++. Dados dois pontos, l1 e l2, é trivial expressar o segmento de linha entre eles como
onde 0 <= A <= 1. Isso é conhecido como a representação vetorial de uma linha se você estiver mais interessado além de apenas usá-la para este problema. Podemos dividir os componentes xey disso, dando:
Pegue um ponto (x, y) e substitua seus componentes xey nessas duas expressões para resolver A. O ponto está na linha se as soluções para A em ambas as expressões forem iguais e 0 <= A <= 1. Porque resolver para A requer divisão, há casos especiais que precisam de tratamento para interromper a divisão por zero quando o segmento de linha é horizontal ou vertical. A solução final é a seguinte:
fonte
Usando uma abordagem mais geométrica, calcule as seguintes distâncias:
e testar se ac + bc é igual a ab :
Isso porque existem três possibilidades:
fonte
Ok, muitas menções de álgebra linear (produto vetorial de vetores) e isso funciona em um espaço real (ou seja, contínuo ou ponto flutuante), mas a questão afirmava especificamente que os dois pontos foram expressos como inteiros e, portanto, um produto vetorial não é o correto embora possa fornecer uma solução aproximada.
A solução correta é usar o Algoritmo de Linha de Bresenham entre os dois pontos e ver se o terceiro ponto é um dos pontos da linha. Se os pontos estiverem suficientemente distantes para que o cálculo do algoritmo não tenha um desempenho (e teria que ser muito grande para que fosse o caso), tenho certeza de que você poderia pesquisar e encontrar otimizações.
fonte
O produto escalar entre (ca) e (ba) deve ser igual ao produto de seus comprimentos (isso significa que os vetores (ca) e (ba) estão alinhados e com a mesma direção). Além disso, o comprimento de (ca) deve ser menor ou igual ao de (ba). Pseudo-código:
fonte
Eu precisava disso para javascript para uso em uma tela html5 para detectar se o cursor do usuário estava sobre ou perto de uma determinada linha. Então eu modifiquei a resposta dada por Darius Bacon em coffeescript:
fonte
Você pode usar o produto cunha e escalar:
fonte
Veja como eu fiz na escola. Esqueci porque não é uma boa ideia.
EDITAR:
@Darius Bacon: cita um livro "Beautiful Code" que contém uma explicação de porque o código abaixo não é uma boa ideia.
fonte
Qualquer ponto no segmento de linha ( a , b ) (onde a e b são vetores) pode ser expresso como uma combinação linear dos dois vetores a e b :
Em outras palavras, se c estiver no segmento de linha ( a , b ):
Resolvendo para m , obtemos:
Então, nosso teste se torna (em Python):
fonte
c # De http://www.faqs.org/faqs/graphics/algorithms-faq/ -> Assunto 1.02: Como faço para encontrar a distância de um ponto a uma linha?
fonte
Aqui está um código Java que funcionou para mim:
fonte
que tal garantir que a inclinação seja a mesma e o ponto entre as outras?
pontos dados (x1, y1) e (x2, y2) (com x2> x1) e ponto candidato (a, b)
if (b-y1) / (a-x1) = (y2-y2) / (x2-x1) E x1 <a <x2
Então (a, b) deve estar na linha entre (x1, y1) e (x2, y2)
fonte
Uma resposta em C # usando uma classe Vector2D
Observe que
é o produto escalar do vetor de segmento via sobrecarga de operador em C #
A chave é aproveitar a projeção do ponto na reta infinita e observar que a quantidade escalar da projeção nos diz trivialmente se a projeção está no segmento ou não. Podemos ajustar os limites da quantidade escalar para usar uma tolerância difusa.
Se a projeção estiver dentro dos limites, apenas testamos se a distância do ponto até a projeção está dentro dos limites.
O benefício sobre a abordagem de produto cruzado é que a tolerância tem um valor significativo.
fonte
Aqui está minha solução com C # no Unity.
fonte
Versão C # da resposta de Jules:
fonte
Você pode fazer isso resolvendo a equação da linha para aquele segmento de linha com as coordenadas do ponto, você saberá se aquele ponto está na linha e, em seguida, verificar os limites do segmento para saber se está dentro ou fora dele. Você pode aplicar algum limite porque bem em algum lugar no espaço provavelmente definido por um valor de ponto flutuante e você não deve atingir o valor exato. Exemplo em php
fonte