Added Triangle mesh to DCEL conversion

git-svn-id: https://triangle.svn.codeplex.com/svn@75154 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
SND\wo80_cp
2014-07-16 12:57:39 +00:00
parent 96fb33322b
commit acc1353f7b
10 changed files with 293 additions and 33 deletions
+1 -3
View File
@@ -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)
+1 -3
View File
@@ -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());
}
}
+162 -13
View File
@@ -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;
/// <summary>
/// The Converter class provides methods for mesh reconstruction.
/// </summary>
public class Converter
public static class Converter
{
#region Triangle mesh conversion
/// <summary>
/// Reconstruct a triangulation from its raw data representation.
/// </summary>
public Mesh ToMesh(Polygon polygon, IList<ITriangle> triangles)
public static Mesh ToMesh(Polygon polygon, IList<ITriangle> triangles)
{
return ToMesh(polygon, triangles.ToArray());
}
@@ -29,14 +35,14 @@ namespace TriangleNet.Meshing
/// <summary>
/// Reconstruct a triangulation from its raw data representation.
/// </summary>
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<HalfEdge>[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<HalfEdge>(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<int, HalfEdge>();
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
}
}
@@ -177,9 +177,7 @@ namespace TriangleNet.Meshing
}
}
var converter = new Converter();
return converter.ToMesh(polygon, triangles);
return Converter.ToMesh(polygon, triangles);
}
}
}
@@ -22,6 +22,9 @@ namespace TriangleNet.Smoothing
{
ConstraintOptions options;
/// <summary>
/// Initializes a new instance of the <see cref="SimpleSmoother" /> class.
/// </summary>
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
/// </summary>
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;
}
/// <summary>
/// Rebuild the input geometry.
/// </summary>
@@ -1,4 +1,9 @@
// -----------------------------------------------------------------------
// <copyright file="DcelMesh.cs">
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
// </copyright>
// -----------------------------------------------------------------------
namespace TriangleNet.Topology.DCEL
{
using System.Collections.Generic;
@@ -10,11 +15,18 @@ namespace TriangleNet.Topology.DCEL
protected List<HalfEdge> edges;
protected List<Face> faces;
/// <summary>
/// Initializes a new instance of the <see cref="DcelMesh" /> class.
/// </summary>
public DcelMesh()
: this(true)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="" /> class.
/// </summary>
/// <param name="initialize">If false, lists will not be initialized.</param>
protected DcelMesh(bool initialize)
{
if (initialize)
@@ -57,6 +69,74 @@ namespace TriangleNet.Topology.DCEL
get { return EnumerateEdges(); }
}
/// <summary>
/// Check if the DCEL ist consistend.
/// </summary>
/// <param name="closed">If true, faces are assumed to be closed (i.e. all edges must have
/// a valid next pointer).</param>
/// <returns></returns>
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;
}
/// <summary>
/// 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);
@@ -13,6 +13,18 @@ namespace TriangleNet.Topology.DCEL
/// </summary>
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;
/// <summary>
/// Gets the face id.
/// </summary>
public int ID
{
get { return id; }
}
/// <summary>
/// Gets or sets a half-edge connected to the face.
/// </summary>
@@ -15,6 +15,14 @@ namespace TriangleNet.Topology.DCEL
internal HalfEdge twin;
internal HalfEdge next;
/// <summary>
/// Gets the half-edge id.
/// </summary>
public int ID
{
get { return id; }
}
/// <summary>
/// Gets or sets the origin of the half-edge.
/// </summary>
@@ -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;
}
+1 -4
View File
@@ -116,10 +116,7 @@
<Compile Include="Voronoi\StandardVoronoi.cs" />
<Compile Include="Voronoi\VoronoiBase.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Data\" />
<Folder Include="Voronoi\DCEL\" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
@@ -68,6 +68,9 @@ namespace TriangleNet.Voronoi
}
}
/// <summary>
/// Case 1: edge origin lies inside the domain.
/// </summary>
private void HandleCase1(HalfEdge edge, TVertex v1, TVertex v2)
{
//int mark = GetBoundaryMark(v1);
@@ -86,9 +89,12 @@ namespace TriangleNet.Voronoi
var h1 = new HalfEdge(edge.twin.origin, edge.face);
var h2 = new HalfEdge(gen, edge.face);
edge.next = h1;
h1.next = h2;
h2.next = edge.face.edge;
gen.leaving = h2;
// Let the face edge point to the edge leaving at generator.
edge.face.edge = h2;
@@ -104,6 +110,9 @@ namespace TriangleNet.Voronoi
base.vertices.Add(gen);
}
/// <summary>
/// Case 1: edge origin lies outside the domain.
/// </summary>
private void HandleCase2(HalfEdge edge, TVertex v1, TVertex v2)
{
// The vertices of the infinite edge.