From c47a6b45c09280831c0f6ec1b36135efd60ef197 Mon Sep 17 00:00:00 2001 From: "SND\\wo80_cp" Date: Thu, 26 Apr 2012 14:22:43 +0000 Subject: [PATCH] Fixed issue #9346 + some minor fixes/changes git-svn-id: https://triangle.svn.codeplex.com/svn@67039 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5 --- Triangle.NET/TestApp/Form1.cs | 8 +- Triangle.NET/Triangle/Algorithm/Dwyer.cs | 4 +- .../Triangle/Algorithm/Incremental.cs | 2 +- Triangle.NET/Triangle/Algorithm/SweepLine.cs | 6 +- Triangle.NET/Triangle/BadTriQueue.cs | 15 +- Triangle.NET/Triangle/Behavior.cs | 4 +- Triangle.NET/Triangle/Data/Subseg.cs | 4 +- Triangle.NET/Triangle/Data/Vertex.cs | 84 +-- Triangle.NET/Triangle/IO/DataReader.cs | 10 +- Triangle.NET/Triangle/IO/DataWriter.cs | 54 +- Triangle.NET/Triangle/IO/FileReader.cs | 110 +++- Triangle.NET/Triangle/IO/VoronoiData.cs | 12 +- Triangle.NET/Triangle/Log/ILog.cs | 20 +- Triangle.NET/Triangle/Log/ILogItem.cs | 24 + .../Log/{SimpleLogger.cs => SimpleLog.cs} | 35 +- Triangle.NET/Triangle/Log/SimpleLogItem.cs | 56 ++ Triangle.NET/Triangle/Mesh.cs | 41 +- Triangle.NET/Triangle/Quality.cs | 8 +- Triangle.NET/Triangle/Sampler.cs | 32 +- Triangle.NET/Triangle/Smoothing/ISmoother.cs | 21 + Triangle.NET/Triangle/Statistic.cs | 518 +++++++----------- Triangle.NET/Triangle/Triangle.csproj | 5 +- 22 files changed, 624 insertions(+), 449 deletions(-) create mode 100644 Triangle.NET/Triangle/Log/ILogItem.cs rename Triangle.NET/Triangle/Log/{SimpleLogger.cs => SimpleLog.cs} (60%) create mode 100644 Triangle.NET/Triangle/Log/SimpleLogItem.cs create mode 100644 Triangle.NET/Triangle/Smoothing/ISmoother.cs diff --git a/Triangle.NET/TestApp/Form1.cs b/Triangle.NET/TestApp/Form1.cs index d9dc928..78cbdce 100644 --- a/Triangle.NET/TestApp/Form1.cs +++ b/Triangle.NET/TestApp/Form1.cs @@ -97,7 +97,7 @@ namespace TestApp meshRenderer1.SetData(mesh, false); - statistic.Update(mesh); + statistic.Update(mesh, 10); if (formStats != null && !formStats.IsDisposed) { @@ -121,7 +121,7 @@ namespace TestApp { if (Directory.Exists(@"..\..\..\Data\")) { - dlgDirectory = @"..\..\..\Data\"; + dlgDirectory = Path.GetFullPath(@"..\..\..\Data\"); //Examples.Example1(); //Examples.Example2(); @@ -129,7 +129,7 @@ namespace TestApp } else if (Directory.Exists(@"Data\")) { - dlgDirectory = @"Data\"; + dlgDirectory = Path.GetFullPath(@"Data\"); } } @@ -217,7 +217,7 @@ namespace TestApp meshRenderer1.SetData(mesh, false); - statistic.Update(mesh); + statistic.Update(mesh, 10); if (formStats != null && !formStats.IsDisposed) { diff --git a/Triangle.NET/Triangle/Algorithm/Dwyer.cs b/Triangle.NET/Triangle/Algorithm/Dwyer.cs index c8cfec6..ee1c11a 100644 --- a/Triangle.NET/Triangle/Algorithm/Dwyer.cs +++ b/Triangle.NET/Triangle/Algorithm/Dwyer.cs @@ -849,7 +849,9 @@ namespace TriangleNet.Algorithm { if (Behavior.Verbose) { - SimpleLogger.Instance.Warning("A duplicate vertex appeared and was ignored.", "DivConquer.DivconqDelaunay()"); + SimpleLog.Instance.Warning( + String.Format("A duplicate vertex appeared and was ignored (ID {0}).", sortarray[j].Hash), + "DivConquer.DivconqDelaunay()"); } sortarray[j].type = VertexType.UndeadVertex; m.undeads++; diff --git a/Triangle.NET/Triangle/Algorithm/Incremental.cs b/Triangle.NET/Triangle/Algorithm/Incremental.cs index 73bd4e5..15622d2 100644 --- a/Triangle.NET/Triangle/Algorithm/Incremental.cs +++ b/Triangle.NET/Triangle/Algorithm/Incremental.cs @@ -170,7 +170,7 @@ namespace TriangleNet.Algorithm { if (Behavior.Verbose) { - SimpleLogger.Instance.Warning("A duplicate vertex appeared and was ignored.", + SimpleLog.Instance.Warning("A duplicate vertex appeared and was ignored.", "Incremental.IncrementalDelaunay()"); } v.type = VertexType.UndeadVertex; diff --git a/Triangle.NET/Triangle/Algorithm/SweepLine.cs b/Triangle.NET/Triangle/Algorithm/SweepLine.cs index f3085ea..52b4538 100644 --- a/Triangle.NET/Triangle/Algorithm/SweepLine.cs +++ b/Triangle.NET/Triangle/Algorithm/SweepLine.cs @@ -583,7 +583,7 @@ namespace TriangleNet.Algorithm { if (heapsize == 0) { - SimpleLogger.Instance.Error("Input vertices are all identical.", "SweepLine.SweepLineDelaunay()"); + SimpleLog.Instance.Error("Input vertices are all identical.", "SweepLine.SweepLineDelaunay()"); throw new Exception("Input vertices are all identical."); } secondvertex = eventheap[0].vertexEvent; @@ -594,7 +594,7 @@ namespace TriangleNet.Algorithm { if (Behavior.Verbose) { - SimpleLogger.Instance.Warning("A duplicate vertex appeared and was ignored.", + SimpleLog.Instance.Warning("A duplicate vertex appeared and was ignored.", "SweepLine.SweepLineDelaunay().1"); } secondvertex.type = VertexType.UndeadVertex; @@ -650,7 +650,7 @@ namespace TriangleNet.Algorithm { if (Behavior.Verbose) { - SimpleLogger.Instance.Warning("A duplicate vertex appeared and was ignored.", + SimpleLog.Instance.Warning("A duplicate vertex appeared and was ignored.", "SweepLine.SweepLineDelaunay().2"); } nextvertex.type = VertexType.UndeadVertex; diff --git a/Triangle.NET/Triangle/BadTriQueue.cs b/Triangle.NET/Triangle/BadTriQueue.cs index db47b18..f7fd187 100644 --- a/Triangle.NET/Triangle/BadTriQueue.cs +++ b/Triangle.NET/Triangle/BadTriQueue.cs @@ -17,7 +17,7 @@ namespace TriangleNet { static readonly double SQRT2 = 1.4142135623730950488016887242096980785696718753769480732; - public List badtriangles; + public int Count { get { return this.count; } } // Variables that maintain the bad triangle queues. The queues are // ordered from 4095 (highest priority) to 0 (lowest priority). @@ -27,15 +27,19 @@ namespace TriangleNet int[] nextnonemptyq;//[4096]; int firstnonemptyq; + int count; + public BadTriQueue() { - badtriangles = new List(); + //badtriangles = new List(); queuefront = new BadTriangle[4096]; queuetail = new BadTriangle[4096]; nextnonemptyq = new int[4096]; firstnonemptyq = -1; + + count = 0; } #region Queue @@ -57,6 +61,8 @@ namespace TriangleNet int posexponent; int i; + this.count++; + // Determine the appropriate queue to put the bad triangle into. // Recall that the key is the square of its shortest edge length. if (badtri.key >= 1.0) @@ -166,7 +172,7 @@ namespace TriangleNet Vertex dest = enqtri.Dest(); Vertex apex = enqtri.Apex(); - badtriangles.Add(newbad); + //badtriangles.Add(newbad); Enqueue(newbad); } @@ -184,6 +190,9 @@ namespace TriangleNet { return null; } + + this.count--; + // Find the first triangle of the highest-priority queue. result = queuefront[firstnonemptyq]; // Remove the triangle from the queue. diff --git a/Triangle.NET/Triangle/Behavior.cs b/Triangle.NET/Triangle/Behavior.cs index fab900d..7f0a13b 100644 --- a/Triangle.NET/Triangle/Behavior.cs +++ b/Triangle.NET/Triangle/Behavior.cs @@ -51,12 +51,12 @@ namespace TriangleNet RegionAttrib = false; Convex = false; Jettison = false; - UseBoundaryMarkers = false; + UseBoundaryMarkers = true; NoHoles = false; NoExact = false; ConformDel = false; Algorithm = TriangulationAlgorithm.Dwyer; - Verbose = false; + Verbose = true; UseSegments = true; NoBisect = 0; diff --git a/Triangle.NET/Triangle/Data/Subseg.cs b/Triangle.NET/Triangle/Data/Subseg.cs index 93a151d..7551d54 100644 --- a/Triangle.NET/Triangle/Data/Subseg.cs +++ b/Triangle.NET/Triangle/Data/Subseg.cs @@ -27,13 +27,13 @@ namespace TriangleNet.Data internal int Hash; // The ID is only used for mesh output. - public int ID; + //public int ID; public Osub[] subsegs; public Vertex[] vertices; public Otri[] triangles; public int boundary; - public int segment; + //public int segment; public Subseg() { diff --git a/Triangle.NET/Triangle/Data/Vertex.cs b/Triangle.NET/Triangle/Data/Vertex.cs index c005be8..83223ba 100644 --- a/Triangle.NET/Triangle/Data/Vertex.cs +++ b/Triangle.NET/Triangle/Data/Vertex.cs @@ -50,28 +50,6 @@ namespace TriangleNet.Data } } - public static bool operator ==(Vertex a, Vertex b) - { - // If vertex is null return false. - if ((object)a == null) - { - return false; - } - - return a.Equals(b); - } - - public static bool operator !=(Vertex a, Vertex b) - { - // If vertex is null return false. - if ((object)a == null) - { - return false; - } - - return !a.Equals(b); - } - /// /// Gets the specified coordinate of the vertex. /// @@ -110,31 +88,53 @@ namespace TriangleNet.Data hashSeed = value; } - public override int GetHashCode() - { - return this.Hash; - } + #region Operator overloading / overriding Equals - public override bool Equals(object obj) - { - Vertex v = obj as Vertex; + // Compare "Guidelines for Overriding Equals() and Operator ==" + // http://msdn.microsoft.com/en-us/library/ms173147.aspx - if (v == null) - { - return false; - } - - return this.Equals(v); - } - - public bool Equals(Vertex v) + public static bool operator ==(Vertex a, Vertex b) { // If both are null, or both are same instance, return true. - if (object.ReferenceEquals(this, v)) + if (Object.ReferenceEquals(a, b)) { return true; } + // If one is null, but not both, return false. + if (((object)a == null) || ((object)b == null)) + { + return false; + } + + return a.Equals(b); + } + + public static bool operator !=(Vertex a, Vertex b) + { + return !(a == b); + } + + public override bool Equals(object obj) + { + // If parameter is null return false. + if (obj == null) + { + return false; + } + + Vertex v = obj as Vertex; + + if ((object)v == null) + { + return false; + } + + return this.pt.Equals(v.pt); + } + + public bool Equals(Vertex v) + { // If vertex is null return false. if ((object)v == null) { @@ -145,6 +145,12 @@ namespace TriangleNet.Data return this.pt.Equals(v.pt); } + public override int GetHashCode() + { + return this.Hash; + } + + #endregion public override string ToString() { diff --git a/Triangle.NET/Triangle/IO/DataReader.cs b/Triangle.NET/Triangle/IO/DataReader.cs index 438603e..c153375 100644 --- a/Triangle.NET/Triangle/IO/DataReader.cs +++ b/Triangle.NET/Triangle/IO/DataReader.cs @@ -20,12 +20,6 @@ namespace TriangleNet.IO /// public static class DataReader { - class StackTri - { - public Otri tri = default(Otri); - public StackTri next; - } - #region Library /// @@ -134,7 +128,7 @@ namespace TriangleNet.IO corner[j] = input.Triangles[i][j]; if ((corner[j] < 0) || (corner[j] >= mesh.invertices)) { - SimpleLogger.Instance.Error("Triangle has an invalid vertex index.", "MeshReader.Reconstruct()"); + SimpleLog.Instance.Error("Triangle has an invalid vertex index.", "MeshReader.Reconstruct()"); throw new Exception("Triangle has an invalid vertex index."); } } @@ -242,7 +236,7 @@ namespace TriangleNet.IO { if ((end[j] < 0) || (end[j] >= mesh.invertices)) { - SimpleLogger.Instance.Error("Segment has an invalid vertex index.", "MeshReader.Reconstruct()"); + SimpleLog.Instance.Error("Segment has an invalid vertex index.", "MeshReader.Reconstruct()"); throw new Exception("Segment has an invalid vertex index."); } } diff --git a/Triangle.NET/Triangle/IO/DataWriter.cs b/Triangle.NET/Triangle/IO/DataWriter.cs index 07add23..6b28a7b 100644 --- a/Triangle.NET/Triangle/IO/DataWriter.cs +++ b/Triangle.NET/Triangle/IO/DataWriter.cs @@ -170,6 +170,20 @@ namespace TriangleNet.IO i++; } + + n = mesh.holes.Count; + + if (n > 0) + { + data.Holes = new double[n][]; + + i = 0; + foreach (var hole in mesh.holes) + { + data.Holes[i] = new double[] { hole.X, hole.Y }; + i++; + } + } } /// @@ -281,7 +295,7 @@ namespace TriangleNet.IO /// /// Gets the Voronoi diagram as raw output data. /// - /// + /// /// /// /// The Voronoi diagram is the geometric dual of the Delaunay triangulation. @@ -292,7 +306,7 @@ namespace TriangleNet.IO /// WARNING: In order to assign numbers to the Voronoi vertices, this /// procedure messes up the subsegments or the extra nodes of every /// element. Hence, you should call this procedure last. - public static VoronoiData WriteVoronoi(Mesh m) + public static VoronoiData WriteVoronoi(Mesh mesh) { VoronoiData data = new VoronoiData(); @@ -302,15 +316,29 @@ namespace TriangleNet.IO double xi = 0, eta = 0; int p1, p2; + int i = 0; + + // Copy input points (actually not part of the voronoi diagram) + data.InputPoints = new double[mesh.vertices.Count][]; + + foreach (var item in mesh.vertices.Values) + { + if (item.type != VertexType.UndeadVertex) + { + data.InputPoints[i] = new double[] { item.pt.X, item.pt.Y }; + i++; + } + } + // Allocate memory for Voronoi vertices. - data.PointList = new double[m.triangles.Count][]; + data.Points = new double[mesh.triangles.Count][]; int index = 0; tri.orient = 0; - int i = 0; - foreach (var item in m.triangles.Values) + i = 0; + foreach (var item in mesh.triangles.Values) { tri.triangle = item; torg = tri.Org(); @@ -319,17 +347,17 @@ namespace TriangleNet.IO circumcenter = Primitives.FindCircumcenter(torg.pt, tdest.pt, tapex.pt, ref xi, ref eta, false); // X and y coordinates. - data.PointList[i] = new double[] { circumcenter.X, circumcenter.Y }; + data.Points[i] = new double[] { circumcenter.X, circumcenter.Y }; // Update element id tri.triangle.ID = i++; } // Allocate memory for output Voronoi edges. - data.EdgeList = new int[m.edges][]; + data.Edges = new int[mesh.edges][]; // Allocate memory for output Voronoi norms. - data.NormList = new double[m.edges][]; + data.Directions = new double[mesh.edges][]; index = 0; // To loop over the set of edges, loop over all triangles, and look at @@ -338,7 +366,7 @@ namespace TriangleNet.IO // adjacent triangle, operate on the edge only if the current triangle // has a smaller pointer than its neighbor. This way, each edge is // considered only once. - foreach (var item in m.triangles.Values) + foreach (var item in mesh.triangles.Values) { tri.triangle = item; @@ -356,8 +384,8 @@ namespace TriangleNet.IO tdest = tri.Dest(); // Copy an infinite ray. Index of one endpoint, and -1. - data.EdgeList[index] = new int[] { p1, -1}; - data.NormList[index] = new double[] { tdest[1] - torg[1], torg[0] - tdest[0] }; + data.Edges[index] = new int[] { p1, -1}; + data.Directions[index] = new double[] { tdest[1] - torg[1], torg[0] - tdest[0] }; } else { @@ -365,8 +393,8 @@ namespace TriangleNet.IO p2 = trisym.triangle.ID; // Finite edge. Write indices of two endpoints. - data.EdgeList[index] = new int[] { p1, p2 }; - data.NormList[index] = new double[] { 0, 0 }; + data.Edges[index] = new int[] { p1, p2 }; + data.Directions[index] = new double[] { 0, 0 }; } index++; diff --git a/Triangle.NET/Triangle/IO/FileReader.cs b/Triangle.NET/Triangle/IO/FileReader.cs index 676846a..4b8104c 100644 --- a/Triangle.NET/Triangle/IO/FileReader.cs +++ b/Triangle.NET/Triangle/IO/FileReader.cs @@ -393,7 +393,7 @@ namespace TriangleNet.IO { if (Behavior.Verbose) { - SimpleLogger.Instance.Warning("Invalid first endpoint of segment.", + SimpleLog.Instance.Warning("Invalid first endpoint of segment.", "MeshReader.ReadPolyfile()"); } } @@ -401,7 +401,7 @@ namespace TriangleNet.IO { if (Behavior.Verbose) { - SimpleLogger.Instance.Warning("Invalid second endpoint of segment.", + SimpleLog.Instance.Warning("Invalid second endpoint of segment.", "MeshReader.ReadPolyfile()"); } } @@ -489,6 +489,15 @@ namespace TriangleNet.IO return data; } + public static MeshData ReadEleFile(string elefilename) + { + MeshData data = new MeshData(); + + ReadEleFile(elefilename, data, false); + + return data; + } + /// /// Read the elements from an .ele file. /// @@ -590,7 +599,7 @@ namespace TriangleNet.IO if (int.Parse(line[0]) != intriangles) { - SimpleLogger.Instance.Warning("Number of area constraints doesn't match number of triangles.", + SimpleLog.Instance.Warning("Number of area constraints doesn't match number of triangles.", "ReadAreaFile()"); return; } @@ -614,5 +623,100 @@ namespace TriangleNet.IO } } } + + public static MeshData ReadEdgeFile(string edgeFile) + { + // Read poly file + MeshData data = new MeshData(); + + startIndex = 0; + + string[] line; + + using (StreamReader reader = new StreamReader(edgeFile)) + { + // Read the edges from a .edge file. + + // Read number of segments and number of boundary markers. + if (!TryReadLine(reader, out line)) + { + throw new Exception("Can't read input file (segments)."); + } + + int inedges = int.Parse(line[0]); + + int edgemarkers = 0; + if (line.Length > 1) + { + edgemarkers = int.Parse(line[1]); + } + + if (inedges > 0) + { + data.Edges = new int[inedges][]; + } + + if (edgemarkers > 0) + { + data.EdgeMarkers = new int[inedges]; + } + + int end1, end2; + // Read and insert the segments. + for (int i = 0; i < inedges; i++) + { + if (!TryReadLine(reader, out line)) + { + throw new Exception("Can't read input file (segments)."); + } + + if (line.Length < 3) + { + throw new Exception("Segment has no endpoints."); + } + + // TODO: startIndex ok? + end1 = int.Parse(line[1]) - startIndex; + end2 = int.Parse(line[2]) - startIndex; + + if (edgemarkers > 0) + { + if (line.Length > 3) + { + data.SegmentMarkers[i] = int.Parse(line[3]); + } + else + { + data.SegmentMarkers[i] = 0; + } + } + + data.Segments[i] = new int[] { end1, end2 }; + + //if ((end1 < 0) || (end1 >= invertices)) + //{ + // if (Behavior.Verbose) + // { + // SimpleLogger.Instance.Warning("Invalid first endpoint of segment.", + // "MeshReader.ReadPolyfile()"); + // } + //} + //else if ((end2 < 0) || (end2 >= invertices)) + //{ + // if (Behavior.Verbose) + // { + // SimpleLogger.Instance.Warning("Invalid second endpoint of segment.", + // "MeshReader.ReadPolyfile()"); + // } + //} + //else + //{ + // data.Segments[i] = new int[] { end1, end2 }; + //} + } + } + + return data; + } } } diff --git a/Triangle.NET/Triangle/IO/VoronoiData.cs b/Triangle.NET/Triangle/IO/VoronoiData.cs index 5094411..905d6ba 100644 --- a/Triangle.NET/Triangle/IO/VoronoiData.cs +++ b/Triangle.NET/Triangle/IO/VoronoiData.cs @@ -8,17 +8,15 @@ namespace TriangleNet.IO { /// - /// Stores the mesh data in- and output. + /// Stores the voronoi data (output only). /// public class VoronoiData { - public double[][] PointList; // In / out - //public int NumberOfPoints; // In / out - - public int[][] EdgeList; // Out only - //public int NumberOfEdges; // Out only + public double[][] InputPoints; + public double[][] Points; + public int[][] Edges; // Stores the direction for infinite voronoi edges - public double[][] NormList; + public double[][] Directions; } } diff --git a/Triangle.NET/Triangle/Log/ILog.cs b/Triangle.NET/Triangle/Log/ILog.cs index 2dd6ce9..3675642 100644 --- a/Triangle.NET/Triangle/Log/ILog.cs +++ b/Triangle.NET/Triangle/Log/ILog.cs @@ -11,17 +11,27 @@ namespace TriangleNet.Log using System.Linq; using System.Text; + public enum LogLevel + { + Info = 0, + Warning = 1, + Error = 2 + } + /// - /// TODO: Update summary. + /// A basic log interface. /// - public interface ILog + public interface ILog where T : ILogItem { void Add(T item); + void Clear(); + void Info(string message); - void Trace(string message, string location); - void Error(string message, string location); - void Warning(string message, string location); + void Error(string message, string info); + void Warning(string message, string info); IList Data { get; } + + LogLevel Level { get; } } } diff --git a/Triangle.NET/Triangle/Log/ILogItem.cs b/Triangle.NET/Triangle/Log/ILogItem.cs new file mode 100644 index 0000000..9bf755f --- /dev/null +++ b/Triangle.NET/Triangle/Log/ILogItem.cs @@ -0,0 +1,24 @@ +// ----------------------------------------------------------------------- +// +// Triangle.NET code by Christian Woltering, http://home.edo.tu-dortmund.de/~woltering/triangle/ +// +// ----------------------------------------------------------------------- + +namespace TriangleNet.Log +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + + /// + /// A basic log item interface. + /// + public interface ILogItem + { + DateTime Time { get; } + LogLevel Level { get; } + string Message { get; } + string Info { get; } + } +} diff --git a/Triangle.NET/Triangle/Log/SimpleLogger.cs b/Triangle.NET/Triangle/Log/SimpleLog.cs similarity index 60% rename from Triangle.NET/Triangle/Log/SimpleLogger.cs rename to Triangle.NET/Triangle/Log/SimpleLog.cs index 5011654..2ee2269 100644 --- a/Triangle.NET/Triangle/Log/SimpleLogger.cs +++ b/Triangle.NET/Triangle/Log/SimpleLog.cs @@ -17,21 +17,23 @@ namespace TriangleNet.Log /// Using singleton pattern as proposed by Jon Skeet. /// http://csharpindepth.com/Articles/General/Singleton.aspx /// - public sealed class SimpleLogger : ILog + public sealed class SimpleLog : ILog { - private List log = new List(); + private List log = new List(); + + private LogLevel level = LogLevel.Info; #region Singleton pattern - private static readonly SimpleLogger instance = new SimpleLogger(); + private static readonly SimpleLog instance = new SimpleLog(); // Explicit static constructor to tell C# compiler // not to mark type as beforefieldinit - static SimpleLogger() { } + static SimpleLog() { } - private SimpleLogger() { } + private SimpleLog() { } - public static ILog Instance + public static ILog Instance { get { @@ -41,34 +43,39 @@ namespace TriangleNet.Log #endregion - public void Add(string item) + public void Add(SimpleLogItem item) { log.Add(item); } - public void Info(string message) + public void Clear() { - log.Add(message); + log.Clear(); } - public void Trace(string message, string location) + public void Info(string message) { - log.Add(message); + log.Add(new SimpleLogItem(LogLevel.Info, message)); } public void Warning(string message, string location) { - log.Add(message); + log.Add(new SimpleLogItem(LogLevel.Warning, message, location)); } public void Error(string message, string location) { - log.Add(message); + log.Add(new SimpleLogItem(LogLevel.Error, message, location)); } - public IList Data + public IList Data { get { return log; } } + + public LogLevel Level + { + get { return level; } + } } } diff --git a/Triangle.NET/Triangle/Log/SimpleLogItem.cs b/Triangle.NET/Triangle/Log/SimpleLogItem.cs new file mode 100644 index 0000000..b48828e --- /dev/null +++ b/Triangle.NET/Triangle/Log/SimpleLogItem.cs @@ -0,0 +1,56 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace TriangleNet.Log +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + + /// + /// TODO: Update summary. + /// + public class SimpleLogItem : ILogItem + { + DateTime time; + LogLevel level; + string message; + string info; + + public DateTime Time + { + get { return time; } + } + + public LogLevel Level + { + get { return level; } + } + + public string Message + { + get { return message; } + } + + public string Info + { + get { return info; } + } + + public SimpleLogItem(LogLevel level, string message) + : this(level, message, "") + { } + + public SimpleLogItem(LogLevel level, string message, string info) + { + this.time = DateTime.Now; + this.level = level; + this.message = message; + this.info = info; + } + } +} diff --git a/Triangle.NET/Triangle/Mesh.cs b/Triangle.NET/Triangle/Mesh.cs index ece6457..ac5daee 100644 --- a/Triangle.NET/Triangle/Mesh.cs +++ b/Triangle.NET/Triangle/Mesh.cs @@ -14,6 +14,7 @@ namespace TriangleNet using TriangleNet.Log; using TriangleNet.IO; using TriangleNet.Algorithm; + using TriangleNet.Smoothing; /// /// Mesh data structure. @@ -22,7 +23,7 @@ namespace TriangleNet { #region Variables - ILog logger; + ILog logger; Quality quality; Sampler sampler; @@ -49,11 +50,11 @@ namespace TriangleNet internal int inelements; // Number of input triangles. internal int insegments; // Number of input segments. internal int undeads; // Number of input vertices that don't appear in the mesh. - internal long edges; // Number of output edges. + internal int edges; // Number of output edges. internal int mesh_dim; // Dimension (ought to be 2). internal int nextras; // Number of attributes per vertex. internal int eextras; // Number of attributes per triangle. - internal long hullsize; // Number of edges in convex hull. + internal int hullsize; // Number of edges in convex hull. internal int steinerleft; // Number of Steiner points not yet used. internal bool checksegments; // Are there segments in the triangulation yet? internal bool checkquality; // Has quality triangulation begun yet? @@ -84,7 +85,7 @@ namespace TriangleNet public Mesh() { - logger = SimpleLogger.Instance; + logger = SimpleLog.Instance; Behavior.Init(); @@ -266,8 +267,6 @@ namespace TriangleNet quality.EnforceQuality(); // Enforce angle and area constraints. } - quality.CheckMesh(); - // Calculate the number of edges. edges = (3 * triangles.Count + hullsize) / 2; } @@ -357,8 +356,8 @@ namespace TriangleNet } // TODO - holes.Clear(); - regions.Clear(); + //holes.Clear(); + //regions.Clear(); if (triangles.Count > 0) { @@ -370,6 +369,15 @@ namespace TriangleNet edges = (3 * triangles.Count + hullsize) / 2; } + /// + /// Smooth the current mesh. + /// + public void Smooth() + { + //ISmoother smoother = new CvdSmoother(this); + //smoother.Smooth(); + } + /// /// Check mesh consistency and (constrained) Delaunay property. /// @@ -626,6 +634,9 @@ namespace TriangleNet triangles.Clear(); subsegs.Clear(); + holes.Clear(); + regions.Clear(); + Triangle.ResetHashSeed(0); Vertex.ResetHashSeed(0); Subseg.ResetHashSeed(0); @@ -633,6 +644,13 @@ namespace TriangleNet viri.Clear(); flipstackers.Clear(); + hullsize = 0; + xmin = 0; + xmax = 0; + ymin = 0; + ymax = 0; + edges = 0; + Reset(); } @@ -2300,7 +2318,7 @@ namespace TriangleNet // TODO: Improve sampling. sampler.Update(this); - int[] samples = sampler.GetSamples(); + int[] samples = sampler.GetSamples(this); foreach (var key in samples) { @@ -2473,7 +2491,6 @@ namespace TriangleNet double tx, ty; double etx, ety; double split, denom; - int i; // Find the other three segment endpoints. endpoint1 = splittri.Apex(); @@ -2990,15 +3007,15 @@ namespace TriangleNet void InsertSegment(Vertex endpoint1, Vertex endpoint2, int newmark) { Otri searchtri1 = default(Otri), searchtri2 = default(Otri); - Vertex checkvertex; + Vertex checkvertex = null; // Find a triangle whose origin is the segment's first endpoint. - checkvertex = null; searchtri1 = endpoint1.tri; if (searchtri1.triangle != null) { checkvertex = searchtri1.Org(); } + if (checkvertex != endpoint1) { // Find a boundary triangle to search from. diff --git a/Triangle.NET/Triangle/Quality.cs b/Triangle.NET/Triangle/Quality.cs index 44beb91..a094ae0 100644 --- a/Triangle.NET/Triangle/Quality.cs +++ b/Triangle.NET/Triangle/Quality.cs @@ -22,11 +22,11 @@ namespace TriangleNet Mesh mesh; Func userTest; - ILog logger; + ILog logger; public Quality(Mesh m) { - logger = SimpleLogger.Instance; + logger = SimpleLog.Instance; badsubsegs = new Queue(); queue = new BadTriQueue(); @@ -957,7 +957,7 @@ namespace TriangleNet TallyFaces(); mesh.checkquality = true; - while ((queue.badtriangles.Count > 0) && (mesh.steinerleft != 0)) + while ((queue.Count > 0) && (mesh.steinerleft != 0)) { // Fix one bad triangle by inserting a vertex at its circumcenter. badtri = queue.Dequeue(); @@ -974,7 +974,7 @@ namespace TriangleNet else { // Return the bad triangle to the pool. - queue.badtriangles.Remove(badtri); + //queue.badtriangles.Remove(badtri); } } } diff --git a/Triangle.NET/Triangle/Sampler.cs b/Triangle.NET/Triangle/Sampler.cs index 5b12004..3176e01 100644 --- a/Triangle.NET/Triangle/Sampler.cs +++ b/Triangle.NET/Triangle/Sampler.cs @@ -35,11 +35,20 @@ namespace TriangleNet /// /// Current mesh. public void Update(Mesh mesh) + { + this.Update(mesh, false); + } + + /// + /// Update sampling parameters if mesh changed. + /// + /// Current mesh. + public void Update(Mesh mesh, bool forceUpdate) { int count = mesh.triangles.Count; // TODO: Is checking the triangle count a good way to monitor mesh changes? - if (triangleCount != count) + if (triangleCount != count || forceUpdate) { triangleCount = count; @@ -61,20 +70,33 @@ namespace TriangleNet /// Get a random sample set of triangle keys. /// /// Array of triangle keys. - public int[] GetSamples() + public int[] GetSamples(Mesh mesh) { - int[] randSamples = new int[samples]; + // TODO: Using currKeys to check key availability? + List randSamples = new List(samples); int range = triangleCount / samples; + int key; for (int i = 0; i < samples; i++) { // Yeah, rand should be equally distributed, but just to make // sure, use a range variable... - randSamples[i] = keys[rand.Next(i * range, (i + 1) * range - 1)]; + key = rand.Next(i * range, (i + 1) * range - 1); + + if (!mesh.triangles.Keys.Contains(keys[key])) + { + // Keys collection isn't up to date anymore! + this.Update(mesh, true); + i--; + } + else + { + randSamples.Add(keys[key]); + } } - return randSamples; + return randSamples.ToArray(); } } } diff --git a/Triangle.NET/Triangle/Smoothing/ISmoother.cs b/Triangle.NET/Triangle/Smoothing/ISmoother.cs new file mode 100644 index 0000000..6ced65c --- /dev/null +++ b/Triangle.NET/Triangle/Smoothing/ISmoother.cs @@ -0,0 +1,21 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace TriangleNet.Smoothing +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + + /// + /// TODO: Update summary. + /// + public interface ISmoother + { + void Smooth(); + } +} diff --git a/Triangle.NET/Triangle/Statistic.cs b/Triangle.NET/Triangle/Statistic.cs index f98bb60..150c87a 100644 --- a/Triangle.NET/Triangle/Statistic.cs +++ b/Triangle.NET/Triangle/Statistic.cs @@ -49,7 +49,7 @@ namespace TriangleNet public static long CircleTopCount = 0; /// - /// Number of vertex relocation. + /// Number of vertex relocations. /// public static long RelocationCount = 0; @@ -59,191 +59,199 @@ namespace TriangleNet double minEdge = 0; /// - /// Shortest edge + /// Gets the shortest edge. /// public double ShortestEdge { get { return minEdge; } } double maxEdge = 0; /// - /// Longest edge + /// Gets the longest edge. /// public double LongestEdge { get { return maxEdge; } } // double minAspect = 0; /// - /// Shortest altitude + /// Gets the shortest altitude. /// public double ShortestAltitude { get { return minAspect; } } double maxAspect = 0; /// - /// Largest aspect ratio + /// Gets the largest aspect ratio. /// public double LargestAspectRatio { get { return maxAspect; } } double minArea = 0; /// - /// Smallest area + /// Gets the smallest area. /// public double SmallestArea { get { return minArea; } } double maxArea = 0; /// - /// Largest area + /// Gets the largest area. /// public double LargestArea { get { return maxArea; } } double minAngle = 0; /// - /// Smallest angle + /// Gets the smallest angle. /// public double SmallestAngle { get { return minAngle; } } double maxAngle = 0; /// - /// Largest angle + /// Gets the largest angle. /// public double LargestAngle { get { return maxAngle; } } int inVetrices = 0; /// - /// Input vertices + /// Gets the number of input vertices. /// public int InputVertices { get { return inVetrices; } } int inTriangles = 0; /// - /// Input triangles + /// Gets the number of input triangles. /// public int InputTriangles { get { return inTriangles; } } int inSegments = 0; /// - /// Input segments + /// Gets the number of input segments. /// public int InputSegments { get { return inSegments; } } int inHoles = 0; /// - /// Input holes + /// Gets the number of input holes. /// public int InputHoles { get { return inHoles; } } int outVertices = 0; /// - /// Mesh vertices + /// Gets the number of mesh vertices. /// public int Vertices { get { return outVertices; } } int outTriangles = 0; /// - /// Mesh triangles + /// Gets the number of mesh triangles. /// public int Triangles { get { return outTriangles; } } int outEdges = 0; /// - /// Mesh edges + /// Gets the number of mesh edges. /// public int Edges { get { return outEdges; } } int boundaryEdges = 0; /// - /// Exterior boundary edges + /// Gets the number of exterior boundary edges. /// public int BoundaryEdges { get { return boundaryEdges; } } int intBoundaryEdges = 0; /// - /// Interior boundary edges + /// Gets the number of interior boundary edges. /// public int InteriorBoundaryEdges { get { return intBoundaryEdges; } } int constrainedEdges = 0; /// - /// Constrained edges + /// Gets the number of constrained edges. /// public int ConstrainedEdges { get { return constrainedEdges; } } int[] angleTable; /// - /// Angle histogram + /// Gets the angle histogram. /// public int[] AngleHistogram { get { return angleTable; } } + int[] minAngles; + /// + /// Gets the min angles histogram. + /// + public int[] MinAngleHistogram { get { return minAngles; } } + + int[] maxAngles; + /// + /// Gets the max angles histogram. + /// + public int[] MaxAngleHistogram { get { return maxAngles; } } + #endregion - /// - /// detailedHistogram() - /// - /// - void detailedHistogram(Mesh m) + #region Private methods + + private void GetAspectHistogram(Mesh mesh) { + int[] aspecttable; + double[] ratiotable; + + aspecttable = new int[16]; + ratiotable = new double[] { + 1.5, 2.0, 2.5, 3.0, 4.0, 6.0, 10.0, 15.0, 25.0, 50.0, + 100.0, 300.0, 1000.0, 10000.0, 100000.0, 0.0 }; + + + Otri tri = default(Otri); Vertex[] p = new Vertex[3]; - double[] cosSquareTable = new double[8]; double[] dx = new double[3], dy = new double[3]; double[] edgelength = new double[3]; - double dotproduct; - double cosSquare; + double triarea; + double trilongest2; + double triminaltitude2; + double triaspect2; - int i, ii, j, k; - double[] cossquaretableHist = new double[89]; - double radconstHist; - int onedegree; - int[] angletableHist = new int[180]; + int aspectindex; + int i, j, k; - radconstHist = Math.PI / 180.0; - for (i = 0; i < 89; i++) + tri.orient = 0; + foreach (var t in mesh.triangles.Values) { - cossquaretableHist[i] = Math.Cos(radconstHist * (i + 1)); - cossquaretableHist[i] = cossquaretableHist[i] * cossquaretableHist[i]; - } - for (i = 0; i < 180; i++) - { - angletableHist[i] = 0; - } - - foreach (var tri in m.triangles.Values) - { - p[0] = tri.vertices[0]; - p[1] = tri.vertices[1]; - p[2] = tri.vertices[2]; + tri.triangle = t; + p[0] = tri.Org(); + p[1] = tri.Dest(); + p[2] = tri.Apex(); + trilongest2 = 0.0; for (i = 0; i < 3; i++) { j = plus1Mod3[i]; k = minus1Mod3[i]; - dx[i] = p[j][0] - p[k][0]; - dy[i] = p[j][1] - p[k][1]; + dx[i] = p[j].pt.X - p[k].pt.X; + dy[i] = p[j].pt.Y - p[k].pt.Y; edgelength[i] = dx[i] * dx[i] + dy[i] * dy[i]; + if (edgelength[i] > trilongest2) + { + trilongest2 = edgelength[i]; + } } - for (i = 0; i < 3; i++) + + //triarea = Primitives.CounterClockwise(p[0], p[1], p[2]); + triarea = Math.Abs((p[2].pt.X - p[0].pt.X) * (p[1].pt.Y - p[0].pt.Y) - + (p[1].pt.X - p[0].pt.X) * (p[2].pt.Y - p[0].pt.Y)) / 2.0; + + triminaltitude2 = triarea * triarea / trilongest2; + + triaspect2 = trilongest2 / triminaltitude2; + + aspectindex = 0; + while ((triaspect2 > ratiotable[aspectindex] * ratiotable[aspectindex]) && (aspectindex < 15)) { - j = plus1Mod3[i]; - k = minus1Mod3[i]; - dotproduct = dx[j] * dx[k] + dy[j] * dy[k]; - cosSquare = dotproduct * dotproduct / (edgelength[j] * edgelength[k]); - onedegree = 89; - for (ii = 88; ii >= 0; ii--) - { - if (cosSquare > cossquaretableHist[ii]) - { - onedegree = ii; - } - } - if (dotproduct <= 0.0) - { - angletableHist[onedegree]++; - } - else - { - angletableHist[179 - onedegree]++; - } + aspectindex++; } + aspecttable[aspectindex]++; } } + #endregion + static readonly int[] plus1Mod3 = { 1, 2, 0 }; static readonly int[] minus1Mod3 = { 2, 0, 1 }; @@ -251,7 +259,7 @@ namespace TriangleNet /// Update statistics about the quality of the mesh. /// /// - public void Update(Mesh mesh) + public void Update(Mesh mesh, int sampleDegrees) { inVetrices = mesh.invertices; inTriangles = mesh.inelements; @@ -267,31 +275,37 @@ namespace TriangleNet Point2[] p = new Point2[3]; int k1, k2; - int tendegree; + int degreeStep; - double[] cosSquareTable = new double[8]; + //sampleDegrees = 36; // sample every 5 degrees + //sampleDegrees = 45; // sample every 4 degrees + sampleDegrees = 60; // sample every 3 degrees + + double[] cosSquareTable = new double[sampleDegrees / 2 - 1]; double[] dx = new double[3]; double[] dy = new double[3]; - double[] edgelength = new double[3]; - double dotproduct; - double cossquare; - double triarea; - double trilongest2; - double triminaltitude2; - double triaspect2; + double[] edgeLength = new double[3]; + double dotProduct; + double cosSquare; + double triArea; + double triLongest2; + double triMinAltitude2; + double triAspect2; - double radconst = Math.PI / 18.0; + double radconst = Math.PI / sampleDegrees; double degconst = 180.0 / Math.PI; // New angle table - angleTable = new int[18]; + angleTable = new int[sampleDegrees]; + minAngles = new int[sampleDegrees]; + maxAngles = new int[sampleDegrees]; - for (int i = 0; i < 8; i++) + for (int i = 0; i < sampleDegrees / 2 - 1; i++) { cosSquareTable[i] = Math.Cos(radconst * (i + 1)); cosSquareTable[i] = cosSquareTable[i] * cosSquareTable[i]; } - for (int i = 0; i < 18; i++) + for (int i = 0; i < sampleDegrees; i++) { angleTable[i] = 0; } @@ -307,14 +321,20 @@ namespace TriangleNet maxAngle = 2.0; bool acuteBiggest = true; + bool acuteBiggestTri = true; + + double triMinAngle, triMaxAngle = 1; foreach (var tri in mesh.triangles.Values) { + triMinAngle = 0; // Min angle: 0 < a < 60 degress + triMaxAngle = 1; // Max angle: 60 < a < 180 degress + p[0] = tri.vertices[0].pt; p[1] = tri.vertices[1].pt; p[2] = tri.vertices[2].pt; - trilongest2 = 0.0; + triLongest2 = 0.0; for (int i = 0; i < 3; i++) { @@ -324,44 +344,48 @@ namespace TriangleNet dx[i] = p[k1].X - p[k2].X; dy[i] = p[k1].Y - p[k2].Y; - edgelength[i] = dx[i] * dx[i] + dy[i] * dy[i]; + edgeLength[i] = dx[i] * dx[i] + dy[i] * dy[i]; - if (edgelength[i] > trilongest2) + if (edgeLength[i] > triLongest2) { - trilongest2 = edgelength[i]; + triLongest2 = edgeLength[i]; } - if (edgelength[i] > maxEdge) + if (edgeLength[i] > maxEdge) { - maxEdge = edgelength[i]; + maxEdge = edgeLength[i]; } - if (edgelength[i] < minEdge) + if (edgeLength[i] < minEdge) { - minEdge = edgelength[i]; + minEdge = edgeLength[i]; } } //triarea = Primitives.CounterClockwise(p[0], p[1], p[2]); - triarea = Math.Abs((p[2].X - p[0].X) * (p[1].Y - p[0].Y) - + triArea = Math.Abs((p[2].X - p[0].X) * (p[1].Y - p[0].Y) - (p[1].X - p[0].X) * (p[2].Y - p[0].Y)); - if (triarea < minArea) + + if (triArea < minArea) { - minArea = triarea; + minArea = triArea; } - if (triarea > maxArea) + + if (triArea > maxArea) { - maxArea = triarea; + maxArea = triArea; } - triminaltitude2 = triarea * triarea / trilongest2; - if (triminaltitude2 < minAspect) + + triMinAltitude2 = triArea * triArea / triLongest2; + if (triMinAltitude2 < minAspect) { - minAspect = triminaltitude2; + minAspect = triMinAltitude2; } - triaspect2 = trilongest2 / triminaltitude2; - if (triaspect2 > maxAspect) + + triAspect2 = triLongest2 / triMinAltitude2; + if (triAspect2 > maxAspect) { - maxAspect = triaspect2; + maxAspect = triAspect2; } for (int i = 0; i < 3; i++) @@ -369,39 +393,91 @@ namespace TriangleNet k1 = plus1Mod3[i]; k2 = minus1Mod3[i]; - dotproduct = dx[k1] * dx[k2] + dy[k1] * dy[k2]; - cossquare = dotproduct * dotproduct / (edgelength[k1] * edgelength[k2]); - tendegree = 8; + dotProduct = dx[k1] * dx[k2] + dy[k1] * dy[k2]; + cosSquare = dotProduct * dotProduct / (edgeLength[k1] * edgeLength[k2]); + degreeStep = sampleDegrees / 2 - 1; - for (int j = 7; j >= 0; j--) + for (int j = degreeStep - 1; j >= 0; j--) { - if (cossquare > cosSquareTable[j]) + if (cosSquare > cosSquareTable[j]) { - tendegree = j; + degreeStep = j; } } - if (dotproduct <= 0.0) + + if (dotProduct <= 0.0) { - angleTable[tendegree]++; - if (cossquare > minAngle) + angleTable[degreeStep]++; + if (cosSquare > minAngle) { - minAngle = cossquare; + minAngle = cosSquare; } - if (acuteBiggest && (cossquare < maxAngle)) + if (acuteBiggest && (cosSquare < maxAngle)) { - maxAngle = cossquare; + maxAngle = cosSquare; + } + + // Update min/max angle per triangle + if (cosSquare > triMinAngle) + { + triMinAngle = cosSquare; + } + if (acuteBiggestTri && (cosSquare < triMaxAngle)) + { + triMaxAngle = cosSquare; } } else { - angleTable[17 - tendegree]++; - if (acuteBiggest || (cossquare > maxAngle)) + angleTable[sampleDegrees - degreeStep - 1]++; + if (acuteBiggest || (cosSquare > maxAngle)) { - maxAngle = cossquare; + maxAngle = cosSquare; acuteBiggest = false; } + + // Update max angle for (possibly non-acute) triangle + if (acuteBiggestTri || (cosSquare > triMaxAngle)) + { + triMaxAngle = cosSquare; + acuteBiggestTri = false; + } } } + + // Update min angle histogram + degreeStep = sampleDegrees / 2 - 1; + + for (int j = degreeStep - 1; j >= 0; j--) + { + if (triMinAngle > cosSquareTable[j]) + { + degreeStep = j; + } + } + minAngles[degreeStep]++; + + // Update max angle histogram + degreeStep = sampleDegrees / 2 - 1; + + for (int j = degreeStep - 1; j >= 0; j--) + { + if (triMaxAngle > cosSquareTable[j]) + { + degreeStep = j; + } + } + + if (acuteBiggestTri) + { + maxAngles[degreeStep]++; + } + else + { + maxAngles[sampleDegrees - degreeStep - 1]++; + } + + acuteBiggestTri = true; } minEdge = Math.Sqrt(minEdge); @@ -418,6 +494,7 @@ namespace TriangleNet { minAngle = degconst * Math.Acos(Math.Sqrt(minAngle)); } + if (maxAngle >= 1.0) { maxAngle = 180.0; @@ -434,208 +511,5 @@ namespace TriangleNet } } } - - /* Original code with aspect ratio - - int[] aspecttable; - double[] ratiotable; - - public Statistic() - { - angletable = new int[18]; - aspecttable = new int[16]; - ratiotable = new double[] { - 1.5, 2.0, 2.5, 3.0, 4.0, 6.0, 10.0, 15.0, 25.0, 50.0, - 100.0, 300.0, 1000.0, 10000.0, 100000.0, 0.0 }; - } - - public void Update(Mesh mesh) - { - inVetrices = mesh.invertices; - inTriangles = mesh.inelements; - inSegments = mesh.insegments; - inHoles = mesh.holes; - outVertices = mesh.vertices.Count - mesh.undeads; - outTriangles = mesh.triangles.Count; - outEdges = (int)mesh.edges; - boundaryEdges = (int)mesh.hullsize; - intBoundaryEdges = mesh.subsegs.Count - (int)mesh.hullsize; - constrainedEdges = mesh.subsegs.Count; - - Otri triangleloop = default(Otri); - Vertex[] p = new Vertex[3]; - double[] cossquaretable = new double[8]; - double[] dx = new double[3], dy = new double[3]; - double[] edgelength = new double[3]; - double dotproduct; - double cossquare; - double triarea; - double trilongest2; - double triminaltitude2; - double triaspect2; - double radconst, degconst; - - int aspectindex; - int tendegree; - bool acutebiggest; - int i, ii, j, k; - - radconst = Math.PI / 18.0; - degconst = 180.0 / Math.PI; - for (i = 0; i < 8; i++) - { - cossquaretable[i] = Math.Cos(radconst * (double)(i + 1)); - cossquaretable[i] = cossquaretable[i] * cossquaretable[i]; - } - for (i = 0; i < 18; i++) - { - angletable[i] = 0; - } - - for (i = 0; i < 16; i++) - { - aspecttable[i] = 0; - } - - worstaspect = 0.0; - minaltitude = mesh.xmax - mesh.xmin + mesh.ymax - mesh.ymin; - minaltitude = minaltitude * minaltitude; - shortest = minaltitude; - longest = 0.0; - smallestarea = minaltitude; - biggestarea = 0.0; - worstaspect = 0.0; - smallestangle = 0.0; - biggestangle = 2.0; - acutebiggest = true; - - triangleloop.orient = 0; - foreach (var t in mesh.triangles) - { - triangleloop.triangle = t; - p[0] = triangleloop.Org(); - p[1] = triangleloop.Dest(); - p[2] = triangleloop.Apex(); - trilongest2 = 0.0; - - for (i = 0; i < 3; i++) - { - j = plus1Mod3[i]; - k = minus1Mod3[i]; - dx[i] = p[j].pt.X - p[k].pt.X; - dy[i] = p[j].pt.Y - p[k].pt.Y; - edgelength[i] = dx[i] * dx[i] + dy[i] * dy[i]; - if (edgelength[i] > trilongest2) - { - trilongest2 = edgelength[i]; - } - if (edgelength[i] > longest) - { - longest = edgelength[i]; - } - if (edgelength[i] < shortest) - { - shortest = edgelength[i]; - } - } - - //triarea = Primitives.CounterClockwise(p[0], p[1], p[2]); - triarea = Math.Abs((p[2].pt.X - p[0].pt.X) * (p[1].pt.Y - p[0].pt.Y) - - (p[1].pt.X - p[0].pt.X) * (p[2].pt.Y - p[0].pt.Y)) / 2.0; - if (triarea < smallestarea) - { - smallestarea = triarea; - } - if (triarea > biggestarea) - { - biggestarea = triarea; - } - triminaltitude2 = triarea * triarea / trilongest2; - if (triminaltitude2 < minaltitude) - { - minaltitude = triminaltitude2; - } - triaspect2 = trilongest2 / triminaltitude2; - if (triaspect2 > worstaspect) - { - worstaspect = triaspect2; - } - aspectindex = 0; - while ((triaspect2 > ratiotable[aspectindex] * ratiotable[aspectindex]) && (aspectindex < 15)) - { - aspectindex++; - } - aspecttable[aspectindex]++; - - for (i = 0; i < 3; i++) - { - j = plus1Mod3[i]; - k = minus1Mod3[i]; - dotproduct = dx[j] * dx[k] + dy[j] * dy[k]; - cossquare = dotproduct * dotproduct / (edgelength[j] * edgelength[k]); - tendegree = 8; - for (ii = 7; ii >= 0; ii--) - { - if (cossquare > cossquaretable[ii]) - { - tendegree = ii; - } - } - if (dotproduct <= 0.0) - { - angletable[tendegree]++; - if (cossquare > smallestangle) - { - smallestangle = cossquare; - } - if (acutebiggest && (cossquare < biggestangle)) - { - biggestangle = cossquare; - } - } - else - { - angletable[17 - tendegree]++; - if (acutebiggest || (cossquare > biggestangle)) - { - biggestangle = cossquare; - acutebiggest = false; - } - } - } - } - - shortest = Math.Sqrt(shortest); - longest = Math.Sqrt(longest); - minaltitude = Math.Sqrt(minaltitude); - worstaspect = Math.Sqrt(worstaspect); - smallestarea *= 0.5; - biggestarea *= 0.5; - if (smallestangle >= 1.0) - { - smallestangle = 0.0; - } - else - { - smallestangle = degconst * Math.Acos(Math.Sqrt(smallestangle)); - } - if (biggestangle >= 1.0) - { - biggestangle = 180.0; - } - else - { - if (acutebiggest) - { - biggestangle = degconst * Math.Acos(Math.Sqrt(biggestangle)); - } - else - { - biggestangle = 180.0 - degconst * Math.Acos(Math.Sqrt(biggestangle)); - } - } - } - - */ } } diff --git a/Triangle.NET/Triangle/Triangle.csproj b/Triangle.NET/Triangle/Triangle.csproj index 0ef6e1c..64c436b 100644 --- a/Triangle.NET/Triangle/Triangle.csproj +++ b/Triangle.NET/Triangle/Triangle.csproj @@ -64,7 +64,9 @@ - + + + @@ -73,6 +75,7 @@ +