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