这段代码试图找到两条线段AB和CD的交点。
有许多不同的方法来解释它是如何做到这一点的,这取决于你如何解释这些操作。
假设点A的坐标为(xa, ya),B为(xb, yb)等等。
dxAB = xb - xa
dyAB = yb - ya
dxCD = xd - xc
dyCD = yd - yc
以下是两个线性方程组:
3x + 2y = 8
-2x + y = 2
| dxAB dxCD | | t | | xc-xa |
| | * | | = | |
| dyAB dyCD | | u | | yc-ya |
如果解决了
t
和
u
,将为您提供在线AB上交点的比例位置(值
t
)和在线CD上的比例位置(值
u
)。如果该点属于相应线段,则这些值将位于
[0, 1]
范围内,如果该点位于线段外(在线段所在的直线上),则这些值将超出该范围。
为了解决这个线性方程组,我们可以使用众所周知的
克莱姆法则。为此,我们需要计算行列式。
| dxAB dxCD |
| |
| dyAB dyCD |
这正是您代码中的determinant(b - a, c - d)
。实际上,我这里有determinant(b - a, d - c)
,但对于本次解释的目的并不重要。您发布的代码出于某种原因交换了C和D,请参见下面的P.S.注释。
我们还需要计算
| xc-xa dxCD |
| |
| yc-ya dyCD |
这与你的代码中的 determinant(c-a,c-d)
精确相符,而且是
| dxAB xc-xa |
| |
| dyAB yc-ya |
这里涉及的是 determinant(b-a,c-a)
的计算。
按照克莱姆法则对这些行列式进行分解,将给出 t
和 u
的值,这正是您发布的代码中所做的。
然后,该代码继续测试 t
和 u
的值,以检查线段是否实际相交,即它们都属于 [0,1]
范围。如果是,则通过评估 a*t+b*(1-t)
(等效地,它可以评估 c*u+d*(1-u)
)来计算实际的交点。(再次查看下面的 P.S. 注释)。
P.S. 在原始代码中,点 D 和 C 有一种“交换”的方式,即代码执行 c - d
,而我在我的说明中执行 d - c
。但是,只要小心符号,这对于算法的一般思想没有影响。
这种交换 C 和 D 点的原因也是在计算交点时使用 a*(1-t)+t*b
表达式的原因。通常情况下,如在我的解释中,人们会期望看到类似于 a*t+b*(1-t)
的表达式。 (不过我对此有些怀疑。我希望在您的版本中也能看到 a*t+b*(1-t)
。可能是个 bug。)
P.P.S. 代码作者忘记检查 det == 0
(或非常接近 0),这种情况发生在线段平行的情况下。