在MATLAB中找到两个向量之间的交点

时间:2010-01-12 17:16:32

标签: math matlab

我有一个非常简单的MATLAB问题。找到两个向量之间交点的最简单方法是什么。我不熟悉各种MATLAB函数 - 看起来应该有一个。

例如,如果我有一个从(0,0)到(6,6)的向量和另一个从(0,6)到(6,0)的向量,我需要确定它们在(3, 3)。

4 个答案:

答案 0 :(得分:13)

一种解决方案是使用this tutorial for finding the intersection point of two lines in 2-D中派生的方程式(更新:这是一个互联网档案链接,因为该网站不再存在)。您可以先创建两个矩阵:一个用于保存线端点的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 = 3yi = 3。如果要检查交点是否位于线的端点之间(即它们是有限线),您只需要检查值{{1 }和ua都介于0和1之间:

ub

我上面链接的教程还有几点:

  • 如果分母isInSegment = all(([ua ub] >= 0) & ([ua ub] <= 1)); 为0,则两条线是平行的。
  • 如果denua的等式的分母和分子为0,则两条线重合。

答案 1 :(得分:8)

嗯,你真的在​​两条不同的线上有两个点,你想要找到交点。最简单的方法是找到两条线的方程,然后计算交点。

线的等式由 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 :(得分: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]

现在使用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]
    

  • 答案 3 :(得分:1)

    其他结果令人困惑,冗长和不完整,IMO。所以这是我的两分钱 - 也可能令人困惑和冗长。

    如果您确定您的线路不是平行或平行的,那么您只需要以下内容:

    % 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
    

    是的,Moore-Penrose pseudoinverse是一个强大的东西。该方法的解释是:您想要找到'方向向量'的权重或比例因子(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.
    

    因此,即使你的M和N向量是偏斜的(但不是平行的,因为要求存在inv(A'.A)),pinv方法也会给你结果。您可以使用它来确定两条平行线之间或两个平行平面之间的最小距离 - 为此,定义k = p2+T(2)*(p2-q2),然后所需的距离为h-k。另请注意,h和k是线条上彼此最接近的点,IFF线是倾斜的。

    因此,使用伪逆和投影空间为我们提供了一个简洁的算法:

    1. 确定两条线的交叉点(不平行,不倾斜)
    2. 确定两条线之间的最小距离(不平行)
    3. 确定两条偏斜线上彼此最近的点。
    4. 简洁与时间效率不同。很大程度上取决于你的确切pinv函数实现 - MATLAB使用svd来解决容差问题。此外,某些结果仅在测量度量(或矢量范数)的更高维度和更高阶定义中近似准确。除了明显的维度独立实现之外,这可以用于统计回归分析和代数最大化点估计的可能性。