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:
@@ -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)
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user