推导:
我们已经知道,从一点P
到无限线的最短距离由穿过 的无限线的垂线给出P
。需要注意的是,我们正在处理沿着这条无限线的线段,并且垂直线交叉可能落在线段之外。让我们从三点的定义开始:
P = [xP yP]; % Point coordinates
A = [xA yA]; % Starting point of line segment
B = [xB yB]; % Ending point of line segment
现在,让我们考虑向量和之间的点积,并且 on 的标量投影等于,两个向量的点积除以 的大小。这是沿向量的分量,并给出了我们与穿过和的无限线之间距离最短的点(即垂直交点)。如果我们再次将该分量除以它的大小,我们将得到一个参数值,即在 point 为 0,在 point 为1 。超出范围的值AP
AB
AP
AB
dot(AP, AB)/|AB|
AB
AP
AB
P
A
B
AB
A
B
[0 1]
表示最短距离发生在线段之外,距离线段最近的点将P
成为线段端点之一。
现在我们可以组合一个算法:
vec = B-A; % Vector from A to B
u = vec*(P-A).'/(vec*vec.'); % Parametric value along AB
if (u <= 0) % Perpendicular is outside segment, closest to A
C = A;
elseif (u >= 1) % Perpendicular is outside segment, closest to B
C = B;
else % Closest point is within segment
C = A+u.*vec;
end
并且C
会给你沿着你的线段AB
最接近的点P
。将此计算扩展到以矢量化方式同时处理多个线段将需要对上述代码进行一些修改......
矢量化解决方案:
让我们首先定义一个点和一组 3 条线段用于此示例:
P = [ 1 1];
A = [ 0 0; ... % Starting points (x, y) of segments
-3 3; ...
0 4];
B = [ 2 -2; ... % Ending points (x, y) of segments
-1 1; ...
3 1];
现在我们将复制 的行P
以匹配A
和B
,重新进行计算u
以容纳多个段,并将参数检查转换为索引操作:
P = repmat(P, [size(A, 1) 1]);
vec = B-A;
u = sum(vec.*(P-A), 2)./sum(vec.*vec, 2);
C = A+[u u].*vec;
C(u < 0, :) = A(u < 0, :);
C(u > 1, :) = B(u >1, :);
这会产生以下结果C
:
C =
0 0
-1 1
2 2
我们可以将其可视化如下:
plot([A(:,1) B(:,1)].', [A(:,2) B(:,2)].', 'r', 'LineWidth', 2);
hold on;
axis equal;
plot(P(1, 1), P(1, 2), 'bo', 'MarkerSize', 16);
plot([P(:,1) C(:,1)].', [P(:,2) C(:,2)].', 'm--');
