Exemplo n.º 1
0
    private HalfEdge PolygonTriangulation(ref int ep, List <HalfEdge> edgePortals)
    {
        int      epB   = ep;
        Vertex   vB    = edgePortals[epB].origin;
        HalfEdge eLast = edgePortals[epB].prev.twin;

        ep += 1;

        while (ep < edgePortals.Count)
        {
            HalfEdge holeEdge = edgePortals[ep].prev.twin;
            if (ep < edgePortals.Count - 1 && holeEdge == edgePortals[ep + 1])
            {
                ep += 1;
                continue;
            }

            Vector2 funnelL = holeEdge.origin.p - vB.p;
            Vector2 funnelR = holeEdge.next.origin.p - vB.p;

            Triangle tri;

            //This can potentially allow 180 degree triangles :'( Must fix
            if (VecMath.Det(funnelR, funnelL) <= 0)
            {
                //Bug is here. Do not make a ref to epLast. Find a way to return the new ep
                HalfEdge e = PolygonTriangulation(ref ep, edgePortals);

                HalfEdge e01 = new HalfEdge(vB);
                HalfEdge e12 = new HalfEdge(e.next.origin);
                HalfEdge e20 = new HalfEdge(e.origin);
                tri = new Triangle(e01, e12, e20);
                HalfEdge.SetTwins(e12, e);
                HalfEdge.SetTwins(e20, eLast);
                eLast = e01;
            }
            else
            {
                //Make triangle
                HalfEdge e01 = new HalfEdge(vB);
                HalfEdge e12 = new HalfEdge(holeEdge.next.origin);
                HalfEdge e20 = new HalfEdge(holeEdge.origin);
                tri = new Triangle(e01, e12, e20);
                HalfEdge.SetTwins(e12, holeEdge);
                HalfEdge.SetTwins(e20, eLast);
                eLast = e01;
            }

            for (int i = epB; i <= ep; i++)
            {
                edgePortals[i].incidentTriangle.children.Add(tri);
            }
            ep += 1;
        }

        ep = edgePortals.Count - 1;

        return(eLast);
    }
Exemplo n.º 2
0
    public HalfEdge[] InsertVertex(Vertex v)
    {
        HalfEdge e01 = this.edge;
        HalfEdge e12 = e01.next;
        HalfEdge e20 = e12.next;

        this.edge = null;

        HalfEdge e13  = new HalfEdge(e12.origin);
        HalfEdge e30  = new HalfEdge(v);
        Triangle tri0 = new Triangle(e01, e13, e30);

        HalfEdge e23  = new HalfEdge(e20.origin);
        HalfEdge e31  = new HalfEdge(v);
        Triangle tri1 = new Triangle(e12, e23, e31);

        HalfEdge e03  = new HalfEdge(e01.origin);
        HalfEdge e32  = new HalfEdge(v);
        Triangle tri2 = new Triangle(e20, e03, e32);

        HalfEdge.SetTwins(e03, e30);
        HalfEdge.SetTwins(e13, e31);
        HalfEdge.SetTwins(e23, e32);

        v.AddOutgoingEdge(e30);
        v.AddOutgoingEdge(e31);
        v.AddOutgoingEdge(e32);

        e03.origin.AddOutgoingEdge(e03);
        e13.origin.AddOutgoingEdge(e13);
        e23.origin.AddOutgoingEdge(e23);


        this.children = new List <Triangle>()
        {
            tri0, tri1, tri2
        };
        return(new HalfEdge[] { e01, e12, e20 });
    }
Exemplo n.º 3
0
    private Triangle[] Triangulate(List <Vertex> verts)
    {
        //Randomize vertices for faster average triangulation
        Algorithm.Shuffle <Vertex>(ref verts);

        //Construct circle enclosing all the vertices
        Vector2 centroid = Vector2.zero;

        foreach (Vertex vert in verts)
        {
            centroid += vert.p;
        }
        centroid /= verts.Count;
        float r = 0.0f;

        foreach (Vertex vert in verts)
        {
            r = Mathf.Max(r, Vector2.Distance(vert.p, centroid));
        }
        //Add some padding to avoid floating point errors later on
        r *= 1.2f;

        Vector2 pi0 = new Vector2(centroid.x, centroid.y - 2 * r);
        Vector2 pi1 = new Vector2(centroid.x + r * Mathf.Sqrt(3), centroid.y + r);
        Vector2 pi2 = new Vector2(centroid.x - r * Mathf.Sqrt(3), centroid.y + r);

        Debug.DrawLine(pi0, pi1, Color.cyan, 5.0f, false);
        Debug.DrawLine(pi1, pi2, Color.cyan, 5.0f, false);
        Debug.DrawLine(pi2, pi0, Color.cyan, 5.0f, false);

        Vertex vi0 = new Vertex(pi0, -1);
        Vertex vi1 = new Vertex(pi1, -1);
        Vertex vi2 = new Vertex(pi2, -1);

        //Imaginary triangle
        HalfEdge e01Imag  = new HalfEdge(vi0);
        HalfEdge e12Imag  = new HalfEdge(vi1);
        HalfEdge e20Imag  = new HalfEdge(vi2);
        Triangle treeRoot = new Triangle(e01Imag, e12Imag, e20Imag);

        //Perform Delaunay Triangulation
        for (int i = 0; i < verts.Count; i++)
        {
            Vertex v = verts[i];

            Triangle containingTri = treeRoot.FindContainingTriangle(v.p);

            //Check for potential degenerate case when point lies on edge of triangle
            HalfEdge   e01 = containingTri.edge;
            HalfEdge   e12 = e01.next;
            HalfEdge   e20 = e12.next;
            Vector3    uvw = Geometry.ToBarycentricCoordinates(e01.origin.p, e12.origin.p, e20.origin.p, v.p);
            HalfEdge[] edges;
            if (uvw[0] < VecMath.epsilon)
            {
                edges = e12.InsertVertex(v);
            }
            else if (uvw[1] < VecMath.epsilon)
            {
                edges = e20.InsertVertex(v);
            }
            else if (uvw[2] < VecMath.epsilon)
            {
                edges = e01.InsertVertex(v);
            }
            else
            {
                edges = containingTri.InsertVertex(v);
            }

            //Flip triangles that don't satisfy delaunay property
            HashSet <HalfEdge>    sptSet   = new HashSet <HalfEdge>();
            LinkedList <HalfEdge> frontier = new LinkedList <HalfEdge>();
            foreach (HalfEdge edge in edges)
            {
                frontier.AddLast(edge);
            }

            LinkedListNode <HalfEdge> curNode;
            int t = 0;
            while (frontier.Count > 0 && t < 100)
            {
                t      += 1;
                curNode = frontier.First;
                frontier.RemoveFirst();
                HalfEdge ab = curNode.Value;
                HalfEdge ba = ab.twin;
                if (!sptSet.Contains(ab) && ba != null)
                {
                    HalfEdge bc = ab.next;
                    HalfEdge ca = bc.next;

                    HalfEdge ad = ba.next;
                    HalfEdge db = ad.next;
                    //Check if Delaunay Property is violated
                    if (Geometry.IsInCircumscribedCircle(ab.origin.p, bc.origin.p, ca.origin.p, db.origin.p))
                    {
                        //Flip triangle
                        HalfEdge dc = new HalfEdge(db.origin);
                        HalfEdge cd = new HalfEdge(ca.origin);
                        HalfEdge.SetTwins(dc, cd);
                        Triangle adc = new Triangle(ad, dc, ca);
                        Triangle bcd = new Triangle(bc, cd, db);

                        //Remove old edges from vertices
                        ab.origin.RemoveOutgoingEdge(ab);
                        ba.origin.RemoveOutgoingEdge(ba);
                        //Add new edges from flip to vertices
                        cd.origin.AddOutgoingEdge(cd);
                        dc.origin.AddOutgoingEdge(dc);

                        ab.incidentTriangle.children = new List <Triangle> {
                            adc, bcd
                        };
                        ba.incidentTriangle.children = new List <Triangle> {
                            adc, bcd
                        };

                        frontier.AddLast(ad);
                        frontier.AddLast(db);
                    }
                    sptSet.Add(ab);
                    sptSet.Add(ba);
                }
            }
        }

        //Insert constrained edges
        foreach (ConstrainedVertex[] segments in constrainedVerts)
        {
            HashSet <HalfEdge> holeBounds = new HashSet <HalfEdge>();
            HalfEdge           holeEdge   = null;
            bool isHole = segments.Length > 2;
            int  n      = isHole ? segments.Length : segments.Length - 1;
            for (int i = 0; i < n; i++)
            {
                Vertex v1 = segments[i % segments.Length];
                Vertex v2 = segments[(i + 1) % segments.Length];
                Debug.DrawLine(v1.p, v2.p, Color.magenta, 5.0f, false);

                Vector2  dir    = v2.p - v1.p;
                HalfEdge eStart = v1.GetOutgoingEdgeClockwiseFrom(dir);
                HalfEdge eEnd   = v2.GetOutgoingEdgeClockwiseFrom(-dir);

                List <HalfEdge> edgePortals = new List <HalfEdge>();
                HalfEdge        intersected = eStart.next.twin;
                Vertex          v           = v1;
                int             t           = 0;
                while (v != v2 && t < 100)
                {
                    t += 1;
                    edgePortals.Add(intersected);
                    v = intersected.prev.origin;
                    Vector2 newDir = v.p - v1.p;
                    if (VecMath.Det(dir, newDir) >= 0)
                    {
                        intersected = intersected.next.twin;
                    }
                    else
                    {
                        intersected = intersected.prev.twin;
                    }
                }


                List <HalfEdge> forwardEdgePortals = new List <HalfEdge>();
                forwardEdgePortals.Add(eStart);
                for (int j = 0; j < edgePortals.Count; j++)
                {
                    forwardEdgePortals.Add(edgePortals[j]);
                }

                List <HalfEdge> backwardEdgePortals = new List <HalfEdge>();
                backwardEdgePortals.Add(eEnd);
                for (int j = edgePortals.Count - 1; j >= 0; j--)
                {
                    backwardEdgePortals.Add(edgePortals[j].twin);
                }

                int      sL            = 0;
                HalfEdge eConstrainedL = PolygonTriangulation(ref sL, forwardEdgePortals);
                holeBounds.Add(eConstrainedL);
                int      sR            = 0;
                HalfEdge eConstrainedR = PolygonTriangulation(ref sR, backwardEdgePortals);
                holeEdge = eConstrainedR;
                HalfEdge.SetTwins(eConstrainedL, eConstrainedR);


                foreach (HalfEdge e in edgePortals)
                {
                    Vector2 ep1 = e.origin.p;
                    Vector2 ep2 = e.next.origin.p;
                    Debug.DrawLine(ep1, ep2, Color.green, 5.0f, false);
                }

                //v1.DrawOutgoingEdges();
                //Debug.DrawLine(eStart.origin.p, eStart.next.origin.p, Color.red, 5.0f, false);
            }

            if (isHole && holeEdge != null)
            {
                //We have a hole. Hide all triangles that are in hole
                CreateHole(holeEdge, holeBounds);
            }
        }

        //Generate Triangle list
        List <Triangle>    leafs   = new List <Triangle>();
        HashSet <Triangle> visited = new HashSet <Triangle>();

        int count = 0;

        treeRoot.GetRealLeafs(ref leafs, ref visited, ref count, 0);
        Debug.Log(count);

        foreach (Triangle leaf in leafs)
        {
            Vector3 p0 = leaf.edge.origin.p;
            Vector3 p1 = leaf.edge.next.origin.p;
            Vector3 p2 = leaf.edge.next.next.origin.p;
            Debug.DrawLine(p0, p1, Color.cyan, 5.0f, false);
            Debug.DrawLine(p1, p2, Color.cyan, 5.0f, false);
            Debug.DrawLine(p2, p0, Color.cyan, 5.0f, false);
        }

        return(leafs.ToArray());
    }
Exemplo n.º 4
0
    public HalfEdge[] InsertVertex(Vertex v)
    {
        //012 forms left triangle. 103 forms right triangle. 4 is inserted vertex on edge 01, v.

        HalfEdge e01 = this;
        HalfEdge e12 = e01.next;
        HalfEdge e20 = e12.next;

        e01.incidentTriangle.edge = null;

        //Split into 4 triangles
        HalfEdge e04  = new HalfEdge(e01.origin);
        HalfEdge e42  = new HalfEdge(v);
        Triangle tri0 = new Triangle(e04, e42, e20);

        HalfEdge e41  = new HalfEdge(v);
        HalfEdge e24  = new HalfEdge(e20.origin);
        Triangle tri1 = new Triangle(e41, e12, e24);

        HalfEdge.SetTwins(e24, e42);

        e04.origin.RemoveOutgoingEdge(e01);
        e04.origin.AddOutgoingEdge(e04);
        v.AddOutgoingEdge(e41);
        v.AddOutgoingEdge(e42);
        e20.origin.AddOutgoingEdge(e24);


        e01.incidentTriangle.children = new List <Triangle> {
            tri0, tri1
        };
        HalfEdge e10 = this.twin;

        if (e10 != null)
        {
            e10.incidentTriangle.edge = null;

            HalfEdge e03 = e10.next;
            HalfEdge e31 = e03.next;

            HalfEdge e14  = new HalfEdge(e10.origin);
            HalfEdge e43  = new HalfEdge(v);
            Triangle tri2 = new Triangle(e14, e43, e31);

            HalfEdge e40  = new HalfEdge(v);
            HalfEdge e34  = new HalfEdge(e31.origin);
            Triangle tri3 = new Triangle(e40, e03, e34);

            HalfEdge.SetTwins(e04, e40);
            HalfEdge.SetTwins(e14, e41);
            HalfEdge.SetTwins(e34, e43);

            e14.origin.RemoveOutgoingEdge(e10);
            e14.origin.AddOutgoingEdge(e14);
            v.AddOutgoingEdge(e40);
            v.AddOutgoingEdge(e43);
            e31.origin.AddOutgoingEdge(e34);

            e10.incidentTriangle.children = new List <Triangle> {
                tri2, tri3
            };
            return(new HalfEdge[] { e20, e12, e31, e03 });
        }

        return(new HalfEdge[] { e20, e12 });
    }