diff --git a/Triangle.NET/TestApp/FormGenerator.cs b/Triangle.NET/TestApp/FormGenerator.cs
index 6bd8356..eaee467 100644
--- a/Triangle.NET/TestApp/FormGenerator.cs
+++ b/Triangle.NET/TestApp/FormGenerator.cs
@@ -63,10 +63,17 @@ namespace MeshExplorer
{
if (currentGenerator != null && InputGenerated != null)
{
- InputGeometry input = currentGenerator.Generate(sliderParam1.Value,
- sliderParam2.Value, sliderParam3.Value);
+ try
+ {
+ InputGeometry input = currentGenerator.Generate(sliderParam1.Value,
+ sliderParam2.Value, sliderParam3.Value);
- InputGenerated(input, EventArgs.Empty);
+ InputGenerated(input, EventArgs.Empty);
+ }
+ catch (Exception ex)
+ {
+ DarkMessageBox.Show("Exception", ex.Message);
+ }
}
}
@@ -135,6 +142,7 @@ namespace MeshExplorer
darkListBox1.Items.Add(new StarInBox());
darkListBox1.Items.Add(new RingPolygon());
darkListBox1.Items.Add(new BoxWithHole());
+ darkListBox1.Items.Add(new CircleWithHole());
darkListBox1.SelectedIndex = 0;
}
diff --git a/Triangle.NET/TestApp/Generators/CircleWithHole.cs b/Triangle.NET/TestApp/Generators/CircleWithHole.cs
new file mode 100644
index 0000000..ccac84f
--- /dev/null
+++ b/Triangle.NET/TestApp/Generators/CircleWithHole.cs
@@ -0,0 +1,139 @@
+// -----------------------------------------------------------------------
+//
+// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
+//
+// -----------------------------------------------------------------------
+
+namespace MeshExplorer.Generators
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using TriangleNet.Geometry;
+
+ ///
+ /// Generates a ring polygon.
+ ///
+ public class CircleWithHole : IGenerator
+ {
+ // Parameters range
+ double[] range1 = { 100, 250 };
+ double[] range2 = { 2, 15 };
+
+ public string Name
+ {
+ get { return "Circle with Hole"; }
+ }
+
+ public string Description
+ {
+ get { return ""; }
+ }
+
+ public int ParameterCount
+ {
+ get { return 2; }
+ }
+
+ public string ParameterDescription(int paramIndex)
+ {
+ if (paramIndex == 1)
+ {
+ return "Number of points:";
+ }
+
+ if (paramIndex == 2)
+ {
+ return "Outer radius:";
+ }
+
+ return "";
+ }
+
+ public string ParameterDescription(int paramIndex, double paramValue)
+ {
+ if (paramIndex == 1)
+ {
+ int num = (int)((range1[1] - range1[0]) / 100.0 * paramValue + range1[0]);
+
+ return num.ToString();
+ }
+
+ if (paramIndex == 2)
+ {
+ int radius = (int)((range2[1] - range2[0]) / 100.0 * paramValue + range2[0]);
+
+ return radius.ToString();
+ }
+
+ return "";
+ }
+
+ public InputGeometry Generate(double param1, double param2, double param3)
+ {
+ // Number of points on the outer circle
+ int n = (int)((range1[1] - range1[0]) / 100.0 * param1 + range1[0]);
+ int count, npoints;
+
+ double radius = (int)((range2[1] - range2[0]) / 100.0 * param2 + range2[0]);
+
+ // Step size on the outer circle
+ double h = 2 * Math.PI * radius / n;
+
+ // Current radius and step size
+ double r, dphi;
+
+ InputGeometry input = new InputGeometry(n + 1);
+
+ // Inner cirlce (radius = 1)
+ r = 1;
+ npoints = (int)(2 * Math.PI * r / h);
+ dphi = 2 * Math.PI / npoints;
+ for (int i = 0; i < npoints; i++)
+ {
+ input.AddPoint(r * Math.Cos(i * dphi), r * Math.Sin(i * dphi), 1);
+ input.AddSegment(i, (i + 1) % npoints, 1);
+ }
+
+ count = input.Count;
+
+ // Center cirlce
+ r = (radius + 1) / 2.0;
+ npoints = (int)(2 * Math.PI * r / h);
+ dphi = 2 * Math.PI / npoints;
+ for (int i = 0; i < npoints; i++)
+ {
+ input.AddPoint(r * Math.Cos(i * dphi), r * Math.Sin(i * dphi), 2);
+ input.AddSegment(count + i, count + (i + 1) % npoints, 2);
+ }
+
+ count = input.Count;
+
+ // Outer cirlce
+ r = radius;
+ npoints = (int)(2 * Math.PI * r / h);
+ dphi = 2 * Math.PI / npoints;
+ for (int i = 0; i < npoints; i++)
+ {
+ input.AddPoint(r * Math.Cos(i * dphi), r * Math.Sin(i * dphi), 3);
+ input.AddSegment(count + i, count + (i + 1) % npoints, 3);
+ }
+
+ input.AddHole(0, 0);
+
+ // Regions: |------|------|---|
+ // r 1 0
+
+ input.AddRegion((r + 3.0) / 4.0, 0, 1);
+ input.AddRegion((3 * r + 1.0) / 4.0, 0, 2);
+
+ return input;
+ }
+
+ public override string ToString()
+ {
+ return this.Name;
+ }
+ }
+}
diff --git a/Triangle.NET/TestApp/Mesh Explorer.csproj b/Triangle.NET/TestApp/Mesh Explorer.csproj
index a291fc1..d174071 100644
--- a/Triangle.NET/TestApp/Mesh Explorer.csproj
+++ b/Triangle.NET/TestApp/Mesh Explorer.csproj
@@ -97,6 +97,7 @@
FormMain.cs
+
diff --git a/Triangle.NET/TestApp/Views/AboutView.Designer.cs b/Triangle.NET/TestApp/Views/AboutView.Designer.cs
index b892f81..2aa417f 100644
--- a/Triangle.NET/TestApp/Views/AboutView.Designer.cs
+++ b/Triangle.NET/TestApp/Views/AboutView.Designer.cs
@@ -79,7 +79,7 @@
this.label19.Name = "label19";
this.label19.Size = new System.Drawing.Size(134, 40);
this.label19.TabIndex = 6;
- this.label19.Text = "Beta 3 (2012-10-30)\r\nChristian Woltering\r\nMIT";
+ this.label19.Text = "Beta 3 (2013-01-20)\r\nChristian Woltering\r\nMIT";
//
// label18
//
diff --git a/Triangle.NET/Triangle/Algorithm/Dwyer.cs b/Triangle.NET/Triangle/Algorithm/Dwyer.cs
index edf0b79..ebf83df 100644
--- a/Triangle.NET/Triangle/Algorithm/Dwyer.cs
+++ b/Triangle.NET/Triangle/Algorithm/Dwyer.cs
@@ -599,7 +599,6 @@ namespace TriangleNet.Algorithm
///
/// Recursively form a Delaunay triangulation by the divide-and-conquer method.
///
- ///
///
///
///
diff --git a/Triangle.NET/Triangle/Behavior.cs b/Triangle.NET/Triangle/Behavior.cs
index 38b8404..979f60f 100644
--- a/Triangle.NET/Triangle/Behavior.cs
+++ b/Triangle.NET/Triangle/Behavior.cs
@@ -24,7 +24,7 @@ namespace TriangleNet
VarArea = false;
FixedArea = false;
Usertest = false;
- RegionAttrib = false;
+ UseRegions = false;
Convex = false;
Jettison = false;
UseBoundaryMarkers = true;
@@ -84,9 +84,9 @@ namespace TriangleNet
///
public bool Usertest { get; set; }
///
- /// Apply attributes to identify triangles in certain regions.
+ /// Identify triangles in certain regions.
///
- public bool RegionAttrib { get; set; }
+ public bool UseRegions { get; set; }
///
/// Enclose the convex hull with segments.
///
diff --git a/Triangle.NET/Triangle/Carver.cs b/Triangle.NET/Triangle/Carver.cs
index 3fdbfbb..1e51d3c 100644
--- a/Triangle.NET/Triangle/Carver.cs
+++ b/Triangle.NET/Triangle/Carver.cs
@@ -11,6 +11,7 @@ namespace TriangleNet
using System;
using TriangleNet.Geometry;
using System.Collections.Generic;
+ using TriangleNet.Tools;
///
/// Carves holes into the triangulation.
@@ -18,10 +19,12 @@ namespace TriangleNet
class Carver
{
Mesh mesh;
+ List viri;
public Carver(Mesh mesh)
{
this.mesh = mesh;
+ this.viri = new List();
}
///
@@ -57,7 +60,7 @@ namespace TriangleNet
if (!hulltri.IsInfected())
{
hulltri.Infect();
- mesh.viri.Add(hulltri.triangle);
+ viri.Add(hulltri.triangle);
}
}
else
@@ -118,11 +121,11 @@ namespace TriangleNet
// Loop through all the infected triangles, spreading the virus to
// their neighbors, then to their neighbors' neighbors.
- for (int i = 0; i < mesh.viri.Count; i++)
+ for (int i = 0; i < viri.Count; i++)
{
// WARNING: Don't use foreach, mesh.viri list may get modified.
- testtri.triangle = mesh.viri[i];
+ testtri.triangle = viri[i];
// A triangle is marked as infected by messing with one of its pointers
// to subsegments, setting it to an illegal value. Hence, we have to
// temporarily uninfect this triangle so that we can examine its
@@ -164,7 +167,7 @@ namespace TriangleNet
// the neighbor becomes infected.
neighbor.Infect();
// Ensure that the neighbor's neighbors will be infected.
- mesh.viri.Add(neighbor.triangle);
+ viri.Add(neighbor.triangle);
}
else
{
@@ -194,7 +197,7 @@ namespace TriangleNet
testtri.Infect();
}
- foreach (var virus in mesh.viri)
+ foreach (var virus in viri)
{
testtri.triangle = virus;
@@ -286,90 +289,9 @@ namespace TriangleNet
}
// Empty the virus pool.
- mesh.viri.Clear();
+ viri.Clear();
}
- ///
- /// Spread regional attributes and/or area constraints (from a .poly file)
- /// throughout the mesh.
- ///
- ///
- ///
- ///
- /// This procedure operates in two phases. The first phase spreads an
- /// attribute and/or an area constraint through a (segment-bounded) region.
- /// The triangles are marked to ensure that each triangle is added to the
- /// virus pool only once, so the procedure will terminate.
- ///
- /// The second phase uninfects all infected triangles, returning them to
- /// normal.
- ///
- void RegionPlague(double attribute, double area)
- {
- Otri testtri = default(Otri);
- Otri neighbor = default(Otri);
- Osub neighborsubseg = default(Osub);
-
- Behavior behavior = mesh.behavior;
-
- // Loop through all the infected triangles, spreading the attribute
- // and/or area constraint to their neighbors, then to their neighbors'
- // neighbors.
- for (int i = 0; i < mesh.viri.Count; i++)
- {
- // WARNING: Don't use foreach, mesh.viri list may get modified.
-
- testtri.triangle = mesh.viri[i];
- // A triangle is marked as infected by messing with one of its pointers
- // to subsegments, setting it to an illegal value. Hence, we have to
- // temporarily uninfect this triangle so that we can examine its
- // adjacent subsegments.
- // TODO: Not true in the C# version (so we could skip this).
- testtri.Uninfect();
- if (behavior.RegionAttrib)
- {
- // Set an attribute (Note: the attributes array was resized before).
- testtri.triangle.attributes[mesh.eextras] = attribute;
- }
- if (behavior.VarArea)
- {
- // Set an area constraint.
- testtri.triangle.area = area;
- }
-
- // Check each of the triangle's three neighbors.
- for (testtri.orient = 0; testtri.orient < 3; testtri.orient++)
- {
- // Find the neighbor.
- testtri.Sym(ref neighbor);
- // Check for a subsegment between the triangle and its neighbor.
- testtri.SegPivot(ref neighborsubseg);
- // Make sure the neighbor exists, is not already infected, and
- // isn't protected by a subsegment.
- if ((neighbor.triangle != Mesh.dummytri) && !neighbor.IsInfected()
- && (neighborsubseg.seg == Mesh.dummysub))
- {
- // Infect the neighbor.
- neighbor.Infect();
- // Ensure that the neighbor's neighbors will be infected.
- mesh.viri.Add(neighbor.triangle);
- }
- }
- // Remark the triangle as infected, so it doesn't get added to the
- // virus pool again.
- testtri.Infect();
- }
-
- // Uninfect all triangles.
- foreach (var virus in mesh.viri)
- {
- testtri.triangle = virus;
- testtri.Uninfect();
- }
-
- // Empty the virus pool.
- mesh.viri.Clear();
- }
///
/// Find the holes and infect them. Find the area constraints and infect
/// them. Infect the convex hull. Spread the infection and kill triangles.
@@ -378,11 +300,10 @@ namespace TriangleNet
public void CarveHoles()
{
Otri searchtri = default(Otri);
- Otri tri = default(Otri);
Vertex searchorg, searchdest;
LocateResult intersect;
- Otri[] regionTris = null;
+ Triangle[] regionTris = null;
if (!mesh.behavior.Convex)
{
@@ -417,7 +338,7 @@ namespace TriangleNet
// Infect the triangle. This is done by marking the triangle
// as infected and including the triangle in the virus pool.
searchtri.Infect();
- mesh.viri.Add(searchtri.triangle);
+ viri.Add(searchtri.triangle);
}
}
}
@@ -430,14 +351,14 @@ namespace TriangleNet
// which might not be convex; they can only be used with a freshly triangulated PSLG.)
if (mesh.regions.Count > 0)
{
- regionTris = new Otri[mesh.regions.Count];
-
int i = 0;
+ regionTris = new Triangle[mesh.regions.Count];
+
// Find the starting triangle for each region.
foreach (var region in mesh.regions)
{
- regionTris[i].triangle = Mesh.dummytri;
+ regionTris[i] = Mesh.dummytri;
// Ignore region points that aren't within the bounds of the mesh.
if (mesh.bounds.Contains(region.point))
{
@@ -458,7 +379,8 @@ namespace TriangleNet
{
// Record the triangle for processing after the
// holes have been carved.
- searchtri.Copy(ref regionTris[i]);
+ regionTris[i] = searchtri.triangle;
+ regionTris[i].region = region.id;
}
}
}
@@ -467,57 +389,33 @@ namespace TriangleNet
}
}
- if (mesh.viri.Count > 0)
+ if (viri.Count > 0)
{
// Carve the holes and concavities.
Plague();
}
- // The virus pool should be empty now.
if (regionTris != null)
{
- if (mesh.behavior.RegionAttrib)
- {
- // Make the triangle's attributes larger.
- double[] attributes = new double[mesh.eextras + 1];
-
- // Assign every triangle a regional attribute of zero.
- tri.orient = 0;
- foreach (var t in mesh.triangles.Values)
- {
- Array.Copy(tri.triangle.attributes, attributes, mesh.eextras);
- tri.triangle = t;
- tri.triangle.attributes = attributes;
- }
- }
+ var iterator = new RegionIterator(mesh);
for (int i = 0; i < regionTris.Length; i++)
{
- if (regionTris[i].triangle != Mesh.dummytri)
+ if (regionTris[i] != Mesh.dummytri)
{
// Make sure the triangle under consideration still exists.
// It may have been eaten by the virus.
- if (!Otri.IsDead(regionTris[i].triangle))
+ if (!Otri.IsDead(regionTris[i]))
{
- // Put one triangle in the virus pool.
- regionTris[i].Infect();
- mesh.viri.Add(regionTris[i].triangle);
// Apply one region's attribute and/or area constraint.
- RegionPlague(mesh.regions[i].Attribute, mesh.regions[i].Area);
- // The virus pool should be empty now.
+ iterator.Process(regionTris[i]);
}
}
}
-
- if (mesh.behavior.RegionAttrib)
- {
- // Note the fact that each triangle has an additional attribute.
- mesh.eextras++;
- }
}
// Free up memory (virus pool should be empty anyway).
- mesh.viri.Clear();
+ viri.Clear();
}
}
}
diff --git a/Triangle.NET/Triangle/Data/Triangle.cs b/Triangle.NET/Triangle/Data/Triangle.cs
index adabc22..2777590 100644
--- a/Triangle.NET/Triangle/Data/Triangle.cs
+++ b/Triangle.NET/Triangle/Data/Triangle.cs
@@ -33,11 +33,11 @@ namespace TriangleNet.Data
internal Otri[] neighbors;
internal Vertex[] vertices;
internal Osub[] subsegs;
- internal double[] attributes;
+ internal int region;
internal double area;
internal bool infected;
- public Triangle(int numAttributes)
+ public Triangle()
{
// Initialize the three adjoining triangles to be "outer space".
neighbors = new Otri[3];
@@ -58,11 +58,6 @@ namespace TriangleNet.Data
subsegs[2].seg = Mesh.dummysub;
}
- if (numAttributes > 0)
- {
- attributes = new double[numAttributes];
- }
-
// TODO:
//if (Behavior.VarArea)
//{
@@ -70,7 +65,6 @@ namespace TriangleNet.Data
//}
}
-
#region Public properties
///
@@ -171,11 +165,11 @@ namespace TriangleNet.Data
}
///
- /// Gets the triangle attributes.
+ /// Region ID the triangle belongs to.
///
- public double[] Attributes
+ public int Region
{
- get { return this.attributes; }
+ get { return this.region; }
}
#endregion
diff --git a/Triangle.NET/Triangle/Geometry/ITriangle.cs b/Triangle.NET/Triangle/Geometry/ITriangle.cs
index 8aa5dd1..75d9201 100644
--- a/Triangle.NET/Triangle/Geometry/ITriangle.cs
+++ b/Triangle.NET/Triangle/Geometry/ITriangle.cs
@@ -80,8 +80,8 @@ namespace TriangleNet.Geometry
double Area { get; }
///
- /// Triangle atributes.
+ /// Region ID the triangle belongs to.
///
- double[] Attributes { get; }
+ int Region { get; }
}
}
diff --git a/Triangle.NET/Triangle/Geometry/InputGeometry.cs b/Triangle.NET/Triangle/Geometry/InputGeometry.cs
index 1461137..59674fc 100644
--- a/Triangle.NET/Triangle/Geometry/InputGeometry.cs
+++ b/Triangle.NET/Triangle/Geometry/InputGeometry.cs
@@ -197,11 +197,10 @@ namespace TriangleNet.Geometry
///
/// X coordinate of the hole.
/// Y coordinate of the hole.
- /// The regions area constraint.
- /// Region attribute.
- public void AddRegion(double x, double y, double area, double attribute)
+ /// The region id.
+ public void AddRegion(double x, double y, int id)
{
- regions.Add(new RegionPointer(x, y, area, attribute));
+ regions.Add(new RegionPointer(x, y, id));
}
///
diff --git a/Triangle.NET/Triangle/Geometry/RegionPointer.cs b/Triangle.NET/Triangle/Geometry/RegionPointer.cs
index 3267ac8..f44b872 100644
--- a/Triangle.NET/Triangle/Geometry/RegionPointer.cs
+++ b/Triangle.NET/Triangle/Geometry/RegionPointer.cs
@@ -16,45 +16,18 @@ namespace TriangleNet.Geometry
public class RegionPointer
{
internal Point point;
- internal double area;
- internal double attribute;
+ internal int id;
///
/// Initializes a new instance of the class.
///
/// X coordinate of the region.
/// Y coordinate of the region.
- /// Area constraint.
- /// Region attribute.
- public RegionPointer(double x, double y, double area, double attribute)
+ /// Region id.
+ public RegionPointer(double x, double y, int id)
{
this.point = new Point(x, y);
- this.area = area;
- this.attribute = attribute;
- }
-
- ///
- /// Gets the location of the region.
- ///
- internal Point Point
- {
- get { return point; }
- }
-
- ///
- /// Gets the area constraint.
- ///
- internal double Area
- {
- get { return area; }
- }
-
- ///
- /// Gets the region attribute.
- ///
- internal double Attribute
- {
- get { return attribute; }
+ this.id = id;
}
}
}
diff --git a/Triangle.NET/Triangle/IO/DataReader.cs b/Triangle.NET/Triangle/IO/DataReader.cs
index b0b0d32..78b6901 100644
--- a/Triangle.NET/Triangle/IO/DataReader.cs
+++ b/Triangle.NET/Triangle/IO/DataReader.cs
@@ -75,7 +75,6 @@ namespace TriangleNet.IO
int numberofsegments = input.segments.Count;
mesh.inelements = elements;
- mesh.eextras = triangles[0].Attributes != null ? triangles[0].Attributes.Length : 0;
// Create the triangles.
for (i = 0; i < mesh.inelements; i++)
@@ -134,9 +133,9 @@ namespace TriangleNet.IO
}
// Read the triangle's attributes.
- tri.triangle.attributes = triangles[i].Attributes;
+ tri.triangle.region = triangles[i].Region;
- // TODO
+ // TODO: VarArea
if (mesh.behavior.VarArea)
{
tri.triangle.area = triangles[i].Area;
diff --git a/Triangle.NET/Triangle/IO/FileReader.cs b/Triangle.NET/Triangle/IO/FileReader.cs
index 254a283..753a987 100644
--- a/Triangle.NET/Triangle/IO/FileReader.cs
+++ b/Triangle.NET/Triangle/IO/FileReader.cs
@@ -447,19 +447,17 @@ namespace TriangleNet.IO
throw new Exception("Can't read input file (region).");
}
- if (line.Length < 5)
+ if (line.Length < 4)
{
- throw new Exception("Invalid region.");
+ throw new Exception("Invalid region attributes.");
}
data.AddRegion(
// Region x and y
- double.Parse(line[1]),
- double.Parse(line[2]),
- // Region attribute
- double.Parse(line[3]),
- // Region area constraint
- double.Parse(line[4]));
+ double.Parse(line[1], nfi),
+ double.Parse(line[2], nfi),
+ // Region id
+ int.Parse(line[3]));
}
}
}
@@ -504,6 +502,7 @@ namespace TriangleNet.IO
{
// Read number of elements and number of attributes.
string[] line;
+ bool validRegion = false;
if (!TryReadLine(reader, out line))
{
@@ -517,6 +516,12 @@ namespace TriangleNet.IO
if (line.Length > 2)
{
attributes = int.Parse(line[2]);
+ validRegion = true;
+ }
+
+ if (attributes > 1)
+ {
+ SimpleLog.Instance.Warning("Triangle attributes not supported.", "FileReader.Read");
}
triangles = new List(intriangles);
@@ -542,18 +547,12 @@ namespace TriangleNet.IO
int.Parse(line[2]) - startIndex,
int.Parse(line[3]) - startIndex);
- // Read triangle attributes
- if (attributes > 0)
+ // Read triangle region
+ if (attributes > 0 && validRegion)
{
- for (int j = 0; j < attributes; j++)
- {
- tri.attributes = new double[attributes];
-
- if (line.Length > 4 + j)
- {
- tri.attributes[j] = double.Parse(line[4 + j]);
- }
- }
+ int region = 0;
+ validRegion = int.TryParse(line[4], out region);
+ tri.region = region;
}
triangles.Add(tri);
diff --git a/Triangle.NET/Triangle/IO/FileWriter.cs b/Triangle.NET/Triangle/IO/FileWriter.cs
index 7abcd58..1d7b2ed 100644
--- a/Triangle.NET/Triangle/IO/FileWriter.cs
+++ b/Triangle.NET/Triangle/IO/FileWriter.cs
@@ -142,6 +142,7 @@ namespace TriangleNet.IO
{
Otri tri = default(Otri);
Vertex p1, p2, p3;
+ bool regions = mesh.behavior.UseRegions;
int j = 0;
@@ -150,7 +151,7 @@ namespace TriangleNet.IO
using (StreamWriter writer = new StreamWriter(filename))
{
// Number of triangles, vertices per triangle, attributes per triangle.
- writer.WriteLine("{0} 3 {1}", mesh.triangles.Count, mesh.eextras);
+ writer.WriteLine("{0} 3 {1}", mesh.triangles.Count, regions ? 1 : 0);
foreach (var item in mesh.triangles.Values)
{
@@ -163,9 +164,9 @@ namespace TriangleNet.IO
// Triangle number, indices for three vertices.
writer.Write("{0} {1} {2} {3}", j, p1.id, p2.id, p3.id);
- for (int i = 0; i < mesh.eextras; i++)
+ if (regions)
{
- writer.Write(" {0}", tri.triangle.attributes[i].ToString(nfi));
+ writer.Write(" {0}", tri.triangle.region);
}
writer.WriteLine();
@@ -260,9 +261,8 @@ namespace TriangleNet.IO
writer.WriteLine("{0}", mesh.regions.Count);
foreach (var region in mesh.regions)
{
- writer.WriteLine("{0} {1} {2} {3} {4}", j, region.point.X.ToString(nfi),
- region.point.Y.ToString(nfi), region.attribute.ToString(nfi),
- region.area.ToString(nfi));
+ writer.WriteLine("{0} {1} {2} {3}", j, region.point.X.ToString(nfi),
+ region.point.Y.ToString(nfi), region.id);
j++;
}
diff --git a/Triangle.NET/Triangle/IO/InputTriangle.cs b/Triangle.NET/Triangle/IO/InputTriangle.cs
index 61c0939..68b6e0e 100644
--- a/Triangle.NET/Triangle/IO/InputTriangle.cs
+++ b/Triangle.NET/Triangle/IO/InputTriangle.cs
@@ -17,7 +17,7 @@ namespace TriangleNet.IO
public class InputTriangle : ITriangle
{
internal int[] vertices;
- internal double[] attributes;
+ internal int region;
internal double area;
public InputTriangle(int p0, int p1, int p2)
@@ -106,11 +106,12 @@ namespace TriangleNet.IO
}
///
- /// Gets the triangle attributes.
+ /// Region ID the triangle belongs to.
///
- public double[] Attributes
+ public int Region
{
- get { return null; }
+ get { return region; }
+ set { region = value; }
}
#endregion
diff --git a/Triangle.NET/Triangle/Mesh.cs b/Triangle.NET/Triangle/Mesh.cs
index 5c5a6f5..c8312b7 100644
--- a/Triangle.NET/Triangle/Mesh.cs
+++ b/Triangle.NET/Triangle/Mesh.cs
@@ -48,8 +48,6 @@ namespace TriangleNet
internal List holes;
internal List regions;
- internal List viri;
-
// Other variables.
internal BoundingBox bounds; // x and y bounds.
internal int invertices; // Number of input vertices.
@@ -59,7 +57,7 @@ namespace TriangleNet
internal int edges; // Number of output edges.
internal int mesh_dim; // Dimension (ought to be 2).
internal int nextras; // Number of attributes per vertex.
- internal int eextras; // Number of attributes per triangle.
+ //internal int eextras; // Number of attributes per triangle.
internal int hullsize; // Number of edges in convex hull.
internal int steinerleft; // Number of Steiner points not yet used.
internal bool checksegments; // Are there segments in the triangulation yet?
@@ -182,7 +180,6 @@ namespace TriangleNet
triangles = new Dictionary();
subsegs = new Dictionary();
- viri = new List();
flipstack = new Stack();
holes = new List();
@@ -247,6 +244,7 @@ namespace TriangleNet
// behavior.VarArea = true;
//}
+ // TODO: remove
if (!behavior.Poly)
{
// Be careful not to allocate space for element area constraints that
@@ -255,9 +253,11 @@ namespace TriangleNet
// Be careful not to add an extra attribute to each element unless the
// input supports it (PSLG in, but not refining a preexisting mesh).
- behavior.RegionAttrib = false;
+ behavior.UseRegions = false;
}
+ behavior.UseRegions = input.Regions.Count > 0;
+
TransferNodes(input);
// Read and reconstruct a mesh.
@@ -296,6 +296,7 @@ namespace TriangleNet
// behavior.UseBoundaryMarkers = true;
//}
+ // TODO: remove
if (!behavior.Poly)
{
// Be careful not to allocate space for element area constraints that
@@ -304,9 +305,11 @@ namespace TriangleNet
// Be careful not to add an extra attribute to each element unless the
// input supports it (PSLG in, but not refining a preexisting mesh).
- behavior.RegionAttrib = false;
+ behavior.UseRegions = false;
}
+ behavior.UseRegions = input.Regions.Count > 0;
+
steinerleft = behavior.Steiner;
TransferNodes(input);
@@ -706,8 +709,6 @@ namespace TriangleNet
{
int hulledges = 0;
- eextras = 0;
-
if (behavior.Algorithm == TriangulationAlgorithm.Dwyer)
{
Dwyer alg = new Dwyer();
@@ -746,7 +747,6 @@ namespace TriangleNet
this.hash_seg = 0;
this.hash_tri = 0;
- viri.Clear();
flipstack.Clear();
hullsize = 0;
@@ -771,6 +771,8 @@ namespace TriangleNet
Statistic.InCircleCount = 0;
Statistic.CounterClockwiseCount = 0;
+ Statistic.InCircleCountDecimal = 0;
+ Statistic.CounterClockwiseCountDecimal = 0;
Statistic.Orient3dCount = 0;
Statistic.HyperbolaCount = 0;
Statistic.CircleTopCount = 0;
@@ -805,7 +807,7 @@ namespace TriangleNet
private void DummyInit()
{
// Set up 'dummytri', the 'triangle' that occupies "outer space."
- dummytri = new Triangle(0);
+ dummytri = new Triangle();
dummytri.hash = -1;
dummytri.id = -1;
@@ -880,7 +882,7 @@ namespace TriangleNet
/// Reference to the new triangle.
internal void MakeTriangle(ref Otri newotri)
{
- Triangle tri = new Triangle(eextras);
+ Triangle tri = new Triangle();
tri.hash = this.hash_tri++;
tri.id = tri.hash;
@@ -981,14 +983,13 @@ namespace TriangleNet
Vertex first;
Vertex leftvertex, rightvertex, botvertex, topvertex, farvertex;
Vertex segmentorg, segmentdest;
- double attrib;
+ int region;
double area;
InsertVertexResult success;
LocateResult intersect;
bool doflip;
bool mirrorflag;
bool enq;
- int i;
if (splitseg.seg == null)
{
@@ -1094,11 +1095,8 @@ namespace TriangleNet
newbotright.SetApex(newvertex);
horiz.SetOrg(newvertex);
- for (i = 0; i < eextras; i++)
- {
- // Set the element attributes of a new triangle.
- newbotright.triangle.attributes[i] = botright.triangle.attributes[i];
- }
+ // Set the region of a new triangle.
+ newbotright.triangle.region = botright.triangle.region;
if (behavior.VarArea)
{
@@ -1114,11 +1112,8 @@ namespace TriangleNet
newtopright.SetApex(newvertex);
topright.SetOrg(newvertex);
- for (i = 0; i < eextras; i++)
- {
- // Set the element attributes of another new triangle.
- newtopright.triangle.attributes[i] = topright.triangle.attributes[i];
- }
+ // Set the region of another new triangle.
+ newtopright.triangle.region = topright.triangle.region;
if (behavior.VarArea)
{
@@ -1223,13 +1218,9 @@ namespace TriangleNet
newbotright.SetApex(newvertex);
horiz.SetApex(newvertex);
- for (i = 0; i < eextras; i++)
- {
- // Set the element attributes of the new triangles.
- attrib = horiz.triangle.attributes[i];
- newbotleft.triangle.attributes[i] = attrib;
- newbotright.triangle.attributes[i] = attrib;
- }
+ // Set the region of the new triangles.
+ newbotleft.triangle.region = horiz.triangle.region;
+ newbotright.triangle.region = horiz.triangle.region;
if (behavior.VarArea)
{
@@ -1426,13 +1417,11 @@ namespace TriangleNet
top.SetDest(farvertex);
top.SetApex(leftvertex);
- for (i = 0; i < eextras; i++)
- {
- // Take the average of the two triangles' attributes.
- attrib = 0.5 * (top.triangle.attributes[i] + horiz.triangle.attributes[i]);
- top.triangle.attributes[i] = attrib;
- horiz.triangle.attributes[i] = attrib;
- }
+ // 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;
if (behavior.VarArea)
{
diff --git a/Triangle.NET/Triangle/Primitives.cs b/Triangle.NET/Triangle/Primitives.cs
index a08f2a9..6d7855a 100644
--- a/Triangle.NET/Triangle/Primitives.cs
+++ b/Triangle.NET/Triangle/Primitives.cs
@@ -152,6 +152,8 @@ namespace TriangleNet
private static decimal CounterClockwiseDecimal(Point pa, Point pb, Point pc)
{
+ Statistic.CounterClockwiseCountDecimal++;
+
decimal detleft, detright, det, detsum;
detleft = ((decimal)pa.x - (decimal)pc.x) * ((decimal)pb.y - (decimal)pc.y);
@@ -258,6 +260,8 @@ namespace TriangleNet
private static decimal InCircleDecimal(Point pa, Point pb, Point pc, Point pd)
{
+ Statistic.InCircleCountDecimal++;
+
decimal adx, bdx, cdx, ady, bdy, cdy;
decimal bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
decimal alift, blift, clift;
diff --git a/Triangle.NET/Triangle/Quality.cs b/Triangle.NET/Triangle/Quality.cs
index 5857090..6212a40 100644
--- a/Triangle.NET/Triangle/Quality.cs
+++ b/Triangle.NET/Triangle/Quality.cs
@@ -724,7 +724,7 @@ namespace TriangleNet
split = 0.5;
}
- // Create the new vertex.
+ // Create the new vertex (interpolate coordinates).
newvertex = new Vertex(
eorg.x + split * (edest.x - eorg.x),
eorg.y + split * (edest.y - eorg.y),
@@ -738,7 +738,7 @@ namespace TriangleNet
mesh.vertices.Add(newvertex.hash, newvertex);
- // Interpolate its coordinate and attributes.
+ // Interpolate attributes.
for (int i = 0; i < mesh.nextras; i++)
{
newvertex.attributes[i] = eorg.attributes[i]
diff --git a/Triangle.NET/Triangle/Tools/RegionIterator.cs b/Triangle.NET/Triangle/Tools/RegionIterator.cs
new file mode 100644
index 0000000..d09599f
--- /dev/null
+++ b/Triangle.NET/Triangle/Tools/RegionIterator.cs
@@ -0,0 +1,139 @@
+// -----------------------------------------------------------------------
+//
+// Original Matlab code by John Burkardt, Florida State University
+// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
+//
+// -----------------------------------------------------------------------
+
+namespace TriangleNet.Tools
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using TriangleNet.Data;
+
+ ///
+ /// Iterates the region a given triangle belongs to and applies an action
+ /// to each connected trianlge in that region. Default action is to set the
+ /// region id.
+ ///
+ public class RegionIterator
+ {
+ Mesh mesh;
+ List viri;
+
+ public RegionIterator(Mesh mesh)
+ {
+ this.mesh = mesh;
+ this.viri = new List();
+ }
+
+ ///
+ /// Spread regional attributes and/or area constraints (from a .poly file)
+ /// throughout the mesh.
+ ///
+ ///
+ ///
+ ///
+ /// This procedure operates in two phases. The first phase spreads an
+ /// attribute and/or an area constraint through a (segment-bounded) region.
+ /// The triangles are marked to ensure that each triangle is added to the
+ /// virus pool only once, so the procedure will terminate.
+ ///
+ /// The second phase uninfects all infected triangles, returning them to
+ /// normal.
+ ///
+ void ProcessRegion(Action func)
+ {
+ Otri testtri = default(Otri);
+ Otri neighbor = default(Otri);
+ Osub neighborsubseg = default(Osub);
+
+ Behavior behavior = mesh.behavior;
+
+ // Loop through all the infected triangles, spreading the attribute
+ // and/or area constraint to their neighbors, then to their neighbors'
+ // neighbors.
+ for (int i = 0; i < viri.Count; i++)
+ {
+ // WARNING: Don't use foreach, viri list gets modified.
+
+ testtri.triangle = viri[i];
+ // A triangle is marked as infected by messing with one of its pointers
+ // to subsegments, setting it to an illegal value. Hence, we have to
+ // temporarily uninfect this triangle so that we can examine its
+ // adjacent subsegments.
+ // TODO: Not true in the C# version (so we could skip this).
+ testtri.Uninfect();
+
+ // Apply function.
+ func(testtri.triangle);
+
+ // Check each of the triangle's three neighbors.
+ for (testtri.orient = 0; testtri.orient < 3; testtri.orient++)
+ {
+ // Find the neighbor.
+ testtri.Sym(ref neighbor);
+ // Check for a subsegment between the triangle and its neighbor.
+ testtri.SegPivot(ref neighborsubseg);
+ // Make sure the neighbor exists, is not already infected, and
+ // isn't protected by a subsegment.
+ if ((neighbor.triangle != Mesh.dummytri) && !neighbor.IsInfected()
+ && (neighborsubseg.seg == Mesh.dummysub))
+ {
+ // Infect the neighbor.
+ neighbor.Infect();
+ // Ensure that the neighbor's neighbors will be infected.
+ viri.Add(neighbor.triangle);
+ }
+ }
+ // Remark the triangle as infected, so it doesn't get added to the
+ // virus pool again.
+ testtri.Infect();
+ }
+
+ // Uninfect all triangles.
+ foreach (var virus in viri)
+ {
+ virus.infected = false;
+ }
+
+ // Empty the virus pool.
+ viri.Clear();
+ }
+
+ ///
+ /// Set the region attribute of all trianlges connected to given triangle.
+ ///
+ public void Process(Triangle triangle)
+ {
+ // Default action is to just set the region id for all trianlges.
+ this.Process(triangle, (tri) => { tri.region = triangle.region; });
+ }
+
+ ///
+ /// Process all trianlges connected to given triangle and apply given action.
+ ///
+ public void Process(Triangle triangle, Action func)
+ {
+ if (triangle != Mesh.dummytri)
+ {
+ // Make sure the triangle under consideration still exists.
+ // It may have been eaten by the virus.
+ if (!Otri.IsDead(triangle))
+ {
+ // Put one triangle in the virus pool.
+ triangle.infected = true;
+ viri.Add(triangle);
+ // Apply one region's attribute and/or area constraint.
+ ProcessRegion(func);
+ // The virus pool should be empty now.
+ }
+ }
+
+ // Free up memory (virus pool should be empty anyway).
+ viri.Clear();
+ }
+ }
+}
diff --git a/Triangle.NET/Triangle/Tools/Statistic.cs b/Triangle.NET/Triangle/Tools/Statistic.cs
index 9b9f007..002d7bb 100644
--- a/Triangle.NET/Triangle/Tools/Statistic.cs
+++ b/Triangle.NET/Triangle/Tools/Statistic.cs
@@ -23,11 +23,13 @@ namespace TriangleNet.Tools
/// Number of incircle tests performed.
///
public static long InCircleCount = 0;
+ public static long InCircleCountDecimal = 0;
///
/// Number of counterclockwise tests performed.
///
public static long CounterClockwiseCount = 0;
+ public static long CounterClockwiseCountDecimal = 0;
///
/// Number of 3D orientation tests performed.
diff --git a/Triangle.NET/Triangle/Triangle.csproj b/Triangle.NET/Triangle/Triangle.csproj
index 0cdc54f..1bf10c9 100644
--- a/Triangle.NET/Triangle/Triangle.csproj
+++ b/Triangle.NET/Triangle/Triangle.csproj
@@ -87,6 +87,7 @@
+