zoukankan      html  css  js  c++  java
  • [算法]检测空间三角形相交算法(Devillers & Guigue算法)

    #pragma once
    //GYDevillersTriangle.h
    /*      快速检测空间三角形相交算法的代码实现(Devillers & Guigue算法)
    博客原地址:http://blog.csdn.net/fourierfeng/article/details/11969915#
    
    Devillers & Guigue算法(简称Devillers 算法) 通过三角形各顶点构成的行列式正负的几何意义来判断三角形中点、线、面之间的相对位置关系, 
    从而判断两三角形是否相交。其基本原理如下:给定空间四个点:a(ax, ay, az), b = (bx, by, bz), c = (cx, cy, cz), d = (dx, dy, dz), 定义行列式如下:
    
    [a, b, c, d] 采用右手螺旋法则定义了四个空间点的位置关系。
    [a, b, c, d] > 0 表示 d 在 a、b、c 按逆时针顺序所组成的三角形的正法线方向(即上方); 
    [a, b, c, d] < 0 表示 d 在 △abc的下方; [a, b, c, d] = 0 表示四点共面。
    
            设两个三角形T1和T2,顶点分别为:V10,V11,V12和V20,V21,V22,
        三角形所在的平面分别为π1和π2,其法向量分别为N1和N2.算法先判别三角形和另一个三角形所在的平面的相互位置关系, 提前排除不相交的情况。
        通过计算[V20, V21, V22, V1i].(i = 0, 1, 2)来判断T1和π2的关系:如果所有的行列式的值都不为零且同号,则T1和T2不相交;否则T1和π2相交。
        相交又分为如下几种情况:
            a)如果所有的行列式的值为零,则T1和T2共面,转化为共面的线段相交问题。
            b)如果其中一个行列式的值为零,而其他两个行列式同号,则只有一个点在平面内,测试顶点是否则T2内部,是则相交,否则不相交;
            c)否则T1的顶点位于平面π2两侧(包含T1的一条边在平面π2中的情况)。
                
            再按照类似的方法对 T 2 和 π 1 作进一步的测试。如果通过测试, 则每个三角形必有确定的一点位于另一个三角形所在平面的一侧, 
        而另外两点位于其另一侧。算法分别循环置换每个三角形的顶点, 以使V10(V20)位于π2(π1)的一侧,另两个点位于其另一侧;
        同时对顶点V21,V22(V11, V12)进行交换操作,以确保V10(V20)位于π2(π1)的上方,即正法线方向。
        经过以上的预排除和置换操作,V10的邻边V10V11,V10V12和V20的邻边V20V21和V20V22与两平面的交线L相交于固定形式的点上,
        分别记为i,j,k,l(i<j, k<l), 如图:(参看原博客)
        这些点在L上形成的封闭区间为i1 = [i, j], i2 = [k, l].至此,两个三角形的相交测试问题转换为封闭区间i1,i2的重叠问题。
        若重叠则相交,否则不相交。由于交点形式固定,只需满足条件k <= j且i <= l即表明区间重叠,条件还可进一步缩减为判别式
        (1)是否成立:
                    [V10, V11, V20, V21] <= 0 && [V10, V12, V22, V20] <= 0        判别式(1)
    */
    
    
    
    typedef float float3[3];
    
    enum TopologicalStructure
    {
        INTERSECT, NONINTERSECT
    };
    
    struct Triangle
    {
        //float3 Normal_0;
        float3 Vertex_1, Vertex_2, Vertex_3;
    };
    
    /*******************************************************************************************************/
    //Devillers算法主函数  
    TopologicalStructure judge_triangle_topologicalStructure(Triangle* tri1, Triangle* tri2);
    
    
    //返回bool值
    bool isTriangleTntersect(Triangle* tri1, Triangle* tri2)
    {
        TopologicalStructure  intersectSt = judge_triangle_topologicalStructure(tri1, tri2);
        if (intersectSt == INTERSECT)
            return true;
        return false;
    }
    //GYDevillersTriangle.cpp
    #include "GYDevillersTriangle.h"
    #pragma once
    
    struct point
    {
        float x, y;
    };
    
    //三维点拷贝为二维点  
    static void copy_point(point& p, float3 f)
    {
        p.x = f[0];
        p.y = f[1];
    }
    
    //四点行列式  
    inline float get_vector4_det(float3 v1, float3 v2, float3 v3, float3 v4)
    {
        float a[3][3];
        for (int i = 0; i != 3; ++i)
        {
            a[0][i] = v1[i] - v4[i];
            a[1][i] = v2[i] - v4[i];
            a[2][i] = v3[i] - v4[i];
        }
    
        return a[0][0] * a[1][1] * a[2][2]
            + a[0][1] * a[1][2] * a[2][0]
            + a[0][2] * a[1][0] * a[2][1]
            - a[0][2] * a[1][1] * a[2][0]
            - a[0][1] * a[1][0] * a[2][2]
            - a[0][0] * a[1][2] * a[2][1];
    }
    
    
    //利用叉积计算点p相对线段p1p2的方位  
    inline double direction(point p1, point p2, point p) {
        return (p.x - p1.x) * (p2.y - p1.y) - (p2.x - p1.x) * (p.y - p1.y);
    }
    
    
    //确定与线段p1p2共线的点p是否在线段p1p2上  
    inline int on_segment(point p1, point p2, point p) {
        double max = p1.x > p2.x ? p1.x : p2.x;
        double min = p1.x < p2.x ? p1.x : p2.x;
        double max1 = p1.y > p2.y ? p1.y : p2.y;
        double min1 = p1.y < p2.y ? p1.y : p2.y;
        if (p.x >= min && p.x <= max && p.y >= min1 && p.y <= max1)
        {
            return 1;
        }
        else
        {
            return 0;
        }
    }
    
    
    //判断线段p1p2与线段p3p4是否相交的主函数  
    inline int segments_intersert(point p1, point p2, point p3, point p4) {
        double d1, d2, d3, d4;
        d1 = direction(p3, p4, p1);
        d2 = direction(p3, p4, p2);
        d3 = direction(p1, p2, p3);
        d4 = direction(p1, p2, p4);
        if (d1 * d2 < 0 && d3 * d4 < 0)
        {
            return 1;
        }
        else if (d1 == 0 && on_segment(p3, p4, p1) == 1)
        {
            return 1;
        }
        else if (d2 == 0 && on_segment(p3, p4, p2) == 1)
        {
            return 1;
        }
        else if (d3 == 0 && on_segment(p1, p2, p3) == 1)
        {
            return 1;
        }
        else if (d4 == 0 && on_segment(p1, p2, p4) == 1)
        {
            return 1;
        }
        return 0;
    }
    
    
    //判断同一平面的直线和三角形是否相交  
    inline bool line_triangle_intersert_inSamePlane(Triangle* tri, float3 f1, float3 f2)
    {
        point p1, p2, p3, p4;
    
        copy_point(p1, f1);
    
        copy_point(p2, f2);
    
        copy_point(p3, tri->Vertex_1);
    
        copy_point(p4, tri->Vertex_2);
    
        if (segments_intersert(p1, p2, p3, p4))
        {
            return true;
        }
    
        copy_point(p3, tri->Vertex_2);
    
        copy_point(p4, tri->Vertex_3);
    
        if (segments_intersert(p1, p2, p3, p4))
        {
            return true;
        }
    
        copy_point(p3, tri->Vertex_1);
    
        copy_point(p4, tri->Vertex_3);
    
        if (segments_intersert(p1, p2, p3, p4))
        {
            return true;
        }
    
        return false;
    }
    
    
    inline void get_central_point(float3 centralPoint, Triangle* tri)
    {
        centralPoint[0] = (tri->Vertex_1[0] + tri->Vertex_2[0] + tri->Vertex_3[0]) / 3;
    
        centralPoint[1] = (tri->Vertex_1[1] + tri->Vertex_2[1] + tri->Vertex_3[1]) / 3;
    
        centralPoint[2] = (tri->Vertex_1[2] + tri->Vertex_2[2] + tri->Vertex_3[2]) / 3;
    }
    
    
    
    
    //向量之差  
    inline void get_vector_diff(float3& aimV, const float3 a, const float3 b)
    {
        aimV[0] = b[0] - a[0];
    
        aimV[1] = b[1] - a[1];
    
        aimV[2] = b[2] - a[2];
    }
    
    //向量内积  
    inline float Dot(const float3& v1, const float3& v2)
    {
        return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
    }
    
    //重心法判断点是否在三角形内部  
    inline bool is_point_within_triangle(Triangle* tri, float3 point)
    {
        float3 v0;
        get_vector_diff(v0, tri->Vertex_1, tri->Vertex_3);
        float3 v1;
        get_vector_diff(v1, tri->Vertex_1, tri->Vertex_2);
        float3 v2;
        get_vector_diff(v2, tri->Vertex_1, point);
        float dot00 = Dot(v0, v0);
        float dot01 = Dot(v0, v1);
        float dot02 = Dot(v0, v2);
        float dot11 = Dot(v1, v1);
        float dot12 = Dot(v1, v2);
        float inverDeno = 1 / (dot00* dot11 - dot01* dot01);
        float u = (dot11* dot02 - dot01* dot12) * inverDeno;
        if (u < 0 || u > 1) // if u out of range, return directly  
        {
            return false;
        }
        float v = (dot00* dot12 - dot01* dot02) * inverDeno;
        if (v < 0 || v > 1) // if v out of range, return directly  
        {
            return false;
        }
        return u + v <= 1;
    }
    
    
    //判断同一平面内的三角形是否相交  
    inline bool triangle_intersert_inSamePlane(Triangle* tri1, Triangle* tri2)
    {
        if (line_triangle_intersert_inSamePlane(tri2, tri1->Vertex_1, tri1->Vertex_2))
        {
            return true;
        }
        else if (line_triangle_intersert_inSamePlane(tri2, tri1->Vertex_2, tri1->Vertex_3))
        {
            return true;
        }
        else if (line_triangle_intersert_inSamePlane(tri2, tri1->Vertex_1, tri1->Vertex_3))
        {
            return true;
        }
        else
        {
            float3 centralPoint1, centralPoint2;
    
            get_central_point(centralPoint1, tri1);
    
            get_central_point(centralPoint2, tri2);
    
            if (is_point_within_triangle(tri2, centralPoint1) || is_point_within_triangle(tri1, centralPoint2))
            {
                return true;
            }
    
            return false;
        }
    }
    
    //Devillers算法主函数  
    TopologicalStructure judge_triangle_topologicalStructure(Triangle* tri1, Triangle* tri2)
    {
        //设tri1所在的平面为p1,tri2所在的平面为p2  
        float p1_tri2_vertex1 = get_vector4_det(tri1->Vertex_1, tri1->Vertex_2, tri1->Vertex_3, tri2->Vertex_1);
    
        float p1_tri2_vertex2 = get_vector4_det(tri1->Vertex_1, tri1->Vertex_2, tri1->Vertex_3, tri2->Vertex_2);
    
        float p1_tri2_vertex3 = get_vector4_det(tri1->Vertex_1, tri1->Vertex_2, tri1->Vertex_3, tri2->Vertex_3);
    
    
        if (p1_tri2_vertex1 > 0 && p1_tri2_vertex2 > 0 && p1_tri2_vertex3 > 0)
        {
            return NONINTERSECT;
        }
    
        if (p1_tri2_vertex1 < 0 && p1_tri2_vertex2 < 0 && p1_tri2_vertex3 < 0)
        {
            return NONINTERSECT;
        }
    
    
        if (p1_tri2_vertex1 == 0 && p1_tri2_vertex2 == 0 && p1_tri2_vertex3 == 0)
        {
            if (triangle_intersert_inSamePlane(tri1, tri2))
            {
                return INTERSECT;
            }
            else
            {
                return NONINTERSECT;
            }
        }
    
    
        if (p1_tri2_vertex1 == 0 && p1_tri2_vertex2 * p1_tri2_vertex3 > 0)
        {
            if (is_point_within_triangle(tri1, tri2->Vertex_1))
            {
                return INTERSECT;
            }
            else
            {
                return NONINTERSECT;
            }
        }
        else if (p1_tri2_vertex2 == 0 && p1_tri2_vertex1 * p1_tri2_vertex3 > 0)
        {
            if (is_point_within_triangle(tri1, tri2->Vertex_2))
            {
                return INTERSECT;
            }
            else
            {
                return NONINTERSECT;
            }
        }
        else if (p1_tri2_vertex3 == 0 && p1_tri2_vertex1 * p1_tri2_vertex2 > 0)
        {
            if (is_point_within_triangle(tri1, tri2->Vertex_3))
            {
                return INTERSECT;
            }
            else
            {
                return NONINTERSECT;
            }
        }
    
    
    
        float p2_tri1_vertex1 = get_vector4_det(tri2->Vertex_1, tri2->Vertex_2, tri2->Vertex_3, tri1->Vertex_1);
    
        float p2_tri1_vertex2 = get_vector4_det(tri2->Vertex_1, tri2->Vertex_2, tri2->Vertex_3, tri1->Vertex_2);
    
        float p2_tri1_vertex3 = get_vector4_det(tri2->Vertex_1, tri2->Vertex_2, tri2->Vertex_3, tri1->Vertex_3);
    
    
        if (p2_tri1_vertex1 > 0 && p2_tri1_vertex2 > 0 && p2_tri1_vertex3 > 0)
        {
            return NONINTERSECT;
        }
    
        if (p2_tri1_vertex1 < 0 && p2_tri1_vertex2 < 0 && p2_tri1_vertex3 < 0)
        {
            return NONINTERSECT;
        }
    
    
        if (p2_tri1_vertex1 == 0 && p2_tri1_vertex2 * p2_tri1_vertex3 > 0)
        {
            if (is_point_within_triangle(tri2, tri1->Vertex_1))
            {
                return INTERSECT;
            }
            else
            {
                return NONINTERSECT;
            }
        }
    
        if (p2_tri1_vertex2 == 0 && p2_tri1_vertex1 * p2_tri1_vertex3 > 0)
        {
            if (is_point_within_triangle(tri2, tri1->Vertex_2))
            {
                return INTERSECT;
            }
            else
            {
                return NONINTERSECT;
            }
        }
    
        if (p2_tri1_vertex3 == 0 && p2_tri1_vertex1 * p2_tri1_vertex2 > 0)
        {
            if (is_point_within_triangle(tri2, tri1->Vertex_3))
            {
                return INTERSECT;
            }
            else
            {
                return NONINTERSECT;
            }
        }
    
    
    
        float* tri1_a = tri1->Vertex_1, *tri1_b = tri1->Vertex_2, *tri1_c = tri1->Vertex_3
            , *tri2_a = tri2->Vertex_1, *tri2_b = tri2->Vertex_2, *tri2_c = tri2->Vertex_3;
    
        float* m;
    
        float im;
    
        if (p2_tri1_vertex2 * p2_tri1_vertex3 >= 0 && p2_tri1_vertex1 != 0)
        {
            if (p2_tri1_vertex1 < 0)
            {
                m = tri2_b;
                tri2_b = tri2_c;
                tri2_c = m;
    
                im = p1_tri2_vertex2;
                p1_tri2_vertex2 = p1_tri2_vertex3;
                p1_tri2_vertex3 = im;
            }
        }
        else if (p2_tri1_vertex1 * p2_tri1_vertex3 >= 0 && p2_tri1_vertex2 != 0)
        {
            m = tri1_a;
            tri1_a = tri1_b;
            tri1_b = tri1_c;
            tri1_c = m;
    
            if (p2_tri1_vertex2 < 0)
            {
                m = tri2_b;
                tri2_b = tri2_c;
                tri2_c = m;
    
                im = p1_tri2_vertex2;
                p1_tri2_vertex2 = p1_tri2_vertex3;
                p1_tri2_vertex3 = im;
            }
        }
        else if (p2_tri1_vertex1 * p2_tri1_vertex2 >= 0 && p2_tri1_vertex3 != 0)
        {
            m = tri1_a;
    
            tri1_a = tri1_c;
    
            tri1_c = tri1_b;
    
            tri1_b = m;
    
            if (p2_tri1_vertex3 < 0)
            {
                m = tri2_b;
                tri2_b = tri2_c;
                tri2_c = m;
    
                im = p1_tri2_vertex2;
                p1_tri2_vertex2 = p1_tri2_vertex3;
                p1_tri2_vertex3 = im;
            }
        }
    
        if (p1_tri2_vertex2 * p1_tri2_vertex3 >= 0 && p1_tri2_vertex1 != 0)
        {
            if (p1_tri2_vertex1 < 0)
            {
                m = tri1_b;
                tri1_b = tri1_c;
                tri1_c = m;
            }
        }
        else if (p1_tri2_vertex1 * p1_tri2_vertex3 >= 0 && p1_tri2_vertex2 != 0)
        {
            m = tri2_a;
    
            tri2_a = tri2_b;
    
            tri2_b = tri2_c;
    
            tri2_c = m;
    
            if (p1_tri2_vertex2 < 0)
            {
                m = tri1_b;
                tri1_b = tri1_c;
                tri1_c = m;
            }
        }
        else if (p1_tri2_vertex1 * p1_tri2_vertex2 >= 0 && p1_tri2_vertex3 != 0)
        {
            m = tri2_a;
    
            tri2_a = tri2_c;
    
            tri2_c = tri2_b;
    
            tri2_b = m;
    
            if (p1_tri2_vertex3 < 0)
            {
                m = tri1_b;
                tri1_b = tri1_c;
                tri1_c = m;
            }
        }
    
        if (get_vector4_det(tri1_a, tri1_b, tri2_a, tri2_b) <= 0 && get_vector4_det(tri1_a, tri1_c, tri2_c, tri2_a) <= 0)
        {
            return INTERSECT;
        }
        else
        {
            return NONINTERSECT;
        }
    }
  • 相关阅读:
    C# 全局变量
    [C#]续:利用键代码自动转换生成字母键或其它键信息
    [WPF](小结2)DataGrid嵌套DataGrid(也叫主从表)
    [C#]winform窗口托盘
    C# arrayList动态添加对象元素,并取出对象元素的方法
    [WPF](小结3)DataGridInTreeView树嵌表
    [WPF](小结4)TreeView的数据分层模板
    [WPF](小结1)ListBox嵌套ListBox
    [C#]利用键代码自动转换生成字母键或其它键信息
    [C#]使用API 获取设置系统热键和快捷键
  • 原文地址:https://www.cnblogs.com/lyggqm/p/5977129.html
Copyright © 2011-2022 走看看