Responderé esto en términos de matlab, pero se pueden usar otros entornos de programación. Añadiré que esta solución es válida para resolver el problema en cualquier cantidad de dimensiones (> = 3).
Supongamos que tenemos dos segmentos de línea en el espacio, PQ y RS. Aquí hay algunos conjuntos aleatorios de puntos.
> P = randn(1,3)
P =
-0.43256 -1.6656 0.12533
> Q = randn(1,3)
Q =
0.28768 -1.1465 1.1909
> R = randn(1,3)
R =
1.1892 -0.037633 0.32729
> S = randn(1,3)
S =
0.17464 -0.18671 0.72579
La línea infinita PQ (t) se define fácilmente como
PQ(u) = P + u*(Q-P)
mismo modo, tenemos
RS(v) = R + v*(S-R)
ver que para cada línea, cuando el parámetro está en 0 o 1 , obtenemos uno de los puntos finales originales en la línea devuelta. Por lo tanto, sabemos que PQ (0) == P, PQ (1) == Q, RS (0) == R y RS (1) == S.
Esta forma de definir una línea paramétricamente es muy útil en muchos contextos.
Después, imagine que estábamos mirando hacia abajo a lo largo de la línea PQ. ¿Podemos encontrar el punto de menor distancia desde el segmento de línea RS a la línea infinita PQ? Esto se hace más fácilmente mediante una proyección en el espacio nulo de la línea PQ.
> N = null(P-Q)
N =
-0.37428 -0.76828
0.9078 -0.18927
-0.18927 0.61149
Por lo tanto, null (PQ) es un par de vectores de la base que abarcan la ortogonal dos subespacio dimensional a la línea PQ.
> r = (R-P)*N
r =
0.83265 -1.4306
> s = (S-P)*N
s =
1.0016 -0.37923
Esencialmente lo que hemos hecho es proyectar el vector RS en el subespacio 2 dimensiones (plano) ortogonales a la línea PQ. Al restar P (un punto en la línea PQ) para obtener rys, nos aseguramos de que la línea infinita pase por el origen en este plano de proyección.
De hecho, hemos reducido esto a la búsqueda de la distancia mínima desde la línea rs (v) al origen (0,0) en el plano de proyección. Recordemos que los rs línea (V) es definido por el parámetro v como:
rs(v) = r + v*(s-r)
El vector normal a la línea rs (v) nos dará lo que necesitamos. Como hemos reducido esto a 2 dimensiones porque el espacio original era 3-d, podemos hacerlo de manera simple. De lo contrario, me gustaría haber utilizado null de nuevo. Este pequeño truco funciona en 2-d:
> n = (s - r)*[0 -1;1 0];
> n = n/norm(n);
n ahora es un vector con la longitud de la unidad. La distancia desde la línea infinita rs (v) al origen es simple.
> d = dot(n,r)
d =
1.0491
Ver que también podría haber usado s, para obtener la misma distancia. La distancia real es abs (d), pero resulta que d fue positiva aquí de todos modos.
> d = dot(n,s)
d =
1.0491
¿Podemos determinar v a partir de esto? Sí. Recuerde que el origen es una distancia de d unidades desde la línea que conecta los puntos r y s. Por lo tanto podemos escribir d n = r + v (sr), para algún valor del escalar v. Formar el producto de puntos de cada lado de esta ecuación con el vector (sr), y resolver para v.
> v = dot(s-r,d*n-r)/dot(s-r,s-r)
v =
1.2024
Esto nos dice que el enfoque más cercano del segmento de línea rs al origen ocurrió fuera de los puntos finales del segmento de línea. Entonces realmente el punto más cercano en rs al origen fue el punto rs (1) = s.
Al retroceder desde la proyección, esto nos dice que el punto más cercano en línea segmento RS a la línea infinita PQ fue el punto S.
Hay un paso más en el análisis a seguir. ¿Cuál es el punto más cercano en el segmento de línea PQ? ¿Este punto cae dentro del segmento de línea, o también cae fuera de los puntos finales?
Proyectamos el punto S en la línea PQ. (Esta expresión para u es bastante facilidad derivado de una lógica similar como lo hacía antes. Nótese aquí que he utilizado \ para hacer el trabajo.)
> u = (Q-P)'\((S - (S*N)*N') - P)'
u =
0.95903
Ver que u se encuentra en el intervalo [0,1] . Hemos resuelto el problema El punto de PQ es
> P + u*(Q-P)
ans =
0.25817 -1.1677 1.1473
Y, la distancia entre los puntos más cercanos de los dos segmentos de línea era
> norm(P + u*(Q-P) - S)
ans =
1.071
Por supuesto, todo esto se puede comprimir en tan sólo unas pocas líneas de código . Pero ayuda a expandirlo todo para obtener una mejor comprensión de cómo funciona.
El código de SoftSurfer es bastante bueno. Tiene problemas con líneas casi paralelas. Terminé escribiendo un cheque para líneas "casi paralelas". Una vez que hice esto, funcionó bien. No estoy seguro de por qué la comprobación de líneas "casi paralelas" integradas en SoftSurfer no funcionó. Solo pensé que el siguiente usuario quisiera saber ... –
Encontré lo mismo que @TimPerry. Utilicé esta verificación paralela: bool parallel = dot (u, v)/(u.length() * v.length())> 1 - SMALL_NUM; Modificar para su biblioteca de vectores. –
@ReedCopsey Intenté dist3D_Segment_to_Segment() con los siguientes segmentos de línea: LineSegment lineSegmentA; lineSegmentA.startPoint = PointType (0., 0., 0); lineSegmentA.endPoint = PointType (1., 0., 0); LineSegment lineSegmentB; lineSegmentB.startPoint = PointType (.5,0.2,0.); lineSegmentB.endPoint = PointType (.5,1.2,0.); La distancia más cercana debe ser desde el punto final de lineSegmentB hasta el punto central de lineSegmentA, que debe tener el valor "0.2". Sin embargo, la función devuelve la distancia como "0.538". ¿Alguna idea? –