Digamos que tiene un plano bidimensional con 2 puntos (llamados ayb) representados por un entero x y un entero ay para cada punto.
¿Cómo se puede determinar si otro punto c está en el segmento de línea definido por ay b?
Yo uso Python más, pero los ejemplos en cualquier idioma serían útiles.
Respuestas:
Compruebe si el producto cruzado de (ba) y (ca) es 0, como le dice Darius Bacon, le dice si los puntos a, byc están alineados.
Pero, como desea saber si c está entre ayb, también debe verificar que el producto escalar de (ba) y (ca) sea positivo y sea menor que el cuadrado de la distancia entre ay b.
En pseudocódigo no optimizado:
fuente
-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)
es suficiente, ¿no?Así es como lo haría:
fuente
-epsilon < (distance(a, c) + distance(c, b) - distance(a, b)) < epsilon
==
es algo incorrecto para los flotadores en la mayoría de los casos .math.isclose()
podría utilizarse en su lugar. No hubomath.isclose()
en 2008 y, por lo tanto, proporcioné la desigualdad explícita conepsilon
(abs_tol
en elmath.isclose()
habla).Compruebe si el producto cruzado de
b-a
yc-a
es0
: eso significa que todos los puntos son colineales. Si es así, compruebe sic
las coordenadas de 'están entrea
' yb
's. Utilice las coordenadas x o y, siempre quea
yb
estén separados en ese eje (o sean iguales en ambos).Esta respuesta solía ser un desastre de tres actualizaciones. La información valiosa de ellos: el capítulo de Brian Hayes en Beautiful Code cubre el espacio de diseño para una función de prueba de colinealidad: antecedentes útiles. La respuesta de Vincent ayudó a mejorar este. Y fue Hayes quien sugirió probar solo una de las coordenadas x o y; originalmente el código tenía
and
en lugar deif a.x != b.x else
.fuente
Aquí hay otro enfoque:
El punto C (x3, y3) estará entre A y B si:
fuente
La longitud del segmento no es importante, por lo que no es necesario utilizar una raíz cuadrada y debe evitarse ya que podríamos perder algo de precisión.
Algún ejemplo aleatorio de uso:
fuente
==
enis_between()
entrar podría fallar (por cierto, es un producto cruzado disfrazado).is_between()
:a, b = self.a, self.b
Aquí hay una forma diferente de hacerlo, con código proporcionado en C ++. Dados dos puntos, l1 y l2, es trivial expresar el segmento de línea entre ellos como
donde 0 <= A <= 1. Esto se conoce como la representación vectorial de una línea si está interesado más allá de usarla para este problema. Podemos dividir los componentes xey de esto, dando:
Tome un punto (x, y) y sustituya sus componentes xey en estas dos expresiones para resolver A. El punto está en la línea si las soluciones para A en ambas expresiones son iguales y 0 <= A <= 1. Porque Resolver para A requiere división, hay casos especiales que deben manejarse para detener la división por cero cuando el segmento de línea es horizontal o vertical. La solución final es la siguiente:
fuente
Utilizando un enfoque más geométrico, calcule las siguientes distancias:
y pruebe si ac + bc es igual a ab :
Eso es porque hay tres posibilidades:
fuente
Ok, muchas menciones de álgebra lineal (producto cruzado de vectores) y esto funciona en un espacio real (es decir, continuo o de punto flotante), pero la pregunta establece específicamente que los dos puntos se expresaron como números enteros. y, por lo tanto, un producto cruzado no es el correcto. solución aunque puede dar una solución aproximada.
La solución correcta es usar el algoritmo de línea de Bresenham entre los dos puntos y ver si el tercer punto es uno de los puntos de la línea. Si los puntos están lo suficientemente distantes como para que el cálculo del algoritmo no funcione (y tendría que ser muy grande para que ese sea el caso), estoy seguro de que podría investigar y encontrar optimizaciones.
fuente
El producto escalar entre (ca) y (ba) debe ser igual al producto de sus longitudes (esto significa que los vectores (ca) y (ba) están alineados y con la misma dirección). Además, la longitud de (ca) debe ser menor o igual que la de (ba). Pseudocódigo:
fuente
Necesitaba esto para javascript para usarlo en un lienzo html5 para detectar si el cursor del usuario estaba sobre o cerca de una determinada línea. Así que modifiqué la respuesta dada por Darius Bacon en coffeescript:
fuente
Puede utilizar el producto de puntos y cuñas:
fuente
Así es como lo hice en la escuela. Olvidé por qué no es una buena idea.
EDITAR:
@Darius Bacon: cita un libro "Beautiful Code" que contiene una explicación de por qué el siguiente código no es una buena idea.
fuente
Cualquier punto en el segmento de línea ( un , b ) (donde un y b son vectores) se puede expresar como una combinación lineal de los dos vectores a y b :
En otras palabras, si c se encuentra en el segmento de línea ( a , b ):
Resolviendo para m , obtenemos:
Entonces, nuestra prueba se convierte (en Python):
fuente
c # De http://www.faqs.org/faqs/graphics/algorithms-faq/ -> Asunto 1.02: ¿Cómo encuentro la distancia de un punto a una línea?
fuente
Aquí hay un código Java que funcionó para mí:
fuente
¿Qué tal si nos aseguramos de que la pendiente sea la misma y el punto entre los demás?
puntos dados (x1, y1) y (x2, y2) (con x2> x1) y punto candidato (a, b)
si (b-y1) / (a-x1) = (y2-y2) / (x2-x1) Y x1 <a <x2
Entonces (a, b) debe estar en línea entre (x1, y1) y (x2, y2)
fuente
Una respuesta en C # usando una clase Vector2D
Tenga en cuenta que
es el producto escalar del vector de segmento a través de la sobrecarga del operador en C #
La clave es aprovechar la proyección del punto sobre la línea infinita y observar que la cantidad escalar de la proyección nos dice trivialmente si la proyección está sobre el segmento o no. Podemos ajustar los límites de la cantidad escalar para usar una tolerancia difusa.
Si la proyección está dentro de los límites, solo probamos si la distancia desde el punto a la proyección está dentro de los límites.
El beneficio sobre el enfoque de productos cruzados es que la tolerancia tiene un valor significativo.
fuente
Aquí está mi solución con C # en Unity.
fuente
Versión C # de la respuesta de Jules:
fuente
Puede hacerlo resolviendo la ecuación de línea para ese segmento de línea con las coordenadas del punto, sabrá si ese punto está en la línea y luego verificando los límites del segmento para saber si está dentro o fuera de él. Puede aplicar algún umbral porque, bueno, está en algún lugar del espacio probablemente definido por un valor de punto flotante y no debe alcanzar el exacto. Ejemplo en php
fuente