More code reorganization (3)

git-svn-id: https://triangle.svn.codeplex.com/svn@75023 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
SND\wo80_cp
2014-05-29 21:57:28 +00:00
parent faa7d4df47
commit a9de99f651
52 changed files with 1376 additions and 1465 deletions
@@ -8,9 +8,9 @@
namespace TriangleNet.Meshing.Algorithm
{
using System;
using System.Collections.Generic;
using TriangleNet.Data;
using TriangleNet.Geometry;
using TriangleNet.Logging;
/// <summary>
/// Builds a delaunay triangulation using the divide-and-conquer algorithm.
@@ -43,7 +43,7 @@ namespace TriangleNet.Meshing.Algorithm
/// The bounding box also makes it easy to traverse the convex hull, as the
/// divide-and-conquer algorithm needs to do.
/// </remarks>
class Dwyer
public class Dwyer : ITriangulator
{
static Random rand = new Random(DateTime.Now.Millisecond);
@@ -52,6 +52,83 @@ namespace TriangleNet.Meshing.Algorithm
Vertex[] sortarray;
Mesh mesh;
/// <summary>
/// Form a Delaunay triangulation by the divide-and-conquer method.
/// </summary>
/// <returns></returns>
/// <remarks>
/// Sorts the vertices, calls a recursive procedure to triangulate them, and
/// removes the bounding box, setting boundary markers as appropriate.
/// </remarks>
public IMesh Triangulate(ICollection<Vertex> points)
{
this.mesh = new Mesh();
this.mesh.TransferNodes(points);
Otri hullleft = default(Otri), hullright = default(Otri);
int divider;
int i, j, n = points.Count;
//DebugWriter.Session.Start("test-dbg");
// Allocate an array of pointers to vertices for sorting.
// TODO: use ToArray
this.sortarray = new Vertex[n];
i = 0;
foreach (var v in points)
{
sortarray[i++] = v;
}
// Sort the vertices.
//Array.Sort(sortarray);
VertexSort(0, n - 1);
// Discard duplicate vertices, which can really mess up the algorithm.
i = 0;
for (j = 1; j < n; j++)
{
if ((sortarray[i].x == sortarray[j].x) && (sortarray[i].y == sortarray[j].y))
{
if (Log.Verbose)
{
Log.Instance.Warning(
String.Format("A duplicate vertex appeared and was ignored (ID {0}).", sortarray[j].hash),
"Dwyer.Triangulate()");
}
sortarray[j].type = VertexType.UndeadVertex;
mesh.undeads++;
}
else
{
i++;
sortarray[i] = sortarray[j];
}
}
i++;
if (UseDwyer)
{
// Re-sort the array of vertices to accommodate alternating cuts.
divider = i >> 1;
if (i - divider >= 2)
{
if (divider >= 2)
{
AlternateAxes(0, divider - 1, 1);
}
AlternateAxes(divider, i - 1, 1);
}
}
// Form the Delaunay triangulation.
DivconqRecurse(0, i - 1, 0, ref hullleft, ref hullright);
//DebugWriter.Session.Write(mesh);
//DebugWriter.Session.Finish();
this.mesh.hullsize = RemoveGhosts(ref hullleft);
return this.mesh;
}
/// <summary>
/// Sort an array of vertices by x-coordinate, using the y-coordinate as a secondary key.
/// </summary>
@@ -103,16 +180,14 @@ namespace TriangleNet.Meshing.Algorithm
left++;
}
while ((left <= right) && ((sortarray[left].x < pivotx) ||
((sortarray[left].x == pivotx) &&
(sortarray[left].y < pivoty))));
((sortarray[left].x == pivotx) && (sortarray[left].y < pivoty))));
// Search for a vertex whose x-coordinate is too small for the right.
do
{
right--;
}
while ((left <= right) && ((sortarray[right].x > pivotx) ||
((sortarray[right].x == pivotx) &&
(sortarray[right].y > pivoty))));
((sortarray[right].x == pivotx) && (sortarray[right].y > pivoty))));
if (left < right)
{
@@ -183,16 +258,14 @@ namespace TriangleNet.Meshing.Algorithm
left++;
}
while ((left <= right) && ((sortarray[left][axis] < pivot1) ||
((sortarray[left][axis] == pivot1) &&
(sortarray[left][1 - axis] < pivot2))));
((sortarray[left][axis] == pivot1) && (sortarray[left][1 - axis] < pivot2))));
// Search for a vertex whose x-coordinate is too small for the right.
do
{
right--;
}
while ((left <= right) && ((sortarray[right][axis] > pivot1) ||
((sortarray[right][axis] == pivot1) &&
(sortarray[right][1 - axis] > pivot2))));
((sortarray[right][axis] == pivot1) && (sortarray[right][1 - axis] > pivot2))));
if (left < right)
{
// Swap the left and right vertices.
@@ -823,80 +896,5 @@ namespace TriangleNet.Meshing.Algorithm
return hullsize;
}
/// <summary>
/// Form a Delaunay triangulation by the divide-and-conquer method.
/// </summary>
/// <returns></returns>
/// <remarks>
/// Sorts the vertices, calls a recursive procedure to triangulate them, and
/// removes the bounding box, setting boundary markers as appropriate.
/// </remarks>
public int Triangulate(Mesh m)
{
Otri hullleft = default(Otri), hullright = default(Otri);
int divider;
int i, j;
this.mesh = m;
//DebugWriter.Session.Start("test-dbg");
// Allocate an array of pointers to vertices for sorting.
// TODO: use ToArray
this.sortarray = new Vertex[m.invertices];
i = 0;
foreach (var v in m.vertices.Values)
{
sortarray[i++] = v;
}
// Sort the vertices.
//Array.Sort(sortarray);
VertexSort(0, m.invertices - 1);
// Discard duplicate vertices, which can really mess up the algorithm.
i = 0;
for (j = 1; j < m.invertices; j++)
{
if ((sortarray[i].x == sortarray[j].x)
&& (sortarray[i].y == sortarray[j].y))
{
if (Log.Verbose)
{
Log.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++;
}
else
{
i++;
sortarray[i] = sortarray[j];
}
}
i++;
if (UseDwyer)
{
// Re-sort the array of vertices to accommodate alternating cuts.
divider = i >> 1;
if (i - divider >= 2)
{
if (divider >= 2)
{
AlternateAxes(0, divider - 1, 1);
}
AlternateAxes(divider, i - 1, 1);
}
}
// Form the Delaunay triangulation.
DivconqRecurse(0, i-1, 0, ref hullleft, ref hullright);
//DebugWriter.Session.Write(mesh);
//DebugWriter.Session.Finish();
return RemoveGhosts(ref hullleft);
}
}
}
@@ -7,17 +7,54 @@
namespace TriangleNet.Meshing.Algorithm
{
using System.Collections.Generic;
using TriangleNet.Data;
using TriangleNet.Logging;
using TriangleNet.Geometry;
/// <summary>
/// Builds a delaunay triangulation using the incremental algorithm.
/// </summary>
class Incremental
public class Incremental : ITriangulator
{
Mesh mesh;
/// <summary>
/// Form a Delaunay triangulation by incrementally inserting vertices.
/// </summary>
/// <returns>Returns the number of edges on the convex hull of the
/// triangulation.</returns>
public IMesh Triangulate(ICollection<Vertex> points)
{
this.mesh = new Mesh();
this.mesh.TransferNodes(points);
Otri starttri = new Otri();
// Create a triangular bounding box.
GetBoundingBox();
foreach (var v in mesh.vertices.Values)
{
starttri.triangle = Mesh.dummytri;
Osub tmp = default(Osub);
if (mesh.InsertVertex(v, ref starttri, ref tmp, false, false) == InsertVertexResult.Duplicate)
{
if (Log.Verbose)
{
Log.Instance.Warning("A duplicate vertex appeared and was ignored.",
"Incremental.IncrementalDelaunay()");
}
v.type = VertexType.UndeadVertex;
mesh.undeads++;
}
}
// Remove the bounding box.
this.mesh.hullsize = RemoveBox();
return this.mesh;
}
/// <summary>
/// Form an "infinite" bounding triangle to insert vertices into.
/// </summary>
@@ -144,38 +181,5 @@ namespace TriangleNet.Meshing.Algorithm
return hullsize;
}
/// <summary>
/// Form a Delaunay triangulation by incrementally inserting vertices.
/// </summary>
/// <returns>Returns the number of edges on the convex hull of the
/// triangulation.</returns>
public int Triangulate(Mesh mesh)
{
this.mesh = mesh;
Otri starttri = new Otri();
// Create a triangular bounding box.
GetBoundingBox();
foreach (var v in mesh.vertices.Values)
{
starttri.triangle = Mesh.dummytri;
Osub tmp = default(Osub);
if (mesh.InsertVertex(v, ref starttri, ref tmp, false, false) == InsertVertexResult.Duplicate)
{
if (Log.Verbose)
{
Log.Instance.Warning("A duplicate vertex appeared and was ignored.",
"Incremental.IncrementalDelaunay()");
}
v.type = VertexType.UndeadVertex;
mesh.undeads++;
}
}
// Remove the bounding box.
return RemoveBox();
}
}
}
@@ -11,18 +11,17 @@ namespace TriangleNet.Meshing.Algorithm
using System.Collections.Generic;
using TriangleNet.Data;
using TriangleNet.Geometry;
using TriangleNet.Logging;
using TriangleNet.Tools;
/// <summary>
/// Builds a delaunay triangulation using the sweepline algorithm.
/// </summary>
class SweepLine
public class SweepLine : ITriangulator
{
static int randomseed = 1;
static int SAMPLERATE = 10;
int randomnation(int choices)
static int randomnation(int choices)
{
randomseed = (randomseed * 1366 + 150889) % 714025;
return randomseed / (714025 / choices + 1);
@@ -32,6 +31,226 @@ namespace TriangleNet.Meshing.Algorithm
double xminextreme; // Nonexistent x value used as a flag in sweepline.
List<SplayNode> splaynodes;
public IMesh Triangulate(ICollection<Vertex> points)
{
this.mesh = new Mesh();
this.mesh.TransferNodes(points);
// Nonexistent x value used as a flag to mark circle events in sweepline
// Delaunay algorithm.
xminextreme = 10 * mesh.bounds.Left - 9 * mesh.bounds.Right;
SweepEvent[] eventheap;
SweepEvent nextevent;
SweepEvent newevent;
SplayNode splayroot;
Otri bottommost = default(Otri);
Otri searchtri = default(Otri);
Otri fliptri;
Otri lefttri = default(Otri);
Otri righttri = default(Otri);
Otri farlefttri = default(Otri);
Otri farrighttri = default(Otri);
Otri inserttri = default(Otri);
Vertex firstvertex, secondvertex;
Vertex nextvertex, lastvertex;
Vertex connectvertex;
Vertex leftvertex, midvertex, rightvertex;
double lefttest, righttest;
int heapsize;
bool check4events, farrightflag = false;
splaynodes = new List<SplayNode>();
splayroot = null;
CreateHeap(out eventheap);//, out events, out freeevents);
heapsize = mesh.invertices;
mesh.MakeTriangle(ref lefttri);
mesh.MakeTriangle(ref righttri);
lefttri.Bond(ref righttri);
lefttri.LnextSelf();
righttri.LprevSelf();
lefttri.Bond(ref righttri);
lefttri.LnextSelf();
righttri.LprevSelf();
lefttri.Bond(ref righttri);
firstvertex = eventheap[0].vertexEvent;
HeapDelete(eventheap, heapsize, 0);
heapsize--;
do
{
if (heapsize == 0)
{
Log.Instance.Error("Input vertices are all identical.", "SweepLine.Triangulate()");
throw new Exception("Input vertices are all identical.");
}
secondvertex = eventheap[0].vertexEvent;
HeapDelete(eventheap, heapsize, 0);
heapsize--;
if ((firstvertex.x == secondvertex.x) &&
(firstvertex.y == secondvertex.y))
{
if (Log.Verbose)
{
Log.Instance.Warning("A duplicate vertex appeared and was ignored (ID " + secondvertex.id + ").",
"SweepLine.Triangulate().1");
}
secondvertex.type = VertexType.UndeadVertex;
mesh.undeads++;
}
} while ((firstvertex.x == secondvertex.x) &&
(firstvertex.y == secondvertex.y));
lefttri.SetOrg(firstvertex);
lefttri.SetDest(secondvertex);
righttri.SetOrg(secondvertex);
righttri.SetDest(firstvertex);
lefttri.Lprev(ref bottommost);
lastvertex = secondvertex;
while (heapsize > 0)
{
nextevent = eventheap[0];
HeapDelete(eventheap, heapsize, 0);
heapsize--;
check4events = true;
if (nextevent.xkey < mesh.bounds.Left)
{
fliptri = nextevent.otriEvent;
fliptri.Oprev(ref farlefttri);
Check4DeadEvent(ref farlefttri, eventheap, ref heapsize);
fliptri.Onext(ref farrighttri);
Check4DeadEvent(ref farrighttri, eventheap, ref heapsize);
if (farlefttri.Equal(bottommost))
{
fliptri.Lprev(ref bottommost);
}
mesh.Flip(ref fliptri);
fliptri.SetApex(null);
fliptri.Lprev(ref lefttri);
fliptri.Lnext(ref righttri);
lefttri.Sym(ref farlefttri);
if (randomnation(SAMPLERATE) == 0)
{
fliptri.SymSelf();
leftvertex = fliptri.Dest();
midvertex = fliptri.Apex();
rightvertex = fliptri.Org();
splayroot = CircleTopInsert(splayroot, lefttri, leftvertex, midvertex, rightvertex, nextevent.ykey);
}
}
else
{
nextvertex = nextevent.vertexEvent;
if ((nextvertex.x == lastvertex.x) &&
(nextvertex.y == lastvertex.y))
{
if (Log.Verbose)
{
Log.Instance.Warning("A duplicate vertex appeared and was ignored (ID " + nextvertex.id + ").",
"SweepLine.Triangulate().2");
}
nextvertex.type = VertexType.UndeadVertex;
mesh.undeads++;
check4events = false;
}
else
{
lastvertex = nextvertex;
splayroot = FrontLocate(splayroot, bottommost, nextvertex, ref searchtri, ref farrightflag);
//bottommost.Copy(ref searchtri);
//farrightflag = false;
//while (!farrightflag && RightOfHyperbola(ref searchtri, nextvertex))
//{
// searchtri.OnextSelf();
// farrightflag = searchtri.Equal(bottommost);
//}
Check4DeadEvent(ref searchtri, eventheap, ref heapsize);
searchtri.Copy(ref farrighttri);
searchtri.Sym(ref farlefttri);
mesh.MakeTriangle(ref lefttri);
mesh.MakeTriangle(ref righttri);
connectvertex = farrighttri.Dest();
lefttri.SetOrg(connectvertex);
lefttri.SetDest(nextvertex);
righttri.SetOrg(nextvertex);
righttri.SetDest(connectvertex);
lefttri.Bond(ref righttri);
lefttri.LnextSelf();
righttri.LprevSelf();
lefttri.Bond(ref righttri);
lefttri.LnextSelf();
righttri.LprevSelf();
lefttri.Bond(ref farlefttri);
righttri.Bond(ref farrighttri);
if (!farrightflag && farrighttri.Equal(bottommost))
{
lefttri.Copy(ref bottommost);
}
if (randomnation(SAMPLERATE) == 0)
{
splayroot = SplayInsert(splayroot, lefttri, nextvertex);
}
else if (randomnation(SAMPLERATE) == 0)
{
righttri.Lnext(ref inserttri);
splayroot = SplayInsert(splayroot, inserttri, nextvertex);
}
}
}
if (check4events)
{
leftvertex = farlefttri.Apex();
midvertex = lefttri.Dest();
rightvertex = lefttri.Apex();
lefttest = RobustPredicates.CounterClockwise(leftvertex, midvertex, rightvertex);
if (lefttest > 0.0)
{
newevent = new SweepEvent();
newevent.xkey = xminextreme;
newevent.ykey = CircleTop(leftvertex, midvertex, rightvertex, lefttest);
newevent.otriEvent = lefttri;
HeapInsert(eventheap, heapsize, newevent);
heapsize++;
lefttri.SetOrg(new SweepEventVertex(newevent));
}
leftvertex = righttri.Apex();
midvertex = righttri.Org();
rightvertex = farrighttri.Apex();
righttest = RobustPredicates.CounterClockwise(leftvertex, midvertex, rightvertex);
if (righttest > 0.0)
{
newevent = new SweepEvent();
newevent.xkey = xminextreme;
newevent.ykey = CircleTop(leftvertex, midvertex, rightvertex, righttest);
newevent.otriEvent = farrighttri;
HeapInsert(eventheap, heapsize, newevent);
heapsize++;
farrighttri.SetOrg(new SweepEventVertex(newevent));
}
}
}
splaynodes.Clear();
bottommost.LprevSelf();
this.mesh.hullsize = RemoveGhosts(ref bottommost);
return this.mesh;
}
#region Heap
void HeapInsert(SweepEvent[] heap, int heapsize, SweepEvent newevent)
@@ -519,222 +738,6 @@ namespace TriangleNet.Meshing.Algorithm
return hullsize;
}
public int Triangulate(Mesh mesh)
{
this.mesh = mesh;
// Nonexistent x value used as a flag to mark circle events in sweepline
// Delaunay algorithm.
xminextreme = 10 * mesh.bounds.Left - 9 * mesh.bounds.Right;
SweepEvent[] eventheap;
SweepEvent nextevent;
SweepEvent newevent;
SplayNode splayroot;
Otri bottommost = default(Otri);
Otri searchtri = default(Otri);
Otri fliptri;
Otri lefttri = default(Otri);
Otri righttri = default(Otri);
Otri farlefttri = default(Otri);
Otri farrighttri = default(Otri);
Otri inserttri = default(Otri);
Vertex firstvertex, secondvertex;
Vertex nextvertex, lastvertex;
Vertex connectvertex;
Vertex leftvertex, midvertex, rightvertex;
double lefttest, righttest;
int heapsize;
bool check4events, farrightflag = false;
splaynodes = new List<SplayNode>();
splayroot = null;
CreateHeap(out eventheap);//, out events, out freeevents);
heapsize = mesh.invertices;
mesh.MakeTriangle(ref lefttri);
mesh.MakeTriangle(ref righttri);
lefttri.Bond(ref righttri);
lefttri.LnextSelf();
righttri.LprevSelf();
lefttri.Bond(ref righttri);
lefttri.LnextSelf();
righttri.LprevSelf();
lefttri.Bond(ref righttri);
firstvertex = eventheap[0].vertexEvent;
HeapDelete(eventheap, heapsize, 0);
heapsize--;
do
{
if (heapsize == 0)
{
Log.Instance.Error("Input vertices are all identical.", "SweepLine.Triangulate()");
throw new Exception("Input vertices are all identical.");
}
secondvertex = eventheap[0].vertexEvent;
HeapDelete(eventheap, heapsize, 0);
heapsize--;
if ((firstvertex.x == secondvertex.x) &&
(firstvertex.y == secondvertex.y))
{
if (Log.Verbose)
{
Log.Instance.Warning("A duplicate vertex appeared and was ignored (ID " + secondvertex.id + ").",
"SweepLine.Triangulate().1");
}
secondvertex.type = VertexType.UndeadVertex;
mesh.undeads++;
}
} while ((firstvertex.x == secondvertex.x) &&
(firstvertex.y == secondvertex.y));
lefttri.SetOrg(firstvertex);
lefttri.SetDest(secondvertex);
righttri.SetOrg(secondvertex);
righttri.SetDest(firstvertex);
lefttri.Lprev(ref bottommost);
lastvertex = secondvertex;
while (heapsize > 0)
{
nextevent = eventheap[0];
HeapDelete(eventheap, heapsize, 0);
heapsize--;
check4events = true;
if (nextevent.xkey < mesh.bounds.Left)
{
fliptri = nextevent.otriEvent;
fliptri.Oprev(ref farlefttri);
Check4DeadEvent(ref farlefttri, eventheap, ref heapsize);
fliptri.Onext(ref farrighttri);
Check4DeadEvent(ref farrighttri, eventheap, ref heapsize);
if (farlefttri.Equal(bottommost))
{
fliptri.Lprev(ref bottommost);
}
mesh.Flip(ref fliptri);
fliptri.SetApex(null);
fliptri.Lprev(ref lefttri);
fliptri.Lnext(ref righttri);
lefttri.Sym(ref farlefttri);
if (randomnation(SAMPLERATE) == 0)
{
fliptri.SymSelf();
leftvertex = fliptri.Dest();
midvertex = fliptri.Apex();
rightvertex = fliptri.Org();
splayroot = CircleTopInsert(splayroot, lefttri, leftvertex, midvertex, rightvertex, nextevent.ykey);
}
}
else
{
nextvertex = nextevent.vertexEvent;
if ((nextvertex.x == lastvertex.x) &&
(nextvertex.y == lastvertex.y))
{
if (Log.Verbose)
{
Log.Instance.Warning("A duplicate vertex appeared and was ignored (ID " + nextvertex.id + ").",
"SweepLine.Triangulate().2");
}
nextvertex.type = VertexType.UndeadVertex;
mesh.undeads++;
check4events = false;
}
else
{
lastvertex = nextvertex;
splayroot = FrontLocate(splayroot, bottommost, nextvertex, ref searchtri, ref farrightflag);
//bottommost.Copy(ref searchtri);
//farrightflag = false;
//while (!farrightflag && RightOfHyperbola(ref searchtri, nextvertex))
//{
// searchtri.OnextSelf();
// farrightflag = searchtri.Equal(bottommost);
//}
Check4DeadEvent(ref searchtri, eventheap, ref heapsize);
searchtri.Copy(ref farrighttri);
searchtri.Sym(ref farlefttri);
mesh.MakeTriangle(ref lefttri);
mesh.MakeTriangle(ref righttri);
connectvertex = farrighttri.Dest();
lefttri.SetOrg(connectvertex);
lefttri.SetDest(nextvertex);
righttri.SetOrg(nextvertex);
righttri.SetDest(connectvertex);
lefttri.Bond(ref righttri);
lefttri.LnextSelf();
righttri.LprevSelf();
lefttri.Bond(ref righttri);
lefttri.LnextSelf();
righttri.LprevSelf();
lefttri.Bond(ref farlefttri);
righttri.Bond(ref farrighttri);
if (!farrightflag && farrighttri.Equal(bottommost))
{
lefttri.Copy(ref bottommost);
}
if (randomnation(SAMPLERATE) == 0)
{
splayroot = SplayInsert(splayroot, lefttri, nextvertex);
}
else if (randomnation(SAMPLERATE) == 0)
{
righttri.Lnext(ref inserttri);
splayroot = SplayInsert(splayroot, inserttri, nextvertex);
}
}
}
if (check4events)
{
leftvertex = farlefttri.Apex();
midvertex = lefttri.Dest();
rightvertex = lefttri.Apex();
lefttest = RobustPredicates.CounterClockwise(leftvertex, midvertex, rightvertex);
if (lefttest > 0.0)
{
newevent = new SweepEvent();
newevent.xkey = xminextreme;
newevent.ykey = CircleTop(leftvertex, midvertex, rightvertex, lefttest);
newevent.otriEvent = lefttri;
HeapInsert(eventheap, heapsize, newevent);
heapsize++;
lefttri.SetOrg(new SweepEventVertex(newevent));
}
leftvertex = righttri.Apex();
midvertex = righttri.Org();
rightvertex = farrighttri.Apex();
righttest = RobustPredicates.CounterClockwise(leftvertex, midvertex, rightvertex);
if (righttest > 0.0)
{
newevent = new SweepEvent();
newevent.xkey = xminextreme;
newevent.ykey = CircleTop(leftvertex, midvertex, rightvertex, righttest);
newevent.otriEvent = farrighttri;
HeapInsert(eventheap, heapsize, newevent);
heapsize++;
farrighttri.SetOrg(new SweepEventVertex(newevent));
}
}
}
splaynodes.Clear();
bottommost.LprevSelf();
return RemoveGhosts(ref bottommost);
}
#region Internal classes
/// <summary>
@@ -12,7 +12,7 @@ namespace TriangleNet.Meshing
using TriangleNet.Data;
using TriangleNet.Geometry;
using TriangleNet.Logging;
using TriangleNet.Tools;
using TriangleNet.Meshing.Iterators;
internal class ConstraintMesher
{
@@ -165,7 +165,7 @@ namespace TriangleNet.Meshing
/// Create the segments of a triangulation, including PSLG segments and edges
/// on the convex hull.
/// </summary>
public void FormSkeleton(InputGeometry input)
public void FormSkeleton(IPolygon input)
{
Vertex endpoint1, endpoint2;
int end1, end2;
@@ -184,7 +184,7 @@ namespace TriangleNet.Meshing
// If segments are to be inserted, compute a mapping
// from vertices to triangles.
if (input.HasSegments)
if (input.Segments.Count > 0)
{
mesh.MakeVertexMap();
}
@@ -192,7 +192,7 @@ namespace TriangleNet.Meshing
boundmarker = 0;
// Read and insert the segments.
foreach (var seg in input.segments)
foreach (var seg in input.Segments)
{
mesh.insegments++;
+7 -8
View File
@@ -12,14 +12,13 @@ namespace TriangleNet.Meshing
using System.Linq;
using TriangleNet.Data;
using TriangleNet.Geometry;
using TriangleNet.Logging;
/// <summary>
/// The DataReader class provides methods for mesh reconstruction.
/// </summary>
public class Converter
{
public Mesh ToMesh(InputGeometry polygon, IList<ITriangle> triangles)
public Mesh ToMesh(Polygon polygon, IList<ITriangle> triangles)
{
return ToMesh(polygon, triangles.ToArray());
}
@@ -46,7 +45,7 @@ namespace TriangleNet.Meshing
/// the corresponding pointer is adjusted to refer to a subsegment rather
/// than the next triangle of the stack.
/// </remarks>
public Mesh ToMesh(InputGeometry polygon, ITriangle[] triangles)
public Mesh ToMesh(Polygon polygon, ITriangle[] triangles)
{
Otri tri = default(Otri);
Osub subseg = default(Osub);
@@ -57,7 +56,7 @@ namespace TriangleNet.Meshing
var mesh = new Mesh();
mesh.TransferNodes(polygon);
mesh.TransferNodes(polygon.Points);
mesh.inelements = elements;
mesh.regions.AddRange(polygon.Regions);
@@ -213,7 +212,7 @@ namespace TriangleNet.Meshing
return vertexarray;
}
private static void SetSegments(Mesh mesh, InputGeometry polygon, List<Otri>[] vertexarray)
private static void SetSegments(Mesh mesh, Polygon polygon, List<Otri>[] vertexarray)
{
Otri checktri = default(Otri);
Otri nexttri; // Triangle
@@ -242,9 +241,9 @@ namespace TriangleNet.Meshing
{
subseg.seg = item;
end[0] = polygon.segments[i].P0;
end[1] = polygon.segments[i].P1;
boundmarker = polygon.segments[i].Boundary;
end[0] = polygon.Segments[i].P0;
end[1] = polygon.Segments[i].P1;
boundmarker = polygon.Segments[i].Boundary;
for (int j = 0; j < 2; j++)
{
@@ -0,0 +1,170 @@
namespace TriangleNet.Meshing
{
using System.Collections.Generic;
using TriangleNet.Geometry;
using TriangleNet.IO;
using TriangleNet.Meshing.Algorithm;
public class GenericMesher : ITriangulator, IConstraintMesher, IQualityMesher
{
ITriangulator triangulator;
public GenericMesher()
: this(new Dwyer())
{
}
public GenericMesher(ITriangulator triangulator)
{
this.triangulator = triangulator;
}
/// <summary>
/// Triangulates a point set.
/// </summary>
/// <param name="points">Collection of points.</param>
/// <returns>Mesh</returns>
public IMesh Triangulate(ICollection<Vertex> points)
{
return triangulator.Triangulate(points);
}
/// <summary>
/// Triangulates a polygon.
/// </summary>
/// <param name="polygon">The polygon.</param>
/// <returns>Mesh</returns>
public IMesh Triangulate(IPolygon polygon)
{
return Triangulate(polygon, null, null);
}
/// <summary>
/// Triangulates a polygon, applying constraint options.
/// </summary>
/// <param name="polygon">The polygon.</param>
/// <param name="options">Constraint options.</param>
/// <returns>Mesh</returns>
public IMesh Triangulate(IPolygon polygon, ConstraintOptions options)
{
return Triangulate(polygon, options, null);
}
/// <summary>
/// Triangulates a polygon, applying quality options.
/// </summary>
/// <param name="polygon">The polygon.</param>
/// <param name="quality">Quality options.</param>
/// <returns>Mesh</returns>
public IMesh Triangulate(IPolygon polygon, QualityOptions quality)
{
return Triangulate(polygon, null, quality);
}
/// <summary>
/// Triangulates a polygon, applying quality and constraint options.
/// </summary>
/// <param name="polygon">The polygon.</param>
/// <param name="options">Constraint options.</param>
/// <param name="quality">Quality options.</param>
/// <returns>Mesh</returns>
public IMesh Triangulate(IPolygon polygon, ConstraintOptions options, QualityOptions quality)
{
var mesh = (Mesh)triangulator.Triangulate(polygon.Points);
mesh.ApplyConstraints(polygon, options, quality);
return mesh;
}
/// <summary>
/// Generates a structured mesh.
/// </summary>
/// <param name="bounds">Bounds of the mesh.</param>
/// <param name="nx">Number of segments in x direction.</param>
/// <param name="ny">Number of segments in y direction.</param>
/// <returns>Mesh</returns>
public IMesh StructurdMesh(Rectangle bounds, int nx, int ny)
{
var polygon = new Polygon((nx + 1) * (ny + 1));
double x, y, dx, dy, left, bottom;
dx = bounds.Width / nx;
dy = bounds.Height / ny;
left = bounds.Left;
bottom = bounds.Bottom;
int i, j, k, l, n;
// Add vertices.
var points = polygon.Points;
for (i = 0; i <= nx; i++)
{
x = left + i * dx;
for (j = 0; j <= ny; j++)
{
y = bottom + j * dy;
points.Add(new Vertex(x, y));
}
}
n = 0;
// Set vertex id and hash.
foreach (var v in points)
{
v.id = v.hash = n++;
}
// Add boundary segments.
var segments = polygon.Segments;
segments.Capacity = 2 * (nx + ny);
for (j = 0; j < ny; j++)
{
// Left
segments.Add(new Edge(j, j + 1));
// Right
segments.Add(new Edge(nx * (ny + 1) + j, nx * (ny + 1) + (j + 1)));
}
for (i = 0; i < nx; i++)
{
// Bottom
segments.Add(new Edge(i * (ny + 1), (i + 1) * (ny + 1)));
// Top
segments.Add(new Edge(i * (ny + 1) + nx, (i + 1) * (ny + 1) + nx));
}
// Add triangles.
var triangles = new InputTriangle[2 * nx * ny];
n = 0;
for (i = 0; i < nx; i++)
{
for (j = 0; j < ny; j++)
{
k = j + (ny + 1) * i;
l = j + (ny + 1) * (i + 1);
triangles[n++] = new InputTriangle(k, l, l + 1);
triangles[n++] = new InputTriangle(k, l + 1, k + 1);
}
}
var converter = new Converter();
return converter.ToMesh(polygon, triangles);
}
}
}
@@ -5,7 +5,7 @@ namespace TriangleNet.Meshing
public interface IConstraintMesher
{
Mesh Triangulate(IPolygon polygon);
Mesh Triangulate(IPolygon polygon, ConstraintOptions options);
IMesh Triangulate(IPolygon polygon);
IMesh Triangulate(IPolygon polygon, ConstraintOptions options);
}
}
+20
View File
@@ -0,0 +1,20 @@
namespace TriangleNet.Meshing
{
using System.Collections.Generic;
using TriangleNet.Data;
using TriangleNet.Geometry;
public interface IMesh
{
ICollection<Vertex> Vertices { get; }
IEnumerable<Edge> Edges { get; }
ICollection<Segment> Segments { get; }
ICollection<Triangle> Triangles { get; }
IList<Point> Holes { get; }
Rectangle Bounds { get; }
void Refine(QualityOptions quality);
}
}
@@ -5,7 +5,7 @@ namespace TriangleNet.Meshing
public interface IQualityMesher
{
Mesh Triangulate(IPolygon polygon, QualityOptions quality);
Mesh Triangulate(IPolygon polygon, ConstraintOptions options, QualityOptions quality);
IMesh Triangulate(IPolygon polygon, QualityOptions quality);
IMesh Triangulate(IPolygon polygon, ConstraintOptions options, QualityOptions quality);
}
}
@@ -14,6 +14,6 @@ namespace TriangleNet.Meshing
/// </summary>
public interface ITriangulator
{
Mesh Triangulate(ICollection<Vertex> points);
IMesh Triangulate(ICollection<Vertex> points);
}
}
@@ -0,0 +1,101 @@
// -----------------------------------------------------------------------
// <copyright file="EdgeEnumerator.cs" company="">
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
// </copyright>
// -----------------------------------------------------------------------
namespace TriangleNet.Meshing.Iterators
{
using System.Collections.Generic;
using TriangleNet.Data;
using TriangleNet.Geometry;
/// <summary>
/// Enumerates the edges of a triangulation.
/// </summary>
public class EdgeIterator : IEnumerator<Edge>
{
IEnumerator<Triangle> triangles;
Otri tri = default(Otri);
Otri neighbor = default(Otri);
Osub sub = default(Osub);
Edge current;
Vertex p1, p2;
/// <summary>
/// Initializes a new instance of the <see cref="EdgeIterator" /> class.
/// </summary>
public EdgeIterator(Mesh mesh)
{
triangles = mesh.triangles.Values.GetEnumerator();
triangles.MoveNext();
tri.triangle = triangles.Current;
tri.orient = 0;
}
public Edge Current
{
get { return current; }
}
public void Dispose()
{
this.triangles.Dispose();
}
object System.Collections.IEnumerator.Current
{
get { return current; }
}
public bool MoveNext()
{
if (tri.triangle == null)
{
return false;
}
current = null;
while (current == null)
{
if (tri.orient == 3)
{
if (triangles.MoveNext())
{
tri.triangle = triangles.Current;
tri.orient = 0;
}
else
{
// Finally no more triangles
return false;
}
}
tri.Sym(ref neighbor);
if ((tri.triangle.id < neighbor.triangle.id) || (neighbor.triangle == Mesh.dummytri))
{
p1 = tri.Org();
p2 = tri.Dest();
tri.SegPivot(ref sub);
// Boundary mark of dummysub is 0, so we don't need to worry about that.
current = new Edge(p1.id, p2.id, sub.seg.boundary);
}
tri.orient++;
}
return true;
}
public void Reset()
{
this.triangles.Reset();
}
}
}
@@ -0,0 +1,126 @@
// -----------------------------------------------------------------------
// <copyright file="RegionIterator.cs" company="">
// Original Matlab code by John Burkardt, Florida State University
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
// </copyright>
// -----------------------------------------------------------------------
namespace TriangleNet.Meshing.Iterators
{
using System;
using System.Collections.Generic;
using TriangleNet.Data;
/// <summary>
/// Iterates the region a given triangle belongs to and applies an action
/// to each connected trianlge in that region. Default action is to set the
/// region id.
/// </summary>
public class RegionIterator
{
Mesh mesh;
List<Triangle> viri;
public RegionIterator(Mesh mesh)
{
this.mesh = mesh;
this.viri = new List<Triangle>();
}
/// <summary>
/// Apply given action to each triangle of selected region.
/// </summary>
/// <param name="func"></param>
void ProcessRegion(Action<Triangle> func)
{
Otri testtri = default(Otri);
Otri neighbor = default(Otri);
Osub neighborsubseg = default(Osub);
Behavior behavior = mesh.behavior;
// Loop through all the infected triangles, spreading the attribute
// and/or area constraint to their neighbors, then to their neighbors'
// neighbors.
for (int i = 0; i < viri.Count; i++)
{
// WARNING: Don't use foreach, viri list gets modified.
testtri.triangle = viri[i];
// A triangle is marked as infected by messing with one of its pointers
// to subsegments, setting it to an illegal value. Hence, we have to
// temporarily uninfect this triangle so that we can examine its
// adjacent subsegments.
// TODO: Not true in the C# version (so we could skip this).
testtri.Uninfect();
// Apply function.
func(testtri.triangle);
// Check each of the triangle's three neighbors.
for (testtri.orient = 0; testtri.orient < 3; testtri.orient++)
{
// Find the neighbor.
testtri.Sym(ref neighbor);
// Check for a subsegment between the triangle and its neighbor.
testtri.SegPivot(ref neighborsubseg);
// Make sure the neighbor exists, is not already infected, and
// isn't protected by a subsegment.
if ((neighbor.triangle != Mesh.dummytri) && !neighbor.IsInfected()
&& (neighborsubseg.seg == Mesh.dummysub))
{
// Infect the neighbor.
neighbor.Infect();
// Ensure that the neighbor's neighbors will be infected.
viri.Add(neighbor.triangle);
}
}
// Remark the triangle as infected, so it doesn't get added to the
// virus pool again.
testtri.Infect();
}
// Uninfect all triangles.
foreach (var virus in viri)
{
virus.infected = false;
}
// Empty the virus pool.
viri.Clear();
}
/// <summary>
/// Set the region attribute of all trianlges connected to given triangle.
/// </summary>
public void Process(Triangle triangle)
{
// Default action is to just set the region id for all trianlges.
this.Process(triangle, (tri) => { tri.region = triangle.region; });
}
/// <summary>
/// Process all trianlges connected to given triangle and apply given action.
/// </summary>
public void Process(Triangle triangle, Action<Triangle> func)
{
if (triangle != Mesh.dummytri)
{
// Make sure the triangle under consideration still exists.
// It may have been eaten by the virus.
if (!Otri.IsDead(triangle))
{
// Put one triangle in the virus pool.
triangle.infected = true;
viri.Add(triangle);
// Apply one region's attribute and/or area constraint.
ProcessRegion(func);
// The virus pool should be empty now.
}
}
// Free up memory (virus pool should be empty anyway).
viri.Clear();
}
}
}