diff --git a/Triangle.NET/Triangle/IO/FileProcessor.cs b/Triangle.NET/Triangle/IO/FileProcessor.cs index d8add9c..d2f1b70 100644 --- a/Triangle.NET/Triangle/IO/FileProcessor.cs +++ b/Triangle.NET/Triangle/IO/FileProcessor.cs @@ -73,6 +73,7 @@ namespace TriangleNet.IO if (format != null && format.IsSupported(filename)) { format.Write(polygon, filename); + return; } } @@ -113,6 +114,7 @@ namespace TriangleNet.IO if (format != null && format.IsSupported(filename)) { format.Write(mesh, filename); + return; } } diff --git a/Triangle.NET/Triangle/IO/TriangleWriter.cs b/Triangle.NET/Triangle/IO/TriangleWriter.cs index 2beaa48..acdb2f2 100644 --- a/Triangle.NET/Triangle/IO/TriangleWriter.cs +++ b/Triangle.NET/Triangle/IO/TriangleWriter.cs @@ -367,7 +367,7 @@ namespace TriangleNet.IO for (tri.orient = 0; tri.orient < 3; tri.orient++) { tri.Sym(ref trisym); - if ((tri.tri.id < trisym.tri.id) || (trisym.tri.id == Triangle.EmptyID)) + if ((tri.tri.id < trisym.tri.id) || (trisym.tri.id == Mesh.DUMMY)) { p1 = tri.Org(); p2 = tri.Dest(); @@ -380,7 +380,7 @@ namespace TriangleNet.IO { tri.Pivot(ref checkmark); - if (checkmark.seg == Segment.Empty) + if (checkmark.seg.hash == Mesh.DUMMY) { writer.WriteLine("{0} {1} {2} {3}", index, p1.id, p2.id, 0); } @@ -393,7 +393,7 @@ namespace TriangleNet.IO else { writer.WriteLine("{0} {1} {2} {3}", index, p1.id, p2.id, - trisym.tri.id == Triangle.EmptyID ? "1" : "0"); + trisym.tri.id == Mesh.DUMMY ? "1" : "0"); } } else @@ -522,12 +522,12 @@ namespace TriangleNet.IO for (tri.orient = 0; tri.orient < 3; tri.orient++) { tri.Sym(ref trisym); - if ((tri.tri.id < trisym.tri.id) || (trisym.tri.id == Triangle.EmptyID)) + if ((tri.tri.id < trisym.tri.id) || (trisym.tri.id == Mesh.DUMMY)) { // Find the number of this triangle (and Voronoi vertex). p1 = tri.tri.id; - if (trisym.tri.id == Triangle.EmptyID) + if (trisym.tri.id == Mesh.DUMMY) { torg = tri.Org(); tdest = tri.Dest(); diff --git a/Triangle.NET/Triangle/Mesh.cs b/Triangle.NET/Triangle/Mesh.cs index 19684ab..021208b 100644 --- a/Triangle.NET/Triangle/Mesh.cs +++ b/Triangle.NET/Triangle/Mesh.cs @@ -156,11 +156,75 @@ namespace TriangleNet #endregion + #region "Outer space" variables + + internal const int DUMMY = -1; + + // The triangle that fills "outer space," called 'dummytri', is pointed to + // by every triangle and subsegment on a boundary (be it outer or inner) of + // the triangulation. Also, 'dummytri' points to one of the triangles on + // the convex hull (until the holes and concavities are carved), making it + // possible to find a starting triangle for point location. + + // 'dummytri' and 'dummysub' are generally required to fulfill only a few + // invariants: their vertices must remain NULL and 'dummytri' must always + // be bonded (at offset zero) to some triangle on the convex hull of the + // mesh, via a boundary edge. Otherwise, the connections of 'dummytri' and + // 'dummysub' may change willy-nilly. This makes it possible to avoid + // writing a good deal of special-case code (in the edge flip, for example) + // for dealing with the boundary of the mesh, places where no subsegment is + // present, and so forth. Other entities are frequently bonded to + // 'dummytri' and 'dummysub' as if they were real mesh entities, with no + // harm done. + + internal Triangle dummytri; + + // Set up 'dummysub', the omnipresent subsegment pointed to by any + // triangle side or subsegment end that isn't attached to a real + // subsegment. + + internal Segment dummysub; + + private void Initialize() + { + dummysub = new Segment(); + dummysub.hash = DUMMY; + + // Initialize the two adjoining subsegments to be the omnipresent + // subsegment. These will eventually be changed by various bonding + // operations, but their values don't really matter, as long as they + // can legally be dereferenced. + dummysub.subsegs[0].seg = dummysub; + dummysub.subsegs[1].seg = dummysub; + + // Set up 'dummytri', the 'triangle' that occupies "outer space." + dummytri = new Triangle(); + dummytri.hash = dummytri.id = DUMMY; + + // Initialize the three adjoining triangles to be "outer space." These + // will eventually be changed by various bonding operations, but their + // values don't really matter, as long as they can legally be + // dereferenced. + dummytri.neighbors[0].tri = dummytri; + dummytri.neighbors[1].tri = dummytri; + dummytri.neighbors[2].tri = dummytri; + + // Initialize the three adjoining subsegments of 'dummytri' to be + // the omnipresent subsegment. + dummytri.subsegs[0].seg = dummysub; + dummytri.subsegs[1].seg = dummysub; + dummytri.subsegs[2].seg = dummysub; + } + + #endregion + /// /// Initializes a new instance of the class. /// public Mesh() { + Initialize(); + logger = Log.Instance; behavior = new Behavior(); @@ -590,8 +654,16 @@ namespace TriangleNet internal void MakeTriangle(ref Otri newotri) { Triangle tri = new Triangle(); - tri.hash = this.hash_tri++; - tri.id = tri.hash; + + tri.hash = tri.id = this.hash_tri++; + + tri.subsegs[0].seg = dummysub; + tri.subsegs[1].seg = dummysub; + tri.subsegs[2].seg = dummysub; + + tri.neighbors[0].tri = dummytri; + tri.neighbors[1].tri = dummytri; + tri.neighbors[2].tri = dummytri; newotri.tri = tri; newotri.orient = 0; @@ -606,8 +678,15 @@ namespace TriangleNet internal void MakeSegment(ref Osub newsubseg) { Segment seg = new Segment(); + seg.hash = this.hash_seg++; + seg.subsegs[0].seg = dummysub; + seg.subsegs[1].seg = dummysub; + + seg.triangles[0].tri = dummytri; + seg.triangles[1].tri = dummytri; + newsubseg.seg = seg; newsubseg.orient = 0; @@ -702,12 +781,13 @@ namespace TriangleNet { // Find the location of the vertex to be inserted. Check if a good // starting triangle has already been provided by the caller. - if (searchtri.tri.id == Triangle.EmptyID) + if (searchtri.tri.id == DUMMY) { // Find a boundary triangle. - horiz.tri = Triangle.Empty; + horiz.tri = dummytri; horiz.orient = 0; horiz.Sym(); + // Search for a triangle containing 'newvertex'. intersect = locator.Locate(newvertex, ref horiz); } @@ -741,7 +821,7 @@ namespace TriangleNet { // Check whether the vertex falls on a subsegment. horiz.Pivot(ref brokensubseg); - if (brokensubseg.seg != Segment.Empty) + if (brokensubseg.seg.hash != DUMMY) { // The vertex falls on a subsegment, and hence will not be inserted. if (segmentflaws) @@ -752,7 +832,7 @@ namespace TriangleNet // This subsegment may be split only if it is an // internal boundary. horiz.Sym(ref testtri); - enq = testtri.tri.id != Triangle.EmptyID; + enq = testtri.tri.id != DUMMY; } if (enq) { @@ -779,7 +859,7 @@ namespace TriangleNet botright.Sym(ref botrcasing); horiz.Sym(ref topright); // Is there a second triangle? (Or does this edge lie on a boundary?) - mirrorflag = topright.tri.id != Triangle.EmptyID; + mirrorflag = topright.tri.id != DUMMY; if (mirrorflag) { topright.Lnext(); @@ -835,18 +915,18 @@ namespace TriangleNet { botright.Pivot(ref botrsubseg); - if (botrsubseg.seg != Segment.Empty) + if (botrsubseg.seg.hash != DUMMY) { - botright.SegDissolve(); + botright.SegDissolve(dummysub); newbotright.SegBond(ref botrsubseg); } if (mirrorflag) { topright.Pivot(ref toprsubseg); - if (toprsubseg.seg != Segment.Empty) + if (toprsubseg.seg.hash != DUMMY) { - topright.SegDissolve(); + topright.SegDissolve(dummysub); newtopright.SegBond(ref toprsubseg); } } @@ -942,15 +1022,15 @@ namespace TriangleNet if (checksegments) { botleft.Pivot(ref botlsubseg); - if (botlsubseg.seg != Segment.Empty) + if (botlsubseg.seg.hash != DUMMY) { - botleft.SegDissolve(); + botleft.SegDissolve(dummysub); newbotleft.SegBond(ref botlsubseg); } botright.Pivot(ref botrsubseg); - if (botrsubseg.seg != Segment.Empty) + if (botrsubseg.seg.hash != DUMMY) { - botright.SegDissolve(); + botright.SegDissolve(dummysub); newbotright.SegBond(ref botrsubseg); } } @@ -992,7 +1072,7 @@ namespace TriangleNet { // Check for a subsegment, which cannot be flipped. horiz.Pivot(ref checksubseg); - if (checksubseg.seg != Segment.Empty) + if (checksubseg.seg.hash != DUMMY) { // The edge is a subsegment and cannot be flipped. doflip = false; @@ -1012,7 +1092,7 @@ namespace TriangleNet { // Check if the edge is a boundary edge. horiz.Sym(ref top); - if (top.tri.id == Triangle.EmptyID) + if (top.tri.id == DUMMY) { // The edge is a boundary edge and cannot be flipped. doflip = false; @@ -1083,33 +1163,33 @@ namespace TriangleNet botleft.Pivot(ref botlsubseg); botright.Pivot(ref botrsubseg); topright.Pivot(ref toprsubseg); - if (toplsubseg.seg == Segment.Empty) + if (toplsubseg.seg.hash == DUMMY) { - topright.SegDissolve(); + topright.SegDissolve(dummysub); } else { topright.SegBond(ref toplsubseg); } - if (botlsubseg.seg == Segment.Empty) + if (botlsubseg.seg.hash == DUMMY) { - topleft.SegDissolve(); + topleft.SegDissolve(dummysub); } else { topleft.SegBond(ref botlsubseg); } - if (botrsubseg.seg == Segment.Empty) + if (botrsubseg.seg.hash == DUMMY) { - botleft.SegDissolve(); + botleft.SegDissolve(dummysub); } else { botleft.SegBond(ref botrsubseg); } - if (toprsubseg.seg == Segment.Empty) + if (toprsubseg.seg.hash == DUMMY) { - botright.SegDissolve(); + botright.SegDissolve(dummysub); } else { @@ -1175,7 +1255,7 @@ namespace TriangleNet // Check for finishing a complete revolution about the new vertex, or // falling outside of the triangulation. The latter will happen when // a vertex is inserted at a boundary. - if ((leftvertex == first) || (testtri.tri.id == Triangle.EmptyID)) + if ((leftvertex == first) || (testtri.tri.id == DUMMY)) { // We're done. Return a triangle whose origin is the new vertex. horiz.Lnext(ref searchtri); @@ -1221,7 +1301,7 @@ namespace TriangleNet } // Check if there's already a subsegment here. tri.Pivot(ref newsubseg); - if (newsubseg.seg == Segment.Empty) + if (newsubseg.seg.hash == DUMMY) { // Make new subsegment and initialize its vertices. MakeSegment(ref newsubseg); @@ -1306,7 +1386,7 @@ namespace TriangleNet // SELF CHECK - //if (top.triangle.id == Triangle.EmptyID) + //if (top.triangle.id == DUMMY) //{ // logger.Error("Attempt to flip on boundary.", "Mesh.Flip()"); // flipedge.LnextSelf(); @@ -1349,36 +1429,36 @@ namespace TriangleNet botright.Pivot(ref botrsubseg); topright.Pivot(ref toprsubseg); - if (toplsubseg.seg == Segment.Empty) + if (toplsubseg.seg.hash == DUMMY) { - topright.SegDissolve(); + topright.SegDissolve(dummysub); } else { topright.SegBond(ref toplsubseg); } - if (botlsubseg.seg == Segment.Empty) + if (botlsubseg.seg.hash == DUMMY) { - topleft.SegDissolve(); + topleft.SegDissolve(dummysub); } else { topleft.SegBond(ref botlsubseg); } - if (botrsubseg.seg == Segment.Empty) + if (botrsubseg.seg.hash == DUMMY) { - botleft.SegDissolve(); + botleft.SegDissolve(dummysub); } else { botleft.SegBond(ref botrsubseg); } - if (toprsubseg.seg == Segment.Empty) + if (toprsubseg.seg.hash == DUMMY) { - botright.SegDissolve(); + botright.SegDissolve(dummysub); } else { @@ -1451,33 +1531,33 @@ namespace TriangleNet botleft.Pivot(ref botlsubseg); botright.Pivot(ref botrsubseg); topright.Pivot(ref toprsubseg); - if (toplsubseg.seg == Segment.Empty) + if (toplsubseg.seg.hash == DUMMY) { - botleft.SegDissolve(); + botleft.SegDissolve(dummysub); } else { botleft.SegBond(ref toplsubseg); } - if (botlsubseg.seg == Segment.Empty) + if (botlsubseg.seg.hash == DUMMY) { - botright.SegDissolve(); + botright.SegDissolve(dummysub); } else { botright.SegBond(ref botlsubseg); } - if (botrsubseg.seg == Segment.Empty) + if (botrsubseg.seg.hash == DUMMY) { - topright.SegDissolve(); + topright.SegDissolve(dummysub); } else { topright.SegBond(ref botrsubseg); } - if (toprsubseg.seg == Segment.Empty) + if (toprsubseg.seg.hash == DUMMY) { - topleft.SegDissolve(); + topleft.SegDissolve(dummysub); } else { @@ -1677,12 +1757,12 @@ namespace TriangleNet deltri.Bond(ref leftcasing); deltriright.Bond(ref rightcasing); lefttri.Pivot(ref leftsubseg); - if (leftsubseg.seg != Segment.Empty) + if (leftsubseg.seg.hash != DUMMY) { deltri.SegBond(ref leftsubseg); } righttri.Pivot(ref rightsubseg); - if (rightsubseg.seg != Segment.Empty) + if (rightsubseg.seg.hash != DUMMY) { deltriright.SegBond(ref rightsubseg); } @@ -1775,7 +1855,7 @@ namespace TriangleNet TriangleDealloc(botright.tri); fliptri.Sym(ref gluetri); - if (gluetri.tri.id != Triangle.EmptyID) + if (gluetri.tri.id != DUMMY) { gluetri.Lnext(); gluetri.Dnext(ref topright); diff --git a/Triangle.NET/Triangle/MeshValidator.cs b/Triangle.NET/Triangle/MeshValidator.cs index e990a9f..59c8dd8 100644 --- a/Triangle.NET/Triangle/MeshValidator.cs +++ b/Triangle.NET/Triangle/MeshValidator.cs @@ -50,7 +50,8 @@ namespace TriangleNet { if (Log.Verbose) { - logger.Warning("Triangle is flat or inverted.", "MeshValidator.IsConsistent()"); + logger.Warning(String.Format("Triangle is flat or inverted (ID {0}).", t.id), + "MeshValidator.IsConsistent()"); } horrors++; @@ -59,7 +60,7 @@ namespace TriangleNet // Find the neighboring triangle on this edge. tri.Sym(ref oppotri); - if (oppotri.tri.id != Triangle.EmptyID) + if (oppotri.tri.id != Mesh.DUMMY) { // Check that the triangle's neighbor knows it's a neighbor. oppotri.Sym(ref oppooppotri); @@ -168,7 +169,7 @@ namespace TriangleNet // adjoining triangle whose pointer is larger (to ensure that // each pair isn't tested twice). shouldbedelaunay = (loop.tri.id < oppotri.tri.id) && - !Otri.IsDead(oppotri.tri) && (oppotri.tri.id != Triangle.EmptyID) && + !Otri.IsDead(oppotri.tri) && (oppotri.tri.id != Mesh.DUMMY) && (org != inf1) && (org != inf2) && (org != inf3) && (dest != inf1) && (dest != inf2) && (dest != inf3) && (apex != inf1) && (apex != inf2) && (apex != inf3) && @@ -180,7 +181,7 @@ namespace TriangleNet // constrained, so no local Delaunay test should be done. loop.Pivot(ref opposubseg); - if (opposubseg.seg != Segment.Empty) + if (opposubseg.seg.hash != Mesh.DUMMY) { shouldbedelaunay = false; } diff --git a/Triangle.NET/Triangle/Meshing/Algorithm/Dwyer.cs b/Triangle.NET/Triangle/Meshing/Algorithm/Dwyer.cs index 7338901..1a0da2a 100644 --- a/Triangle.NET/Triangle/Meshing/Algorithm/Dwyer.cs +++ b/Triangle.NET/Triangle/Meshing/Algorithm/Dwyer.cs @@ -860,7 +860,8 @@ namespace TriangleNet.Meshing.Algorithm // Find an edge on the convex hull to start point location from. startghost.Lprev(ref searchedge); searchedge.Sym(); - Triangle.Empty.neighbors[0] = searchedge; + mesh.dummytri.neighbors[0] = searchedge; + // Remove the bounding box and count the convex hull edges. startghost.Copy(ref dissolveedge); hullsize = 0; @@ -876,7 +877,7 @@ namespace TriangleNet.Meshing.Algorithm if (noPoly) { // Watch out for the case where all the input vertices are collinear. - if (dissolveedge.tri.id != Triangle.EmptyID) + if (dissolveedge.tri.id != Mesh.DUMMY) { markorg = dissolveedge.Org(); if (markorg.mark == 0) @@ -886,7 +887,7 @@ namespace TriangleNet.Meshing.Algorithm } } // Remove a bounding triangle from a convex hull triangle. - dissolveedge.Dissolve(); + dissolveedge.Dissolve(mesh.dummytri); // Find the next bounding triangle. deadtriangle.Sym(ref dissolveedge); diff --git a/Triangle.NET/Triangle/Meshing/Algorithm/Incremental.cs b/Triangle.NET/Triangle/Meshing/Algorithm/Incremental.cs index 4b6cf6f..d03527f 100644 --- a/Triangle.NET/Triangle/Meshing/Algorithm/Incremental.cs +++ b/Triangle.NET/Triangle/Meshing/Algorithm/Incremental.cs @@ -35,7 +35,7 @@ namespace TriangleNet.Meshing.Algorithm foreach (var v in mesh.vertices.Values) { - starttri.tri = Triangle.Empty; + starttri.tri = mesh.dummytri; Osub tmp = default(Osub); if (mesh.InsertVertex(v, ref starttri, ref tmp, false, false) == InsertVertexResult.Duplicate) { @@ -85,12 +85,14 @@ namespace TriangleNet.Meshing.Algorithm // Create the bounding box. mesh.MakeTriangle(ref inftri); + inftri.SetOrg(mesh.infvertex1); inftri.SetDest(mesh.infvertex2); inftri.SetApex(mesh.infvertex3); + // Link dummytri to the bounding box so we can always find an // edge to begin searching (point location) from. - Triangle.Empty.neighbors[0] = inftri; + mesh.dummytri.neighbors[0] = inftri; } /// @@ -115,9 +117,10 @@ namespace TriangleNet.Meshing.Algorithm bool noPoly = !mesh.behavior.Poly; // Find a boundary triangle. - nextedge.tri = Triangle.Empty; + nextedge.tri = mesh.dummytri; nextedge.orient = 0; nextedge.Sym(); + // Mark a place to stop. nextedge.Lprev(ref finaledge); nextedge.Lnext(); @@ -130,7 +133,7 @@ namespace TriangleNet.Meshing.Algorithm // adjacent to the first one. nextedge.Lnext(ref checkedge); checkedge.Sym(); - if (checkedge.tri.id == Triangle.EmptyID) + if (checkedge.tri.id == Mesh.DUMMY) { // Go on to the next triangle. There are only three boundary // triangles, and this next triangle cannot be the third one, @@ -138,9 +141,11 @@ namespace TriangleNet.Meshing.Algorithm searchedge.Lprev(); searchedge.Sym(); } + // Find a new boundary edge to search from, as the current search // edge lies on a bounding box triangle and will be deleted. - Triangle.Empty.neighbors[0] = searchedge; + mesh.dummytri.neighbors[0] = searchedge; + hullsize = -2; while (!nextedge.Equal(finaledge)) { @@ -155,7 +160,7 @@ namespace TriangleNet.Meshing.Algorithm // 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.tri.id != Triangle.EmptyID) + if (dissolveedge.tri.id != Mesh.DUMMY) { markorg = dissolveedge.Org(); if (markorg.mark == 0) @@ -165,18 +170,19 @@ namespace TriangleNet.Meshing.Algorithm } } // Disconnect the bounding box triangle from the mesh triangle. - dissolveedge.Dissolve(); + dissolveedge.Dissolve(mesh.dummytri); nextedge.Lnext(ref deadtriangle); deadtriangle.Sym(ref nextedge); // Get rid of the bounding box triangle. mesh.TriangleDealloc(deadtriangle.tri); // Do we need to turn the corner? - if (nextedge.tri.id == Triangle.EmptyID) + if (nextedge.tri.id == Mesh.DUMMY) { // Turn the corner. dissolveedge.Copy(ref nextedge); } } + mesh.TriangleDealloc(finaledge.tri); return hullsize; diff --git a/Triangle.NET/Triangle/Meshing/Algorithm/SweepLine.cs b/Triangle.NET/Triangle/Meshing/Algorithm/SweepLine.cs index b8b3fe7..1ff2c2f 100644 --- a/Triangle.NET/Triangle/Meshing/Algorithm/SweepLine.cs +++ b/Triangle.NET/Triangle/Meshing/Algorithm/SweepLine.cs @@ -698,10 +698,12 @@ namespace TriangleNet.Meshing.Algorithm bool noPoly = !mesh.behavior.Poly; + var dummytri = mesh.dummytri; + // Find an edge on the convex hull to start point location from. startghost.Lprev(ref searchedge); searchedge.Sym(); - Triangle.Empty.neighbors[0] = searchedge; + dummytri.neighbors[0] = searchedge; // Remove the bounding box and count the convex hull edges. startghost.Copy(ref dissolveedge); hullsize = 0; @@ -717,7 +719,7 @@ namespace TriangleNet.Meshing.Algorithm if (noPoly) { // Watch out for the case where all the input vertices are collinear. - if (dissolveedge.tri.id != Triangle.EmptyID) + if (dissolveedge.tri.id != Mesh.DUMMY) { markorg = dissolveedge.Org(); if (markorg.mark == 0) @@ -727,7 +729,7 @@ namespace TriangleNet.Meshing.Algorithm } } // Remove a bounding triangle from a convex hull triangle. - dissolveedge.Dissolve(); + dissolveedge.Dissolve(dummytri); // Find the next bounding triangle. deadtriangle.Sym(ref dissolveedge); diff --git a/Triangle.NET/Triangle/Meshing/ConstraintMesher.cs b/Triangle.NET/Triangle/Meshing/ConstraintMesher.cs index 5a3f1b9..9d2dc92 100644 --- a/Triangle.NET/Triangle/Meshing/ConstraintMesher.cs +++ b/Triangle.NET/Triangle/Meshing/ConstraintMesher.cs @@ -48,6 +48,8 @@ namespace TriangleNet.Meshing Triangle[] regionTris = null; + var dummytri = mesh.dummytri; + if (!mesh.behavior.Convex) { // Mark as infected any unprotected triangles on the boundary. @@ -64,7 +66,7 @@ namespace TriangleNet.Meshing if (mesh.bounds.Contains(hole)) { // Start searching from some triangle on the outer boundary. - searchtri.tri = Triangle.Empty; + searchtri.tri = dummytri; searchtri.orient = 0; searchtri.Sym(); // Ensure that the hole is to the left of this boundary edge; @@ -101,12 +103,12 @@ namespace TriangleNet.Meshing // Find the starting triangle for each region. foreach (var region in mesh.regions) { - regionTris[i] = Triangle.Empty; + regionTris[i] = dummytri; // Ignore region points that aren't within the bounds of the mesh. if (mesh.bounds.Contains(region.point)) { // Start searching from some triangle on the outer boundary. - searchtri.tri = Triangle.Empty; + searchtri.tri = dummytri; searchtri.orient = 0; searchtri.Sym(); // Ensure that the region point is to the left of this boundary @@ -144,7 +146,7 @@ namespace TriangleNet.Meshing for (int i = 0; i < regionTris.Length; i++) { - if (regionTris[i].id != Triangle.EmptyID) + if (regionTris[i].id != Mesh.DUMMY) { // Make sure the triangle under consideration still exists. // It may have been eaten by the virus. @@ -260,10 +262,14 @@ namespace TriangleNet.Meshing Osub hullsubseg = default(Osub); Vertex horg, hdest; + var dummytri = mesh.dummytri; + var dummysub = mesh.dummysub; + // Find a triangle handle on the hull. - hulltri.tri = Triangle.Empty; + hulltri.tri = 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. @@ -274,7 +280,7 @@ namespace TriangleNet.Meshing { // Is the triangle protected by a subsegment? hulltri.Pivot(ref hullsubseg); - if (hullsubseg.seg == Segment.Empty) + if (hullsubseg.seg.hash == Mesh.DUMMY) { // The triangle is not protected; infect it. if (!hulltri.IsInfected()) @@ -305,7 +311,7 @@ namespace TriangleNet.Meshing // To find the next hull edge, go clockwise around the next vertex. hulltri.Lnext(); hulltri.Oprev(ref nexttri); - while (nexttri.tri.id != Triangle.EmptyID) + while (nexttri.tri.id != Mesh.DUMMY) { nexttri.Copy(ref hulltri); hulltri.Oprev(ref nexttri); @@ -337,6 +343,9 @@ namespace TriangleNet.Meshing Vertex testvertex; Vertex norg, ndest; + var dummysub = mesh.dummysub; + var dummytri = mesh.dummytri; + bool killorg; // Loop through all the infected triangles, spreading the virus to @@ -361,27 +370,27 @@ namespace TriangleNet.Meshing // Check for a subsegment between the triangle and its neighbor. testtri.Pivot(ref neighborsubseg); // Check if the neighbor is nonexistent or already infected. - if ((neighbor.tri.id == Triangle.EmptyID) || neighbor.IsInfected()) + if ((neighbor.tri.id == Mesh.DUMMY) || neighbor.IsInfected()) { - if (neighborsubseg.seg != Segment.Empty) + if (neighborsubseg.seg.hash != Mesh.DUMMY) { // 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.tri.id != Triangle.EmptyID) + if (neighbor.tri.id != Mesh.DUMMY) { // Make sure the subsegment doesn't get deallocated again // later when the infected neighbor is visited. neighbor.Uninfect(); - neighbor.SegDissolve(); + neighbor.SegDissolve(dummysub); neighbor.Infect(); } } } else { // The neighbor exists and is not infected. - if (neighborsubseg.seg == Segment.Empty) + if (neighborsubseg.seg.hash == Mesh.DUMMY) { // There is no subsegment protecting the neighbor, so // the neighbor becomes infected. @@ -393,7 +402,7 @@ namespace TriangleNet.Meshing { // The neighbor is protected by a subsegment. // Remove this triangle from the subsegment. - neighborsubseg.TriDissolve(); + neighborsubseg.TriDissolve(dummytri); // The subsegment becomes a boundary. Set markers accordingly. if (neighborsubseg.seg.boundary == 0) { @@ -436,7 +445,7 @@ namespace TriangleNet.Meshing // Walk counterclockwise about the vertex. testtri.Onext(ref neighbor); // Stop upon reaching a boundary or the starting triangle. - while ((neighbor.tri.id != Triangle.EmptyID) && + while ((neighbor.tri.id != Mesh.DUMMY) && (!neighbor.Equal(testtri))) { if (neighbor.IsInfected()) @@ -453,12 +462,12 @@ namespace TriangleNet.Meshing neighbor.Onext(); } // If we reached a boundary, we must walk clockwise as well. - if (neighbor.tri.id == Triangle.EmptyID) + if (neighbor.tri.id == Mesh.DUMMY) { // Walk clockwise about the vertex. testtri.Oprev(ref neighbor); // Stop upon reaching a boundary. - while (neighbor.tri.id != Triangle.EmptyID) + while (neighbor.tri.id != Mesh.DUMMY) { if (neighbor.IsInfected()) { @@ -488,7 +497,7 @@ namespace TriangleNet.Meshing for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { testtri.Sym(ref neighbor); - if (neighbor.tri.id == Triangle.EmptyID) + if (neighbor.tri.id == Mesh.DUMMY) { // There is no neighboring triangle on this edge, so this edge // is a boundary edge. This triangle is being deleted, so this @@ -498,7 +507,7 @@ namespace TriangleNet.Meshing else { // Disconnect the triangle from its neighbor. - neighbor.Dissolve(); + neighbor.Dissolve(dummytri); // There is a neighboring triangle on this edge, so this edge // becomes a boundary edge when this triangle is deleted. mesh.hullsize++; @@ -554,7 +563,7 @@ namespace TriangleNet.Meshing // 'searchtri' faces directly away from 'searchpoint'. We could go left // or right. Ask whether it's a triangle or a boundary on the left. searchtri.Onext(ref checktri); - if (checktri.tri.id == Triangle.EmptyID) + if (checktri.tri.id == Mesh.DUMMY) { leftflag = false; } @@ -567,7 +576,7 @@ namespace TriangleNet.Meshing { // Turn left until satisfied. searchtri.Onext(); - if (searchtri.tri.id == Triangle.EmptyID) + if (searchtri.tri.id == Mesh.DUMMY) { logger.Error("Unable to find a triangle on path.", "Mesh.FindDirection().1"); throw new Exception("Unable to find a triangle on path."); @@ -581,7 +590,7 @@ namespace TriangleNet.Meshing { // Turn right until satisfied. searchtri.Oprev(); - if (searchtri.tri.id == Triangle.EmptyID) + if (searchtri.tri.id == Mesh.DUMMY) { logger.Error("Unable to find a triangle on path.", "Mesh.FindDirection().2"); throw new Exception("Unable to find a triangle on path."); @@ -630,6 +639,8 @@ namespace TriangleNet.Meshing Vertex newvertex; InsertVertexResult success; + var dummysub = mesh.dummysub; + double ex, ey; double tx, ty; double etx, ety; @@ -690,18 +701,18 @@ namespace TriangleNet.Meshing // Divide the segment into two, and correct the segment endpoints. splitsubseg.Sym(); splitsubseg.Pivot(ref opposubseg); - splitsubseg.Dissolve(); - opposubseg.Dissolve(); + splitsubseg.Dissolve(dummysub); + opposubseg.Dissolve(dummysub); do { splitsubseg.SetSegOrg(newvertex); splitsubseg.Next(); - } while (splitsubseg.seg != Segment.Empty); + } while (splitsubseg.seg.hash != Mesh.DUMMY); do { opposubseg.SetSegOrg(newvertex); opposubseg.Next(); - } while (opposubseg.seg != Segment.Empty); + } while (opposubseg.seg.hash != Mesh.DUMMY); // Inserting the vertex may have caused edge flips. We wish to rediscover // the edge connecting endpoint1 to the new intersection vertex. @@ -789,7 +800,7 @@ namespace TriangleNet.Meshing searchtri.Lnext(ref crosstri); crosstri.Pivot(ref crosssubseg); // Check for a crossing segment. - if (crosssubseg.seg == Segment.Empty) + if (crosssubseg.seg.hash == Mesh.DUMMY) { return false; } @@ -850,12 +861,12 @@ namespace TriangleNet.Meshing fixuptri.Lnext(ref neartri); neartri.Sym(ref fartri); // Check if the edge opposite the origin of fixuptri can be flipped. - if (fartri.tri.id == Triangle.EmptyID) + if (fartri.tri.id == Mesh.DUMMY) { return; } neartri.Pivot(ref faredge); - if (faredge.seg != Segment.Empty) + if (faredge.seg.hash != Mesh.DUMMY) { return; } @@ -1027,7 +1038,7 @@ namespace TriangleNet.Meshing } // Check for two intersecting segments. fixuptri.Pivot(ref crosssubseg); - if (crosssubseg.seg == Segment.Empty) + if (crosssubseg.seg.hash == Mesh.DUMMY) { mesh.Flip(ref fixuptri); // May create inverted triangle at left. } @@ -1067,6 +1078,8 @@ namespace TriangleNet.Meshing Otri searchtri1 = default(Otri), searchtri2 = default(Otri); Vertex checkvertex = null; + var dummytri = mesh.dummytri; + // Find a triangle whose origin is the segment's first endpoint. searchtri1 = endpoint1.tri; if (searchtri1.tri != null) @@ -1077,7 +1090,7 @@ namespace TriangleNet.Meshing if (checkvertex != endpoint1) { // Find a boundary triangle to search from. - searchtri1.tri = Triangle.Empty; + searchtri1.tri = dummytri; searchtri1.orient = 0; searchtri1.Sym(); // Search for the segment's first endpoint by point location. @@ -1111,7 +1124,7 @@ namespace TriangleNet.Meshing if (checkvertex != endpoint2) { // Find a boundary triangle to search from. - searchtri2.tri = Triangle.Empty; + searchtri2.tri = dummytri; searchtri2.orient = 0; searchtri2.Sym(); // Search for the segment's second endpoint by point location. @@ -1148,7 +1161,7 @@ namespace TriangleNet.Meshing Otri starttri = default(Otri); // Find a triangle handle on the hull. - hulltri.tri = Triangle.Empty; + hulltri.tri = mesh.dummytri; hulltri.orient = 0; hulltri.Sym(); // Remember where we started so we know when to stop. @@ -1161,7 +1174,7 @@ namespace TriangleNet.Meshing // To find the next hull edge, go clockwise around the next vertex. hulltri.Lnext(); hulltri.Oprev(ref nexttri); - while (nexttri.tri.id != Triangle.EmptyID) + while (nexttri.tri.id != Mesh.DUMMY) { nexttri.Copy(ref hulltri); hulltri.Oprev(ref nexttri); diff --git a/Triangle.NET/Triangle/Meshing/Converter.cs b/Triangle.NET/Triangle/Meshing/Converter.cs index 6e286ef..34b9370 100644 --- a/Triangle.NET/Triangle/Meshing/Converter.cs +++ b/Triangle.NET/Triangle/Meshing/Converter.cs @@ -106,7 +106,7 @@ namespace TriangleNet.Meshing for (i = 0; i < mesh.vertices.Count; i++) { Otri tmp = default(Otri); - tmp.tri = Triangle.Empty; + tmp.tri = mesh.dummytri; vertexarray[i] = new List(3); vertexarray[i].Add(tmp); } @@ -164,7 +164,7 @@ namespace TriangleNet.Meshing checktri = nexttri; - if (checktri.tri.id != Triangle.EmptyID) + if (checktri.tri.id != Mesh.DUMMY) { tdest = tri.Dest(); tapex = tri.Apex(); @@ -192,7 +192,7 @@ namespace TriangleNet.Meshing nexttri = vertexarray[aroundvertex][index]; checktri = nexttri; - } while (checktri.tri.id != Triangle.EmptyID); + } while (checktri.tri.id != Mesh.DUMMY); } } @@ -276,7 +276,7 @@ namespace TriangleNet.Meshing // occurrence of a triangle on a list can (and does) represent // an edge. In this way, most edges are represented twice, and // every triangle-subsegment bond is represented once. - while (notfound && (checktri.tri.id != Triangle.EmptyID)) + while (notfound && (checktri.tri.id != Mesh.DUMMY)) { checkdest = checktri.Dest(); @@ -289,7 +289,7 @@ namespace TriangleNet.Meshing checktri.SegBond(ref subseg); // Check if this is a boundary edge. checktri.Sym(ref checkneighbor); - if (checkneighbor.tri.id == Triangle.EmptyID) + if (checkneighbor.tri.id == Mesh.DUMMY) { // The next line doesn't insert a subsegment (because there's // already one there), but it sets the boundary markers of @@ -321,16 +321,16 @@ namespace TriangleNet.Meshing nexttri = vertexarray[i][index]; checktri = nexttri; - while (checktri.tri.id != Triangle.EmptyID) + while (checktri.tri.id != Mesh.DUMMY) { // Find the next triangle in the stack before this // information gets overwritten. index--; nexttri = vertexarray[i][index]; // No adjacent subsegment. (This overwrites the stack info.) - checktri.SegDissolve(); + checktri.SegDissolve(mesh.dummysub); checktri.Sym(ref checkneighbor); - if (checkneighbor.tri.id == Triangle.EmptyID) + if (checkneighbor.tri.id == Mesh.DUMMY) { mesh.InsertSubseg(ref checktri, 1); hullsize++; diff --git a/Triangle.NET/Triangle/Meshing/Iterators/EdgeIterator.cs b/Triangle.NET/Triangle/Meshing/Iterators/EdgeIterator.cs index b8b7c09..ebacb1a 100644 --- a/Triangle.NET/Triangle/Meshing/Iterators/EdgeIterator.cs +++ b/Triangle.NET/Triangle/Meshing/Iterators/EdgeIterator.cs @@ -76,7 +76,7 @@ namespace TriangleNet.Meshing.Iterators tri.Sym(ref neighbor); - if ((tri.tri.id < neighbor.tri.id) || (neighbor.tri.id == Triangle.EmptyID)) + if ((tri.tri.id < neighbor.tri.id) || (neighbor.tri.id == Mesh.DUMMY)) { p1 = tri.Org(); p2 = tri.Dest(); diff --git a/Triangle.NET/Triangle/Meshing/Iterators/RegionIterator.cs b/Triangle.NET/Triangle/Meshing/Iterators/RegionIterator.cs index e1f1cb1..d2edeb1 100644 --- a/Triangle.NET/Triangle/Meshing/Iterators/RegionIterator.cs +++ b/Triangle.NET/Triangle/Meshing/Iterators/RegionIterator.cs @@ -66,8 +66,8 @@ namespace TriangleNet.Meshing.Iterators testtri.Pivot(ref neighborsubseg); // Make sure the neighbor exists, is not already infected, and // isn't protected by a subsegment. - if ((neighbor.tri.id != Triangle.EmptyID) && !neighbor.IsInfected() - && (neighborsubseg.seg == Segment.Empty)) + if ((neighbor.tri.id != Mesh.DUMMY) && !neighbor.IsInfected() + && (neighborsubseg.seg.hash == Mesh.DUMMY)) { // Infect the neighbor. neighbor.Infect(); @@ -104,7 +104,7 @@ namespace TriangleNet.Meshing.Iterators /// public void Process(Triangle triangle, Action func) { - if (triangle.id != Triangle.EmptyID) + if (triangle.id != Mesh.DUMMY) { // Make sure the triangle under consideration still exists. // It may have been eaten by the virus. diff --git a/Triangle.NET/Triangle/Meshing/QualityMesher.cs b/Triangle.NET/Triangle/Meshing/QualityMesher.cs index 6b4984c..00625eb 100644 --- a/Triangle.NET/Triangle/Meshing/QualityMesher.cs +++ b/Triangle.NET/Triangle/Meshing/QualityMesher.cs @@ -90,7 +90,7 @@ namespace TriangleNet.Meshing // Check one neighbor of the subsegment. testsubseg.Pivot(ref neighbortri); // Does the neighbor exist, or is this a boundary edge? - if (neighbortri.tri.id != Triangle.EmptyID) + if (neighbortri.tri.id != Mesh.DUMMY) { sides++; // Find a vertex opposite this subsegment. @@ -120,7 +120,7 @@ namespace TriangleNet.Meshing testsubseg.Sym(ref testsym); testsym.Pivot(ref neighbortri); // Does the neighbor exist, or is this a boundary edge? - if (neighbortri.tri.id != Triangle.EmptyID) + if (neighbortri.tri.id != Mesh.DUMMY) { sides++; // Find the other vertex opposite this subsegment. @@ -319,7 +319,7 @@ namespace TriangleNet.Meshing // Check if both points lie in a common segment. If they do, the // skinny triangle is enqueued to be split as usual. tri1.Pivot(ref testsub); - if (testsub.seg == Segment.Empty) + if (testsub.seg.hash == Mesh.DUMMY) { // No common segment. Find a subsegment that contains 'torg'. tri1.Copy(ref tri2); @@ -327,7 +327,7 @@ namespace TriangleNet.Meshing { tri1.Oprev(); tri1.Pivot(ref testsub); - } while (testsub.seg == Segment.Empty); + } while (testsub.seg.hash == Mesh.DUMMY); // Find the endpoints of the containing segment. org1 = testsub.SegOrg(); dest1 = testsub.SegDest(); @@ -336,7 +336,7 @@ namespace TriangleNet.Meshing { tri2.Dnext(); tri2.Pivot(ref testsub); - } while (testsub.seg == Segment.Empty); + } while (testsub.seg.hash == Mesh.DUMMY); // Find the endpoints of the containing segment. org2 = testsub.SegOrg(); dest2 = testsub.SegDest(); @@ -459,11 +459,11 @@ namespace TriangleNet.Meshing currentenc.Pivot(ref enctri); enctri.Lnext(ref testtri); testtri.Pivot(ref testsh); - acuteorg = testsh.seg != Segment.Empty; + acuteorg = testsh.seg.hash != Mesh.DUMMY; // Is the destination shared with another segment? testtri.Lnext(); testtri.Pivot(ref testsh); - acutedest = testsh.seg != Segment.Empty; + acutedest = testsh.seg.hash != Mesh.DUMMY; // If we're using Chew's algorithm (rather than Ruppert's) // to define encroachment, delete free vertices from the @@ -484,17 +484,17 @@ namespace TriangleNet.Meshing // Now, check the other side of the segment, if there's a triangle there. enctri.Sym(ref testtri); - if (testtri.tri.id != Triangle.EmptyID) + if (testtri.tri.id != Mesh.DUMMY) { // Is the destination shared with another segment? testtri.Lnext(); testtri.Pivot(ref testsh); - acutedest2 = testsh.seg != Segment.Empty; + acutedest2 = testsh.seg.hash != Mesh.DUMMY; acutedest = acutedest || acutedest2; // Is the origin shared with another segment? testtri.Lnext(); testtri.Pivot(ref testsh); - acuteorg2 = testsh.seg != Segment.Empty; + acuteorg2 = testsh.seg.hash != Mesh.DUMMY; acuteorg = acuteorg || acuteorg2; // Delete free vertices from the subsegment's diametral circle. diff --git a/Triangle.NET/Triangle/NewLocation.cs b/Triangle.NET/Triangle/NewLocation.cs index 0315424..68138a0 100644 --- a/Triangle.NET/Triangle/NewLocation.cs +++ b/Triangle.NET/Triangle/NewLocation.cs @@ -2364,7 +2364,7 @@ namespace TriangleNet badotri.Sym(ref neighbor); // check if it is the one we are looking for by checking the corners // first check if the neighbor is nonexistent, since it can be on the border - if (neighbor.tri.id != Triangle.EmptyID) + if (neighbor.tri.id != Mesh.DUMMY) { // then check if two wanted corners are also in this triangle // take the vertices of the candidate neighbor diff --git a/Triangle.NET/Triangle/Sampler.cs b/Triangle.NET/Triangle/Sampler.cs index aaa4de3..bc94aca 100644 --- a/Triangle.NET/Triangle/Sampler.cs +++ b/Triangle.NET/Triangle/Sampler.cs @@ -16,19 +16,24 @@ namespace TriangleNet /// class Sampler { - static Random rand = new Random(DateTime.Now.Millisecond); + // Empirically chosen factor. + private const int samplefactor = 11; + + private Random rand; // Number of random samples for point location (at least 1). - int samples = 1; + private int samples = 1; // Number of triangles in mesh. - int triangleCount = 0; - - // Empirically chosen factor. - static int samplefactor = 11; + private int triangleCount = 0; // Keys of the triangle dictionary. - int[] keys; + private int[] keys; + + public Sampler() + { + this.rand = new Random(110503); + } /// /// Reset the sampler. diff --git a/Triangle.NET/Triangle/Topology/DCEL/Face.cs b/Triangle.NET/Triangle/Topology/DCEL/Face.cs index 14b4217..76cb6a7 100644 --- a/Triangle.NET/Triangle/Topology/DCEL/Face.cs +++ b/Triangle.NET/Triangle/Topology/DCEL/Face.cs @@ -79,11 +79,16 @@ namespace TriangleNet.Topology.DCEL this.generator = generator; this.edge = edge; this.bounded = true; + + if (generator != null) + { + this.id = generator.ID; + } } public override string ToString() { - return string.Format("F-ID {0}", generator == null ? id : generator.id); + return string.Format("F-ID {0}", id); } } } diff --git a/Triangle.NET/Triangle/Topology/Osub.cs b/Triangle.NET/Triangle/Topology/Osub.cs index 640b5aa..3a82522 100644 --- a/Triangle.NET/Triangle/Topology/Osub.cs +++ b/Triangle.NET/Triangle/Topology/Osub.cs @@ -213,9 +213,9 @@ namespace TriangleNet.Topology /// /// Note that the other subsegment will still think it's /// connected to this subsegment. - internal void Dissolve() + internal void Dissolve(Segment dummy) { - seg.subsegs[orient].seg = Segment.Empty; + seg.subsegs[orient].seg = dummy; } /// @@ -229,9 +229,9 @@ namespace TriangleNet.Topology /// /// Dissolve a bond (from the subsegment side). /// - internal void TriDissolve() + internal void TriDissolve(Triangle dummy) { - seg.triangles[orient].tri = Triangle.Empty; + seg.triangles[orient].tri = dummy; } /// diff --git a/Triangle.NET/Triangle/Topology/Otri.cs b/Triangle.NET/Triangle/Topology/Otri.cs index 6a193b0..51544f8 100644 --- a/Triangle.NET/Triangle/Topology/Otri.cs +++ b/Triangle.NET/Triangle/Topology/Otri.cs @@ -396,9 +396,9 @@ namespace TriangleNet.Topology /// this triangle. Usually, however, the other triangle is being deleted /// entirely, or bonded to another triangle, so it doesn't matter. /// - internal void Dissolve() + internal void Dissolve(Triangle dummy) { - tri.neighbors[orient].tri = Triangle.Empty; + tri.neighbors[orient].tri = dummy; tri.neighbors[orient].orient = 0; } @@ -454,9 +454,9 @@ namespace TriangleNet.Topology /// /// Dissolve a bond (from the triangle side). /// - internal void SegDissolve() + internal void SegDissolve(Segment dummy) { - tri.subsegs[orient].seg = Segment.Empty; + tri.subsegs[orient].seg = dummy; } /// diff --git a/Triangle.NET/Triangle/Topology/Segment.cs b/Triangle.NET/Triangle/Topology/Segment.cs index a7afdea..3cbb21b 100644 --- a/Triangle.NET/Triangle/Topology/Segment.cs +++ b/Triangle.NET/Triangle/Topology/Segment.cs @@ -15,29 +15,6 @@ namespace TriangleNet.Topology /// public class Segment : ISegment { - #region Static initialization of "omnipresent" subsegment - - // Set up 'dummysub', the omnipresent subsegment pointed to by any - // triangle side or subsegment end that isn't attached to a real - // subsegment. - - internal static readonly Segment Empty; - - static Segment() - { - Empty = new Segment(); - Empty.hash = -1; - - // Initialize the two adjoining subsegments to be the omnipresent - // subsegment. These will eventually be changed by various bonding - // operations, but their values don't really matter, as long as they - // can legally be dereferenced. - Empty.subsegs[0].seg = Empty; - Empty.subsegs[1].seg = Empty; - } - - #endregion - // Hash for dictionary. Will be set by mesh instance. internal int hash; @@ -48,22 +25,18 @@ namespace TriangleNet.Topology public Segment() { - // Initialize the two adjoining subsegments to be the omnipresent - // subsegment. - subsegs = new Osub[2]; - subsegs[0].seg = Empty; - subsegs[1].seg = Empty; - // Four NULL vertices. vertices = new Vertex[4]; - // Initialize the two adjoining triangles to be "outer space." - triangles = new Otri[2]; - triangles[0].tri = Triangle.Empty; - triangles[1].tri = Triangle.Empty; - // Set the boundary marker to zero. boundary = 0; + + // Initialize the two adjoining subsegments to be the omnipresent + // subsegment. + subsegs = new Osub[2]; + + // Initialize the two adjoining triangles to be "outer space." + triangles = new Otri[2]; } #region Public properties @@ -107,7 +80,7 @@ namespace TriangleNet.Topology /// public ITriangle GetTriangle(int index) { - return triangles[index].tri.id == Triangle.EmptyID ? null : triangles[index].tri; + return triangles[index].tri.hash == Mesh.DUMMY ? null : triangles[index].tri; } public override int GetHashCode() diff --git a/Triangle.NET/Triangle/Topology/Triangle.cs b/Triangle.NET/Triangle/Topology/Triangle.cs index 4bcee8f..d92e5d8 100644 --- a/Triangle.NET/Triangle/Topology/Triangle.cs +++ b/Triangle.NET/Triangle/Topology/Triangle.cs @@ -15,61 +15,6 @@ namespace TriangleNet.Topology /// public class Triangle : ITriangle { - #region Static initialization of "Outer Space" triangle - - // The triangle that fills "outer space," called 'dummytri', is pointed to - // by every triangle and subsegment on a boundary (be it outer or inner) of - // the triangulation. Also, 'dummytri' points to one of the triangles on - // the convex hull (until the holes and concavities are carved), making it - // possible to find a starting triangle for point location. - - // 'dummytri' and 'dummysub' are generally required to fulfill only a few - // invariants: their vertices must remain NULL and 'dummytri' must always - // be bonded (at offset zero) to some triangle on the convex hull of the - // mesh, via a boundary edge. Otherwise, the connections of 'dummytri' and - // 'dummysub' may change willy-nilly. This makes it possible to avoid - // writing a good deal of special-case code (in the edge flip, for example) - // for dealing with the boundary of the mesh, places where no subsegment is - // present, and so forth. Other entities are frequently bonded to - // 'dummytri' and 'dummysub' as if they were real mesh entities, with no - // harm done. - - internal const int EmptyID = -1; - - internal static readonly Triangle Empty; - - /// - /// Initializes the dummytri (Triangle.Empty). - /// - static Triangle() - { - // Set up 'dummytri', the 'triangle' that occupies "outer space." - Empty = new Triangle(); - Empty.hash = Empty.id = EmptyID; - - // Initialize the three adjoining triangles to be "outer space." These - // will eventually be changed by various bonding operations, but their - // values don't really matter, as long as they can legally be - // dereferenced. - Empty.neighbors[0].tri = Empty; - Empty.neighbors[1].tri = Empty; - Empty.neighbors[2].tri = Empty; - - if (Segment.Empty == null) - { - // In case the static Segment constructor hasn't been called yet. - Empty.subsegs[0].seg = new Segment(); - } - - // Initialize the three adjoining subsegments of 'dummytri' to be - // the omnipresent subsegment. - Empty.subsegs[0].seg = Segment.Empty; - Empty.subsegs[1].seg = Segment.Empty; - Empty.subsegs[2].seg = Segment.Empty; - } - - #endregion - // Hash for dictionary. Will be set by mesh instance. internal int hash; @@ -93,15 +38,9 @@ namespace TriangleNet.Topology // Initialize the three adjoining subsegments to be the omnipresent subsegment. subsegs = new Osub[3]; - subsegs[0].seg = Segment.Empty; - subsegs[1].seg = Segment.Empty; - subsegs[2].seg = Segment.Empty; // Initialize the three adjoining triangles to be "outer space". neighbors = new Otri[3]; - neighbors[0].tri = Empty; - neighbors[1].tri = Empty; - neighbors[2].tri = Empty; // area = -1.0; } @@ -185,7 +124,7 @@ namespace TriangleNet.Topology /// The neigbbor opposite of vertex with given index. public ITriangle GetNeighbor(int index) { - return neighbors[index].tri.id == EmptyID ? null : neighbors[index].tri; + return neighbors[index].tri.hash == Mesh.DUMMY ? null : neighbors[index].tri; } /// @@ -195,7 +134,7 @@ namespace TriangleNet.Topology /// The segment opposite of vertex with given index. public ISegment GetSegment(int index) { - return subsegs[index].seg == Segment.Empty ? null : subsegs[index].seg; + return subsegs[index].seg.hash == Mesh.DUMMY ? null : subsegs[index].seg; } /// diff --git a/Triangle.NET/Triangle/TriangleLocator.cs b/Triangle.NET/Triangle/TriangleLocator.cs index 1c7535c..7e0cdfd 100644 --- a/Triangle.NET/Triangle/TriangleLocator.cs +++ b/Triangle.NET/Triangle/TriangleLocator.cs @@ -196,7 +196,7 @@ namespace TriangleNet { // Check for walking through a subsegment. backtracktri.Pivot(ref checkedge); - if (checkedge.seg != Segment.Empty) + if (checkedge.seg.hash != Mesh.DUMMY) { // Go back to the last triangle. backtracktri.Copy(ref searchtri); @@ -204,7 +204,7 @@ namespace TriangleNet } } // Check for walking right out of the triangulation. - if (searchtri.tri.id == Triangle.EmptyID) + if (searchtri.tri.id == Mesh.DUMMY) { // Go back to the last triangle. backtracktri.Copy(ref searchtri); diff --git a/Triangle.NET/Triangle/Voronoi/Legacy/BoundedVoronoiLegacy.cs b/Triangle.NET/Triangle/Voronoi/Legacy/BoundedVoronoiLegacy.cs index 7aa4a4f..5196c25 100644 --- a/Triangle.NET/Triangle/Voronoi/Legacy/BoundedVoronoiLegacy.cs +++ b/Triangle.NET/Triangle/Voronoi/Legacy/BoundedVoronoiLegacy.cs @@ -177,7 +177,7 @@ namespace TriangleNet.Voronoi.Legacy e.orient = 0; e.Pivot(ref f); - if (f.tri.id != Triangle.EmptyID && !f.tri.infected) + if (f.tri.id != Mesh.DUMMY && !f.tri.infected) { triangles.Push(f.tri); } @@ -185,7 +185,7 @@ namespace TriangleNet.Voronoi.Legacy e.Sym(); e.Pivot(ref f); - if (f.tri.id != Triangle.EmptyID && !f.tri.infected) + if (f.tri.id != Mesh.DUMMY && !f.tri.infected) { triangles.Push(f.tri); } @@ -216,7 +216,7 @@ namespace TriangleNet.Voronoi.Legacy // if f0 is finite and tagged non-blind & the common edge // between f and f0 is unconstrained then - if (f0.tri.id != Triangle.EmptyID && !f0.tri.infected && sub1.seg == Segment.Empty) + if (f0.tri.id != Mesh.DUMMY && !f0.tri.infected && sub1.seg.hash == Mesh.DUMMY) { // Push f0 into triangles. triangles.Push(f0.tri); @@ -413,10 +413,10 @@ namespace TriangleNet.Voronoi.Legacy f_init.Oprev(ref f_prev); // Is the border to the left? - if (f_prev.tri.id != Triangle.EmptyID) + if (f_prev.tri.id != Mesh.DUMMY) { // Go clockwise until we reach the border (or the initial triangle) - while (f_prev.tri.id != Triangle.EmptyID && !f_prev.Equal(f_init)) + while (f_prev.tri.id != Mesh.DUMMY && !f_prev.Equal(f_init)) { f_prev.Copy(ref f); f_prev.Oprev(); @@ -426,7 +426,7 @@ namespace TriangleNet.Voronoi.Legacy f.Onext(ref f_next); } - if (f_prev.tri.id == Triangle.EmptyID) + if (f_prev.tri.id == Mesh.DUMMY) { // For vertices on the domain boundaray, add the vertex. For // internal boundaries don't add it. @@ -452,7 +452,7 @@ namespace TriangleNet.Voronoi.Legacy // Call Lffnext the line going through the circumcenters of f and f_next cc_f = this.points[f.tri.id]; - if (f_next.tri.id == Triangle.EmptyID) + if (f_next.tri.id == Mesh.DUMMY) { if (!f.tri.infected) { diff --git a/Triangle.NET/Triangle/Voronoi/Legacy/SimpleVoronoi.cs b/Triangle.NET/Triangle/Voronoi/Legacy/SimpleVoronoi.cs index 50f5cf0..8f0333b 100644 --- a/Triangle.NET/Triangle/Voronoi/Legacy/SimpleVoronoi.cs +++ b/Triangle.NET/Triangle/Voronoi/Legacy/SimpleVoronoi.cs @@ -156,11 +156,11 @@ namespace TriangleNet.Voronoi.Legacy f_init.Onext(ref f_next); // Check if f_init lies on the boundary of the triangulation. - if (f_next.tri.id == Triangle.EmptyID) + if (f_next.tri.id == Mesh.DUMMY) { f_init.Oprev(ref f_prev); - if (f_prev.tri.id != Triangle.EmptyID) + if (f_prev.tri.id != Mesh.DUMMY) { f_init.Copy(ref f_next); // Move one triangle clockwise @@ -170,7 +170,7 @@ namespace TriangleNet.Voronoi.Legacy } // Go counterclockwise until we reach the border or the initial triangle. - while (f_next.tri.id != Triangle.EmptyID) + while (f_next.tri.id != Mesh.DUMMY) { // Add circumcenter of current triangle vpoints.Add(points[f.tri.id]); @@ -228,7 +228,7 @@ namespace TriangleNet.Voronoi.Legacy f_init.Copy(ref f); f.Oprev(ref f_prev); - while (f_prev.tri.id != Triangle.EmptyID) + while (f_prev.tri.id != Mesh.DUMMY) { vpoints.Add(points[f_prev.tri.id]); region.AddNeighbor(f_prev.tri.id, regions[f_prev.Apex().id]);