Eu tenho um conjunto de pontos. Eu quero separá-los em 2 conjuntos distintos. Para fazer isso, eu escolho dois pontos ( um e b ) e desenhar uma linha imaginária entre eles. Agora eu quero ter todos os pontos que restam desta linha em um conjunto e os que estão à direita dessa linha no outro conjunto.
Como posso saber para qualquer ponto z se ele está no conjunto esquerdo ou no conjunto certo? Tentei calcular o ângulo entre azb - ângulos menores que 180 estão no lado direito, maiores que 180 no lado esquerdo - mas, devido à definição do ArcCos, os ângulos calculados são sempre menores que 180 °. Existe uma fórmula para calcular ângulos maiores que 180 ° (ou qualquer outra fórmula para escolher o lado direito ou esquerdo)?
c#
math
geometry
convex-hull
Aaginor
fonte
fonte
Respostas:
Use o sinal do determinante de vetores
(AB,AM)
, ondeM(X,Y)
está o ponto de consulta:Está
0
na linha, e+1
de um lado,-1
do outro lado.fonte
positions
?Experimente este código que utiliza um produto cruzado :
Onde a = ponto da linha 1; b = ponto da linha 2; c = ponto para verificar.
Se a fórmula for igual a 0, os pontos serão colineares.
Se a linha for horizontal, isso retornará verdadeiro se o ponto estiver acima da linha.
fonte
return (b.x - a.x)*(c.y - a.y) > (b.y - a.y)*(c.x - a.x);
, mas o compilador provavelmente otimiza isso de qualquer maneira.Você olha para o sinal do determinante de
Será positivo para pontos de um lado e negativo no outro (e zero para pontos na própria linha).
fonte
O vetor
(y1 - y2, x2 - x1)
é perpendicular à linha e sempre apontando para a direita (ou sempre apontando para a esquerda, se você planeja uma orientação diferente da minha).Você pode então calcular o produto escalar desse vetor e
(x3 - x1, y3 - y1)
determinar se o ponto está no mesmo lado da linha que o vetor perpendicular (produto escalar>0
) ou não.fonte
Usando a equação da linha ab , obtenha a coordenada x na linha na mesma coordenada y que o ponto a ser classificado.
fonte
Primeiro verifique se você tem uma linha vertical:
Em seguida, calcule a inclinação:
m = (y2-y1)/(x2-x1)
Em seguida, crie uma equação da linha, utilizando o formulário inclinação ponto:
y - y1 = m*(x-x1) + y1
. Por uma questão de explicação, simplifique-a para a forma de interceptação de inclinação (não é necessária no seu algoritmo):y = mx+b
.Agora conecte
(x3, y3)
parax
ey
. Aqui estão alguns pseudocódigo detalhando o que deve acontecer:fonte
Eu implementei isso em java e executei um teste de unidade (fonte abaixo). Nenhuma das soluções acima funciona. Este código passa no teste de unidade. Se alguém encontrar um teste de unidade que não passe, entre em contato.
Código: NOTA:
nearlyEqual(double,double)
retorna verdadeiro se os dois números estiverem muito próximos.Aqui está o teste de unidade:
fonte
Assumindo que os pontos são (Ax, Ay) (Bx, By) e (Cx, Cy), você precisa calcular:
(Bx - Ax) * (Cy - Ay) - (Por - Ay) * (Cx - Ax)
Isso será igual a zero se o ponto C estiver na linha formada pelos pontos A e B e terá um sinal diferente, dependendo do lado. De que lado isso depende da orientação de suas coordenadas (x, y), mas você pode inserir valores de teste para A, B e C nessa fórmula para determinar se os valores negativos estão à esquerda ou à direita.
fonte
Eu queria fornecer uma solução inspirada na física.
Imagine uma força aplicada ao longo da linha e você está medindo o torque da força sobre o ponto. Se o torque for positivo (sentido anti-horário), o ponto será "esquerdo" da linha, mas se o torque for negativo, o ponto será "direito" da linha.
Portanto, se o vetor de força for igual ao intervalo dos dois pontos que definem a linha
você testa o lado de um ponto com
(px,py)
base no sinal do seguinte testefonte
basicamente, acho que existe uma solução muito mais fácil e direta, para qualquer polígono, digamos, consistir em quatro vértices (p1, p2, p3, p4), encontrar os dois vértices extremos opostos no polígono, em outro palavras, encontre, por exemplo, o vértice superior esquerdo (digamos p1) e o vértice oposto, localizado no canto inferior direito (digamos). Portanto, dado o ponto de teste C (x, y), agora você deve fazer uma verificação dupla entre C e p1 e C e p4:
se cx> p1x AND cy> p1y ==> significa que C é menor e à direita de p1 a seguir se cx <p2x AND cy <p2y ==> significa que C é superior e à esquerda de p4
conclusão, C está dentro do retângulo.
Obrigado :)
fonte
@ Resposta do AVB em ruby
Se
det
é positivo é acima, se negativo é abaixo. Se 0, está na linha.fonte
Aqui está uma versão, novamente usando a lógica de produtos cruzados, escrita em Clojure.
Exemplo de uso:
O que significa que o ponto (0, 10) fica à esquerda da linha determinada por (-3, -1) e (3, 1).
NOTA: Esta implementação resolve um problema que nenhum dos outros (até agora) resolve! A ordem é importante ao fornecer os pontos que determinam a linha. Ou seja, é uma "linha direcionada", em certo sentido. Portanto, com o código acima, essa invocação também produz o resultado de
true
:Isso ocorre por causa desse trecho de código:
Finalmente, como nas outras soluções baseadas em produtos cruzados, essa solução retorna um valor booleano e não fornece um terceiro resultado para a colinearidade. Mas dará um resultado que faça sentido, por exemplo:
fonte
Uma maneira alternativa de obter uma idéia das soluções fornecidas pelos netters é entender algumas implicações geométricas.
Seja pqr = [P, Q, R] pontos que formam um plano dividido em 2 lados pela linha [P, R] . Devemos descobrir se dois pontos no pqr plano , A, B, estão do mesmo lado.
Qualquer ponto T no plano pqr pode ser representado com 2 vetores: v = PQ e u = RQ, como:
T '= TQ = i * v + j * u
Agora as implicações da geometria:
i+j: <0 0 <1 =1 >1 ---------Q------[PR]--------- <== this is PQR plane ^ pr line
Em geral,
Os outros significados geometria de i e j (não relacionadas com esta solução) são os seguintes:
O valor de i, j pode ser obtido resolvendo as equações:
Então, recebemos 2 pontos, A, B no avião:
A = a1 * v + a2 * u B = b1 * v + b2 * u
Se A, B estiverem do mesmo lado, isso será verdade:
sign(a1+a2-1) = sign(b1+b2-1)
Observe que isso se aplica também à pergunta: A, B estão no mesmo lado do plano [P, Q, R] , no qual:
T = i * P + j * Q + k * R
e i + j + k = 1 implica que T está no plano [P, Q, R] e o sinal de i + j + k-1 implica sua lateral. A partir disso, temos:
A = a1 * P + a2 * Q + a3 * R B = b1 * P + b2 * Q + b3 * R
e A, B estão do mesmo lado do plano [P, Q, R] se
sign(a1+a2+a3-1) = sign(b1+b2+b3-1)
fonte