Beispiel #1
0
 public Triangle(HalfEdge halfEdge)
 {
     this.halfEdge = halfEdge;
 }
        //Alternative 1. Triangulate with some algorithm - then flip edges until we have a delaunay triangulation
        public static List <Triangle> TriangulateByFlippingEdges(List <Vector3> sites)
        {
            //Step 1. Triangulate the points with some algorithm
            //Vector3 to vertex
            List <Vertex> vertices = new List <Vertex>();

            for (int i = 0; i < sites.Count; i++)
            {
                vertices.Add(new Vertex(sites[i]));
            }

            //Triangulate the convex hull of the sites
            List <Triangle> triangles = TriangulatePoints(vertices);
            //List triangles = TriangulatePoints.TriangleSplitting(vertices);

            //Step 2. Change the structure from triangle to half-edge to make it faster to flip edges
            List <HalfEdge> halfEdges = TransformFromTriangleToHalfEdge(triangles);

            //Step 3. Flip edges until we have a delaunay triangulation
            int safety = 0;

            int flippedEdges = 0;

            while (true)
            {
                safety += 1;

                if (safety > 100000)
                {
                    Debug.Log("Stuck in endless loop");

                    break;
                }

                bool hasFlippedEdge = false;

                //Search through all edges to see if we can flip an edge
                for (int i = 0; i < halfEdges.Count; i++)
                {
                    HalfEdge thisEdge = halfEdges[i];

                    //Is this edge sharing an edge, otherwise its a border, and then we cant flip the edge
                    if (thisEdge.oppositeEdge == null)
                    {
                        continue;
                    }

                    //The vertices belonging to the two triangles, c-a are the edge vertices, b belongs to this triangle
                    Vertex a = thisEdge.v;
                    Vertex b = thisEdge.nextEdge.v;
                    Vertex c = thisEdge.prevEdge.v;
                    Vertex d = thisEdge.oppositeEdge.nextEdge.v;

                    Vector2 aPos = a.GetPos2D_XZ();
                    Vector2 bPos = b.GetPos2D_XZ();
                    Vector2 cPos = c.GetPos2D_XZ();
                    Vector2 dPos = d.GetPos2D_XZ();

                    //Use the circle test to test if we need to flip this edge
                    if (IsPointInsideOutsideOrOnCircle(aPos, bPos, cPos, dPos) < 0f)
                    {
                        //Are these the two triangles that share this edge forming a convex quadrilateral?
                        //Otherwise the edge cant be flipped
                        if (IsQuadrilateralConvex(aPos, bPos, cPos, dPos))
                        {
                            //If the new triangle after a flip is not better, then dont flip
                            //This will also stop the algoritm from ending up in an endless loop
                            if (IsPointInsideOutsideOrOnCircle(bPos, cPos, dPos, aPos) < 0f)
                            {
                                continue;
                            }

                            //Flip the edge
                            flippedEdges += 1;

                            hasFlippedEdge = true;

                            FlipEdge(thisEdge);
                        }
                    }
                }

                //We have searched through all edges and havent found an edge to flip, so we have a Delaunay triangulation!
                if (!hasFlippedEdge)
                {
                    //Debug.Log("Found a delaunay triangulation");

                    break;
                }
            }

            //Debug.Log("Flipped edges: " + flippedEdges);

            //Dont have to convert from half edge to triangle because the algorithm will modify the objects, which belongs to the
            //original triangles, so the triangles have the data we need

            return(triangles);
        }
        //Flip an edge
        private static void FlipEdge(HalfEdge one)
        {
            //The data we need
            //This edge's triangle
            HalfEdge two   = one.nextEdge;
            HalfEdge three = one.prevEdge;
            //The opposite edge's triangle
            HalfEdge four = one.oppositeEdge;
            HalfEdge five = one.oppositeEdge.nextEdge;
            HalfEdge six  = one.oppositeEdge.prevEdge;
            //The vertices
            Vertex a = one.v;
            Vertex b = one.nextEdge.v;
            Vertex c = one.prevEdge.v;
            Vertex d = one.oppositeEdge.nextEdge.v;



            //Flip

            //Change vertex
            a.halfEdge = one.nextEdge;
            c.halfEdge = one.oppositeEdge.nextEdge;

            //Change half-edge
            //Half-edge - half-edge connections
            one.nextEdge = three;
            one.prevEdge = five;

            two.nextEdge = four;
            two.prevEdge = six;

            three.nextEdge = five;
            three.prevEdge = one;

            four.nextEdge = six;
            four.prevEdge = two;

            five.nextEdge = one;
            five.prevEdge = three;

            six.nextEdge = two;
            six.prevEdge = four;

            //Half-edge - vertex connection
            one.v   = b;
            two.v   = b;
            three.v = c;
            four.v  = d;
            five.v  = d;
            six.v   = a;

            //Half-edge - triangle connection
            Triangle t1 = one.t;
            Triangle t2 = four.t;

            one.t   = t1;
            three.t = t1;
            five.t  = t1;

            two.t  = t2;
            four.t = t2;
            six.t  = t2;

            //Opposite-edges are not changing!

            //Triangle connection
            t1.v1 = b;
            t1.v2 = c;
            t1.v3 = d;

            t2.v1 = b;
            t2.v2 = d;
            t2.v3 = a;

            t1.halfEdge = three;
            t2.halfEdge = four;
        }
        //From triangle where each triangle has one vertex to half edge
        public static List <HalfEdge> TransformFromTriangleToHalfEdge(List <Triangle> triangles)
        {
            //Make sure the triangles have the same orientation
            OrientTrianglesClockwise(triangles);

            //First create a list with all possible half-edges
            List <HalfEdge> halfEdges = new List <HalfEdge>(triangles.Count * 3);

            for (int i = 0; i < triangles.Count; i++)
            {
                Triangle t = triangles[i];

                HalfEdge he1 = new HalfEdge(t.v1);
                HalfEdge he2 = new HalfEdge(t.v2);
                HalfEdge he3 = new HalfEdge(t.v3);

                he1.nextEdge = he2;
                he2.nextEdge = he3;
                he3.nextEdge = he1;

                he1.prevEdge = he3;
                he2.prevEdge = he1;
                he3.prevEdge = he2;

                //The vertex needs to know of an edge going from it
                he1.v.halfEdge = he2;
                he2.v.halfEdge = he3;
                he3.v.halfEdge = he1;

                //The face the half-edge is connected to
                t.halfEdge = he1;

                he1.t = t;
                he2.t = t;
                he3.t = t;

                //Add the half-edges to the list
                halfEdges.Add(he1);
                halfEdges.Add(he2);
                halfEdges.Add(he3);
            }

            //Find the half-edges going in the opposite direction
            for (int i = 0; i < halfEdges.Count; i++)
            {
                HalfEdge he = halfEdges[i];

                Vertex goingToVertex   = he.v;
                Vertex goingFromVertex = he.prevEdge.v;

                for (int j = 0; j < halfEdges.Count; j++)
                {
                    //Dont compare with itself
                    if (i == j)
                    {
                        continue;
                    }

                    HalfEdge heOpposite = halfEdges[j];

                    //Is this edge going between the vertices in the opposite direction
                    if (goingFromVertex.position == heOpposite.v.position && goingToVertex.position == heOpposite.prevEdge.v.position)
                    {
                        he.oppositeEdge = heOpposite;

                        break;
                    }
                }
            }


            return(halfEdges);
        }