Расчет кратчайшего расстояния между двумя линиями (отрезками) в 3D - PullRequest
22 голосов
/ 09 марта 2009

У меня есть два линейных сегмента: X1, Y1, Z1 - X2, Y2, Z2 и X3, Y3, Z3 - X4, Y4, Z4

Я пытаюсь найти кратчайшее расстояние между двумя сегментами.

Я искал решение в течение нескольких часов, но все они, похоже, работают с линиями, а не с отрезками.

Есть идеи, как это сделать, или какие-нибудь источники фурмул?

Ответы [ 6 ]

27 голосов
/ 31 марта 2009

Я отвечу на это в терминах 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 (t) легко определяется как

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

Таким образом, нуль (P-Q) - это пара базисных векторов, которые охватывают двумерное подпространство, ортогональное прямой 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-м, мы можем сделать это просто. В противном случае, я бы просто использовал 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 = dot(n,s)
d =
       1.0491

Можем ли мы определить V из этого? Да. Напомним, что начало координат - это расстояние d единиц от линии, соединяющей точки r и s. Поэтому мы можем записать d n = r + v (sr) для некоторого значения скаляра v. Сформировать точечное произведение каждой стороны этого уравнения с вектором (sr) и решить для v.

> 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

Смотрите, что u лежит в интервале [0,1]. Мы решили проблему. Точка на линии PQ равна

> P + u*(Q-P)
ans =
      0.25817      -1.1677       1.1473

И, расстояние между ближайшими точками на двух отрезках линии было

> norm(P + u*(Q-P) - S)
ans =
        1.071

Конечно, все это можно сжать в несколько коротких строк кода. Но это помогает расширить все это, чтобы понять, как это работает.

19 голосов
/ 09 марта 2009

Один базовый подход аналогичен вычислению кратчайшего расстояния между двумя линиями, за одним исключением.

Если вы посмотрите на большинство алгоритмов нахождения кратчайшего расстояния между двумя линиями, вы обнаружите, что он находит точки на каждой линии, которые являются ближайшими, а затем вычисляет расстояние от них.

Уловка, позволяющая распространить это на сегменты (или лучи), состоит в том, чтобы увидеть, находится ли эта точка за пределами одной из конечных точек линии, и, если это так, использовать конечную точку вместо фактической ближайшей точки на бесконечной линии .

Для конкретного образца см .:

http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm

Более конкретно:

http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm#dist3D_Segment_to_Segment()

2 голосов
/ 09 марта 2009

Я бы параметризовал оба отрезка, чтобы использовать один параметр каждый, ограниченный от 0 до 1 включительно. Затем найдите разницу между обеими линейными функциями и используйте ее в качестве целевой функции в задаче линейной оптимизации с параметрами в качестве переменных.

Допустим, у вас есть строка от (0,0,0) до (1,0,0), а другая от (0,1,0) до (0,0,0) (да, я использую простые). Строки могут быть параметризованы как (1 * t, 0 * t, 0 * t), где t лежит в [0,1] и (0 * s, 1 * s, 0 * s), где s лежит в [0,1 ], не зависит от т.

Тогда вам нужно минимизировать || (1 * t, 1 * s, 0) || где t, s лежат в [0,1]. Это довольно простая проблема, которую нужно решить.

0 голосов
/ 09 апреля 2017

Сначала найдите ближайший подход, соединяющий отрезок линии между их расширенными линиями. Давайте назовем это LineSeg BR.

Если BR.endPt1 падает на LS1, а BR.endPt2 падает на LS2, все готово ... просто рассчитайте длину BR.

Если BR моста пересекает LS1, но не LS2, используйте более короткое из этих двух расстояний: меньший по размеру (dist (BR.endPt1, LS2.endPt1), dist (BR.endPt1, LS2.endPt2))

Если мост BR пересекает LS2, но не LS1, используйте более короткое из этих двух расстояний: меньшийOf (dist (BR.endPt2, LS1.endPt1), dist (BR.endPt2, LS1.endPt2))

Если ни одно из этих условий не выполняется, самое близкое расстояние - это самое близкое спаривание конечных точек на противоположных сегментных линиях.

0 голосов
/ 05 марта 2017

Нахождение расстояния между двумя конечными линиями на основе нахождения между двумя бесконечными линиями, а затем привязка бесконечных линий к конечным линиям не всегда работает. например попробуйте это очки

Q=[5 2 0]
P=[2 2 0]
S=[3 3.25 0]
R=[0 3 0]

Основываясь на бесконечном приближении, алгоритм выбирает R и P для расчета расстояния (расстояние = 2,2361), но где-то посередине R и S находится ближе к точке P. Очевидно, что выбор P и [2 3.166] от линии R до S имеет меньшее расстояние 1.1666. Даже этот ответ мог бы стать лучше благодаря точному вычислению и нахождению ортогональной линии от линии P до R S.

0 голосов
/ 09 марта 2009

Как насчет расширения отрезков на бесконечные линии и нахождения кратчайшего расстояния между двумя линиями. Затем найдите точки на каждой линии, которые являются конечными точками отрезка линии наименьшего расстояния.

Если точка для каждой линии находится на исходном отрезке, то у вас есть ответ. Если точка для каждой линии не находится на исходном отрезке, то эта точка является одной из конечных точек исходных отрезков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...