+ some minor fixes/changes

git-svn-id: https://triangle.svn.codeplex.com/svn@67039 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
SND\wo80_cp
2012-04-26 14:22:43 +00:00
parent 7a20268d3b
commit c47a6b45c0
22 changed files with 624 additions and 449 deletions
+4 -4
View File
@@ -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)
{
+3 -1
View File
@@ -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++;
@@ -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;
+3 -3
View File
@@ -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;
+12 -3
View File
@@ -17,7 +17,7 @@ namespace TriangleNet
{
static readonly double SQRT2 = 1.4142135623730950488016887242096980785696718753769480732;
public List<BadTriangle> 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<BadTriangle>();
//badtriangles = new List<BadTriangle>();
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.
+2 -2
View File
@@ -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;
+2 -2
View File
@@ -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()
{
+45 -39
View File
@@ -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);
}
/// <summary>
/// Gets the specified coordinate of the vertex.
/// </summary>
@@ -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()
{
+2 -8
View File
@@ -20,12 +20,6 @@ namespace TriangleNet.IO
/// </summary>
public static class DataReader
{
class StackTri
{
public Otri tri = default(Otri);
public StackTri next;
}
#region Library
/// <summary>
@@ -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.");
}
}
+41 -13
View File
@@ -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++;
}
}
}
/// <summary>
@@ -281,7 +295,7 @@ namespace TriangleNet.IO
/// <summary>
/// Gets the Voronoi diagram as raw output data.
/// </summary>
/// <param name="m"></param>
/// <param name="mesh"></param>
/// <returns></returns>
/// <remarks>
/// 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.</remarks>
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++;
+107 -3
View File
@@ -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;
}
/// <summary>
/// Read the elements from an .ele file.
/// </summary>
@@ -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;
}
}
}
+5 -7
View File
@@ -8,17 +8,15 @@
namespace TriangleNet.IO
{
/// <summary>
/// Stores the mesh data in- and output.
/// Stores the voronoi data (output only).
/// </summary>
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;
}
}
+15 -5
View File
@@ -11,17 +11,27 @@ namespace TriangleNet.Log
using System.Linq;
using System.Text;
public enum LogLevel
{
Info = 0,
Warning = 1,
Error = 2
}
/// <summary>
/// TODO: Update summary.
/// A basic log interface.
/// </summary>
public interface ILog<T>
public interface ILog<T> 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<T> Data { get; }
LogLevel Level { get; }
}
}
+24
View File
@@ -0,0 +1,24 @@
// -----------------------------------------------------------------------
// <copyright file="ILogger.cs" company="">
// Triangle.NET code by Christian Woltering, http://home.edo.tu-dortmund.de/~woltering/triangle/
// </copyright>
// -----------------------------------------------------------------------
namespace TriangleNet.Log
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
/// <summary>
/// A basic log item interface.
/// </summary>
public interface ILogItem
{
DateTime Time { get; }
LogLevel Level { get; }
string Message { get; }
string Info { get; }
}
}
@@ -17,21 +17,23 @@ namespace TriangleNet.Log
/// <remarks>Using singleton pattern as proposed by Jon Skeet.
/// http://csharpindepth.com/Articles/General/Singleton.aspx
/// </remarks>
public sealed class SimpleLogger : ILog<string>
public sealed class SimpleLog : ILog<SimpleLogItem>
{
private List<string> log = new List<string>();
private List<SimpleLogItem> log = new List<SimpleLogItem>();
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<string> Instance
public static ILog<SimpleLogItem> 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<string> Data
public IList<SimpleLogItem> Data
{
get { return log; }
}
public LogLevel Level
{
get { return level; }
}
}
}
@@ -0,0 +1,56 @@
// -----------------------------------------------------------------------
// <copyright file="SimpleLogItem.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------
namespace TriangleNet.Log
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
/// <summary>
/// TODO: Update summary.
/// </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;
}
}
}
+29 -12
View File
@@ -14,6 +14,7 @@ namespace TriangleNet
using TriangleNet.Log;
using TriangleNet.IO;
using TriangleNet.Algorithm;
using TriangleNet.Smoothing;
/// <summary>
/// Mesh data structure.
@@ -22,7 +23,7 @@ namespace TriangleNet
{
#region Variables
ILog<string> logger;
ILog<SimpleLogItem> 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;
}
/// <summary>
/// Smooth the current mesh.
/// </summary>
public void Smooth()
{
//ISmoother smoother = new CvdSmoother(this);
//smoother.Smooth();
}
/// <summary>
/// Check mesh consistency and (constrained) Delaunay property.
/// </summary>
@@ -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.
+4 -4
View File
@@ -22,11 +22,11 @@ namespace TriangleNet
Mesh mesh;
Func<Vertex, Vertex, Vertex, double, bool> userTest;
ILog<string> logger;
ILog<SimpleLogItem> logger;
public Quality(Mesh m)
{
logger = SimpleLogger.Instance;
logger = SimpleLog.Instance;
badsubsegs = new Queue<BadSubseg>();
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);
}
}
}
+27 -5
View File
@@ -35,11 +35,20 @@ namespace TriangleNet
/// </summary>
/// <param name="mesh">Current mesh.</param>
public void Update(Mesh mesh)
{
this.Update(mesh, false);
}
/// <summary>
/// Update sampling parameters if mesh changed.
/// </summary>
/// <param name="mesh">Current mesh.</param>
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.
/// </summary>
/// <returns>Array of triangle keys.</returns>
public int[] GetSamples()
public int[] GetSamples(Mesh mesh)
{
int[] randSamples = new int[samples];
// TODO: Using currKeys to check key availability?
List<int> randSamples = new List<int>(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();
}
}
}
@@ -0,0 +1,21 @@
// -----------------------------------------------------------------------
// <copyright file="ISmoother.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------
namespace TriangleNet.Smoothing
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
/// <summary>
/// TODO: Update summary.
/// </summary>
public interface ISmoother
{
void Smooth();
}
}
+196 -322
View File
@@ -49,7 +49,7 @@ namespace TriangleNet
public static long CircleTopCount = 0;
/// <summary>
/// Number of vertex relocation.
/// Number of vertex relocations.
/// </summary>
public static long RelocationCount = 0;
@@ -59,191 +59,199 @@ namespace TriangleNet
double minEdge = 0;
/// <summary>
/// Shortest edge
/// Gets the shortest edge.
/// </summary>
public double ShortestEdge { get { return minEdge; } }
double maxEdge = 0;
/// <summary>
/// Longest edge
/// Gets the longest edge.
/// </summary>
public double LongestEdge { get { return maxEdge; } }
//
double minAspect = 0;
/// <summary>
/// Shortest altitude
/// Gets the shortest altitude.
/// </summary>
public double ShortestAltitude { get { return minAspect; } }
double maxAspect = 0;
/// <summary>
/// Largest aspect ratio
/// Gets the largest aspect ratio.
/// </summary>
public double LargestAspectRatio { get { return maxAspect; } }
double minArea = 0;
/// <summary>
/// Smallest area
/// Gets the smallest area.
/// </summary>
public double SmallestArea { get { return minArea; } }
double maxArea = 0;
/// <summary>
/// Largest area
/// Gets the largest area.
/// </summary>
public double LargestArea { get { return maxArea; } }
double minAngle = 0;
/// <summary>
/// Smallest angle
/// Gets the smallest angle.
/// </summary>
public double SmallestAngle { get { return minAngle; } }
double maxAngle = 0;
/// <summary>
/// Largest angle
/// Gets the largest angle.
/// </summary>
public double LargestAngle { get { return maxAngle; } }
int inVetrices = 0;
/// <summary>
/// Input vertices
/// Gets the number of input vertices.
/// </summary>
public int InputVertices { get { return inVetrices; } }
int inTriangles = 0;
/// <summary>
/// Input triangles
/// Gets the number of input triangles.
/// </summary>
public int InputTriangles { get { return inTriangles; } }
int inSegments = 0;
/// <summary>
/// Input segments
/// Gets the number of input segments.
/// </summary>
public int InputSegments { get { return inSegments; } }
int inHoles = 0;
/// <summary>
/// Input holes
/// Gets the number of input holes.
/// </summary>
public int InputHoles { get { return inHoles; } }
int outVertices = 0;
/// <summary>
/// Mesh vertices
/// Gets the number of mesh vertices.
/// </summary>
public int Vertices { get { return outVertices; } }
int outTriangles = 0;
/// <summary>
/// Mesh triangles
/// Gets the number of mesh triangles.
/// </summary>
public int Triangles { get { return outTriangles; } }
int outEdges = 0;
/// <summary>
/// Mesh edges
/// Gets the number of mesh edges.
/// </summary>
public int Edges { get { return outEdges; } }
int boundaryEdges = 0;
/// <summary>
/// Exterior boundary edges
/// Gets the number of exterior boundary edges.
/// </summary>
public int BoundaryEdges { get { return boundaryEdges; } }
int intBoundaryEdges = 0;
/// <summary>
/// Interior boundary edges
/// Gets the number of interior boundary edges.
/// </summary>
public int InteriorBoundaryEdges { get { return intBoundaryEdges; } }
int constrainedEdges = 0;
/// <summary>
/// Constrained edges
/// Gets the number of constrained edges.
/// </summary>
public int ConstrainedEdges { get { return constrainedEdges; } }
int[] angleTable;
/// <summary>
/// Angle histogram
/// Gets the angle histogram.
/// </summary>
public int[] AngleHistogram { get { return angleTable; } }
int[] minAngles;
/// <summary>
/// Gets the min angles histogram.
/// </summary>
public int[] MinAngleHistogram { get { return minAngles; } }
int[] maxAngles;
/// <summary>
/// Gets the max angles histogram.
/// </summary>
public int[] MaxAngleHistogram { get { return maxAngles; } }
#endregion
/// <summary>
/// detailedHistogram()
/// </summary>
/// <param name="m"></param>
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.
/// </summary>
/// <param name="mesh"></param>
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));
}
}
}
*/
}
}
+4 -1
View File
@@ -64,7 +64,9 @@
<Compile Include="IO\DataWriter.cs" />
<Compile Include="IO\FileReader.cs" />
<Compile Include="Log\ILog.cs" />
<Compile Include="Log\SimpleLogger.cs" />
<Compile Include="Log\ILogItem.cs" />
<Compile Include="Log\SimpleLog.cs" />
<Compile Include="Log\SimpleLogItem.cs" />
<Compile Include="NewLocation.cs" />
<Compile Include="Quality.cs" />
<Compile Include="Enums.cs" />
@@ -73,6 +75,7 @@
<Compile Include="Primitives.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Sampler.cs" />
<Compile Include="Smoothing\ISmoother.cs" />
<Compile Include="Statistic.cs" />
<Compile Include="Algorithm\SweepLine.cs" />
<Compile Include="IO\MeshData.cs" />