More code reorganization (6)
git-svn-id: https://triangle.svn.codeplex.com/svn@75300 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
@@ -5,6 +5,7 @@ using TriangleNet;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Tools;
|
||||
using TriangleNet.Topology;
|
||||
|
||||
namespace MeshExplorer
|
||||
{
|
||||
@@ -12,7 +13,7 @@ namespace MeshExplorer
|
||||
{
|
||||
Mesh mesh;
|
||||
QuadTree tree;
|
||||
OrientedTriangle current;
|
||||
Otri current;
|
||||
|
||||
public FormTopology()
|
||||
{
|
||||
@@ -28,7 +29,7 @@ namespace MeshExplorer
|
||||
|
||||
topoControlView.PrimitiveCommandInvoked += PrimitiveCommandHandler;
|
||||
|
||||
current = new OrientedTriangle();
|
||||
current = default(Otri);
|
||||
}
|
||||
|
||||
void PrimitiveCommandHandler(object sender, GenericEventArgs<string> e)
|
||||
@@ -46,12 +47,10 @@ namespace MeshExplorer
|
||||
|
||||
var tri = FindTriangleAt(((float)p.X) / size.Width, ((float)p.Y) / size.Height);
|
||||
|
||||
current.Triangle = tri;
|
||||
current.Orientation = 0;
|
||||
current.Triangle = (Triangle)tri;
|
||||
|
||||
renderControl.Update(current);
|
||||
|
||||
topoControlView.SetTriangle(current);
|
||||
topoControlView.SetTriangle(current.Triangle);
|
||||
}
|
||||
|
||||
private ITriangle FindTriangleAt(float x, float y)
|
||||
@@ -110,7 +109,7 @@ namespace MeshExplorer
|
||||
}
|
||||
|
||||
renderControl.Update(current);
|
||||
topoControlView.SetTriangle(current);
|
||||
topoControlView.SetTriangle(current.Triangle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,8 +120,6 @@
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Settings.cs" />
|
||||
<Compile Include="Topology\OrientedTriangle.cs" />
|
||||
<Compile Include="Topology\RectanglePolygon.cs" />
|
||||
<Compile Include="Topology\TopologyControlView.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
|
||||
namespace MeshExplorer.Topology
|
||||
{
|
||||
using TriangleNet.Topology;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
public class OrientedTriangle
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public ITriangle Triangle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ranges from 0 to 2.
|
||||
/// </summary>
|
||||
public int Orientation { get; set; }
|
||||
|
||||
#region Oriented triangle primitives
|
||||
|
||||
// For fast access
|
||||
static readonly int[] plus1Mod3 = { 1, 2, 0 };
|
||||
static readonly int[] minus1Mod3 = { 2, 0, 1 };
|
||||
|
||||
/// <summary>
|
||||
/// Find the abutting triangle; same edge. [sym(abc) -> ba*]
|
||||
/// </summary>
|
||||
public void Sym()
|
||||
{
|
||||
if (this.Triangle == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var org = this.Org();
|
||||
Triangle = Triangle.GetNeighbor(Orientation);
|
||||
Orientation = GetOrientation(Triangle, org.ID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the next edge (counterclockwise) of a triangle. [lnext(abc) -> bca]
|
||||
/// </summary>
|
||||
public void Lnext()
|
||||
{
|
||||
Orientation = plus1Mod3[Orientation];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the previous edge (clockwise) of a triangle. [lprev(abc) -> cab]
|
||||
/// </summary>
|
||||
public void Lprev()
|
||||
{
|
||||
Orientation = minus1Mod3[Orientation];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the next edge counterclockwise with the same origin. [onext(abc) -> ac*]
|
||||
/// </summary>
|
||||
public void Onext()
|
||||
{
|
||||
Lprev();
|
||||
Sym();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the next edge clockwise with the same origin. [oprev(abc) -> a*b]
|
||||
/// </summary>
|
||||
public void Oprev()
|
||||
{
|
||||
Sym();
|
||||
Lnext();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the next edge counterclockwise with the same destination. [dnext(abc) -> *ba]
|
||||
/// </summary>
|
||||
public void Dnext()
|
||||
{
|
||||
Sym();
|
||||
Lprev();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the next edge clockwise with the same destination. [dprev(abc) -> cb*]
|
||||
/// </summary>
|
||||
public void Dprev()
|
||||
{
|
||||
Lnext();
|
||||
Sym();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the next edge (counterclockwise) of the adjacent triangle. [rnext(abc) -> *a*]
|
||||
/// </summary>
|
||||
public void Rnext()
|
||||
{
|
||||
Sym();
|
||||
Lnext();
|
||||
Sym();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the previous edge (clockwise) of the adjacent triangle. [rprev(abc) -> b**]
|
||||
/// </summary>
|
||||
public void Rprev()
|
||||
{
|
||||
Sym();
|
||||
Lprev();
|
||||
Sym();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Origin [org(abc) -> a]
|
||||
/// </summary>
|
||||
public Vertex Org()
|
||||
{
|
||||
return Triangle.GetVertex(plus1Mod3[Orientation]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destination [dest(abc) -> b]
|
||||
/// </summary>
|
||||
public Vertex Dest()
|
||||
{
|
||||
return Triangle.GetVertex(minus1Mod3[Orientation]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apex [apex(abc) -> c]
|
||||
/// </summary>
|
||||
public Vertex Apex()
|
||||
{
|
||||
return Triangle.GetVertex(Orientation);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private int GetOrientation(ITriangle tri, int org)
|
||||
{
|
||||
if (tri == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tri.P0 == org)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (tri.P1 == org)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
|
||||
namespace MeshExplorer.Topology
|
||||
{
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
internal static class RectanglePolygon
|
||||
{
|
||||
public static IPolygon Generate(int n, double bounds = 10.0)
|
||||
{
|
||||
var geometry = new Polygon((n + 1) * (n + 1));
|
||||
|
||||
double x, y, d = 2 * bounds / n;
|
||||
|
||||
int mark = 0;
|
||||
|
||||
for (int i = 0; i <= n; i++)
|
||||
{
|
||||
y = -bounds + i * d;
|
||||
|
||||
for (int j = 0; j <= n; j++)
|
||||
{
|
||||
x = -bounds + j * d;
|
||||
|
||||
geometry.Add(new Vertex(x, y, mark));
|
||||
}
|
||||
}
|
||||
|
||||
// Add boundary segments
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
// Bottom
|
||||
geometry.Add(new Edge(i, i + 1));
|
||||
|
||||
// Right
|
||||
geometry.Add(new Edge(i * (n + 1) + n, (i + 1) * (n + 1) + n));
|
||||
|
||||
// Top
|
||||
geometry.Add(new Edge(n * (n + 1) + i, n * (n + 1) + (i + 1)));
|
||||
|
||||
// Left
|
||||
geometry.Add(new Edge(i * (n + 1), (i + 1) * (n + 1)));
|
||||
}
|
||||
|
||||
return geometry;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,25 +22,23 @@ namespace MeshExplorer.Topology
|
||||
lbPosition.Text = String.Format(nfi, "X: {0:0.0}, Y: {1:0.0}", p.X, p.Y);
|
||||
}
|
||||
|
||||
public void SetTriangle(OrientedTriangle tri)
|
||||
public void SetTriangle(ITriangle tri)
|
||||
{
|
||||
var t = tri.Triangle;
|
||||
|
||||
if (t != null)
|
||||
if (tri != null)
|
||||
{
|
||||
lbTriangle.Text = t.ID.ToString();
|
||||
lbTriangle.Text = tri.ID.ToString();
|
||||
|
||||
lbV0.Text = t.P0.ToString();
|
||||
lbV1.Text = t.P1.ToString();
|
||||
lbV2.Text = t.P2.ToString();
|
||||
lbV0.Text = tri.P0.ToString();
|
||||
lbV1.Text = tri.P1.ToString();
|
||||
lbV2.Text = tri.P2.ToString();
|
||||
|
||||
lbN0.Text = t.N0.ToString();
|
||||
lbN1.Text = t.N1.ToString();
|
||||
lbN2.Text = t.N2.ToString();
|
||||
lbN0.Text = tri.N0.ToString();
|
||||
lbN1.Text = tri.N1.ToString();
|
||||
lbN2.Text = tri.N2.ToString();
|
||||
|
||||
lbS0.Text = GetSegmentString(t.GetSegment(0));
|
||||
lbS1.Text = GetSegmentString(t.GetSegment(1));
|
||||
lbS2.Text = GetSegmentString(t.GetSegment(2));
|
||||
lbS0.Text = GetSegmentString(tri.GetSegment(0));
|
||||
lbS1.Text = GetSegmentString(tri.GetSegment(1));
|
||||
lbS2.Text = GetSegmentString(tri.GetSegment(2));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace MeshExplorer.Topology
|
||||
using System.Windows.Forms;
|
||||
using TriangleNet;
|
||||
using TriangleNet.Rendering;
|
||||
using TriangleNet.Topology;
|
||||
|
||||
public class TopologyRenderControl : Control
|
||||
{
|
||||
@@ -57,9 +58,17 @@ namespace MeshExplorer.Topology
|
||||
this.Render();
|
||||
}
|
||||
|
||||
public void Update(OrientedTriangle otri)
|
||||
public void Update(Otri otri)
|
||||
{
|
||||
renderer.SelectTriangle(otri.Triangle == null ? null : otri);
|
||||
if (otri.Triangle == null || otri.Triangle.ID < 0)
|
||||
{
|
||||
renderer.SelectTriangle(null, null, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderer.SelectTriangle(otri.Triangle, otri.Org(), otri.Dest());
|
||||
}
|
||||
|
||||
this.Render();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace MeshExplorer.Topology
|
||||
using TriangleNet;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Rendering;
|
||||
using TriangleNet.Topology;
|
||||
|
||||
public class TopologyRenderer
|
||||
{
|
||||
@@ -25,7 +26,8 @@ namespace MeshExplorer.Topology
|
||||
|
||||
Font font, fontTri;
|
||||
|
||||
OrientedTriangle selection;
|
||||
ITriangle currentTri;
|
||||
Vertex currentOrg, currentDest;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MeshRenderer" /> class.
|
||||
@@ -78,9 +80,11 @@ namespace MeshExplorer.Topology
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectTriangle(OrientedTriangle tri)
|
||||
public void SelectTriangle(ITriangle tri, Vertex org, Vertex dest)
|
||||
{
|
||||
selection = tri;
|
||||
currentTri = tri;
|
||||
currentOrg = org;
|
||||
currentDest = dest;
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
@@ -136,7 +140,7 @@ namespace MeshExplorer.Topology
|
||||
int n = points.Length;
|
||||
PointF pt;
|
||||
|
||||
int id = selection != null ? selection.Org().ID : -1;
|
||||
int id = currentOrg != null ? currentOrg.ID : -1;
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
@@ -245,12 +249,12 @@ namespace MeshExplorer.Topology
|
||||
|
||||
private void RenderSelectedEdge(Graphics g)
|
||||
{
|
||||
if (selection != null)
|
||||
if (currentTri != null)
|
||||
{
|
||||
PointF p0, p1;
|
||||
|
||||
p0 = points[selection.Org().ID];
|
||||
p1 = points[selection.Dest().ID];
|
||||
p0 = points[currentOrg.ID];
|
||||
p1 = points[currentDest.ID];
|
||||
|
||||
zoom.WorldToScreen(ref p0);
|
||||
zoom.WorldToScreen(ref p1);
|
||||
@@ -261,15 +265,13 @@ namespace MeshExplorer.Topology
|
||||
|
||||
private void RenderSelectedTriangle(Graphics g)
|
||||
{
|
||||
if (selection != null)
|
||||
if (currentTri != null)
|
||||
{
|
||||
var tri = selection.Triangle;
|
||||
|
||||
var p = new PointF[3];
|
||||
|
||||
p[0] = points[tri.P0];
|
||||
p[1] = points[tri.P1];
|
||||
p[2] = points[tri.P2];
|
||||
p[0] = points[currentTri.P0];
|
||||
p[1] = points[currentTri.P1];
|
||||
p[2] = points[currentTri.P2];
|
||||
|
||||
zoom.WorldToScreen(ref p[0]);
|
||||
zoom.WorldToScreen(ref p[1]);
|
||||
|
||||
@@ -197,7 +197,7 @@ namespace TriangleNet.IO
|
||||
|
||||
foreach (var item in mesh.triangles.Values)
|
||||
{
|
||||
tri.triangle = item;
|
||||
tri.tri = item;
|
||||
|
||||
p1 = tri.Org();
|
||||
p2 = tri.Dest();
|
||||
@@ -208,19 +208,19 @@ namespace TriangleNet.IO
|
||||
h3 = (p3 == null) ? -1 : p3.hash;
|
||||
|
||||
// Triangle number, indices for three vertices.
|
||||
stream.Write("{0} {1} {2} {3}", tri.triangle.hash, h1, h2, h3);
|
||||
stream.Write("{0} {1} {2} {3}", tri.tri.hash, h1, h2, h3);
|
||||
|
||||
tri.orient = 1;
|
||||
tri.Sym(ref trisym);
|
||||
n1 = trisym.triangle.hash;
|
||||
n1 = trisym.tri.hash;
|
||||
|
||||
tri.orient = 2;
|
||||
tri.Sym(ref trisym);
|
||||
n2 = trisym.triangle.hash;
|
||||
n2 = trisym.tri.hash;
|
||||
|
||||
tri.orient = 0;
|
||||
tri.Sym(ref trisym);
|
||||
n3 = trisym.triangle.hash;
|
||||
n3 = trisym.tri.hash;
|
||||
|
||||
// Neighboring triangle numbers.
|
||||
stream.WriteLine(" {0} {1} {2}", n1, n2, n3);
|
||||
|
||||
@@ -155,7 +155,7 @@ namespace TriangleNet.IO
|
||||
|
||||
foreach (var item in mesh.triangles.Values)
|
||||
{
|
||||
tri.triangle = item;
|
||||
tri.tri = item;
|
||||
|
||||
p1 = tri.Org();
|
||||
p2 = tri.Dest();
|
||||
@@ -166,7 +166,7 @@ namespace TriangleNet.IO
|
||||
|
||||
if (regions)
|
||||
{
|
||||
writer.Write(" {0}", tri.triangle.region);
|
||||
writer.Write(" {0}", tri.tri.region);
|
||||
}
|
||||
|
||||
writer.WriteLine();
|
||||
@@ -362,12 +362,12 @@ namespace TriangleNet.IO
|
||||
// considered only once.
|
||||
foreach (var item in mesh.triangles.Values)
|
||||
{
|
||||
tri.triangle = item;
|
||||
tri.tri = item;
|
||||
|
||||
for (tri.orient = 0; tri.orient < 3; tri.orient++)
|
||||
{
|
||||
tri.Sym(ref trisym);
|
||||
if ((tri.triangle.id < trisym.triangle.id) || (trisym.triangle.id == Triangle.EmptyID))
|
||||
if ((tri.tri.id < trisym.tri.id) || (trisym.tri.id == Triangle.EmptyID))
|
||||
{
|
||||
p1 = tri.Org();
|
||||
p2 = tri.Dest();
|
||||
@@ -378,7 +378,7 @@ namespace TriangleNet.IO
|
||||
// If there's no subsegment, the boundary marker is zero.
|
||||
if (behavior.useSegments)
|
||||
{
|
||||
tri.SegPivot(ref checkmark);
|
||||
tri.Pivot(ref checkmark);
|
||||
|
||||
if (checkmark.seg == Segment.Empty)
|
||||
{
|
||||
@@ -393,7 +393,7 @@ namespace TriangleNet.IO
|
||||
else
|
||||
{
|
||||
writer.WriteLine("{0} {1} {2} {3}", index, p1.id, p2.id,
|
||||
trisym.triangle.id == Triangle.EmptyID ? "1" : "0");
|
||||
trisym.tri.id == Triangle.EmptyID ? "1" : "0");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -429,19 +429,19 @@ namespace TriangleNet.IO
|
||||
|
||||
foreach (var item in mesh.triangles.Values)
|
||||
{
|
||||
tri.triangle = item;
|
||||
tri.tri = item;
|
||||
|
||||
tri.orient = 1;
|
||||
tri.Sym(ref trisym);
|
||||
n1 = trisym.triangle.id;
|
||||
n1 = trisym.tri.id;
|
||||
|
||||
tri.orient = 2;
|
||||
tri.Sym(ref trisym);
|
||||
n2 = trisym.triangle.id;
|
||||
n2 = trisym.tri.id;
|
||||
|
||||
tri.orient = 0;
|
||||
tri.Sym(ref trisym);
|
||||
n3 = trisym.triangle.id;
|
||||
n3 = trisym.tri.id;
|
||||
|
||||
// Triangle number, neighboring triangle numbers.
|
||||
writer.WriteLine("{0} {1} {2} {3}", i++, n1, n2, n3);
|
||||
@@ -481,7 +481,7 @@ namespace TriangleNet.IO
|
||||
|
||||
foreach (var item in mesh.triangles.Values)
|
||||
{
|
||||
tri.triangle = item;
|
||||
tri.tri = item;
|
||||
torg = tri.Org();
|
||||
tdest = tri.Dest();
|
||||
tapex = tri.Apex();
|
||||
@@ -501,7 +501,7 @@ namespace TriangleNet.IO
|
||||
}
|
||||
writer.WriteLine();
|
||||
|
||||
tri.triangle.id = index++;
|
||||
tri.tri.id = index++;
|
||||
}
|
||||
|
||||
|
||||
@@ -517,17 +517,17 @@ namespace TriangleNet.IO
|
||||
// considered only once.
|
||||
foreach (var item in mesh.triangles.Values)
|
||||
{
|
||||
tri.triangle = item;
|
||||
tri.tri = item;
|
||||
|
||||
for (tri.orient = 0; tri.orient < 3; tri.orient++)
|
||||
{
|
||||
tri.Sym(ref trisym);
|
||||
if ((tri.triangle.id < trisym.triangle.id) || (trisym.triangle.id == Triangle.EmptyID))
|
||||
if ((tri.tri.id < trisym.tri.id) || (trisym.tri.id == Triangle.EmptyID))
|
||||
{
|
||||
// Find the number of this triangle (and Voronoi vertex).
|
||||
p1 = tri.triangle.id;
|
||||
p1 = tri.tri.id;
|
||||
|
||||
if (trisym.triangle.id == Triangle.EmptyID)
|
||||
if (trisym.tri.id == Triangle.EmptyID)
|
||||
{
|
||||
torg = tri.Org();
|
||||
tdest = tri.Dest();
|
||||
@@ -542,7 +542,7 @@ namespace TriangleNet.IO
|
||||
else
|
||||
{
|
||||
// Find the number of the adjacent triangle (and Voronoi vertex).
|
||||
p2 = trisym.triangle.id;
|
||||
p2 = trisym.tri.id;
|
||||
// Finite edge. Write indices of two endpoints.
|
||||
writer.WriteLine("{0} {1} {2}", index, p1, p2);
|
||||
}
|
||||
@@ -599,7 +599,7 @@ namespace TriangleNet.IO
|
||||
tri.orient = 0;
|
||||
foreach (var item in mesh.triangles.Values)
|
||||
{
|
||||
tri.triangle = item;
|
||||
tri.tri = item;
|
||||
|
||||
p1 = tri.Org();
|
||||
p2 = tri.Dest();
|
||||
|
||||
@@ -569,7 +569,7 @@ namespace TriangleNet
|
||||
|
||||
foreach (var t in this.triangles.Values)
|
||||
{
|
||||
tri.triangle = t;
|
||||
tri.tri = t;
|
||||
// Check all three vertices of the triangle.
|
||||
for (tri.orient = 0; tri.orient < 3; tri.orient++)
|
||||
{
|
||||
@@ -593,7 +593,7 @@ namespace TriangleNet
|
||||
tri.hash = this.hash_tri++;
|
||||
tri.id = tri.hash;
|
||||
|
||||
newotri.triangle = tri;
|
||||
newotri.tri = tri;
|
||||
newotri.orient = 0;
|
||||
|
||||
triangles.Add(tri.hash, tri);
|
||||
@@ -702,12 +702,12 @@ namespace TriangleNet
|
||||
{
|
||||
// Find the location of the vertex to be inserted. Check if a good
|
||||
// starting triangle has already been provided by the caller.
|
||||
if (searchtri.triangle.id == Triangle.EmptyID)
|
||||
if (searchtri.tri.id == Triangle.EmptyID)
|
||||
{
|
||||
// Find a boundary triangle.
|
||||
horiz.triangle = Triangle.Empty;
|
||||
horiz.tri = Triangle.Empty;
|
||||
horiz.orient = 0;
|
||||
horiz.SymSelf();
|
||||
horiz.Sym();
|
||||
// Search for a triangle containing 'newvertex'.
|
||||
intersect = locator.Locate(newvertex, ref horiz);
|
||||
}
|
||||
@@ -740,7 +740,7 @@ namespace TriangleNet
|
||||
if (checksegments && (splitseg.seg == null))
|
||||
{
|
||||
// Check whether the vertex falls on a subsegment.
|
||||
horiz.SegPivot(ref brokensubseg);
|
||||
horiz.Pivot(ref brokensubseg);
|
||||
if (brokensubseg.seg != Segment.Empty)
|
||||
{
|
||||
// The vertex falls on a subsegment, and hence will not be inserted.
|
||||
@@ -752,7 +752,7 @@ namespace TriangleNet
|
||||
// This subsegment may be split only if it is an
|
||||
// internal boundary.
|
||||
horiz.Sym(ref testtri);
|
||||
enq = testtri.triangle.id != Triangle.EmptyID;
|
||||
enq = testtri.tri.id != Triangle.EmptyID;
|
||||
}
|
||||
if (enq)
|
||||
{
|
||||
@@ -779,10 +779,10 @@ namespace TriangleNet
|
||||
botright.Sym(ref botrcasing);
|
||||
horiz.Sym(ref topright);
|
||||
// Is there a second triangle? (Or does this edge lie on a boundary?)
|
||||
mirrorflag = topright.triangle.id != Triangle.EmptyID;
|
||||
mirrorflag = topright.tri.id != Triangle.EmptyID;
|
||||
if (mirrorflag)
|
||||
{
|
||||
topright.LnextSelf();
|
||||
topright.Lnext();
|
||||
topright.Sym(ref toprcasing);
|
||||
MakeTriangle(ref newtopright);
|
||||
}
|
||||
@@ -803,12 +803,12 @@ namespace TriangleNet
|
||||
horiz.SetOrg(newvertex);
|
||||
|
||||
// Set the region of a new triangle.
|
||||
newbotright.triangle.region = botright.triangle.region;
|
||||
newbotright.tri.region = botright.tri.region;
|
||||
|
||||
if (behavior.VarArea)
|
||||
{
|
||||
// Set the area constraint of a new triangle.
|
||||
newbotright.triangle.area = botright.triangle.area;
|
||||
newbotright.tri.area = botright.tri.area;
|
||||
}
|
||||
|
||||
if (mirrorflag)
|
||||
@@ -820,12 +820,12 @@ namespace TriangleNet
|
||||
topright.SetOrg(newvertex);
|
||||
|
||||
// Set the region of another new triangle.
|
||||
newtopright.triangle.region = topright.triangle.region;
|
||||
newtopright.tri.region = topright.tri.region;
|
||||
|
||||
if (behavior.VarArea)
|
||||
{
|
||||
// Set the area constraint of another new triangle.
|
||||
newtopright.triangle.area = topright.triangle.area;
|
||||
newtopright.tri.area = topright.tri.area;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -833,7 +833,7 @@ namespace TriangleNet
|
||||
// to the new triangle(s).
|
||||
if (checksegments)
|
||||
{
|
||||
botright.SegPivot(ref botrsubseg);
|
||||
botright.Pivot(ref botrsubseg);
|
||||
|
||||
if (botrsubseg.seg != Segment.Empty)
|
||||
{
|
||||
@@ -843,7 +843,7 @@ namespace TriangleNet
|
||||
|
||||
if (mirrorflag)
|
||||
{
|
||||
topright.SegPivot(ref toprsubseg);
|
||||
topright.Pivot(ref toprsubseg);
|
||||
if (toprsubseg.seg != Segment.Empty)
|
||||
{
|
||||
topright.SegDissolve();
|
||||
@@ -854,16 +854,16 @@ namespace TriangleNet
|
||||
|
||||
// Bond the new triangle(s) to the surrounding triangles.
|
||||
newbotright.Bond(ref botrcasing);
|
||||
newbotright.LprevSelf();
|
||||
newbotright.Lprev();
|
||||
newbotright.Bond(ref botright);
|
||||
newbotright.LprevSelf();
|
||||
newbotright.Lprev();
|
||||
|
||||
if (mirrorflag)
|
||||
{
|
||||
newtopright.Bond(ref toprcasing);
|
||||
newtopright.LnextSelf();
|
||||
newtopright.Lnext();
|
||||
newtopright.Bond(ref topright);
|
||||
newtopright.LnextSelf();
|
||||
newtopright.Lnext();
|
||||
newtopright.Bond(ref newbotright);
|
||||
}
|
||||
|
||||
@@ -873,16 +873,16 @@ namespace TriangleNet
|
||||
splitseg.SetDest(newvertex);
|
||||
segmentorg = splitseg.SegOrg();
|
||||
segmentdest = splitseg.SegDest();
|
||||
splitseg.SymSelf();
|
||||
splitseg.Sym();
|
||||
splitseg.Pivot(ref rightsubseg);
|
||||
InsertSubseg(ref newbotright, splitseg.seg.boundary);
|
||||
newbotright.SegPivot(ref newsubseg);
|
||||
newbotright.Pivot(ref newsubseg);
|
||||
newsubseg.SetSegOrg(segmentorg);
|
||||
newsubseg.SetSegDest(segmentdest);
|
||||
splitseg.Bond(ref newsubseg);
|
||||
newsubseg.SymSelf();
|
||||
newsubseg.Sym();
|
||||
newsubseg.Bond(ref rightsubseg);
|
||||
splitseg.SymSelf();
|
||||
splitseg.Sym();
|
||||
|
||||
// Transfer the subsegment's boundary marker to the vertex if required.
|
||||
if (newvertex.mark == 0)
|
||||
@@ -901,7 +901,7 @@ namespace TriangleNet
|
||||
|
||||
// Position 'horiz' on the first edge to check for
|
||||
// the Delaunay property.
|
||||
horiz.LnextSelf();
|
||||
horiz.Lnext();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -926,28 +926,28 @@ namespace TriangleNet
|
||||
horiz.SetApex(newvertex);
|
||||
|
||||
// Set the region of the new triangles.
|
||||
newbotleft.triangle.region = horiz.triangle.region;
|
||||
newbotright.triangle.region = horiz.triangle.region;
|
||||
newbotleft.tri.region = horiz.tri.region;
|
||||
newbotright.tri.region = horiz.tri.region;
|
||||
|
||||
if (behavior.VarArea)
|
||||
{
|
||||
// Set the area constraint of the new triangles.
|
||||
area = horiz.triangle.area;
|
||||
newbotleft.triangle.area = area;
|
||||
newbotright.triangle.area = area;
|
||||
area = horiz.tri.area;
|
||||
newbotleft.tri.area = area;
|
||||
newbotright.tri.area = area;
|
||||
}
|
||||
|
||||
// There may be subsegments that need to be bonded
|
||||
// to the new triangles.
|
||||
if (checksegments)
|
||||
{
|
||||
botleft.SegPivot(ref botlsubseg);
|
||||
botleft.Pivot(ref botlsubseg);
|
||||
if (botlsubseg.seg != Segment.Empty)
|
||||
{
|
||||
botleft.SegDissolve();
|
||||
newbotleft.SegBond(ref botlsubseg);
|
||||
}
|
||||
botright.SegPivot(ref botrsubseg);
|
||||
botright.Pivot(ref botrsubseg);
|
||||
if (botrsubseg.seg != Segment.Empty)
|
||||
{
|
||||
botright.SegDissolve();
|
||||
@@ -958,12 +958,12 @@ namespace TriangleNet
|
||||
// Bond the new triangles to the surrounding triangles.
|
||||
newbotleft.Bond(ref botlcasing);
|
||||
newbotright.Bond(ref botrcasing);
|
||||
newbotleft.LnextSelf();
|
||||
newbotright.LprevSelf();
|
||||
newbotleft.Lnext();
|
||||
newbotright.Lprev();
|
||||
newbotleft.Bond(ref newbotright);
|
||||
newbotleft.LnextSelf();
|
||||
newbotleft.Lnext();
|
||||
botleft.Bond(ref newbotleft);
|
||||
newbotright.LprevSelf();
|
||||
newbotright.Lprev();
|
||||
botright.Bond(ref newbotright);
|
||||
|
||||
if (checkquality)
|
||||
@@ -991,7 +991,7 @@ namespace TriangleNet
|
||||
if (checksegments)
|
||||
{
|
||||
// Check for a subsegment, which cannot be flipped.
|
||||
horiz.SegPivot(ref checksubseg);
|
||||
horiz.Pivot(ref checksubseg);
|
||||
if (checksubseg.seg != Segment.Empty)
|
||||
{
|
||||
// The edge is a subsegment and cannot be flipped.
|
||||
@@ -1012,7 +1012,7 @@ namespace TriangleNet
|
||||
{
|
||||
// Check if the edge is a boundary edge.
|
||||
horiz.Sym(ref top);
|
||||
if (top.triangle.id == Triangle.EmptyID)
|
||||
if (top.tri.id == Triangle.EmptyID)
|
||||
{
|
||||
// The edge is a boundary edge and cannot be flipped.
|
||||
doflip = false;
|
||||
@@ -1079,10 +1079,10 @@ namespace TriangleNet
|
||||
if (checksegments)
|
||||
{
|
||||
// Check for subsegments and rebond them to the quadrilateral.
|
||||
topleft.SegPivot(ref toplsubseg);
|
||||
botleft.SegPivot(ref botlsubseg);
|
||||
botright.SegPivot(ref botrsubseg);
|
||||
topright.SegPivot(ref toprsubseg);
|
||||
topleft.Pivot(ref toplsubseg);
|
||||
botleft.Pivot(ref botlsubseg);
|
||||
botright.Pivot(ref botrsubseg);
|
||||
topright.Pivot(ref toprsubseg);
|
||||
if (toplsubseg.seg == Segment.Empty)
|
||||
{
|
||||
topright.SegDissolve();
|
||||
@@ -1126,13 +1126,13 @@ namespace TriangleNet
|
||||
|
||||
// Assign region.
|
||||
// TODO: check region ok (no Math.Min necessary)
|
||||
region = Math.Min(top.triangle.region, horiz.triangle.region);
|
||||
top.triangle.region = region;
|
||||
horiz.triangle.region = region;
|
||||
region = Math.Min(top.tri.region, horiz.tri.region);
|
||||
top.tri.region = region;
|
||||
horiz.tri.region = region;
|
||||
|
||||
if (behavior.VarArea)
|
||||
{
|
||||
if ((top.triangle.area <= 0.0) || (horiz.triangle.area <= 0.0))
|
||||
if ((top.tri.area <= 0.0) || (horiz.tri.area <= 0.0))
|
||||
{
|
||||
area = -1.0;
|
||||
}
|
||||
@@ -1141,11 +1141,11 @@ namespace TriangleNet
|
||||
// Take the average of the two triangles' area constraints.
|
||||
// This prevents small area constraints from migrating a
|
||||
// long, long way from their original location due to flips.
|
||||
area = 0.5 * (top.triangle.area + horiz.triangle.area);
|
||||
area = 0.5 * (top.tri.area + horiz.tri.area);
|
||||
}
|
||||
|
||||
top.triangle.area = area;
|
||||
horiz.triangle.area = area;
|
||||
top.tri.area = area;
|
||||
horiz.tri.area = area;
|
||||
}
|
||||
|
||||
if (checkquality)
|
||||
@@ -1155,7 +1155,7 @@ namespace TriangleNet
|
||||
|
||||
// On the next iterations, consider the two edges that were exposed (this
|
||||
// is, are now visible to the newly inserted vertex) by the edge flip.
|
||||
horiz.LprevSelf();
|
||||
horiz.Lprev();
|
||||
leftvertex = farvertex;
|
||||
}
|
||||
}
|
||||
@@ -1170,12 +1170,12 @@ namespace TriangleNet
|
||||
}
|
||||
|
||||
// Look for the next edge around the newly inserted vertex.
|
||||
horiz.LnextSelf();
|
||||
horiz.Lnext();
|
||||
horiz.Sym(ref testtri);
|
||||
// Check for finishing a complete revolution about the new vertex, or
|
||||
// falling outside of the triangulation. The latter will happen when
|
||||
// a vertex is inserted at a boundary.
|
||||
if ((leftvertex == first) || (testtri.triangle.id == Triangle.EmptyID))
|
||||
if ((leftvertex == first) || (testtri.tri.id == Triangle.EmptyID))
|
||||
{
|
||||
// We're done. Return a triangle whose origin is the new vertex.
|
||||
horiz.Lnext(ref searchtri);
|
||||
@@ -1220,7 +1220,7 @@ namespace TriangleNet
|
||||
tridest.mark = subsegmark;
|
||||
}
|
||||
// Check if there's already a subsegment here.
|
||||
tri.SegPivot(ref newsubseg);
|
||||
tri.Pivot(ref newsubseg);
|
||||
if (newsubseg.seg == Segment.Empty)
|
||||
{
|
||||
// Make new subsegment and initialize its vertices.
|
||||
@@ -1234,7 +1234,7 @@ namespace TriangleNet
|
||||
// (outer space), but the new subsegment is bonded to it all the same.
|
||||
tri.SegBond(ref newsubseg);
|
||||
tri.Sym(ref oppotri);
|
||||
newsubseg.SymSelf();
|
||||
newsubseg.Sym();
|
||||
oppotri.SegBond(ref newsubseg);
|
||||
newsubseg.seg.boundary = subsegmark;
|
||||
}
|
||||
@@ -1344,10 +1344,10 @@ namespace TriangleNet
|
||||
if (checksegments)
|
||||
{
|
||||
// Check for subsegments and rebond them to the quadrilateral.
|
||||
topleft.SegPivot(ref toplsubseg);
|
||||
botleft.SegPivot(ref botlsubseg);
|
||||
botright.SegPivot(ref botrsubseg);
|
||||
topright.SegPivot(ref toprsubseg);
|
||||
topleft.Pivot(ref toplsubseg);
|
||||
botleft.Pivot(ref botlsubseg);
|
||||
botright.Pivot(ref botrsubseg);
|
||||
topright.Pivot(ref toprsubseg);
|
||||
|
||||
if (toplsubseg.seg == Segment.Empty)
|
||||
{
|
||||
@@ -1447,10 +1447,10 @@ namespace TriangleNet
|
||||
if (checksegments)
|
||||
{
|
||||
// Check for subsegments and rebond them to the quadrilateral.
|
||||
topleft.SegPivot(ref toplsubseg);
|
||||
botleft.SegPivot(ref botlsubseg);
|
||||
botright.SegPivot(ref botrsubseg);
|
||||
topright.SegPivot(ref toprsubseg);
|
||||
topleft.Pivot(ref toplsubseg);
|
||||
botleft.Pivot(ref botlsubseg);
|
||||
botright.Pivot(ref botrsubseg);
|
||||
topright.Pivot(ref toprsubseg);
|
||||
if (toplsubseg.seg == Segment.Empty)
|
||||
{
|
||||
botleft.SegDissolve();
|
||||
@@ -1580,7 +1580,7 @@ namespace TriangleNet
|
||||
|
||||
for (int i = 2; i <= edgecount - 2; i++)
|
||||
{
|
||||
testtri.OnextSelf();
|
||||
testtri.Onext();
|
||||
testvertex = testtri.Dest();
|
||||
// Is this a better vertex?
|
||||
if (RobustPredicates.InCircle(leftbasevertex, rightbasevertex, bestvertex, testvertex) > 0.0)
|
||||
@@ -1656,7 +1656,7 @@ namespace TriangleNet
|
||||
while (!deltri.Equal(countingtri))
|
||||
{
|
||||
edgecount++;
|
||||
countingtri.OnextSelf();
|
||||
countingtri.Onext();
|
||||
}
|
||||
|
||||
if (edgecount > 3)
|
||||
@@ -1676,12 +1676,12 @@ namespace TriangleNet
|
||||
righttri.Sym(ref rightcasing);
|
||||
deltri.Bond(ref leftcasing);
|
||||
deltriright.Bond(ref rightcasing);
|
||||
lefttri.SegPivot(ref leftsubseg);
|
||||
lefttri.Pivot(ref leftsubseg);
|
||||
if (leftsubseg.seg != Segment.Empty)
|
||||
{
|
||||
deltri.SegBond(ref leftsubseg);
|
||||
}
|
||||
righttri.SegPivot(ref rightsubseg);
|
||||
righttri.Pivot(ref rightsubseg);
|
||||
if (rightsubseg.seg != Segment.Empty)
|
||||
{
|
||||
deltriright.SegBond(ref rightsubseg);
|
||||
@@ -1696,8 +1696,8 @@ namespace TriangleNet
|
||||
}
|
||||
|
||||
// Delete the two spliced-out triangles.
|
||||
TriangleDealloc(lefttri.triangle);
|
||||
TriangleDealloc(righttri.triangle);
|
||||
TriangleDealloc(lefttri.tri);
|
||||
TriangleDealloc(righttri.tri);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1735,59 +1735,59 @@ namespace TriangleNet
|
||||
// Restore a triangle that was split into three triangles,
|
||||
// so it is again one triangle.
|
||||
fliptri.Dprev(ref botleft);
|
||||
botleft.LnextSelf();
|
||||
botleft.Lnext();
|
||||
fliptri.Onext(ref botright);
|
||||
botright.LprevSelf();
|
||||
botright.Lprev();
|
||||
botleft.Sym(ref botlcasing);
|
||||
botright.Sym(ref botrcasing);
|
||||
botvertex = botleft.Dest();
|
||||
|
||||
fliptri.SetApex(botvertex);
|
||||
fliptri.LnextSelf();
|
||||
fliptri.Lnext();
|
||||
fliptri.Bond(ref botlcasing);
|
||||
botleft.SegPivot(ref botlsubseg);
|
||||
botleft.Pivot(ref botlsubseg);
|
||||
fliptri.SegBond(ref botlsubseg);
|
||||
fliptri.LnextSelf();
|
||||
fliptri.Lnext();
|
||||
fliptri.Bond(ref botrcasing);
|
||||
botright.SegPivot(ref botrsubseg);
|
||||
botright.Pivot(ref botrsubseg);
|
||||
fliptri.SegBond(ref botrsubseg);
|
||||
|
||||
// Delete the two spliced-out triangles.
|
||||
TriangleDealloc(botleft.triangle);
|
||||
TriangleDealloc(botright.triangle);
|
||||
TriangleDealloc(botleft.tri);
|
||||
TriangleDealloc(botright.tri);
|
||||
}
|
||||
else if (flipstack.Peek().triangle == null) // Dummy flip
|
||||
else if (flipstack.Peek().tri == null) // Dummy flip
|
||||
{
|
||||
// Restore two triangles that were split into four triangles,
|
||||
// so they are again two triangles.
|
||||
fliptri.Lprev(ref gluetri);
|
||||
gluetri.Sym(ref botright);
|
||||
botright.LnextSelf();
|
||||
botright.Lnext();
|
||||
botright.Sym(ref botrcasing);
|
||||
rightvertex = botright.Dest();
|
||||
|
||||
fliptri.SetOrg(rightvertex);
|
||||
gluetri.Bond(ref botrcasing);
|
||||
botright.SegPivot(ref botrsubseg);
|
||||
botright.Pivot(ref botrsubseg);
|
||||
gluetri.SegBond(ref botrsubseg);
|
||||
|
||||
// Delete the spliced-out triangle.
|
||||
TriangleDealloc(botright.triangle);
|
||||
TriangleDealloc(botright.tri);
|
||||
|
||||
fliptri.Sym(ref gluetri);
|
||||
if (gluetri.triangle.id != Triangle.EmptyID)
|
||||
if (gluetri.tri.id != Triangle.EmptyID)
|
||||
{
|
||||
gluetri.LnextSelf();
|
||||
gluetri.Lnext();
|
||||
gluetri.Dnext(ref topright);
|
||||
topright.Sym(ref toprcasing);
|
||||
|
||||
gluetri.SetOrg(rightvertex);
|
||||
gluetri.Bond(ref toprcasing);
|
||||
topright.SegPivot(ref toprsubseg);
|
||||
topright.Pivot(ref toprsubseg);
|
||||
gluetri.SegBond(ref toprsubseg);
|
||||
|
||||
// Delete the spliced-out triangle.
|
||||
TriangleDealloc(topright.triangle);
|
||||
TriangleDealloc(topright.tri);
|
||||
}
|
||||
|
||||
flipstack.Clear();
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace TriangleNet
|
||||
// Run through the list of triangles, checking each one.
|
||||
foreach (var t in mesh.triangles.Values)
|
||||
{
|
||||
tri.triangle = t;
|
||||
tri.tri = t;
|
||||
|
||||
// Check all three edges of the triangle.
|
||||
for (tri.orient = 0; tri.orient < 3; tri.orient++)
|
||||
@@ -59,13 +59,13 @@ namespace TriangleNet
|
||||
|
||||
// Find the neighboring triangle on this edge.
|
||||
tri.Sym(ref oppotri);
|
||||
if (oppotri.triangle.id != Triangle.EmptyID)
|
||||
if (oppotri.tri.id != Triangle.EmptyID)
|
||||
{
|
||||
// Check that the triangle's neighbor knows it's a neighbor.
|
||||
oppotri.Sym(ref oppooppotri);
|
||||
if ((tri.triangle != oppooppotri.triangle) || (tri.orient != oppooppotri.orient))
|
||||
if ((tri.tri != oppooppotri.tri) || (tri.orient != oppooppotri.orient))
|
||||
{
|
||||
if (tri.triangle == oppooppotri.triangle && Log.Verbose)
|
||||
if (tri.tri == oppooppotri.tri && Log.Verbose)
|
||||
{
|
||||
logger.Warning("Asymmetric triangle-triangle bond: (Right triangle, wrong orientation)",
|
||||
"MeshValidator.IsConsistent()");
|
||||
@@ -95,7 +95,7 @@ namespace TriangleNet
|
||||
mesh.MakeVertexMap();
|
||||
foreach (var v in mesh.vertices.Values)
|
||||
{
|
||||
if (v.tri.triangle == null && Log.Verbose)
|
||||
if (v.tri.tri == null && Log.Verbose)
|
||||
{
|
||||
logger.Warning("Vertex (ID " + v.id + ") not connected to mesh (duplicate input vertex?)",
|
||||
"MeshValidator.IsConsistent()");
|
||||
@@ -152,7 +152,7 @@ namespace TriangleNet
|
||||
// Run through the list of triangles, checking each one.
|
||||
foreach (var tri in mesh.triangles.Values)
|
||||
{
|
||||
loop.triangle = tri;
|
||||
loop.tri = tri;
|
||||
|
||||
// Check all three edges of the triangle.
|
||||
for (loop.orient = 0; loop.orient < 3; loop.orient++)
|
||||
@@ -167,8 +167,8 @@ namespace TriangleNet
|
||||
// Only test that the edge is locally Delaunay if there is an
|
||||
// adjoining triangle whose pointer is larger (to ensure that
|
||||
// each pair isn't tested twice).
|
||||
shouldbedelaunay = (loop.triangle.id < oppotri.triangle.id) &&
|
||||
!Otri.IsDead(oppotri.triangle) && (oppotri.triangle.id != Triangle.EmptyID) &&
|
||||
shouldbedelaunay = (loop.tri.id < oppotri.tri.id) &&
|
||||
!Otri.IsDead(oppotri.tri) && (oppotri.tri.id != Triangle.EmptyID) &&
|
||||
(org != inf1) && (org != inf2) && (org != inf3) &&
|
||||
(dest != inf1) && (dest != inf2) && (dest != inf3) &&
|
||||
(apex != inf1) && (apex != inf2) && (apex != inf3) &&
|
||||
@@ -178,7 +178,7 @@ namespace TriangleNet
|
||||
{
|
||||
// If a subsegment separates the triangles, then the edge is
|
||||
// constrained, so no local Delaunay test should be done.
|
||||
loop.SegPivot(ref opposubseg);
|
||||
loop.Pivot(ref opposubseg);
|
||||
|
||||
if (opposubseg.seg != Segment.Empty)
|
||||
{
|
||||
@@ -193,7 +193,7 @@ namespace TriangleNet
|
||||
if (Log.Verbose)
|
||||
{
|
||||
logger.Warning(String.Format("Non-regular pair of triangles found (IDs {0}/{1}).",
|
||||
loop.triangle.id, oppotri.triangle.id), "MeshValidator.IsDelaunay()");
|
||||
loop.tri.id, oppotri.tri.id), "MeshValidator.IsDelaunay()");
|
||||
}
|
||||
|
||||
horrors++;
|
||||
|
||||
@@ -400,8 +400,8 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
// leftmost and rightmost vertices.
|
||||
while (farleftapex.y < farleftpt.y)
|
||||
{
|
||||
farleft.LnextSelf();
|
||||
farleft.SymSelf();
|
||||
farleft.Lnext();
|
||||
farleft.Sym();
|
||||
farleftpt = farleftapex;
|
||||
farleftapex = farleft.Apex();
|
||||
}
|
||||
@@ -417,8 +417,8 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
}
|
||||
while (innerrightapex.y < innerrightorg.y)
|
||||
{
|
||||
innerright.LnextSelf();
|
||||
innerright.SymSelf();
|
||||
innerright.Lnext();
|
||||
innerright.Sym();
|
||||
innerrightorg = innerrightapex;
|
||||
innerrightapex = innerright.Apex();
|
||||
}
|
||||
@@ -440,8 +440,8 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
// Make innerleftdest the "bottommost" vertex of the left hull.
|
||||
if (RobustPredicates.CounterClockwise(innerleftdest, innerleftapex, innerrightorg) > 0.0)
|
||||
{
|
||||
innerleft.LprevSelf();
|
||||
innerleft.SymSelf();
|
||||
innerleft.Lprev();
|
||||
innerleft.Sym();
|
||||
innerleftdest = innerleftapex;
|
||||
innerleftapex = innerleft.Apex();
|
||||
changemade = true;
|
||||
@@ -449,8 +449,8 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
// Make innerrightorg the "bottommost" vertex of the right hull.
|
||||
if (RobustPredicates.CounterClockwise(innerrightapex, innerrightorg, innerleftdest) > 0.0)
|
||||
{
|
||||
innerright.LnextSelf();
|
||||
innerright.SymSelf();
|
||||
innerright.Lnext();
|
||||
innerright.Sym();
|
||||
innerrightorg = innerrightapex;
|
||||
innerrightapex = innerright.Apex();
|
||||
changemade = true;
|
||||
@@ -464,9 +464,9 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
mesh.MakeTriangle(ref baseedge);
|
||||
// Connect it to the bounding boxes of the left and right triangulations.
|
||||
baseedge.Bond(ref innerleft);
|
||||
baseedge.LnextSelf();
|
||||
baseedge.Lnext();
|
||||
baseedge.Bond(ref innerright);
|
||||
baseedge.LnextSelf();
|
||||
baseedge.Lnext();
|
||||
baseedge.SetOrg(innerrightorg);
|
||||
baseedge.SetDest(innerleftdest);
|
||||
// Apex is intentionally left NULL.
|
||||
@@ -506,9 +506,9 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
// Apex is intentionally left NULL.
|
||||
// Connect it to the bounding boxes of the two triangulations.
|
||||
nextedge.Bond(ref baseedge);
|
||||
nextedge.LnextSelf();
|
||||
nextedge.Lnext();
|
||||
nextedge.Bond(ref rightcand);
|
||||
nextedge.LnextSelf();
|
||||
nextedge.Lnext();
|
||||
nextedge.Bond(ref leftcand);
|
||||
|
||||
// Special treatment for horizontal cuts.
|
||||
@@ -533,8 +533,8 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
}
|
||||
while (farrightapex.x > farrightpt.x)
|
||||
{
|
||||
farright.LprevSelf();
|
||||
farright.SymSelf();
|
||||
farright.Lprev();
|
||||
farright.Sym();
|
||||
farrightpt = farrightapex;
|
||||
farrightapex = farright.Apex();
|
||||
}
|
||||
@@ -546,7 +546,7 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
{
|
||||
// What vertex would be exposed if an edge were deleted?
|
||||
leftcand.Lprev(ref nextedge);
|
||||
nextedge.SymSelf();
|
||||
nextedge.Sym();
|
||||
nextapex = nextedge.Apex();
|
||||
// If nextapex is NULL, then no vertex would be exposed; the
|
||||
// triangulation would have been eaten right through.
|
||||
@@ -558,15 +558,15 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
{
|
||||
// Eliminate the edge with an edge flip. As a result, the
|
||||
// left triangulation will have one more boundary triangle.
|
||||
nextedge.LnextSelf();
|
||||
nextedge.Lnext();
|
||||
nextedge.Sym(ref topcasing);
|
||||
nextedge.LnextSelf();
|
||||
nextedge.Lnext();
|
||||
nextedge.Sym(ref sidecasing);
|
||||
nextedge.Bond(ref topcasing);
|
||||
leftcand.Bond(ref sidecasing);
|
||||
leftcand.LnextSelf();
|
||||
leftcand.Lnext();
|
||||
leftcand.Sym(ref outercasing);
|
||||
nextedge.LprevSelf();
|
||||
nextedge.Lprev();
|
||||
nextedge.Bond(ref outercasing);
|
||||
// Correct the vertices to reflect the edge flip.
|
||||
leftcand.SetOrg(lowerleft);
|
||||
@@ -598,7 +598,7 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
{
|
||||
// What vertex would be exposed if an edge were deleted?
|
||||
rightcand.Lnext(ref nextedge);
|
||||
nextedge.SymSelf();
|
||||
nextedge.Sym();
|
||||
nextapex = nextedge.Apex();
|
||||
// If nextapex is NULL, then no vertex would be exposed; the
|
||||
// triangulation would have been eaten right through.
|
||||
@@ -610,15 +610,15 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
{
|
||||
// Eliminate the edge with an edge flip. As a result, the
|
||||
// right triangulation will have one more boundary triangle.
|
||||
nextedge.LprevSelf();
|
||||
nextedge.Lprev();
|
||||
nextedge.Sym(ref topcasing);
|
||||
nextedge.LprevSelf();
|
||||
nextedge.Lprev();
|
||||
nextedge.Sym(ref sidecasing);
|
||||
nextedge.Bond(ref topcasing);
|
||||
rightcand.Bond(ref sidecasing);
|
||||
rightcand.LprevSelf();
|
||||
rightcand.Lprev();
|
||||
rightcand.Sym(ref outercasing);
|
||||
nextedge.LnextSelf();
|
||||
nextedge.Lnext();
|
||||
nextedge.Bond(ref outercasing);
|
||||
// Correct the vertices to reflect the edge flip.
|
||||
rightcand.SetOrg(null);
|
||||
@@ -715,11 +715,11 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
farright.SetDest(sortarray[left]);
|
||||
// The apex is intentionally left NULL.
|
||||
farleft.Bond(ref farright);
|
||||
farleft.LprevSelf();
|
||||
farright.LnextSelf();
|
||||
farleft.Lprev();
|
||||
farright.Lnext();
|
||||
farleft.Bond(ref farright);
|
||||
farleft.LprevSelf();
|
||||
farright.LnextSelf();
|
||||
farleft.Lprev();
|
||||
farright.Lnext();
|
||||
farleft.Bond(ref farright);
|
||||
|
||||
// Ensure that the origin of 'farleft' is sortarray[0].
|
||||
@@ -750,16 +750,16 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
// All apices are intentionally left NULL.
|
||||
midtri.Bond(ref tri1);
|
||||
tri2.Bond(ref tri3);
|
||||
midtri.LnextSelf();
|
||||
tri1.LprevSelf();
|
||||
tri2.LnextSelf();
|
||||
tri3.LprevSelf();
|
||||
midtri.Lnext();
|
||||
tri1.Lprev();
|
||||
tri2.Lnext();
|
||||
tri3.Lprev();
|
||||
midtri.Bond(ref tri3);
|
||||
tri1.Bond(ref tri2);
|
||||
midtri.LnextSelf();
|
||||
tri1.LprevSelf();
|
||||
tri2.LnextSelf();
|
||||
tri3.LprevSelf();
|
||||
midtri.Lnext();
|
||||
tri1.Lprev();
|
||||
tri2.Lnext();
|
||||
tri3.Lprev();
|
||||
midtri.Bond(ref tri1);
|
||||
tri2.Bond(ref tri3);
|
||||
// Ensure that the origin of 'farleft' is sortarray[0].
|
||||
@@ -797,18 +797,18 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
}
|
||||
// The topology does not depend on how the vertices are ordered.
|
||||
midtri.Bond(ref tri1);
|
||||
midtri.LnextSelf();
|
||||
midtri.Lnext();
|
||||
midtri.Bond(ref tri2);
|
||||
midtri.LnextSelf();
|
||||
midtri.Lnext();
|
||||
midtri.Bond(ref tri3);
|
||||
tri1.LprevSelf();
|
||||
tri2.LnextSelf();
|
||||
tri1.Lprev();
|
||||
tri2.Lnext();
|
||||
tri1.Bond(ref tri2);
|
||||
tri1.LprevSelf();
|
||||
tri3.LprevSelf();
|
||||
tri1.Lprev();
|
||||
tri3.Lprev();
|
||||
tri1.Bond(ref tri3);
|
||||
tri2.LnextSelf();
|
||||
tri3.LprevSelf();
|
||||
tri2.Lnext();
|
||||
tri3.Lprev();
|
||||
tri2.Bond(ref tri3);
|
||||
// Ensure that the origin of 'farleft' is sortarray[0].
|
||||
tri1.Copy(ref farleft);
|
||||
@@ -859,7 +859,7 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
|
||||
// Find an edge on the convex hull to start point location from.
|
||||
startghost.Lprev(ref searchedge);
|
||||
searchedge.SymSelf();
|
||||
searchedge.Sym();
|
||||
Triangle.Empty.neighbors[0] = searchedge;
|
||||
// Remove the bounding box and count the convex hull edges.
|
||||
startghost.Copy(ref dissolveedge);
|
||||
@@ -868,15 +868,15 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
{
|
||||
hullsize++;
|
||||
dissolveedge.Lnext(ref deadtriangle);
|
||||
dissolveedge.LprevSelf();
|
||||
dissolveedge.SymSelf();
|
||||
dissolveedge.Lprev();
|
||||
dissolveedge.Sym();
|
||||
|
||||
// If no PSLG is involved, set the boundary markers of all the vertices
|
||||
// on the convex hull. If a PSLG is used, this step is done later.
|
||||
if (noPoly)
|
||||
{
|
||||
// Watch out for the case where all the input vertices are collinear.
|
||||
if (dissolveedge.triangle.id != Triangle.EmptyID)
|
||||
if (dissolveedge.tri.id != Triangle.EmptyID)
|
||||
{
|
||||
markorg = dissolveedge.Org();
|
||||
if (markorg.mark == 0)
|
||||
@@ -891,7 +891,7 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
deadtriangle.Sym(ref dissolveedge);
|
||||
|
||||
// Delete the bounding triangle.
|
||||
mesh.TriangleDealloc(deadtriangle.triangle);
|
||||
mesh.TriangleDealloc(deadtriangle.tri);
|
||||
} while (!dissolveedge.Equal(startghost));
|
||||
|
||||
return hullsize;
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
|
||||
foreach (var v in mesh.vertices.Values)
|
||||
{
|
||||
starttri.triangle = Triangle.Empty;
|
||||
starttri.tri = Triangle.Empty;
|
||||
Osub tmp = default(Osub);
|
||||
if (mesh.InsertVertex(v, ref starttri, ref tmp, false, false) == InsertVertexResult.Duplicate)
|
||||
{
|
||||
@@ -115,28 +115,28 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
bool noPoly = !mesh.behavior.Poly;
|
||||
|
||||
// Find a boundary triangle.
|
||||
nextedge.triangle = Triangle.Empty;
|
||||
nextedge.tri = Triangle.Empty;
|
||||
nextedge.orient = 0;
|
||||
nextedge.SymSelf();
|
||||
nextedge.Sym();
|
||||
// Mark a place to stop.
|
||||
nextedge.Lprev(ref finaledge);
|
||||
nextedge.LnextSelf();
|
||||
nextedge.SymSelf();
|
||||
nextedge.Lnext();
|
||||
nextedge.Sym();
|
||||
// Find a triangle (on the boundary of the vertex set) that isn't
|
||||
// a bounding box triangle.
|
||||
nextedge.Lprev(ref searchedge);
|
||||
searchedge.SymSelf();
|
||||
searchedge.Sym();
|
||||
// Check whether nextedge is another boundary triangle
|
||||
// adjacent to the first one.
|
||||
nextedge.Lnext(ref checkedge);
|
||||
checkedge.SymSelf();
|
||||
if (checkedge.triangle.id == Triangle.EmptyID)
|
||||
checkedge.Sym();
|
||||
if (checkedge.tri.id == Triangle.EmptyID)
|
||||
{
|
||||
// Go on to the next triangle. There are only three boundary
|
||||
// triangles, and this next triangle cannot be the third one,
|
||||
// so it's safe to stop here.
|
||||
searchedge.LprevSelf();
|
||||
searchedge.SymSelf();
|
||||
searchedge.Lprev();
|
||||
searchedge.Sym();
|
||||
}
|
||||
// Find a new boundary edge to search from, as the current search
|
||||
// edge lies on a bounding box triangle and will be deleted.
|
||||
@@ -146,7 +146,7 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
{
|
||||
hullsize++;
|
||||
nextedge.Lprev(ref dissolveedge);
|
||||
dissolveedge.SymSelf();
|
||||
dissolveedge.Sym();
|
||||
// If not using a PSLG, the vertices should be marked now.
|
||||
// (If using a PSLG, markhull() will do the job.)
|
||||
if (noPoly)
|
||||
@@ -155,7 +155,7 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
// vertices are collinear, and thus all the triangles are part of
|
||||
// the bounding box. Otherwise, the setvertexmark() call below
|
||||
// will cause a bad pointer reference.
|
||||
if (dissolveedge.triangle.id != Triangle.EmptyID)
|
||||
if (dissolveedge.tri.id != Triangle.EmptyID)
|
||||
{
|
||||
markorg = dissolveedge.Org();
|
||||
if (markorg.mark == 0)
|
||||
@@ -169,15 +169,15 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
nextedge.Lnext(ref deadtriangle);
|
||||
deadtriangle.Sym(ref nextedge);
|
||||
// Get rid of the bounding box triangle.
|
||||
mesh.TriangleDealloc(deadtriangle.triangle);
|
||||
mesh.TriangleDealloc(deadtriangle.tri);
|
||||
// Do we need to turn the corner?
|
||||
if (nextedge.triangle.id == Triangle.EmptyID)
|
||||
if (nextedge.tri.id == Triangle.EmptyID)
|
||||
{
|
||||
// Turn the corner.
|
||||
dissolveedge.Copy(ref nextedge);
|
||||
}
|
||||
}
|
||||
mesh.TriangleDealloc(finaledge.triangle);
|
||||
mesh.TriangleDealloc(finaledge.tri);
|
||||
|
||||
return hullsize;
|
||||
}
|
||||
|
||||
@@ -70,11 +70,11 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
mesh.MakeTriangle(ref lefttri);
|
||||
mesh.MakeTriangle(ref righttri);
|
||||
lefttri.Bond(ref righttri);
|
||||
lefttri.LnextSelf();
|
||||
righttri.LprevSelf();
|
||||
lefttri.Lnext();
|
||||
righttri.Lprev();
|
||||
lefttri.Bond(ref righttri);
|
||||
lefttri.LnextSelf();
|
||||
righttri.LprevSelf();
|
||||
lefttri.Lnext();
|
||||
righttri.Lprev();
|
||||
lefttri.Bond(ref righttri);
|
||||
firstvertex = eventheap[0].vertexEvent;
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
|
||||
if (randomnation(SAMPLERATE) == 0)
|
||||
{
|
||||
fliptri.SymSelf();
|
||||
fliptri.Sym();
|
||||
leftvertex = fliptri.Dest();
|
||||
midvertex = fliptri.Apex();
|
||||
rightvertex = fliptri.Org();
|
||||
@@ -184,11 +184,11 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
righttri.SetOrg(nextvertex);
|
||||
righttri.SetDest(connectvertex);
|
||||
lefttri.Bond(ref righttri);
|
||||
lefttri.LnextSelf();
|
||||
righttri.LprevSelf();
|
||||
lefttri.Lnext();
|
||||
righttri.Lprev();
|
||||
lefttri.Bond(ref righttri);
|
||||
lefttri.LnextSelf();
|
||||
righttri.LprevSelf();
|
||||
lefttri.Lnext();
|
||||
righttri.Lprev();
|
||||
lefttri.Bond(ref farlefttri);
|
||||
righttri.Bond(ref farrighttri);
|
||||
if (!farrightflag && farrighttri.Equal(bottommost))
|
||||
@@ -244,7 +244,7 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
}
|
||||
|
||||
splaynodes.Clear();
|
||||
bottommost.LprevSelf();
|
||||
bottommost.Lprev();
|
||||
|
||||
this.mesh.hullsize = RemoveGhosts(ref bottommost);
|
||||
|
||||
@@ -584,7 +584,7 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
farrightflag = false;
|
||||
while (!farrightflag && RightOfHyperbola(ref searchtri, searchvertex))
|
||||
{
|
||||
searchtri.OnextSelf();
|
||||
searchtri.Onext();
|
||||
farrightflag = searchtri.Equal(bottommost);
|
||||
}
|
||||
farright = farrightflag;
|
||||
@@ -700,7 +700,7 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
|
||||
// Find an edge on the convex hull to start point location from.
|
||||
startghost.Lprev(ref searchedge);
|
||||
searchedge.SymSelf();
|
||||
searchedge.Sym();
|
||||
Triangle.Empty.neighbors[0] = searchedge;
|
||||
// Remove the bounding box and count the convex hull edges.
|
||||
startghost.Copy(ref dissolveedge);
|
||||
@@ -709,15 +709,15 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
{
|
||||
hullsize++;
|
||||
dissolveedge.Lnext(ref deadtriangle);
|
||||
dissolveedge.LprevSelf();
|
||||
dissolveedge.SymSelf();
|
||||
dissolveedge.Lprev();
|
||||
dissolveedge.Sym();
|
||||
|
||||
// If no PSLG is involved, set the boundary markers of all the vertices
|
||||
// on the convex hull. If a PSLG is used, this step is done later.
|
||||
if (noPoly)
|
||||
{
|
||||
// Watch out for the case where all the input vertices are collinear.
|
||||
if (dissolveedge.triangle.id != Triangle.EmptyID)
|
||||
if (dissolveedge.tri.id != Triangle.EmptyID)
|
||||
{
|
||||
markorg = dissolveedge.Org();
|
||||
if (markorg.mark == 0)
|
||||
@@ -732,7 +732,7 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
deadtriangle.Sym(ref dissolveedge);
|
||||
|
||||
// Delete the bounding triangle.
|
||||
mesh.TriangleDealloc(deadtriangle.triangle);
|
||||
mesh.TriangleDealloc(deadtriangle.tri);
|
||||
} while (!dissolveedge.Equal(startghost));
|
||||
|
||||
return hullsize;
|
||||
|
||||
@@ -64,9 +64,9 @@ namespace TriangleNet.Meshing
|
||||
if (mesh.bounds.Contains(hole))
|
||||
{
|
||||
// Start searching from some triangle on the outer boundary.
|
||||
searchtri.triangle = Triangle.Empty;
|
||||
searchtri.tri = Triangle.Empty;
|
||||
searchtri.orient = 0;
|
||||
searchtri.SymSelf();
|
||||
searchtri.Sym();
|
||||
// Ensure that the hole is to the left of this boundary edge;
|
||||
// otherwise, locate() will falsely report that the hole
|
||||
// falls within the starting triangle.
|
||||
@@ -81,7 +81,7 @@ namespace TriangleNet.Meshing
|
||||
// Infect the triangle. This is done by marking the triangle
|
||||
// as infected and including the triangle in the virus pool.
|
||||
searchtri.Infect();
|
||||
viri.Add(searchtri.triangle);
|
||||
viri.Add(searchtri.tri);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,9 +106,9 @@ namespace TriangleNet.Meshing
|
||||
if (mesh.bounds.Contains(region.point))
|
||||
{
|
||||
// Start searching from some triangle on the outer boundary.
|
||||
searchtri.triangle = Triangle.Empty;
|
||||
searchtri.tri = Triangle.Empty;
|
||||
searchtri.orient = 0;
|
||||
searchtri.SymSelf();
|
||||
searchtri.Sym();
|
||||
// Ensure that the region point is to the left of this boundary
|
||||
// edge; otherwise, locate() will falsely report that the
|
||||
// region point falls within the starting triangle.
|
||||
@@ -122,7 +122,7 @@ namespace TriangleNet.Meshing
|
||||
{
|
||||
// Record the triangle for processing after the
|
||||
// holes have been carved.
|
||||
regionTris[i] = searchtri.triangle;
|
||||
regionTris[i] = searchtri.tri;
|
||||
regionTris[i].region = region.id;
|
||||
}
|
||||
}
|
||||
@@ -261,9 +261,9 @@ namespace TriangleNet.Meshing
|
||||
Vertex horg, hdest;
|
||||
|
||||
// Find a triangle handle on the hull.
|
||||
hulltri.triangle = Triangle.Empty;
|
||||
hulltri.tri = Triangle.Empty;
|
||||
hulltri.orient = 0;
|
||||
hulltri.SymSelf();
|
||||
hulltri.Sym();
|
||||
// Remember where we started so we know when to stop.
|
||||
hulltri.Copy(ref starttri);
|
||||
// Go once counterclockwise around the convex hull.
|
||||
@@ -273,14 +273,14 @@ namespace TriangleNet.Meshing
|
||||
if (!hulltri.IsInfected())
|
||||
{
|
||||
// Is the triangle protected by a subsegment?
|
||||
hulltri.SegPivot(ref hullsubseg);
|
||||
hulltri.Pivot(ref hullsubseg);
|
||||
if (hullsubseg.seg == Segment.Empty)
|
||||
{
|
||||
// The triangle is not protected; infect it.
|
||||
if (!hulltri.IsInfected())
|
||||
{
|
||||
hulltri.Infect();
|
||||
viri.Add(hulltri.triangle);
|
||||
viri.Add(hulltri.tri);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -303,9 +303,9 @@ namespace TriangleNet.Meshing
|
||||
}
|
||||
}
|
||||
// To find the next hull edge, go clockwise around the next vertex.
|
||||
hulltri.LnextSelf();
|
||||
hulltri.Lnext();
|
||||
hulltri.Oprev(ref nexttri);
|
||||
while (nexttri.triangle.id != Triangle.EmptyID)
|
||||
while (nexttri.tri.id != Triangle.EmptyID)
|
||||
{
|
||||
nexttri.Copy(ref hulltri);
|
||||
hulltri.Oprev(ref nexttri);
|
||||
@@ -345,7 +345,7 @@ namespace TriangleNet.Meshing
|
||||
{
|
||||
// WARNING: Don't use foreach, mesh.viri list may get modified.
|
||||
|
||||
testtri.triangle = viri[i];
|
||||
testtri.tri = 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
|
||||
@@ -359,9 +359,9 @@ namespace TriangleNet.Meshing
|
||||
// Find the neighbor.
|
||||
testtri.Sym(ref neighbor);
|
||||
// Check for a subsegment between the triangle and its neighbor.
|
||||
testtri.SegPivot(ref neighborsubseg);
|
||||
testtri.Pivot(ref neighborsubseg);
|
||||
// Check if the neighbor is nonexistent or already infected.
|
||||
if ((neighbor.triangle.id == Triangle.EmptyID) || neighbor.IsInfected())
|
||||
if ((neighbor.tri.id == Triangle.EmptyID) || neighbor.IsInfected())
|
||||
{
|
||||
if (neighborsubseg.seg != Segment.Empty)
|
||||
{
|
||||
@@ -369,7 +369,7 @@ namespace TriangleNet.Meshing
|
||||
// neighbor, but both triangles are dying, so the subsegment
|
||||
// dies too.
|
||||
mesh.SubsegDealloc(neighborsubseg.seg);
|
||||
if (neighbor.triangle.id != Triangle.EmptyID)
|
||||
if (neighbor.tri.id != Triangle.EmptyID)
|
||||
{
|
||||
// Make sure the subsegment doesn't get deallocated again
|
||||
// later when the infected neighbor is visited.
|
||||
@@ -387,7 +387,7 @@ namespace TriangleNet.Meshing
|
||||
// the neighbor becomes infected.
|
||||
neighbor.Infect();
|
||||
// Ensure that the neighbor's neighbors will be infected.
|
||||
viri.Add(neighbor.triangle);
|
||||
viri.Add(neighbor.tri);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -419,7 +419,7 @@ namespace TriangleNet.Meshing
|
||||
|
||||
foreach (var virus in viri)
|
||||
{
|
||||
testtri.triangle = virus;
|
||||
testtri.tri = virus;
|
||||
|
||||
// Check each of the three corners of the triangle for elimination.
|
||||
// This is done by walking around each vertex, checking if it is
|
||||
@@ -436,7 +436,7 @@ namespace TriangleNet.Meshing
|
||||
// Walk counterclockwise about the vertex.
|
||||
testtri.Onext(ref neighbor);
|
||||
// Stop upon reaching a boundary or the starting triangle.
|
||||
while ((neighbor.triangle.id != Triangle.EmptyID) &&
|
||||
while ((neighbor.tri.id != Triangle.EmptyID) &&
|
||||
(!neighbor.Equal(testtri)))
|
||||
{
|
||||
if (neighbor.IsInfected())
|
||||
@@ -450,15 +450,15 @@ namespace TriangleNet.Meshing
|
||||
killorg = false;
|
||||
}
|
||||
// Walk counterclockwise about the vertex.
|
||||
neighbor.OnextSelf();
|
||||
neighbor.Onext();
|
||||
}
|
||||
// If we reached a boundary, we must walk clockwise as well.
|
||||
if (neighbor.triangle.id == Triangle.EmptyID)
|
||||
if (neighbor.tri.id == Triangle.EmptyID)
|
||||
{
|
||||
// Walk clockwise about the vertex.
|
||||
testtri.Oprev(ref neighbor);
|
||||
// Stop upon reaching a boundary.
|
||||
while (neighbor.triangle.id != Triangle.EmptyID)
|
||||
while (neighbor.tri.id != Triangle.EmptyID)
|
||||
{
|
||||
if (neighbor.IsInfected())
|
||||
{
|
||||
@@ -471,7 +471,7 @@ namespace TriangleNet.Meshing
|
||||
killorg = false;
|
||||
}
|
||||
// Walk clockwise about the vertex.
|
||||
neighbor.OprevSelf();
|
||||
neighbor.Oprev();
|
||||
}
|
||||
}
|
||||
if (killorg)
|
||||
@@ -488,7 +488,7 @@ namespace TriangleNet.Meshing
|
||||
for (testtri.orient = 0; testtri.orient < 3; testtri.orient++)
|
||||
{
|
||||
testtri.Sym(ref neighbor);
|
||||
if (neighbor.triangle.id == Triangle.EmptyID)
|
||||
if (neighbor.tri.id == Triangle.EmptyID)
|
||||
{
|
||||
// There is no neighboring triangle on this edge, so this edge
|
||||
// is a boundary edge. This triangle is being deleted, so this
|
||||
@@ -505,7 +505,7 @@ namespace TriangleNet.Meshing
|
||||
}
|
||||
}
|
||||
// Return the dead triangle to the pool of triangles.
|
||||
mesh.TriangleDealloc(testtri.triangle);
|
||||
mesh.TriangleDealloc(testtri.tri);
|
||||
}
|
||||
|
||||
// Empty the virus pool.
|
||||
@@ -554,7 +554,7 @@ namespace TriangleNet.Meshing
|
||||
// 'searchtri' faces directly away from 'searchpoint'. We could go left
|
||||
// or right. Ask whether it's a triangle or a boundary on the left.
|
||||
searchtri.Onext(ref checktri);
|
||||
if (checktri.triangle.id == Triangle.EmptyID)
|
||||
if (checktri.tri.id == Triangle.EmptyID)
|
||||
{
|
||||
leftflag = false;
|
||||
}
|
||||
@@ -566,8 +566,8 @@ namespace TriangleNet.Meshing
|
||||
while (leftflag)
|
||||
{
|
||||
// Turn left until satisfied.
|
||||
searchtri.OnextSelf();
|
||||
if (searchtri.triangle.id == Triangle.EmptyID)
|
||||
searchtri.Onext();
|
||||
if (searchtri.tri.id == Triangle.EmptyID)
|
||||
{
|
||||
logger.Error("Unable to find a triangle on path.", "Mesh.FindDirection().1");
|
||||
throw new Exception("Unable to find a triangle on path.");
|
||||
@@ -580,8 +580,8 @@ namespace TriangleNet.Meshing
|
||||
while (rightflag)
|
||||
{
|
||||
// Turn right until satisfied.
|
||||
searchtri.OprevSelf();
|
||||
if (searchtri.triangle.id == Triangle.EmptyID)
|
||||
searchtri.Oprev();
|
||||
if (searchtri.tri.id == Triangle.EmptyID)
|
||||
{
|
||||
logger.Error("Unable to find a triangle on path.", "Mesh.FindDirection().2");
|
||||
throw new Exception("Unable to find a triangle on path.");
|
||||
@@ -688,19 +688,19 @@ namespace TriangleNet.Meshing
|
||||
}
|
||||
|
||||
// Divide the segment into two, and correct the segment endpoints.
|
||||
splitsubseg.SymSelf();
|
||||
splitsubseg.Sym();
|
||||
splitsubseg.Pivot(ref opposubseg);
|
||||
splitsubseg.Dissolve();
|
||||
opposubseg.Dissolve();
|
||||
do
|
||||
{
|
||||
splitsubseg.SetSegOrg(newvertex);
|
||||
splitsubseg.NextSelf();
|
||||
splitsubseg.Next();
|
||||
} while (splitsubseg.seg != Segment.Empty);
|
||||
do
|
||||
{
|
||||
opposubseg.SetSegOrg(newvertex);
|
||||
opposubseg.NextSelf();
|
||||
opposubseg.Next();
|
||||
} while (opposubseg.seg != Segment.Empty);
|
||||
|
||||
// Inserting the vertex may have caused edge flips. We wish to rediscover
|
||||
@@ -711,7 +711,7 @@ namespace TriangleNet.Meshing
|
||||
leftvertex = splittri.Apex();
|
||||
if ((leftvertex.x == endpoint1.x) && (leftvertex.y == endpoint1.y))
|
||||
{
|
||||
splittri.OnextSelf();
|
||||
splittri.Onext();
|
||||
}
|
||||
else if ((rightvertex.x != endpoint1.x) || (rightvertex.y != endpoint1.y))
|
||||
{
|
||||
@@ -760,7 +760,7 @@ namespace TriangleNet.Meshing
|
||||
// The segment is already an edge in the mesh.
|
||||
if ((leftvertex.x == endpoint2.x) && (leftvertex.y == endpoint2.y))
|
||||
{
|
||||
searchtri.LprevSelf();
|
||||
searchtri.Lprev();
|
||||
}
|
||||
// Insert a subsegment, if there isn't already one there.
|
||||
mesh.InsertSubseg(ref searchtri, newmark);
|
||||
@@ -770,7 +770,7 @@ namespace TriangleNet.Meshing
|
||||
{
|
||||
// We've collided with a vertex between the segment's endpoints.
|
||||
// Make the collinear vertex be the triangle's origin.
|
||||
searchtri.LprevSelf();
|
||||
searchtri.Lprev();
|
||||
mesh.InsertSubseg(ref searchtri, newmark);
|
||||
// Insert the remainder of the segment.
|
||||
return ScoutSegment(ref searchtri, endpoint2, newmark);
|
||||
@@ -780,14 +780,14 @@ namespace TriangleNet.Meshing
|
||||
// We've collided with a vertex between the segment's endpoints.
|
||||
mesh.InsertSubseg(ref searchtri, newmark);
|
||||
// Make the collinear vertex be the triangle's origin.
|
||||
searchtri.LnextSelf();
|
||||
searchtri.Lnext();
|
||||
// Insert the remainder of the segment.
|
||||
return ScoutSegment(ref searchtri, endpoint2, newmark);
|
||||
}
|
||||
else
|
||||
{
|
||||
searchtri.Lnext(ref crosstri);
|
||||
crosstri.SegPivot(ref crosssubseg);
|
||||
crosstri.Pivot(ref crosssubseg);
|
||||
// Check for a crossing segment.
|
||||
if (crosssubseg.seg == Segment.Empty)
|
||||
{
|
||||
@@ -850,11 +850,11 @@ namespace TriangleNet.Meshing
|
||||
fixuptri.Lnext(ref neartri);
|
||||
neartri.Sym(ref fartri);
|
||||
// Check if the edge opposite the origin of fixuptri can be flipped.
|
||||
if (fartri.triangle.id == Triangle.EmptyID)
|
||||
if (fartri.tri.id == Triangle.EmptyID)
|
||||
{
|
||||
return;
|
||||
}
|
||||
neartri.SegPivot(ref faredge);
|
||||
neartri.Pivot(ref faredge);
|
||||
if (faredge.seg != Segment.Empty)
|
||||
{
|
||||
return;
|
||||
@@ -897,7 +897,7 @@ namespace TriangleNet.Meshing
|
||||
}
|
||||
// else fartri is inverted; remove it from the stack by flipping.
|
||||
mesh.Flip(ref neartri);
|
||||
fixuptri.LprevSelf(); // Restore the origin of fixuptri after the flip.
|
||||
fixuptri.Lprev(); // Restore the origin of fixuptri after the flip.
|
||||
// Recursively process the two triangles that result from the flip.
|
||||
DelaunayFixup(ref fixuptri, leftside);
|
||||
DelaunayFixup(ref fartri, leftside);
|
||||
@@ -1014,7 +1014,7 @@ namespace TriangleNet.Meshing
|
||||
// Flip the edge that crosses the segment. After the edge is
|
||||
// flipped, one of its endpoints is the fan vertex, and the
|
||||
// destination of fixuptri is the fan vertex.
|
||||
fixuptri.LprevSelf();
|
||||
fixuptri.Lprev();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1023,10 +1023,10 @@ namespace TriangleNet.Meshing
|
||||
// Flip the edge that crosses the segment. After the edge is
|
||||
// flipped, one of its endpoints is the fan vertex, and the
|
||||
// destination of fixuptri is the fan vertex.
|
||||
fixuptri.OprevSelf();
|
||||
fixuptri.Oprev();
|
||||
}
|
||||
// Check for two intersecting segments.
|
||||
fixuptri.SegPivot(ref crosssubseg);
|
||||
fixuptri.Pivot(ref crosssubseg);
|
||||
if (crosssubseg.seg == Segment.Empty)
|
||||
{
|
||||
mesh.Flip(ref fixuptri); // May create inverted triangle at left.
|
||||
@@ -1069,7 +1069,7 @@ namespace TriangleNet.Meshing
|
||||
|
||||
// Find a triangle whose origin is the segment's first endpoint.
|
||||
searchtri1 = endpoint1.tri;
|
||||
if (searchtri1.triangle != null)
|
||||
if (searchtri1.tri != null)
|
||||
{
|
||||
checkvertex = searchtri1.Org();
|
||||
}
|
||||
@@ -1077,9 +1077,9 @@ namespace TriangleNet.Meshing
|
||||
if (checkvertex != endpoint1)
|
||||
{
|
||||
// Find a boundary triangle to search from.
|
||||
searchtri1.triangle = Triangle.Empty;
|
||||
searchtri1.tri = Triangle.Empty;
|
||||
searchtri1.orient = 0;
|
||||
searchtri1.SymSelf();
|
||||
searchtri1.Sym();
|
||||
// Search for the segment's first endpoint by point location.
|
||||
if (locator.Locate(endpoint1, ref searchtri1) != LocateResult.OnVertex)
|
||||
{
|
||||
@@ -1104,16 +1104,16 @@ namespace TriangleNet.Meshing
|
||||
// Find a triangle whose origin is the segment's second endpoint.
|
||||
checkvertex = null;
|
||||
searchtri2 = endpoint2.tri;
|
||||
if (searchtri2.triangle != null)
|
||||
if (searchtri2.tri != null)
|
||||
{
|
||||
checkvertex = searchtri2.Org();
|
||||
}
|
||||
if (checkvertex != endpoint2)
|
||||
{
|
||||
// Find a boundary triangle to search from.
|
||||
searchtri2.triangle = Triangle.Empty;
|
||||
searchtri2.tri = Triangle.Empty;
|
||||
searchtri2.orient = 0;
|
||||
searchtri2.SymSelf();
|
||||
searchtri2.Sym();
|
||||
// Search for the segment's second endpoint by point location.
|
||||
if (locator.Locate(endpoint2, ref searchtri2) != LocateResult.OnVertex)
|
||||
{
|
||||
@@ -1148,9 +1148,9 @@ namespace TriangleNet.Meshing
|
||||
Otri starttri = default(Otri);
|
||||
|
||||
// Find a triangle handle on the hull.
|
||||
hulltri.triangle = Triangle.Empty;
|
||||
hulltri.tri = Triangle.Empty;
|
||||
hulltri.orient = 0;
|
||||
hulltri.SymSelf();
|
||||
hulltri.Sym();
|
||||
// Remember where we started so we know when to stop.
|
||||
hulltri.Copy(ref starttri);
|
||||
// Go once counterclockwise around the convex hull.
|
||||
@@ -1159,9 +1159,9 @@ namespace TriangleNet.Meshing
|
||||
// Create a subsegment if there isn't already one here.
|
||||
mesh.InsertSubseg(ref hulltri, 1);
|
||||
// To find the next hull edge, go clockwise around the next vertex.
|
||||
hulltri.LnextSelf();
|
||||
hulltri.Lnext();
|
||||
hulltri.Oprev(ref nexttri);
|
||||
while (nexttri.triangle.id != Triangle.EmptyID)
|
||||
while (nexttri.tri.id != Triangle.EmptyID)
|
||||
{
|
||||
nexttri.Copy(ref hulltri);
|
||||
hulltri.Oprev(ref nexttri);
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace TriangleNet.Meshing
|
||||
using TVertex = TriangleNet.Geometry.Vertex;
|
||||
|
||||
/// <summary>
|
||||
/// The Converter class provides methods for mesh reconstruction.
|
||||
/// The Converter class provides methods for mesh reconstruction and conversion.
|
||||
/// </summary>
|
||||
public static class Converter
|
||||
{
|
||||
@@ -106,7 +106,7 @@ namespace TriangleNet.Meshing
|
||||
for (i = 0; i < mesh.vertices.Count; i++)
|
||||
{
|
||||
Otri tmp = default(Otri);
|
||||
tmp.triangle = Triangle.Empty;
|
||||
tmp.tri = Triangle.Empty;
|
||||
vertexarray[i] = new List<Otri>(3);
|
||||
vertexarray[i].Add(tmp);
|
||||
}
|
||||
@@ -117,7 +117,7 @@ namespace TriangleNet.Meshing
|
||||
// together those that share an edge.
|
||||
foreach (var item in mesh.triangles.Values)
|
||||
{
|
||||
tri.triangle = item;
|
||||
tri.tri = item;
|
||||
|
||||
corner[0] = triangles[i].P0;
|
||||
corner[1] = triangles[i].P1;
|
||||
@@ -134,12 +134,12 @@ namespace TriangleNet.Meshing
|
||||
}
|
||||
|
||||
// Read the triangle's attributes.
|
||||
tri.triangle.region = triangles[i].Region;
|
||||
tri.tri.region = triangles[i].Region;
|
||||
|
||||
// TODO: VarArea
|
||||
if (mesh.behavior.VarArea)
|
||||
{
|
||||
tri.triangle.area = triangles[i].Area;
|
||||
tri.tri.area = triangles[i].Area;
|
||||
}
|
||||
|
||||
// Set the triangle's vertices.
|
||||
@@ -164,7 +164,7 @@ namespace TriangleNet.Meshing
|
||||
|
||||
checktri = nexttri;
|
||||
|
||||
if (checktri.triangle.id != Triangle.EmptyID)
|
||||
if (checktri.tri.id != Triangle.EmptyID)
|
||||
{
|
||||
tdest = tri.Dest();
|
||||
tapex = tri.Apex();
|
||||
@@ -192,7 +192,7 @@ namespace TriangleNet.Meshing
|
||||
nexttri = vertexarray[aroundvertex][index];
|
||||
|
||||
checktri = nexttri;
|
||||
} while (checktri.triangle.id != Triangle.EmptyID);
|
||||
} while (checktri.tri.id != Triangle.EmptyID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +276,7 @@ namespace TriangleNet.Meshing
|
||||
// occurrence of a triangle on a list can (and does) represent
|
||||
// an edge. In this way, most edges are represented twice, and
|
||||
// every triangle-subsegment bond is represented once.
|
||||
while (notfound && (checktri.triangle.id != Triangle.EmptyID))
|
||||
while (notfound && (checktri.tri.id != Triangle.EmptyID))
|
||||
{
|
||||
checkdest = checktri.Dest();
|
||||
|
||||
@@ -289,7 +289,7 @@ namespace TriangleNet.Meshing
|
||||
checktri.SegBond(ref subseg);
|
||||
// Check if this is a boundary edge.
|
||||
checktri.Sym(ref checkneighbor);
|
||||
if (checkneighbor.triangle.id == Triangle.EmptyID)
|
||||
if (checkneighbor.tri.id == Triangle.EmptyID)
|
||||
{
|
||||
// The next line doesn't insert a subsegment (because there's
|
||||
// already one there), but it sets the boundary markers of
|
||||
@@ -321,7 +321,7 @@ namespace TriangleNet.Meshing
|
||||
nexttri = vertexarray[i][index];
|
||||
checktri = nexttri;
|
||||
|
||||
while (checktri.triangle.id != Triangle.EmptyID)
|
||||
while (checktri.tri.id != Triangle.EmptyID)
|
||||
{
|
||||
// Find the next triangle in the stack before this
|
||||
// information gets overwritten.
|
||||
@@ -330,7 +330,7 @@ namespace TriangleNet.Meshing
|
||||
// No adjacent subsegment. (This overwrites the stack info.)
|
||||
checktri.SegDissolve();
|
||||
checktri.Sym(ref checkneighbor);
|
||||
if (checkneighbor.triangle.id == Triangle.EmptyID)
|
||||
if (checkneighbor.tri.id == Triangle.EmptyID)
|
||||
{
|
||||
mesh.InsertSubseg(ref checktri, 1);
|
||||
hullsize++;
|
||||
@@ -404,14 +404,14 @@ namespace TriangleNet.Meshing
|
||||
{
|
||||
id = t.id;
|
||||
|
||||
tri.triangle = t;
|
||||
tri.tri = t;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
tri.orient = i;
|
||||
tri.Sym(ref neighbor);
|
||||
|
||||
nid = neighbor.triangle.id;
|
||||
nid = neighbor.tri.id;
|
||||
|
||||
if (id < nid || nid < 0)
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace TriangleNet.Meshing.Data
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("B-TID {0}", poortri.triangle.hash);
|
||||
return String.Format("B-TID {0}", poortri.tri.hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace TriangleNet.Meshing.Iterators
|
||||
triangles = mesh.triangles.Values.GetEnumerator();
|
||||
triangles.MoveNext();
|
||||
|
||||
tri.triangle = triangles.Current;
|
||||
tri.tri = triangles.Current;
|
||||
tri.orient = 0;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace TriangleNet.Meshing.Iterators
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (tri.triangle == null)
|
||||
if (tri.tri == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -64,7 +64,7 @@ namespace TriangleNet.Meshing.Iterators
|
||||
{
|
||||
if (triangles.MoveNext())
|
||||
{
|
||||
tri.triangle = triangles.Current;
|
||||
tri.tri = triangles.Current;
|
||||
tri.orient = 0;
|
||||
}
|
||||
else
|
||||
@@ -76,12 +76,12 @@ namespace TriangleNet.Meshing.Iterators
|
||||
|
||||
tri.Sym(ref neighbor);
|
||||
|
||||
if ((tri.triangle.id < neighbor.triangle.id) || (neighbor.triangle.id == Triangle.EmptyID))
|
||||
if ((tri.tri.id < neighbor.tri.id) || (neighbor.tri.id == Triangle.EmptyID))
|
||||
{
|
||||
p1 = tri.Org();
|
||||
p2 = tri.Dest();
|
||||
|
||||
tri.SegPivot(ref sub);
|
||||
tri.Pivot(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);
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace TriangleNet.Meshing.Iterators
|
||||
{
|
||||
// WARNING: Don't use foreach, viri list gets modified.
|
||||
|
||||
testtri.triangle = viri[i];
|
||||
testtri.tri = 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
|
||||
@@ -55,7 +55,7 @@ namespace TriangleNet.Meshing.Iterators
|
||||
testtri.Uninfect();
|
||||
|
||||
// Apply function.
|
||||
func(testtri.triangle);
|
||||
func(testtri.tri);
|
||||
|
||||
// Check each of the triangle's three neighbors.
|
||||
for (testtri.orient = 0; testtri.orient < 3; testtri.orient++)
|
||||
@@ -63,16 +63,16 @@ namespace TriangleNet.Meshing.Iterators
|
||||
// Find the neighbor.
|
||||
testtri.Sym(ref neighbor);
|
||||
// Check for a subsegment between the triangle and its neighbor.
|
||||
testtri.SegPivot(ref neighborsubseg);
|
||||
testtri.Pivot(ref neighborsubseg);
|
||||
// Make sure the neighbor exists, is not already infected, and
|
||||
// isn't protected by a subsegment.
|
||||
if ((neighbor.triangle.id != Triangle.EmptyID) && !neighbor.IsInfected()
|
||||
if ((neighbor.tri.id != Triangle.EmptyID) && !neighbor.IsInfected()
|
||||
&& (neighborsubseg.seg == Segment.Empty))
|
||||
{
|
||||
// Infect the neighbor.
|
||||
neighbor.Infect();
|
||||
// Ensure that the neighbor's neighbors will be infected.
|
||||
viri.Add(neighbor.triangle);
|
||||
viri.Add(neighbor.tri);
|
||||
}
|
||||
}
|
||||
// Remark the triangle as infected, so it doesn't get added to the
|
||||
|
||||
@@ -88,9 +88,9 @@ namespace TriangleNet.Meshing
|
||||
eorg = testsubseg.Org();
|
||||
edest = testsubseg.Dest();
|
||||
// Check one neighbor of the subsegment.
|
||||
testsubseg.TriPivot(ref neighbortri);
|
||||
testsubseg.Pivot(ref neighbortri);
|
||||
// Does the neighbor exist, or is this a boundary edge?
|
||||
if (neighbortri.triangle.id != Triangle.EmptyID)
|
||||
if (neighbortri.tri.id != Triangle.EmptyID)
|
||||
{
|
||||
sides++;
|
||||
// Find a vertex opposite this subsegment.
|
||||
@@ -118,9 +118,9 @@ namespace TriangleNet.Meshing
|
||||
}
|
||||
// Check the other neighbor of the subsegment.
|
||||
testsubseg.Sym(ref testsym);
|
||||
testsym.TriPivot(ref neighbortri);
|
||||
testsym.Pivot(ref neighbortri);
|
||||
// Does the neighbor exist, or is this a boundary edge?
|
||||
if (neighbortri.triangle.id != Triangle.EmptyID)
|
||||
if (neighbortri.tri.id != Triangle.EmptyID)
|
||||
{
|
||||
sides++;
|
||||
// Find the other vertex opposite this subsegment.
|
||||
@@ -260,7 +260,7 @@ namespace TriangleNet.Meshing
|
||||
}
|
||||
|
||||
// Nonpositive area constraints are treated as unconstrained.
|
||||
if ((behavior.VarArea) && (area > testtri.triangle.area) && (testtri.triangle.area > 0.0))
|
||||
if ((behavior.VarArea) && (area > testtri.tri.area) && (testtri.tri.area > 0.0))
|
||||
{
|
||||
// Add this triangle to the list of bad triangles.
|
||||
queue.Enqueue(ref testtri, minedge, tapex, torg, tdest);
|
||||
@@ -270,7 +270,7 @@ namespace TriangleNet.Meshing
|
||||
// Check whether the user thinks this triangle is too large.
|
||||
if (behavior.UserTest != null)
|
||||
{
|
||||
if (behavior.UserTest(testtri.triangle, area))
|
||||
if (behavior.UserTest(testtri.tri, area))
|
||||
{
|
||||
queue.Enqueue(ref testtri, minedge, tapex, torg, tdest);
|
||||
return;
|
||||
@@ -318,15 +318,15 @@ namespace TriangleNet.Meshing
|
||||
{
|
||||
// Check if both points lie in a common segment. If they do, the
|
||||
// skinny triangle is enqueued to be split as usual.
|
||||
tri1.SegPivot(ref testsub);
|
||||
tri1.Pivot(ref testsub);
|
||||
if (testsub.seg == Segment.Empty)
|
||||
{
|
||||
// No common segment. Find a subsegment that contains 'torg'.
|
||||
tri1.Copy(ref tri2);
|
||||
do
|
||||
{
|
||||
tri1.OprevSelf();
|
||||
tri1.SegPivot(ref testsub);
|
||||
tri1.Oprev();
|
||||
tri1.Pivot(ref testsub);
|
||||
} while (testsub.seg == Segment.Empty);
|
||||
// Find the endpoints of the containing segment.
|
||||
org1 = testsub.SegOrg();
|
||||
@@ -334,8 +334,8 @@ namespace TriangleNet.Meshing
|
||||
// Find a subsegment that contains 'tdest'.
|
||||
do
|
||||
{
|
||||
tri2.DnextSelf();
|
||||
tri2.SegPivot(ref testsub);
|
||||
tri2.Dnext();
|
||||
tri2.Pivot(ref testsub);
|
||||
} while (testsub.seg == Segment.Empty);
|
||||
// Find the endpoints of the containing segment.
|
||||
org2 = testsub.SegOrg();
|
||||
@@ -456,13 +456,13 @@ namespace TriangleNet.Meshing
|
||||
// concentric circles for later splittings.)
|
||||
|
||||
// Is the origin shared with another segment?
|
||||
currentenc.TriPivot(ref enctri);
|
||||
currentenc.Pivot(ref enctri);
|
||||
enctri.Lnext(ref testtri);
|
||||
testtri.SegPivot(ref testsh);
|
||||
testtri.Pivot(ref testsh);
|
||||
acuteorg = testsh.seg != Segment.Empty;
|
||||
// Is the destination shared with another segment?
|
||||
testtri.LnextSelf();
|
||||
testtri.SegPivot(ref testsh);
|
||||
testtri.Lnext();
|
||||
testtri.Pivot(ref testsh);
|
||||
acutedest = testsh.seg != Segment.Empty;
|
||||
|
||||
// If we're using Chew's algorithm (rather than Ruppert's)
|
||||
@@ -476,7 +476,7 @@ namespace TriangleNet.Meshing
|
||||
(eorg.y - eapex.y) * (edest.y - eapex.y) < 0.0))
|
||||
{
|
||||
mesh.DeleteVertex(ref testtri);
|
||||
currentenc.TriPivot(ref enctri);
|
||||
currentenc.Pivot(ref enctri);
|
||||
eapex = enctri.Apex();
|
||||
enctri.Lprev(ref testtri);
|
||||
}
|
||||
@@ -484,16 +484,16 @@ namespace TriangleNet.Meshing
|
||||
|
||||
// Now, check the other side of the segment, if there's a triangle there.
|
||||
enctri.Sym(ref testtri);
|
||||
if (testtri.triangle.id != Triangle.EmptyID)
|
||||
if (testtri.tri.id != Triangle.EmptyID)
|
||||
{
|
||||
// Is the destination shared with another segment?
|
||||
testtri.LnextSelf();
|
||||
testtri.SegPivot(ref testsh);
|
||||
testtri.Lnext();
|
||||
testtri.Pivot(ref testsh);
|
||||
acutedest2 = testsh.seg != Segment.Empty;
|
||||
acutedest = acutedest || acutedest2;
|
||||
// Is the origin shared with another segment?
|
||||
testtri.LnextSelf();
|
||||
testtri.SegPivot(ref testsh);
|
||||
testtri.Lnext();
|
||||
testtri.Pivot(ref testsh);
|
||||
acuteorg2 = testsh.seg != Segment.Empty;
|
||||
acuteorg = acuteorg || acuteorg2;
|
||||
|
||||
@@ -508,7 +508,7 @@ namespace TriangleNet.Meshing
|
||||
mesh.DeleteVertex(ref testtri);
|
||||
enctri.Sym(ref testtri);
|
||||
eapex = testtri.Apex();
|
||||
testtri.LprevSelf();
|
||||
testtri.Lprev();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -548,7 +548,7 @@ namespace TriangleNet.Meshing
|
||||
newvertex = new Vertex(
|
||||
eorg.x + split * (edest.x - eorg.x),
|
||||
eorg.y + split * (edest.y - eorg.y),
|
||||
currentenc.Mark(),
|
||||
currentenc.seg.boundary,
|
||||
mesh.nextras);
|
||||
|
||||
newvertex.type = VertexType.SegmentVertex;
|
||||
@@ -610,7 +610,7 @@ namespace TriangleNet.Meshing
|
||||
}
|
||||
// Check the two new subsegments to see if they're encroached.
|
||||
CheckSeg4Encroach(ref currentenc);
|
||||
currentenc.NextSelf();
|
||||
currentenc.Next();
|
||||
CheckSeg4Encroach(ref currentenc);
|
||||
}
|
||||
|
||||
@@ -630,7 +630,7 @@ namespace TriangleNet.Meshing
|
||||
|
||||
foreach (var tri in mesh.triangles.Values)
|
||||
{
|
||||
triangleloop.triangle = tri;
|
||||
triangleloop.tri = tri;
|
||||
|
||||
// If the triangle is bad, enqueue it.
|
||||
TestTriangle(ref triangleloop);
|
||||
@@ -659,7 +659,7 @@ namespace TriangleNet.Meshing
|
||||
// Make sure that this triangle is still the same triangle it was
|
||||
// when it was tested and determined to be of bad quality.
|
||||
// Subsequent transformations may have made it a different triangle.
|
||||
if (!Otri.IsDead(badotri.triangle) && (borg == badtri.org) &&
|
||||
if (!Otri.IsDead(badotri.tri) && (borg == badtri.org) &&
|
||||
(bdest == badtri.dest) && (bapex == badtri.apex))
|
||||
{
|
||||
errorflag = false;
|
||||
@@ -713,7 +713,7 @@ namespace TriangleNet.Meshing
|
||||
// negative when it should be, so I test eta against xi.)
|
||||
if (eta < xi)
|
||||
{
|
||||
badotri.LprevSelf();
|
||||
badotri.Lprev();
|
||||
}
|
||||
|
||||
// Insert the circumcenter, searching from the edge of the triangle,
|
||||
|
||||
@@ -411,12 +411,12 @@ namespace TriangleNet
|
||||
break;
|
||||
case 2:
|
||||
//printf("Relocate: (%f,%f)\n", tdest[0],tdest[1]);
|
||||
delotri.LnextSelf();
|
||||
delotri.Lnext();
|
||||
mesh.DeleteVertex(ref delotri);
|
||||
break;
|
||||
case 3:
|
||||
//printf("Relocate: (%f,%f)\n", tapex[0],tapex[1]);
|
||||
delotri.LprevSelf();
|
||||
delotri.Lprev();
|
||||
mesh.DeleteVertex(ref delotri);
|
||||
break;
|
||||
|
||||
@@ -1124,12 +1124,12 @@ namespace TriangleNet
|
||||
break;
|
||||
case 2:
|
||||
//printf("Relocate: (%f,%f)\n", tdest[0],tdest[1]);
|
||||
delotri.LnextSelf();
|
||||
delotri.Lnext();
|
||||
mesh.DeleteVertex(ref delotri);
|
||||
break;
|
||||
case 3:
|
||||
//printf("Relocate: (%f,%f)\n", tapex[0],tapex[1]);
|
||||
delotri.LprevSelf();
|
||||
delotri.Lprev();
|
||||
mesh.DeleteVertex(ref delotri);
|
||||
break;
|
||||
}
|
||||
@@ -2364,7 +2364,7 @@ namespace TriangleNet
|
||||
badotri.Sym(ref neighbor);
|
||||
// check if it is the one we are looking for by checking the corners
|
||||
// first check if the neighbor is nonexistent, since it can be on the border
|
||||
if (neighbor.triangle.id != Triangle.EmptyID)
|
||||
if (neighbor.tri.id != Triangle.EmptyID)
|
||||
{
|
||||
// then check if two wanted corners are also in this triangle
|
||||
// take the vertices of the candidate neighbor
|
||||
@@ -4092,7 +4092,7 @@ namespace TriangleNet
|
||||
}
|
||||
else if ((tdest.x == newvertex.x) && (tdest.y == newvertex.y))
|
||||
{
|
||||
searchtri.LnextSelf();
|
||||
searchtri.Lnext();
|
||||
intersect = LocateResult.OnVertex;
|
||||
searchtri.Copy(ref horiz);
|
||||
}
|
||||
@@ -4104,7 +4104,7 @@ namespace TriangleNet
|
||||
{
|
||||
// Turn around so that 'searchpoint' is to the left of the
|
||||
// edge specified by 'searchtri'.
|
||||
searchtri.SymSelf();
|
||||
searchtri.Sym();
|
||||
searchtri.Copy(ref horiz);
|
||||
intersect = mesh.locator.PreciseLocate(newvertex, ref horiz, false);
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
|
||||
namespace TriangleNet.Smoothing
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Voronoi.Legacy;
|
||||
using TriangleNet.Topology.DCEL;
|
||||
using TriangleNet.Voronoi;
|
||||
|
||||
/// <summary>
|
||||
/// Simple mesh smoother implementation.
|
||||
@@ -56,48 +56,49 @@ namespace TriangleNet.Smoothing
|
||||
smoothedMesh.CopyTo((Mesh)mesh);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Smooth all free nodes.
|
||||
/// </summary>
|
||||
private void Step(Mesh mesh)
|
||||
{
|
||||
var voronoi = new BoundedVoronoiLegacy(mesh, false);
|
||||
|
||||
var cells = voronoi.Regions;
|
||||
var voronoi = new BoundedVoronoi(mesh);
|
||||
|
||||
double x, y;
|
||||
|
||||
foreach (var cell in cells)
|
||||
foreach (var face in voronoi.Faces)
|
||||
{
|
||||
Centroid((List<Point>)cell.Vertices, out x, out y);
|
||||
if (face.generator.mark == 0)
|
||||
{
|
||||
Centroid(face, out x, out y);
|
||||
|
||||
cell.Generator.x = x;
|
||||
cell.Generator.y = y;
|
||||
face.generator.x = x;
|
||||
face.generator.y = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the centroid of a polygon.
|
||||
/// </summary>
|
||||
/// <param name="points">Points of the polygon.</param>
|
||||
/// <param name="x">Centroid x coordinate.</param>
|
||||
/// <param name="y">Centroid y coordinate.</param>
|
||||
/// <remarks>
|
||||
/// Based on ANSI C code from the article "Centroid of a Polygon" by Gerard Bashein
|
||||
/// and Paul R. Detmer in "Graphics Gems IV", Academic Press, 1994
|
||||
/// </remarks>
|
||||
private void Centroid(List<Point> points, out double x, out double y)
|
||||
private void Centroid(Face face, out double x, out double y)
|
||||
{
|
||||
int i, j, n = points.Count;
|
||||
double ai, atmp = 0, xtmp = 0, ytmp = 0;
|
||||
|
||||
for (i = n - 1, j = 0; j < n; i = j, j++)
|
||||
var edge = face.Edge;
|
||||
var first = edge.Next.ID;
|
||||
|
||||
Point p, q;
|
||||
|
||||
do
|
||||
{
|
||||
ai = points[i].X * points[j].Y - points[j].X * points[i].Y;
|
||||
p = edge.Origin;
|
||||
q = edge.Twin.Origin;
|
||||
|
||||
ai = p.X * q.Y - q.X * p.Y;
|
||||
atmp += ai;
|
||||
xtmp += (points[j].X + points[i].X) * ai;
|
||||
ytmp += (points[j].Y + points[i].Y) * ai;
|
||||
}
|
||||
xtmp += (q.X + p.X) * ai;
|
||||
ytmp += (q.Y + p.Y) * ai;
|
||||
|
||||
edge = edge.Next;
|
||||
|
||||
} while (edge.Next.ID != first);
|
||||
|
||||
x = xtmp / (3 * atmp);
|
||||
y = ytmp / (3 * atmp);
|
||||
|
||||
@@ -137,7 +137,7 @@ namespace TriangleNet.Tools
|
||||
// Add edge (1,2) if this is the first occurrence, that is, if
|
||||
// the edge (1,2) is on a boundary (nid <= 0) or if this triangle
|
||||
// is the first of the pair in which the edge occurs (tid < nid).
|
||||
neigh_id = tri.neighbors[2].triangle.id;
|
||||
neigh_id = tri.neighbors[2].tri.id;
|
||||
|
||||
if (neigh_id < 0 || tri_id < neigh_id)
|
||||
{
|
||||
@@ -146,7 +146,7 @@ namespace TriangleNet.Tools
|
||||
}
|
||||
|
||||
// Add edge (2,3).
|
||||
neigh_id = tri.neighbors[0].triangle.id;
|
||||
neigh_id = tri.neighbors[0].tri.id;
|
||||
|
||||
if (neigh_id < 0 || tri_id < neigh_id)
|
||||
{
|
||||
@@ -155,7 +155,7 @@ namespace TriangleNet.Tools
|
||||
}
|
||||
|
||||
// Add edge (3,1).
|
||||
neigh_id = tri.neighbors[1].triangle.id;
|
||||
neigh_id = tri.neighbors[1].tri.id;
|
||||
|
||||
if (neigh_id < 0 || tri_id < neigh_id)
|
||||
{
|
||||
@@ -227,7 +227,7 @@ namespace TriangleNet.Tools
|
||||
// Add edge (1,2) if this is the first occurrence, that is, if
|
||||
// the edge (1,2) is on a boundary (nid <= 0) or if this triangle
|
||||
// is the first of the pair in which the edge occurs (tid < nid).
|
||||
nid = tri.neighbors[2].triangle.id;
|
||||
nid = tri.neighbors[2].tri.id;
|
||||
|
||||
if (nid < 0 || tid < nid)
|
||||
{
|
||||
@@ -238,7 +238,7 @@ namespace TriangleNet.Tools
|
||||
}
|
||||
|
||||
// Add edge (2,3).
|
||||
nid = tri.neighbors[0].triangle.id;
|
||||
nid = tri.neighbors[0].tri.id;
|
||||
|
||||
if (nid < 0 || tid < nid)
|
||||
{
|
||||
@@ -249,7 +249,7 @@ namespace TriangleNet.Tools
|
||||
}
|
||||
|
||||
// Add edge (3,1).
|
||||
nid = tri.neighbors[1].triangle.id;
|
||||
nid = tri.neighbors[1].tri.id;
|
||||
|
||||
if (nid < 0 || tid < nid)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="IntersectionHelper.cs" company="">
|
||||
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Tools
|
||||
{
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
using Vertex = TriangleNet.Topology.DCEL.Vertex;
|
||||
|
||||
public static class IntersectionHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Compute intersection of two segments.
|
||||
/// </summary>
|
||||
/// <param name="p0">Segment 1 start point.</param>
|
||||
/// <param name="p1">Segment 1 end point.</param>
|
||||
/// <param name="q0">Segment 2 start point.</param>
|
||||
/// <param name="q1">Segment 2 end point.</param>
|
||||
/// <param name="c0">The intersection point.</param>
|
||||
/// <remarks>
|
||||
/// This is a special case of segment intersection. Since the calling algorithm assures
|
||||
/// that a valid intersection exists, there's no need to check for any special cases.
|
||||
/// </remarks>
|
||||
public static void IntersectSegments(Point p0, Point p1, Point q0, Point q1, ref Point c0)
|
||||
{
|
||||
double ux = p1.x - p0.x;
|
||||
double uy = p1.y - p0.y;
|
||||
double vx = q1.x - q0.x;
|
||||
double vy = q1.y - q0.y;
|
||||
double wx = p0.x - q0.x;
|
||||
double wy = p0.y - q0.y;
|
||||
|
||||
double d = (ux * vy - uy * vx);
|
||||
double s = (vx * wy - vy * wx) / d;
|
||||
|
||||
// Intersection point
|
||||
c0.x = p0.X + s * ux;
|
||||
c0.y = p0.Y + s * uy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Intersect segment with a bounding box.
|
||||
/// </summary>
|
||||
/// <param name="rect">The clip rectangle.</param>
|
||||
/// <param name="p0">Segment endpoint.</param>
|
||||
/// <param name="p1">Segment endpoint.</param>
|
||||
/// <param name="c0">The new location of p0 (DCEL vertex).</param>
|
||||
/// <param name="c1">The new location of p1 (DCEL vertex).</param>
|
||||
/// <returns>Returns true, if segment is clipped.</returns>
|
||||
/// <remarks>
|
||||
/// Based on Liang-Barsky function by Daniel White:
|
||||
/// http://www.skytopia.com/project/articles/compsci/clipping.html
|
||||
/// </remarks>
|
||||
public static bool LiangBarsky(Rectangle rect, Point p0, Point p1, ref Point c0, ref Point c1)
|
||||
{
|
||||
// Define the x/y clipping values for the border.
|
||||
double xmin = rect.Left;
|
||||
double xmax = rect.Right;
|
||||
double ymin = rect.Bottom;
|
||||
double ymax = rect.Top;
|
||||
|
||||
// Define the start and end points of the line.
|
||||
double x0 = p0.X;
|
||||
double y0 = p0.Y;
|
||||
double x1 = p1.X;
|
||||
double y1 = p1.Y;
|
||||
|
||||
double t0 = 0.0;
|
||||
double t1 = 1.0;
|
||||
|
||||
double dx = x1 - x0;
|
||||
double dy = y1 - y0;
|
||||
|
||||
double p = 0.0, q = 0.0, r;
|
||||
|
||||
for (int edge = 0; edge < 4; edge++)
|
||||
{
|
||||
// Traverse through left, right, bottom, top edges.
|
||||
if (edge == 0) { p = -dx; q = -(xmin - x0); }
|
||||
if (edge == 1) { p = dx; q = (xmax - x0); }
|
||||
if (edge == 2) { p = -dy; q = -(ymin - y0); }
|
||||
if (edge == 3) { p = dy; q = (ymax - y0); }
|
||||
r = q / p;
|
||||
if (p == 0 && q < 0) return false; // Don't draw line at all. (parallel line outside)
|
||||
if (p < 0)
|
||||
{
|
||||
if (r > t1) return false; // Don't draw line at all.
|
||||
else if (r > t0) t0 = r; // Line is clipped!
|
||||
}
|
||||
else if (p > 0)
|
||||
{
|
||||
if (r < t0) return false; // Don't draw line at all.
|
||||
else if (r < t1) t1 = r; // Line is clipped!
|
||||
}
|
||||
}
|
||||
|
||||
c0.X = x0 + t0 * dx;
|
||||
c0.Y = y0 + t0 * dy;
|
||||
c1.X = x0 + t1 * dx;
|
||||
c1.Y = y0 + t1 * dy;
|
||||
|
||||
return true; // (clipped) line is drawn
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Intersect a ray with a bounding box.
|
||||
/// </summary>
|
||||
/// <param name="rect">The clip rectangle.</param>
|
||||
/// <param name="p0">The ray startpoint (inside the box).</param>
|
||||
/// <param name="p1">Any point in ray direction (NOT the direction vector).</param>
|
||||
/// <param name="c1">The intersection point (DCEL vertex).</param>
|
||||
/// <returns>Returns false, if startpoint is outside the box.</returns>
|
||||
public static bool BoxRayIntersection(Rectangle rect, Point p0, Point p1, ref Point c1)
|
||||
{
|
||||
double x = p0.X;
|
||||
double y = p0.Y;
|
||||
|
||||
double dx = p1.x - x;
|
||||
double dy = p1.y - y;
|
||||
|
||||
double t1, x1, y1, t2, x2, y2;
|
||||
|
||||
// Bounding box
|
||||
double xmin = rect.Left;
|
||||
double xmax = rect.Right;
|
||||
double ymin = rect.Bottom;
|
||||
double ymax = rect.Top;
|
||||
|
||||
// Check if point is inside the bounds
|
||||
if (x < xmin || x > xmax || y < ymin || y > ymax)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate the cut through the vertical boundaries
|
||||
if (dx < 0)
|
||||
{
|
||||
// Line going to the left: intersect with x = minX
|
||||
t1 = (xmin - x) / dx;
|
||||
x1 = xmin;
|
||||
y1 = y + t1 * dy;
|
||||
}
|
||||
else if (dx > 0)
|
||||
{
|
||||
// Line going to the right: intersect with x = maxX
|
||||
t1 = (xmax - x) / dx;
|
||||
x1 = xmax;
|
||||
y1 = y + t1 * dy;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Line going straight up or down: no intersection possible
|
||||
t1 = double.MaxValue;
|
||||
x1 = y1 = 0;
|
||||
}
|
||||
|
||||
// Calculate the cut through upper and lower boundaries
|
||||
if (dy < 0)
|
||||
{
|
||||
// Line going downwards: intersect with y = minY
|
||||
t2 = (ymin - y) / dy;
|
||||
x2 = x + t2 * dx;
|
||||
y2 = ymin;
|
||||
}
|
||||
else if (dy > 0)
|
||||
{
|
||||
// Line going upwards: intersect with y = maxY
|
||||
t2 = (ymax - y) / dy;
|
||||
x2 = x + t2 * dx;
|
||||
y2 = ymax;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Horizontal line: no intersection possible
|
||||
t2 = double.MaxValue;
|
||||
x2 = y2 = 0;
|
||||
}
|
||||
|
||||
if (t1 < t2)
|
||||
{
|
||||
c1.x = x1;
|
||||
c1.y = y1;
|
||||
}
|
||||
else
|
||||
{
|
||||
c1.x = x2;
|
||||
c1.y = y2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace TriangleNet.Tools
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// A Quadtree implementation optimised for triangles.
|
||||
/// A Quadtree implementation optimized for triangles.
|
||||
/// </summary>
|
||||
public class QuadTree
|
||||
{
|
||||
@@ -181,9 +181,9 @@ namespace TriangleNet.Tools
|
||||
{
|
||||
// The four sub regions of the quad tree
|
||||
// +--------------+
|
||||
// | nw | ne |
|
||||
// | nw 2 | ne 3 |
|
||||
// |------+pivot--|
|
||||
// | sw | se |
|
||||
// | sw 0 | se 1 |
|
||||
// +--------------+
|
||||
Rectangle box;
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ namespace TriangleNet.Tools
|
||||
tri.orient = 0;
|
||||
foreach (var t in mesh.triangles.Values)
|
||||
{
|
||||
tri.triangle = t;
|
||||
tri.tri = t;
|
||||
p[0] = tri.Org();
|
||||
p[1] = tri.Dest();
|
||||
p[2] = tri.Apex();
|
||||
|
||||
@@ -70,71 +70,141 @@ namespace TriangleNet.Topology.DCEL
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the DCEL ist consistend.
|
||||
/// Check if the DCEL is consistend.
|
||||
/// </summary>
|
||||
/// <param name="closed">If true, faces are assumed to be closed (i.e. all edges must have
|
||||
/// a valid next pointer).</param>
|
||||
/// <param name="depth">Maximum edge count of faces (default = 0 means skip check).</param>
|
||||
/// <returns></returns>
|
||||
public bool IsConsistent(bool closed = true)
|
||||
public virtual bool IsConsistent(bool closed = true, int depth = 0)
|
||||
{
|
||||
int horrors = 0;
|
||||
|
||||
// Check faces
|
||||
foreach (var face in faces)
|
||||
// Check vertices for null pointers.
|
||||
foreach (var vertex in vertices)
|
||||
{
|
||||
if (face.edge == null)
|
||||
if (vertex.id < 0)
|
||||
{
|
||||
horrors++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vertex.leaving == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vertex.Leaving.Origin.id != vertex.id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check half-edges
|
||||
// Check faces for null pointers.
|
||||
foreach (var face in faces)
|
||||
{
|
||||
if (face.ID < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (face.edge == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (face.id != face.edge.face.id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check half-edges for null pointers.
|
||||
foreach (var edge in edges)
|
||||
{
|
||||
var twin = edge.twin;
|
||||
if (edge.id < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (edge.twin == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (edge.face == null)
|
||||
{
|
||||
horrors++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check vertices
|
||||
foreach (var vertex in vertices)
|
||||
{
|
||||
if (vertex.leaving == null)
|
||||
if (closed && edge.next == null)
|
||||
{
|
||||
horrors++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return horrors == 0;
|
||||
// Check half-edges (topology).
|
||||
foreach (var edge in edges)
|
||||
{
|
||||
if (edge.id < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var twin = edge.twin;
|
||||
var next = edge.next;
|
||||
|
||||
if (edge.id != twin.twin.id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (closed)
|
||||
{
|
||||
if (next.origin.id != twin.origin.id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (next.twin.next.origin.id != edge.twin.origin.id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (closed && depth > 0)
|
||||
{
|
||||
// Check if faces are closed.
|
||||
foreach (var face in faces)
|
||||
{
|
||||
if (face.id < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var edge = face.edge;
|
||||
var next = edge.next;
|
||||
|
||||
int id = edge.id;
|
||||
int k = 0;
|
||||
|
||||
while (next.id != id && k < depth)
|
||||
{
|
||||
next = next.next;
|
||||
k++;
|
||||
}
|
||||
|
||||
if (next.id != id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -144,7 +214,7 @@ namespace TriangleNet.Topology.DCEL
|
||||
/// <remarks>
|
||||
/// This method assumes that all faces are closed (i.e. no edge.next pointers are null).
|
||||
/// </remarks>
|
||||
internal void ResolveBoundaryEdges()
|
||||
public void ResolveBoundaryEdges()
|
||||
{
|
||||
// Maps vertices to leaving boundary edge.
|
||||
var map = new Dictionary<int, HalfEdge>();
|
||||
|
||||
@@ -18,10 +18,15 @@ namespace TriangleNet.Topology
|
||||
/// side of the edge. Hence, there are two possible orientations. By convention, the
|
||||
/// edge is always directed so that the "side" denoted is the right side of the edge.
|
||||
/// </remarks>
|
||||
struct Osub
|
||||
public struct Osub
|
||||
{
|
||||
public Segment seg;
|
||||
public int orient; // Ranges from 0 to 1.
|
||||
internal Segment seg;
|
||||
internal int orient; // Ranges from 0 to 1.
|
||||
|
||||
public Segment Segment
|
||||
{
|
||||
get { return seg; }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
@@ -37,18 +42,16 @@ namespace TriangleNet.Topology
|
||||
/// <summary>
|
||||
/// Reverse the orientation of a subsegment. [sym(ab) -> ba]
|
||||
/// </summary>
|
||||
/// <remarks>ssym() toggles the orientation of a subsegment.
|
||||
/// </remarks>
|
||||
public void Sym(ref Osub o2)
|
||||
public void Sym(ref Osub os)
|
||||
{
|
||||
o2.seg = seg;
|
||||
o2.orient = 1 - orient;
|
||||
os.seg = seg;
|
||||
os.orient = 1 - orient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverse the orientation of a subsegment. [sym(ab) -> ba]
|
||||
/// </summary>
|
||||
public void SymSelf()
|
||||
public void Sym()
|
||||
{
|
||||
orient = 1 - orient;
|
||||
}
|
||||
@@ -59,40 +62,33 @@ namespace TriangleNet.Topology
|
||||
/// <remarks>spivot() finds the other subsegment (from the same segment)
|
||||
/// that shares the same origin.
|
||||
/// </remarks>
|
||||
public void Pivot(ref Osub o2)
|
||||
public void Pivot(ref Osub os)
|
||||
{
|
||||
o2 = seg.subsegs[orient];
|
||||
//sdecode(sptr, o2);
|
||||
os = seg.subsegs[orient];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find adjoining subsegment with the same origin. [pivot(ab) -> a*]
|
||||
/// Finds a triangle abutting a subsegment.
|
||||
/// </summary>
|
||||
public void PivotSelf()
|
||||
internal void Pivot(ref Otri ot)
|
||||
{
|
||||
this = seg.subsegs[orient];
|
||||
//sdecode(sptr, osub);
|
||||
ot = seg.triangles[orient];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find next subsegment in sequence. [next(ab) -> b*]
|
||||
/// </summary>
|
||||
/// <remarks>snext() finds the next subsegment (from the same segment) in
|
||||
/// sequence; one whose origin is the input subsegment's destination.
|
||||
/// </remarks>
|
||||
public void Next(ref Osub o2)
|
||||
public void Next(ref Osub ot)
|
||||
{
|
||||
o2 = seg.subsegs[1 - orient];
|
||||
//sdecode(sptr, o2);
|
||||
ot = seg.subsegs[1 - orient];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find next subsegment in sequence. [next(ab) -> b*]
|
||||
/// </summary>
|
||||
public void NextSelf()
|
||||
public void Next()
|
||||
{
|
||||
this = seg.subsegs[1 - orient];
|
||||
//sdecode(sptr, osub);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -111,26 +107,31 @@ namespace TriangleNet.Topology
|
||||
return seg.vertices[1 - orient];
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Osub primitives (internal)
|
||||
|
||||
/// <summary>
|
||||
/// Set the origin or destination of a subsegment.
|
||||
/// </summary>
|
||||
public void SetOrg(Vertex ptr)
|
||||
internal void SetOrg(Vertex vertex)
|
||||
{
|
||||
seg.vertices[orient] = ptr;
|
||||
seg.vertices[orient] = vertex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set destination of a subsegment.
|
||||
/// </summary>
|
||||
public void SetDest(Vertex ptr)
|
||||
internal void SetDest(Vertex vertex)
|
||||
{
|
||||
seg.vertices[1 - orient] = ptr;
|
||||
seg.vertices[1 - orient] = vertex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the origin of the segment that includes the subsegment.
|
||||
/// </summary>
|
||||
public Vertex SegOrg()
|
||||
internal Vertex SegOrg()
|
||||
{
|
||||
return seg.vertices[2 + orient];
|
||||
}
|
||||
@@ -138,7 +139,7 @@ namespace TriangleNet.Topology
|
||||
/// <summary>
|
||||
/// Get the destination of the segment that includes the subsegment.
|
||||
/// </summary>
|
||||
public Vertex SegDest()
|
||||
internal Vertex SegDest()
|
||||
{
|
||||
return seg.vertices[3 - orient];
|
||||
}
|
||||
@@ -146,17 +147,27 @@ namespace TriangleNet.Topology
|
||||
/// <summary>
|
||||
/// Set the origin of the segment that includes the subsegment.
|
||||
/// </summary>
|
||||
public void SetSegOrg(Vertex ptr)
|
||||
internal void SetSegOrg(Vertex vertex)
|
||||
{
|
||||
seg.vertices[2 + orient] = ptr;
|
||||
seg.vertices[2 + orient] = vertex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the destination of the segment that includes the subsegment.
|
||||
/// </summary>
|
||||
public void SetSegDest(Vertex ptr)
|
||||
internal void SetSegDest(Vertex vertex)
|
||||
{
|
||||
seg.vertices[3 - orient] = ptr;
|
||||
seg.vertices[3 - orient] = vertex;
|
||||
}
|
||||
|
||||
/* Unused primitives.
|
||||
|
||||
/// <summary>
|
||||
/// Find adjoining subsegment with the same origin. [pivot(ab) -> a*]
|
||||
/// </summary>
|
||||
public void PivotSelf()
|
||||
{
|
||||
this = seg.subsegs[orient];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -177,25 +188,6 @@ namespace TriangleNet.Topology
|
||||
seg.boundary = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bond two subsegments together. [bond(abc, ba)]
|
||||
/// </summary>
|
||||
public void Bond(ref Osub o2)
|
||||
{
|
||||
seg.subsegs[orient] = o2;
|
||||
o2.seg.subsegs[o2.orient] = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dissolve a subsegment bond (from one side).
|
||||
/// </summary>
|
||||
/// <remarks>Note that the other subsegment will still think it's
|
||||
/// connected to this subsegment.</remarks>
|
||||
public void Dissolve()
|
||||
{
|
||||
seg.subsegs[orient].seg = Segment.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy a subsegment.
|
||||
/// </summary>
|
||||
@@ -205,18 +197,47 @@ namespace TriangleNet.Topology
|
||||
o2.orient = orient;
|
||||
}
|
||||
|
||||
//*/
|
||||
|
||||
/// <summary>
|
||||
/// Bond two subsegments together. [bond(abc, ba)]
|
||||
/// </summary>
|
||||
internal void Bond(ref Osub os)
|
||||
{
|
||||
seg.subsegs[orient] = os;
|
||||
os.seg.subsegs[os.orient] = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dissolve a subsegment bond (from one side).
|
||||
/// </summary>
|
||||
/// <remarks>Note that the other subsegment will still think it's
|
||||
/// connected to this subsegment.</remarks>
|
||||
internal void Dissolve()
|
||||
{
|
||||
seg.subsegs[orient].seg = Segment.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test for equality of subsegments.
|
||||
/// </summary>
|
||||
public bool Equal(Osub o2)
|
||||
internal bool Equal(Osub os)
|
||||
{
|
||||
return ((seg == o2.seg) && (orient == o2.orient));
|
||||
return ((seg == os.seg) && (orient == os.orient));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dissolve a bond (from the subsegment side).
|
||||
/// </summary>
|
||||
internal void TriDissolve()
|
||||
{
|
||||
seg.triangles[orient].tri = Triangle.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check a subsegment's deallocation.
|
||||
/// </summary>
|
||||
public static bool IsDead(Segment sub)
|
||||
internal static bool IsDead(Segment sub)
|
||||
{
|
||||
return sub.subsegs[0].seg == null;
|
||||
}
|
||||
@@ -224,29 +245,12 @@ namespace TriangleNet.Topology
|
||||
/// <summary>
|
||||
/// Set a subsegment's deallocation.
|
||||
/// </summary>
|
||||
public static void Kill(Segment sub)
|
||||
internal static void Kill(Segment sub)
|
||||
{
|
||||
sub.subsegs[0].seg = null;
|
||||
sub.subsegs[1].seg = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds a triangle abutting a subsegment.
|
||||
/// </summary>
|
||||
public void TriPivot(ref Otri ot)
|
||||
{
|
||||
ot = seg.triangles[orient];
|
||||
//decode(ptr, otri)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dissolve a bond (from the subsegment side).
|
||||
/// </summary>
|
||||
public void TriDissolve()
|
||||
{
|
||||
seg.triangles[orient].triangle = Triangle.Empty;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,73 +18,97 @@ namespace TriangleNet.Topology
|
||||
/// of the triangle. Hence, there are three possible orientations. By convention, each
|
||||
/// edge always points counterclockwise about the corresponding triangle.
|
||||
/// </remarks>
|
||||
struct Otri
|
||||
public struct Otri
|
||||
{
|
||||
public Triangle triangle;
|
||||
public int orient; // Ranges from 0 to 2.
|
||||
internal Triangle tri;
|
||||
internal int orient; // Ranges from 0 to 2.
|
||||
|
||||
public Triangle Triangle
|
||||
{
|
||||
get { return tri; }
|
||||
set { tri = value; }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (triangle == null)
|
||||
if (tri == null)
|
||||
{
|
||||
return "O-TID [null]";
|
||||
}
|
||||
return String.Format("O-TID {0}", triangle.hash);
|
||||
return String.Format("O-TID {0}", tri.hash);
|
||||
}
|
||||
|
||||
#region Otri primitives
|
||||
#region Otri primitives (public)
|
||||
|
||||
// For fast access
|
||||
static readonly int[] plus1Mod3 = { 1, 2, 0 };
|
||||
static readonly int[] minus1Mod3 = { 2, 0, 1 };
|
||||
|
||||
// The following handle manipulation primitives are all described by Guibas
|
||||
// and Stolfi. However, Guibas and Stolfi use an edge-based data structure,
|
||||
// The following primitives are all described by Guibas and Stolfi.
|
||||
// However, Guibas and Stolfi use an edge-based data structure,
|
||||
// whereas I use a triangle-based data structure.
|
||||
//
|
||||
// lnext: finds the next edge (counterclockwise) of a triangle.
|
||||
//
|
||||
// onext: spins counterclockwise around a vertex; that is, it finds
|
||||
// the next edge with the same origin in the counterclockwise direction. This
|
||||
// edge is part of a different triangle.
|
||||
//
|
||||
// oprev: spins clockwise around a vertex; that is, it finds the
|
||||
// next edge with the same origin in the clockwise direction. This edge is
|
||||
// part of a different triangle.
|
||||
//
|
||||
// dnext: spins counterclockwise around a vertex; that is, it finds
|
||||
// the next edge with the same destination in the counterclockwise direction.
|
||||
// This edge is part of a different triangle.
|
||||
//
|
||||
// dprev: spins clockwise around a vertex; that is, it finds the
|
||||
// next edge with the same destination in the clockwise direction. This edge
|
||||
// is part of a different triangle.
|
||||
//
|
||||
// rnext: moves one edge counterclockwise about the adjacent
|
||||
// triangle. (It's best understood by reading Guibas and Stolfi. It
|
||||
// involves changing triangles twice.)
|
||||
//
|
||||
// rprev: moves one edge clockwise about the adjacent triangle.
|
||||
// (It's best understood by reading Guibas and Stolfi. It involves
|
||||
// changing triangles twice.)
|
||||
|
||||
/// <summary>
|
||||
/// Find the abutting triangle; same edge. [sym(abc) -> ba*]
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note that the edge direction is necessarily reversed, because the handle specified
|
||||
/// by an oriented triangle is directed counterclockwise around the triangle.
|
||||
/// </remarks>
|
||||
public void Sym(ref Otri o2)
|
||||
public void Sym(ref Otri ot)
|
||||
{
|
||||
//o2 = tri.triangles[orient];
|
||||
// decode(ptr, otri2);
|
||||
|
||||
o2.triangle = triangle.neighbors[orient].triangle;
|
||||
o2.orient = triangle.neighbors[orient].orient;
|
||||
ot.tri = tri.neighbors[orient].tri;
|
||||
ot.orient = tri.neighbors[orient].orient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the abutting triangle; same edge. [sym(abc) -> ba*]
|
||||
/// </summary>
|
||||
public void SymSelf()
|
||||
public void Sym()
|
||||
{
|
||||
//this = tri.triangles[orient];
|
||||
// decode(ptr, otri);
|
||||
|
||||
int tmp = orient;
|
||||
orient = triangle.neighbors[tmp].orient;
|
||||
triangle = triangle.neighbors[tmp].triangle;
|
||||
orient = tri.neighbors[tmp].orient;
|
||||
tri = tri.neighbors[tmp].tri;
|
||||
}
|
||||
// lnext() finds the next edge (counterclockwise) of a triangle.
|
||||
|
||||
/// <summary>
|
||||
/// Find the next edge (counterclockwise) of a triangle. [lnext(abc) -> bca]
|
||||
/// </summary>
|
||||
public void Lnext(ref Otri o2)
|
||||
public void Lnext(ref Otri ot)
|
||||
{
|
||||
o2.triangle = triangle;
|
||||
o2.orient = plus1Mod3[orient];
|
||||
ot.tri = tri;
|
||||
ot.orient = plus1Mod3[orient];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the next edge (counterclockwise) of a triangle. [lnext(abc) -> bca]
|
||||
/// </summary>
|
||||
public void LnextSelf()
|
||||
public void Lnext()
|
||||
{
|
||||
orient = plus1Mod3[orient];
|
||||
}
|
||||
@@ -92,16 +116,16 @@ namespace TriangleNet.Topology
|
||||
/// <summary>
|
||||
/// Find the previous edge (clockwise) of a triangle. [lprev(abc) -> cab]
|
||||
/// </summary>
|
||||
public void Lprev(ref Otri o2)
|
||||
public void Lprev(ref Otri ot)
|
||||
{
|
||||
o2.triangle = triangle;
|
||||
o2.orient = minus1Mod3[orient];
|
||||
ot.tri = tri;
|
||||
ot.orient = minus1Mod3[orient];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the previous edge (clockwise) of a triangle. [lprev(abc) -> cab]
|
||||
/// </summary>
|
||||
public void LprevSelf()
|
||||
public void Lprev()
|
||||
{
|
||||
orient = minus1Mod3[orient];
|
||||
}
|
||||
@@ -109,62 +133,54 @@ namespace TriangleNet.Topology
|
||||
/// <summary>
|
||||
/// Find the next edge counterclockwise with the same origin. [onext(abc) -> ac*]
|
||||
/// </summary>
|
||||
/// <remarks>onext() spins counterclockwise around a vertex; that is, it finds
|
||||
/// the next edge with the same origin in the counterclockwise direction. This
|
||||
/// edge is part of a different triangle.
|
||||
/// </remarks>
|
||||
public void Onext(ref Otri o2)
|
||||
public void Onext(ref Otri ot)
|
||||
{
|
||||
//Lprev(ref o2);
|
||||
o2.triangle = triangle;
|
||||
o2.orient = minus1Mod3[orient];
|
||||
//Lprev(ref ot);
|
||||
ot.tri = tri;
|
||||
ot.orient = minus1Mod3[orient];
|
||||
|
||||
//o2.SymSelf();
|
||||
int tmp = o2.orient;
|
||||
o2.orient = o2.triangle.neighbors[tmp].orient;
|
||||
o2.triangle = o2.triangle.neighbors[tmp].triangle;
|
||||
//ot.SymSelf();
|
||||
int tmp = ot.orient;
|
||||
ot.orient = ot.tri.neighbors[tmp].orient;
|
||||
ot.tri = ot.tri.neighbors[tmp].tri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the next edge counterclockwise with the same origin. [onext(abc) -> ac*]
|
||||
/// </summary>
|
||||
public void OnextSelf()
|
||||
public void Onext()
|
||||
{
|
||||
//LprevSelf();
|
||||
orient = minus1Mod3[orient];
|
||||
|
||||
//SymSelf();
|
||||
int tmp = orient;
|
||||
orient = triangle.neighbors[tmp].orient;
|
||||
triangle = triangle.neighbors[tmp].triangle;
|
||||
orient = tri.neighbors[tmp].orient;
|
||||
tri = tri.neighbors[tmp].tri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the next edge clockwise with the same origin. [oprev(abc) -> a*b]
|
||||
/// </summary>
|
||||
/// <remarks>oprev() spins clockwise around a vertex; that is, it finds the
|
||||
/// next edge with the same origin in the clockwise direction. This edge is
|
||||
/// part of a different triangle.
|
||||
/// </remarks>
|
||||
public void Oprev(ref Otri o2)
|
||||
public void Oprev(ref Otri ot)
|
||||
{
|
||||
//Sym(ref o2);
|
||||
o2.triangle = triangle.neighbors[orient].triangle;
|
||||
o2.orient = triangle.neighbors[orient].orient;
|
||||
//Sym(ref ot);
|
||||
ot.tri = tri.neighbors[orient].tri;
|
||||
ot.orient = tri.neighbors[orient].orient;
|
||||
|
||||
//o2.LnextSelf();
|
||||
o2.orient = plus1Mod3[o2.orient];
|
||||
//ot.LnextSelf();
|
||||
ot.orient = plus1Mod3[ot.orient];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the next edge clockwise with the same origin. [oprev(abc) -> a*b]
|
||||
/// </summary>
|
||||
public void OprevSelf()
|
||||
public void Oprev()
|
||||
{
|
||||
//SymSelf();
|
||||
int tmp = orient;
|
||||
orient = triangle.neighbors[tmp].orient;
|
||||
triangle = triangle.neighbors[tmp].triangle;
|
||||
orient = tri.neighbors[tmp].orient;
|
||||
tri = tri.neighbors[tmp].tri;
|
||||
|
||||
//LnextSelf();
|
||||
orient = plus1Mod3[orient];
|
||||
@@ -173,29 +189,25 @@ namespace TriangleNet.Topology
|
||||
/// <summary>
|
||||
/// Find the next edge counterclockwise with the same destination. [dnext(abc) -> *ba]
|
||||
/// </summary>
|
||||
/// <remarks>dnext() spins counterclockwise around a vertex; that is, it finds
|
||||
/// the next edge with the same destination in the counterclockwise direction.
|
||||
/// This edge is part of a different triangle.
|
||||
/// </remarks>
|
||||
public void Dnext(ref Otri o2)
|
||||
public void Dnext(ref Otri ot)
|
||||
{
|
||||
//Sym(ref o2);
|
||||
o2.triangle = triangle.neighbors[orient].triangle;
|
||||
o2.orient = triangle.neighbors[orient].orient;
|
||||
//Sym(ref ot);
|
||||
ot.tri = tri.neighbors[orient].tri;
|
||||
ot.orient = tri.neighbors[orient].orient;
|
||||
|
||||
//o2.LprevSelf();
|
||||
o2.orient = minus1Mod3[o2.orient];
|
||||
//ot.LprevSelf();
|
||||
ot.orient = minus1Mod3[ot.orient];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the next edge counterclockwise with the same destination. [dnext(abc) -> *ba]
|
||||
/// </summary>
|
||||
public void DnextSelf()
|
||||
public void Dnext()
|
||||
{
|
||||
//SymSelf();
|
||||
int tmp = orient;
|
||||
orient = triangle.neighbors[tmp].orient;
|
||||
triangle = triangle.neighbors[tmp].triangle;
|
||||
orient = tri.neighbors[tmp].orient;
|
||||
tri = tri.neighbors[tmp].tri;
|
||||
|
||||
//LprevSelf();
|
||||
orient = minus1Mod3[orient];
|
||||
@@ -204,116 +216,104 @@ namespace TriangleNet.Topology
|
||||
/// <summary>
|
||||
/// Find the next edge clockwise with the same destination. [dprev(abc) -> cb*]
|
||||
/// </summary>
|
||||
/// <remarks>dprev() spins clockwise around a vertex; that is, it finds the
|
||||
/// next edge with the same destination in the clockwise direction. This edge
|
||||
/// is part of a different triangle.
|
||||
/// </remarks>
|
||||
public void Dprev(ref Otri o2)
|
||||
public void Dprev(ref Otri ot)
|
||||
{
|
||||
//Lnext(ref o2);
|
||||
o2.triangle = triangle;
|
||||
o2.orient = plus1Mod3[orient];
|
||||
//Lnext(ref ot);
|
||||
ot.tri = tri;
|
||||
ot.orient = plus1Mod3[orient];
|
||||
|
||||
//o2.SymSelf();
|
||||
int tmp = o2.orient;
|
||||
o2.orient = o2.triangle.neighbors[tmp].orient;
|
||||
o2.triangle = o2.triangle.neighbors[tmp].triangle;
|
||||
//ot.SymSelf();
|
||||
int tmp = ot.orient;
|
||||
ot.orient = ot.tri.neighbors[tmp].orient;
|
||||
ot.tri = ot.tri.neighbors[tmp].tri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the next edge clockwise with the same destination. [dprev(abc) -> cb*]
|
||||
/// </summary>
|
||||
public void DprevSelf()
|
||||
public void Dprev()
|
||||
{
|
||||
//LnextSelf();
|
||||
orient = plus1Mod3[orient];
|
||||
|
||||
//SymSelf();
|
||||
int tmp = orient;
|
||||
orient = triangle.neighbors[tmp].orient;
|
||||
triangle = triangle.neighbors[tmp].triangle;
|
||||
orient = tri.neighbors[tmp].orient;
|
||||
tri = tri.neighbors[tmp].tri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the next edge (counterclockwise) of the adjacent triangle. [rnext(abc) -> *a*]
|
||||
/// </summary>
|
||||
/// <remarks>rnext() moves one edge counterclockwise about the adjacent
|
||||
/// triangle. (It's best understood by reading Guibas and Stolfi. It
|
||||
/// involves changing triangles twice.)
|
||||
/// </remarks>
|
||||
public void Rnext(ref Otri o2)
|
||||
public void Rnext(ref Otri ot)
|
||||
{
|
||||
//Sym(ref o2);
|
||||
o2.triangle = triangle.neighbors[orient].triangle;
|
||||
o2.orient = triangle.neighbors[orient].orient;
|
||||
//Sym(ref ot);
|
||||
ot.tri = tri.neighbors[orient].tri;
|
||||
ot.orient = tri.neighbors[orient].orient;
|
||||
|
||||
//o2.LnextSelf();
|
||||
o2.orient = plus1Mod3[o2.orient];
|
||||
//ot.LnextSelf();
|
||||
ot.orient = plus1Mod3[ot.orient];
|
||||
|
||||
//o2.SymSelf();
|
||||
int tmp = o2.orient;
|
||||
o2.orient = o2.triangle.neighbors[tmp].orient;
|
||||
o2.triangle = o2.triangle.neighbors[tmp].triangle;
|
||||
//ot.SymSelf();
|
||||
int tmp = ot.orient;
|
||||
ot.orient = ot.tri.neighbors[tmp].orient;
|
||||
ot.tri = ot.tri.neighbors[tmp].tri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the next edge (counterclockwise) of the adjacent triangle. [rnext(abc) -> *a*]
|
||||
/// </summary>
|
||||
public void RnextSelf()
|
||||
public void Rnext()
|
||||
{
|
||||
//SymSelf();
|
||||
int tmp = orient;
|
||||
orient = triangle.neighbors[tmp].orient;
|
||||
triangle = triangle.neighbors[tmp].triangle;
|
||||
orient = tri.neighbors[tmp].orient;
|
||||
tri = tri.neighbors[tmp].tri;
|
||||
|
||||
//LnextSelf();
|
||||
orient = plus1Mod3[orient];
|
||||
|
||||
//SymSelf();
|
||||
tmp = orient;
|
||||
orient = triangle.neighbors[tmp].orient;
|
||||
triangle = triangle.neighbors[tmp].triangle;
|
||||
orient = tri.neighbors[tmp].orient;
|
||||
tri = tri.neighbors[tmp].tri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the previous edge (clockwise) of the adjacent triangle. [rprev(abc) -> b**]
|
||||
/// </summary>
|
||||
/// <remarks>rprev() moves one edge clockwise about the adjacent triangle.
|
||||
/// (It's best understood by reading Guibas and Stolfi. It involves
|
||||
/// changing triangles twice.)
|
||||
/// </remarks>
|
||||
public void Rprev(ref Otri o2)
|
||||
public void Rprev(ref Otri ot)
|
||||
{
|
||||
//Sym(ref o2);
|
||||
o2.triangle = triangle.neighbors[orient].triangle;
|
||||
o2.orient = triangle.neighbors[orient].orient;
|
||||
//Sym(ref ot);
|
||||
ot.tri = tri.neighbors[orient].tri;
|
||||
ot.orient = tri.neighbors[orient].orient;
|
||||
|
||||
//o2.LprevSelf();
|
||||
o2.orient = minus1Mod3[o2.orient];
|
||||
//ot.LprevSelf();
|
||||
ot.orient = minus1Mod3[ot.orient];
|
||||
|
||||
//o2.SymSelf();
|
||||
int tmp = o2.orient;
|
||||
o2.orient = o2.triangle.neighbors[tmp].orient;
|
||||
o2.triangle = o2.triangle.neighbors[tmp].triangle;
|
||||
//ot.SymSelf();
|
||||
int tmp = ot.orient;
|
||||
ot.orient = ot.tri.neighbors[tmp].orient;
|
||||
ot.tri = ot.tri.neighbors[tmp].tri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the previous edge (clockwise) of the adjacent triangle. [rprev(abc) -> b**]
|
||||
/// </summary>
|
||||
public void RprevSelf()
|
||||
public void Rprev()
|
||||
{
|
||||
//SymSelf();
|
||||
int tmp = orient;
|
||||
orient = triangle.neighbors[tmp].orient;
|
||||
triangle = triangle.neighbors[tmp].triangle;
|
||||
orient = tri.neighbors[tmp].orient;
|
||||
tri = tri.neighbors[tmp].tri;
|
||||
|
||||
//LprevSelf();
|
||||
orient = minus1Mod3[orient];
|
||||
|
||||
//SymSelf();
|
||||
tmp = orient;
|
||||
orient = triangle.neighbors[tmp].orient;
|
||||
triangle = triangle.neighbors[tmp].triangle;
|
||||
orient = tri.neighbors[tmp].orient;
|
||||
tri = tri.neighbors[tmp].tri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -321,7 +321,7 @@ namespace TriangleNet.Topology
|
||||
/// </summary>
|
||||
public Vertex Org()
|
||||
{
|
||||
return triangle.vertices[plus1Mod3[orient]];
|
||||
return tri.vertices[plus1Mod3[orient]];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -329,7 +329,7 @@ namespace TriangleNet.Topology
|
||||
/// </summary>
|
||||
public Vertex Dest()
|
||||
{
|
||||
return triangle.vertices[minus1Mod3[orient]];
|
||||
return tri.vertices[minus1Mod3[orient]];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -337,46 +337,56 @@ namespace TriangleNet.Topology
|
||||
/// </summary>
|
||||
public Vertex Apex()
|
||||
{
|
||||
return triangle.vertices[orient];
|
||||
return tri.vertices[orient];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy an oriented triangle.
|
||||
/// </summary>
|
||||
public void Copy(ref Otri ot)
|
||||
{
|
||||
ot.tri = tri;
|
||||
ot.orient = orient;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Otri primitives (internal)
|
||||
|
||||
/// <summary>
|
||||
/// Set Origin
|
||||
/// </summary>
|
||||
public void SetOrg(Vertex ptr)
|
||||
internal void SetOrg(Vertex v)
|
||||
{
|
||||
triangle.vertices[plus1Mod3[orient]] = ptr;
|
||||
tri.vertices[plus1Mod3[orient]] = v;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set Destination
|
||||
/// </summary>
|
||||
public void SetDest(Vertex ptr)
|
||||
internal void SetDest(Vertex v)
|
||||
{
|
||||
triangle.vertices[minus1Mod3[orient]] = ptr;
|
||||
tri.vertices[minus1Mod3[orient]] = v;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set Apex
|
||||
/// </summary>
|
||||
public void SetApex(Vertex ptr)
|
||||
internal void SetApex(Vertex v)
|
||||
{
|
||||
triangle.vertices[orient] = ptr;
|
||||
tri.vertices[orient] = v;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bond two triangles together at the resepective handles. [bond(abc, bad)]
|
||||
/// </summary>
|
||||
public void Bond(ref Otri o2)
|
||||
internal void Bond(ref Otri ot)
|
||||
{
|
||||
//triangle.neighbors[orient]= o2;
|
||||
//o2.triangle.neighbors[o2.orient] = this;
|
||||
tri.neighbors[orient].tri = ot.tri;
|
||||
tri.neighbors[orient].orient = ot.orient;
|
||||
|
||||
triangle.neighbors[orient].triangle = o2.triangle;
|
||||
triangle.neighbors[orient].orient = o2.orient;
|
||||
|
||||
o2.triangle.neighbors[o2.orient].triangle = this.triangle;
|
||||
o2.triangle.neighbors[o2.orient].orient = this.orient;
|
||||
ot.tri.neighbors[ot.orient].tri = this.tri;
|
||||
ot.tri.neighbors[ot.orient].orient = this.orient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -386,94 +396,84 @@ namespace TriangleNet.Topology
|
||||
/// this triangle. Usually, however, the other triangle is being deleted
|
||||
/// entirely, or bonded to another triangle, so it doesn't matter.
|
||||
/// </remarks>
|
||||
public void Dissolve()
|
||||
internal void Dissolve()
|
||||
{
|
||||
triangle.neighbors[orient].triangle = Triangle.Empty;
|
||||
triangle.neighbors[orient].orient = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy an oriented triangle.
|
||||
/// </summary>
|
||||
public void Copy(ref Otri o2)
|
||||
{
|
||||
o2.triangle = triangle;
|
||||
o2.orient = orient;
|
||||
tri.neighbors[orient].tri = Triangle.Empty;
|
||||
tri.neighbors[orient].orient = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test for equality of oriented triangles.
|
||||
/// </summary>
|
||||
public bool Equal(Otri o2)
|
||||
internal bool Equal(Otri ot)
|
||||
{
|
||||
return ((triangle == o2.triangle) && (orient == o2.orient));
|
||||
return ((tri == ot.tri) && (orient == ot.orient));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Infect a triangle with the virus.
|
||||
/// </summary>
|
||||
public void Infect()
|
||||
internal void Infect()
|
||||
{
|
||||
triangle.infected = true;
|
||||
tri.infected = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cure a triangle from the virus.
|
||||
/// </summary>
|
||||
public void Uninfect()
|
||||
internal void Uninfect()
|
||||
{
|
||||
triangle.infected = false;
|
||||
tri.infected = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test a triangle for viral infection.
|
||||
/// </summary>
|
||||
public bool IsInfected()
|
||||
internal bool IsInfected()
|
||||
{
|
||||
return triangle.infected;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check a triangle's deallocation.
|
||||
/// </summary>
|
||||
public static bool IsDead(Triangle tria)
|
||||
{
|
||||
return tria.neighbors[0].triangle == null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set a triangle's deallocation.
|
||||
/// </summary>
|
||||
public static void Kill(Triangle tria)
|
||||
{
|
||||
tria.neighbors[0].triangle = null;
|
||||
tria.neighbors[2].triangle = null;
|
||||
return tri.infected;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds a subsegment abutting a triangle.
|
||||
/// </summary>
|
||||
public void SegPivot(ref Osub os)
|
||||
internal void Pivot(ref Osub os)
|
||||
{
|
||||
os = triangle.subsegs[orient];
|
||||
//sdecode(sptr, osub)
|
||||
os = tri.subsegs[orient];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bond a triangle to a subsegment.
|
||||
/// </summary>
|
||||
public void SegBond(ref Osub os)
|
||||
internal void SegBond(ref Osub os)
|
||||
{
|
||||
triangle.subsegs[orient] = os;
|
||||
tri.subsegs[orient] = os;
|
||||
os.seg.triangles[os.orient] = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dissolve a bond (from the triangle side).
|
||||
/// </summary>
|
||||
public void SegDissolve()
|
||||
internal void SegDissolve()
|
||||
{
|
||||
triangle.subsegs[orient].seg = Segment.Empty;
|
||||
tri.subsegs[orient].seg = Segment.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check a triangle's deallocation.
|
||||
/// </summary>
|
||||
internal static bool IsDead(Triangle tria)
|
||||
{
|
||||
return tria.neighbors[0].tri == null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set a triangle's deallocation.
|
||||
/// </summary>
|
||||
internal static void Kill(Triangle tri)
|
||||
{
|
||||
tri.neighbors[0].tri = null;
|
||||
tri.neighbors[2].tri = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -59,8 +59,8 @@ namespace TriangleNet.Topology
|
||||
|
||||
// Initialize the two adjoining triangles to be "outer space."
|
||||
triangles = new Otri[2];
|
||||
triangles[0].triangle = Triangle.Empty;
|
||||
triangles[1].triangle = Triangle.Empty;
|
||||
triangles[0].tri = Triangle.Empty;
|
||||
triangles[1].tri = Triangle.Empty;
|
||||
|
||||
// Set the boundary marker to zero.
|
||||
boundary = 0;
|
||||
@@ -107,7 +107,7 @@ namespace TriangleNet.Topology
|
||||
/// </summary>
|
||||
public ITriangle GetTriangle(int index)
|
||||
{
|
||||
return triangles[index].triangle.id == Triangle.EmptyID ? null : triangles[index].triangle;
|
||||
return triangles[index].tri.id == Triangle.EmptyID ? null : triangles[index].tri;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
|
||||
@@ -51,9 +51,9 @@ namespace TriangleNet.Topology
|
||||
// will eventually be changed by various bonding operations, but their
|
||||
// values don't really matter, as long as they can legally be
|
||||
// dereferenced.
|
||||
Empty.neighbors[0].triangle = Empty;
|
||||
Empty.neighbors[1].triangle = Empty;
|
||||
Empty.neighbors[2].triangle = Empty;
|
||||
Empty.neighbors[0].tri = Empty;
|
||||
Empty.neighbors[1].tri = Empty;
|
||||
Empty.neighbors[2].tri = Empty;
|
||||
|
||||
if (Segment.Empty == null)
|
||||
{
|
||||
@@ -83,6 +83,9 @@ namespace TriangleNet.Topology
|
||||
internal double area;
|
||||
internal bool infected;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Triangle" /> class.
|
||||
/// </summary>
|
||||
public Triangle()
|
||||
{
|
||||
// Three NULL vertices.
|
||||
@@ -96,9 +99,9 @@ namespace TriangleNet.Topology
|
||||
|
||||
// Initialize the three adjoining triangles to be "outer space".
|
||||
neighbors = new Otri[3];
|
||||
neighbors[0].triangle = Empty;
|
||||
neighbors[1].triangle = Empty;
|
||||
neighbors[2].triangle = Empty;
|
||||
neighbors[0].tri = Empty;
|
||||
neighbors[1].tri = Empty;
|
||||
neighbors[2].tri = Empty;
|
||||
|
||||
// area = -1.0;
|
||||
}
|
||||
@@ -130,14 +133,6 @@ namespace TriangleNet.Topology
|
||||
get { return this.vertices[1] == null ? -1 : this.vertices[1].id; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified corners vertex.
|
||||
/// </summary>
|
||||
public Vertex GetVertex(int index)
|
||||
{
|
||||
return this.vertices[index]; // TODO: Check range?
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the third corners vertex id.
|
||||
/// </summary>
|
||||
@@ -146,6 +141,14 @@ namespace TriangleNet.Topology
|
||||
get { return this.vertices[2] == null ? -1 : this.vertices[2].id; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified corners vertex.
|
||||
/// </summary>
|
||||
public Vertex GetVertex(int index)
|
||||
{
|
||||
return this.vertices[index]; // TODO: Check range?
|
||||
}
|
||||
|
||||
public bool SupportsNeighbors
|
||||
{
|
||||
get { return true; }
|
||||
@@ -156,7 +159,7 @@ namespace TriangleNet.Topology
|
||||
/// </summary>
|
||||
public int N0
|
||||
{
|
||||
get { return this.neighbors[0].triangle.id; }
|
||||
get { return this.neighbors[0].tri.id; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -164,7 +167,7 @@ namespace TriangleNet.Topology
|
||||
/// </summary>
|
||||
public int N1
|
||||
{
|
||||
get { return this.neighbors[1].triangle.id; }
|
||||
get { return this.neighbors[1].tri.id; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -172,7 +175,7 @@ namespace TriangleNet.Topology
|
||||
/// </summary>
|
||||
public int N2
|
||||
{
|
||||
get { return this.neighbors[2].triangle.id; }
|
||||
get { return this.neighbors[2].tri.id; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -182,7 +185,7 @@ namespace TriangleNet.Topology
|
||||
/// <returns>The neigbbor opposite of vertex with given index.</returns>
|
||||
public ITriangle GetNeighbor(int index)
|
||||
{
|
||||
return neighbors[index].triangle.id == EmptyID ? null : neighbors[index].triangle;
|
||||
return neighbors[index].tri.id == EmptyID ? null : neighbors[index].tri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
<Compile Include="Meshing\ConstraintMesher.cs" />
|
||||
<Compile Include="Meshing\Data\BadSubseg.cs" />
|
||||
<Compile Include="Meshing\Data\BadTriangle.cs" />
|
||||
<Compile Include="Tools\IntersectionHelper.cs" />
|
||||
<Compile Include="Topology\DCEL\DcelMesh.cs" />
|
||||
<Compile Include="Topology\Osub.cs" />
|
||||
<Compile Include="Topology\Otri.cs" />
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace TriangleNet
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
recenttri.triangle = null; // No triangle has been visited yet.
|
||||
recenttri.tri = null; // No triangle has been visited yet.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -127,7 +127,7 @@ namespace TriangleNet
|
||||
// Check whether the apex is the point we seek.
|
||||
if ((fapex.x == searchpoint.X) && (fapex.y == searchpoint.Y))
|
||||
{
|
||||
searchtri.LprevSelf();
|
||||
searchtri.Lprev();
|
||||
return LocateResult.OnVertex;
|
||||
}
|
||||
// Does the point lie on the other side of the line defined by the
|
||||
@@ -165,12 +165,12 @@ namespace TriangleNet
|
||||
// triangle.
|
||||
if (destorient == 0.0)
|
||||
{
|
||||
searchtri.LprevSelf();
|
||||
searchtri.Lprev();
|
||||
return LocateResult.OnEdge;
|
||||
}
|
||||
if (orgorient == 0.0)
|
||||
{
|
||||
searchtri.LnextSelf();
|
||||
searchtri.Lnext();
|
||||
return LocateResult.OnEdge;
|
||||
}
|
||||
return LocateResult.InTriangle;
|
||||
@@ -195,7 +195,7 @@ namespace TriangleNet
|
||||
if (mesh.checksegments && stopatsubsegment)
|
||||
{
|
||||
// Check for walking through a subsegment.
|
||||
backtracktri.SegPivot(ref checkedge);
|
||||
backtracktri.Pivot(ref checkedge);
|
||||
if (checkedge.seg != Segment.Empty)
|
||||
{
|
||||
// Go back to the last triangle.
|
||||
@@ -204,7 +204,7 @@ namespace TriangleNet
|
||||
}
|
||||
}
|
||||
// Check for walking right out of the triangulation.
|
||||
if (searchtri.triangle.id == Triangle.EmptyID)
|
||||
if (searchtri.tri.id == Triangle.EmptyID)
|
||||
{
|
||||
// Go back to the last triangle.
|
||||
backtracktri.Copy(ref searchtri);
|
||||
@@ -267,9 +267,9 @@ namespace TriangleNet
|
||||
|
||||
// If a recently encountered triangle has been recorded and has not been
|
||||
// deallocated, test it as a good starting point.
|
||||
if (recenttri.triangle != null)
|
||||
if (recenttri.tri != null)
|
||||
{
|
||||
if (!Otri.IsDead(recenttri.triangle))
|
||||
if (!Otri.IsDead(recenttri.tri))
|
||||
{
|
||||
torg = recenttri.Org();
|
||||
if ((torg.x == searchpoint.X) && (torg.y == searchpoint.Y))
|
||||
@@ -293,8 +293,8 @@ namespace TriangleNet
|
||||
|
||||
foreach (var key in samples)
|
||||
{
|
||||
sampletri.triangle = mesh.triangles[key];
|
||||
if (!Otri.IsDead(sampletri.triangle))
|
||||
sampletri.tri = mesh.triangles[key];
|
||||
if (!Otri.IsDead(sampletri.tri))
|
||||
{
|
||||
torg = sampletri.Org();
|
||||
dist = (searchpoint.X - torg.x) * (searchpoint.X - torg.x) +
|
||||
@@ -317,7 +317,7 @@ namespace TriangleNet
|
||||
}
|
||||
if ((tdest.x == searchpoint.X) && (tdest.y == searchpoint.Y))
|
||||
{
|
||||
searchtri.LnextSelf();
|
||||
searchtri.Lnext();
|
||||
return LocateResult.OnVertex;
|
||||
}
|
||||
// Orient 'searchtri' to fit the preconditions of calling preciselocate().
|
||||
@@ -326,7 +326,7 @@ namespace TriangleNet
|
||||
{
|
||||
// Turn around so that 'searchpoint' is to the left of the
|
||||
// edge specified by 'searchtri'.
|
||||
searchtri.SymSelf();
|
||||
searchtri.Sym();
|
||||
}
|
||||
else if (ahead == 0.0)
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace TriangleNet.Voronoi
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Tools;
|
||||
using TriangleNet.Topology.DCEL;
|
||||
|
||||
using HVertex = TriangleNet.Topology.DCEL.Vertex;
|
||||
@@ -38,22 +39,12 @@ namespace TriangleNet.Voronoi
|
||||
/// </summary>
|
||||
private void PostProcess()
|
||||
{
|
||||
var infEdges = new List<HalfEdge>();
|
||||
|
||||
// TODO: save the half-infinite boundary edge in base class
|
||||
// so we don't have to process the complete list here.
|
||||
foreach (var edge in base.edges)
|
||||
foreach (var edge in rays)
|
||||
{
|
||||
if (edge.next == null)
|
||||
{
|
||||
infEdges.Add(edge);
|
||||
}
|
||||
}
|
||||
var twin = edge.twin;
|
||||
|
||||
foreach (var edge in infEdges)
|
||||
{
|
||||
var v1 = (TVertex)edge.face.generator;
|
||||
var v2 = (TVertex)edge.twin.face.generator;
|
||||
var v2 = (TVertex)twin.face.generator;
|
||||
|
||||
double dir = RobustPredicates.CounterClockwise(v1, v2, edge.origin);
|
||||
|
||||
@@ -111,7 +102,7 @@ namespace TriangleNet.Voronoi
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Case 1: edge origin lies outside the domain.
|
||||
/// Case 2: edge origin lies outside the domain.
|
||||
/// </summary>
|
||||
private void HandleCase2(HalfEdge edge, TVertex v1, TVertex v2)
|
||||
{
|
||||
@@ -124,8 +115,8 @@ namespace TriangleNet.Voronoi
|
||||
var e2 = e1.twin.next;
|
||||
|
||||
// Find the two intersections with boundary edge.
|
||||
IntersectSegments(v1, v2, e1.origin, e1.twin.origin, ref p2);
|
||||
IntersectSegments(v1, v2, e2.origin, e2.twin.origin, ref p1);
|
||||
IntersectionHelper.IntersectSegments(v1, v2, e1.origin, e1.twin.origin, ref p2);
|
||||
IntersectionHelper.IntersectSegments(v1, v2, e2.origin, e2.twin.origin, ref p1);
|
||||
|
||||
// The infinite edge will now lie on the boundary. Update pointers:
|
||||
e1.twin.next = edge.twin;
|
||||
@@ -182,56 +173,5 @@ namespace TriangleNet.Voronoi
|
||||
return seg.seg.boundary;
|
||||
}
|
||||
//*/
|
||||
|
||||
/// <summary>
|
||||
/// Compute intersection of two segments.
|
||||
/// </summary>
|
||||
/// <param name="p0">Segment 1 start point.</param>
|
||||
/// <param name="p1">Segment 1 end point.</param>
|
||||
/// <param name="q0">Segment 2 start point.</param>
|
||||
/// <param name="q1">Segment 2 end point.</param>
|
||||
/// <param name="i0">The intersection point.</param>
|
||||
/// <remarks>
|
||||
/// This is a special case of segment intersection. Since the calling algorithm assures
|
||||
/// that a valid intersection exists, there's no need to check for any special cases.
|
||||
/// </remarks>
|
||||
private static void IntersectSegments(Point p0, Point p1, Point q0, Point q1, ref Point i0)
|
||||
{
|
||||
double ux = p1.x - p0.x;
|
||||
double uy = p1.y - p0.y;
|
||||
double vx = q1.x - q0.x;
|
||||
double vy = q1.y - q0.y;
|
||||
double wx = p0.x - q0.x;
|
||||
double wy = p0.y - q0.y;
|
||||
|
||||
double d = (ux * vy - uy * vx);
|
||||
double s = (vx * wy - vy * wx) / d;
|
||||
|
||||
// Intersection point
|
||||
i0.x = p0.X + s * ux;
|
||||
i0.y = p0.Y + s * uy;
|
||||
}
|
||||
|
||||
protected override IEnumerable<IEdge> EnumerateEdges()
|
||||
{
|
||||
var edges = new List<IEdge>(this.edges.Count / 2);
|
||||
|
||||
foreach (var edge in this.edges)
|
||||
{
|
||||
var twin = edge.twin;
|
||||
|
||||
// Report edge only once.
|
||||
if (twin == null)
|
||||
{
|
||||
edges.Add(new Edge(edge.origin.id, edge.next.origin.id));
|
||||
}
|
||||
else if (edge.id < twin.id)
|
||||
{
|
||||
edges.Add(new Edge(edge.origin.id, twin.origin.id));
|
||||
}
|
||||
}
|
||||
|
||||
return edges;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
// Compue triangle circumcenters
|
||||
foreach (var item in mesh.triangles.Values)
|
||||
{
|
||||
tri.triangle = item;
|
||||
tri.tri = item;
|
||||
|
||||
pt = RobustPredicates.FindCircumcenter(tri.Org(), tri.Dest(), tri.Apex(), ref xi, ref eta);
|
||||
pt.id = item.id;
|
||||
@@ -175,51 +175,51 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
// Push fe into triangles
|
||||
e.seg = ss;
|
||||
e.orient = 0;
|
||||
e.TriPivot(ref f);
|
||||
e.Pivot(ref f);
|
||||
|
||||
if (f.triangle.id != Triangle.EmptyID && !f.triangle.infected)
|
||||
if (f.tri.id != Triangle.EmptyID && !f.tri.infected)
|
||||
{
|
||||
triangles.Push(f.triangle);
|
||||
triangles.Push(f.tri);
|
||||
}
|
||||
|
||||
e.SymSelf();
|
||||
e.TriPivot(ref f);
|
||||
e.Sym();
|
||||
e.Pivot(ref f);
|
||||
|
||||
if (f.triangle.id != Triangle.EmptyID && !f.triangle.infected)
|
||||
if (f.tri.id != Triangle.EmptyID && !f.tri.infected)
|
||||
{
|
||||
triangles.Push(f.triangle);
|
||||
triangles.Push(f.tri);
|
||||
}
|
||||
|
||||
// while triangles is non-empty
|
||||
while (triangles.Count > 0)
|
||||
{
|
||||
// Pop f from stack triangles
|
||||
f.triangle = triangles.Pop();
|
||||
f.tri = triangles.Pop();
|
||||
f.orient = 0;
|
||||
|
||||
// if f is blinded by e (use P) then
|
||||
if (TriangleIsBlinded(ref f, ref e))
|
||||
{
|
||||
// Tag f as blinded by e
|
||||
f.triangle.infected = true;
|
||||
f.tri.infected = true;
|
||||
blinded++;
|
||||
|
||||
// Store association triangle -> subseg
|
||||
subsegMap.Add(f.triangle.hash, e.seg);
|
||||
subsegMap.Add(f.tri.hash, e.seg);
|
||||
|
||||
// for each adjacent triangle f0 to f do
|
||||
for (f.orient = 0; f.orient < 3; f.orient++)
|
||||
{
|
||||
f.Sym(ref f0);
|
||||
|
||||
f0.SegPivot(ref sub1);
|
||||
f0.Pivot(ref sub1);
|
||||
|
||||
// if f0 is finite and tagged non-blind & the common edge
|
||||
// between f and f0 is unconstrained then
|
||||
if (f0.triangle.id != Triangle.EmptyID && !f0.triangle.infected && sub1.seg == Segment.Empty)
|
||||
if (f0.tri.id != Triangle.EmptyID && !f0.tri.infected && sub1.seg == Segment.Empty)
|
||||
{
|
||||
// Push f0 into triangles.
|
||||
triangles.Push(f0.triangle);
|
||||
triangles.Push(f0.tri);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -246,7 +246,7 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
Vertex sorg = seg.Org();
|
||||
Vertex sdest = seg.Dest();
|
||||
|
||||
c = this.points[tri.triangle.id];
|
||||
c = this.points[tri.tri.id];
|
||||
|
||||
if (SegmentsIntersect(sorg, sdest, c, torg, out pt, true))
|
||||
{
|
||||
@@ -301,19 +301,19 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
do
|
||||
{
|
||||
// Call Lffnext the line going through the circumcenters of f and f_next
|
||||
cc_f = this.points[f.triangle.id];
|
||||
cc_f_next = this.points[f_next.triangle.id];
|
||||
cc_f = this.points[f.tri.id];
|
||||
cc_f_next = this.points[f_next.tri.id];
|
||||
|
||||
// if f is tagged non-blind then
|
||||
if (!f.triangle.infected)
|
||||
if (!f.tri.infected)
|
||||
{
|
||||
// Insert the circumcenter of f into P
|
||||
vpoints.Add(cc_f);
|
||||
|
||||
if (f_next.triangle.infected)
|
||||
if (f_next.tri.infected)
|
||||
{
|
||||
// Call S_fnext the constrained edge blinding f_next
|
||||
sfn.seg = subsegMap[f_next.triangle.hash];
|
||||
sfn.seg = subsegMap[f_next.tri.hash];
|
||||
|
||||
// Insert point Lf,f_next /\ Sf_next into P
|
||||
if (SegmentsIntersect(sfn.Org(), sfn.Dest(), cc_f, cc_f_next, out p, true))
|
||||
@@ -327,10 +327,10 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
else
|
||||
{
|
||||
// Call Sf the constrained edge blinding f
|
||||
sf.seg = subsegMap[f.triangle.hash];
|
||||
sf.seg = subsegMap[f.tri.hash];
|
||||
|
||||
// if f_next is tagged non-blind then
|
||||
if (!f_next.triangle.infected)
|
||||
if (!f_next.tri.infected)
|
||||
{
|
||||
// Insert point Lf,f_next /\ Sf into P
|
||||
if (SegmentsIntersect(sf.Org(), sf.Dest(), cc_f, cc_f_next, out p, true))
|
||||
@@ -343,7 +343,7 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
else
|
||||
{
|
||||
// Call Sf_next the constrained edge blinding f_next
|
||||
sfn.seg = subsegMap[f_next.triangle.hash];
|
||||
sfn.seg = subsegMap[f_next.tri.hash];
|
||||
|
||||
// if Sf != Sf_next then
|
||||
if (!sf.Equal(sfn))
|
||||
@@ -370,7 +370,7 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
f_next.Copy(ref f);
|
||||
|
||||
// Call f_next the next triangle counterclockwise around x
|
||||
f_next.OnextSelf();
|
||||
f_next.Onext();
|
||||
}
|
||||
while (!f.Equal(f_init));
|
||||
|
||||
@@ -413,20 +413,20 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
f_init.Oprev(ref f_prev);
|
||||
|
||||
// Is the border to the left?
|
||||
if (f_prev.triangle.id != Triangle.EmptyID)
|
||||
if (f_prev.tri.id != Triangle.EmptyID)
|
||||
{
|
||||
// Go clockwise until we reach the border (or the initial triangle)
|
||||
while (f_prev.triangle.id != Triangle.EmptyID && !f_prev.Equal(f_init))
|
||||
while (f_prev.tri.id != Triangle.EmptyID && !f_prev.Equal(f_init))
|
||||
{
|
||||
f_prev.Copy(ref f);
|
||||
f_prev.OprevSelf();
|
||||
f_prev.Oprev();
|
||||
}
|
||||
|
||||
f.Copy(ref f_init);
|
||||
f.Onext(ref f_next);
|
||||
}
|
||||
|
||||
if (f_prev.triangle.id == Triangle.EmptyID)
|
||||
if (f_prev.tri.id == Triangle.EmptyID)
|
||||
{
|
||||
// For vertices on the domain boundaray, add the vertex. For
|
||||
// internal boundaries don't add it.
|
||||
@@ -450,11 +450,11 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
do
|
||||
{
|
||||
// Call Lffnext the line going through the circumcenters of f and f_next
|
||||
cc_f = this.points[f.triangle.id];
|
||||
cc_f = this.points[f.tri.id];
|
||||
|
||||
if (f_next.triangle.id == Triangle.EmptyID)
|
||||
if (f_next.tri.id == Triangle.EmptyID)
|
||||
{
|
||||
if (!f.triangle.infected)
|
||||
if (!f.tri.infected)
|
||||
{
|
||||
// Add last circumcenter
|
||||
vpoints.Add(cc_f);
|
||||
@@ -473,18 +473,18 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
break;
|
||||
}
|
||||
|
||||
cc_f_next = this.points[f_next.triangle.id];
|
||||
cc_f_next = this.points[f_next.tri.id];
|
||||
|
||||
// if f is tagged non-blind then
|
||||
if (!f.triangle.infected)
|
||||
if (!f.tri.infected)
|
||||
{
|
||||
// Insert the circumcenter of f into P
|
||||
vpoints.Add(cc_f);
|
||||
|
||||
if (f_next.triangle.infected)
|
||||
if (f_next.tri.infected)
|
||||
{
|
||||
// Call S_fnext the constrained edge blinding f_next
|
||||
sfn.seg = subsegMap[f_next.triangle.hash];
|
||||
sfn.seg = subsegMap[f_next.tri.hash];
|
||||
|
||||
// Insert point Lf,f_next /\ Sf_next into P
|
||||
if (SegmentsIntersect(sfn.Org(), sfn.Dest(), cc_f, cc_f_next, out p, true))
|
||||
@@ -498,13 +498,13 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
else
|
||||
{
|
||||
// Call Sf the constrained edge blinding f
|
||||
sf.seg = subsegMap[f.triangle.hash];
|
||||
sf.seg = subsegMap[f.tri.hash];
|
||||
|
||||
sorg = sf.Org();
|
||||
sdest = sf.Dest();
|
||||
|
||||
// if f_next is tagged non-blind then
|
||||
if (!f_next.triangle.infected)
|
||||
if (!f_next.tri.infected)
|
||||
{
|
||||
tdest = f.Dest();
|
||||
tapex = f.Apex();
|
||||
@@ -534,7 +534,7 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
else
|
||||
{
|
||||
// Call Sf_next the constrained edge blinding f_next
|
||||
sfn.seg = subsegMap[f_next.triangle.hash];
|
||||
sfn.seg = subsegMap[f_next.tri.hash];
|
||||
|
||||
// if Sf != Sf_next then
|
||||
if (!sf.Equal(sfn))
|
||||
@@ -577,7 +577,7 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
f_next.Copy(ref f);
|
||||
|
||||
// Call f_next the next triangle counterclockwise around x
|
||||
f_next.OnextSelf();
|
||||
f_next.Onext();
|
||||
}
|
||||
while (!f.Equal(f_init));
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
// Compue triangle circumcenters
|
||||
foreach (var item in mesh.triangles.Values)
|
||||
{
|
||||
tri.triangle = item;
|
||||
tri.tri = item;
|
||||
|
||||
pt = RobustPredicates.FindCircumcenter(tri.Org(), tri.Dest(), tri.Apex(), ref xi, ref eta);
|
||||
pt.id = item.id;
|
||||
@@ -156,26 +156,26 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
f_init.Onext(ref f_next);
|
||||
|
||||
// Check if f_init lies on the boundary of the triangulation.
|
||||
if (f_next.triangle.id == Triangle.EmptyID)
|
||||
if (f_next.tri.id == Triangle.EmptyID)
|
||||
{
|
||||
f_init.Oprev(ref f_prev);
|
||||
|
||||
if (f_prev.triangle.id != Triangle.EmptyID)
|
||||
if (f_prev.tri.id != Triangle.EmptyID)
|
||||
{
|
||||
f_init.Copy(ref f_next);
|
||||
// Move one triangle clockwise
|
||||
f_init.OprevSelf();
|
||||
f_init.Oprev();
|
||||
f_init.Copy(ref f);
|
||||
}
|
||||
}
|
||||
|
||||
// Go counterclockwise until we reach the border or the initial triangle.
|
||||
while (f_next.triangle.id != Triangle.EmptyID)
|
||||
while (f_next.tri.id != Triangle.EmptyID)
|
||||
{
|
||||
// Add circumcenter of current triangle
|
||||
vpoints.Add(points[f.triangle.id]);
|
||||
vpoints.Add(points[f.tri.id]);
|
||||
|
||||
region.AddNeighbor(f.triangle.id, regions[f.Apex().id]);
|
||||
region.AddNeighbor(f.tri.id, regions[f.Apex().id]);
|
||||
|
||||
if (f_next.Equal(f_init))
|
||||
{
|
||||
@@ -185,7 +185,7 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
}
|
||||
|
||||
f_next.Copy(ref f);
|
||||
f_next.OnextSelf();
|
||||
f_next.Onext();
|
||||
}
|
||||
|
||||
// Voronoi cell is unbounded
|
||||
@@ -197,19 +197,19 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
|
||||
// Find the boundary segment id (we use this id to number the endpoints of infinit rays).
|
||||
f.Lprev(ref f_next);
|
||||
f_next.SegPivot(ref sub);
|
||||
f_next.Pivot(ref sub);
|
||||
sid = sub.seg.hash;
|
||||
|
||||
// Last valid f lies at the boundary. Add the circumcenter.
|
||||
vpoints.Add(points[f.triangle.id]);
|
||||
region.AddNeighbor(f.triangle.id, regions[f.Apex().id]);
|
||||
vpoints.Add(points[f.tri.id]);
|
||||
region.AddNeighbor(f.tri.id, regions[f.Apex().id]);
|
||||
|
||||
// Check if the intersection with the bounding box has already been computed.
|
||||
if (!rayPoints.TryGetValue(sid, out intersection))
|
||||
{
|
||||
torg = f.Org();
|
||||
tapex = f.Apex();
|
||||
BoxRayIntersection(points[f.triangle.id], torg.y - tapex.y, tapex.x - torg.x, out intersection);
|
||||
BoxRayIntersection(points[f.tri.id], torg.y - tapex.y, tapex.x - torg.x, out intersection);
|
||||
|
||||
// Set the correct id for the vertex
|
||||
intersection.id = n + rayIndex;
|
||||
@@ -228,17 +228,17 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
f_init.Copy(ref f);
|
||||
f.Oprev(ref f_prev);
|
||||
|
||||
while (f_prev.triangle.id != Triangle.EmptyID)
|
||||
while (f_prev.tri.id != Triangle.EmptyID)
|
||||
{
|
||||
vpoints.Add(points[f_prev.triangle.id]);
|
||||
region.AddNeighbor(f_prev.triangle.id, regions[f_prev.Apex().id]);
|
||||
vpoints.Add(points[f_prev.tri.id]);
|
||||
region.AddNeighbor(f_prev.tri.id, regions[f_prev.Apex().id]);
|
||||
|
||||
f_prev.Copy(ref f);
|
||||
f_prev.OprevSelf();
|
||||
f_prev.Oprev();
|
||||
}
|
||||
|
||||
// Find the boundary segment id.
|
||||
f.SegPivot(ref sub);
|
||||
f.Pivot(ref sub);
|
||||
sid = sub.seg.hash;
|
||||
|
||||
if (!rayPoints.TryGetValue(sid, out intersection))
|
||||
@@ -247,7 +247,7 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
torg = f.Org();
|
||||
tdest = f.Dest();
|
||||
|
||||
BoxRayIntersection(points[f.triangle.id], tdest.y - torg.y, torg.x - tdest.x, out intersection);
|
||||
BoxRayIntersection(points[f.tri.id], tdest.y - torg.y, torg.x - tdest.x, out intersection);
|
||||
|
||||
// Set the correct id for the vertex
|
||||
intersection.id = n + rayIndex;
|
||||
|
||||
@@ -11,21 +11,13 @@ namespace TriangleNet.Voronoi
|
||||
public class StandardVoronoi : VoronoiBase
|
||||
{
|
||||
public StandardVoronoi(Mesh mesh)
|
||||
: this(mesh, mesh.bounds)
|
||||
{
|
||||
}
|
||||
|
||||
public StandardVoronoi(Mesh mesh, Rectangle box)
|
||||
: base(mesh, true)
|
||||
{
|
||||
// We explicitly told the base constructor to call the Generate method, so
|
||||
// at this point the basic Voronoi diagram is already created.
|
||||
PostProcess(box);
|
||||
}
|
||||
|
||||
private void PostProcess(Rectangle box)
|
||||
private void Intersect(Rectangle box)
|
||||
{
|
||||
// Compute edge intersections with bounding box.
|
||||
// TODO: compute edge intersections with bounding box.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@ namespace TriangleNet.Voronoi
|
||||
/// </summary>
|
||||
public abstract class VoronoiBase : DcelMesh
|
||||
{
|
||||
// List of infinite half-edges, i.e. half-edges that start at circumcenters of triangles
|
||||
// which lie on the domain boundary.
|
||||
protected List<HalfEdge> rays;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="VoronoiBase" /> class.
|
||||
/// </summary>
|
||||
@@ -39,18 +43,19 @@ namespace TriangleNet.Voronoi
|
||||
/// Generate the Voronoi diagram from given triangle mesh..
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="bounded"></param>
|
||||
protected void Generate(Mesh mesh)
|
||||
{
|
||||
mesh.Renumber();
|
||||
mesh.MakeVertexMap();
|
||||
|
||||
base.edges = new List<HalfEdge>();
|
||||
this.rays = new List<HalfEdge>();
|
||||
|
||||
// Allocate space for voronoi diagram
|
||||
// Allocate space for Voronoi diagram.
|
||||
var vertices = new Vertex[mesh.triangles.Count + mesh.hullsize];
|
||||
var faces = new Face[mesh.vertices.Count];
|
||||
|
||||
// Compute triangles circumcenters and setup bounding box
|
||||
// Compute triangles circumcenters.
|
||||
var map = ComputeVertices(mesh, vertices);
|
||||
|
||||
// Create all Voronoi faces.
|
||||
@@ -87,7 +92,7 @@ namespace TriangleNet.Voronoi
|
||||
foreach (var t in mesh.triangles.Values)
|
||||
{
|
||||
id = t.id;
|
||||
tri.triangle = t;
|
||||
tri.tri = t;
|
||||
|
||||
pt = RobustPredicates.FindCircumcenter(tri.Org(), tri.Dest(), tri.Apex(), ref xi, ref eta);
|
||||
|
||||
@@ -104,6 +109,9 @@ namespace TriangleNet.Voronoi
|
||||
/// <summary>
|
||||
/// Compute the edges of the Voronoi diagram.
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="vertices"></param>
|
||||
/// <param name="faces"></param>
|
||||
/// <param name="map">Empty vertex map.</param>
|
||||
protected void ComputeEdges(Mesh mesh, Vertex[] vertices, Face[] faces, List<HalfEdge>[] map)
|
||||
{
|
||||
@@ -132,14 +140,14 @@ namespace TriangleNet.Voronoi
|
||||
{
|
||||
id = t.id;
|
||||
|
||||
tri.triangle = t;
|
||||
tri.tri = t;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
tri.orient = i;
|
||||
tri.Sym(ref neighbor);
|
||||
|
||||
nid = neighbor.triangle.id;
|
||||
nid = neighbor.tri.id;
|
||||
|
||||
if (id < nid || nid < 0)
|
||||
{
|
||||
@@ -156,7 +164,7 @@ namespace TriangleNet.Voronoi
|
||||
// in the Voronoi diagram, i.e. two half-edges will be created.
|
||||
if (nid < 0)
|
||||
{
|
||||
// Undounded edge, direction perpendicular to the boundary edge,
|
||||
// Unbounded edge, direction perpendicular to the boundary edge,
|
||||
// pointing outwards.
|
||||
px = dest.y - org.y;
|
||||
py = org.x - dest.x;
|
||||
@@ -169,31 +177,31 @@ namespace TriangleNet.Voronoi
|
||||
edge = new HalfEdge(end, face);
|
||||
twin = new HalfEdge(vertex, neighborFace);
|
||||
|
||||
end.leaving = edge;
|
||||
|
||||
// Make (face.edge) always point to an edge that starts at an infinite
|
||||
// vertex. This will allow traversing of unbounded faces.
|
||||
face.edge = edge;
|
||||
face.bounded = false;
|
||||
|
||||
map[id].Add(twin);
|
||||
|
||||
rays.Add(twin);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create half-edges.
|
||||
edge = new HalfEdge(vertices[nid], face);
|
||||
twin = new HalfEdge(vertex, neighborFace);
|
||||
end = vertices[nid];
|
||||
|
||||
// Set leaving edges.
|
||||
vertices[nid].leaving = edge;
|
||||
vertex.leaving = twin;
|
||||
// Create half-edges.
|
||||
edge = new HalfEdge(end, face);
|
||||
twin = new HalfEdge(vertex, neighborFace);
|
||||
|
||||
// Add to vertex map.
|
||||
map[nid].Add(edge);
|
||||
map[id].Add(twin);
|
||||
}
|
||||
|
||||
// Setup twin edges.
|
||||
vertex.leaving = twin;
|
||||
end.leaving = edge;
|
||||
|
||||
edge.twin = twin;
|
||||
twin.twin = edge;
|
||||
|
||||
@@ -211,11 +219,11 @@ namespace TriangleNet.Voronoi
|
||||
/// Connect all edges of the Voronoi diagram.
|
||||
/// </summary>
|
||||
/// <param name="map">Maps all vertices to a list of leaving edges.</param>
|
||||
protected void ConnectEdges(List<HalfEdge>[] map)
|
||||
protected virtual void ConnectEdges(List<HalfEdge>[] map)
|
||||
{
|
||||
int length = map.Length;
|
||||
|
||||
// For each halfe-edge, find its successor in the connected face.
|
||||
// For each half-edge, find its successor in the connected face.
|
||||
foreach (var edge in this.edges)
|
||||
{
|
||||
var face = edge.face.generator.id;
|
||||
@@ -223,6 +231,8 @@ namespace TriangleNet.Voronoi
|
||||
// The id of the dest vertex of current edge.
|
||||
int id = edge.twin.origin.id;
|
||||
|
||||
// The edge origin can also be an infinite vertex. Sort them out
|
||||
// by checking the id.
|
||||
if (id < length)
|
||||
{
|
||||
// Look for the edge that is connected to the current face. Each
|
||||
@@ -238,5 +248,27 @@ namespace TriangleNet.Voronoi
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override IEnumerable<IEdge> EnumerateEdges()
|
||||
{
|
||||
var edges = new List<IEdge>(this.edges.Count / 2);
|
||||
|
||||
foreach (var edge in this.edges)
|
||||
{
|
||||
var twin = edge.twin;
|
||||
|
||||
// Report edge only once.
|
||||
if (twin == null)
|
||||
{
|
||||
edges.Add(new Edge(edge.origin.id, edge.next.origin.id));
|
||||
}
|
||||
else if (edge.id < twin.id)
|
||||
{
|
||||
edges.Add(new Edge(edge.origin.id, twin.origin.id));
|
||||
}
|
||||
}
|
||||
|
||||
return edges;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user