diff --git a/Triangle.NET/TestApp/IO/Formats/JsonFile.cs b/Triangle.NET/TestApp/IO/Formats/JsonFile.cs
index b75f50e..3891e7e 100644
--- a/Triangle.NET/TestApp/IO/Formats/JsonFile.cs
+++ b/Triangle.NET/TestApp/IO/Formats/JsonFile.cs
@@ -96,9 +96,7 @@ namespace MeshExplorer.IO.Formats
}
}
- var converter = new Converter();
-
- return converter.ToMesh(geometry, triangles);
+ return Converter.ToMesh(geometry, triangles);
}
public void Write(IMesh mesh, string filename)
diff --git a/Triangle.NET/Triangle/IO/TriangleFormat.cs b/Triangle.NET/Triangle/IO/TriangleFormat.cs
index 87ed979..b1bda4a 100644
--- a/Triangle.NET/Triangle/IO/TriangleFormat.cs
+++ b/Triangle.NET/Triangle/IO/TriangleFormat.cs
@@ -42,9 +42,7 @@ namespace TriangleNet.IO
if (geometry != null && triangles != null)
{
- var converter = new Converter();
-
- return converter.ToMesh(geometry, triangles.ToArray());
+ return Converter.ToMesh(geometry, triangles.ToArray());
}
}
diff --git a/Triangle.NET/Triangle/Meshing/Converter.cs b/Triangle.NET/Triangle/Meshing/Converter.cs
index 5d0029b..8fda7b6 100644
--- a/Triangle.NET/Triangle/Meshing/Converter.cs
+++ b/Triangle.NET/Triangle/Meshing/Converter.cs
@@ -10,18 +10,24 @@ namespace TriangleNet.Meshing
using System;
using System.Collections.Generic;
using System.Linq;
- using TriangleNet.Topology;
using TriangleNet.Geometry;
+ using TriangleNet.Topology;
+ using TriangleNet.Topology.DCEL;
+
+ using HVertex = TriangleNet.Topology.DCEL.Vertex;
+ using TVertex = TriangleNet.Geometry.Vertex;
///
/// The Converter class provides methods for mesh reconstruction.
///
- public class Converter
+ public static class Converter
{
+ #region Triangle mesh conversion
+
///
/// Reconstruct a triangulation from its raw data representation.
///
- public Mesh ToMesh(Polygon polygon, IList triangles)
+ public static Mesh ToMesh(Polygon polygon, IList triangles)
{
return ToMesh(polygon, triangles.ToArray());
}
@@ -29,14 +35,14 @@ namespace TriangleNet.Meshing
///
/// Reconstruct a triangulation from its raw data representation.
///
- public Mesh ToMesh(Polygon polygon, ITriangle[] triangles)
+ public static Mesh ToMesh(Polygon polygon, ITriangle[] triangles)
{
Otri tri = default(Otri);
Osub subseg = default(Osub);
int i = 0;
int elements = triangles == null ? 0 : triangles.Length;
- int numberofsegments = polygon.Segments.Count;
+ int segments = polygon.Segments.Count;
var mesh = new Mesh();
@@ -53,17 +59,17 @@ namespace TriangleNet.Meshing
}
// Create the triangles.
- for (i = 0; i < mesh.inelements; i++)
+ for (i = 0; i < elements; i++)
{
mesh.MakeTriangle(ref tri);
}
if (mesh.behavior.Poly)
{
- mesh.insegments = numberofsegments;
+ mesh.insegments = segments;
// Create the subsegments.
- for (i = 0; i < mesh.insegments; i++)
+ for (i = 0; i < segments; i++)
{
mesh.MakeSegment(ref subseg);
}
@@ -87,8 +93,8 @@ namespace TriangleNet.Meshing
Otri checktri = default(Otri);
Otri checkleft = default(Otri);
Otri nexttri;
- Vertex tdest, tapex;
- Vertex checkdest, checkapex;
+ TVertex tdest, tapex;
+ TVertex checkdest, checkapex;
int[] corner = new int[3];
int aroundvertex;
int i;
@@ -203,12 +209,12 @@ namespace TriangleNet.Meshing
{
Otri checktri = default(Otri);
Otri nexttri; // Triangle
- Vertex checkdest;
+ TVertex checkdest;
Otri checkneighbor = default(Otri);
Osub subseg = default(Osub);
Otri prevlink; // Triangle
- Vertex shorg;
- Vertex segmentorg, segmentdest;
+ TVertex shorg;
+ TVertex segmentorg, segmentdest;
int[] end = new int[2];
bool notfound;
//bool segmentmarkers = false;
@@ -337,5 +343,148 @@ namespace TriangleNet.Meshing
mesh.hullsize = hullsize;
mesh.edges = (3 * mesh.triangles.Count + hullsize) / 2;
}
+
+ #endregion
+
+ #region DCEL conversion
+
+ public static DcelMesh ToDCEL(Mesh mesh)
+ {
+ var dcel = new DcelMesh();
+
+ var vertices = new HVertex[mesh.vertices.Count];
+ var faces = new Face[mesh.triangles.Count];
+
+ dcel.HalfEdges.Capacity = 2 * mesh.edges;
+
+ mesh.Renumber();
+
+ HVertex vertex;
+
+ foreach (var v in mesh.vertices.Values)
+ {
+ vertex = new HVertex(v.x, v.y);
+ vertex.id = v.id;
+ vertex.mark = v.mark;
+
+ vertices[v.id] = vertex;
+ }
+
+ // Maps a triangle to its 3 edges (used to set next pointers).
+ var map = new List[mesh.triangles.Count];
+
+ Face face;
+
+ foreach (var t in mesh.triangles.Values)
+ {
+ face = new Face(null);
+ face.id = t.id;
+
+ faces[t.id] = face;
+
+ map[t.id] = new List(3);
+ }
+
+ Otri tri = default(Otri), neighbor = default(Otri);
+ TriangleNet.Geometry.Vertex org, dest;
+
+ int id, nid, count = mesh.triangles.Count;
+
+ HalfEdge edge, twin, next;
+
+ var edges = dcel.HalfEdges;
+
+ // Count half-edges (edge ids).
+ int k = 0;
+
+ // Maps a vertex to its leaving boundary edge.
+ var boundary = new Dictionary();
+
+ foreach (var t in mesh.triangles.Values)
+ {
+ id = t.id;
+
+ tri.triangle = t;
+
+ for (int i = 0; i < 3; i++)
+ {
+ tri.orient = i;
+ tri.Sym(ref neighbor);
+
+ nid = neighbor.triangle.id;
+
+ if (id < nid || nid < 0)
+ {
+ face = faces[id];
+
+ // Get the endpoints of the current triangle edge.
+ org = tri.Org();
+ dest = tri.Dest();
+
+ // Create half-edges.
+ edge = new HalfEdge(vertices[org.id], face);
+ twin = new HalfEdge(vertices[dest.id], nid < 0 ? Face.Empty : faces[nid]);
+
+ map[id].Add(edge);
+
+ if (nid >= 0)
+ {
+ map[nid].Add(twin);
+ }
+ else
+ {
+ boundary.Add(dest.id, twin);
+ }
+
+ // Set leaving edges.
+ edge.origin.leaving = edge;
+ twin.origin.leaving = twin;
+
+ // Set twin edges.
+ edge.twin = twin;
+ twin.twin = edge;
+
+ edge.id = k++;
+ twin.id = k++;
+
+ edges.Add(edge);
+ edges.Add(twin);
+ }
+ }
+ }
+
+ // Set next pointers for each triangle face.
+ foreach (var t in map)
+ {
+ edge = t[0];
+ next = t[1];
+
+ if (edge.twin.origin.id == next.origin.id)
+ {
+ edge.next = next;
+ next.next = t[2];
+ t[2].next = edge;
+ }
+ else
+ {
+ edge.next = t[2];
+ next.next = edge;
+ t[2].next = next;
+ }
+ }
+
+ // Resolve boundary edges.
+ foreach (var e in boundary.Values)
+ {
+ e.next = boundary[e.twin.origin.id];
+ }
+
+ dcel.Vertices.AddRange(vertices);
+ dcel.Faces.AddRange(faces);
+
+ return dcel;
+ }
+
+ #endregion
}
}
diff --git a/Triangle.NET/Triangle/Meshing/GenericMesher.cs b/Triangle.NET/Triangle/Meshing/GenericMesher.cs
index 759b851..12a8fa6 100644
--- a/Triangle.NET/Triangle/Meshing/GenericMesher.cs
+++ b/Triangle.NET/Triangle/Meshing/GenericMesher.cs
@@ -177,9 +177,7 @@ namespace TriangleNet.Meshing
}
}
- var converter = new Converter();
-
- return converter.ToMesh(polygon, triangles);
+ return Converter.ToMesh(polygon, triangles);
}
}
}
diff --git a/Triangle.NET/Triangle/Smoothing/SimpleSmoother.cs b/Triangle.NET/Triangle/Smoothing/SimpleSmoother.cs
index 644c450..bab21d0 100644
--- a/Triangle.NET/Triangle/Smoothing/SimpleSmoother.cs
+++ b/Triangle.NET/Triangle/Smoothing/SimpleSmoother.cs
@@ -22,6 +22,9 @@ namespace TriangleNet.Smoothing
{
ConstraintOptions options;
+ ///
+ /// Initializes a new instance of the class.
+ ///
public SimpleSmoother()
{
this.options = new ConstraintOptions() { ConformingDelaunay = true };
@@ -39,7 +42,7 @@ namespace TriangleNet.Smoothing
// The smoother should respect the mesh segment splitting behavior.
this.options.SegmentSplitting = smoothedMesh.behavior.NoBisect;
- // Take a few smoothing rounds.
+ // Take a few smoothing rounds (Lloyd's algorithm).
for (int i = 0; i < limit; i++)
{
Step(smoothedMesh);
@@ -58,7 +61,7 @@ namespace TriangleNet.Smoothing
///
private void Step(Mesh mesh)
{
- BoundedVoronoiLegacy voronoi = new BoundedVoronoiLegacy(mesh, false);
+ var voronoi = new BoundedVoronoiLegacy(mesh, false);
var cells = voronoi.Regions;
@@ -101,7 +104,7 @@ namespace TriangleNet.Smoothing
//area = atmp / 2;
}
-
+
///
/// Rebuild the input geometry.
///
diff --git a/Triangle.NET/Triangle/Topology/DCEL/DcelMesh.cs b/Triangle.NET/Triangle/Topology/DCEL/DcelMesh.cs
index 1276766..e5d9d3a 100644
--- a/Triangle.NET/Triangle/Topology/DCEL/DcelMesh.cs
+++ b/Triangle.NET/Triangle/Topology/DCEL/DcelMesh.cs
@@ -1,4 +1,9 @@
-
+// -----------------------------------------------------------------------
+//
+// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
+//
+// -----------------------------------------------------------------------
+
namespace TriangleNet.Topology.DCEL
{
using System.Collections.Generic;
@@ -10,11 +15,18 @@ namespace TriangleNet.Topology.DCEL
protected List edges;
protected List faces;
+ ///
+ /// Initializes a new instance of the class.
+ ///
public DcelMesh()
: this(true)
{
}
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// If false, lists will not be initialized.
protected DcelMesh(bool initialize)
{
if (initialize)
@@ -57,6 +69,74 @@ namespace TriangleNet.Topology.DCEL
get { return EnumerateEdges(); }
}
+ ///
+ /// Check if the DCEL ist consistend.
+ ///
+ /// If true, faces are assumed to be closed (i.e. all edges must have
+ /// a valid next pointer).
+ ///
+ public bool IsConsistent(bool closed = true)
+ {
+ int horrors = 0;
+
+ // Check faces
+ foreach (var face in faces)
+ {
+ if (face.edge == null)
+ {
+ horrors++;
+ }
+ }
+
+ // Check half-edges
+ foreach (var edge in edges)
+ {
+ var twin = edge.twin;
+
+ if (edge.origin == null)
+ {
+ horrors++;
+ }
+
+ if (twin == null)
+ {
+ horrors++;
+ }
+ else if (twin.twin != null && edge.id != twin.twin.id)
+ {
+ horrors++;
+ }
+
+ if (closed)
+ {
+ if (edge.next == null)
+ {
+ horrors++;
+ }
+ else if (twin != null && edge.next.origin.id != twin.origin.id)
+ {
+ horrors++;
+ }
+ }
+
+ if (edge.face == null)
+ {
+ horrors++;
+ }
+ }
+
+ // Check vertices
+ foreach (var vertex in vertices)
+ {
+ if (vertex.leaving == null)
+ {
+ horrors++;
+ }
+ }
+
+ return horrors == 0;
+ }
+
///
/// Search for half-edge without twin and add a twin. Connect twins to form connected
/// boundary contours.
@@ -74,7 +154,7 @@ namespace TriangleNet.Topology.DCEL
{
if (edge.twin == null)
{
- var twin = edge.twin = new HalfEdge(edge.next.origin);
+ var twin = edge.twin = new HalfEdge(edge.next.origin, Face.Empty);
twin.twin = edge;
map.Add(twin.origin.id, twin);
diff --git a/Triangle.NET/Triangle/Topology/DCEL/Face.cs b/Triangle.NET/Triangle/Topology/DCEL/Face.cs
index b2b0102..e3f6d47 100644
--- a/Triangle.NET/Triangle/Topology/DCEL/Face.cs
+++ b/Triangle.NET/Triangle/Topology/DCEL/Face.cs
@@ -13,6 +13,18 @@ namespace TriangleNet.Topology.DCEL
///
public class Face
{
+ #region Static initialization of "Outer Space" face
+
+ public static readonly Face Empty;
+
+ static Face()
+ {
+ Empty = new Face(null);
+ Empty.id = -1;
+ }
+
+ #endregion
+
internal int id;
internal Point generator;
@@ -20,6 +32,14 @@ namespace TriangleNet.Topology.DCEL
internal HalfEdge edge;
internal bool bounded;
+ ///
+ /// Gets the face id.
+ ///
+ public int ID
+ {
+ get { return id; }
+ }
+
///
/// Gets or sets a half-edge connected to the face.
///
diff --git a/Triangle.NET/Triangle/Topology/DCEL/HalfEdge.cs b/Triangle.NET/Triangle/Topology/DCEL/HalfEdge.cs
index 0d85b77..3f72422 100644
--- a/Triangle.NET/Triangle/Topology/DCEL/HalfEdge.cs
+++ b/Triangle.NET/Triangle/Topology/DCEL/HalfEdge.cs
@@ -15,6 +15,14 @@ namespace TriangleNet.Topology.DCEL
internal HalfEdge twin;
internal HalfEdge next;
+ ///
+ /// Gets the half-edge id.
+ ///
+ public int ID
+ {
+ get { return id; }
+ }
+
///
/// Gets or sets the origin of the half-edge.
///
@@ -70,8 +78,8 @@ namespace TriangleNet.Topology.DCEL
this.origin = origin;
this.face = face;
- // IMPORTANT: do not remove the (this.face == null) check!
- if (face != null && this.face.edge == null)
+ // IMPORTANT: do not remove the (face.edge == null) check!
+ if (face != null && face.edge == null)
{
face.edge = this;
}
diff --git a/Triangle.NET/Triangle/Triangle.csproj b/Triangle.NET/Triangle/Triangle.csproj
index 2e1f77c..22f3c46 100644
--- a/Triangle.NET/Triangle/Triangle.csproj
+++ b/Triangle.NET/Triangle/Triangle.csproj
@@ -116,10 +116,7 @@
-
-
-
-
+