More code reorganization (3)
git-svn-id: https://triangle.svn.codeplex.com/svn@75023 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user