diff --git a/Triangle.NET/TestApp/FormTopology.cs b/Triangle.NET/TestApp/FormTopology.cs index ce71b0f..8e235c2 100644 --- a/Triangle.NET/TestApp/FormTopology.cs +++ b/Triangle.NET/TestApp/FormTopology.cs @@ -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 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); } } } diff --git a/Triangle.NET/TestApp/Mesh Explorer.csproj b/Triangle.NET/TestApp/Mesh Explorer.csproj index aad11c5..d8d1ad3 100644 --- a/Triangle.NET/TestApp/Mesh Explorer.csproj +++ b/Triangle.NET/TestApp/Mesh Explorer.csproj @@ -120,8 +120,6 @@ - - UserControl diff --git a/Triangle.NET/TestApp/Topology/OrientedTriangle.cs b/Triangle.NET/TestApp/Topology/OrientedTriangle.cs deleted file mode 100644 index 22926c4..0000000 --- a/Triangle.NET/TestApp/Topology/OrientedTriangle.cs +++ /dev/null @@ -1,158 +0,0 @@ - -namespace MeshExplorer.Topology -{ - using TriangleNet.Topology; - using TriangleNet.Geometry; - - public class OrientedTriangle - { - /// - /// - /// - public ITriangle Triangle { get; set; } - - /// - /// Ranges from 0 to 2. - /// - 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 }; - - /// - /// Find the abutting triangle; same edge. [sym(abc) -> ba*] - /// - public void Sym() - { - if (this.Triangle == null) - { - return; - } - - var org = this.Org(); - Triangle = Triangle.GetNeighbor(Orientation); - Orientation = GetOrientation(Triangle, org.ID); - } - - /// - /// Find the next edge (counterclockwise) of a triangle. [lnext(abc) -> bca] - /// - public void Lnext() - { - Orientation = plus1Mod3[Orientation]; - } - - /// - /// Find the previous edge (clockwise) of a triangle. [lprev(abc) -> cab] - /// - public void Lprev() - { - Orientation = minus1Mod3[Orientation]; - } - - /// - /// Find the next edge counterclockwise with the same origin. [onext(abc) -> ac*] - /// - public void Onext() - { - Lprev(); - Sym(); - } - - /// - /// Find the next edge clockwise with the same origin. [oprev(abc) -> a*b] - /// - public void Oprev() - { - Sym(); - Lnext(); - } - - /// - /// Find the next edge counterclockwise with the same destination. [dnext(abc) -> *ba] - /// - public void Dnext() - { - Sym(); - Lprev(); - } - - /// - /// Find the next edge clockwise with the same destination. [dprev(abc) -> cb*] - /// - public void Dprev() - { - Lnext(); - Sym(); - } - - /// - /// Find the next edge (counterclockwise) of the adjacent triangle. [rnext(abc) -> *a*] - /// - public void Rnext() - { - Sym(); - Lnext(); - Sym(); - } - - /// - /// Find the previous edge (clockwise) of the adjacent triangle. [rprev(abc) -> b**] - /// - public void Rprev() - { - Sym(); - Lprev(); - Sym(); - } - - /// - /// Origin [org(abc) -> a] - /// - public Vertex Org() - { - return Triangle.GetVertex(plus1Mod3[Orientation]); - } - - /// - /// Destination [dest(abc) -> b] - /// - public Vertex Dest() - { - return Triangle.GetVertex(minus1Mod3[Orientation]); - } - - /// - /// Apex [apex(abc) -> c] - /// - 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; - } - } -} diff --git a/Triangle.NET/TestApp/Topology/RectanglePolygon.cs b/Triangle.NET/TestApp/Topology/RectanglePolygon.cs deleted file mode 100644 index 80def75..0000000 --- a/Triangle.NET/TestApp/Topology/RectanglePolygon.cs +++ /dev/null @@ -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; - } - } -} diff --git a/Triangle.NET/TestApp/Topology/TopologyControlView.cs b/Triangle.NET/TestApp/Topology/TopologyControlView.cs index 377b7e8..693865b 100644 --- a/Triangle.NET/TestApp/Topology/TopologyControlView.cs +++ b/Triangle.NET/TestApp/Topology/TopologyControlView.cs @@ -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 { diff --git a/Triangle.NET/TestApp/Topology/TopologyRenderControl.cs b/Triangle.NET/TestApp/Topology/TopologyRenderControl.cs index d070716..13dc147 100644 --- a/Triangle.NET/TestApp/Topology/TopologyRenderControl.cs +++ b/Triangle.NET/TestApp/Topology/TopologyRenderControl.cs @@ -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(); } diff --git a/Triangle.NET/TestApp/Topology/TopologyRenderer.cs b/Triangle.NET/TestApp/Topology/TopologyRenderer.cs index 0f0be5e..38ce710 100644 --- a/Triangle.NET/TestApp/Topology/TopologyRenderer.cs +++ b/Triangle.NET/TestApp/Topology/TopologyRenderer.cs @@ -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; /// /// Initializes a new instance of the 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]); diff --git a/Triangle.NET/Triangle/IO/DebugWriter.cs b/Triangle.NET/Triangle/IO/DebugWriter.cs index e7c95fb..c3fc868 100644 --- a/Triangle.NET/Triangle/IO/DebugWriter.cs +++ b/Triangle.NET/Triangle/IO/DebugWriter.cs @@ -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); diff --git a/Triangle.NET/Triangle/IO/TriangleWriter.cs b/Triangle.NET/Triangle/IO/TriangleWriter.cs index 2b21f93..2beaa48 100644 --- a/Triangle.NET/Triangle/IO/TriangleWriter.cs +++ b/Triangle.NET/Triangle/IO/TriangleWriter.cs @@ -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(); diff --git a/Triangle.NET/Triangle/Mesh.cs b/Triangle.NET/Triangle/Mesh.cs index fd41cff..19684ab 100644 --- a/Triangle.NET/Triangle/Mesh.cs +++ b/Triangle.NET/Triangle/Mesh.cs @@ -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); } /// @@ -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(); diff --git a/Triangle.NET/Triangle/MeshValidator.cs b/Triangle.NET/Triangle/MeshValidator.cs index 1cb0999..e990a9f 100644 --- a/Triangle.NET/Triangle/MeshValidator.cs +++ b/Triangle.NET/Triangle/MeshValidator.cs @@ -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++; diff --git a/Triangle.NET/Triangle/Meshing/Algorithm/Dwyer.cs b/Triangle.NET/Triangle/Meshing/Algorithm/Dwyer.cs index d34bc21..7338901 100644 --- a/Triangle.NET/Triangle/Meshing/Algorithm/Dwyer.cs +++ b/Triangle.NET/Triangle/Meshing/Algorithm/Dwyer.cs @@ -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; diff --git a/Triangle.NET/Triangle/Meshing/Algorithm/Incremental.cs b/Triangle.NET/Triangle/Meshing/Algorithm/Incremental.cs index 26777e4..4b6cf6f 100644 --- a/Triangle.NET/Triangle/Meshing/Algorithm/Incremental.cs +++ b/Triangle.NET/Triangle/Meshing/Algorithm/Incremental.cs @@ -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; } diff --git a/Triangle.NET/Triangle/Meshing/Algorithm/SweepLine.cs b/Triangle.NET/Triangle/Meshing/Algorithm/SweepLine.cs index 4440ce8..b8b3fe7 100644 --- a/Triangle.NET/Triangle/Meshing/Algorithm/SweepLine.cs +++ b/Triangle.NET/Triangle/Meshing/Algorithm/SweepLine.cs @@ -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; diff --git a/Triangle.NET/Triangle/Meshing/ConstraintMesher.cs b/Triangle.NET/Triangle/Meshing/ConstraintMesher.cs index f039ae8..5a3f1b9 100644 --- a/Triangle.NET/Triangle/Meshing/ConstraintMesher.cs +++ b/Triangle.NET/Triangle/Meshing/ConstraintMesher.cs @@ -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); diff --git a/Triangle.NET/Triangle/Meshing/Converter.cs b/Triangle.NET/Triangle/Meshing/Converter.cs index 8fda7b6..6e286ef 100644 --- a/Triangle.NET/Triangle/Meshing/Converter.cs +++ b/Triangle.NET/Triangle/Meshing/Converter.cs @@ -18,7 +18,7 @@ namespace TriangleNet.Meshing using TVertex = TriangleNet.Geometry.Vertex; /// - /// The Converter class provides methods for mesh reconstruction. + /// The Converter class provides methods for mesh reconstruction and conversion. /// 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(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) { diff --git a/Triangle.NET/Triangle/Meshing/Data/BadTriangle.cs b/Triangle.NET/Triangle/Meshing/Data/BadTriangle.cs index 544742e..40cc398 100644 --- a/Triangle.NET/Triangle/Meshing/Data/BadTriangle.cs +++ b/Triangle.NET/Triangle/Meshing/Data/BadTriangle.cs @@ -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); } } } diff --git a/Triangle.NET/Triangle/Meshing/Iterators/EdgeIterator.cs b/Triangle.NET/Triangle/Meshing/Iterators/EdgeIterator.cs index 5e05a15..b8b7c09 100644 --- a/Triangle.NET/Triangle/Meshing/Iterators/EdgeIterator.cs +++ b/Triangle.NET/Triangle/Meshing/Iterators/EdgeIterator.cs @@ -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); diff --git a/Triangle.NET/Triangle/Meshing/Iterators/RegionIterator.cs b/Triangle.NET/Triangle/Meshing/Iterators/RegionIterator.cs index 60b07ca..e1f1cb1 100644 --- a/Triangle.NET/Triangle/Meshing/Iterators/RegionIterator.cs +++ b/Triangle.NET/Triangle/Meshing/Iterators/RegionIterator.cs @@ -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 diff --git a/Triangle.NET/Triangle/Meshing/QualityMesher.cs b/Triangle.NET/Triangle/Meshing/QualityMesher.cs index 1ce2ecf..6b4984c 100644 --- a/Triangle.NET/Triangle/Meshing/QualityMesher.cs +++ b/Triangle.NET/Triangle/Meshing/QualityMesher.cs @@ -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, diff --git a/Triangle.NET/Triangle/NewLocation.cs b/Triangle.NET/Triangle/NewLocation.cs index fb71f49..0315424 100644 --- a/Triangle.NET/Triangle/NewLocation.cs +++ b/Triangle.NET/Triangle/NewLocation.cs @@ -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); } diff --git a/Triangle.NET/Triangle/Smoothing/SimpleSmoother.cs b/Triangle.NET/Triangle/Smoothing/SimpleSmoother.cs index bab21d0..09a4c6b 100644 --- a/Triangle.NET/Triangle/Smoothing/SimpleSmoother.cs +++ b/Triangle.NET/Triangle/Smoothing/SimpleSmoother.cs @@ -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; /// /// Simple mesh smoother implementation. @@ -56,48 +56,49 @@ namespace TriangleNet.Smoothing smoothedMesh.CopyTo((Mesh)mesh); } - /// - /// Smooth all free nodes. - /// 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)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; + } } } /// /// Calculate the centroid of a polygon. /// - /// Points of the polygon. - /// Centroid x coordinate. - /// Centroid y coordinate. - /// - /// 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 - /// - private void Centroid(List 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); diff --git a/Triangle.NET/Triangle/Tools/AdjacencyMatrix.cs b/Triangle.NET/Triangle/Tools/AdjacencyMatrix.cs index 77e23a4..90b5a19 100644 --- a/Triangle.NET/Triangle/Tools/AdjacencyMatrix.cs +++ b/Triangle.NET/Triangle/Tools/AdjacencyMatrix.cs @@ -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) { diff --git a/Triangle.NET/Triangle/Tools/IntersectionHelper.cs b/Triangle.NET/Triangle/Tools/IntersectionHelper.cs new file mode 100644 index 0000000..42e6ffd --- /dev/null +++ b/Triangle.NET/Triangle/Tools/IntersectionHelper.cs @@ -0,0 +1,196 @@ +// ----------------------------------------------------------------------- +// +// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/ +// +// ----------------------------------------------------------------------- + +namespace TriangleNet.Tools +{ + using TriangleNet.Geometry; + + using Vertex = TriangleNet.Topology.DCEL.Vertex; + + public static class IntersectionHelper + { + /// + /// Compute intersection of two segments. + /// + /// Segment 1 start point. + /// Segment 1 end point. + /// Segment 2 start point. + /// Segment 2 end point. + /// The intersection point. + /// + /// 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. + /// + 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; + } + + /// + /// Intersect segment with a bounding box. + /// + /// The clip rectangle. + /// Segment endpoint. + /// Segment endpoint. + /// The new location of p0 (DCEL vertex). + /// The new location of p1 (DCEL vertex). + /// Returns true, if segment is clipped. + /// + /// Based on Liang-Barsky function by Daniel White: + /// http://www.skytopia.com/project/articles/compsci/clipping.html + /// + 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 + } + + /// + /// Intersect a ray with a bounding box. + /// + /// The clip rectangle. + /// The ray startpoint (inside the box). + /// Any point in ray direction (NOT the direction vector). + /// The intersection point (DCEL vertex). + /// Returns false, if startpoint is outside the box. + 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; + } + } +} diff --git a/Triangle.NET/Triangle/Tools/QuadTree.cs b/Triangle.NET/Triangle/Tools/QuadTree.cs index da29482..8caefbb 100644 --- a/Triangle.NET/Triangle/Tools/QuadTree.cs +++ b/Triangle.NET/Triangle/Tools/QuadTree.cs @@ -12,7 +12,7 @@ namespace TriangleNet.Tools using TriangleNet.Geometry; /// - /// A Quadtree implementation optimised for triangles. + /// A Quadtree implementation optimized for triangles. /// 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; diff --git a/Triangle.NET/Triangle/Tools/Statistic.cs b/Triangle.NET/Triangle/Tools/Statistic.cs index 5ca43ce..c48dd9d 100644 --- a/Triangle.NET/Triangle/Tools/Statistic.cs +++ b/Triangle.NET/Triangle/Tools/Statistic.cs @@ -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(); diff --git a/Triangle.NET/Triangle/Topology/DCEL/DcelMesh.cs b/Triangle.NET/Triangle/Topology/DCEL/DcelMesh.cs index e5d9d3a..cf301db 100644 --- a/Triangle.NET/Triangle/Topology/DCEL/DcelMesh.cs +++ b/Triangle.NET/Triangle/Topology/DCEL/DcelMesh.cs @@ -70,71 +70,141 @@ namespace TriangleNet.Topology.DCEL } /// - /// Check if the DCEL ist consistend. + /// Check if the DCEL is consistend. /// /// If true, faces are assumed to be closed (i.e. all edges must have /// a valid next pointer). + /// Maximum edge count of faces (default = 0 means skip check). /// - 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; } /// @@ -144,7 +214,7 @@ namespace TriangleNet.Topology.DCEL /// /// This method assumes that all faces are closed (i.e. no edge.next pointers are null). /// - internal void ResolveBoundaryEdges() + public void ResolveBoundaryEdges() { // Maps vertices to leaving boundary edge. var map = new Dictionary(); diff --git a/Triangle.NET/Triangle/Topology/Osub.cs b/Triangle.NET/Triangle/Topology/Osub.cs index c06c681..640b5aa 100644 --- a/Triangle.NET/Triangle/Topology/Osub.cs +++ b/Triangle.NET/Triangle/Topology/Osub.cs @@ -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. /// - 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 /// /// Reverse the orientation of a subsegment. [sym(ab) -> ba] /// - /// ssym() toggles the orientation of a subsegment. - /// - 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; } /// /// Reverse the orientation of a subsegment. [sym(ab) -> ba] /// - public void SymSelf() + public void Sym() { orient = 1 - orient; } @@ -59,40 +62,33 @@ namespace TriangleNet.Topology /// spivot() finds the other subsegment (from the same segment) /// that shares the same origin. /// - public void Pivot(ref Osub o2) + public void Pivot(ref Osub os) { - o2 = seg.subsegs[orient]; - //sdecode(sptr, o2); + os = seg.subsegs[orient]; } /// - /// Find adjoining subsegment with the same origin. [pivot(ab) -> a*] + /// Finds a triangle abutting a subsegment. /// - public void PivotSelf() + internal void Pivot(ref Otri ot) { - this = seg.subsegs[orient]; - //sdecode(sptr, osub); + ot = seg.triangles[orient]; } /// /// Find next subsegment in sequence. [next(ab) -> b*] /// - /// snext() finds the next subsegment (from the same segment) in - /// sequence; one whose origin is the input subsegment's destination. - /// - 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]; } /// /// Find next subsegment in sequence. [next(ab) -> b*] /// - public void NextSelf() + public void Next() { this = seg.subsegs[1 - orient]; - //sdecode(sptr, osub); } /// @@ -111,26 +107,31 @@ namespace TriangleNet.Topology return seg.vertices[1 - orient]; } + + #endregion + + #region Osub primitives (internal) + /// /// Set the origin or destination of a subsegment. /// - public void SetOrg(Vertex ptr) + internal void SetOrg(Vertex vertex) { - seg.vertices[orient] = ptr; + seg.vertices[orient] = vertex; } /// /// Set destination of a subsegment. /// - public void SetDest(Vertex ptr) + internal void SetDest(Vertex vertex) { - seg.vertices[1 - orient] = ptr; + seg.vertices[1 - orient] = vertex; } /// /// Get the origin of the segment that includes the subsegment. /// - public Vertex SegOrg() + internal Vertex SegOrg() { return seg.vertices[2 + orient]; } @@ -138,7 +139,7 @@ namespace TriangleNet.Topology /// /// Get the destination of the segment that includes the subsegment. /// - public Vertex SegDest() + internal Vertex SegDest() { return seg.vertices[3 - orient]; } @@ -146,17 +147,27 @@ namespace TriangleNet.Topology /// /// Set the origin of the segment that includes the subsegment. /// - public void SetSegOrg(Vertex ptr) + internal void SetSegOrg(Vertex vertex) { - seg.vertices[2 + orient] = ptr; + seg.vertices[2 + orient] = vertex; } /// /// Set the destination of the segment that includes the subsegment. /// - public void SetSegDest(Vertex ptr) + internal void SetSegDest(Vertex vertex) { - seg.vertices[3 - orient] = ptr; + seg.vertices[3 - orient] = vertex; + } + + /* Unused primitives. + + /// + /// Find adjoining subsegment with the same origin. [pivot(ab) -> a*] + /// + public void PivotSelf() + { + this = seg.subsegs[orient]; } /// @@ -177,25 +188,6 @@ namespace TriangleNet.Topology seg.boundary = value; } - /// - /// Bond two subsegments together. [bond(abc, ba)] - /// - public void Bond(ref Osub o2) - { - seg.subsegs[orient] = o2; - o2.seg.subsegs[o2.orient] = this; - } - - /// - /// Dissolve a subsegment bond (from one side). - /// - /// Note that the other subsegment will still think it's - /// connected to this subsegment. - public void Dissolve() - { - seg.subsegs[orient].seg = Segment.Empty; - } - /// /// Copy a subsegment. /// @@ -205,18 +197,47 @@ namespace TriangleNet.Topology o2.orient = orient; } + //*/ + + /// + /// Bond two subsegments together. [bond(abc, ba)] + /// + internal void Bond(ref Osub os) + { + seg.subsegs[orient] = os; + os.seg.subsegs[os.orient] = this; + } + + /// + /// Dissolve a subsegment bond (from one side). + /// + /// Note that the other subsegment will still think it's + /// connected to this subsegment. + internal void Dissolve() + { + seg.subsegs[orient].seg = Segment.Empty; + } + /// /// Test for equality of subsegments. /// - public bool Equal(Osub o2) + internal bool Equal(Osub os) { - return ((seg == o2.seg) && (orient == o2.orient)); + return ((seg == os.seg) && (orient == os.orient)); + } + + /// + /// Dissolve a bond (from the subsegment side). + /// + internal void TriDissolve() + { + seg.triangles[orient].tri = Triangle.Empty; } /// /// Check a subsegment's deallocation. /// - 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 /// /// Set a subsegment's deallocation. /// - public static void Kill(Segment sub) + internal static void Kill(Segment sub) { sub.subsegs[0].seg = null; sub.subsegs[1].seg = null; } - /// - /// Finds a triangle abutting a subsegment. - /// - public void TriPivot(ref Otri ot) - { - ot = seg.triangles[orient]; - //decode(ptr, otri) - } - - /// - /// Dissolve a bond (from the subsegment side). - /// - public void TriDissolve() - { - seg.triangles[orient].triangle = Triangle.Empty; - } - #endregion } } diff --git a/Triangle.NET/Triangle/Topology/Otri.cs b/Triangle.NET/Triangle/Topology/Otri.cs index 7e73a36..6a193b0 100644 --- a/Triangle.NET/Triangle/Topology/Otri.cs +++ b/Triangle.NET/Triangle/Topology/Otri.cs @@ -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. /// - 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.) /// /// Find the abutting triangle; same edge. [sym(abc) -> ba*] /// - /// /// Note that the edge direction is necessarily reversed, because the handle specified /// by an oriented triangle is directed counterclockwise around the triangle. /// - 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; } /// /// Find the abutting triangle; same edge. [sym(abc) -> ba*] /// - 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. /// /// Find the next edge (counterclockwise) of a triangle. [lnext(abc) -> bca] /// - 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]; } /// /// Find the next edge (counterclockwise) of a triangle. [lnext(abc) -> bca] /// - public void LnextSelf() + public void Lnext() { orient = plus1Mod3[orient]; } @@ -92,16 +116,16 @@ namespace TriangleNet.Topology /// /// Find the previous edge (clockwise) of a triangle. [lprev(abc) -> cab] /// - 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]; } /// /// Find the previous edge (clockwise) of a triangle. [lprev(abc) -> cab] /// - public void LprevSelf() + public void Lprev() { orient = minus1Mod3[orient]; } @@ -109,62 +133,54 @@ namespace TriangleNet.Topology /// /// Find the next edge counterclockwise with the same origin. [onext(abc) -> ac*] /// - /// 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. - /// - 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; } /// /// Find the next edge counterclockwise with the same origin. [onext(abc) -> ac*] /// - 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; } /// /// Find the next edge clockwise with the same origin. [oprev(abc) -> a*b] /// - /// 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. - /// - 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]; } /// /// Find the next edge clockwise with the same origin. [oprev(abc) -> a*b] /// - 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 /// /// Find the next edge counterclockwise with the same destination. [dnext(abc) -> *ba] /// - /// 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. - /// - 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]; } /// /// Find the next edge counterclockwise with the same destination. [dnext(abc) -> *ba] /// - 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 /// /// Find the next edge clockwise with the same destination. [dprev(abc) -> cb*] /// - /// 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. - /// - 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; } /// /// Find the next edge clockwise with the same destination. [dprev(abc) -> cb*] /// - 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; } /// /// Find the next edge (counterclockwise) of the adjacent triangle. [rnext(abc) -> *a*] /// - /// rnext() moves one edge counterclockwise about the adjacent - /// triangle. (It's best understood by reading Guibas and Stolfi. It - /// involves changing triangles twice.) - /// - 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; } /// /// Find the next edge (counterclockwise) of the adjacent triangle. [rnext(abc) -> *a*] /// - 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; } /// /// Find the previous edge (clockwise) of the adjacent triangle. [rprev(abc) -> b**] /// - /// rprev() moves one edge clockwise about the adjacent triangle. - /// (It's best understood by reading Guibas and Stolfi. It involves - /// changing triangles twice.) - /// - 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; } /// /// Find the previous edge (clockwise) of the adjacent triangle. [rprev(abc) -> b**] /// - 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; } /// @@ -321,7 +321,7 @@ namespace TriangleNet.Topology /// public Vertex Org() { - return triangle.vertices[plus1Mod3[orient]]; + return tri.vertices[plus1Mod3[orient]]; } /// @@ -329,7 +329,7 @@ namespace TriangleNet.Topology /// public Vertex Dest() { - return triangle.vertices[minus1Mod3[orient]]; + return tri.vertices[minus1Mod3[orient]]; } /// @@ -337,46 +337,56 @@ namespace TriangleNet.Topology /// public Vertex Apex() { - return triangle.vertices[orient]; + return tri.vertices[orient]; } + /// + /// Copy an oriented triangle. + /// + public void Copy(ref Otri ot) + { + ot.tri = tri; + ot.orient = orient; + } + + #endregion + + #region Otri primitives (internal) + /// /// Set Origin /// - public void SetOrg(Vertex ptr) + internal void SetOrg(Vertex v) { - triangle.vertices[plus1Mod3[orient]] = ptr; + tri.vertices[plus1Mod3[orient]] = v; } /// /// Set Destination /// - public void SetDest(Vertex ptr) + internal void SetDest(Vertex v) { - triangle.vertices[minus1Mod3[orient]] = ptr; + tri.vertices[minus1Mod3[orient]] = v; } /// /// Set Apex /// - public void SetApex(Vertex ptr) + internal void SetApex(Vertex v) { - triangle.vertices[orient] = ptr; + tri.vertices[orient] = v; } /// /// Bond two triangles together at the resepective handles. [bond(abc, bad)] /// - 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; } /// @@ -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. /// - public void Dissolve() + internal void Dissolve() { - triangle.neighbors[orient].triangle = Triangle.Empty; - triangle.neighbors[orient].orient = 0; - } - - /// - /// Copy an oriented triangle. - /// - public void Copy(ref Otri o2) - { - o2.triangle = triangle; - o2.orient = orient; + tri.neighbors[orient].tri = Triangle.Empty; + tri.neighbors[orient].orient = 0; } /// /// Test for equality of oriented triangles. /// - public bool Equal(Otri o2) + internal bool Equal(Otri ot) { - return ((triangle == o2.triangle) && (orient == o2.orient)); + return ((tri == ot.tri) && (orient == ot.orient)); } /// /// Infect a triangle with the virus. /// - public void Infect() + internal void Infect() { - triangle.infected = true; + tri.infected = true; } /// /// Cure a triangle from the virus. /// - public void Uninfect() + internal void Uninfect() { - triangle.infected = false; + tri.infected = false; } /// /// Test a triangle for viral infection. /// - public bool IsInfected() + internal bool IsInfected() { - return triangle.infected; - } - - /// - /// Check a triangle's deallocation. - /// - public static bool IsDead(Triangle tria) - { - return tria.neighbors[0].triangle == null; - } - - /// - /// Set a triangle's deallocation. - /// - public static void Kill(Triangle tria) - { - tria.neighbors[0].triangle = null; - tria.neighbors[2].triangle = null; + return tri.infected; } /// /// Finds a subsegment abutting a triangle. /// - public void SegPivot(ref Osub os) + internal void Pivot(ref Osub os) { - os = triangle.subsegs[orient]; - //sdecode(sptr, osub) + os = tri.subsegs[orient]; } /// /// Bond a triangle to a subsegment. /// - 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; } /// /// Dissolve a bond (from the triangle side). /// - public void SegDissolve() + internal void SegDissolve() { - triangle.subsegs[orient].seg = Segment.Empty; + tri.subsegs[orient].seg = Segment.Empty; + } + + /// + /// Check a triangle's deallocation. + /// + internal static bool IsDead(Triangle tria) + { + return tria.neighbors[0].tri == null; + } + + /// + /// Set a triangle's deallocation. + /// + internal static void Kill(Triangle tri) + { + tri.neighbors[0].tri = null; + tri.neighbors[2].tri = null; } #endregion diff --git a/Triangle.NET/Triangle/Topology/Segment.cs b/Triangle.NET/Triangle/Topology/Segment.cs index 5df1cce..a7afdea 100644 --- a/Triangle.NET/Triangle/Topology/Segment.cs +++ b/Triangle.NET/Triangle/Topology/Segment.cs @@ -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 /// 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() diff --git a/Triangle.NET/Triangle/Topology/Triangle.cs b/Triangle.NET/Triangle/Topology/Triangle.cs index 30379a4..4bcee8f 100644 --- a/Triangle.NET/Triangle/Topology/Triangle.cs +++ b/Triangle.NET/Triangle/Topology/Triangle.cs @@ -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; + /// + /// Initializes a new instance of the class. + /// 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; } } - /// - /// Gets the specified corners vertex. - /// - public Vertex GetVertex(int index) - { - return this.vertices[index]; // TODO: Check range? - } - /// /// Gets the third corners vertex id. /// @@ -146,6 +141,14 @@ namespace TriangleNet.Topology get { return this.vertices[2] == null ? -1 : this.vertices[2].id; } } + /// + /// Gets the specified corners vertex. + /// + 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 /// public int N0 { - get { return this.neighbors[0].triangle.id; } + get { return this.neighbors[0].tri.id; } } /// @@ -164,7 +167,7 @@ namespace TriangleNet.Topology /// public int N1 { - get { return this.neighbors[1].triangle.id; } + get { return this.neighbors[1].tri.id; } } /// @@ -172,7 +175,7 @@ namespace TriangleNet.Topology /// public int N2 { - get { return this.neighbors[2].triangle.id; } + get { return this.neighbors[2].tri.id; } } /// @@ -182,7 +185,7 @@ namespace TriangleNet.Topology /// The neigbbor opposite of vertex with given index. 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; } /// diff --git a/Triangle.NET/Triangle/Triangle.csproj b/Triangle.NET/Triangle/Triangle.csproj index 22f3c46..9485261 100644 --- a/Triangle.NET/Triangle/Triangle.csproj +++ b/Triangle.NET/Triangle/Triangle.csproj @@ -59,6 +59,7 @@ + diff --git a/Triangle.NET/Triangle/TriangleLocator.cs b/Triangle.NET/Triangle/TriangleLocator.cs index 3ef6854..1c7535c 100644 --- a/Triangle.NET/Triangle/TriangleLocator.cs +++ b/Triangle.NET/Triangle/TriangleLocator.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. } /// @@ -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) { diff --git a/Triangle.NET/Triangle/Voronoi/BoundedVoronoi.cs b/Triangle.NET/Triangle/Voronoi/BoundedVoronoi.cs index 02aa4ee..2700b4f 100644 --- a/Triangle.NET/Triangle/Voronoi/BoundedVoronoi.cs +++ b/Triangle.NET/Triangle/Voronoi/BoundedVoronoi.cs @@ -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 /// private void PostProcess() { - var infEdges = new List(); - - // 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 } /// - /// Case 1: edge origin lies outside the domain. + /// Case 2: edge origin lies outside the domain. /// 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; } //*/ - - /// - /// Compute intersection of two segments. - /// - /// Segment 1 start point. - /// Segment 1 end point. - /// Segment 2 start point. - /// Segment 2 end point. - /// The intersection point. - /// - /// 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. - /// - 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 EnumerateEdges() - { - var edges = new List(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; - } } } diff --git a/Triangle.NET/Triangle/Voronoi/Legacy/BoundedVoronoiLegacy.cs b/Triangle.NET/Triangle/Voronoi/Legacy/BoundedVoronoiLegacy.cs index 7eccbbc..7aa4a4f 100644 --- a/Triangle.NET/Triangle/Voronoi/Legacy/BoundedVoronoiLegacy.cs +++ b/Triangle.NET/Triangle/Voronoi/Legacy/BoundedVoronoiLegacy.cs @@ -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)); diff --git a/Triangle.NET/Triangle/Voronoi/Legacy/SimpleVoronoi.cs b/Triangle.NET/Triangle/Voronoi/Legacy/SimpleVoronoi.cs index b289f88..50f5cf0 100644 --- a/Triangle.NET/Triangle/Voronoi/Legacy/SimpleVoronoi.cs +++ b/Triangle.NET/Triangle/Voronoi/Legacy/SimpleVoronoi.cs @@ -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; diff --git a/Triangle.NET/Triangle/Voronoi/StandardVoronoi.cs b/Triangle.NET/Triangle/Voronoi/StandardVoronoi.cs index b35832a..0270e2a 100644 --- a/Triangle.NET/Triangle/Voronoi/StandardVoronoi.cs +++ b/Triangle.NET/Triangle/Voronoi/StandardVoronoi.cs @@ -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. } } } diff --git a/Triangle.NET/Triangle/Voronoi/VoronoiBase.cs b/Triangle.NET/Triangle/Voronoi/VoronoiBase.cs index b21fb93..0741d4f 100644 --- a/Triangle.NET/Triangle/Voronoi/VoronoiBase.cs +++ b/Triangle.NET/Triangle/Voronoi/VoronoiBase.cs @@ -20,6 +20,10 @@ namespace TriangleNet.Voronoi /// 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 rays; + /// /// Initializes a new instance of the class. /// @@ -39,18 +43,19 @@ namespace TriangleNet.Voronoi /// Generate the Voronoi diagram from given triangle mesh.. /// /// + /// protected void Generate(Mesh mesh) { mesh.Renumber(); - mesh.MakeVertexMap(); base.edges = new List(); + this.rays = new List(); - // 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 /// /// Compute the edges of the Voronoi diagram. /// + /// + /// + /// /// Empty vertex map. protected void ComputeEdges(Mesh mesh, Vertex[] vertices, Face[] faces, List[] 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. /// /// Maps all vertices to a list of leaving edges. - protected void ConnectEdges(List[] map) + protected virtual void ConnectEdges(List[] 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 EnumerateEdges() + { + var edges = new List(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; + } } }