Я отвечу на это в терминах matlab, но могут использоваться другие среды программирования. Добавлю, что это решение действительно для решения проблемы в любом количестве измерений (> = 3).
Предположим, что у нас есть два отрезка в пространстве, PQ и RS. Вот несколько случайных множеств точек.
> 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
Бесконечная линия PQ (т) легко определяется как
PQ(u) = P + u*(Q-P)
Аналогично, мы имеем
RS(v) = R + v*(S-R)
Смотрите, что для каждой строки, если параметр равен 0 или 1 , мы получаем одну из исходных конечных точек на возвращаемой строке. Таким образом, мы знаем, что PQ (0) == P, PQ (1) == Q, RS (0) == R и RS (1) == S.
Этот способ определения линии параметрически равен очень полезно во многих контекстах.
Далее, представьте, что мы смотрели вниз по линии PQ. Можем ли мы найти точку наименьшего расстояния от отрезка линии RS до бесконечной линии PQ? Это проще всего сделать с помощью проекции в нулевое пространство прямой PQ.
> N = null(P-Q)
N =
-0.37428 -0.76828
0.9078 -0.18927
-0.18927 0.61149
Таким образом, нулевой (PQ) представляет собой пару базисных векторов, которые охватывают два мерное подпространство, ортогональное к линии PQ.
> r = (R-P)*N
r =
0.83265 -1.4306
> s = (S-P)*N
s =
1.0016 -0.37923
По сути то, что мы сделали, это спроецировать вектор RS в положении 2 подпространства (плоскость), перпендикулярные линии PQ. Вычитая P (точку на линии PQ), чтобы получить r и s, мы гарантируем, что бесконечная линия проходит через начало координат в этой плоскости проектирования.
Итак, мы уменьшили это до нахождения минимального расстояния от линии rs (v) до начала координат (0,0) в плоскости проекции. Напомним, что линия RS (V) определяется параметром V, как:
rs(v) = r + v*(s-r)
вектор нормали к линии RS (v) даст нам то, что нам нужно. Поскольку мы уменьшили это до 2 измерений, потому что исходное пространство было 3-d, мы можем сделать это просто. В противном случае я бы просто снова использовал null. Этот небольшой трюк работает в 2-х:
> n = (s - r)*[0 -1;1 0];
> n = n/norm(n);
n теперь вектор с единичной длиной. Расстояние от бесконечной прямой rs (v) до начала координат прост.
> d = dot(n,r)
d =
1.0491
Посмотрите, что я мог бы также использовать s, чтобы получить то же расстояние. Фактическое расстояние - abs (d), но, как оказалось, d всегда был положительным.
> d = dot(n,s)
d =
1.0491
Можем ли мы определить v из этого? Да. Напомним, что начало координат - это расстояние d единиц от линии, соединяющей точки r и s. Поэтому можно записать д п = R + v (SR), при некотором значении скалярного ст. Форма скалярного произведения каждой части этого уравнения с вектором (SR), и решить для ст.
> v = dot(s-r,d*n-r)/dot(s-r,s-r)
v =
1.2024
Это говорит о том, что ближайший подход отрезка rs к началу координат происходил вне конечных точек отрезка. Так что самой близкой точкой на rs к началу координат была точка rs (1) = s.
Резерв из проекции, это говорит о том, что ближайшей точкой на отрезке линии RS до бесконечной прямой PQ была точка S.
В анализе есть еще один шаг. Какова ближайшая точка на сегменте линии PQ? Оказывает ли эта точка внутри сегмента линии, или она слишком падает за пределы конечных точек?
Проецируем точку S на прямую PQ. (Это выражение для и достаточно легко вывести из подобной логики, как я делал раньше. Обратите внимание на то, что я использовал \, чтобы сделать работу.)
> u = (Q-P)'\((S - (S*N)*N') - P)'
u =
0.95903
Смотрите, что и лежит в интервале [0,1] , Мы решили проблему. Точка на линии PQ является
> P + u*(Q-P)
ans =
0.25817 -1.1677 1.1473
А, расстояние между ближайшими точками на двух отрезков был
> norm(P + u*(Q-P) - S)
ans =
1.071
Конечно, все это может быть сжаты в течение нескольких коротких строк кода , Но это помогает расширить все это, чтобы понять, как это работает.
Код SoftSurfer довольно хорош. У него проблемы с почти параллельными линиями. В итоге я написал чек на «почти параллельные» линии. Как только я это сделал, он работал хорошо. Я не уверен, почему проверка на «почти параллельные» линии, встроенные в SoftSurfer, не сработала. Просто подумал, что следующий пользователь хотел бы знать .... –
Я нашел то же самое, что @TimPerry. Я использовал эту параллельную проверку: bool parallel = dot (u, v)/(u.length() * v.length())> 1 - SMALL_NUM; Изменить для вашей векторной библиотеки. –
@ReedCopsey Я попробовал dist3D_Segment_to_Segment() со следующими сегментами строк: LineSegment lineSegmentA; lineSegmentA.startPoint = PointType (0., 0., 0). lineSegmentA.endPoint = PointType (1., 0., 0.); LineSegment lineSegmentB; lineSegmentB.startPoint = PointType (.0,0.2,0.); lineSegmentB.endPoint = PointType (.5,1,2,0.); Ближайшее расстояние должно быть от конечного пункта lineSegmentB до центральной точки линииSegmentA, которая должна иметь значение «0,2». Однако функция возвращает расстояние «0,538». Есть предположения? –