Risponderò a questo in termini di MATLAB, ma è possibile utilizzare altri ambienti di programmazione. Aggiungo che questa soluzione è valida per risolvere il problema in qualsiasi numero di dimensioni (> = 3).
Supponiamo di avere due segmenti di linea nello spazio, PQ e RS. Ecco alcuni set casuali di punti.
> 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 linea infinita PQ (t) è facilmente definito come
PQ(u) = P + u*(Q-P)
Analogamente, abbiamo
RS(v) = R + v*(S-R)
vedere che per ogni linea, quando il parametro è a 0 o 1 , otteniamo uno degli endpoint originali sulla riga restituita. Quindi, sappiamo che PQ (0) == P, PQ (1) == Q, RS (0) == R e RS (1) == S.
Questo modo di definire una linea in modo parametrico è molto utile in molti contesti.
Quindi, immaginavamo di guardare lungo la linea PQ. Possiamo trovare il punto di minima distanza dal segmento di linea RS alla linea infinita PQ? Questo è fatto più facilmente da una proiezione nello spazio nullo della riga PQ.
> N = null(P-Q)
N =
-0.37428 -0.76828
0.9078 -0.18927
-0.18927 0.61149
Così, null (PQ) è una coppia di vettori di base che coprono l'ortogonale bidimensionale sottospazio alla linea PQ.
> r = (R-P)*N
r =
0.83265 -1.4306
> s = (S-P)*N
s =
1.0016 -0.37923
sostanza ciò abbiamo fatto è di proiettare RS vettoriale nel 2 sottospazio bidimensionale (aereo) ortogonali alla linea PQ. Sottraendo P (un punto sulla linea PQ) per ottenere r e s, ci assicuriamo che la linea infinita passi attraverso l'origine in questo piano di proiezione.
Quindi, in realtà, abbiamo ridotto questo valore alla ricerca della distanza minima dalla linea rs (v) all'origine (0,0) nel piano di proiezione. Ricordiamo che le RS di linea (V) è definito dal parametro v come:
rs(v) = r + v*(s-r)
Il vettore normale alla RS di linea (v) ci darà quello che ci serve. Dal momento che abbiamo ridotto questo a 2 dimensioni perché lo spazio originale era 3-d, possiamo farlo semplicemente. Altrimenti, avrei usato di nuovo null. Questo piccolo trucco funziona in 2-d:
> n = (s - r)*[0 -1;1 0];
> n = n/norm(n);
n è ora un vettore con unità di lunghezza. La distanza dalla linea infinita rs (v) all'origine è semplice.
> d = dot(n,r)
d =
1.0491
Vedere che avrei potuto anche usare s, per ottenere la stessa distanza. La distanza effettiva è abs (d), ma come risulta, d era comunque positivo qui.
> d = dot(n,s)
d =
1.0491
Possiamo determinare v da questo? Sì. Ricorda che l'origine è una distanza di unità d dalla linea che collega i punti r e s. Quindi possiamo scrivere d n = r + v (sr), per qualche valore dello scalare v. Formare il prodotto scalare di ogni lato di questa equazione con il vettore (sr), e calcolare v.
> v = dot(s-r,d*n-r)/dot(s-r,s-r)
v =
1.2024
Questo ci dice che l'approccio più vicino del segmento di linea rs all'origine è accaduto al di fuori dei punti finali del segmento di linea. Quindi il punto più vicino su rs all'origine era il punto rs (1) = s.
Backing out dalla proiezione, questo ci dice che il punto più vicino sul segmento di linea RS alla linea infinita PQ era il punto S.
C'è ancora un passo da compiere nell'analisi. Qual è il punto più vicino sul segmento di linea PQ? Questo punto cade all'interno del segmento di linea o troppo fuori dagli endpoint?
Proiettiamo il punto S sulla linea PQ. (Questa espressione per u è abbastanza facilmente derivata dalla logica simile come ho fatto prima. Notare qui che ho usato \ per fare il lavoro.)
> u = (Q-P)'\((S - (S*N)*N') - P)'
u =
0.95903
Vedi che u si trova nell'intervallo [0,1] . Abbiamo risolto il problema. Il punto sulla linea PQ è
> P + u*(Q-P)
ans =
0.25817 -1.1677 1.1473
E, la distanza tra i punti più vicini ai due segmenti di linea era
> norm(P + u*(Q-P) - S)
ans =
1.071
Naturalmente, tutto questo può essere compresso in poche righe brevi di codice . Ma aiuta a espandere tutto per capire come funziona.
Il codice SoftSurfer è abbastanza buono. Ha problemi con linee quasi parallele. Ho finito per scrivere un assegno per linee "quasi parallele". Una volta fatto questo, ha funzionato bene. Non sono sicuro del motivo per cui il controllo di linee "quasi parallele" incorporate in SoftSurfer non ha funzionato. Ho pensato che il prossimo utente vorrebbe sapere ... –
Ho trovato la stessa cosa di @TimPerry. Ho usato questo controllo parallelo: bool parallel = punto (u, v)/(u.length() * v.length())> 1 - SMALL_NUM; Modifica per la libreria vettoriale. –
@ReedCopsey Ho provato dist3D_Segment_to_Segment() con i seguenti segmenti di linea: 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 distanza più vicina dovrebbe provenire dal punto finale di LineSegmentB al punto centrale di lineSegmentA, che dovrebbe avere valore "0,2". Tuttavia, la funzione restituisce la distanza come "0.538". qualche idea? –