Math 什么';检测三角形交点最有效的方法是什么?

Math 什么';检测三角形交点最有效的方法是什么?,math,geometry,mathematical-optimization,Math,Geometry,Mathematical Optimization,如何判断两个三角形在二维欧几里德空间中是否相交?(即经典二维几何)给定每个三角形中每个顶点的(X,Y)坐标 一种方法是检查三角形A的两条边是否与三角形B的任何一条边相同,然后检查A点在B内或B点在A内的所有六种可能性 有关三角形内的点,请参见示例: 当我们在多边形上测试碰撞时,我们的多边形也有一个周围的矩形。因此,我们首先测试矩形碰撞,如果有碰撞,我们继续进行多边形碰撞检测。您真正想要的是“多边形中的点”算法。如果一个三角形的任一点在另一个三角形中,则它们相交。这里有一个好问题要问 如上所述,您

如何判断两个三角形在二维欧几里德空间中是否相交?(即经典二维几何)给定每个三角形中每个顶点的(X,Y)坐标

一种方法是检查三角形A的两条边是否与三角形B的任何一条边相同,然后检查A点在B内或B点在A内的所有六种可能性

有关三角形内的点,请参见示例:


当我们在多边形上测试碰撞时,我们的多边形也有一个周围的矩形。因此,我们首先测试矩形碰撞,如果有碰撞,我们继续进行多边形碰撞检测。

您真正想要的是“多边形中的点”算法。如果一个三角形的任一点在另一个三角形中,则它们相交。这里有一个好问题要问


如上所述,您需要检查一个点是否在三角形内。检查点是否位于闭合多边形内的最简单方法是从该点沿任意方向绘制一条直线,并计算该直线与顶点相交的次数。如果答案是奇数,那么点在多边形中,偶数,那么它在外部

要检查的最简单的直线是水平到点右侧(或其他垂直方向)的直线。这使得顶点交叉的检查几乎微不足道。以下检查应足够:

  • 点的y坐标位于 两端的y坐标 顶点的点?不,那么 不交叉

  • 该点的x坐标是否大于该点的最右端点 顶点?是的,那就不交叉了

  • 点的x坐标是否小于顶点的最左端点?是的,那就交叉了

  • 如果上述案例失败,那么您可以 使用向量的叉积 表示顶点和向量 从顶点的末端到 重点。否定答案表示点位于顶点的一侧,肯定答案表示顶点的另一侧,零答案表示顶点。这是因为叉积需要取两个向量的正弦

和的Python实现,稍加修改

def line_intersect2(v1,v2,v3,v4):
    '''
    judge if line (v1,v2) intersects with line(v3,v4)
    '''
    d = (v4[1]-v3[1])*(v2[0]-v1[0])-(v4[0]-v3[0])*(v2[1]-v1[1])
    u = (v4[0]-v3[0])*(v1[1]-v3[1])-(v4[1]-v3[1])*(v1[0]-v3[0])
    v = (v2[0]-v1[0])*(v1[1]-v3[1])-(v2[1]-v1[1])*(v1[0]-v3[0])
    if d<0:
        u,v,d= -u,-v,-d
    return (0<=u<=d) and (0<=v<=d)

def point_in_triangle2(A,B,C,P):
    v0 = [C[0]-A[0], C[1]-A[1]]
    v1 = [B[0]-A[0], B[1]-A[1]]
    v2 = [P[0]-A[0], P[1]-A[1]]
    cross = lambda u,v: u[0]*v[1]-u[1]*v[0]
    u = cross(v2,v0)
    v = cross(v1,v2)
    d = cross(v1,v0)
    if d<0:
        u,v,d = -u,-v,-d
    return u>=0 and v>=0 and (u+v) <= d

def tri_intersect2(t1, t2):
    '''
    judge if two triangles in a plane intersect 
    '''
    if line_intersect2(t1[0],t1[1],t2[0],t2[1]): return True
    if line_intersect2(t1[0],t1[1],t2[0],t2[2]): return True
    if line_intersect2(t1[0],t1[1],t2[1],t2[2]): return True
    if line_intersect2(t1[0],t1[2],t2[0],t2[1]): return True
    if line_intersect2(t1[0],t1[2],t2[0],t2[2]): return True
    if line_intersect2(t1[0],t1[2],t2[1],t2[2]): return True
    if line_intersect2(t1[1],t1[2],t2[0],t2[1]): return True
    if line_intersect2(t1[1],t1[2],t2[0],t2[2]): return True
    if line_intersect2(t1[1],t1[2],t2[1],t2[2]): return True
    inTri = True 
    inTri = inTri and point_in_triangle2(t1[0],t1[1],t1[2], t2[0])
    inTri = inTri and point_in_triangle2(t1[0],t1[1],t1[2], t2[1])
    inTri = inTri and point_in_triangle2(t1[0],t1[1],t1[2], t2[2])
    if inTri == True: return True
    inTri = True
    inTri = inTri and point_in_triangle2(t2[0],t2[1],t2[2], t1[0])
    inTri = inTri and point_in_triangle2(t2[0],t2[1],t2[2], t1[1])
    inTri = inTri and point_in_triangle2(t2[0],t2[1],t2[2], t1[2])
    if inTri == True: return True
    return False
def线路2(v1、v2、v3、v4):
'''
判断直线(v1,v2)是否与直线(v3,v4)相交
'''
d=(v4[1]-v3[1])*(v2[0]-v1[0])-(v4[0]-v3[0])*(v2[1]-v1[1])
u=(v4[0]-v3[0])*(v1[1]-v3[1])-(v4[1]-v3[1])*(v1[0]-v3[0])
v=(v2[0]-v1[0])*(v1[1]-v3[1])-(v2[1]-v1[1])*(v1[0]-v3[0])

如果d这里是我对三角形碰撞问题的尝试(用python实现):

python中的二维三角形碰撞 #Tim Sheerman Chase 2016根据CC0发布 将numpy作为np导入 def CHECKTRI绕组(tri,allowReversed): trisq=np.one((3,3)) trisq[:,0:2]=np.数组(tri) detTri=np.linalg.det(trisq) 如果detTri<0.0: 如果允许,则: a=trisq[2,:].copy() trisq[2,:]=trisq[1,:] trisq[1,:]=a 其他:提升值错误(“三角形绕线方向错误”) 返回trisq def TriTri2D(t1、t2、eps=0.0、allowReversed=False、onBoundary=True): #变换必须逆时针表示 t1s=检查绕组(t1,允许反向) t2s=检查绕组(t2,允许反向) 如果在边界上: #边界上的点被视为碰撞 chkEdge=lambda x:np.linalg.det(x)chkEdge=lambda x:np.linalg.det(x)通过减少纵坐标对两个三角形的顶点进行排序。每个三角形最多需要三次比较。然后合并这两个序列。我想这最多需要五次比较

现在对于每个纵坐标,考虑一条水平线。它最多在一条线段上与两个三角形相交,检查线段是否重叠很容易。如果他们这样做,或者如果他们改变两条线之间的顺序,那么三角形相交


这不会给出一般的解决方案,因为两个三角形有可能重叠,而它们的任何一个顶点都不在另一个顶点内。如果只有一个很小的点重叠,则很难知道为testhi@Joe选择哪个点。我们应该检查A的所有3条边和B的所有3条边,这是正确的。但是,由于我们要检查A的角是否在B内(反之亦然),在线段相交检查之后,整个过程仍然有效。这是因为如果我们检测到另一个三角形内的任何一个角,我们就会发生碰撞。只需要三角形中的4个点测试。这不是一个三角形相交的快速算法。这是一个真正最有效的算法,在这个问题上没有做太多的工作——没有人决定性地表明哪种变化最快。一个问题是,很多讨论都涉及3D空间中的tris。例如realtimecollisiondetection.net/blog/?p=29 PS此类问题通常根据线段“正确一侧”上的点来判断。正如尼克在最后一段中指出的,实际上,关键在于你的扑杀技术有多好。这不会告诉你两个三角形是否相交,这是个问题。你不能只测试一个三角形的顶点,因为三角形可以在没有顶点的情况下相交(例如大卫之星)。你真的认为这有助于“检测三角形交点的最有效方法是什么?”在这种情况下,这得到了错误的答案:
t1=[[0,0],[5,0],[0,5];t2=[-10,0]、-5,0]、-1,6];打印(三相交2(t1,t2),假)
@TimSC是,它无法检测两条平行线的相交。你可以在函数
line_intersect2
中强制要求| d |大于一个小正数。你不需要做所有9条直线的交点,你只需要做8条。因为如果其中一个三角形穿过
#2D Triangle-Triangle collisions in python
#Release by Tim Sheerman-Chase 2016 under CC0

import numpy as np

def CheckTriWinding(tri, allowReversed):
    trisq = np.ones((3,3))
    trisq[:,0:2] = np.array(tri)
    detTri = np.linalg.det(trisq)
    if detTri < 0.0:
        if allowReversed:
            a = trisq[2,:].copy()
            trisq[2,:] = trisq[1,:]
            trisq[1,:] = a
        else: raise ValueError("triangle has wrong winding direction")
    return trisq

def TriTri2D(t1, t2, eps = 0.0, allowReversed = False, onBoundary = True):
    #Trangles must be expressed anti-clockwise
    t1s = CheckTriWinding(t1, allowReversed)
    t2s = CheckTriWinding(t2, allowReversed)

    if onBoundary:
        #Points on the boundary are considered as colliding
        chkEdge = lambda x: np.linalg.det(x) < eps
    else:
        #Points on the boundary are not considered as colliding
        chkEdge = lambda x: np.linalg.det(x) <= eps

    #For edge E of trangle 1,
    for i in range(3):
        edge = np.roll(t1s, i, axis=0)[:2,:]

        #Check all points of trangle 2 lay on the external side of the edge E. If
        #they do, the triangles do not collide.
        if (chkEdge(np.vstack((edge, t2s[0]))) and
            chkEdge(np.vstack((edge, t2s[1]))) and  
            chkEdge(np.vstack((edge, t2s[2])))):
            return False

    #For edge E of trangle 2,
    for i in range(3):
        edge = np.roll(t2s, i, axis=0)[:2,:]

        #Check all points of trangle 1 lay on the external side of the edge E. If
        #they do, the triangles do not collide.
        if (chkEdge(np.vstack((edge, t1s[0]))) and
            chkEdge(np.vstack((edge, t1s[1]))) and  
            chkEdge(np.vstack((edge, t1s[2])))):
            return False

    #The triangles collide
    return True

if __name__=="__main__":
    t1 = [[0,0],[5,0],[0,5]]
    t2 = [[0,0],[5,0],[0,6]]
    print (TriTri2D(t1, t2), True)

    t1 = [[0,0],[0,5],[5,0]]
    t2 = [[0,0],[0,6],[5,0]]
    print (TriTri2D(t1, t2, allowReversed = True), True)

    t1 = [[0,0],[5,0],[0,5]]
    t2 = [[-10,0],[-5,0],[-1,6]]
    print (TriTri2D(t1, t2), False)

    t1 = [[0,0],[5,0],[2.5,5]]
    t2 = [[0,4],[2.5,-1],[5,4]]
    print (TriTri2D(t1, t2), True)

    t1 = [[0,0],[1,1],[0,2]]
    t2 = [[2,1],[3,0],[3,2]]
    print (TriTri2D(t1, t2), False)

    t1 = [[0,0],[1,1],[0,2]]
    t2 = [[2,1],[3,-2],[3,4]]
    print (TriTri2D(t1, t2), False)

    #Barely touching
    t1 = [[0,0],[1,0],[0,1]]
    t2 = [[1,0],[2,0],[1,1]]
    print (TriTri2D(t1, t2, onBoundary = True), True)

    #Barely touching
    t1 = [[0,0],[1,0],[0,1]]
    t2 = [[1,0],[2,0],[1,1]]
    print (TriTri2D(t1, t2, onBoundary = False), False)