Necesito una función básica para encontrar la distancia más corta entre un punto y un segmento de línea. Siéntase libre de escribir la solución en el idioma que desee; Puedo traducirlo a lo que estoy usando (Javascript).
EDITAR: Mi segmento de línea está definido por dos puntos finales. Entonces mi segmento de línea AB
está definido por los dos puntos A (x1,y1)
y B (x2,y2)
. Estoy tratando de encontrar la distancia entre este segmento de línea y un punto C (x3,y3)
. Mis habilidades de geometría están oxidadas, por lo que los ejemplos que he visto son confusos, lamento admitirlo.
language-agnostic
geometry
distance
line-segment
Eli Courtwright
fuente
fuente
Respuestas:
Eli, el código que has establecido es incorrecto. Un punto cerca de la línea en la que se encuentra el segmento pero lejos de un extremo del segmento se juzgaría incorrectamente cerca del segmento.Actualización: la respuesta incorrecta mencionada ya no es la aceptada.Aquí hay un código correcto, en C ++. Presume un vector de clase 2D
class vec2 {float x,y;}
, esencialmente, con operadores para sumar, restar, escalar, etc., y una función de producto de distancia y punto (es decirx1 x2 + y1 y2
).EDITAR: necesitaba una implementación de Javascript, así que aquí está, sin dependencias (o comentarios, pero es un puerto directo de lo anterior). Los puntos se representan como objetos con
x
yy
atributos.EDIT 2: necesitaba una versión de Java, pero más importante, la necesitaba en 3d en lugar de 2d.
fuente
p
en una línea es el punto en la línea más cercana ap
. (Y una perpendicular a la línea a la proyección pasará a travésp
). El númerot
es hasta qué punto a lo largo del segmento de línea dev
aw
que la proyección cae. Entonces, sit
es 0, la proyección cae directamentev
; si es 1, está encendidow
; si es 0.5, por ejemplo, entonces está a medio camino. Sit
es menor que 0 o mayor que 1, cae en la línea más allá de un extremo u otro del segmento. En ese caso, la distancia al segmento será la distancia al extremo más cercano.Aquí está el código completo más simple en Javascript.
x, y es su punto objetivo y x1, y1 a x2, y2 es su segmento de línea.
ACTUALIZADO: se corrigió el problema de la línea de longitud 0 de los comentarios.
fuente
Esta es una implementación hecha para SEGMENTOS DE LÍNEA FINITA, no líneas infinitas como la mayoría de las otras funciones aquí parecen ser (es por eso que hice esto).
Implementación de la teoría por Paul Bourke .
Pitón:
AS3:
Java
fuente
distAnother(0, 0, 4, 0, 2, 2)
da 2.8284271247461903 (incorrecto).distAnother(0., 0., 4., 0., 2., 2.)
da 2.0 (correcto). Tenga en cuenta esto. Creo que el código se puede mejorar para tener conversión flotante en alguna parte.En mi propio hilo de preguntas, ¿cómo calcular la distancia 2D más corta entre un punto y un segmento de línea en todos los casos en C, C # / .NET 2.0 o Java? Me pidieron que pusiera una respuesta de C # aquí cuando encuentro una: así que aquí está, modificada de http://www.topcoder.com/tc?d1=tutorials&d2=geometry1&module=Static :
No estoy para responder pero hacer preguntas, así que espero no obtener millones de votos por algunas razones, sino por construir críticas. Solo quería (y me animaron) compartir las ideas de otra persona, ya que las soluciones en este hilo son con un lenguaje exótico (Fortran, Mathematica) o etiquetados como defectuosos por alguien. El único útil (por Grumdrig) para mí está escrito con C ++ y nadie lo etiquetó como defectuoso. Pero faltan los métodos (punto, etc.) que se llaman.
fuente
En F #, la distancia desde el punto
c
al segmento de línea entrea
yb
está dada por:El vector
d
apunta desdea
a lob
largo del segmento de línea. El producto punto ded/s
withc-a
da el parámetro del punto de aproximación más cercano entre la línea infinita y el puntoc
. La funciónmin
ymax
se utiliza para sujetar este parámetro al rango de0..s
modo que el punto se encuentre entrea
yb
. Finalmente, la longitud dea+p-c
es la distancia desdec
el punto más cercano en el segmento de línea.Ejemplo de uso:
fuente
(a + p - c).Length
lambda
yp
comolet lambda = (c - a) * d / (s * s)
ylet p = a + (lambda |> max 0.0 |> min 1.0) * d
, respectivamente. Después de que la función devuelve correcta distancia por ejemplo, para el caso en quea = (0,1)
,b = (1,0)
yc = (1,1)
.Para cualquier persona interesada, aquí hay una conversión trivial del código Javascript de Joshua a Objective-C:
Necesitaba esta solución para trabajar,
MKMapPoint
así que la compartiré en caso de que alguien más la necesite. Solo algunos cambios menores y esto devolverá la distancia en metros:fuente
En Mathematica
Utiliza una descripción paramétrica del segmento y proyecta el punto en la línea definida por el segmento. A medida que el parámetro va de 0 a 1 en el segmento, si la proyección está fuera de estos límites, calculamos la distancia al punto correspondiente, en lugar de la línea recta normal al segmento.
Resultado del trazado:
Trace esos puntos más cerca que una distancia de corte :
Dibujo de contorno:
fuente
Hola, acabo de escribir esto ayer. Está en Actionscript 3.0, que es básicamente Javascript, aunque es posible que no tenga la misma clase Point.
Además, aquí hay una discusión bastante completa y legible del problema: notejot.com
fuente
Para los perezosos, aquí está mi puerto Objective-C de la solución de @ Grumdrig anterior:
fuente
return dist2(p, CGPointMake(v.x + t * (w.x - v.x), v.y + t * (w.y - v.y)))
sqrtf(x) = x*x
.No pude resistir la codificación en python :)
Lo mismo para fortran :)
fuente
Aquí hay una ortografía más completa de la solución de Grumdrig. Esta versión también devuelve el punto más cercano.
fuente
Solución de una línea usando arcotangentes:
La idea es mover A a (0, 0) y rotar el triángulo en el sentido de las agujas del reloj para que C quede en el eje X, cuando esto suceda, By será la distancia.
C#
Una línea C # (para convertir a SQL)
fuente
Considere esta modificación a la respuesta de Grumdrig anterior. Muchas veces encontrará que la imprecisión de coma flotante puede causar problemas. Estoy usando dobles en la versión a continuación, pero puedes cambiar fácilmente a flotantes. La parte importante es que utiliza un épsilon para manejar el "descuido". Además, muchas veces querrá saber DÓNDE sucedió la intersección, o si sucedió en absoluto. Si la t devuelta es <0.0 o> 1.0, no se produjo colisión. Sin embargo, incluso si no se produjo una colisión, muchas veces querrá saber dónde está el punto más cercano en el segmento a P, y por lo tanto uso qx y qy para devolver esta ubicación.
fuente
Supongo que quieres encontrar el más cortodistancia entre el punto y un segmento de línea; para hacer esto, necesita encontrar la línea (línea A) que es perpendicular a su segmento de línea (línea B) que pasa por su punto, determine la intersección entre esa línea (línea A) y su línea que pasa por su segmento de línea (línea B) ; si ese punto está entre los dos puntos de su segmento de línea, entonces la distancia es la distancia entre su punto y el punto que acaba de encontrar, que es la intersección de la línea A y la línea B; si el punto no está entre los dos puntos de su segmento de línea, debe obtener la distancia entre su punto y el más cercano de los dos extremos del segmento de línea; esto se puede hacer fácilmente tomando la distancia cuadrada (para evitar una raíz cuadrada) entre el punto y los dos puntos del segmento de línea; el que esté más cerca, toma la raíz cuadrada de ese.
fuente
La implementación de C ++ / JavaScript de Grumdrig fue muy útil para mí, por lo que proporcioné un puerto directo de Python que estoy usando. El código completo está aquí .
fuente
Código de Matlab, con "autocomprobación" incorporada si llaman a la función sin argumentos:
fuente
Y ahora mi solución también ...... (Javascript)
Es muy rápido porque trato de evitar cualquier función Math.pow.
Como puede ver, al final de la función tengo la distancia de la línea.
el código es de la biblioteca http://www.draw2d.org/graphiti/jsdoc/#!/example
fuente
codificado en t-sql
el punto es (@px, @py) y el segmento de línea va desde (@ax, @ay) a (@bx, @by)
fuente
Parece que casi todos los demás en StackOverflow han aportado una respuesta (23 respuestas hasta ahora), así que aquí está mi contribución para C #. Esto se basa principalmente en la respuesta de M. Katz, que a su vez se basa en la respuesta de Grumdrig.
Y aquí hay un pequeño programa de prueba.
Como puede ver, traté de medir la diferencia entre usar la versión que evita el método Sqrt () y la versión normal. Mis pruebas indican que tal vez pueda ahorrar alrededor del 2.5%, pero ni siquiera estoy seguro de eso: las variaciones dentro de las diferentes pruebas fueron del mismo orden de magnitud. También intenté medir la versión publicada por Matti (más una optimización obvia), y esa versión parece ser aproximadamente un 4% más lenta que la versión basada en el código Katz / Grumdrig.
Editar: Por cierto, también he intentado medir un método que encuentra la distancia a una línea infinita (no un segmento de línea) usando un producto cruzado (y un Sqrt ()), y es aproximadamente un 32% más rápido.
fuente
Aquí está la versión de C ++ de devnullicus convertida a C #. Para mi implementación, necesitaba conocer el punto de intersección y encontré que su solución funcionaba bien.
fuente
Aquí está usando Swift
fuente
C#
Adaptado de @Grumdrig
fuente
Una solución 2D y 3D.
Considere un cambio de base tal que el segmento de línea se convierta
(0, 0, 0)-(d, 0, 0)
y el punto(u, v, 0)
. La distancia más corta ocurre en ese plano y está dada por(la distancia a uno de los puntos finales o a la línea de soporte, dependiendo de la proyección a la línea. El locus de iso-distancia está formado por dos semicírculos y dos segmentos de línea).
En la expresión anterior, d es la longitud del segmento AB, y u, v son respectivamente el producto escalar y (módulo del) producto cruzado de AB / d (vector unitario en la dirección de AB) y AC. Por lo tanto, vectorialmente,
fuente
consulte la caja de herramientas GEOMETRÍA de Matlab en el siguiente sitio web: http://people.sc.fsu.edu/~jburkardt/m_src/geometry/geometry.html
ctrl + f y escriba "segmento" para buscar funciones relacionadas con el segmento de línea. las funciones "segmento_punto_dist_2d.m" y "segmento_punto_dist_3d.m" son lo que necesita.
Los códigos de GEOMETRÍA están disponibles en una versión C y una versión C ++ y una versión FORTRAN77 y una versión FORTRAN90 y una versión MATLAB.
fuente
Versión de AutoHotkeys basada en el Javascript de Joshua:
fuente
No vi una implementación de Java aquí, así que traduje la función Javascript de la respuesta aceptada al código Java:
fuente
Versión WPF:
fuente
Aquí está el código que terminé escribiendo. Este código supone que un punto se define en forma de
{x:5, y:7}
. Tenga en cuenta que esta no es la forma más eficiente, pero es el código más simple y fácil de entender que se me ocurrió.fuente
La función anterior no funciona en líneas verticales. ¡Aquí hay una función que funciona bien! Línea con los puntos p1, p2. y CheckPoint es p;
fuente
Aquí es lo mismo que la respuesta de C ++ pero portado a pascal. El orden del parámetro de punto ha cambiado para adaptarse a mi código, pero es lo mismo.
fuente