Пример #1
0
        /// <summary>
        ///     Cover the convex hull of a triangulation with subsegments.
        /// </summary>
        private void MarkHull()
        {
            Otri hulltri  = default(Otri);
            Otri nexttri  = default(Otri);
            Otri starttri = default(Otri);

            // Find a triangle handle on the hull.
            hulltri.tri    = mesh.dummytri;
            hulltri.orient = 0;
            hulltri.Sym();
            // Remember where we started so we know when to stop.
            hulltri.Copy(ref starttri);
            // Go once counterclockwise around the convex hull.
            do
            {
                // Create a subsegment if there isn't already one here.
                mesh.InsertSubseg(ref hulltri, 1);
                // To find the next hull edge, go clockwise around the next vertex.
                hulltri.Lnext();
                hulltri.Oprev(ref nexttri);
                while (nexttri.tri.Id != Mesh.DUMMY)
                {
                    nexttri.Copy(ref hulltri);
                    hulltri.Oprev(ref nexttri);
                }
            } while (!hulltri.Equal(starttri));
        }
Пример #2
0
        private int RemoveGhosts(ref Otri startghost)
        {
            Otri otri  = new Otri();
            Otri otri1 = new Otri();
            Otri otri2 = new Otri();
            bool poly  = !this.mesh.behavior.Poly;

            startghost.Lprev(ref otri);
            otri.SymSelf();
            Mesh.dummytri.neighbors[0] = otri;
            startghost.Copy(ref otri1);
            int num = 0;

            do
            {
                num++;
                otri1.Lnext(ref otri2);
                otri1.LprevSelf();
                otri1.SymSelf();
                if (poly && otri1.triangle != Mesh.dummytri)
                {
                    Vertex vertex = otri1.Org();
                    if (vertex.mark == 0)
                    {
                        vertex.mark = 1;
                    }
                }
                otri1.Dissolve();
                otri2.Sym(ref otri1);
                this.mesh.TriangleDealloc(otri2.triangle);
            }while (!otri1.Equal(startghost));
            return(num);
        }
Пример #3
0
        /// <summary>
        /// Virally infect all of the triangles of the convex hull that are not
        /// protected by subsegments. Where there are subsegments, set boundary
        /// markers as appropriate.
        /// </summary>
        private void InfectHull()
        {
            Otri   hulltri = default(Otri);
            Otri   nexttri = default(Otri);
            Otri   starttri = default(Otri);
            Osub   hullsubseg = default(Osub);
            Vertex horg, hdest;

            // Find a triangle handle on the hull.
            hulltri.triangle = Mesh.dummytri;
            hulltri.orient   = 0;
            hulltri.SymSelf();
            // Remember where we started so we know when to stop.
            hulltri.Copy(ref starttri);
            // Go once counterclockwise around the convex hull.
            do
            {
                // Ignore triangles that are already infected.
                if (!hulltri.IsInfected())
                {
                    // Is the triangle protected by a subsegment?
                    hulltri.SegPivot(ref hullsubseg);
                    if (hullsubseg.seg == Mesh.dummysub)
                    {
                        // The triangle is not protected; infect it.
                        if (!hulltri.IsInfected())
                        {
                            hulltri.Infect();
                            viri.Add(hulltri.triangle);
                        }
                    }
                    else
                    {
                        // The triangle is protected; set boundary markers if appropriate.
                        if (hullsubseg.seg.boundary == 0)
                        {
                            hullsubseg.seg.boundary = 1;
                            horg  = hulltri.Org();
                            hdest = hulltri.Dest();
                            if (horg.mark == 0)
                            {
                                horg.mark = 1;
                            }
                            if (hdest.mark == 0)
                            {
                                hdest.mark = 1;
                            }
                        }
                    }
                }
                // To find the next hull edge, go clockwise around the next vertex.
                hulltri.LnextSelf();
                hulltri.Oprev(ref nexttri);
                while (nexttri.triangle != Mesh.dummytri)
                {
                    nexttri.Copy(ref hulltri);
                    hulltri.Oprev(ref nexttri);
                }
            } while (!hulltri.Equal(starttri));
        }
Пример #4
0
        private int RemoveBox()
        {
            Otri otri  = new Otri();
            Otri otri1 = new Otri();
            Otri otri2 = new Otri();
            Otri otri3 = new Otri();
            Otri otri4 = new Otri();
            Otri otri5 = new Otri();
            bool poly  = !this.mesh.behavior.Poly;

            otri3.triangle = Mesh.dummytri;
            otri3.orient   = 0;
            otri3.SymSelf();
            otri3.Lprev(ref otri4);
            otri3.LnextSelf();
            otri3.SymSelf();
            otri3.Lprev(ref otri1);
            otri1.SymSelf();
            otri3.Lnext(ref otri2);
            otri2.SymSelf();
            if (otri2.triangle == Mesh.dummytri)
            {
                otri1.LprevSelf();
                otri1.SymSelf();
            }
            Mesh.dummytri.neighbors[0] = otri1;
            int num = -2;

            while (!otri3.Equal(otri4))
            {
                num++;
                otri3.Lprev(ref otri5);
                otri5.SymSelf();
                if (poly && otri5.triangle != Mesh.dummytri)
                {
                    Vertex vertex = otri5.Org();
                    if (vertex.mark == 0)
                    {
                        vertex.mark = 1;
                    }
                }
                otri5.Dissolve();
                otri3.Lnext(ref otri);
                otri.Sym(ref otri3);
                this.mesh.TriangleDealloc(otri.triangle);
                if (otri3.triangle != Mesh.dummytri)
                {
                    continue;
                }
                otri5.Copy(ref otri3);
            }
            this.mesh.TriangleDealloc(otri4.triangle);
            return(num);
        }
        /// <summary>
        /// Removes ghost triangles.
        /// </summary>
        /// <param name="startghost"></param>
        /// <returns>Number of vertices on the hull.</returns>
        int RemoveGhosts(ref Otri startghost)
        {
            Otri   searchedge   = default(Otri);
            Otri   dissolveedge = default(Otri);
            Otri   deadtriangle = default(Otri);
            Vertex markorg;

            int hullsize;

            bool noPoly = !mesh.behavior.Poly;

            // Find an edge on the convex hull to start point location from.
            startghost.Lprev(ref searchedge);
            searchedge.SymSelf();
            Mesh.dummytri.neighbors[0] = searchedge;
            // Remove the bounding box and count the convex hull edges.
            startghost.Copy(ref dissolveedge);
            hullsize = 0;
            do
            {
                hullsize++;
                dissolveedge.Lnext(ref deadtriangle);
                dissolveedge.LprevSelf();
                dissolveedge.SymSelf();

                // If no PSLG is involved, set the boundary markers of all the vertices
                // on the convex hull.  If a PSLG is used, this step is done later.
                if (noPoly)
                {
                    // Watch out for the case where all the input vertices are collinear.
                    if (dissolveedge.triangle != Mesh.dummytri)
                    {
                        markorg = dissolveedge.Org();
                        if (markorg.mark == 0)
                        {
                            markorg.mark = 1;
                        }
                    }
                }

                // Remove a bounding triangle from a convex hull triangle.
                dissolveedge.Dissolve();
                // Find the next bounding triangle.
                deadtriangle.Sym(ref dissolveedge);

                // Delete the bounding triangle.
                mesh.TriangleDealloc(deadtriangle.triangle);
            } while (!dissolveedge.Equal(startghost));

            return(hullsize);
        }
Пример #6
0
        private void InfectHull()
        {
            Otri otri  = new Otri();
            Otri otri1 = new Otri();
            Otri otri2 = new Otri();
            Osub osub  = new Osub();

            otri.triangle = Mesh.dummytri;
            otri.orient   = 0;
            otri.SymSelf();
            otri.Copy(ref otri2);
            do
            {
                if (!otri.IsInfected())
                {
                    otri.SegPivot(ref osub);
                    if (osub.seg == Mesh.dummysub)
                    {
                        if (!otri.IsInfected())
                        {
                            otri.Infect();
                            this.viri.Add(otri.triangle);
                        }
                    }
                    else if (osub.seg.boundary == 0)
                    {
                        osub.seg.boundary = 1;
                        Vertex vertex  = otri.Org();
                        Vertex vertex1 = otri.Dest();
                        if (vertex.mark == 0)
                        {
                            vertex.mark = 1;
                        }
                        if (vertex1.mark == 0)
                        {
                            vertex1.mark = 1;
                        }
                    }
                }
                otri.LnextSelf();
                otri.Oprev(ref otri1);
                while (otri1.triangle != Mesh.dummytri)
                {
                    otri1.Copy(ref otri);
                    otri.Oprev(ref otri1);
                }
            }while (!otri.Equal(otri2));
        }
Пример #7
0
        SplayNode FrontLocate(SplayNode splayroot, Otri bottommost, Vertex searchvertex,
                              ref Otri searchtri, ref bool farright)
        {
            bool farrightflag;

            bottommost.Copy(ref searchtri);
            splayroot = Splay(splayroot, searchvertex, ref searchtri);

            farrightflag = false;
            while (!farrightflag && RightOfHyperbola(ref searchtri, searchvertex))
            {
                searchtri.OnextSelf();
                farrightflag = searchtri.Equal(bottommost);
            }
            farright = farrightflag;
            return(splayroot);
        }
Пример #8
0
        private void ConstructBvdCell(Vertex vertex)
        {
            VoronoiRegion region = new VoronoiRegion(vertex);

            regions.Add(region);

            Otri f      = default(Otri);
            Otri f_init = default(Otri);
            Otri f_next = default(Otri);
            Osub sf     = default(Osub);
            Osub sfn    = default(Osub);

            Point cc_f, cc_f_next, p;

            int n = mesh.triangles.Count;

            // Call P the polygon (cell) in construction
            List <Point> vpoints = new List <Point>();

            // Call f_init a triangle incident to x
            vertex.tri.Copy(ref f_init);

            if (f_init.Org() != vertex)
            {
                throw new Exception("ConstructBvdCell: inconsistent topology.");
            }

            // Let f be initialized to f_init
            f_init.Copy(ref f);
            // Call f_next the next triangle counterclockwise around x
            f_init.Onext(ref f_next);

            // repeat ... until f = f_init
            do
            {
                // Call Lffnext the line going through the circumcenters of f and f_next
                cc_f      = this.points[f.triangle.id];
                cc_f_next = this.points[f_next.triangle.id];

                // if f is tagged non-blind then
                if (!f.triangle.infected)
                {
                    // Insert the circumcenter of f into P
                    vpoints.Add(cc_f);

                    if (f_next.triangle.infected)
                    {
                        // Call S_fnext the constrained edge blinding f_next
                        sfn.seg = subsegMap[f_next.triangle.hash];

                        // Insert point Lf,f_next /\ Sf_next into P
                        if (SegmentsIntersect(sfn.SegOrg(), sfn.SegDest(), cc_f, cc_f_next, out p, true))
                        {
                            p.id = n + segIndex;
                            points[n + segIndex] = p;
                            segIndex++;

                            vpoints.Add(p);
                        }
                    }
                }
                else
                {
                    // Call Sf the constrained edge blinding f
                    sf.seg = subsegMap[f.triangle.hash];

                    // if f_next is tagged non-blind then
                    if (!f_next.triangle.infected)
                    {
                        // Insert point Lf,f_next /\ Sf into P
                        if (SegmentsIntersect(sf.SegOrg(), sf.SegDest(), cc_f, cc_f_next, out p, true))
                        {
                            p.id = n + segIndex;
                            points[n + segIndex] = p;
                            segIndex++;

                            vpoints.Add(p);
                        }
                    }
                    else
                    {
                        // Call Sf_next the constrained edge blinding f_next
                        sfn.seg = subsegMap[f_next.triangle.hash];

                        // if Sf != Sf_next then
                        if (!sf.Equal(sfn))
                        {
                            // Insert Lf,fnext /\ Sf and Lf,fnext /\ Sfnext into P
                            if (SegmentsIntersect(sf.SegOrg(), sf.SegDest(), cc_f, cc_f_next, out p, true))
                            {
                                p.id = n + segIndex;
                                points[n + segIndex] = p;
                                segIndex++;

                                vpoints.Add(p);
                            }

                            if (SegmentsIntersect(sfn.SegOrg(), sfn.SegDest(), cc_f, cc_f_next, out p, true))
                            {
                                p.id = n + segIndex;
                                points[n + segIndex] = p;
                                segIndex++;

                                vpoints.Add(p);
                            }
                        }
                    }
                }

                // f <- f_next
                f_next.Copy(ref f);

                // Call f_next the next triangle counterclockwise around x
                f_next.OnextSelf();
            }while (!f.Equal(f_init));

            // Output: Bounded Voronoi cell of x in counterclockwise order.
            region.Add(vpoints);
        }
Пример #9
0
        private SweepLine.SplayNode FrontLocate(SweepLine.SplayNode splayroot, Otri bottommost, Vertex searchvertex, ref Otri searchtri, ref bool farright)
        {
            bool i;

            bottommost.Copy(ref searchtri);
            splayroot = this.Splay(splayroot, searchvertex, ref searchtri);
            for (i = false; !i && this.RightOfHyperbola(ref searchtri, searchvertex); i = searchtri.Equal(bottommost))
            {
                searchtri.OnextSelf();
            }
            farright = i;
            return(splayroot);
        }
Пример #10
0
        public int Triangulate(Mesh mesh)
        {
            SweepLine.SweepEvent[] sweepEventArray;
            SweepLine.SweepEvent   sweepEvent;
            Vertex vertex;
            Vertex vertex1;
            Vertex vertex2;
            Vertex vertex3;

            this.mesh        = mesh;
            this.xminextreme = 10 * mesh.bounds.Xmin - 9 * mesh.bounds.Xmax;
            Otri otri  = new Otri();
            Otri otri1 = new Otri();
            Otri otri2 = new Otri();
            Otri otri3 = new Otri();
            Otri otri4 = new Otri();
            Otri otri5 = new Otri();
            Otri otri6 = new Otri();
            bool i     = false;

            this.splaynodes = new List <SweepLine.SplayNode>();
            SweepLine.SplayNode splayNode = null;
            this.CreateHeap(out sweepEventArray);
            int num = mesh.invertices;

            mesh.MakeTriangle(ref otri2);
            mesh.MakeTriangle(ref otri3);
            otri2.Bond(ref otri3);
            otri2.LnextSelf();
            otri3.LprevSelf();
            otri2.Bond(ref otri3);
            otri2.LnextSelf();
            otri3.LprevSelf();
            otri2.Bond(ref otri3);
            Vertex vertex4 = sweepEventArray[0].vertexEvent;

            this.HeapDelete(sweepEventArray, num, 0);
            num--;
            do
            {
                if (num == 0)
                {
                    SimpleLog.Instance.Error("Input vertices are all identical.", "SweepLine.SweepLineDelaunay()");
                    throw new Exception("Input vertices are all identical.");
                }
                vertex = sweepEventArray[0].vertexEvent;
                this.HeapDelete(sweepEventArray, num, 0);
                num--;
                if (vertex4.x != vertex.x || vertex4.y != vertex.y)
                {
                    continue;
                }
                if (Behavior.Verbose)
                {
                    SimpleLog.Instance.Warning("A duplicate vertex appeared and was ignored.", "SweepLine.SweepLineDelaunay().1");
                }
                vertex.type = VertexType.UndeadVertex;
                Mesh mesh1 = mesh;
                mesh1.undeads = mesh1.undeads + 1;
            }while (vertex4.x == vertex.x && vertex4.y == vertex.y);
            otri2.SetOrg(vertex4);
            otri2.SetDest(vertex);
            otri3.SetOrg(vertex);
            otri3.SetDest(vertex4);
            otri2.Lprev(ref otri);
            Vertex vertex5 = vertex;

            while (num > 0)
            {
                SweepLine.SweepEvent sweepEvent1 = sweepEventArray[0];
                this.HeapDelete(sweepEventArray, num, 0);
                num--;
                bool flag = true;
                if (sweepEvent1.xkey >= mesh.bounds.Xmin)
                {
                    Vertex vertex6 = sweepEvent1.vertexEvent;
                    if (vertex6.x != vertex5.x || vertex6.y != vertex5.y)
                    {
                        vertex5   = vertex6;
                        splayNode = this.FrontLocate(splayNode, otri, vertex6, ref otri1, ref i);
                        otri.Copy(ref otri1);
                        for (i = false; !i && this.RightOfHyperbola(ref otri1, vertex6); i = otri1.Equal(otri))
                        {
                            otri1.OnextSelf();
                        }
                        this.Check4DeadEvent(ref otri1, sweepEventArray, ref num);
                        otri1.Copy(ref otri5);
                        otri1.Sym(ref otri4);
                        mesh.MakeTriangle(ref otri2);
                        mesh.MakeTriangle(ref otri3);
                        Vertex vertex7 = otri5.Dest();
                        otri2.SetOrg(vertex7);
                        otri2.SetDest(vertex6);
                        otri3.SetOrg(vertex6);
                        otri3.SetDest(vertex7);
                        otri2.Bond(ref otri3);
                        otri2.LnextSelf();
                        otri3.LprevSelf();
                        otri2.Bond(ref otri3);
                        otri2.LnextSelf();
                        otri3.LprevSelf();
                        otri2.Bond(ref otri4);
                        otri3.Bond(ref otri5);
                        if (!i && otri5.Equal(otri))
                        {
                            otri2.Copy(ref otri);
                        }
                        if (this.randomnation(SweepLine.SAMPLERATE) == 0)
                        {
                            splayNode = this.SplayInsert(splayNode, otri2, vertex6);
                        }
                        else if (this.randomnation(SweepLine.SAMPLERATE) == 0)
                        {
                            otri3.Lnext(ref otri6);
                            splayNode = this.SplayInsert(splayNode, otri6, vertex6);
                        }
                    }
                    else
                    {
                        if (Behavior.Verbose)
                        {
                            SimpleLog.Instance.Warning("A duplicate vertex appeared and was ignored.", "SweepLine.SweepLineDelaunay().2");
                        }
                        vertex6.type = VertexType.UndeadVertex;
                        Mesh mesh2 = mesh;
                        mesh2.undeads = mesh2.undeads + 1;
                        flag          = false;
                    }
                }
                else
                {
                    Otri otri7 = sweepEvent1.otriEvent;
                    otri7.Oprev(ref otri4);
                    this.Check4DeadEvent(ref otri4, sweepEventArray, ref num);
                    otri7.Onext(ref otri5);
                    this.Check4DeadEvent(ref otri5, sweepEventArray, ref num);
                    if (otri4.Equal(otri))
                    {
                        otri7.Lprev(ref otri);
                    }
                    mesh.Flip(ref otri7);
                    otri7.SetApex(null);
                    otri7.Lprev(ref otri2);
                    otri7.Lnext(ref otri3);
                    otri2.Sym(ref otri4);
                    if (this.randomnation(SweepLine.SAMPLERATE) == 0)
                    {
                        otri7.SymSelf();
                        vertex1   = otri7.Dest();
                        vertex2   = otri7.Apex();
                        vertex3   = otri7.Org();
                        splayNode = this.CircleTopInsert(splayNode, otri2, vertex1, vertex2, vertex3, sweepEvent1.ykey);
                    }
                }
                if (!flag)
                {
                    continue;
                }
                vertex1 = otri4.Apex();
                vertex2 = otri2.Dest();
                vertex3 = otri2.Apex();
                double num1 = Primitives.CounterClockwise(vertex1, vertex2, vertex3);
                if (num1 > 0)
                {
                    sweepEvent = new SweepLine.SweepEvent()
                    {
                        xkey      = this.xminextreme,
                        ykey      = this.CircleTop(vertex1, vertex2, vertex3, num1),
                        otriEvent = otri2
                    };
                    this.HeapInsert(sweepEventArray, num, sweepEvent);
                    num++;
                    otri2.SetOrg(new SweepLine.SweepEventVertex(sweepEvent));
                }
                vertex1 = otri3.Apex();
                vertex2 = otri3.Org();
                vertex3 = otri5.Apex();
                double num2 = Primitives.CounterClockwise(vertex1, vertex2, vertex3);
                if (num2 <= 0)
                {
                    continue;
                }
                sweepEvent = new SweepLine.SweepEvent()
                {
                    xkey      = this.xminextreme,
                    ykey      = this.CircleTop(vertex1, vertex2, vertex3, num2),
                    otriEvent = otri5
                };
                this.HeapInsert(sweepEventArray, num, sweepEvent);
                num++;
                otri5.SetOrg(new SweepLine.SweepEventVertex(sweepEvent));
            }
            this.splaynodes.Clear();
            otri.LprevSelf();
            return(this.RemoveGhosts(ref otri));
        }
Пример #11
0
        public int Triangulate(Mesh mesh)
        {
            this.mesh = mesh;

            // Nonexistent x value used as a flag to mark circle events in sweepline
            // Delaunay algorithm.
            xminextreme = 10 * mesh.bounds.Xmin - 9 * mesh.bounds.Xmax;

            SweepEvent[] eventheap;

            SweepEvent nextevent;
            SweepEvent newevent;
            SplayNode  splayroot;
            Otri       bottommost = default(Otri);
            Otri       searchtri  = default(Otri);
            Otri       fliptri;
            Otri       lefttri = default(Otri);
            Otri       righttri = default(Otri);
            Otri       farlefttri = default(Otri);
            Otri       farrighttri = default(Otri);
            Otri       inserttri = default(Otri);
            Vertex     firstvertex, secondvertex;
            Vertex     nextvertex, lastvertex;
            Vertex     connectvertex;
            Vertex     leftvertex, midvertex, rightvertex;
            float      lefttest, righttest;
            int        heapsize;
            bool       check4events, farrightflag = false;

            splaynodes = new List <SplayNode>();
            splayroot  = null;

            CreateHeap(out eventheap);//, out events, out freeevents);
            heapsize = mesh.invertices;

            mesh.MakeTriangle(ref lefttri);
            mesh.MakeTriangle(ref righttri);
            lefttri.Bond(ref righttri);
            lefttri.LnextSelf();
            righttri.LprevSelf();
            lefttri.Bond(ref righttri);
            lefttri.LnextSelf();
            righttri.LprevSelf();
            lefttri.Bond(ref righttri);
            firstvertex = eventheap[0].vertexEvent;

            HeapDelete(eventheap, heapsize, 0);
            heapsize--;
            do
            {
                if (heapsize == 0)
                {
                    SimpleLog.Instance.Error("Input vertices are all identical.", "SweepLine.SweepLineDelaunay()");
                    throw new Exception("Input vertices are all identical.");
                }
                secondvertex = eventheap[0].vertexEvent;
                HeapDelete(eventheap, heapsize, 0);
                heapsize--;
                if ((firstvertex.x == secondvertex.x) &&
                    (firstvertex.y == secondvertex.y))
                {
                    if (Behavior.Verbose)
                    {
                        SimpleLog.Instance.Warning("A duplicate vertex appeared and was ignored.",
                                                   "SweepLine.SweepLineDelaunay().1");
                    }
                    secondvertex.type = VertexType.UndeadVertex;
                    mesh.undeads++;
                }
            } while ((firstvertex.x == secondvertex.x) &&
                     (firstvertex.y == secondvertex.y));
            lefttri.SetOrg(firstvertex);
            lefttri.SetDest(secondvertex);
            righttri.SetOrg(secondvertex);
            righttri.SetDest(firstvertex);
            lefttri.Lprev(ref bottommost);
            lastvertex = secondvertex;

            while (heapsize > 0)
            {
                nextevent = eventheap[0];
                HeapDelete(eventheap, heapsize, 0);
                heapsize--;
                check4events = true;
                if (nextevent.xkey < mesh.bounds.Xmin)
                {
                    fliptri = nextevent.otriEvent;
                    fliptri.Oprev(ref farlefttri);
                    Check4DeadEvent(ref farlefttri, eventheap, ref heapsize);
                    fliptri.Onext(ref farrighttri);
                    Check4DeadEvent(ref farrighttri, eventheap, ref heapsize);

                    if (farlefttri.Equal(bottommost))
                    {
                        fliptri.Lprev(ref bottommost);
                    }
                    mesh.Flip(ref fliptri);
                    fliptri.SetApex(null);
                    fliptri.Lprev(ref lefttri);
                    fliptri.Lnext(ref righttri);
                    lefttri.Sym(ref farlefttri);

                    if (randomnation(SAMPLERATE) == 0)
                    {
                        fliptri.SymSelf();
                        leftvertex  = fliptri.Dest();
                        midvertex   = fliptri.Apex();
                        rightvertex = fliptri.Org();
                        splayroot   = CircleTopInsert(splayroot, lefttri, leftvertex, midvertex, rightvertex, nextevent.ykey);
                    }
                }
                else
                {
                    nextvertex = nextevent.vertexEvent;
                    if ((nextvertex.x == lastvertex.x) &&
                        (nextvertex.y == lastvertex.y))
                    {
                        if (Behavior.Verbose)
                        {
                            SimpleLog.Instance.Warning("A duplicate vertex appeared and was ignored.",
                                                       "SweepLine.SweepLineDelaunay().2");
                        }
                        nextvertex.type = VertexType.UndeadVertex;
                        mesh.undeads++;
                        check4events = false;
                    }
                    else
                    {
                        lastvertex = nextvertex;

                        splayroot = FrontLocate(splayroot, bottommost, nextvertex,
                                                ref searchtri, ref farrightflag);
                        //
                        bottommost.Copy(ref searchtri);
                        farrightflag = false;
                        while (!farrightflag && RightOfHyperbola(ref searchtri, nextvertex))
                        {
                            searchtri.OnextSelf();
                            farrightflag = searchtri.Equal(bottommost);
                        }


                        Check4DeadEvent(ref searchtri, eventheap, ref heapsize);

                        searchtri.Copy(ref farrighttri);
                        searchtri.Sym(ref farlefttri);
                        mesh.MakeTriangle(ref lefttri);
                        mesh.MakeTriangle(ref righttri);
                        connectvertex = farrighttri.Dest();
                        lefttri.SetOrg(connectvertex);
                        lefttri.SetDest(nextvertex);
                        righttri.SetOrg(nextvertex);
                        righttri.SetDest(connectvertex);
                        lefttri.Bond(ref righttri);
                        lefttri.LnextSelf();
                        righttri.LprevSelf();
                        lefttri.Bond(ref righttri);
                        lefttri.LnextSelf();
                        righttri.LprevSelf();
                        lefttri.Bond(ref farlefttri);
                        righttri.Bond(ref farrighttri);
                        if (!farrightflag && farrighttri.Equal(bottommost))
                        {
                            lefttri.Copy(ref bottommost);
                        }

                        if (randomnation(SAMPLERATE) == 0)
                        {
                            splayroot = SplayInsert(splayroot, lefttri, nextvertex);
                        }
                        else if (randomnation(SAMPLERATE) == 0)
                        {
                            righttri.Lnext(ref inserttri);
                            splayroot = SplayInsert(splayroot, inserttri, nextvertex);
                        }
                    }
                }

                if (check4events)
                {
                    leftvertex  = farlefttri.Apex();
                    midvertex   = lefttri.Dest();
                    rightvertex = lefttri.Apex();
                    lefttest    = Primitives.CounterClockwise(leftvertex, midvertex, rightvertex);
                    if (lefttest > 0.0)
                    {
                        newevent = new SweepEvent();

                        newevent.xkey      = xminextreme;
                        newevent.ykey      = CircleTop(leftvertex, midvertex, rightvertex, lefttest);
                        newevent.otriEvent = lefttri;
                        HeapInsert(eventheap, heapsize, newevent);
                        heapsize++;
                        lefttri.SetOrg(new SweepEventVertex(newevent));
                    }
                    leftvertex  = righttri.Apex();
                    midvertex   = righttri.Org();
                    rightvertex = farrighttri.Apex();
                    righttest   = Primitives.CounterClockwise(leftvertex, midvertex, rightvertex);
                    if (righttest > 0.0)
                    {
                        newevent = new SweepEvent();

                        newevent.xkey      = xminextreme;
                        newevent.ykey      = CircleTop(leftvertex, midvertex, rightvertex, righttest);
                        newevent.otriEvent = farrighttri;
                        HeapInsert(eventheap, heapsize, newevent);
                        heapsize++;
                        farrighttri.SetOrg(new SweepEventVertex(newevent));
                    }
                }
            }

            splaynodes.Clear();
            bottommost.LprevSelf();
            return(RemoveGhosts(ref bottommost));
        }
Пример #12
0
        private void ConstructBoundaryBvdCell(Vertex vertex)
        {
            VoronoiRegion region = new VoronoiRegion(vertex);

            regions.Add(region);

            Otri f      = default(Otri);
            Otri f_init = default(Otri);
            Otri f_next = default(Otri);
            Otri f_prev = default(Otri);
            Osub sf     = default(Osub);
            Osub sfn    = default(Osub);

            Vertex torg, tdest, tapex, sorg, sdest;
            Point  cc_f, cc_f_next, p;

            int n = mesh.triangles.Count;

            // Call P the polygon (cell) in construction
            List <Point> vpoints = new List <Point>();

            // Call f_init a triangle incident to x
            vertex.tri.Copy(ref f_init);

            if (f_init.Org() != vertex)
            {
                throw new Exception("ConstructBoundaryBvdCell: inconsistent topology.");
            }
            // Let f be initialized to f_init
            f_init.Copy(ref f);
            // Call f_next the next triangle counterclockwise around x
            f_init.Onext(ref f_next);

            f_init.Oprev(ref f_prev);

            // Is the border to the left?
            if (f_prev.triangle != Mesh.dummytri)
            {
                // Go clockwise until we reach the border (or the initial triangle)
                while (f_prev.triangle != Mesh.dummytri && !f_prev.Equal(f_init))
                {
                    f_prev.Copy(ref f);
                    f_prev.OprevSelf();
                }

                f.Copy(ref f_init);
                f.Onext(ref f_next);
            }

            if (f_prev.triangle == Mesh.dummytri)
            {
                // For vertices on the domain boundaray, add the vertex. For
                // internal boundaries don't add it.
                p    = new Point(vertex.x, vertex.y);
                p.id = n + segIndex;
                points[n + segIndex] = p;
                segIndex++;

                vpoints.Add(p);
            }

            // Add midpoint of start triangles' edge.
            torg  = f.Org();
            tdest = f.Dest();
            p     = new Point((torg.X + tdest.X) / 2, (torg.Y + tdest.Y) / 2);
            p.id  = n + segIndex;
            points[n + segIndex] = p;
            segIndex++;

            vpoints.Add(p);

            // repeat ... until f = f_init
            do
            {
                // Call Lffnext the line going through the circumcenters of f and f_next
                cc_f = this.points[f.triangle.id];

                if (f_next.triangle == Mesh.dummytri)
                {
                    if (!f.triangle.infected)
                    {
                        // Add last circumcenter
                        vpoints.Add(cc_f);
                    }

                    // Add midpoint of last triangles' edge (chances are it has already
                    // been added, so post process cell to remove duplicates???)
                    torg  = f.Org();
                    tapex = f.Apex();
                    p     = new Point((torg.X + tapex.X) / 2, (torg.Y + tapex.Y) / 2);
                    p.id  = n + segIndex;
                    points[n + segIndex] = p;
                    segIndex++;

                    vpoints.Add(p);

                    break;
                }

                cc_f_next = this.points[f_next.triangle.id];

                // if f is tagged non-blind then
                if (!f.triangle.infected)
                {
                    // Insert the circumcenter of f into P
                    vpoints.Add(cc_f);

                    if (f_next.triangle.infected)
                    {
                        // Call S_fnext the constrained edge blinding f_next
                        sfn.seg = subsegMap[f_next.triangle.hash];

                        // Insert point Lf,f_next /\ Sf_next into P
                        if (SegmentsIntersect(sfn.SegOrg(), sfn.SegDest(), cc_f, cc_f_next, out p, true))
                        {
                            p.id = n + segIndex;
                            points[n + segIndex] = p;
                            segIndex++;

                            vpoints.Add(p);
                        }
                    }
                }
                else
                {
                    // Call Sf the constrained edge blinding f
                    sf.seg = subsegMap[f.triangle.hash];

                    sorg  = sf.SegOrg();
                    sdest = sf.SegDest();

                    // if f_next is tagged non-blind then
                    if (!f_next.triangle.infected)
                    {
                        tdest = f.Dest();
                        tapex = f.Apex();

                        // Both circumcenters lie on the blinded side, but we
                        // have to add the intersection with the segment.

                        // Center of f edge dest->apex
                        Point bisec = new Point((tdest.X + tapex.X) / 2, (tdest.Y + tapex.Y) / 2);

                        // Find intersection of seg with line through f's bisector and circumcenter
                        if (SegmentsIntersect(sorg, sdest, bisec, cc_f, out p, false))
                        {
                            p.id = n + segIndex;
                            points[n + segIndex] = p;
                            segIndex++;

                            vpoints.Add(p);
                        }

                        // Insert point Lf,f_next /\ Sf into P
                        if (SegmentsIntersect(sorg, sdest, cc_f, cc_f_next, out p, true))
                        {
                            p.id = n + segIndex;
                            points[n + segIndex] = p;
                            segIndex++;

                            vpoints.Add(p);
                        }
                    }
                    else
                    {
                        // Call Sf_next the constrained edge blinding f_next
                        sfn.seg = subsegMap[f_next.triangle.hash];

                        // if Sf != Sf_next then
                        if (!sf.Equal(sfn))
                        {
                            // Insert Lf,fnext /\ Sf and Lf,fnext /\ Sfnext into P
                            if (SegmentsIntersect(sorg, sdest, cc_f, cc_f_next, out p, true))
                            {
                                p.id = n + segIndex;
                                points[n + segIndex] = p;
                                segIndex++;

                                vpoints.Add(p);
                            }

                            if (SegmentsIntersect(sfn.SegOrg(), sfn.SegDest(), cc_f, cc_f_next, out p, true))
                            {
                                p.id = n + segIndex;
                                points[n + segIndex] = p;
                                segIndex++;

                                vpoints.Add(p);
                            }
                        }
                        else
                        {
                            // Both circumcenters lie on the blinded side, but we
                            // have to add the intersection with the segment.

                            // Center of f_next edge org->dest
                            Point bisec = new Point((torg.X + tdest.X) / 2, (torg.Y + tdest.Y) / 2);

                            // Find intersection of seg with line through f_next's bisector and circumcenter
                            if (SegmentsIntersect(sorg, sdest, bisec, cc_f_next, out p, false))
                            {
                                p.id = n + segIndex;
                                points[n + segIndex] = p;
                                segIndex++;

                                vpoints.Add(p);
                            }
                        }
                    }
                }

                // f <- f_next
                f_next.Copy(ref f);

                // Call f_next the next triangle counterclockwise around x
                f_next.OnextSelf();
            }while (!f.Equal(f_init));

            // Output: Bounded Voronoi cell of x in counterclockwise order.
            region.Add(vpoints);
        }
Пример #13
0
        private void Plague()
        {
            Otri item = new Otri();
            Otri otri = new Otri();
            Osub osub = new Osub();

            for (int i = 0; i < this.viri.Count; i++)
            {
                item.triangle = this.viri[i];
                item.Uninfect();
                item.orient = 0;
                while (item.orient < 3)
                {
                    item.Sym(ref otri);
                    item.SegPivot(ref osub);
                    if (otri.triangle != Mesh.dummytri && !otri.IsInfected())
                    {
                        if (osub.seg != Mesh.dummysub)
                        {
                            osub.TriDissolve();
                            if (osub.seg.boundary == 0)
                            {
                                osub.seg.boundary = 1;
                            }
                            Vertex vertex  = otri.Org();
                            Vertex vertex1 = otri.Dest();
                            if (vertex.mark == 0)
                            {
                                vertex.mark = 1;
                            }
                            if (vertex1.mark == 0)
                            {
                                vertex1.mark = 1;
                            }
                        }
                        else
                        {
                            otri.Infect();
                            this.viri.Add(otri.triangle);
                        }
                    }
                    else if (osub.seg != Mesh.dummysub)
                    {
                        this.mesh.SubsegDealloc(osub.seg);
                        if (otri.triangle != Mesh.dummytri)
                        {
                            otri.Uninfect();
                            otri.SegDissolve();
                            otri.Infect();
                        }
                    }
                    item.orient = item.orient + 1;
                }
                item.Infect();
            }
            foreach (Triangle virus in this.viri)
            {
                item.triangle = virus;
                item.orient   = 0;
                while (item.orient < 3)
                {
                    Vertex vertex2 = item.Org();
                    if (vertex2 != null)
                    {
                        bool flag = true;
                        item.SetOrg(null);
                        item.Onext(ref otri);
                        while (otri.triangle != Mesh.dummytri && !otri.Equal(item))
                        {
                            if (!otri.IsInfected())
                            {
                                flag = false;
                            }
                            else
                            {
                                otri.SetOrg(null);
                            }
                            otri.OnextSelf();
                        }
                        if (otri.triangle == Mesh.dummytri)
                        {
                            item.Oprev(ref otri);
                            while (otri.triangle != Mesh.dummytri)
                            {
                                if (!otri.IsInfected())
                                {
                                    flag = false;
                                }
                                else
                                {
                                    otri.SetOrg(null);
                                }
                                otri.OprevSelf();
                            }
                        }
                        if (flag)
                        {
                            vertex2.type = VertexType.UndeadVertex;
                            Mesh mesh = this.mesh;
                            mesh.undeads = mesh.undeads + 1;
                        }
                    }
                    item.orient = item.orient + 1;
                }
                item.orient = 0;
                while (item.orient < 3)
                {
                    item.Sym(ref otri);
                    if (otri.triangle != Mesh.dummytri)
                    {
                        otri.Dissolve();
                        Mesh mesh1 = this.mesh;
                        mesh1.hullsize = mesh1.hullsize + 1;
                    }
                    else
                    {
                        Mesh mesh2 = this.mesh;
                        mesh2.hullsize = mesh2.hullsize - 1;
                    }
                    item.orient = item.orient + 1;
                }
                this.mesh.TriangleDealloc(item.triangle);
            }
            this.viri.Clear();
        }
Пример #14
0
        /// <summary>
        /// Spread the virus from all infected triangles to any neighbors not
        /// protected by subsegments. Delete all infected triangles.
        /// </summary>
        /// <remarks>
        /// This is the procedure that actually creates holes and concavities.
        ///
        /// This procedure operates in two phases. The first phase identifies all
        /// the triangles that will die, and marks them as infected. They are
        /// marked to ensure that each triangle is added to the virus pool only
        /// once, so the procedure will terminate.
        ///
        /// The second phase actually eliminates the infected triangles. It also
        /// eliminates orphaned vertices.
        /// </remarks>
        void Plague()
        {
            Otri   testtri        = default(Otri);
            Otri   neighbor       = default(Otri);
            Osub   neighborsubseg = default(Osub);
            Vertex testvertex;
            Vertex norg, ndest;

            bool killorg;

            // Loop through all the infected triangles, spreading the virus to
            // their neighbors, then to their neighbors' neighbors.
            for (int i = 0; i < viri.Count; i++)
            {
                // WARNING: Don't use foreach, mesh.viri list may get modified.

                testtri.triangle = viri[i];
                // A triangle is marked as infected by messing with one of its pointers
                // to subsegments, setting it to an illegal value.  Hence, we have to
                // temporarily uninfect this triangle so that we can examine its
                // adjacent subsegments.
                // TODO: Not true in the C# version (so we could skip this).
                testtri.Uninfect();

                // Check each of the triangle's three neighbors.
                for (testtri.orient = 0; testtri.orient < 3; testtri.orient++)
                {
                    // Find the neighbor.
                    testtri.Sym(ref neighbor);
                    // Check for a subsegment between the triangle and its neighbor.
                    testtri.SegPivot(ref neighborsubseg);
                    // Check if the neighbor is nonexistent or already infected.
                    if ((neighbor.triangle == Mesh.dummytri) || neighbor.IsInfected())
                    {
                        if (neighborsubseg.seg != Mesh.dummysub)
                        {
                            // There is a subsegment separating the triangle from its
                            // neighbor, but both triangles are dying, so the subsegment
                            // dies too.
                            mesh.SubsegDealloc(neighborsubseg.seg);
                            if (neighbor.triangle != Mesh.dummytri)
                            {
                                // Make sure the subsegment doesn't get deallocated again
                                // later when the infected neighbor is visited.
                                neighbor.Uninfect();
                                neighbor.SegDissolve();
                                neighbor.Infect();
                            }
                        }
                    }
                    else
                    {   // The neighbor exists and is not infected.
                        if (neighborsubseg.seg == Mesh.dummysub)
                        {
                            // There is no subsegment protecting the neighbor, so
                            // the neighbor becomes infected.
                            neighbor.Infect();
                            // Ensure that the neighbor's neighbors will be infected.
                            viri.Add(neighbor.triangle);
                        }
                        else
                        {
                            // The neighbor is protected by a subsegment.
                            // Remove this triangle from the subsegment.
                            neighborsubseg.TriDissolve();
                            // The subsegment becomes a boundary.  Set markers accordingly.
                            if (neighborsubseg.seg.boundary == 0)
                            {
                                neighborsubseg.seg.boundary = 1;
                            }
                            norg  = neighbor.Org();
                            ndest = neighbor.Dest();
                            if (norg.mark == 0)
                            {
                                norg.mark = 1;
                            }
                            if (ndest.mark == 0)
                            {
                                ndest.mark = 1;
                            }
                        }
                    }
                }
                // Remark the triangle as infected, so it doesn't get added to the
                // virus pool again.
                testtri.Infect();
            }

            foreach (var virus in viri)
            {
                testtri.triangle = virus;

                // Check each of the three corners of the triangle for elimination.
                // This is done by walking around each vertex, checking if it is
                // still connected to at least one live triangle.
                for (testtri.orient = 0; testtri.orient < 3; testtri.orient++)
                {
                    testvertex = testtri.Org();
                    // Check if the vertex has already been tested.
                    if (testvertex != null)
                    {
                        killorg = true;
                        // Mark the corner of the triangle as having been tested.
                        testtri.SetOrg(null);
                        // Walk counterclockwise about the vertex.
                        testtri.Onext(ref neighbor);
                        // Stop upon reaching a boundary or the starting triangle.
                        while ((neighbor.triangle != Mesh.dummytri) &&
                               (!neighbor.Equal(testtri)))
                        {
                            if (neighbor.IsInfected())
                            {
                                // Mark the corner of this triangle as having been tested.
                                neighbor.SetOrg(null);
                            }
                            else
                            {
                                // A live triangle.  The vertex survives.
                                killorg = false;
                            }
                            // Walk counterclockwise about the vertex.
                            neighbor.OnextSelf();
                        }
                        // If we reached a boundary, we must walk clockwise as well.
                        if (neighbor.triangle == Mesh.dummytri)
                        {
                            // Walk clockwise about the vertex.
                            testtri.Oprev(ref neighbor);
                            // Stop upon reaching a boundary.
                            while (neighbor.triangle != Mesh.dummytri)
                            {
                                if (neighbor.IsInfected())
                                {
                                    // Mark the corner of this triangle as having been tested.
                                    neighbor.SetOrg(null);
                                }
                                else
                                {
                                    // A live triangle.  The vertex survives.
                                    killorg = false;
                                }
                                // Walk clockwise about the vertex.
                                neighbor.OprevSelf();
                            }
                        }
                        if (killorg)
                        {
                            // Deleting vertex
                            testvertex.type = VertexType.UndeadVertex;
                            mesh.undeads++;
                        }
                    }
                }

                // Record changes in the number of boundary edges, and disconnect
                // dead triangles from their neighbors.
                for (testtri.orient = 0; testtri.orient < 3; testtri.orient++)
                {
                    testtri.Sym(ref neighbor);
                    if (neighbor.triangle == Mesh.dummytri)
                    {
                        // There is no neighboring triangle on this edge, so this edge
                        // is a boundary edge. This triangle is being deleted, so this
                        // boundary edge is deleted.
                        mesh.hullsize--;
                    }
                    else
                    {
                        // Disconnect the triangle from its neighbor.
                        neighbor.Dissolve();
                        // There is a neighboring triangle on this edge, so this edge
                        // becomes a boundary edge when this triangle is deleted.
                        mesh.hullsize++;
                    }
                }
                // Return the dead triangle to the pool of triangles.
                mesh.TriangleDealloc(testtri.triangle);
            }

            // Empty the virus pool.
            viri.Clear();
        }
Пример #15
0
        private void ConstructVoronoiRegion(Vertex vertex)
        {
            Vertex        vertex1;
            Vertex        vertex2;
            VoronoiRegion voronoiRegion = new VoronoiRegion(vertex);

            this.regions.Add(voronoiRegion);
            List <Point> points = new List <Point>();
            Otri         otri   = new Otri();
            Otri         otri1  = new Otri();
            Otri         otri2  = new Otri();
            Otri         otri3  = new Otri();
            Osub         osub   = new Osub();

            vertex.tri.Copy(ref otri1);
            otri1.Copy(ref otri);
            otri1.Onext(ref otri2);
            if (otri2.triangle == Mesh.dummytri)
            {
                otri1.Oprev(ref otri3);
                if (otri3.triangle != Mesh.dummytri)
                {
                    otri1.Copy(ref otri2);
                    otri1.OprevSelf();
                    otri1.Copy(ref otri);
                }
            }
            while (otri2.triangle != Mesh.dummytri)
            {
                points.Add(this.points[otri.triangle.id]);
                if (otri2.Equal(otri1))
                {
                    voronoiRegion.Add(points);
                    return;
                }
                otri2.Copy(ref otri);
                otri2.OnextSelf();
            }
            voronoiRegion.Bounded = false;
            int count = this.mesh.triangles.Count;

            otri.Lprev(ref otri2);
            otri2.SegPivot(ref osub);
            int num = osub.seg.hash;

            points.Add(this.points[otri.triangle.id]);
            if (!this.rayPoints.ContainsKey(num))
            {
                vertex1 = otri.Org();
                Vertex vertex3 = otri.Apex();
                this.BoxRayIntersection(this.points[otri.triangle.id], vertex1.y - vertex3.y, vertex3.x - vertex1.x, out vertex2);
                vertex2.id = count + this.rayIndex;
                this.points[count + this.rayIndex] = vertex2;
                this.rayIndex = this.rayIndex + 1;
                points.Add(vertex2);
                this.rayPoints.Add(num, vertex2);
            }
            else
            {
                points.Add(this.rayPoints[num]);
            }
            points.Reverse();
            otri1.Copy(ref otri);
            otri.Oprev(ref otri3);
            while (otri3.triangle != Mesh.dummytri)
            {
                points.Add(this.points[otri3.triangle.id]);
                otri3.Copy(ref otri);
                otri3.OprevSelf();
            }
            otri.SegPivot(ref osub);
            num = osub.seg.hash;
            if (!this.rayPoints.ContainsKey(num))
            {
                vertex1 = otri.Org();
                Vertex vertex4 = otri.Dest();
                this.BoxRayIntersection(this.points[otri.triangle.id], vertex4.y - vertex1.y, vertex1.x - vertex4.x, out vertex2);
                vertex2.id = count + this.rayIndex;
                this.points[count + this.rayIndex] = vertex2;
                this.rayIndex = this.rayIndex + 1;
                points.Add(vertex2);
                this.rayPoints.Add(num, vertex2);
            }
            else
            {
                points.Add(this.rayPoints[num]);
            }
            points.Reverse();
            voronoiRegion.Add(points);
        }
Пример #16
0
        public Mesh Triangulate(List <Vertex> points)
        {
            mesh = TrianglePool.AllocMesh();
            mesh.TransferNodes(points);

            // Nonexistent x value used as a flag to mark circle events in sweepline
            // Delaunay algorithm.
            xminextreme = 10 * mesh.bounds.Left - 9 * mesh.bounds.Right;

            SweepEvent[] eventheap;

            SweepEvent nextevent;
            SweepEvent newevent;
            SplayNode  splayroot;
            Otri       bottommost = default(Otri);
            Otri       searchtri  = default(Otri);
            Otri       fliptri;
            Otri       lefttri = default(Otri);
            Otri       righttri = default(Otri);
            Otri       farlefttri = default(Otri);
            Otri       farrighttri = default(Otri);
            Otri       inserttri = default(Otri);
            Vertex     firstvertex, secondvertex;
            Vertex     nextvertex, lastvertex;
            Vertex     connectvertex;
            Vertex     leftvertex, midvertex, rightvertex;
            double     lefttest, righttest;
            int        heapsize;
            bool       check4events, farrightflag = false;

            splaynodes = new List <SplayNode>();
            splayroot  = null;

            CreateHeap(out eventheap); //, out events, out freeevents);
            heapsize = mesh.invertices;

            mesh.MakeTriangle(ref lefttri);
            mesh.MakeTriangle(ref righttri);
            lefttri.Bond(ref righttri);
            lefttri.Lnext();
            righttri.Lprev();
            lefttri.Bond(ref righttri);
            lefttri.Lnext();
            righttri.Lprev();
            lefttri.Bond(ref righttri);
            firstvertex = eventheap[0].vertexEvent;

            HeapDelete(eventheap, heapsize, 0);
            heapsize--;
            do
            {
                if (heapsize == 0)
                {
                    throw new Exception("Input vertices are all identical.");
                }

                secondvertex = eventheap[0].vertexEvent;
                HeapDelete(eventheap, heapsize, 0);
                heapsize--;
                if ((firstvertex.X == secondvertex.X) &&
                    (firstvertex.Y == secondvertex.Y))
                {
                    secondvertex.type = VertexType.UndeadVertex;
                    mesh.undeads++;
                }
            } while ((firstvertex.X == secondvertex.X) &&
                     (firstvertex.Y == secondvertex.Y));
            lefttri.SetOrg(firstvertex);
            lefttri.SetDest(secondvertex);
            righttri.SetOrg(secondvertex);
            righttri.SetDest(firstvertex);
            lefttri.Lprev(ref bottommost);
            lastvertex = secondvertex;

            while (heapsize > 0)
            {
                nextevent = eventheap[0];
                HeapDelete(eventheap, heapsize, 0);
                heapsize--;
                check4events = true;
                if (nextevent.xkey < mesh.bounds.Left)
                {
                    fliptri = nextevent.otriEvent;
                    fliptri.Oprev(ref farlefttri);
                    Check4DeadEvent(ref farlefttri, eventheap, ref heapsize);
                    fliptri.Onext(ref farrighttri);
                    Check4DeadEvent(ref farrighttri, eventheap, ref heapsize);

                    if (farlefttri.Equal(bottommost))
                    {
                        fliptri.Lprev(ref bottommost);
                    }
                    mesh.Flip(ref fliptri);
                    fliptri.SetApex(null);
                    fliptri.Lprev(ref lefttri);
                    fliptri.Lnext(ref righttri);
                    lefttri.Sym(ref farlefttri);

                    if (randomnation(SAMPLERATE) == 0)
                    {
                        fliptri.Sym();
                        leftvertex  = fliptri.Dest();
                        midvertex   = fliptri.Apex();
                        rightvertex = fliptri.Org();
                        splayroot   = CircleTopInsert(splayroot, lefttri, leftvertex, midvertex, rightvertex,
                                                      nextevent.ykey);
                    }
                }
                else
                {
                    nextvertex = nextevent.vertexEvent;
                    if ((nextvertex.X == lastvertex.X) &&
                        (nextvertex.Y == lastvertex.Y))
                    {
                        nextvertex.type = VertexType.UndeadVertex;
                        mesh.undeads++;
                        check4events = false;
                    }
                    else
                    {
                        lastvertex = nextvertex;

                        splayroot = FrontLocate(splayroot, bottommost, nextvertex, ref searchtri, ref farrightflag);

                        //bottommost.Copy(ref searchtri);
                        //farrightflag = false;
                        //while (!farrightflag && RightOfHyperbola(ref searchtri, nextvertex))
                        //{
                        //    searchtri.OnextSelf();
                        //    farrightflag = searchtri.Equal(bottommost);
                        //}

                        Check4DeadEvent(ref searchtri, eventheap, ref heapsize);

                        searchtri.Copy(ref farrighttri);
                        searchtri.Sym(ref farlefttri);
                        mesh.MakeTriangle(ref lefttri);
                        mesh.MakeTriangle(ref righttri);
                        connectvertex = farrighttri.Dest();
                        lefttri.SetOrg(connectvertex);
                        lefttri.SetDest(nextvertex);
                        righttri.SetOrg(nextvertex);
                        righttri.SetDest(connectvertex);
                        lefttri.Bond(ref righttri);
                        lefttri.Lnext();
                        righttri.Lprev();
                        lefttri.Bond(ref righttri);
                        lefttri.Lnext();
                        righttri.Lprev();
                        lefttri.Bond(ref farlefttri);
                        righttri.Bond(ref farrighttri);
                        if (!farrightflag && farrighttri.Equal(bottommost))
                        {
                            lefttri.Copy(ref bottommost);
                        }

                        if (randomnation(SAMPLERATE) == 0)
                        {
                            splayroot = SplayInsert(splayroot, lefttri, nextvertex);
                        }
                        else if (randomnation(SAMPLERATE) == 0)
                        {
                            righttri.Lnext(ref inserttri);
                            splayroot = SplayInsert(splayroot, inserttri, nextvertex);
                        }
                    }
                }

                if (check4events)
                {
                    leftvertex  = farlefttri.Apex();
                    midvertex   = lefttri.Dest();
                    rightvertex = lefttri.Apex();
                    lefttest    = RobustPredicates.CounterClockwise(leftvertex, midvertex, rightvertex);
                    if (lefttest > 0.0)
                    {
                        newevent = new SweepEvent();

                        newevent.xkey      = xminextreme;
                        newevent.ykey      = CircleTop(leftvertex, midvertex, rightvertex, lefttest);
                        newevent.otriEvent = lefttri;
                        HeapInsert(eventheap, heapsize, newevent);
                        heapsize++;
                        lefttri.SetOrg(new SweepEventVertex(newevent));
                    }
                    leftvertex  = righttri.Apex();
                    midvertex   = righttri.Org();
                    rightvertex = farrighttri.Apex();
                    righttest   = RobustPredicates.CounterClockwise(leftvertex, midvertex, rightvertex);
                    if (righttest > 0.0)
                    {
                        newevent = new SweepEvent();

                        newevent.xkey      = xminextreme;
                        newevent.ykey      = CircleTop(leftvertex, midvertex, rightvertex, righttest);
                        newevent.otriEvent = farrighttri;
                        HeapInsert(eventheap, heapsize, newevent);
                        heapsize++;
                        farrighttri.SetOrg(new SweepEventVertex(newevent));
                    }
                }
            }

            splaynodes.Clear();
            bottommost.Lprev();

            mesh.hullsize = RemoveGhosts(ref bottommost);

            return(mesh);
        }
Пример #17
0
        private void ConstructBoundaryBvdCell(Vertex vertex)
        {
            Vertex        vertex1;
            Point         point;
            VoronoiRegion voronoiRegion = new VoronoiRegion(vertex);

            this.regions.Add(voronoiRegion);
            Otri         otri   = new Otri();
            Otri         otri1  = new Otri();
            Otri         otri2  = new Otri();
            Otri         otri3  = new Otri();
            Osub         item   = new Osub();
            Osub         osub   = new Osub();
            int          count  = this.mesh.triangles.Count;
            List <Point> points = new List <Point>();

            vertex.tri.Copy(ref otri1);
            if (otri1.Org() != vertex)
            {
                throw new Exception("ConstructBoundaryBvdCell: inconsistent topology.");
            }
            otri1.Copy(ref otri);
            otri1.Onext(ref otri2);
            otri1.Oprev(ref otri3);
            if (otri3.triangle != Mesh.dummytri)
            {
                while (otri3.triangle != Mesh.dummytri && !otri3.Equal(otri1))
                {
                    otri3.Copy(ref otri);
                    otri3.OprevSelf();
                }
                otri.Copy(ref otri1);
                otri.Onext(ref otri2);
            }
            if (otri3.triangle == Mesh.dummytri)
            {
                point = new Point(vertex.x, vertex.y)
                {
                    id = count + this.segIndex
                };
                this.points[count + this.segIndex] = point;
                this.segIndex = this.segIndex + 1;
                points.Add(point);
            }
            Vertex vertex2 = otri.Org();
            Vertex vertex3 = otri.Dest();

            point = new Point((vertex2.X + vertex3.X) / 2, (vertex2.Y + vertex3.Y) / 2)
            {
                id = count + this.segIndex
            };
            this.points[count + this.segIndex] = point;
            this.segIndex = this.segIndex + 1;
            points.Add(point);
            do
            {
                Point point1 = this.points[otri.triangle.id];
                if (otri2.triangle != Mesh.dummytri)
                {
                    Point point2 = this.points[otri2.triangle.id];
                    if (otri.triangle.infected)
                    {
                        item.seg = this.subsegMap[otri.triangle.hash];
                        Vertex vertex4 = item.SegOrg();
                        Vertex vertex5 = item.SegDest();
                        if (otri2.triangle.infected)
                        {
                            osub.seg = this.subsegMap[otri2.triangle.hash];
                            if (!item.Equal(osub))
                            {
                                if (this.SegmentsIntersect(vertex4, vertex5, point1, point2, out point, true))
                                {
                                    point.id = count + this.segIndex;
                                    this.points[count + this.segIndex] = point;
                                    this.segIndex = this.segIndex + 1;
                                    points.Add(point);
                                }
                                if (this.SegmentsIntersect(osub.SegOrg(), osub.SegDest(), point1, point2, out point, true))
                                {
                                    point.id = count + this.segIndex;
                                    this.points[count + this.segIndex] = point;
                                    this.segIndex = this.segIndex + 1;
                                    points.Add(point);
                                }
                            }
                            else if (this.SegmentsIntersect(vertex4, vertex5, new Point((vertex2.X + vertex3.X) / 2, (vertex2.Y + vertex3.Y) / 2), point2, out point, false))
                            {
                                point.id = count + this.segIndex;
                                this.points[count + this.segIndex] = point;
                                this.segIndex = this.segIndex + 1;
                                points.Add(point);
                            }
                        }
                        else
                        {
                            vertex3 = otri.Dest();
                            vertex1 = otri.Apex();
                            if (this.SegmentsIntersect(vertex4, vertex5, new Point((vertex3.X + vertex1.X) / 2, (vertex3.Y + vertex1.Y) / 2), point1, out point, false))
                            {
                                point.id = count + this.segIndex;
                                this.points[count + this.segIndex] = point;
                                this.segIndex = this.segIndex + 1;
                                points.Add(point);
                            }
                            if (this.SegmentsIntersect(vertex4, vertex5, point1, point2, out point, true))
                            {
                                point.id = count + this.segIndex;
                                this.points[count + this.segIndex] = point;
                                this.segIndex = this.segIndex + 1;
                                points.Add(point);
                            }
                        }
                    }
                    else
                    {
                        points.Add(point1);
                        if (otri2.triangle.infected)
                        {
                            osub.seg = this.subsegMap[otri2.triangle.hash];
                            if (this.SegmentsIntersect(osub.SegOrg(), osub.SegDest(), point1, point2, out point, true))
                            {
                                point.id = count + this.segIndex;
                                this.points[count + this.segIndex] = point;
                                this.segIndex = this.segIndex + 1;
                                points.Add(point);
                            }
                        }
                    }
                    otri2.Copy(ref otri);
                    otri2.OnextSelf();
                }
                else
                {
                    if (!otri.triangle.infected)
                    {
                        points.Add(point1);
                    }
                    vertex2 = otri.Org();
                    vertex1 = otri.Apex();
                    point   = new Point((vertex2.X + vertex1.X) / 2, (vertex2.Y + vertex1.Y) / 2)
                    {
                        id = count + this.segIndex
                    };
                    this.points[count + this.segIndex] = point;
                    this.segIndex = this.segIndex + 1;
                    points.Add(point);
                    break;
                }
            }while (!otri.Equal(otri1));
            voronoiRegion.Add(points);
        }
Пример #18
0
        private void ConstructBvdCell(Vertex vertex)
        {
            Point         point;
            VoronoiRegion voronoiRegion = new VoronoiRegion(vertex);

            this.regions.Add(voronoiRegion);
            Otri         otri   = new Otri();
            Otri         otri1  = new Otri();
            Otri         otri2  = new Otri();
            Osub         item   = new Osub();
            Osub         osub   = new Osub();
            int          count  = this.mesh.triangles.Count;
            List <Point> points = new List <Point>();

            vertex.tri.Copy(ref otri1);
            if (otri1.Org() != vertex)
            {
                throw new Exception("ConstructBvdCell: inconsistent topology.");
            }
            otri1.Copy(ref otri);
            otri1.Onext(ref otri2);
            do
            {
                Point point1 = this.points[otri.triangle.id];
                Point point2 = this.points[otri2.triangle.id];
                if (otri.triangle.infected)
                {
                    item.seg = this.subsegMap[otri.triangle.hash];
                    if (otri2.triangle.infected)
                    {
                        osub.seg = this.subsegMap[otri2.triangle.hash];
                        if (!item.Equal(osub))
                        {
                            if (this.SegmentsIntersect(item.SegOrg(), item.SegDest(), point1, point2, out point, true))
                            {
                                point.id = count + this.segIndex;
                                this.points[count + this.segIndex] = point;
                                this.segIndex = this.segIndex + 1;
                                points.Add(point);
                            }
                            if (this.SegmentsIntersect(osub.SegOrg(), osub.SegDest(), point1, point2, out point, true))
                            {
                                point.id = count + this.segIndex;
                                this.points[count + this.segIndex] = point;
                                this.segIndex = this.segIndex + 1;
                                points.Add(point);
                            }
                        }
                    }
                    else if (this.SegmentsIntersect(item.SegOrg(), item.SegDest(), point1, point2, out point, true))
                    {
                        point.id = count + this.segIndex;
                        this.points[count + this.segIndex] = point;
                        this.segIndex = this.segIndex + 1;
                        points.Add(point);
                    }
                }
                else
                {
                    points.Add(point1);
                    if (otri2.triangle.infected)
                    {
                        osub.seg = this.subsegMap[otri2.triangle.hash];
                        if (this.SegmentsIntersect(osub.SegOrg(), osub.SegDest(), point1, point2, out point, true))
                        {
                            point.id = count + this.segIndex;
                            this.points[count + this.segIndex] = point;
                            this.segIndex = this.segIndex + 1;
                            points.Add(point);
                        }
                    }
                }
                otri2.Copy(ref otri);
                otri2.OnextSelf();
            }while (!otri.Equal(otri1));
            voronoiRegion.Add(points);
        }
Пример #19
0
        /// <summary>
        /// Construct Voronoi region for given vertex.
        /// </summary>
        /// <param name="vertex"></param>
        /// <returns>The circumcenter indices which make up the cell.</returns>
        private void ConstructVoronoiRegion(Vertex vertex)
        {
            VoronoiRegion region = new VoronoiRegion(vertex);

            regions.Add(region);

            List <Point> vpoints = new List <Point>();

            Otri f      = default(Otri);
            Otri f_init = default(Otri);
            Otri f_next = default(Otri);
            Otri f_prev = default(Otri);

            Osub sub = default(Osub);

            // Call f_init a triangle incident to x
            vertex.tri.Copy(ref f_init);

            f_init.Copy(ref f);
            f_init.Onext(ref f_next);

            // Check if f_init lies on the boundary of the triangulation.
            if (f_next.triangle == Mesh.dummytri)
            {
                f_init.Oprev(ref f_prev);

                if (f_prev.triangle != Mesh.dummytri)
                {
                    f_init.Copy(ref f_next);
                    // Move one triangle clockwise
                    f_init.OprevSelf();
                    f_init.Copy(ref f);
                }
            }

            // Go counterclockwise until we reach the border or the initial triangle.
            while (f_next.triangle != Mesh.dummytri)
            {
                // Add circumcenter of current triangle
                vpoints.Add(points[f.triangle.id]);

                if (f_next.Equal(f_init))
                {
                    // Voronoi cell is complete (bounded case).
                    region.Add(vpoints);
                    return;
                }

                f_next.Copy(ref f);
                f_next.OnextSelf();
            }

            // Voronoi cell is unbounded
            region.Bounded = false;

            Vertex torg, tdest, tapex, intersection;
            int    sid, n = mesh.triangles.Count;

            // Find the boundary segment id.
            f.Lprev(ref f_next);
            f_next.SegPivot(ref sub);
            sid = sub.seg.hash;

            // Last valid f lies at the boundary. Add the circumcenter.
            vpoints.Add(points[f.triangle.id]);

            // Check if the intersection with the bounding box has already been computed.
            if (rayPoints.ContainsKey(sid))
            {
                vpoints.Add(rayPoints[sid]);
            }
            else
            {
                torg  = f.Org();
                tapex = f.Apex();
                BoxRayIntersection(points[f.triangle.id], torg.y - tapex.y, tapex.x - torg.x, out intersection);

                // Set the correct id for the vertex
                intersection.id = n + rayIndex;

                points[n + rayIndex] = intersection;

                rayIndex++;

                vpoints.Add(intersection);
                rayPoints.Add(sid, intersection);
            }

            // Now walk from f_init clockwise till we reach the boundary.
            vpoints.Reverse();

            f_init.Copy(ref f);
            f.Oprev(ref f_prev);

            while (f_prev.triangle != Mesh.dummytri)
            {
                vpoints.Add(points[f_prev.triangle.id]);

                f_prev.Copy(ref f);
                f_prev.OprevSelf();
            }

            // Find the boundary segment id.
            f.SegPivot(ref sub);
            sid = sub.seg.hash;

            if (rayPoints.ContainsKey(sid))
            {
                vpoints.Add(rayPoints[sid]);
            }
            else
            {
                // Intersection has not been computed yet.
                torg  = f.Org();
                tdest = f.Dest();

                BoxRayIntersection(points[f.triangle.id], tdest.y - torg.y, torg.x - tdest.x, out intersection);

                // Set the correct id for the vertex
                intersection.id = n + rayIndex;

                points[n + rayIndex] = intersection;

                rayIndex++;

                vpoints.Add(intersection);
                rayPoints.Add(sid, intersection);
            }

            // Add the new points to the region (in counter-clockwise order)
            vpoints.Reverse();
            region.Add(vpoints);
        }
Пример #20
0
        /// <summary>
        /// Remove the "infinite" bounding triangle, setting boundary markers as appropriate.
        /// </summary>
        /// <returns>Returns the number of edges on the convex hull of the triangulation.</returns>
        /// <remarks>
        /// The triangular bounding box has three boundary triangles (one for each
        /// side of the bounding box), and a bunch of triangles fanning out from
        /// the three bounding box vertices (one triangle for each edge of the
        /// convex hull of the inner mesh).  This routine removes these triangles.
        /// </remarks>
        int RemoveBox()
        {
            Otri   deadtriangle = default(Otri);
            Otri   searchedge = default(Otri);
            Otri   checkedge = default(Otri);
            Otri   nextedge = default(Otri), finaledge = default(Otri), dissolveedge = default(Otri);
            Vertex markorg;
            int    hullsize;

            bool noPoly = !mesh.behavior.Poly;

            // Find a boundary triangle.
            nextedge.triangle = Mesh.dummytri;
            nextedge.orient   = 0;
            nextedge.SymSelf();
            // Mark a place to stop.
            nextedge.Lprev(ref finaledge);
            nextedge.LnextSelf();
            nextedge.SymSelf();
            // Find a triangle (on the boundary of the vertex set) that isn't
            // a bounding box triangle.
            nextedge.Lprev(ref searchedge);
            searchedge.SymSelf();
            // Check whether nextedge is another boundary triangle
            // adjacent to the first one.
            nextedge.Lnext(ref checkedge);
            checkedge.SymSelf();
            if (checkedge.triangle == Mesh.dummytri)
            {
                // Go on to the next triangle.  There are only three boundary
                // triangles, and this next triangle cannot be the third one,
                // so it's safe to stop here.
                searchedge.LprevSelf();
                searchedge.SymSelf();
            }

            // Find a new boundary edge to search from, as the current search
            // edge lies on a bounding box triangle and will be deleted.
            Mesh.dummytri.neighbors[0] = searchedge;
            hullsize = -2;
            while (!nextedge.Equal(finaledge))
            {
                hullsize++;
                nextedge.Lprev(ref dissolveedge);
                dissolveedge.SymSelf();
                // If not using a PSLG, the vertices should be marked now.
                // (If using a PSLG, markhull() will do the job.)
                if (noPoly)
                {
                    // Be careful!  One must check for the case where all the input
                    // vertices are collinear, and thus all the triangles are part of
                    // the bounding box.  Otherwise, the setvertexmark() call below
                    // will cause a bad pointer reference.
                    if (dissolveedge.triangle != Mesh.dummytri)
                    {
                        markorg = dissolveedge.Org();
                        if (markorg.mark == 0)
                        {
                            markorg.mark = 1;
                        }
                    }
                }

                // Disconnect the bounding box triangle from the mesh triangle.
                dissolveedge.Dissolve();
                nextedge.Lnext(ref deadtriangle);
                deadtriangle.Sym(ref nextedge);
                // Get rid of the bounding box triangle.
                mesh.TriangleDealloc(deadtriangle.triangle);
                // Do we need to turn the corner?
                if (nextedge.triangle == Mesh.dummytri)
                {
                    // Turn the corner.
                    dissolveedge.Copy(ref nextedge);
                }
            }

            mesh.TriangleDealloc(finaledge.triangle);

            return(hullsize);
        }