Найти точку пересечения двух векторов в MATLAB - PullRequest
13 голосов
/ 12 января 2010

У меня очень простой вопрос MATLAB. Какой самый простой способ найти точку пересечения между двумя векторами. Я не знаком с различными функциями MATLAB - похоже, для этого должна быть одна.

Например, если у меня есть один вектор от (0,0) до (6,6) и другой вектор от (0,6) до (6,0), мне нужно определить, что они пересекаются в (3 3).

Ответы [ 4 ]

13 голосов
/ 12 января 2010

Одним из решений является использование уравнений, полученных в этого руководства, для нахождения точки пересечения двух линий в 2-D ( update: это ссылка на интернет-архив, поскольку сайт более не существует). Сначала вы можете создать две матрицы: одну для хранения координат x конечных точек линии и одну для хранения координат y.

x = [0 0; 6 6];  %# Starting points in first row, ending points in second row
y = [0 6; 6 0];

Уравнения из вышеупомянутого источника могут быть затем закодированы следующим образом:

dx = diff(x);  %# Take the differences down each column
dy = diff(y);
den = dx(1)*dy(2)-dy(1)*dx(2);  %# Precompute the denominator
ua = (dx(2)*(y(1)-y(3))-dy(2)*(x(1)-x(3)))/den;
ub = (dx(1)*(y(1)-y(3))-dy(1)*(x(1)-x(3)))/den;

И теперь вы можете вычислить точку пересечения двух линий:

xi = x(1)+ua*dx(1);
yi = y(1)+ua*dy(1);

Для примера в вопросе приведенный выше код дает xi = 3 и yi = 3, как и ожидалось. Если вы хотите проверить, что точка пересечения лежит между конечными точками линий (т.е. они являются конечной линией отрезков ), вам просто нужно проверить, что значения ua и ub оба лежат между 0 и 1:

isInSegment = all(([ua ub] >= 0) & ([ua ub] <= 1));

Еще пара моментов из урока, с которым я связан выше:

  • Если знаменатель den равен 0, тогда две линии параллельны.
  • Если знаменатель и числитель для уравнений для ua и ub равны 0, тогда две строки совпадают.
8 голосов
/ 12 января 2010

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

Уравнение линии задается как y = mx + b , где m - наклон, а b - y-перехват. Для одной линии у вас есть две точки, которые дают два уравнения. Итак, вы можете решить для констант m и b . Это дает следующие два уравнения:

 0 = 0*m + 1*b  % Using the first point x=y=0 into y=m*x+b
 6 = 6*m + 1*b  % Using the second point x=y=6

Или в матричной форме:

 [ 0 ] = [ 0 1 ]* [ m ]
 [ 6 ]   [ 6 1 ]  [ b ]

Для первой строки константы могут быть вычислены в MATLAB как

 C1 = inv([0 1;6 1]*[1;0]; % m=C1(1) and b=C(2)

Теперь, когда у вас есть уравнение для двух линий, вы можете решить для пересечения, решив следующую систему уравнений (которые получаются путем манипулирования уравнением для линии):

 m_1*x-y = -b_1
 m_2*x-y = -b_2

Осталось только написать вышеуказанную систему уравнений в матричной форме и решить:

 [x] = inv [m_1 -1] * [-b_1]
 [y]       [m_2 -1]   [-b_2]

Или в синтаксисе MATLAB:

 I = inv([m_1 -1; m_2 -1])*[-b_1;-b_2]; % I is the intersection.

Примечания

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

  • Если два уклона равны, m_1 = m_2, то пересечений не будет или будет бесконечно много пересечений.

2 голосов
/ 12 января 2010

Для общего многомерного решения на самом деле вы решаете ряд линейных систем.

Сначала необходимо привести уравнения к линейной форме: Ax+By=C (при необходимости расширить размеры)

Для двухточечных:

y - y1 = (y2 - y1) / (x2 - x1) * (x - x1)
y - y1 = (y2 - y1) / (x2 - x1) * x - (y2 - y1) / (x2 - x1) * x1
(y1 - y2) / (x2 - x1) * x + y - y1 = (y1 - y2) / (x2 - x1) * x1
(y1 - y2) / (x2 - x1) * x + y = (y1 - y2) / (x2 - x1) * x1 + y1
(y1 - y2) * x + (x2 - x1) * y = (y1 - y2) * x1 + (x2 - x1) * y1

A = (y1 - y2)
B = (x2 - x1)
C = (y1 - y2) * x1 + (x2 - x1) * y1 = A * x1 + B * y1

Для вашего примера:

x1 = 0, x2 = 6, y1 = 0, y2 = 6
A1 = (0 - 6) = -6
B1 = (6 - 0) = 6
C1 = A1 * 0 + B1 * 0 = 0

x1 = 0, x2 = 6, y1 = 6, y2 = 0
A2 = (6 - 0) = 6
B2 = (6 - 0) = 6
C2 = A2 * 0 + B2 * 6 = 6 * 6 = 36

Затем сформируйте матрицу с A B и C в строках:

[A1 B1 C1]
[A2 B2 C2]

[-6 6 0]
[ 6 6 36]

Теперь приведите к уменьшенной форме эшелона, используя функцию Matlab rref(matrix):

[ 1 0 3]
[ 0 1 3]

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

dim = 2;

% Do other stuff, ending with rref(matrix)

if (matrix(:,1:dim) == eye(dim))
    % Matrix has unique solution.
    solution = (matrix(:,dim+1))'
else
    % No unique solution.
end

В двух измерениях возможны следующие варианты:

Линейное решение, обозначающее решение в виде строки x + By = C:
[ 1 B C]
[ 0 0 0]

Нет решения, указывающего, что линии не пересекаются, где C2 <> 0:
[ 1 B C1]
[ 0 0 C2]

1 голос
/ 02 июля 2013

Другие результаты сбивают с толку, многословны и неполны, ИМО. Итак, вот мои два цента - также потенциально запутанные и многословные.

Если вы уверены, что ваши линии не параллельны или параллельны, вам нужно следующее:

% Let each point be def as a 3x1 array
% Let points defining first line be  : p1, q1
% Let points defining second line be : p2, q2

L = p1-p2;
M = p1-q1;
N = p2-q2;
A = [M N];
T = pinv(A)*L;
h = p1-T(1)*(p1-q1); % h is a 3x1 array representing the actual pt of intersection

Да, псевдообратная Мура-Пенроуза - мощная вещь. Объяснение этого подхода таково: вы хотите найти весовые коэффициенты или коэффициенты масштабирования «векторов направления» (M и N - векторы направления), которые линейно объединяют M и N, чтобы получить L.

Полное описание представлено ниже. Он представляет простую схему обнаружения исключений, и их обработка остается за пользователем. (Минимальное расстояние между двумя линейными алгоритмами взято из Википедии; сравнение направляющих косинусов (DCS) для проверки ориентации вектора является общеизвестным.)

% Let each point be def as a 3x1 array
% Let points defining first line be : p1, q1
% Let points defining second line be: p2, q2

% There are two conditions that prevent intersection of line segments/lines
% in L3 space. 1. parallel 2. skew-parallel (two lines on parallel planes do not intersect)
% Both conditions need to be identified and handled in a general algorithm.

% First check that lines are not parallel, this is done by comparing DCS of
% the line vectors
% L, M, N ARE DIRECTION VECTORS.
L = p1-p2;
M = p1-q1;
N = p2-q2;

% Calculate a normalized DCS for comparison. If equal, it means lines are parallel.
MVectorMagnitude = sqrt(sum(M.*M,2)); % The rowsum is just a generalization for N-D vectors.
NVectorMagnitude=sqrt(sum(N.*N,2)); % The rowsum is just a generalization for N-D vectors.

if isequal(M/MVectorMagnitude,N/NVectorMagnitude) % Compare the DCS for equality
     fprintf('%s\n', 'lines are parallel. End routine')
end;

% Now check that lines do not exist on parallel planes
% This is done by checking the minimum distance between the two lines. If there's a minimum distance, then the lines are skew.

a1 = dot(M,L); b1 = dot(M,M); c1 = dot(M,N);
a2 = dot(N,L); b2 = dot(N,M); c2 = dot(N,N);

s1 = -(a1*c2 - a2*c1)/(b1*c2-b2*c1);
s2 = -(a1*b2 - a2*b1)/(b1*c2-b2*c1);

Sm = (L + s1*M - s2*N);
s = sqrt(sum(Sm.*Sm,2));

if ~isequal(s,0) % If the minimum distance between two lines is not zero, then the lines do not intersect
    fprintf('%s\n','lines are skew. End routine')
end;

% Here's the actual calculation of the point of intersection of two lines.
A = [M N];
T = pinv(A)*L;
h = p1-T(1)*(p1-q1); % h is a 3x1 array representing the actual pt of intersection.

Таким образом, подход pinv даст вам результаты, даже если ваши векторы M и N перекошены (но не параллельны, потому что inv (A'.A) должен существовать). Вы можете использовать это, чтобы определить минимальное расстояние между двумя параллельными линиями или между двумя параллельными плоскостями - для этого определите k = p2+T(2)*(p2-q2), и тогда требуемое расстояние будет h-k. Также обратите внимание, что h и k - это точки на линиях, которые находятся ближе всего друг к другу. Линии IFF перекошены.

Таким образом, использование псевдообратного и проекционного пространств дает нам краткий алгоритм для:

  1. Определение точки пересечения двух прямых (не параллельных и не косых)
  2. Определение минимального расстояния между двумя линиями (не параллельно)
  3. Определение точек, ближайших друг к другу на двух наклонных линиях.

Лаконичность - это не то же самое, что экономия времени. Многое зависит от вашей точной реализации функции pinv - MATLAB использует svd, что решает проблему с допуском. Кроме того, некоторые результаты будут только приблизительно точными в более высоких измерениях и более высоких порядках определения метрики измерения (или векторных норм). Помимо реализации, не зависящей от очевидного измерения, она может использоваться в статистическом регрессионном анализе и алгебраически максимизировать вероятность точечных оценок.

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