From c5c0b3363a130e2fa15c72b24d4d4ec6d365b728 Mon Sep 17 00:00:00 2001 From: "SND\\wo80_cp" Date: Thu, 24 Apr 2014 12:24:42 +0000 Subject: [PATCH] Fix Bounded Voronoi exception; More code reorganization; git-svn-id: https://triangle.svn.codeplex.com/svn@74907 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5 --- Triangle.NET/Triangle/Carver.cs | 421 ------------------ Triangle.NET/Triangle/ConstraintMesher.cs | 404 ++++++++++++++++- Triangle.NET/Triangle/Mesh.cs | 12 +- Triangle.NET/Triangle/Primitives.cs | 2 + Triangle.NET/Triangle/Tools/BoundedVoronoi.cs | 94 ++-- Triangle.NET/Triangle/Tools/Statistic.cs | 4 +- Triangle.NET/Triangle/Triangle.csproj | 1 - 7 files changed, 455 insertions(+), 483 deletions(-) delete mode 100644 Triangle.NET/Triangle/Carver.cs diff --git a/Triangle.NET/Triangle/Carver.cs b/Triangle.NET/Triangle/Carver.cs deleted file mode 100644 index 12e20f7..0000000 --- a/Triangle.NET/Triangle/Carver.cs +++ /dev/null @@ -1,421 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Original Triangle code by Jonathan Richard Shewchuk, http://www.cs.cmu.edu/~quake/triangle.html -// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/ -// -// ----------------------------------------------------------------------- - -namespace TriangleNet -{ - using TriangleNet.Data; - using System; - using TriangleNet.Geometry; - using System.Collections.Generic; - using TriangleNet.Tools; - - /// - /// Carves holes into the triangulation. - /// - class Carver - { - Mesh mesh; - List viri; - - public Carver(Mesh mesh) - { - this.mesh = mesh; - this.viri = new List(); - } - - /// - /// 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. - /// - 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)); - } - - /// - /// Spread the virus from all infected triangles to any neighbors not - /// protected by subsegments. Delete all infected triangles. - /// - /// - /// 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. - /// - 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(); - } - - /// - /// Find the holes and infect them. Find the area constraints and infect - /// them. Infect the convex hull. Spread the infection and kill triangles. - /// Spread the area constraints. - /// - public void CarveHoles() - { - Otri searchtri = default(Otri); - Vertex searchorg, searchdest; - LocateResult intersect; - - Triangle[] regionTris = null; - - if (!mesh.behavior.Convex) - { - // Mark as infected any unprotected triangles on the boundary. - // This is one way by which concavities are created. - InfectHull(); - } - - if (!mesh.behavior.NoHoles) - { - // Infect each triangle in which a hole lies. - foreach (var hole in mesh.holes) - { - // Ignore holes that aren't within the bounds of the mesh. - if (mesh.bounds.Contains(hole)) - { - // Start searching from some triangle on the outer boundary. - searchtri.triangle = Mesh.dummytri; - searchtri.orient = 0; - searchtri.SymSelf(); - // Ensure that the hole is to the left of this boundary edge; - // otherwise, locate() will falsely report that the hole - // falls within the starting triangle. - searchorg = searchtri.Org(); - searchdest = searchtri.Dest(); - if (Primitives.CounterClockwise(searchorg, searchdest, hole) > 0.0) - { - // Find a triangle that contains the hole. - intersect = mesh.locator.Locate(hole, ref searchtri); - if ((intersect != LocateResult.Outside) && (!searchtri.IsInfected())) - { - // Infect the triangle. This is done by marking the triangle - // as infected and including the triangle in the virus pool. - searchtri.Infect(); - viri.Add(searchtri.triangle); - } - } - } - } - } - - // Now, we have to find all the regions BEFORE we carve the holes, because locate() won't - // work when the triangulation is no longer convex. (Incidentally, this is the reason why - // regional attributes and area constraints can't be used when refining a preexisting mesh, - // which might not be convex; they can only be used with a freshly triangulated PSLG.) - if (mesh.regions.Count > 0) - { - int i = 0; - - regionTris = new Triangle[mesh.regions.Count]; - - // Find the starting triangle for each region. - foreach (var region in mesh.regions) - { - regionTris[i] = Mesh.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.triangle = Mesh.dummytri; - searchtri.orient = 0; - searchtri.SymSelf(); - // Ensure that the region point is to the left of this boundary - // edge; otherwise, locate() will falsely report that the - // region point falls within the starting triangle. - searchorg = searchtri.Org(); - searchdest = searchtri.Dest(); - if (Primitives.CounterClockwise(searchorg, searchdest, region.point) > 0.0) - { - // Find a triangle that contains the region point. - intersect = mesh.locator.Locate(region.point, ref searchtri); - if ((intersect != LocateResult.Outside) && (!searchtri.IsInfected())) - { - // Record the triangle for processing after the - // holes have been carved. - regionTris[i] = searchtri.triangle; - regionTris[i].region = region.id; - } - } - } - - i++; - } - } - - if (viri.Count > 0) - { - // Carve the holes and concavities. - Plague(); - } - - if (regionTris != null) - { - var iterator = new RegionIterator(mesh); - - for (int i = 0; i < regionTris.Length; i++) - { - if (regionTris[i] != Mesh.dummytri) - { - // Make sure the triangle under consideration still exists. - // It may have been eaten by the virus. - if (!Otri.IsDead(regionTris[i])) - { - // Apply one region's attribute and/or area constraint. - iterator.Process(regionTris[i]); - } - } - } - } - - // Free up memory (virus pool should be empty anyway). - viri.Clear(); - } - } -} diff --git a/Triangle.NET/Triangle/ConstraintMesher.cs b/Triangle.NET/Triangle/ConstraintMesher.cs index 13ec654..db3809d 100644 --- a/Triangle.NET/Triangle/ConstraintMesher.cs +++ b/Triangle.NET/Triangle/ConstraintMesher.cs @@ -8,9 +8,11 @@ namespace TriangleNet { using System; + using System.Collections.Generic; using TriangleNet.Data; using TriangleNet.Geometry; using TriangleNet.Log; + using TriangleNet.Tools; internal class ConstraintMesher { @@ -18,6 +20,8 @@ namespace TriangleNet Behavior behavior; TriangleLocator locator; + List viri; + ILog logger; public ConstraintMesher(Mesh mesh) @@ -26,16 +30,141 @@ namespace TriangleNet this.behavior = mesh.behavior; this.locator = mesh.locator; + this.viri = new List(); + logger = SimpleLog.Instance; } + /// + /// Find the holes and infect them. Find the area constraints and infect + /// them. Infect the convex hull. Spread the infection and kill triangles. + /// Spread the area constraints. + /// + public void CarveHoles() + { + Otri searchtri = default(Otri); + Vertex searchorg, searchdest; + LocateResult intersect; + + Triangle[] regionTris = null; + + if (!mesh.behavior.Convex) + { + // Mark as infected any unprotected triangles on the boundary. + // This is one way by which concavities are created. + InfectHull(); + } + + if (!mesh.behavior.NoHoles) + { + // Infect each triangle in which a hole lies. + foreach (var hole in mesh.holes) + { + // Ignore holes that aren't within the bounds of the mesh. + if (mesh.bounds.Contains(hole)) + { + // Start searching from some triangle on the outer boundary. + searchtri.triangle = Mesh.dummytri; + searchtri.orient = 0; + searchtri.SymSelf(); + // Ensure that the hole is to the left of this boundary edge; + // otherwise, locate() will falsely report that the hole + // falls within the starting triangle. + searchorg = searchtri.Org(); + searchdest = searchtri.Dest(); + if (Primitives.CounterClockwise(searchorg, searchdest, hole) > 0.0) + { + // Find a triangle that contains the hole. + intersect = mesh.locator.Locate(hole, ref searchtri); + if ((intersect != LocateResult.Outside) && (!searchtri.IsInfected())) + { + // Infect the triangle. This is done by marking the triangle + // as infected and including the triangle in the virus pool. + searchtri.Infect(); + viri.Add(searchtri.triangle); + } + } + } + } + } + + // Now, we have to find all the regions BEFORE we carve the holes, because locate() won't + // work when the triangulation is no longer convex. (Incidentally, this is the reason why + // regional attributes and area constraints can't be used when refining a preexisting mesh, + // which might not be convex; they can only be used with a freshly triangulated PSLG.) + if (mesh.regions.Count > 0) + { + int i = 0; + + regionTris = new Triangle[mesh.regions.Count]; + + // Find the starting triangle for each region. + foreach (var region in mesh.regions) + { + regionTris[i] = Mesh.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.triangle = Mesh.dummytri; + searchtri.orient = 0; + searchtri.SymSelf(); + // Ensure that the region point is to the left of this boundary + // edge; otherwise, locate() will falsely report that the + // region point falls within the starting triangle. + searchorg = searchtri.Org(); + searchdest = searchtri.Dest(); + if (Primitives.CounterClockwise(searchorg, searchdest, region.point) > 0.0) + { + // Find a triangle that contains the region point. + intersect = mesh.locator.Locate(region.point, ref searchtri); + if ((intersect != LocateResult.Outside) && (!searchtri.IsInfected())) + { + // Record the triangle for processing after the + // holes have been carved. + regionTris[i] = searchtri.triangle; + regionTris[i].region = region.id; + } + } + } + + i++; + } + } + + if (viri.Count > 0) + { + // Carve the holes and concavities. + Plague(); + } + + if (regionTris != null) + { + var iterator = new RegionIterator(mesh); + + for (int i = 0; i < regionTris.Length; i++) + { + if (regionTris[i] != Mesh.dummytri) + { + // Make sure the triangle under consideration still exists. + // It may have been eaten by the virus. + if (!Otri.IsDead(regionTris[i])) + { + // Apply one region's attribute and/or area constraint. + iterator.Process(regionTris[i]); + } + } + } + } + + // Free up memory (virus pool should be empty anyway). + viri.Clear(); + } + /// /// Create the segments of a triangulation, including PSLG segments and edges /// on the convex hull. /// - /// - /// - /// public void FormSkeleton(InputGeometry input) { Vertex endpoint1, endpoint2; @@ -116,6 +245,275 @@ namespace TriangleNet } } + #region Carving holes + + /// + /// 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. + /// + 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)); + } + + /// + /// Spread the virus from all infected triangles to any neighbors not + /// protected by subsegments. Delete all infected triangles. + /// + /// + /// 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. + /// + 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(); + } + + #endregion + #region Segment insertion /// diff --git a/Triangle.NET/Triangle/Mesh.cs b/Triangle.NET/Triangle/Mesh.cs index c0eaa7f..2255a46 100644 --- a/Triangle.NET/Triangle/Mesh.cs +++ b/Triangle.NET/Triangle/Mesh.cs @@ -335,13 +335,14 @@ namespace TriangleNet infvertex2 = null; infvertex3 = null; + // Insert segments, carving holes. + var mesher = new ConstraintMesher(this); + if (behavior.useSegments) { // Segments will be introduced next. checksegments = true; - var mesher = new ConstraintMesher(this); - // Insert PSLG segments and/or convex hull segments. mesher.FormSkeleton(input); } @@ -363,8 +364,7 @@ namespace TriangleNet //dummytri.neighbors[2].triangle = dummytri; // Carve out holes and concavities. - Carver c = new Carver(this); - c.CarveHoles(); + mesher.CarveHoles(); } else { @@ -618,8 +618,8 @@ namespace TriangleNet Statistic.InCircleCount = 0; Statistic.CounterClockwiseCount = 0; - Statistic.InCircleCountDecimal = 0; - Statistic.CounterClockwiseCountDecimal = 0; + Statistic.InCircleAdaptCount = 0; + Statistic.CounterClockwiseAdaptCount = 0; Statistic.Orient3dCount = 0; Statistic.HyperbolaCount = 0; Statistic.CircleTopCount = 0; diff --git a/Triangle.NET/Triangle/Primitives.cs b/Triangle.NET/Triangle/Primitives.cs index 6433046..793de81 100644 --- a/Triangle.NET/Triangle/Primitives.cs +++ b/Triangle.NET/Triangle/Primitives.cs @@ -147,6 +147,7 @@ namespace TriangleNet return det; } + Statistic.CounterClockwiseAdaptCount++; return CounterClockwiseAdapt(pa, pb, pc, detsum); } @@ -209,6 +210,7 @@ namespace TriangleNet return det; } + Statistic.InCircleAdaptCount++; return InCircleAdapt(pa, pb, pc, pd, permanent); } diff --git a/Triangle.NET/Triangle/Tools/BoundedVoronoi.cs b/Triangle.NET/Triangle/Tools/BoundedVoronoi.cs index 91c0156..8ffd857 100644 --- a/Triangle.NET/Triangle/Tools/BoundedVoronoi.cs +++ b/Triangle.NET/Triangle/Tools/BoundedVoronoi.cs @@ -27,6 +27,8 @@ namespace TriangleNet.Tools Point[] points; List regions; + // Used for new points on segments. + List segPoints; int segIndex; Dictionary subsegMap; @@ -79,9 +81,11 @@ namespace TriangleNet.Tools mesh.MakeVertexMap(); // Allocate space for voronoi diagram - this.points = new Point[mesh.triangles.Count + mesh.subsegs.Count * 5]; // This is an upper bound. this.regions = new List(mesh.vertices.Count); + this.points = new Point[mesh.triangles.Count]; + this.segPoints = new List(mesh.subsegs.Count * 4); + ComputeCircumCenters(); TagBlindTriangles(); @@ -98,6 +102,19 @@ namespace TriangleNet.Tools ConstructBoundaryBvdCell(v); } } + + // Add the new points on segments to the point array. + int length = points.Length; + + Array.Resize(ref points, length + segPoints.Count); + + for (int i = 0; i < segPoints.Count; i++) + { + points[length + i] = segPoints[i]; + } + + this.segPoints.Clear(); + this.segPoints = null; } private void ComputeCircumCenters() @@ -297,10 +314,8 @@ namespace TriangleNet.Tools // 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++; - + p.id = n + segIndex++; + segPoints.Add(p); vpoints.Add(p); } } @@ -316,10 +331,8 @@ namespace TriangleNet.Tools // 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++; - + p.id = n + segIndex++; + segPoints.Add(p); vpoints.Add(p); } } @@ -334,19 +347,15 @@ namespace TriangleNet.Tools // 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++; - + p.id = n + segIndex++; + segPoints.Add(p); 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++; - + p.id = n + segIndex++; + segPoints.Add(p); vpoints.Add(p); } } @@ -418,10 +427,9 @@ namespace TriangleNet.Tools // 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++; + p.id = n + segIndex++; + segPoints.Add(p); vpoints.Add(p); } @@ -429,10 +437,9 @@ namespace TriangleNet.Tools 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++; + p.id = n + segIndex++; + segPoints.Add(p); vpoints.Add(p); // repeat ... until f = f_init @@ -454,10 +461,9 @@ namespace TriangleNet.Tools 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++; + p.id = n + segIndex++; + segPoints.Add(p); vpoints.Add(p); break; @@ -479,10 +485,8 @@ namespace TriangleNet.Tools // 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++; - + p.id = n + segIndex++; + segPoints.Add(p); vpoints.Add(p); } } @@ -510,20 +514,16 @@ namespace TriangleNet.Tools // 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++; - + p.id = n + segIndex++; + segPoints.Add(p); 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++; - + p.id = n + segIndex++; + segPoints.Add(p); vpoints.Add(p); } } @@ -538,19 +538,15 @@ namespace TriangleNet.Tools // 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++; - + p.id = n + segIndex++; + segPoints.Add(p); 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++; - + p.id = n + segIndex++; + segPoints.Add(p); vpoints.Add(p); } } @@ -565,10 +561,8 @@ namespace TriangleNet.Tools // 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++; - + p.id = n + segIndex++; + segPoints.Add(p); vpoints.Add(p); } } diff --git a/Triangle.NET/Triangle/Tools/Statistic.cs b/Triangle.NET/Triangle/Tools/Statistic.cs index 002d7bb..a22b17b 100644 --- a/Triangle.NET/Triangle/Tools/Statistic.cs +++ b/Triangle.NET/Triangle/Tools/Statistic.cs @@ -23,13 +23,13 @@ namespace TriangleNet.Tools /// Number of incircle tests performed. /// public static long InCircleCount = 0; - public static long InCircleCountDecimal = 0; + public static long InCircleAdaptCount = 0; /// /// Number of counterclockwise tests performed. /// public static long CounterClockwiseCount = 0; - public static long CounterClockwiseCountDecimal = 0; + public static long CounterClockwiseAdaptCount = 0; /// /// Number of 3D orientation tests performed. diff --git a/Triangle.NET/Triangle/Triangle.csproj b/Triangle.NET/Triangle/Triangle.csproj index 488da34..7fbd442 100644 --- a/Triangle.NET/Triangle/Triangle.csproj +++ b/Triangle.NET/Triangle/Triangle.csproj @@ -44,7 +44,6 @@ -