diff --git a/Triangle.NET/TestApp/FormTopology.cs b/Triangle.NET/TestApp/FormTopology.cs index c2889be..3600993 100644 --- a/Triangle.NET/TestApp/FormTopology.cs +++ b/Triangle.NET/TestApp/FormTopology.cs @@ -22,8 +22,7 @@ namespace MeshExplorer private void FormTopology_Load(object sender, EventArgs e) { - var mesher = new GenericMesher(); - mesh = (Mesh)mesher.StructuredMesh(new Rectangle(0.0, 0.0, 4.0, 4.0), 4, 4); + mesh = (Mesh)GenericMesher.StructuredMesh(new Rectangle(0.0, 0.0, 4.0, 4.0), 4, 4); renderControl.Initialize(mesh); diff --git a/Triangle.NET/Triangle/Mesh.cs b/Triangle.NET/Triangle/Mesh.cs index a9cce7a..39a359b 100644 --- a/Triangle.NET/Triangle/Mesh.cs +++ b/Triangle.NET/Triangle/Mesh.cs @@ -252,20 +252,23 @@ namespace TriangleNet this.predicates = predicates; - this.qualityMesher = new QualityMesher(this, predicates); - this.locator = new TriangleLocator(this, predicates); } public void Refine(QualityOptions quality) { - behavior.MinAngle = quality.MinimumAngle; - behavior.MaxAngle = quality.MaximumAngle; + inelements = triangles.Count; + invertices = vertices.Count; - behavior.MaxArea = quality.MaximumArea; - behavior.VarArea = quality.VariableArea; + if (behavior.Poly) + { + insegments = behavior.useSegments ? subsegs.Count : hullsize; + } - this.Refine(); + Reset(); + + // Enforce angle and area constraints. + qualityMesher.Apply(quality); } /// @@ -321,130 +324,14 @@ namespace TriangleNet } #region Misc - - /// - /// Triangulate given input data. - /// - /// - internal void ApplyConstraints(IPolygon input, ConstraintOptions options, QualityOptions quality) - { - behavior.Poly = input.Segments.Count > 0; - - // Copy constraint options - if (options != null) - { - behavior.ConformingDelaunay = options.ConformingDelaunay; - behavior.Convex = options.Convex; - behavior.NoBisect = options.SegmentSplitting; - - if (behavior.ConformingDelaunay) - { - behavior.Quality = true; - } - } - - // Copy quality options - if (quality != null) - { - behavior.Quality = true; - - behavior.MinAngle = quality.MinimumAngle; - behavior.MaxAngle = quality.MaximumAngle; - behavior.MaxArea = quality.MaximumArea; - behavior.UserTest = quality.UserTest; - - steinerleft = quality.SteinerPoints == 0 ? -1 : quality.SteinerPoints; - } - - //if (input.EdgeMarkers != null) - //{ - // behavior.UseBoundaryMarkers = true; - //} - - // TODO: remove - if (!behavior.Poly) - { - // Be careful not to allocate space for element area constraints that - // will never be assigned any value (other than the default -1.0). - behavior.VarArea = false; - } - - behavior.useRegions = input.Regions.Count > 0; - - // Ensure that no vertex can be mistaken for a triangular bounding - // box vertex in insertvertex(). - infvertex1 = null; - infvertex2 = null; - infvertex3 = null; - - // Insert segments, carving holes. - var mesher = new ConstraintMesher(this, predicates); - - if (behavior.useSegments) - { - // Segments will be introduced next. - checksegments = true; - - // Insert PSLG segments and/or convex hull segments. - mesher.FormSkeleton(input); - } - - if (behavior.Poly && (triangles.Count > 0)) - { - // Copy holes - foreach (var item in input.Holes) - { - holes.Add(item); - } - - // Copy regions - foreach (var item in input.Regions) - { - regions.Add(item); - } - - // Carve out holes and concavities. - mesher.CarveHoles(); - } - - if (behavior.Quality && triangles.Count > 0) - { - // Enforce angle and area constraints. - qualityMesher.EnforceQuality(); - } - } /// - /// Refines the current mesh. + /// Set QualityMesher for mesh refinement. /// - internal void Refine() + /// + internal void SetQualityMesher(QualityMesher qmesher) { - inelements = triangles.Count; - invertices = vertices.Count; - - // TODO: Set all vertex types to input (i.e. NOT free)? - - if (behavior.Poly) - { - insegments = behavior.useSegments ? subsegs.Count : hullsize; - } - - Reset(); - - // Ensure that no vertex can be mistaken for a triangular bounding - // box vertex in insertvertex(). - infvertex1 = infvertex2 = infvertex3 = null; - - if (behavior.useSegments) - { - checksegments = true; - } - - if (triangles.Count > 0) - { - // Enforce angle and area constraints. - qualityMesher.EnforceQuality(); - } + qualityMesher = qmesher; } internal void CopyTo(Mesh target) @@ -535,7 +422,7 @@ namespace TriangleNet // Simple heuristic to check if ids are already set. We assume that if the // first two vertex ids are distinct, then all input vertices have pairwise // distinct ids. - bool userId = (v.ID != points[1].ID); + bool userId = (v.id != points[1].id); foreach (var p in points) { diff --git a/Triangle.NET/Triangle/Meshing/ConstraintMesher.cs b/Triangle.NET/Triangle/Meshing/ConstraintMesher.cs index 7e83a53..c5af9ec 100644 --- a/Triangle.NET/Triangle/Meshing/ConstraintMesher.cs +++ b/Triangle.NET/Triangle/Meshing/ConstraintMesher.cs @@ -9,10 +9,10 @@ namespace TriangleNet.Meshing { using System; using System.Collections.Generic; - using TriangleNet.Topology; using TriangleNet.Geometry; using TriangleNet.Logging; using TriangleNet.Meshing.Iterators; + using TriangleNet.Topology; internal class ConstraintMesher { @@ -39,12 +39,67 @@ namespace TriangleNet.Meshing logger = Log.Instance; } + + /// + /// Triangulate given input data. + /// + /// + public void Apply(IPolygon input, ConstraintOptions options) + { + behavior.Poly = input.Segments.Count > 0; + + // Copy constraint options + if (options != null) + { + behavior.ConformingDelaunay = options.ConformingDelaunay; + behavior.Convex = options.Convex; + behavior.NoBisect = options.SegmentSplitting; + + if (behavior.ConformingDelaunay) + { + behavior.Quality = true; + } + } + + //if (input.EdgeMarkers != null) + //{ + // behavior.UseBoundaryMarkers = true; + //} + + behavior.useRegions = input.Regions.Count > 0; + + // Ensure that no vertex can be mistaken for a triangular bounding + // box vertex in insertvertex(). + mesh.infvertex1 = null; + mesh.infvertex2 = null; + mesh.infvertex3 = null; + + if (behavior.useSegments) + { + // Segments will be introduced next. + mesh.checksegments = true; + + // Insert PSLG segments and/or convex hull segments. + FormSkeleton(input); + } + + if (behavior.Poly && (mesh.triangles.Count > 0)) + { + // Copy holes and regions + mesh.holes.AddRange(input.Holes); + mesh.regions.AddRange(input.Regions); + + // Carve out holes and concavities. + CarveHoles(); + } + } + /// /// 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() + private void CarveHoles() { Otri searchtri = default(Otri); Vertex searchorg, searchdest; @@ -171,7 +226,7 @@ namespace TriangleNet.Meshing /// Create the segments of a triangulation, including PSLG segments and edges /// on the convex hull. /// - public void FormSkeleton(IPolygon input) + private void FormSkeleton(IPolygon input) { // The segment endpoints. Vertex p, q; diff --git a/Triangle.NET/Triangle/Meshing/GenericMesher.cs b/Triangle.NET/Triangle/Meshing/GenericMesher.cs index cc3b3bb..d7e2dfe 100644 --- a/Triangle.NET/Triangle/Meshing/GenericMesher.cs +++ b/Triangle.NET/Triangle/Meshing/GenericMesher.cs @@ -23,7 +23,7 @@ namespace TriangleNet.Meshing public GenericMesher() { - this.predicates = RobustPredicates.Default; + this.predicates = new RobustPredicates(); this.triangulator = new Dwyer(this.predicates); } @@ -67,7 +67,16 @@ namespace TriangleNet.Meshing { var mesh = (Mesh)triangulator.Triangulate(polygon.Points); - mesh.ApplyConstraints(polygon, options, quality); + var cmesher = new ConstraintMesher(mesh, predicates); + var qmesher = new QualityMesher(mesh, predicates); + + mesh.SetQualityMesher(qmesher); + + // Insert segments. + cmesher.Apply(polygon, options); + + // Refine mesh. + qmesher.Apply(quality); return mesh; } @@ -80,7 +89,7 @@ namespace TriangleNet.Meshing /// Number of segments in x direction. /// Number of segments in y direction. /// Mesh - public IMesh StructuredMesh(double width, double height, int nx, int ny) + public static IMesh StructuredMesh(double width, double height, int nx, int ny) { if (width <= 0.0) { @@ -102,7 +111,7 @@ namespace TriangleNet.Meshing /// Number of segments in x direction. /// Number of segments in y direction. /// Mesh - public IMesh StructuredMesh(Rectangle bounds, int nx, int ny) + public static IMesh StructuredMesh(Rectangle bounds, int nx, int ny) { var polygon = new Polygon((nx + 1) * (ny + 1)); diff --git a/Triangle.NET/Triangle/Meshing/QualityMesher.cs b/Triangle.NET/Triangle/Meshing/QualityMesher.cs index cf6f29f..d566463 100644 --- a/Triangle.NET/Triangle/Meshing/QualityMesher.cs +++ b/Triangle.NET/Triangle/Meshing/QualityMesher.cs @@ -45,6 +45,51 @@ namespace TriangleNet.Meshing newLocation = new NewLocation(mesh, predicates); } + /// + /// Triangulate given input data. + /// + /// + public void Apply(QualityOptions quality) + { + // Copy quality options + if (quality != null) + { + behavior.Quality = true; + + behavior.MinAngle = quality.MinimumAngle; + behavior.MaxAngle = quality.MaximumAngle; + behavior.MaxArea = quality.MaximumArea; + behavior.UserTest = quality.UserTest; + + mesh.steinerleft = quality.SteinerPoints == 0 ? -1 : quality.SteinerPoints; + } + + // TODO: remove + if (!behavior.Poly) + { + // Be careful not to allocate space for element area constraints that + // will never be assigned any value (other than the default -1.0). + behavior.VarArea = false; + } + + // Ensure that no vertex can be mistaken for a triangular bounding + // box vertex in insertvertex(). + mesh.infvertex1 = null; + mesh.infvertex2 = null; + mesh.infvertex3 = null; + + if (behavior.useSegments) + { + mesh.checksegments = true; + } + + if (behavior.Quality && mesh.triangles.Count > 0) + { + // Enforce angle and area constraints. + EnforceQuality(); + } + } + /// /// Add a bad subsegment to the queue. /// @@ -272,13 +317,10 @@ namespace TriangleNet.Meshing } // Check whether the user thinks this triangle is too large. - if (behavior.UserTest != null) + if ((behavior.UserTest != null) && behavior.UserTest(testtri.tri, area)) { - if (behavior.UserTest(testtri.tri, area)) - { - queue.Enqueue(ref testtri, minedge, tapex, torg, tdest); - return; - } + queue.Enqueue(ref testtri, minedge, tapex, torg, tdest); + return; } } @@ -773,7 +815,7 @@ namespace TriangleNet.Meshing /// /// Remove all the encroached subsegments and bad triangles from the triangulation. /// - public void EnforceQuality() + private void EnforceQuality() { BadTriangle badtri;