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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
</Compile>
|
||||
<Compile Include="Generators\BoxWithHole.cs" />
|
||||
<Compile Include="Generators\CircleWithHole.cs" />
|
||||
<Compile Include="Generators\IGenerator.cs" />
|
||||
<Compile Include="Generators\RandomPoints.cs" />
|
||||
<Compile Include="Generators\RandomPointsCircle.cs" />
|
||||
|
||||
+1
-1
@@ -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
|
||||
//
|
||||
|
||||
@@ -599,7 +599,6 @@ namespace TriangleNet.Algorithm
|
||||
/// <summary>
|
||||
/// Recursively form a Delaunay triangulation by the divide-and-conquer method.
|
||||
/// </summary>
|
||||
/// <param name="sortarray"></param>
|
||||
/// <param name="left"></param>
|
||||
/// <param name="right"></param>
|
||||
/// <param name="axis"></param>
|
||||
|
||||
@@ -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
|
||||
/// </summary>
|
||||
public bool Usertest { get; set; }
|
||||
/// <summary>
|
||||
/// Apply attributes to identify triangles in certain regions.
|
||||
/// Identify triangles in certain regions.
|
||||
/// </summary>
|
||||
public bool RegionAttrib { get; set; }
|
||||
public bool UseRegions { get; set; }
|
||||
/// <summary>
|
||||
/// Enclose the convex hull with segments.
|
||||
/// </summary>
|
||||
|
||||
+22
-124
@@ -11,6 +11,7 @@ namespace TriangleNet
|
||||
using System;
|
||||
using TriangleNet.Geometry;
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
/// <summary>
|
||||
/// Carves holes into the triangulation.
|
||||
@@ -18,10 +19,12 @@ namespace TriangleNet
|
||||
class Carver
|
||||
{
|
||||
Mesh mesh;
|
||||
List<Triangle> viri;
|
||||
|
||||
public Carver(Mesh mesh)
|
||||
{
|
||||
this.mesh = mesh;
|
||||
this.viri = new List<Triangle>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
/// <summary>
|
||||
@@ -171,11 +165,11 @@ namespace TriangleNet.Data
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the triangle attributes.
|
||||
/// Region ID the triangle belongs to.
|
||||
/// </summary>
|
||||
public double[] Attributes
|
||||
public int Region
|
||||
{
|
||||
get { return this.attributes; }
|
||||
get { return this.region; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -80,8 +80,8 @@ namespace TriangleNet.Geometry
|
||||
double Area { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Triangle atributes.
|
||||
/// Region ID the triangle belongs to.
|
||||
/// </summary>
|
||||
double[] Attributes { get; }
|
||||
int Region { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,11 +197,10 @@ namespace TriangleNet.Geometry
|
||||
/// </summary>
|
||||
/// <param name="x">X coordinate of the hole.</param>
|
||||
/// <param name="y">Y coordinate of the hole.</param>
|
||||
/// <param name="area">The regions area constraint.</param>
|
||||
/// <param name="attribute">Region attribute.</param>
|
||||
public void AddRegion(double x, double y, double area, double attribute)
|
||||
/// <param name="id">The region id.</param>
|
||||
public void AddRegion(double x, double y, int id)
|
||||
{
|
||||
regions.Add(new RegionPointer(x, y, area, attribute));
|
||||
regions.Add(new RegionPointer(x, y, id));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -16,45 +16,18 @@ namespace TriangleNet.Geometry
|
||||
public class RegionPointer
|
||||
{
|
||||
internal Point point;
|
||||
internal double area;
|
||||
internal double attribute;
|
||||
internal int id;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RegionPointer" /> class.
|
||||
/// </summary>
|
||||
/// <param name="x">X coordinate of the region.</param>
|
||||
/// <param name="y">Y coordinate of the region.</param>
|
||||
/// <param name="area">Area constraint.</param>
|
||||
/// <param name="attribute">Region attribute.</param>
|
||||
public RegionPointer(double x, double y, double area, double attribute)
|
||||
/// <param name="id">Region id.</param>
|
||||
public RegionPointer(double x, double y, int id)
|
||||
{
|
||||
this.point = new Point(x, y);
|
||||
this.area = area;
|
||||
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; }
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<ITriangle>(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);
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the triangle attributes.
|
||||
/// Region ID the triangle belongs to.
|
||||
/// </summary>
|
||||
public double[] Attributes
|
||||
public int Region
|
||||
{
|
||||
get { return null; }
|
||||
get { return region; }
|
||||
set { region = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -48,8 +48,6 @@ namespace TriangleNet
|
||||
internal List<Point> holes;
|
||||
internal List<RegionPointer> regions;
|
||||
|
||||
internal List<Triangle> 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<int, Triangle>();
|
||||
subsegs = new Dictionary<int, Segment>();
|
||||
|
||||
viri = new List<Triangle>();
|
||||
flipstack = new Stack<Otri>();
|
||||
|
||||
holes = new List<Point>();
|
||||
@@ -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
|
||||
/// <param name="newotri">Reference to the new triangle.</param>
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,11 +23,13 @@ namespace TriangleNet.Tools
|
||||
/// Number of incircle tests performed.
|
||||
/// </summary>
|
||||
public static long InCircleCount = 0;
|
||||
public static long InCircleCountDecimal = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Number of counterclockwise tests performed.
|
||||
/// </summary>
|
||||
public static long CounterClockwiseCount = 0;
|
||||
public static long CounterClockwiseCountDecimal = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Number of 3D orientation tests performed.
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
<Compile Include="Tools\CuthillMcKee.cs" />
|
||||
<Compile Include="Tools\IVoronoi.cs" />
|
||||
<Compile Include="Tools\QualityMeasure.cs" />
|
||||
<Compile Include="Tools\RegionIterator.cs" />
|
||||
<Compile Include="Tools\Statistic.cs" />
|
||||
<Compile Include="Algorithm\SweepLine.cs" />
|
||||
<Compile Include="Tools\Voronoi.cs" />
|
||||
|
||||
Reference in New Issue
Block a user