Python 三维线段盒交点

Python 三维线段盒交点,python,3d,Python,3d,正在查找代码以检测三维线段(不是直线/光线)和三维长方体(不一定是立方体,但始终与轴对齐)之间的交点。长方体是体素,因此它们具有规则的间距 已具有查找线段/平面交点的代码。理想情况下,我希望找到一个有效的解决方案,将其应用于矩形,对3d长方体的每个面重复,然后迭代数万个线段和长方体 seg_start = array([x1,y1,z1]) seg_end = array([x2,y2,z2]) plane_point = array([x3,y3,z3]) plane_normal = arr

正在查找代码以检测三维线段(不是直线/光线)和三维长方体(不一定是立方体,但始终与轴对齐)之间的交点。长方体是体素,因此它们具有规则的间距

已具有查找线段/平面交点的代码。理想情况下,我希望找到一个有效的解决方案,将其应用于矩形,对3d长方体的每个面重复,然后迭代数万个线段和长方体

seg_start = array([x1,y1,z1])
seg_end = array([x2,y2,z2])
plane_point = array([x3,y3,z3])
plane_normal = array([x4,y4,z4])
u = seg_end - seg_start
w = seg_start - plane_point
D = dot(plane_normal,u)
N = -dot(plane_normal,w)
sI = N / D
if sI >= 0 and sI <= 1:
    return 1
seg_start=array([x1,y1,z1])
seg_end=数组([x2,y2,z2])
平面_点=阵列([x3,y3,z3])
平面法向=阵列([x4,y4,z4])
u=分段结束-分段开始
w=seg_起点-平面_点
D=点(平面\法线,u)
N=-点(平面_法线,w)
sI=N/D

首先,如果sI>=0且sI,则在if条件下,您可能是指
,而不是
,否则它将始终返回true。其次,如果您只是测试是否存在交叉点,您可以更快地进行测试(不使用浮点分割):

  • 您可以使用向量数学确定任何给定点位于每个平面的哪一侧:
    side=dot(我的点-平面点,平面法向)

    现在,如果
    side
    为正,
    my_点
    位于平面的“前面”(即,它位于法线指向的一侧);如果是负数,则在飞机的“后面”。如果
    side
    为零,则点位于平面上
  • 通过测试起点和终点是否位于不同的侧面,可以检查线段是否与(无限)平面相交:

    start\u side=dot(seg\u start-平面\u点,平面\u法线)
    端点侧=点(分段端点-平面点,平面法线)
    返回起始端*结束端
    #如果<0,则两个点位于不同的边上,因此相交
    #如果=0,则平面上至少有一个点
    #如果>0,则两个点位于同一侧,即没有交点
    
  • 您也可以使用“side”检查进行轴对齐的长方体相交(实际上,这适用于任何平行管道):

    • 将您的箱子视为一组六个平面
    • 确保平面法线都指向长方体的“向外”或“向内”。我假设你用的是“向外”
    • 要想让任何一点位于你的盒子里,它必须“在”所有六个平面的后面。如果不是,它就在盒子外面
    • 要使任何线段与长方体相交,一个点必须位于长方体外部,一个点必须位于长方体内部
    • 就这些
编辑:最后一点实际上不正确;正如您所说,即使两个端点都位于外部,体素也可以相交。所以这不是全部的解决方案-实际上,如果不计算交点,你就不能真正做到这一点。但是,您仍然可以使用“侧面测试”作为早期拒绝机制,以减少需要进行的完整计算的数量:如果两个点位于六个平面中任何一个平面的同一侧,则不可能存在交点


就您的具体情况而言,似乎您正在尝试查找某些给定线段的所有相交体素?在这种情况下,使用诸如显式计算路径之类的方法可能会更好,而不是测试所有体素的交点…

因为框是轴对齐的,所以您需要做的只是检查每个坐标中的间隔交点

下面是一个python示例,并进行了一些测试。请注意,它对于N维是通用的,对于长方体交点也是相同的算法:

def are_intervals_intersecting(a0, a1, b0, b1):
    '''
    @param a0: float
    @param a1: float
    @param b0: float
    @param b1: float
    '''
    if (a1 < a0):
        a1, a0 = a0, a1

    if (b1 < b0):
        b1, b0 = b0, b1

    # 6 conditions:

    # 1)
    #        a0 ---------- a1                              a0 < b0 and a1 < b0
    #                             b0 ---------- b1         (no intersection)

    # 2)
    #               a0 ---------- a1
    #                      b0 ---------- b1                (intersection)

    # 3)
    #               a0 ------------------------ a1
    #                      b0 ---------- b1                (intersection)

    # 4)
    #                      a0 ---------- a1         
    #               b0 ------------------------ b1         (intersection)

    # 5)
    #                             a0 ---------- a1         (intersection)
    #                      b0 ---------- b1

    # 6)
    #                                    a0 ---------- a1  b0 < a0 and b1 < a0         
    #               b0 ---------- b1                       (no intersection)

    if b0 < a0:
        # conditions 4, 5 and 6
        return a0 < b1 # conditions 4 and 5
    else:
        # conditions 1, 2 and 3
        return b0 < a1 # conditions 2 and 3


def is_segment_intersecting_box(P0, P1, B0, B1):
    '''
    @param P0: tuple(float)
    @param P1: tuple(float)
    @param B0: tuple(float)
    @param B1: tuple(float)
    '''
    for i in xrange(len(P0)):
        if not are_intervals_intersecting(P0[i], P1[i], B0[i], B1[i]):
            return False
    return True


if __name__ == '__main__':
    assert not is_segment_intersecting_box(
        (0.0, 0.0, 0.0), (1.0, 1.0, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0))

    assert not is_segment_intersecting_box(
        (0.0, 0.0, 0.0), (4.0, 1.0, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0))

    assert not is_segment_intersecting_box(
        (1.5, 1.5, 0.0), (4.0, 2.5, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0))

    assert is_segment_intersecting_box(
        (1.5, 1.5, 0.0), (4.0, 2.5, 2.5), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0))

    assert is_segment_intersecting_box(
        (1.5, 1.5, 1.5), (2.5, 2.5, 2.5), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0))

    assert is_segment_intersecting_box(
        (2.5, 2.5, 2.5), (2.6, 2.6, 2.6), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0))

    assert is_segment_intersecting_box(
        (2.5, 2.5), (2.5, 3.5), (2.0, 2.0), (3.0, 3.0))

    print 'ok'
def是相交的(a0、a1、b0、b1):
'''
@参数a0:浮动
@参数a1:浮动
@参数b0:浮动
@参数b1:浮动
'''
如果(a1def are_intervals_intersecting(a0, a1, b0, b1):
    '''
    @param a0: float
    @param a1: float
    @param b0: float
    @param b1: float
    '''
    if (a1 < a0):
        a1, a0 = a0, a1

    if (b1 < b0):
        b1, b0 = b0, b1

    # 6 conditions:

    # 1)
    #        a0 ---------- a1                              a0 < b0 and a1 < b0
    #                             b0 ---------- b1         (no intersection)

    # 2)
    #               a0 ---------- a1
    #                      b0 ---------- b1                (intersection)

    # 3)
    #               a0 ------------------------ a1
    #                      b0 ---------- b1                (intersection)

    # 4)
    #                      a0 ---------- a1         
    #               b0 ------------------------ b1         (intersection)

    # 5)
    #                             a0 ---------- a1         (intersection)
    #                      b0 ---------- b1

    # 6)
    #                                    a0 ---------- a1  b0 < a0 and b1 < a0         
    #               b0 ---------- b1                       (no intersection)

    if b0 < a0:
        # conditions 4, 5 and 6
        return a0 < b1 # conditions 4 and 5
    else:
        # conditions 1, 2 and 3
        return b0 < a1 # conditions 2 and 3


def is_segment_intersecting_box(P0, P1, B0, B1):
    '''
    @param P0: tuple(float)
    @param P1: tuple(float)
    @param B0: tuple(float)
    @param B1: tuple(float)
    '''
    for i in xrange(len(P0)):
        if not are_intervals_intersecting(P0[i], P1[i], B0[i], B1[i]):
            return False
    return True


if __name__ == '__main__':
    assert not is_segment_intersecting_box(
        (0.0, 0.0, 0.0), (1.0, 1.0, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0))

    assert not is_segment_intersecting_box(
        (0.0, 0.0, 0.0), (4.0, 1.0, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0))

    assert not is_segment_intersecting_box(
        (1.5, 1.5, 0.0), (4.0, 2.5, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0))

    assert is_segment_intersecting_box(
        (1.5, 1.5, 0.0), (4.0, 2.5, 2.5), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0))

    assert is_segment_intersecting_box(
        (1.5, 1.5, 1.5), (2.5, 2.5, 2.5), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0))

    assert is_segment_intersecting_box(
        (2.5, 2.5, 2.5), (2.6, 2.6, 2.6), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0))

    assert is_segment_intersecting_box(
        (2.5, 2.5), (2.5, 3.5), (2.0, 2.0), (3.0, 3.0))

    print 'ok'