Removed support for triangle attributes,

Added triangle region marker

git-svn-id: https://triangle.svn.codeplex.com/svn@71645 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
SND\wo80_cp
2013-01-21 14:59:13 +00:00
parent 99d2202fad
commit c19681b2dd
21 changed files with 396 additions and 251 deletions
+11 -3
View File
@@ -63,10 +63,17 @@ namespace MeshExplorer
{ {
if (currentGenerator != null && InputGenerated != null) if (currentGenerator != null && InputGenerated != null)
{ {
InputGeometry input = currentGenerator.Generate(sliderParam1.Value, try
sliderParam2.Value, sliderParam3.Value); {
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 StarInBox());
darkListBox1.Items.Add(new RingPolygon()); darkListBox1.Items.Add(new RingPolygon());
darkListBox1.Items.Add(new BoxWithHole()); darkListBox1.Items.Add(new BoxWithHole());
darkListBox1.Items.Add(new CircleWithHole());
darkListBox1.SelectedIndex = 0; darkListBox1.SelectedIndex = 0;
} }
@@ -0,0 +1,139 @@
// -----------------------------------------------------------------------
// <copyright file="RingPolygon.cs" company="">
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
// </copyright>
// -----------------------------------------------------------------------
namespace MeshExplorer.Generators
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TriangleNet.Geometry;
/// <summary>
/// Generates a ring polygon.
/// </summary>
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;
}
}
}
@@ -97,6 +97,7 @@
<DependentUpon>FormMain.cs</DependentUpon> <DependentUpon>FormMain.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Generators\BoxWithHole.cs" /> <Compile Include="Generators\BoxWithHole.cs" />
<Compile Include="Generators\CircleWithHole.cs" />
<Compile Include="Generators\IGenerator.cs" /> <Compile Include="Generators\IGenerator.cs" />
<Compile Include="Generators\RandomPoints.cs" /> <Compile Include="Generators\RandomPoints.cs" />
<Compile Include="Generators\RandomPointsCircle.cs" /> <Compile Include="Generators\RandomPointsCircle.cs" />
+1 -1
View File
@@ -79,7 +79,7 @@
this.label19.Name = "label19"; this.label19.Name = "label19";
this.label19.Size = new System.Drawing.Size(134, 40); this.label19.Size = new System.Drawing.Size(134, 40);
this.label19.TabIndex = 6; 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 // label18
// //
-1
View File
@@ -599,7 +599,6 @@ namespace TriangleNet.Algorithm
/// <summary> /// <summary>
/// Recursively form a Delaunay triangulation by the divide-and-conquer method. /// Recursively form a Delaunay triangulation by the divide-and-conquer method.
/// </summary> /// </summary>
/// <param name="sortarray"></param>
/// <param name="left"></param> /// <param name="left"></param>
/// <param name="right"></param> /// <param name="right"></param>
/// <param name="axis"></param> /// <param name="axis"></param>
+3 -3
View File
@@ -24,7 +24,7 @@ namespace TriangleNet
VarArea = false; VarArea = false;
FixedArea = false; FixedArea = false;
Usertest = false; Usertest = false;
RegionAttrib = false; UseRegions = false;
Convex = false; Convex = false;
Jettison = false; Jettison = false;
UseBoundaryMarkers = true; UseBoundaryMarkers = true;
@@ -84,9 +84,9 @@ namespace TriangleNet
/// </summary> /// </summary>
public bool Usertest { get; set; } public bool Usertest { get; set; }
/// <summary> /// <summary>
/// Apply attributes to identify triangles in certain regions. /// Identify triangles in certain regions.
/// </summary> /// </summary>
public bool RegionAttrib { get; set; } public bool UseRegions { get; set; }
/// <summary> /// <summary>
/// Enclose the convex hull with segments. /// Enclose the convex hull with segments.
/// </summary> /// </summary>
+22 -124
View File
@@ -11,6 +11,7 @@ namespace TriangleNet
using System; using System;
using TriangleNet.Geometry; using TriangleNet.Geometry;
using System.Collections.Generic; using System.Collections.Generic;
using TriangleNet.Tools;
/// <summary> /// <summary>
/// Carves holes into the triangulation. /// Carves holes into the triangulation.
@@ -18,10 +19,12 @@ namespace TriangleNet
class Carver class Carver
{ {
Mesh mesh; Mesh mesh;
List<Triangle> viri;
public Carver(Mesh mesh) public Carver(Mesh mesh)
{ {
this.mesh = mesh; this.mesh = mesh;
this.viri = new List<Triangle>();
} }
/// <summary> /// <summary>
@@ -57,7 +60,7 @@ namespace TriangleNet
if (!hulltri.IsInfected()) if (!hulltri.IsInfected())
{ {
hulltri.Infect(); hulltri.Infect();
mesh.viri.Add(hulltri.triangle); viri.Add(hulltri.triangle);
} }
} }
else else
@@ -118,11 +121,11 @@ namespace TriangleNet
// Loop through all the infected triangles, spreading the virus to // Loop through all the infected triangles, spreading the virus to
// their neighbors, then to their neighbors' neighbors. // 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. // 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 // 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 // to subsegments, setting it to an illegal value. Hence, we have to
// temporarily uninfect this triangle so that we can examine its // temporarily uninfect this triangle so that we can examine its
@@ -164,7 +167,7 @@ namespace TriangleNet
// the neighbor becomes infected. // the neighbor becomes infected.
neighbor.Infect(); neighbor.Infect();
// Ensure that the neighbor's neighbors will be infected. // Ensure that the neighbor's neighbors will be infected.
mesh.viri.Add(neighbor.triangle); viri.Add(neighbor.triangle);
} }
else else
{ {
@@ -194,7 +197,7 @@ namespace TriangleNet
testtri.Infect(); testtri.Infect();
} }
foreach (var virus in mesh.viri) foreach (var virus in viri)
{ {
testtri.triangle = virus; testtri.triangle = virus;
@@ -286,90 +289,9 @@ namespace TriangleNet
} }
// Empty the virus pool. // Empty the virus pool.
mesh.viri.Clear(); viri.Clear();
} }
/// <summary>
/// Spread regional attributes and/or area constraints (from a .poly file)
/// throughout the mesh.
/// </summary>
/// <param name="attribute"></param>
/// <param name="area"></param>
/// <remarks>
/// 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.
/// </remarks>
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();
}
/// <summary> /// <summary>
/// Find the holes and infect them. Find the area constraints and infect /// Find the holes and infect them. Find the area constraints and infect
/// them. Infect the convex hull. Spread the infection and kill triangles. /// them. Infect the convex hull. Spread the infection and kill triangles.
@@ -378,11 +300,10 @@ namespace TriangleNet
public void CarveHoles() public void CarveHoles()
{ {
Otri searchtri = default(Otri); Otri searchtri = default(Otri);
Otri tri = default(Otri);
Vertex searchorg, searchdest; Vertex searchorg, searchdest;
LocateResult intersect; LocateResult intersect;
Otri[] regionTris = null; Triangle[] regionTris = null;
if (!mesh.behavior.Convex) if (!mesh.behavior.Convex)
{ {
@@ -417,7 +338,7 @@ namespace TriangleNet
// Infect the triangle. This is done by marking the triangle // Infect the triangle. This is done by marking the triangle
// as infected and including the triangle in the virus pool. // as infected and including the triangle in the virus pool.
searchtri.Infect(); 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.) // which might not be convex; they can only be used with a freshly triangulated PSLG.)
if (mesh.regions.Count > 0) if (mesh.regions.Count > 0)
{ {
regionTris = new Otri[mesh.regions.Count];
int i = 0; int i = 0;
regionTris = new Triangle[mesh.regions.Count];
// Find the starting triangle for each region. // Find the starting triangle for each region.
foreach (var region in mesh.regions) 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. // Ignore region points that aren't within the bounds of the mesh.
if (mesh.bounds.Contains(region.point)) if (mesh.bounds.Contains(region.point))
{ {
@@ -458,7 +379,8 @@ namespace TriangleNet
{ {
// Record the triangle for processing after the // Record the triangle for processing after the
// holes have been carved. // 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. // Carve the holes and concavities.
Plague(); Plague();
} }
// The virus pool should be empty now.
if (regionTris != null) if (regionTris != null)
{ {
if (mesh.behavior.RegionAttrib) var iterator = new RegionIterator(mesh);
{
// 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;
}
}
for (int i = 0; i < regionTris.Length; i++) 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. // Make sure the triangle under consideration still exists.
// It may have been eaten by the virus. // 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. // Apply one region's attribute and/or area constraint.
RegionPlague(mesh.regions[i].Attribute, mesh.regions[i].Area); iterator.Process(regionTris[i]);
// The virus pool should be empty now.
} }
} }
} }
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). // Free up memory (virus pool should be empty anyway).
mesh.viri.Clear(); viri.Clear();
} }
} }
} }
+5 -11
View File
@@ -33,11 +33,11 @@ namespace TriangleNet.Data
internal Otri[] neighbors; internal Otri[] neighbors;
internal Vertex[] vertices; internal Vertex[] vertices;
internal Osub[] subsegs; internal Osub[] subsegs;
internal double[] attributes; internal int region;
internal double area; internal double area;
internal bool infected; internal bool infected;
public Triangle(int numAttributes) public Triangle()
{ {
// Initialize the three adjoining triangles to be "outer space". // Initialize the three adjoining triangles to be "outer space".
neighbors = new Otri[3]; neighbors = new Otri[3];
@@ -58,11 +58,6 @@ namespace TriangleNet.Data
subsegs[2].seg = Mesh.dummysub; subsegs[2].seg = Mesh.dummysub;
} }
if (numAttributes > 0)
{
attributes = new double[numAttributes];
}
// TODO: // TODO:
//if (Behavior.VarArea) //if (Behavior.VarArea)
//{ //{
@@ -70,7 +65,6 @@ namespace TriangleNet.Data
//} //}
} }
#region Public properties #region Public properties
/// <summary> /// <summary>
@@ -171,11 +165,11 @@ namespace TriangleNet.Data
} }
/// <summary> /// <summary>
/// Gets the triangle attributes. /// Region ID the triangle belongs to.
/// </summary> /// </summary>
public double[] Attributes public int Region
{ {
get { return this.attributes; } get { return this.region; }
} }
#endregion #endregion
+2 -2
View File
@@ -80,8 +80,8 @@ namespace TriangleNet.Geometry
double Area { get; } double Area { get; }
/// <summary> /// <summary>
/// Triangle atributes. /// Region ID the triangle belongs to.
/// </summary> /// </summary>
double[] Attributes { get; } int Region { get; }
} }
} }
@@ -197,11 +197,10 @@ namespace TriangleNet.Geometry
/// </summary> /// </summary>
/// <param name="x">X coordinate of the hole.</param> /// <param name="x">X coordinate of the hole.</param>
/// <param name="y">Y coordinate of the hole.</param> /// <param name="y">Y coordinate of the hole.</param>
/// <param name="area">The regions area constraint.</param> /// <param name="id">The region id.</param>
/// <param name="attribute">Region attribute.</param> public void AddRegion(double x, double y, int id)
public void AddRegion(double x, double y, double area, double attribute)
{ {
regions.Add(new RegionPointer(x, y, area, attribute)); regions.Add(new RegionPointer(x, y, id));
} }
/// <summary> /// <summary>
@@ -16,45 +16,18 @@ namespace TriangleNet.Geometry
public class RegionPointer public class RegionPointer
{ {
internal Point point; internal Point point;
internal double area; internal int id;
internal double attribute;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RegionPointer" /> class. /// Initializes a new instance of the <see cref="RegionPointer" /> class.
/// </summary> /// </summary>
/// <param name="x">X coordinate of the region.</param> /// <param name="x">X coordinate of the region.</param>
/// <param name="y">Y coordinate of the region.</param> /// <param name="y">Y coordinate of the region.</param>
/// <param name="area">Area constraint.</param> /// <param name="id">Region id.</param>
/// <param name="attribute">Region attribute.</param> public RegionPointer(double x, double y, int id)
public RegionPointer(double x, double y, double area, double attribute)
{ {
this.point = new Point(x, y); this.point = new Point(x, y);
this.area = area; this.id = id;
this.attribute = attribute;
}
/// <summary>
/// Gets the location of the region.
/// </summary>
internal Point Point
{
get { return point; }
}
/// <summary>
/// Gets the area constraint.
/// </summary>
internal double Area
{
get { return area; }
}
/// <summary>
/// Gets the region attribute.
/// </summary>
internal double Attribute
{
get { return attribute; }
} }
} }
} }
+2 -3
View File
@@ -75,7 +75,6 @@ namespace TriangleNet.IO
int numberofsegments = input.segments.Count; int numberofsegments = input.segments.Count;
mesh.inelements = elements; mesh.inelements = elements;
mesh.eextras = triangles[0].Attributes != null ? triangles[0].Attributes.Length : 0;
// Create the triangles. // Create the triangles.
for (i = 0; i < mesh.inelements; i++) for (i = 0; i < mesh.inelements; i++)
@@ -134,9 +133,9 @@ namespace TriangleNet.IO
} }
// Read the triangle's attributes. // Read the triangle's attributes.
tri.triangle.attributes = triangles[i].Attributes; tri.triangle.region = triangles[i].Region;
// TODO // TODO: VarArea
if (mesh.behavior.VarArea) if (mesh.behavior.VarArea)
{ {
tri.triangle.area = triangles[i].Area; tri.triangle.area = triangles[i].Area;
+18 -19
View File
@@ -447,19 +447,17 @@ namespace TriangleNet.IO
throw new Exception("Can't read input file (region)."); 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( data.AddRegion(
// Region x and y // Region x and y
double.Parse(line[1]), double.Parse(line[1], nfi),
double.Parse(line[2]), double.Parse(line[2], nfi),
// Region attribute // Region id
double.Parse(line[3]), int.Parse(line[3]));
// Region area constraint
double.Parse(line[4]));
} }
} }
} }
@@ -504,6 +502,7 @@ namespace TriangleNet.IO
{ {
// Read number of elements and number of attributes. // Read number of elements and number of attributes.
string[] line; string[] line;
bool validRegion = false;
if (!TryReadLine(reader, out line)) if (!TryReadLine(reader, out line))
{ {
@@ -517,6 +516,12 @@ namespace TriangleNet.IO
if (line.Length > 2) if (line.Length > 2)
{ {
attributes = int.Parse(line[2]); attributes = int.Parse(line[2]);
validRegion = true;
}
if (attributes > 1)
{
SimpleLog.Instance.Warning("Triangle attributes not supported.", "FileReader.Read");
} }
triangles = new List<ITriangle>(intriangles); triangles = new List<ITriangle>(intriangles);
@@ -542,18 +547,12 @@ namespace TriangleNet.IO
int.Parse(line[2]) - startIndex, int.Parse(line[2]) - startIndex,
int.Parse(line[3]) - startIndex); int.Parse(line[3]) - startIndex);
// Read triangle attributes // Read triangle region
if (attributes > 0) if (attributes > 0 && validRegion)
{ {
for (int j = 0; j < attributes; j++) int region = 0;
{ validRegion = int.TryParse(line[4], out region);
tri.attributes = new double[attributes]; tri.region = region;
if (line.Length > 4 + j)
{
tri.attributes[j] = double.Parse(line[4 + j]);
}
}
} }
triangles.Add(tri); triangles.Add(tri);
+6 -6
View File
@@ -142,6 +142,7 @@ namespace TriangleNet.IO
{ {
Otri tri = default(Otri); Otri tri = default(Otri);
Vertex p1, p2, p3; Vertex p1, p2, p3;
bool regions = mesh.behavior.UseRegions;
int j = 0; int j = 0;
@@ -150,7 +151,7 @@ namespace TriangleNet.IO
using (StreamWriter writer = new StreamWriter(filename)) using (StreamWriter writer = new StreamWriter(filename))
{ {
// Number of triangles, vertices per triangle, attributes per triangle. // 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) foreach (var item in mesh.triangles.Values)
{ {
@@ -163,9 +164,9 @@ namespace TriangleNet.IO
// Triangle number, indices for three vertices. // Triangle number, indices for three vertices.
writer.Write("{0} {1} {2} {3}", j, p1.id, p2.id, p3.id); 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(); writer.WriteLine();
@@ -260,9 +261,8 @@ namespace TriangleNet.IO
writer.WriteLine("{0}", mesh.regions.Count); writer.WriteLine("{0}", mesh.regions.Count);
foreach (var region in mesh.regions) foreach (var region in mesh.regions)
{ {
writer.WriteLine("{0} {1} {2} {3} {4}", j, region.point.X.ToString(nfi), writer.WriteLine("{0} {1} {2} {3}", j, region.point.X.ToString(nfi),
region.point.Y.ToString(nfi), region.attribute.ToString(nfi), region.point.Y.ToString(nfi), region.id);
region.area.ToString(nfi));
j++; j++;
} }
+5 -4
View File
@@ -17,7 +17,7 @@ namespace TriangleNet.IO
public class InputTriangle : ITriangle public class InputTriangle : ITriangle
{ {
internal int[] vertices; internal int[] vertices;
internal double[] attributes; internal int region;
internal double area; internal double area;
public InputTriangle(int p0, int p1, int p2) public InputTriangle(int p0, int p1, int p2)
@@ -106,11 +106,12 @@ namespace TriangleNet.IO
} }
/// <summary> /// <summary>
/// Gets the triangle attributes. /// Region ID the triangle belongs to.
/// </summary> /// </summary>
public double[] Attributes public int Region
{ {
get { return null; } get { return region; }
set { region = value; }
} }
#endregion #endregion
+26 -37
View File
@@ -48,8 +48,6 @@ namespace TriangleNet
internal List<Point> holes; internal List<Point> holes;
internal List<RegionPointer> regions; internal List<RegionPointer> regions;
internal List<Triangle> viri;
// Other variables. // Other variables.
internal BoundingBox bounds; // x and y bounds. internal BoundingBox bounds; // x and y bounds.
internal int invertices; // Number of input vertices. internal int invertices; // Number of input vertices.
@@ -59,7 +57,7 @@ namespace TriangleNet
internal int edges; // Number of output edges. internal int edges; // Number of output edges.
internal int mesh_dim; // Dimension (ought to be 2). internal int mesh_dim; // Dimension (ought to be 2).
internal int nextras; // Number of attributes per vertex. 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 hullsize; // Number of edges in convex hull.
internal int steinerleft; // Number of Steiner points not yet used. internal int steinerleft; // Number of Steiner points not yet used.
internal bool checksegments; // Are there segments in the triangulation yet? internal bool checksegments; // Are there segments in the triangulation yet?
@@ -182,7 +180,6 @@ namespace TriangleNet
triangles = new Dictionary<int, Triangle>(); triangles = new Dictionary<int, Triangle>();
subsegs = new Dictionary<int, Segment>(); subsegs = new Dictionary<int, Segment>();
viri = new List<Triangle>();
flipstack = new Stack<Otri>(); flipstack = new Stack<Otri>();
holes = new List<Point>(); holes = new List<Point>();
@@ -247,6 +244,7 @@ namespace TriangleNet
// behavior.VarArea = true; // behavior.VarArea = true;
//} //}
// TODO: remove
if (!behavior.Poly) if (!behavior.Poly)
{ {
// Be careful not to allocate space for element area constraints that // 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 // Be careful not to add an extra attribute to each element unless the
// input supports it (PSLG in, but not refining a preexisting mesh). // 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); TransferNodes(input);
// Read and reconstruct a mesh. // Read and reconstruct a mesh.
@@ -296,6 +296,7 @@ namespace TriangleNet
// behavior.UseBoundaryMarkers = true; // behavior.UseBoundaryMarkers = true;
//} //}
// TODO: remove
if (!behavior.Poly) if (!behavior.Poly)
{ {
// Be careful not to allocate space for element area constraints that // 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 // Be careful not to add an extra attribute to each element unless the
// input supports it (PSLG in, but not refining a preexisting mesh). // 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; steinerleft = behavior.Steiner;
TransferNodes(input); TransferNodes(input);
@@ -706,8 +709,6 @@ namespace TriangleNet
{ {
int hulledges = 0; int hulledges = 0;
eextras = 0;
if (behavior.Algorithm == TriangulationAlgorithm.Dwyer) if (behavior.Algorithm == TriangulationAlgorithm.Dwyer)
{ {
Dwyer alg = new Dwyer(); Dwyer alg = new Dwyer();
@@ -746,7 +747,6 @@ namespace TriangleNet
this.hash_seg = 0; this.hash_seg = 0;
this.hash_tri = 0; this.hash_tri = 0;
viri.Clear();
flipstack.Clear(); flipstack.Clear();
hullsize = 0; hullsize = 0;
@@ -771,6 +771,8 @@ namespace TriangleNet
Statistic.InCircleCount = 0; Statistic.InCircleCount = 0;
Statistic.CounterClockwiseCount = 0; Statistic.CounterClockwiseCount = 0;
Statistic.InCircleCountDecimal = 0;
Statistic.CounterClockwiseCountDecimal = 0;
Statistic.Orient3dCount = 0; Statistic.Orient3dCount = 0;
Statistic.HyperbolaCount = 0; Statistic.HyperbolaCount = 0;
Statistic.CircleTopCount = 0; Statistic.CircleTopCount = 0;
@@ -805,7 +807,7 @@ namespace TriangleNet
private void DummyInit() private void DummyInit()
{ {
// Set up 'dummytri', the 'triangle' that occupies "outer space." // Set up 'dummytri', the 'triangle' that occupies "outer space."
dummytri = new Triangle(0); dummytri = new Triangle();
dummytri.hash = -1; dummytri.hash = -1;
dummytri.id = -1; dummytri.id = -1;
@@ -880,7 +882,7 @@ namespace TriangleNet
/// <param name="newotri">Reference to the new triangle.</param> /// <param name="newotri">Reference to the new triangle.</param>
internal void MakeTriangle(ref Otri newotri) internal void MakeTriangle(ref Otri newotri)
{ {
Triangle tri = new Triangle(eextras); Triangle tri = new Triangle();
tri.hash = this.hash_tri++; tri.hash = this.hash_tri++;
tri.id = tri.hash; tri.id = tri.hash;
@@ -981,14 +983,13 @@ namespace TriangleNet
Vertex first; Vertex first;
Vertex leftvertex, rightvertex, botvertex, topvertex, farvertex; Vertex leftvertex, rightvertex, botvertex, topvertex, farvertex;
Vertex segmentorg, segmentdest; Vertex segmentorg, segmentdest;
double attrib; int region;
double area; double area;
InsertVertexResult success; InsertVertexResult success;
LocateResult intersect; LocateResult intersect;
bool doflip; bool doflip;
bool mirrorflag; bool mirrorflag;
bool enq; bool enq;
int i;
if (splitseg.seg == null) if (splitseg.seg == null)
{ {
@@ -1094,11 +1095,8 @@ namespace TriangleNet
newbotright.SetApex(newvertex); newbotright.SetApex(newvertex);
horiz.SetOrg(newvertex); horiz.SetOrg(newvertex);
for (i = 0; i < eextras; i++) // Set the region of a new triangle.
{ newbotright.triangle.region = botright.triangle.region;
// Set the element attributes of a new triangle.
newbotright.triangle.attributes[i] = botright.triangle.attributes[i];
}
if (behavior.VarArea) if (behavior.VarArea)
{ {
@@ -1114,11 +1112,8 @@ namespace TriangleNet
newtopright.SetApex(newvertex); newtopright.SetApex(newvertex);
topright.SetOrg(newvertex); topright.SetOrg(newvertex);
for (i = 0; i < eextras; i++) // Set the region of another new triangle.
{ newtopright.triangle.region = topright.triangle.region;
// Set the element attributes of another new triangle.
newtopright.triangle.attributes[i] = topright.triangle.attributes[i];
}
if (behavior.VarArea) if (behavior.VarArea)
{ {
@@ -1223,13 +1218,9 @@ namespace TriangleNet
newbotright.SetApex(newvertex); newbotright.SetApex(newvertex);
horiz.SetApex(newvertex); horiz.SetApex(newvertex);
for (i = 0; i < eextras; i++) // Set the region of the new triangles.
{ newbotleft.triangle.region = horiz.triangle.region;
// Set the element attributes of the new triangles. newbotright.triangle.region = horiz.triangle.region;
attrib = horiz.triangle.attributes[i];
newbotleft.triangle.attributes[i] = attrib;
newbotright.triangle.attributes[i] = attrib;
}
if (behavior.VarArea) if (behavior.VarArea)
{ {
@@ -1426,13 +1417,11 @@ namespace TriangleNet
top.SetDest(farvertex); top.SetDest(farvertex);
top.SetApex(leftvertex); top.SetApex(leftvertex);
for (i = 0; i < eextras; i++) // Assign region.
{ // TODO: check region ok (no Math.Min necessary)
// Take the average of the two triangles' attributes. region = Math.Min(top.triangle.region, horiz.triangle.region);
attrib = 0.5 * (top.triangle.attributes[i] + horiz.triangle.attributes[i]); top.triangle.region = region;
top.triangle.attributes[i] = attrib; horiz.triangle.region = region;
horiz.triangle.attributes[i] = attrib;
}
if (behavior.VarArea) if (behavior.VarArea)
{ {
+4
View File
@@ -152,6 +152,8 @@ namespace TriangleNet
private static decimal CounterClockwiseDecimal(Point pa, Point pb, Point pc) private static decimal CounterClockwiseDecimal(Point pa, Point pb, Point pc)
{ {
Statistic.CounterClockwiseCountDecimal++;
decimal detleft, detright, det, detsum; decimal detleft, detright, det, detsum;
detleft = ((decimal)pa.x - (decimal)pc.x) * ((decimal)pb.y - (decimal)pc.y); 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) private static decimal InCircleDecimal(Point pa, Point pb, Point pc, Point pd)
{ {
Statistic.InCircleCountDecimal++;
decimal adx, bdx, cdx, ady, bdy, cdy; decimal adx, bdx, cdx, ady, bdy, cdy;
decimal bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; decimal bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
decimal alift, blift, clift; decimal alift, blift, clift;
+2 -2
View File
@@ -724,7 +724,7 @@ namespace TriangleNet
split = 0.5; split = 0.5;
} }
// Create the new vertex. // Create the new vertex (interpolate coordinates).
newvertex = new Vertex( newvertex = new Vertex(
eorg.x + split * (edest.x - eorg.x), eorg.x + split * (edest.x - eorg.x),
eorg.y + split * (edest.y - eorg.y), eorg.y + split * (edest.y - eorg.y),
@@ -738,7 +738,7 @@ namespace TriangleNet
mesh.vertices.Add(newvertex.hash, newvertex); mesh.vertices.Add(newvertex.hash, newvertex);
// Interpolate its coordinate and attributes. // Interpolate attributes.
for (int i = 0; i < mesh.nextras; i++) for (int i = 0; i < mesh.nextras; i++)
{ {
newvertex.attributes[i] = eorg.attributes[i] newvertex.attributes[i] = eorg.attributes[i]
@@ -0,0 +1,139 @@
// -----------------------------------------------------------------------
// <copyright file="RegionIterator.cs" company="">
// Original Matlab code by John Burkardt, Florida State University
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
// </copyright>
// -----------------------------------------------------------------------
namespace TriangleNet.Tools
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TriangleNet.Data;
/// <summary>
/// Iterates the region a given triangle belongs to and applies an action
/// to each connected trianlge in that region. Default action is to set the
/// region id.
/// </summary>
public class RegionIterator
{
Mesh mesh;
List<Triangle> viri;
public RegionIterator(Mesh mesh)
{
this.mesh = mesh;
this.viri = new List<Triangle>();
}
/// <summary>
/// Spread regional attributes and/or area constraints (from a .poly file)
/// throughout the mesh.
/// </summary>
/// <param name="attribute"></param>
/// <param name="area"></param>
/// <remarks>
/// 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.
/// </remarks>
void ProcessRegion(Action<Triangle> func)
{
Otri testtri = default(Otri);
Otri neighbor = default(Otri);
Osub neighborsubseg = default(Osub);
Behavior behavior = mesh.behavior;
// Loop through all the infected triangles, spreading the attribute
// and/or area constraint to their neighbors, then to their neighbors'
// neighbors.
for (int i = 0; i < viri.Count; i++)
{
// WARNING: Don't use foreach, viri list gets modified.
testtri.triangle = viri[i];
// A triangle is marked as infected by messing with one of its pointers
// to subsegments, setting it to an illegal value. Hence, we have to
// temporarily uninfect this triangle so that we can examine its
// adjacent subsegments.
// TODO: Not true in the C# version (so we could skip this).
testtri.Uninfect();
// Apply function.
func(testtri.triangle);
// Check each of the triangle's three neighbors.
for (testtri.orient = 0; testtri.orient < 3; testtri.orient++)
{
// Find the neighbor.
testtri.Sym(ref neighbor);
// Check for a subsegment between the triangle and its neighbor.
testtri.SegPivot(ref neighborsubseg);
// Make sure the neighbor exists, is not already infected, and
// isn't protected by a subsegment.
if ((neighbor.triangle != Mesh.dummytri) && !neighbor.IsInfected()
&& (neighborsubseg.seg == Mesh.dummysub))
{
// Infect the neighbor.
neighbor.Infect();
// Ensure that the neighbor's neighbors will be infected.
viri.Add(neighbor.triangle);
}
}
// Remark the triangle as infected, so it doesn't get added to the
// virus pool again.
testtri.Infect();
}
// Uninfect all triangles.
foreach (var virus in viri)
{
virus.infected = false;
}
// Empty the virus pool.
viri.Clear();
}
/// <summary>
/// Set the region attribute of all trianlges connected to given triangle.
/// </summary>
public void Process(Triangle triangle)
{
// Default action is to just set the region id for all trianlges.
this.Process(triangle, (tri) => { tri.region = triangle.region; });
}
/// <summary>
/// Process all trianlges connected to given triangle and apply given action.
/// </summary>
public void Process(Triangle triangle, Action<Triangle> func)
{
if (triangle != Mesh.dummytri)
{
// Make sure the triangle under consideration still exists.
// It may have been eaten by the virus.
if (!Otri.IsDead(triangle))
{
// Put one triangle in the virus pool.
triangle.infected = true;
viri.Add(triangle);
// Apply one region's attribute and/or area constraint.
ProcessRegion(func);
// The virus pool should be empty now.
}
}
// Free up memory (virus pool should be empty anyway).
viri.Clear();
}
}
}
+2
View File
@@ -23,11 +23,13 @@ namespace TriangleNet.Tools
/// Number of incircle tests performed. /// Number of incircle tests performed.
/// </summary> /// </summary>
public static long InCircleCount = 0; public static long InCircleCount = 0;
public static long InCircleCountDecimal = 0;
/// <summary> /// <summary>
/// Number of counterclockwise tests performed. /// Number of counterclockwise tests performed.
/// </summary> /// </summary>
public static long CounterClockwiseCount = 0; public static long CounterClockwiseCount = 0;
public static long CounterClockwiseCountDecimal = 0;
/// <summary> /// <summary>
/// Number of 3D orientation tests performed. /// Number of 3D orientation tests performed.
+1
View File
@@ -87,6 +87,7 @@
<Compile Include="Tools\CuthillMcKee.cs" /> <Compile Include="Tools\CuthillMcKee.cs" />
<Compile Include="Tools\IVoronoi.cs" /> <Compile Include="Tools\IVoronoi.cs" />
<Compile Include="Tools\QualityMeasure.cs" /> <Compile Include="Tools\QualityMeasure.cs" />
<Compile Include="Tools\RegionIterator.cs" />
<Compile Include="Tools\Statistic.cs" /> <Compile Include="Tools\Statistic.cs" />
<Compile Include="Algorithm\SweepLine.cs" /> <Compile Include="Algorithm\SweepLine.cs" />
<Compile Include="Tools\Voronoi.cs" /> <Compile Include="Tools\Voronoi.cs" />