diff --git a/src/Triangle.Examples/Examples/Example4.cs b/src/Triangle.Examples/Examples/Example4.cs index c7ab07a..449eb4b 100644 --- a/src/Triangle.Examples/Examples/Example4.cs +++ b/src/Triangle.Examples/Examples/Example4.cs @@ -8,7 +8,7 @@ namespace TriangleNet.Examples using TriangleNet.Smoothing; /// - /// Refine only a part of a polygon mesh be using region pointers and an area constraint. + /// Refine only a part of a polygon mesh by using region pointers and an area constraint. /// public class Example4 { diff --git a/src/Triangle.Examples/Examples/Example7.cs b/src/Triangle.Examples/Examples/Example7.cs index f08de35..5c18841 100644 --- a/src/Triangle.Examples/Examples/Example7.cs +++ b/src/Triangle.Examples/Examples/Example7.cs @@ -1,8 +1,10 @@  namespace TriangleNet.Examples { + using System; using TriangleNet.Geometry; using TriangleNet.Meshing; + using TriangleNet.Meshing.Iterators; using TriangleNet.Rendering.Text; /// @@ -26,7 +28,18 @@ namespace TriangleNet.Examples }; // Generate mesh using the polygons Triangulate extension method. - var mesh = poly.Triangulate(quality); + var mesh = (Mesh)poly.Triangulate(quality); + + // Validate. + foreach (var e in EdgeIterator.EnumerateEdges(mesh)) + { + double length = Math.Sqrt(DistSqr(e.GetVertex(0), e.GetVertex(1))); + + if (length > MAX_EDGE_LENGTH) + { + Console.WriteLine("Something's wrong in here ..."); + } + } if (print) SvgImage.Save(mesh, "example-7.svg", 500); } diff --git a/src/Triangle.Examples/Examples/Example9.cs b/src/Triangle.Examples/Examples/Example9.cs index 72d264f..93d4a53 100644 --- a/src/Triangle.Examples/Examples/Example9.cs +++ b/src/Triangle.Examples/Examples/Example9.cs @@ -11,7 +11,7 @@ namespace TriangleNet.Examples /// public class Example9 { - public static void Run() + public static void Run(bool print = false) { var pts = new List { @@ -39,7 +39,7 @@ namespace TriangleNet.Examples var list = MeshValidator.GetDegenerateBoundaryTriangles(mesh); - if (list.Any()) + if (print && list.Any()) { Console.WriteLine("Iteration {0}: found {1} degenerate triangle(s) of {2}.", i, list.Count(), mesh.Triangles.Count); diff --git a/src/Triangle/Geometry/Contour.cs b/src/Triangle/Geometry/Contour.cs index 08932a9..68ab9af 100644 --- a/src/Triangle/Geometry/Contour.cs +++ b/src/Triangle/Geometry/Contour.cs @@ -142,7 +142,7 @@ namespace TriangleNet.Geometry double dx, dy; double h; - var predicates = new RobustPredicates(); + var predicates = RobustPredicates.Default; a = contour[0]; b = contour[1]; diff --git a/src/Triangle/Tools/PolygonValidator.cs b/src/Triangle/Tools/PolygonValidator.cs index 4609519..64c82cc 100644 --- a/src/Triangle/Tools/PolygonValidator.cs +++ b/src/Triangle/Tools/PolygonValidator.cs @@ -37,17 +37,17 @@ namespace TriangleNet.Tools if (p == null) { horrors++; - logger.Warning(String.Format("Point {0} is null.", i), "PolygonValidator.IsConsistent()"); + logger.Warning(string.Format("Point {0} is null.", i), "PolygonValidator.IsConsistent()"); } else if (double.IsNaN(p.x) || double.IsNaN(p.y)) { horrors++; - logger.Warning(String.Format("Point {0} has invalid coordinates.", i), "PolygonValidator.IsConsistent()"); + logger.Warning(string.Format("Point {0} has invalid coordinates.", i), "PolygonValidator.IsConsistent()"); } else if (double.IsInfinity(p.x) || double.IsInfinity(p.y)) { horrors++; - logger.Warning(String.Format("Point {0} has invalid coordinates.", i), "PolygonValidator.IsConsistent()"); + logger.Warning(string.Format("Point {0} has invalid coordinates.", i), "PolygonValidator.IsConsistent()"); } i++; @@ -60,7 +60,7 @@ namespace TriangleNet.Tools if (seg == null) { horrors++; - logger.Warning(String.Format("Segment {0} is null.", i), "PolygonValidator.IsConsistent()"); + logger.Warning(string.Format("Segment {0} is null.", i), "PolygonValidator.IsConsistent()"); // Always abort if a NULL-segment is found. return false; @@ -72,7 +72,7 @@ namespace TriangleNet.Tools if ((p.x == q.x) && (p.y == q.y)) { horrors++; - logger.Warning(String.Format("Endpoints of segment {0} are coincident (IDs {1} / {2}).", i, p.id, q.id), + logger.Warning(string.Format("Endpoints of segment {0} are coincident (IDs {1} / {2}).", i, p.id, q.id), "PolygonValidator.IsConsistent()"); } @@ -109,7 +109,7 @@ namespace TriangleNet.Tools if (points[i - 1] == points[i]) { horrors++; - logger.Warning(string.Format("Found duplicate point {0}.", points[i]), + logger.Warning(string.Format("Found duplicate point ({0}, {1}).", points[i].x, points[i].y), "PolygonValidator.HasDuplicateVertices()"); } } @@ -117,6 +117,53 @@ namespace TriangleNet.Tools return horrors > 0; } + /// + /// Get the ratio of the largest and smallest segment length. + /// + /// The polygon. + /// The ratio threshold. + /// + /// This method will also report zero-length segments. + /// + public static double GetSegmentRatio(IPolygon poly, double threshold = 2e12) + { + var logger = Log.Instance; + + double min = double.MaxValue; + double max = 0.0; + + foreach (var seg in poly.Segments) + { + var p = seg.GetVertex(0); + var q = seg.GetVertex(1); + + var dx = p.X - q.X; + var dy = p.Y - q.Y; + + var length = Math.Sqrt(dx * dx + dy * dy); + + if (length == 0.0) + { + logger.Warning(string.Format("Found zero-length segment (vertex IDs {0} / {1}).", p.id, q.id), + "PolygonValidator.GetSegmentRatio()"); + continue; + } + + min = Math.Min(min, length); + max = Math.Max(max, length); + } + + double ratio = max / min; + + if (ratio > threshold) + { + logger.Warning(string.Format("Polygon has large segment ratio {0:G2}.", ratio), + "PolygonValidator.GetSegmentRatio()"); + } + + return ratio; + } + /// /// Test the polygon for 360 degree angles. /// diff --git a/src/Triangle/TrianglePool.cs b/src/Triangle/TrianglePool.cs index 30d866c..aa67836 100644 --- a/src/Triangle/TrianglePool.cs +++ b/src/Triangle/TrianglePool.cs @@ -27,6 +27,11 @@ namespace TriangleNet // A stack of free triangles. Stack stack; + /// + /// Gets the total number of currently allocated triangles. + /// + public int Capacity => size; + public TrianglePool() { size = 0;