首先,两个几何对象 A 和 B 之间的距离是什么?它是 A 和 B 上任意两点之间的最小距离,即
dist(A,B) = min { EuclideanLength(x - y) | x in A, y in B}
。(如果存在且唯一,则在您的情况下确实存在。)
这里的
EuclideanLength((x,y,z)) = sqrt(x^2 + y^2 + z^2)
,正如您已经知道的那样。因为
sqrt
是严格递增的,所以最小化
SquareEuclideanLength((x,y,z)) = x^2 + y^2 + z^2
就足够了,这大大简化了问题。
在您的问题中,对象是线段
A := {v1 + t*(v2-v1) | 0 <= t <= 1}
和一条直线
B := {p + s*d | s is any real number}
。(不用担心您问的是射线,直线才是您想要的。)
现在计算距离就是要找到适当的t
和s
,使得SquareEuclideanLength(v1 + t*(v2-v1) - p - s*d)
最小,然后计算EuclideanLength(v1 + t*(v2-v1) - p - s*d)
以获得实际距离。
为了解决这个问题,我们需要一些解析几何知识。因为d
不为零,我们可以将每个向量v
写成与d
正交的部分和d
的倍数之和的形式:v = Ov + Mv
。对于这样的“正交分解”,它总是满足SquareEuclideanLength(v) = SquareEuclideanLength(Ov) + SquareEuclideanLength(Mv)
。
由于上述中有d = Md
SquareEuclideanLength(v1 + t*(v2-v1) - p - s*d) =
SquareEuclideanLength(Ov1 + t*(Ov2-Ov1) - Op)
+ SquareEuclideanLength(Mv1 + t*(Mv2-Mv1) - Mp - s*d)
左边的被加数不取决于s
,而你无论如何选择t
,都可以找到一个s
使右边的被加数为0!(记住,Mv1
、Mv2
等都是d
的倍数。)
因此,要找到最小值,你只需要找到这样的映射O
、M
,并找到极小化器t
。
假设d
已经被标准化,则它们实际上由Ov := CrossProduct(v, d)
和Mv := DotProduct(v, d)*d
给出,但请相信我,如果d
没有被标准化,这也是有效的。
现在找到距离的方法是:找到0 <= t <= 1
,使其最小化
SquareEuclideanLength(Cross(v1 - p, d) + t*Cross(v2 - v1, d))
= SquareEuclideanLength(Cross(v1 - p, d))
+ 2*t*Dot(Cross(v1 - p, d), Cross(v2 - v1, d))
+ t^2 SquareEuclideanLength(Cross(v2 - v1, d))
。
您可能已经从点线距离计算中了解到这个公式(就是它),通过对t
求导并将其等于0来解决。
因此,这个方程的最小化器是
t = -Dot(Cross(v1 - p, d), Cross(v2 - v1, d))/SquareEuclideanLength(Cross(v2 - v1, d))
使用这个t
,您可以计算出线段A上距离线B最近的点v1 + t*(v2 - v1)
,然后将其插入到您的点线距离算法中以找到所需的距离。
希望这能帮助您!