/// <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)); }
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); }
/// <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)); }
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); }
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)); }
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); }
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); }
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); }
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)); }
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)); }
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); }
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(); }
/// <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(); }
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); }
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); }
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); }
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); }
/// <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); }
/// <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); }