我有一个非常简单的MATLAB问题。找到两个向量的交点最简单的方法是什么?我不熟悉各种MATLAB函数--看起来应该有一个函数可以实现这个功能。
例如,如果我有一个从(0,0)到(6,6)的向量和另一个从(0,6)到(6,0)的向量,我需要确定它们相交于(3,3)。
我有一个非常简单的MATLAB问题。找到两个向量的交点最简单的方法是什么?我不熟悉各种MATLAB函数--看起来应该有一个函数可以实现这个功能。
例如,如果我有一个从(0,0)到(6,6)的向量和另一个从(0,6)到(6,0)的向量,我需要确定它们相交于(3,3)。
一种解决方法是使用此教程中推导的方程式,在二维中找到两条直线的交点 (更新:这是互联网档案馆的链接,因为该网站已经不存在)。您可以先创建两个矩阵:一个用于保存线段端点的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,则这两条线是重合的。x
和 y
矩阵包含每条线的坐标,按列组织,即第 1 列包含第 1 条线的起始和结束坐标,以此类推。此外,在我的方程中,我使用线性索引,因此例如 x(3)
相当于 x(1,2)
。 - gnovice好的,您有两个不同线上的点,想要找到它们的交点。最简单的方法是找出这两条线的方程,然后计算它们的交点。
一条直线的方程可以表示为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,则要么没有交点,要么有无限多个交点。
对于一般的多维解决方案,实际上你正在解决一系列线性系统。
首先,你需要将方程转化为线性形式: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]
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]
% 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
% 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.
因此,使用伪逆方法即使当您的M和N向量不平行时也会给出结果(但是不能平行,因为需要inv(A'.A)存在)。您可以使用此方法确定两条平行线或两个平面之间的最小距离-为此,请定义k = p2+T(2)*(p2-q2)
,然后所需的距离为h-k。还要注意,如果线是斜的,则h和k是彼此最接近的线上的点。
因此,伪逆和投影空间的使用为我们提供了一个简洁的算法来:
简洁并不意味着时间效率高。很多东西取决于您的精确伪逆函数实现- MATLAB使用svd
进行求解,从而达到容差。此外,在更高的维度和更高阶的测量度量(或矢量范数)定义中,某些结果只能近似准确。除了明显的与维度无关的实现外,这可以用于统计回归分析和代数最大化点估计的可能性。