判断3维空间中两线段是否相交

  • 判断这条线段与选中线段是否共面
  • 若两线段共面 判断两线段是否满足快速排斥实验
  • 若两线段满足快速排斥实验 判断两条线段是否满足跨立实验
  • 若满足跨立实验 则认为两条线段相交
# ---------------------------------------------------------------------------------------- #
#  判断两条线段是否共面  (任取两条线段的三个端点,计算这三个端点中随意构成的两个向量的叉积N【叉积垂直于三点构成的平面】;用叉积N与未曾参与计算的那个端点所在的向量做点积 若点积为0则两条线段共面)
# ---------------------------------------------------------------------------------------- #
# V1[[x1,y1, z1], [x2, y2, z2]]
# 计算两点表示的两个三维向量的叉积  N = [NX2-NX1, NY2-NY1, NZ2-NZ1]
def CrossProduct3D(V1, V2):
    '''
    计算端点表示的三维向量的叉积
    :param V1: 两端点表示的向量  例如 V1=[[x1,y1, z1], [x2, y2, z2]]
    :param V2: 两端点表示的向量  例如 V2=[[x1,y1, z1], [x2, y2, z2]]
    :return: 两向量的叉积, 向量坐标表示的向量 例如 N = [Xn1, Yn1, Zn1]  (其中Xn1 = x2-x1 若N=[[x1,y1, z1], [x2, y2, z2]])
    '''
    N = [(V1[1][1]-V1[0][1])*(V2[1][2]-V2[0][2]) - (V1[1][2]-V1[0][2])*(V2[1][1]-V2[0][1]),
         -((V1[1][2]-V1[0][2])*(V2[1][0]-V2[0][0]) - (V1[1][0]-V1[0][0])*(V2[1][2]-V2[0][2])),
         (V1[1][0]-V1[0][0])*(V2[1][1]-V2[0][1]) - (V1[1][1]-V1[0][1])*(V2[1][0]-V2[0][0])]
    return N


# V1[V1X, V1Y, V1Z]
# 计算坐标表示的两个三维向量的点积
def DotProduct3D(V1, V2):
    '''
    计算向量坐标表示的三维向量的点积
    :param V1: 向量坐标表示的向量 例如 V1 = [Xv1, Yv1, Zv1]  (其中Xv1 = x2-x1 若V1=[[x1,y1, z1], [x2, y2, z2]])
    :param V2: 向量坐标表示的向量 例如 V2 = [Xv2, Yv2, Zv2]
    :return: 两向量的点积,数值
    '''
    Dot = V1[0]*V2[0] + V1[1]*V2[1] + V1[2]*V2[2]
    return Dot


# V1[[x1,y1, z1], [x2, y2, z2]]
# V2[[x1,y1, z1], [x2, y2, z2]]
# 判断两条线段是否共面
def twoLineSegmentCoplanar3D(V1, V2):
    '''
    判断三维空间中的两条线段是否共面
    :param V1: 两端点表示的向量  例如 V1=[[x1,y1, z1], [x2, y2, z2]]
    :param V2: 两端点表示的向量  例如 V2=[[x1,y1, z1], [x2, y2, z2]]
    :return: 若共面则True 否则False
    '''
    tempV1 = V1
    tempV2 = [V1[0], V2[1]]
    N = CrossProduct3D(tempV1, tempV2)
    V2p = [V2[1][0]-V2[0][0], V2[1][1]-V2[0][1], V2[1][2]-V2[0][2]]
    if abs(DotProduct3D(N, V2p)) <0.0001:
        return True
    else:
        return False

# ---------------------------------------------------------------------------------------- #
#  快速排斥法  排除一部分不满足条件的线段
# ---------------------------------------------------------------------------------------- #

# 三维空间中快速排斥
# Vo[[x1,y1, z1], [x2, y2, z2]]
def RapidRepel(Vo, Vp):
    '''
    快速排斥法,排除三维空间中不可能相交的线段
    :param Vo: 两端点表示的向量  例如 Vo=[[x1,y1, z1], [x2, y2, z2]]
    :param Vp: 两端点表示的向量  例如 Vp=[[x1,y1, z1], [x2, y2, z2]]
    :return: 若通过快速排斥 则表示两线段可能相交 返回True;否则Falsse
    '''
    if (        max(Vo[0][0], Vo[1][0]) >= min(Vp[0][0], Vp[1][0])
            and min(Vo[0][0], Vo[1][0]) <= max(Vp[0][0], Vp[1][0])
            and max(Vo[0][1], Vo[1][1]) >= min(Vp[0][1], Vp[1][1])
            and min(Vo[0][1], Vo[1][1]) <= max(Vp[0][1], Vp[1][1])
            and max(Vo[0][2], Vo[1][2]) >= min(Vp[0][2], Vp[1][2])
            and min(Vo[0][2], Vo[1][2]) <= max(Vp[0][2], Vp[1][2])
    ):
        return True
    else:
        return False


# ---------------------------------------------------------------------------------------- #
#  跨立实验  若满足前面的两个条件  且通过跨立实验   则认为这两条线段是相交的  (这里先计算以一条线段的一个端点为起点与另一条线段的一个端点组成的向量tempV1,与该点为起点线段的向量的叉积N1;
#  再计算该点为起点线段的向量 与 该点为起点与另一条线段的另一个端点组成的向量TempV2 的叉积N2 计算N1、N2的点积 再以另一条线段为中间向量再进行计算 若两次计算的结果均大于0 则认为两条线段相交)
# ---------------------------------------------------------------------------------------- #
def StraddleExperiment(V1, V2):
    '''
    跨立实验,排除三维空间中不可能相交的线段
    :param V1: 两端点表示的向量  例如 V1=[[x1,y1, z1], [x2, y2, z2]]
    :param V2: 两端点表示的向量  例如 V2=[[x1,y1, z1], [x2, y2, z2]]
    :return: 通过跨立实验 返回True,否则返回False
    '''
    tempV1 = [V1[0], V2[1]]
    tempV2 = [V1[0], V2[0]]
    N1 = CrossProduct3D(tempV1, V1)
    N2 = CrossProduct3D(V1, tempV2)
    res1 = DotProduct3D(N1, N2)

    tempV3 = [V2[0], V1[1]]
    tempV4 = [V2[0], V1[0]]
    N3 = CrossProduct3D(tempV3, V2)
    N4 = CrossProduct3D(V2, tempV4)
    res2 = DotProduct3D(N3, N4)

    if res1 > 0 and res2>0:
        return True
    else:
        return False