Matlab - Найти точку пересечения между двумя векторами

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

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

Ответы

Ответ 1

Одним из решений является использование уравнений, полученных в этот учебник для поиска точки пересечения двух строк в 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, то две линии совпадают.

Ответ 2

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

Уравнение прямой задается формулой 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, то либо пересечения, либо бесконечно много пересечений не будет.

Ответ 3

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

Сначала вам нужно свести уравнения к линейной форме: 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]

Ответ 4

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

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

% 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.

Полное описание представлено ниже. В нем представлена ​​простая схема обнаружения исключений, их обработка предоставляется пользователю. (Минимальное расстояние между двумя строчными алгоритмами - от wikipedia, сравнение косинусов направления (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 algo.

% 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 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 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 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 - точки на линиях, которые ближе всего друг к другу.

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

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

Enjoy.

-ssh