What's the most efficient way to detect triangle-triangle intersections?

前端 未结 5 1170
广开言路
广开言路 2020-12-08 23:37

How can I tell whether two triangles intersect in 2D Euclidean space? (i.e. classic 2D geometry) given the (X,Y) coordinates of each vertex in each triangle.

5条回答
  •  北海茫月
    2020-12-08 23:46

    Here is my attempt at the triangle-triangle collision problem (implemented in python):

    #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)
    

    It works based based on the fact that the triangles do not overlap if all the points of triangle 1 are on the external side of at least one of the edges of triangle 2 (or vice versa is true). Of course, triangles are never concave.

    I don't know if this approach is more or less efficient than the others.

    Bonus: I ported it to C++ https://gist.github.com/TimSC/5ba18ae21c4459275f90

提交回复
热议问题