我不能说有什么“诀窍”,但确实有一种有效的方法来判断两个共线线段是否相交。
假设我们有两个共线线段:[AB]和[CD]。
将坐标转换为1D
首先,我们需要将点的坐标转换为1D环境,因为这样比较点的位置会更容易。
这个过程非常简单:我们将从坐标中去掉y和z值。这是因为在一条直线上没有两个具有相同x值的点(只要线段不属于与x轴正交的平面)。但是如果所有点都具有相同的x值,那么我们将使用y坐标。如果所有点都具有相同的y坐标,我们将考虑z坐标。如果我们到达了这一点,那么点不能都具有相同的z坐标。
判断所有点是否具有相同的x/y坐标的方法是计算向量AB。如果AB.x等于0,则意味着我们不需要在x轴上移动从点A到点B,因此点A和点B具有相同的x值,对于点C和点D也是如此。
我主要讨论的是3D,但对于2D、4D、5D等情况,原理是相同的。
代码如下:
if AB.x == 0
if AB.y == 0
A = A.z
B = B.z
C = C.z
D = D.z
else
A = A.y
B = B.y
C = C.y
D = D.y
else
A = A.x
B = B.x
C = C.x
D = D.x
检测碰撞在最后也是相当简单的。点A、B、C和D可以有52个不同的相对位置(包括2个具有完全相同坐标的点)。在这52个位置中,有44个表示发生了碰撞,只有8个表示相反。因此,明显的解决方案是只寻找这8个位置。
但我们可以将这个数字减少到2个。实际上,如果我们考虑到A和B的坐标以及C和D的坐标是按升序排列的,那么这四个点可能有13个不同的相对位置(*请参见注释部分)。在这13个位置中,只有2个位置表示没有任何碰撞。这两个位置是D的x值小于A(
C-D A-B
)或者C的x值大于B(
A-B C-D
)。
因此,在对点A和B以及C和D进行排序后,如果false;否则返回true
,这样我们就得到了return not(D < A or B < C)
或者更简化的表达方式:return A <= D and C <= B
算法的最后部分应该如下所示:
if A < B
if C < D
return A <= D and C <= B
else
return A <= C and D <= B
else
if C < D
return B <= D and C <= A
else
return B <= C and D <= A
注意事项
位置A、B、C和D可以有13个不同的位置:
┏━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ C D ┃ C D ┃ C D ┃
┃ AB ┃ A B ┃ A B ┃
┃━━━━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━━┫
┃ C D ┃ C D ┃ C D ┃
┃ A B ┃ A B ┃ A B ┃
┣━━━━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━━┫
┃ C D ┃ C D ┃ C D ┃
┃ A B ┃ A B ┃ AB ┃
┣━━━━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━━┫
┃ C D ┃ C D ┃ C D ┃
┃ A B ┃ A B ┃ A B ┃
┣━━━━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━━┫
┃ C D ┃ ┃ ┃
┃ AB ┃ ┃ ┃
┗━━━━━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━━━━━━┛