More code reorganization (3)
git-svn-id: https://triangle.svn.codeplex.com/svn@75023 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
@@ -1,11 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
|
||||
|
||||
namespace MeshRenderer.Core
|
||||
{
|
||||
using System.Drawing;
|
||||
using Rectangle = TriangleNet.Geometry.Rectangle;
|
||||
|
||||
public struct BoundingBox
|
||||
{
|
||||
public float Left;
|
||||
@@ -31,6 +29,14 @@ namespace MeshRenderer.Core
|
||||
this.Top = top;
|
||||
}
|
||||
|
||||
public BoundingBox(Rectangle rectangle)
|
||||
{
|
||||
this.Left = (float)rectangle.Left;
|
||||
this.Right = (float)rectangle.Right;
|
||||
this.Bottom = (float)rectangle.Bottom;
|
||||
this.Top = (float)rectangle.Top;
|
||||
}
|
||||
|
||||
public void Update(Point pt)
|
||||
{
|
||||
this.Update(pt.X, pt.Y);
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace MeshRenderer.Core
|
||||
using TriangleNet;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Tools;
|
||||
using TriangleNet.Meshing.Iterators;
|
||||
|
||||
/// <summary>
|
||||
/// Stores the current mesh in a rendering friendly data structure.
|
||||
@@ -31,7 +32,7 @@ namespace MeshRenderer.Core
|
||||
/// <summary>
|
||||
/// Copy input geometry data.
|
||||
/// </summary>
|
||||
public void SetInputGeometry(InputGeometry data)
|
||||
public void SetInputGeometry(IPolygon data)
|
||||
{
|
||||
// Clear unused buffers
|
||||
this.Segments = null;
|
||||
@@ -40,7 +41,7 @@ namespace MeshRenderer.Core
|
||||
this.VoronoiPoints = null;
|
||||
this.VoronoiEdges = null;
|
||||
|
||||
int n = data.Count;
|
||||
int n = data.Points.Count;
|
||||
int i = 0;
|
||||
|
||||
this.NumberOfRegions = data.Regions.Count;
|
||||
@@ -68,11 +69,7 @@ namespace MeshRenderer.Core
|
||||
this.Segments = segments.ToArray();
|
||||
}
|
||||
|
||||
this.Bounds = new BoundingBox(
|
||||
(float)data.Bounds.Left,
|
||||
(float)data.Bounds.Right,
|
||||
(float)data.Bounds.Bottom,
|
||||
(float)data.Bounds.Top);
|
||||
this.Bounds = new BoundingBox(data.Bounds());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -118,14 +115,14 @@ namespace MeshRenderer.Core
|
||||
// Copy edges
|
||||
var edges = new List<uint>(2 * mesh.NumberOfEdges);
|
||||
|
||||
EdgeEnumerator e = new EdgeEnumerator(mesh);
|
||||
var e = new EdgeIterator(mesh);
|
||||
while (e.MoveNext())
|
||||
{
|
||||
edges.Add((uint)e.Current.P0);
|
||||
edges.Add((uint)e.Current.P1);
|
||||
}
|
||||
this.MeshEdges = edges.ToArray();
|
||||
|
||||
this.MeshEdges = edges.ToArray();
|
||||
|
||||
if (this.NumberOfRegions > 0)
|
||||
{
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace MeshExplorer
|
||||
{
|
||||
try
|
||||
{
|
||||
InputGeometry input = currentGenerator.Generate(sliderParam1.Value,
|
||||
var input = currentGenerator.Generate(sliderParam1.Value,
|
||||
sliderParam2.Value, sliderParam3.Value);
|
||||
|
||||
InputGenerated(input, EventArgs.Empty);
|
||||
|
||||
@@ -8,7 +8,9 @@ using MeshExplorer.IO;
|
||||
using MeshRenderer.Core;
|
||||
using TriangleNet;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Logging;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Meshing.Algorithm;
|
||||
using TriangleNet.Smoothing;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
namespace MeshExplorer
|
||||
@@ -16,7 +18,7 @@ namespace MeshExplorer
|
||||
public partial class FormMain : Form
|
||||
{
|
||||
Settings settings;
|
||||
InputGeometry input;
|
||||
IPolygon input;
|
||||
Mesh mesh;
|
||||
|
||||
FormLog frmLog;
|
||||
@@ -108,7 +110,7 @@ namespace MeshExplorer
|
||||
|
||||
void frmGenerator_InputGenerated(object sender, EventArgs e)
|
||||
{
|
||||
this.input = sender as InputGeometry;
|
||||
this.input = sender as IPolygon;
|
||||
|
||||
if (input != null)
|
||||
{
|
||||
@@ -442,29 +444,25 @@ namespace MeshExplorer
|
||||
|
||||
//Stopwatch sw = new Stopwatch();
|
||||
|
||||
mesh = new Mesh();
|
||||
var options = new ConstraintOptions();
|
||||
var quality = new QualityOptions();
|
||||
|
||||
if (meshControlView.ParamConformDelChecked)
|
||||
{
|
||||
mesh.Behavior.ConformingDelaunay = true;
|
||||
}
|
||||
|
||||
if (meshControlView.ParamSweeplineChecked)
|
||||
{
|
||||
mesh.Behavior.Algorithm = TriangulationAlgorithm.SweepLine;
|
||||
options.ConformingDelaunay = true;
|
||||
}
|
||||
|
||||
if (meshControlView.ParamQualityChecked)
|
||||
{
|
||||
mesh.Behavior.Quality = true;
|
||||
//mesh.Behavior.Quality = true;
|
||||
|
||||
mesh.Behavior.MinAngle = meshControlView.ParamMinAngleValue;
|
||||
quality.MinimumAngle = meshControlView.ParamMinAngleValue;
|
||||
|
||||
double maxAngle = meshControlView.ParamMaxAngleValue;
|
||||
|
||||
if (maxAngle < 180)
|
||||
{
|
||||
mesh.Behavior.MaxAngle = maxAngle;
|
||||
quality.MaximumAngle = maxAngle;
|
||||
}
|
||||
|
||||
// Ignore area constraints on initial triangulation.
|
||||
@@ -474,19 +472,26 @@ namespace MeshExplorer
|
||||
//{
|
||||
// var size = input.Bounds;
|
||||
// double min = Math.Min(size.Width, size.Height);
|
||||
// mesh.Behavior.MaxArea, area * min);
|
||||
// mesh.SetOption(Options.MaxArea, area * min);
|
||||
//}
|
||||
}
|
||||
|
||||
if (meshControlView.ParamConvexChecked)
|
||||
{
|
||||
mesh.Behavior.Convex = true;
|
||||
options.Convex = true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
//sw.Start();
|
||||
mesh.Triangulate(input);
|
||||
if (meshControlView.ParamSweeplineChecked)
|
||||
{
|
||||
mesh = (Mesh)input.Triangulate(options, quality, new SweepLine());
|
||||
}
|
||||
else
|
||||
{
|
||||
mesh = (Mesh)input.Triangulate(options, quality);
|
||||
}
|
||||
//sw.Stop();
|
||||
|
||||
statisticView.UpdateStatistic(mesh);
|
||||
@@ -515,24 +520,26 @@ namespace MeshExplorer
|
||||
|
||||
double area = meshControlView.ParamMaxAreaValue;
|
||||
|
||||
var quality = new QualityOptions();
|
||||
|
||||
if (area > 0 && area < 1)
|
||||
{
|
||||
mesh.Behavior.MaxArea = area * statisticView.Statistic.LargestArea;
|
||||
quality.MaximumArea = area * statisticView.Statistic.LargestArea;
|
||||
}
|
||||
|
||||
mesh.Behavior.MinAngle = meshControlView.ParamMinAngleValue;
|
||||
quality.MinimumAngle = meshControlView.ParamMinAngleValue;
|
||||
|
||||
double maxAngle = meshControlView.ParamMaxAngleValue;
|
||||
|
||||
if (maxAngle < 180)
|
||||
{
|
||||
mesh.Behavior.MaxAngle = maxAngle;
|
||||
quality.MaximumAngle = maxAngle;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
sw.Start();
|
||||
mesh.Refine();
|
||||
mesh.Refine(quality);
|
||||
sw.Stop();
|
||||
|
||||
statisticView.UpdateStatistic(mesh);
|
||||
@@ -572,10 +579,12 @@ namespace MeshExplorer
|
||||
|
||||
Stopwatch sw = new Stopwatch();
|
||||
|
||||
var smoother = new SimpleSmoother();
|
||||
|
||||
try
|
||||
{
|
||||
sw.Start();
|
||||
mesh.Smooth();
|
||||
smoother.Smooth(this.mesh);
|
||||
sw.Stop();
|
||||
|
||||
statisticView.UpdateStatistic(mesh);
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using MeshExplorer.Topology;
|
||||
using TriangleNet;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
namespace MeshExplorer
|
||||
@@ -25,10 +21,8 @@ namespace MeshExplorer
|
||||
|
||||
private void FormTopology_Load(object sender, EventArgs e)
|
||||
{
|
||||
var geometry = RectanglePolygon.Generate(4);
|
||||
|
||||
mesh = new Mesh();
|
||||
mesh.Triangulate(geometry);
|
||||
var mesher = new GenericMesher();
|
||||
mesh = (Mesh)mesher.StructurdMesh(new Rectangle(0.0, 0.0, 4.0, 4.0), 4, 4);
|
||||
|
||||
renderControl.Initialize(mesh);
|
||||
|
||||
@@ -75,23 +69,6 @@ namespace MeshExplorer
|
||||
return tree.Query(p.X, p.Y);
|
||||
}
|
||||
|
||||
private bool TriangleContainsPoint(ITriangle triangle, float x, float y)
|
||||
{
|
||||
bool t1, t2, t3;
|
||||
|
||||
t1 = Sign(x, y, triangle.GetVertex(0), triangle.GetVertex(1)) < 0.0;
|
||||
t2 = Sign(x, y, triangle.GetVertex(1), triangle.GetVertex(2)) < 0.0;
|
||||
t3 = Sign(x, y, triangle.GetVertex(2), triangle.GetVertex(0)) < 0.0;
|
||||
|
||||
return (t1 == t2) && (t2 == t3);
|
||||
}
|
||||
|
||||
private double Sign(double x, double y, Point p, Point q)
|
||||
{
|
||||
return (x - q.X) * (p.Y - q.Y) - (p.X - q.X) * (y - q.Y);
|
||||
}
|
||||
|
||||
|
||||
private void InvokePrimitive(string name)
|
||||
{
|
||||
if (name == "sym")
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
namespace MeshExplorer.Generators
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
@@ -53,7 +50,7 @@ namespace MeshExplorer.Generators
|
||||
return num.ToString();
|
||||
}
|
||||
|
||||
public abstract InputGeometry Generate(double param0, double param1, double param2);
|
||||
public abstract IPolygon Generate(double param0, double param1, double param2);
|
||||
|
||||
protected int GetParamValueInt(int paramIndex, double paramOffset)
|
||||
{
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
namespace MeshExplorer.Generators
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
@@ -32,11 +29,11 @@ namespace MeshExplorer.Generators
|
||||
ranges[2] = new int[] { 5, 20 };
|
||||
}
|
||||
|
||||
public override InputGeometry Generate(double param0, double param1, double param2)
|
||||
public override IPolygon Generate(double param0, double param1, double param2)
|
||||
{
|
||||
int numPoints = GetParamValueInt(1, param1);
|
||||
|
||||
InputGeometry input = new InputGeometry(numPoints + 4);
|
||||
var input = new Polygon(numPoints + 4);
|
||||
|
||||
double x, y, step = 2 * Math.PI / numPoints;
|
||||
|
||||
@@ -48,11 +45,11 @@ namespace MeshExplorer.Generators
|
||||
x = r * Math.Cos(i * step);
|
||||
y = r * Math.Sin(i * step);
|
||||
|
||||
input.AddPoint(x, y, 2);
|
||||
input.AddSegment(i, (i + 1) % numPoints, 2);
|
||||
input.Add(new Vertex(x, y, 2));
|
||||
input.Add(new Edge(i, (i + 1) % numPoints, 2));
|
||||
}
|
||||
|
||||
numPoints = input.Count;
|
||||
numPoints = input.Points.Count;
|
||||
|
||||
int numPointsB = GetParamValueInt(0, param0);
|
||||
|
||||
@@ -62,38 +59,38 @@ namespace MeshExplorer.Generators
|
||||
// Left box boundary points
|
||||
for (int i = 0; i < numPointsB; i++)
|
||||
{
|
||||
input.AddPoint(-50, -50 + i * step, 1);
|
||||
input.Add(new Vertex(-50, -50 + i * step, 1));
|
||||
}
|
||||
|
||||
// Top box boundary points
|
||||
for (int i = 0; i < numPointsB; i++)
|
||||
{
|
||||
input.AddPoint(-50 + i * step, 50, 1);
|
||||
input.Add(new Vertex(-50 + i * step, 50, 1));
|
||||
}
|
||||
|
||||
// Right box boundary points
|
||||
for (int i = 0; i < numPointsB; i++)
|
||||
{
|
||||
input.AddPoint(50, 50 - i * step, 1);
|
||||
input.Add(new Vertex(50, 50 - i * step, 1));
|
||||
}
|
||||
|
||||
// Bottom box boundary points
|
||||
for (int i = 0; i < numPointsB; i++)
|
||||
{
|
||||
input.AddPoint(50 - i * step, -50, 1);
|
||||
input.Add(new Vertex(50 - i * step, -50, 1));
|
||||
}
|
||||
|
||||
// Add box segments
|
||||
for (int i = numPoints; i < input.Count - 1; i++)
|
||||
{
|
||||
input.AddSegment(i, i + 1, 1);
|
||||
input.Add(new Edge(i, i + 1, 1));
|
||||
}
|
||||
|
||||
// Add last segments which closes the box
|
||||
input.AddSegment(input.Count - 1, numPoints, 1);
|
||||
input.Add(new Edge(input.Count - 1, numPoints, 1));
|
||||
|
||||
// Add hole
|
||||
input.AddHole(0, 0);
|
||||
input.Holes.Add(new Point(0, 0));
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace MeshExplorer.Generators
|
||||
ranges[1] = new int[] { 2, 15 };
|
||||
}
|
||||
|
||||
public override InputGeometry Generate(double param0, double param1, double param2)
|
||||
public override IPolygon Generate(double param0, double param1, double param2)
|
||||
{
|
||||
// Number of points on the outer circle
|
||||
int n = GetParamValueInt(0, param0);
|
||||
@@ -44,7 +44,7 @@ namespace MeshExplorer.Generators
|
||||
// Current radius and step size
|
||||
double r, dphi;
|
||||
|
||||
InputGeometry input = new InputGeometry(n + 1);
|
||||
var input = new Polygon(n + 1);
|
||||
|
||||
// Inner cirlce (radius = 1)
|
||||
r = 1;
|
||||
@@ -52,8 +52,8 @@ namespace MeshExplorer.Generators
|
||||
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);
|
||||
input.Add(new Vertex(r * Math.Cos(i * dphi), r * Math.Sin(i * dphi), 1));
|
||||
input.Add(new Edge(i, (i + 1) % npoints, 1));
|
||||
}
|
||||
|
||||
count = input.Count;
|
||||
@@ -64,8 +64,8 @@ namespace MeshExplorer.Generators
|
||||
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);
|
||||
input.Add(new Vertex(r * Math.Cos(i * dphi), r * Math.Sin(i * dphi), 2));
|
||||
input.Add(new Edge(count + i, count + (i + 1) % npoints, 2));
|
||||
}
|
||||
|
||||
count = input.Count;
|
||||
@@ -76,17 +76,17 @@ namespace MeshExplorer.Generators
|
||||
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.Add(new Vertex(r * Math.Cos(i * dphi), r * Math.Sin(i * dphi), 3));
|
||||
input.Add(new Edge(count + i, count + (i + 1) % npoints, 3));
|
||||
}
|
||||
|
||||
input.AddHole(0, 0);
|
||||
input.Holes.Add(new Point(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);
|
||||
input.Regions.Add(new RegionPointer((r + 3.0) / 4.0, 0, 1));
|
||||
input.Regions.Add(new RegionPointer((3 * r + 1.0) / 4.0, 0, 2));
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
@@ -6,10 +6,6 @@
|
||||
|
||||
namespace MeshExplorer.Generators
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
@@ -22,6 +18,6 @@ namespace MeshExplorer.Generators
|
||||
int ParameterCount { get; }
|
||||
string ParameterDescription(int paramIndex);
|
||||
string ParameterDescription(int paramIndex, double paramValue);
|
||||
InputGeometry Generate(double param1, double param2, double param3);
|
||||
IPolygon Generate(double param1, double param2, double param3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,6 @@
|
||||
|
||||
namespace MeshExplorer.Generators
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
@@ -32,7 +28,7 @@ namespace MeshExplorer.Generators
|
||||
ranges[2] = new int[] { 10, 200 };
|
||||
}
|
||||
|
||||
public override InputGeometry Generate(double param0, double param1, double param2)
|
||||
public override IPolygon Generate(double param0, double param1, double param2)
|
||||
{
|
||||
int numPoints = GetParamValueInt(0, param0);
|
||||
numPoints = (numPoints / 10) * 10;
|
||||
@@ -42,15 +38,15 @@ namespace MeshExplorer.Generators
|
||||
numPoints = 5;
|
||||
}
|
||||
|
||||
InputGeometry input = new InputGeometry(numPoints);
|
||||
var input = new Polygon(numPoints);
|
||||
|
||||
int width = GetParamValueInt(1, param1);
|
||||
int height = GetParamValueInt(2, param2);
|
||||
|
||||
for (int i = 0; i < numPoints; i++)
|
||||
{
|
||||
input.AddPoint(Util.Random.NextDouble() * width,
|
||||
Util.Random.NextDouble() * height);
|
||||
input.Add(new Vertex(Util.Random.NextDouble() * width,
|
||||
Util.Random.NextDouble() * height));
|
||||
}
|
||||
|
||||
return input;
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
namespace MeshExplorer.Generators
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
@@ -60,7 +57,7 @@ namespace MeshExplorer.Generators
|
||||
return "";
|
||||
}
|
||||
|
||||
public override InputGeometry Generate(double param0, double param1, double param2)
|
||||
public override IPolygon Generate(double param0, double param1, double param2)
|
||||
{
|
||||
int numPoints = GetParamValueInt(0, param0);
|
||||
numPoints = (numPoints / 10) * 10;
|
||||
@@ -72,7 +69,7 @@ namespace MeshExplorer.Generators
|
||||
|
||||
double exp = (param1 + 10) / 100;
|
||||
|
||||
InputGeometry input = new InputGeometry(numPoints);
|
||||
var input = new Polygon(numPoints);
|
||||
|
||||
int i = 0, cNum = 2 * (int)Math.Floor(Math.Sqrt(numPoints));
|
||||
|
||||
@@ -84,8 +81,8 @@ namespace MeshExplorer.Generators
|
||||
// Add a little error
|
||||
r = Util.Random.NextDouble();
|
||||
|
||||
input.AddPoint((radius + r) * Math.Cos(i * step),
|
||||
(radius + r) * Math.Sin(i * step));
|
||||
input.Add(new Vertex((radius + r) * Math.Cos(i * step),
|
||||
(radius + r) * Math.Sin(i * step)));
|
||||
}
|
||||
|
||||
for (; i < numPoints; i++)
|
||||
@@ -94,7 +91,7 @@ namespace MeshExplorer.Generators
|
||||
r = Math.Pow(Util.Random.NextDouble(), exp) * radius;
|
||||
phi = Util.Random.NextDouble() * Math.PI * 2;
|
||||
|
||||
input.AddPoint(r * Math.Cos(phi), r * Math.Sin(phi));
|
||||
input.Add(new Vertex(r * Math.Cos(phi), r * Math.Sin(phi)));
|
||||
}
|
||||
|
||||
return input;
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
namespace MeshExplorer.Generators
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
@@ -47,12 +44,12 @@ namespace MeshExplorer.Generators
|
||||
return "";
|
||||
}
|
||||
|
||||
public override InputGeometry Generate(double param0, double param1, double param2)
|
||||
public override IPolygon Generate(double param0, double param1, double param2)
|
||||
{
|
||||
int n = GetParamValueInt(0, param0);
|
||||
int m = n / 2;
|
||||
|
||||
InputGeometry input = new InputGeometry(n + 1);
|
||||
var input = new Polygon(n + 1);
|
||||
|
||||
double ro, r = 10;
|
||||
double step = 2 * Math.PI / m;
|
||||
@@ -60,8 +57,8 @@ namespace MeshExplorer.Generators
|
||||
// Inner ring
|
||||
for (int i = 0; i < m; i++)
|
||||
{
|
||||
input.AddPoint(r * Math.Cos(i * step), r * Math.Sin(i * step));
|
||||
input.AddSegment(i, (i + 1) % m, 1);
|
||||
input.Add(new Vertex(r * Math.Cos(i * step), r * Math.Sin(i * step)));
|
||||
input.Add(new Edge(i, (i + 1) % m, 1));
|
||||
}
|
||||
|
||||
r = 1.5 * r;
|
||||
@@ -80,11 +77,11 @@ namespace MeshExplorer.Generators
|
||||
ro = r + r * Util.Random.NextDouble() * (param1 / 100);
|
||||
}
|
||||
|
||||
input.AddPoint(ro * Math.Cos(i * step + offset), ro * Math.Sin(i * step + offset));
|
||||
input.AddSegment(m + i, m + ((i + 1) % n), 2);
|
||||
input.Add(new Vertex(ro * Math.Cos(i * step + offset), ro * Math.Sin(i * step + offset)));
|
||||
input.Add(new Edge(m + i, m + ((i + 1) % n), 2));
|
||||
}
|
||||
|
||||
input.AddHole(0, 0);
|
||||
input.Holes.Add(new Point(0, 0));
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
namespace MeshExplorer.Generators
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
@@ -28,13 +25,13 @@ namespace MeshExplorer.Generators
|
||||
ranges[0] = new int[] { 3, 61 };
|
||||
}
|
||||
|
||||
public override InputGeometry Generate(double param0, double param1, double param2)
|
||||
public override IPolygon Generate(double param0, double param1, double param2)
|
||||
{
|
||||
int numRays = GetParamValueInt(0, param0);
|
||||
|
||||
InputGeometry input = new InputGeometry(numRays + 4);
|
||||
var input = new Polygon(numRays + 4);
|
||||
|
||||
input.AddPoint(0, 0); // Center
|
||||
input.Add(new Vertex(0, 0)); // Center
|
||||
|
||||
double x, y, r, e, step = 2 * Math.PI / numRays;
|
||||
|
||||
@@ -45,20 +42,20 @@ namespace MeshExplorer.Generators
|
||||
x = r * Math.Cos(i * step + e);
|
||||
y = r * Math.Sin(i * step + e);
|
||||
|
||||
input.AddPoint(x, y, 2);
|
||||
input.AddSegment(0, i + 1, 2);
|
||||
input.Add(new Vertex(x, y, 2));
|
||||
input.Add(new Edge(0, i + 1, 2));
|
||||
}
|
||||
|
||||
input.AddPoint(-1, -1, 1); // Box
|
||||
input.AddPoint(1, -1, 1);
|
||||
input.AddPoint(1, 1, 1);
|
||||
input.AddPoint(-1, 1, 1);
|
||||
input.Add(new Vertex(-1, -1, 1)); // Box
|
||||
input.Add(new Vertex(1, -1, 1));
|
||||
input.Add(new Vertex(1, 1, 1));
|
||||
input.Add(new Vertex(-1, 1, 1));
|
||||
|
||||
numRays = input.Count;
|
||||
input.AddSegment(numRays - 1, numRays - 2, 1);
|
||||
input.AddSegment(numRays - 2, numRays - 3, 1);
|
||||
input.AddSegment(numRays - 3, numRays - 4, 1);
|
||||
input.AddSegment(numRays - 4, numRays - 1, 1);
|
||||
input.Add(new Edge(numRays - 1, numRays - 2, 1));
|
||||
input.Add(new Edge(numRays - 2, numRays - 3, 1));
|
||||
input.Add(new Edge(numRays - 3, numRays - 4, 1));
|
||||
input.Add(new Edge(numRays - 4, numRays - 1, 1));
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
@@ -51,9 +51,9 @@ namespace MeshExplorer.IO
|
||||
/// <summary>
|
||||
/// Read an input geometry from given file.
|
||||
/// </summary>
|
||||
public static InputGeometry Read(string path)
|
||||
public static IPolygon Read(string path)
|
||||
{
|
||||
IMeshFile provider = GetProviderInstance(path);
|
||||
var provider = GetProviderInstance(path);
|
||||
|
||||
return provider.Read(path);
|
||||
}
|
||||
@@ -65,9 +65,9 @@ namespace MeshExplorer.IO
|
||||
/// <returns></returns>
|
||||
public static Mesh Import(string path)
|
||||
{
|
||||
IMeshFile provider = GetProviderInstance(path);
|
||||
var provider = GetProviderInstance(path);
|
||||
|
||||
return provider.Import(path);
|
||||
return (Mesh)provider.Import(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -80,9 +80,9 @@ namespace MeshExplorer.IO.Formats
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Mesh Import(string filename)
|
||||
public IMesh Import(string filename)
|
||||
{
|
||||
InputGeometry geometry = this.Read(filename);
|
||||
var geometry = (Polygon)this.Read(filename);
|
||||
|
||||
List<ITriangle> triangles = null;
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace MeshExplorer.IO.Formats
|
||||
|
||||
if (tri != null)
|
||||
{
|
||||
triangles = ReadTriangles(tri, geometry.Count);
|
||||
triangles = ReadTriangles(tri, geometry.Points.Count);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace MeshExplorer.IO.Formats
|
||||
return converter.ToMesh(geometry, triangles);
|
||||
}
|
||||
|
||||
public void Write(Mesh mesh, string filename)
|
||||
public void Write(IMesh mesh, string filename)
|
||||
{
|
||||
using (StreamWriter writer = new StreamWriter(filename))
|
||||
{
|
||||
@@ -119,16 +119,16 @@ namespace MeshExplorer.IO.Formats
|
||||
writer.Write("\"dim\":2");
|
||||
writer.Write("}");
|
||||
|
||||
if (mesh.CurrentNumbering == NodeNumbering.None)
|
||||
if (((Mesh)mesh).CurrentNumbering == NodeNumbering.None)
|
||||
{
|
||||
mesh.Renumber(NodeNumbering.Linear);
|
||||
((Mesh)mesh).Renumber(NodeNumbering.Linear);
|
||||
}
|
||||
|
||||
// Write the coordinates
|
||||
if (nv > 0)
|
||||
{
|
||||
writer.Write(",");
|
||||
WritePoints(mesh, writer, nv);
|
||||
WritePoints((Mesh)mesh, writer, nv);
|
||||
}
|
||||
|
||||
// Write the segments
|
||||
@@ -156,7 +156,7 @@ namespace MeshExplorer.IO.Formats
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(Mesh mesh, StreamWriter stream)
|
||||
public void Write(IMesh mesh, StreamWriter stream)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -166,11 +166,11 @@ namespace MeshExplorer.IO.Formats
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <returns></returns>
|
||||
public InputGeometry Read(string filename)
|
||||
public IPolygon Read(string filename)
|
||||
{
|
||||
ParseJson(filename);
|
||||
|
||||
InputGeometry data = new InputGeometry();
|
||||
var data = new Polygon();
|
||||
|
||||
if (json == null)
|
||||
{
|
||||
@@ -223,12 +223,12 @@ namespace MeshExplorer.IO.Formats
|
||||
return data;
|
||||
}
|
||||
|
||||
public void Write(InputGeometry polygon, string filename)
|
||||
public void Write(IPolygon polygon, string filename)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Write(InputGeometry polygon, StreamWriter stream)
|
||||
public void Write(IPolygon polygon, StreamWriter stream)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -248,7 +248,7 @@ namespace MeshExplorer.IO.Formats
|
||||
|
||||
#region Read helpers
|
||||
|
||||
private void ReadPoints(InputGeometry geometry, Dictionary<string, object> points, ref int count)
|
||||
private void ReadPoints(Polygon geometry, Dictionary<string, object> points, ref int count)
|
||||
{
|
||||
ArrayList data = points["data"] as ArrayList;
|
||||
|
||||
@@ -286,16 +286,16 @@ namespace MeshExplorer.IO.Formats
|
||||
mark = int.Parse(markers[i / 2].ToString());
|
||||
}
|
||||
|
||||
geometry.AddPoint(
|
||||
geometry.Add(new Vertex(
|
||||
double.Parse(data[i].ToString(), Util.Nfi),
|
||||
double.Parse(data[i + 1].ToString(), Util.Nfi),
|
||||
mark
|
||||
);
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadSegments(InputGeometry geometry, Dictionary<string, object> segments, int count)
|
||||
private void ReadSegments(Polygon geometry, Dictionary<string, object> segments, int count)
|
||||
{
|
||||
ArrayList data = segments["data"] as ArrayList;
|
||||
|
||||
@@ -334,12 +334,12 @@ namespace MeshExplorer.IO.Formats
|
||||
throw new Exception("JSON format error (segment index).");
|
||||
}
|
||||
|
||||
geometry.AddSegment(p0, p1, mark);
|
||||
geometry.Add(new Edge(p0, p1, mark));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadHoles(InputGeometry geometry, ArrayList holes)
|
||||
private void ReadHoles(Polygon geometry, ArrayList holes)
|
||||
{
|
||||
int n = holes.Count;
|
||||
|
||||
@@ -350,10 +350,10 @@ namespace MeshExplorer.IO.Formats
|
||||
|
||||
for (int i = 0; i < n; i += 2)
|
||||
{
|
||||
geometry.AddHole(
|
||||
geometry.Holes.Add(new Point(
|
||||
double.Parse(holes[i].ToString(), Util.Nfi),
|
||||
double.Parse(holes[i + 1].ToString(), Util.Nfi)
|
||||
);
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@ namespace MeshExplorer.IO.Formats
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using TriangleNet;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.IO;
|
||||
using TriangleNet.Meshing;
|
||||
|
||||
/// <summary>
|
||||
/// Read and write files defined in classic Triangle format.
|
||||
@@ -47,27 +47,27 @@ namespace MeshExplorer.IO.Formats
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public InputGeometry Read(string filename)
|
||||
public IPolygon Read(string filename)
|
||||
{
|
||||
return format.Read(filename);
|
||||
}
|
||||
|
||||
public void Write(InputGeometry polygon, string filename)
|
||||
public void Write(IPolygon polygon, string filename)
|
||||
{
|
||||
format.Write(polygon, filename);
|
||||
}
|
||||
|
||||
public void Write(InputGeometry polygon, StreamWriter stream)
|
||||
public void Write(IPolygon polygon, StreamWriter stream)
|
||||
{
|
||||
format.Write(polygon, stream);
|
||||
}
|
||||
|
||||
public Mesh Import(string filename)
|
||||
public IMesh Import(string filename)
|
||||
{
|
||||
return format.Import(filename);
|
||||
}
|
||||
|
||||
public void Write(Mesh mesh, string filename)
|
||||
public void Write(IMesh mesh, string filename)
|
||||
{
|
||||
if (mesh.Vertices.Count > 0)
|
||||
{
|
||||
@@ -75,9 +75,9 @@ namespace MeshExplorer.IO.Formats
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(Mesh mesh, StreamWriter stream)
|
||||
public void Write(IMesh mesh, StreamWriter stream)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
format.Write(mesh, stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ namespace MeshExplorer.Topology
|
||||
|
||||
internal static class RectanglePolygon
|
||||
{
|
||||
public static InputGeometry Generate(int n, double bounds = 10.0)
|
||||
public static IPolygon Generate(int n, double bounds = 10.0)
|
||||
{
|
||||
var geometry = new InputGeometry((n + 1) * (n + 1));
|
||||
var geometry = new Polygon((n + 1) * (n + 1));
|
||||
|
||||
double x, y, d = 2 * bounds / n;
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace MeshExplorer.Topology
|
||||
{
|
||||
x = -bounds + j * d;
|
||||
|
||||
geometry.AddPoint(x, y, mark);
|
||||
geometry.Add(new Vertex(x, y, mark));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,16 +29,16 @@ namespace MeshExplorer.Topology
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
// Bottom
|
||||
geometry.AddSegment(i, i + 1);
|
||||
geometry.Add(new Edge(i, i + 1));
|
||||
|
||||
// Right
|
||||
geometry.AddSegment(i * (n + 1) + n, (i + 1) * (n + 1) + n);
|
||||
geometry.Add(new Edge(i * (n + 1) + n, (i + 1) * (n + 1) + n));
|
||||
|
||||
// Top
|
||||
geometry.AddSegment(n * (n + 1) + i, n * (n + 1) + (i + 1));
|
||||
geometry.Add(new Edge(n * (n + 1) + i, n * (n + 1) + (i + 1)));
|
||||
|
||||
// Left
|
||||
geometry.AddSegment(i * (n + 1), (i + 1) * (n + 1));
|
||||
geometry.Add(new Edge(i * (n + 1), (i + 1) * (n + 1)));
|
||||
}
|
||||
|
||||
return geometry;
|
||||
|
||||
+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 (2013-06-18)\r\nChristian Woltering\r\nMIT";
|
||||
this.label19.Text = "Beta 4 (2014-05-30)\r\nChristian Woltering\r\nMIT";
|
||||
//
|
||||
// label18
|
||||
//
|
||||
|
||||
@@ -32,11 +32,11 @@ namespace MeshExplorer.Views
|
||||
|
||||
#region IView
|
||||
|
||||
public void HandleNewInput(InputGeometry geometry)
|
||||
public void HandleNewInput(IPolygon geometry)
|
||||
{
|
||||
}
|
||||
|
||||
public void HandleMeshImport(InputGeometry geometry, Mesh mesh)
|
||||
public void HandleMeshImport(IPolygon geometry, Mesh mesh)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ namespace MeshExplorer.Views
|
||||
/// </summary>
|
||||
public interface IView
|
||||
{
|
||||
void HandleNewInput(InputGeometry geometry);
|
||||
void HandleMeshImport(InputGeometry geometry, Mesh mesh);
|
||||
void HandleNewInput(IPolygon geometry);
|
||||
void HandleMeshImport(IPolygon geometry, Mesh mesh);
|
||||
void HandleMeshUpdate(Mesh mesh);
|
||||
void HandleMeshChange(Mesh mesh);
|
||||
}
|
||||
|
||||
@@ -76,11 +76,11 @@ namespace MeshExplorer.Views
|
||||
|
||||
#region IView
|
||||
|
||||
public void HandleNewInput(InputGeometry geometry)
|
||||
public void HandleNewInput(IPolygon geometry)
|
||||
{
|
||||
}
|
||||
|
||||
public void HandleMeshImport(InputGeometry geometry, Mesh mesh)
|
||||
public void HandleMeshImport(IPolygon geometry, Mesh mesh)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -34,14 +34,14 @@ namespace MeshExplorer.Views
|
||||
|
||||
#region IView
|
||||
|
||||
public void HandleNewInput(InputGeometry geometry)
|
||||
public void HandleNewInput(IPolygon geometry)
|
||||
{
|
||||
// Reset labels
|
||||
lbNumVert2.Text = "-";
|
||||
lbNumTri2.Text = "-";
|
||||
lbNumSeg2.Text = "-";
|
||||
|
||||
lbNumVert.Text = geometry.Count.ToString();
|
||||
lbNumVert.Text = geometry.Points.Count.ToString();
|
||||
lbNumSeg.Text = geometry.Segments.Count().ToString();
|
||||
lbNumTri.Text = "0";
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace MeshExplorer.Views
|
||||
angleHistogram1.SetData(null, null);
|
||||
}
|
||||
|
||||
public void HandleMeshImport(InputGeometry geometry, Mesh mesh)
|
||||
public void HandleMeshImport(IPolygon geometry, Mesh mesh)
|
||||
{
|
||||
// Previous mesh stats
|
||||
lbNumVert2.Text = "-";
|
||||
|
||||
@@ -9,15 +9,12 @@ namespace TriangleNet
|
||||
{
|
||||
using System;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Logging;
|
||||
|
||||
/// <summary>
|
||||
/// Controls the behavior of the meshing software.
|
||||
/// </summary>
|
||||
public class Behavior
|
||||
class Behavior
|
||||
{
|
||||
#region Class members
|
||||
|
||||
bool poly = false;
|
||||
bool quality = false;
|
||||
bool varArea = false;
|
||||
@@ -26,7 +23,6 @@ namespace TriangleNet
|
||||
bool boundaryMarkers = true;
|
||||
bool noHoles = false;
|
||||
bool conformDel = false;
|
||||
TriangulationAlgorithm algorithm = TriangulationAlgorithm.Dwyer;
|
||||
|
||||
Func<ITriangle, double, bool> usertest;
|
||||
|
||||
@@ -44,8 +40,6 @@ namespace TriangleNet
|
||||
internal double maxGoodAngle = 0.0;
|
||||
internal double offconstant = 0.0;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the Behavior class.
|
||||
/// </summary>
|
||||
@@ -153,7 +147,7 @@ namespace TriangleNet
|
||||
set
|
||||
{
|
||||
maxArea = value;
|
||||
fixedArea = value > 0;
|
||||
fixedArea = value > 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,15 +196,6 @@ namespace TriangleNet
|
||||
set { conformDel = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Algorithm to use for triangulation.
|
||||
/// </summary>
|
||||
public TriangulationAlgorithm Algorithm
|
||||
{
|
||||
get { return algorithm; }
|
||||
set { algorithm = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Suppresses boundary segment splitting.
|
||||
/// </summary>
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
namespace TriangleNet
|
||||
{
|
||||
/// <summary>
|
||||
/// Implemented triangulation algorithms.
|
||||
/// The type of the mesh vertex.
|
||||
/// </summary>
|
||||
public enum TriangulationAlgorithm
|
||||
{
|
||||
Dwyer,
|
||||
Incremental,
|
||||
SweepLine
|
||||
};
|
||||
public enum VertexType { InputVertex, SegmentVertex, FreeVertex, DeadVertex, UndeadVertex };
|
||||
|
||||
/// <summary>
|
||||
/// Node renumbering algorithms.
|
||||
/// </summary>
|
||||
public enum NodeNumbering { None, Linear, CuthillMcKee };
|
||||
|
||||
/// <summary>
|
||||
/// Labels that signify the result of point location.
|
||||
@@ -43,14 +43,4 @@ namespace TriangleNet
|
||||
/// direction triangle, or along the right edge of the direction triangle.
|
||||
/// </remarks>
|
||||
enum FindDirectionResult { Within, Leftcollinear, Rightcollinear };
|
||||
|
||||
/// <summary>
|
||||
/// The type of the mesh vertex.
|
||||
/// </summary>
|
||||
public enum VertexType { InputVertex, SegmentVertex, FreeVertex, DeadVertex, UndeadVertex };
|
||||
|
||||
/// <summary>
|
||||
/// Node renumbering algorithms.
|
||||
/// </summary>
|
||||
public enum NodeNumbering { None, Linear, CuthillMcKee };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
|
||||
namespace TriangleNet.Geometry
|
||||
{
|
||||
using TriangleNet.Meshing;
|
||||
|
||||
public static class IPolygonExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Triangulates a polygon.
|
||||
/// </summary>
|
||||
public static IMesh Triangulate(this IPolygon polygon)
|
||||
{
|
||||
var mesher = new GenericMesher();
|
||||
|
||||
return mesher.Triangulate(polygon, null, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triangulates a polygon, applying constraint options.
|
||||
/// </summary>
|
||||
/// <param name="options">Constraint options.</param>
|
||||
public static IMesh Triangulate(this IPolygon polygon, ConstraintOptions options)
|
||||
{
|
||||
var mesher = new GenericMesher();
|
||||
|
||||
return mesher.Triangulate(polygon, options, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triangulates a polygon, applying quality options.
|
||||
/// </summary>
|
||||
/// <param name="quality">Quality options.</param>
|
||||
public static IMesh Triangulate(this IPolygon polygon, QualityOptions quality)
|
||||
{
|
||||
var mesher = new GenericMesher();
|
||||
|
||||
return mesher.Triangulate(polygon, null, quality);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triangulates a polygon, applying quality and constraint options.
|
||||
/// </summary>
|
||||
/// <param name="options">Constraint options.</param>
|
||||
/// <param name="quality">Quality options.</param>
|
||||
public static IMesh Triangulate(this IPolygon polygon, ConstraintOptions options, QualityOptions quality)
|
||||
{
|
||||
var mesher = new GenericMesher();
|
||||
|
||||
var mesh = (Mesh)mesher.Triangulate(polygon.Points);
|
||||
|
||||
mesh.ApplyConstraints(polygon, options, quality);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triangulates a polygon, applying quality and constraint options.
|
||||
/// </summary>
|
||||
/// <param name="options">Constraint options.</param>
|
||||
/// <param name="quality">Quality options.</param>
|
||||
/// <param name="triangulator">The triangulation algorithm.</param>
|
||||
public static IMesh Triangulate(this IPolygon polygon, ConstraintOptions options, QualityOptions quality,
|
||||
ITriangulator triangulator)
|
||||
{
|
||||
var mesher = new GenericMesher(triangulator);
|
||||
|
||||
var mesh = (Mesh)mesher.Triangulate(polygon.Points);
|
||||
|
||||
mesh.ApplyConstraints(polygon, options, quality);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,257 +0,0 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="InputGeometry.cs" company="">
|
||||
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Geometry
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Data;
|
||||
|
||||
/// <summary>
|
||||
/// The input geometry which will be triangulated. May represent a
|
||||
/// pointset or a planar straight line graph.
|
||||
/// </summary>
|
||||
public class InputGeometry
|
||||
{
|
||||
internal List<Vertex> points;
|
||||
internal List<Edge> segments;
|
||||
internal List<Point> holes;
|
||||
internal List<RegionPointer> regions;
|
||||
|
||||
Rectangle bounds;
|
||||
|
||||
// Used to check consitent use of point attributes.
|
||||
private int pointAttributes = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InputGeometry" /> class.
|
||||
/// </summary>
|
||||
public InputGeometry()
|
||||
: this(3)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InputGeometry" /> class.
|
||||
/// The point list will be initialized with a given capacity.
|
||||
/// </summary>
|
||||
/// <param name="capacity">Point list capacity.</param>
|
||||
public InputGeometry(int capacity)
|
||||
{
|
||||
points = new List<Vertex>(capacity);
|
||||
segments = new List<Edge>();
|
||||
holes = new List<Point>();
|
||||
regions = new List<RegionPointer>();
|
||||
|
||||
bounds = new Rectangle();
|
||||
|
||||
pointAttributes = -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bounding box of the input geometry.
|
||||
/// </summary>
|
||||
public Rectangle Bounds
|
||||
{
|
||||
get { return bounds; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates, whether the geometry should be treated as a PSLG.
|
||||
/// </summary>
|
||||
public bool HasSegments
|
||||
{
|
||||
get { return segments.Count > 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of points.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get { return points.Count; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of input points.
|
||||
/// </summary>
|
||||
public IEnumerable<Point> Points
|
||||
{
|
||||
get { return points; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of input segments.
|
||||
/// </summary>
|
||||
public ICollection<Edge> Segments
|
||||
{
|
||||
get { return segments; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of input holes.
|
||||
/// </summary>
|
||||
public ICollection<Point> Holes
|
||||
{
|
||||
get { return holes; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of regions.
|
||||
/// </summary>
|
||||
public ICollection<RegionPointer> Regions
|
||||
{
|
||||
get { return regions; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear input geometry.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
points.Clear();
|
||||
segments.Clear();
|
||||
holes.Clear();
|
||||
regions.Clear();
|
||||
|
||||
pointAttributes = -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a point to the geometry.
|
||||
/// </summary>
|
||||
/// <param name="x">X coordinate.</param>
|
||||
/// <param name="y">Y coordinate.</param>
|
||||
public void AddPoint(double x, double y)
|
||||
{
|
||||
AddPoint(x, y, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a point to the geometry.
|
||||
/// </summary>
|
||||
/// <param name="x">X coordinate.</param>
|
||||
/// <param name="y">Y coordinate.</param>
|
||||
/// <param name="boundary">Boundary marker.</param>
|
||||
public void AddPoint(double x, double y, int boundary)
|
||||
{
|
||||
var v = new Vertex(x, y, boundary);
|
||||
points.Add(v);
|
||||
bounds.Expand(v);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a point to the geometry.
|
||||
/// </summary>
|
||||
/// <param name="x">X coordinate.</param>
|
||||
/// <param name="y">Y coordinate.</param>
|
||||
/// <param name="boundary">Boundary marker.</param>
|
||||
/// <param name="attribute">Point attribute.</param>
|
||||
public void AddPoint(double x, double y, int boundary, double attribute)
|
||||
{
|
||||
AddPoint(x, y, 0, new double[] { attribute });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a point to the geometry.
|
||||
/// </summary>
|
||||
/// <param name="x">X coordinate.</param>
|
||||
/// <param name="y">Y coordinate.</param>
|
||||
/// <param name="boundary">Boundary marker.</param>
|
||||
/// <param name="attribs">Point attributes.</param>
|
||||
public void AddPoint(double x, double y, int boundary, double[] attribs)
|
||||
{
|
||||
if (pointAttributes < 0)
|
||||
{
|
||||
pointAttributes = attribs == null ? 0 : attribs.Length;
|
||||
}
|
||||
else if (attribs == null && pointAttributes > 0)
|
||||
{
|
||||
throw new ArgumentException("Inconsitent use of point attributes.");
|
||||
}
|
||||
else if (attribs != null && pointAttributes != attribs.Length)
|
||||
{
|
||||
throw new ArgumentException("Inconsitent use of point attributes.");
|
||||
}
|
||||
|
||||
var v = new Vertex(x, y, boundary) { attributes = attribs };
|
||||
points.Add(v);
|
||||
bounds.Expand(v);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a vertex to the geometry.
|
||||
/// </summary>
|
||||
/// <param name="v">Vertex instance.</param>
|
||||
public void AddPoint(Vertex v)
|
||||
{
|
||||
var attribs = v.attributes;
|
||||
|
||||
if (pointAttributes < 0)
|
||||
{
|
||||
pointAttributes = attribs == null ? 0 : attribs.Length;
|
||||
}
|
||||
else if (attribs == null && pointAttributes > 0)
|
||||
{
|
||||
throw new ArgumentException("Inconsitent use of point attributes.");
|
||||
}
|
||||
else if (attribs != null && pointAttributes != attribs.Length)
|
||||
{
|
||||
throw new ArgumentException("Inconsitent use of point attributes.");
|
||||
}
|
||||
|
||||
points.Add(v);
|
||||
bounds.Expand(v);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a hole location to the geometry.
|
||||
/// </summary>
|
||||
/// <param name="x">X coordinate of the hole.</param>
|
||||
/// <param name="y">Y coordinate of the hole.</param>
|
||||
public void AddHole(double x, double y)
|
||||
{
|
||||
holes.Add(new Point(x, y));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a hole location to the geometry.
|
||||
/// </summary>
|
||||
/// <param name="x">X coordinate of the hole.</param>
|
||||
/// <param name="y">Y coordinate of the hole.</param>
|
||||
/// <param name="id">The region id.</param>
|
||||
public void AddRegion(double x, double y, int id)
|
||||
{
|
||||
regions.Add(new RegionPointer(x, y, id));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a segment to the geometry.
|
||||
/// </summary>
|
||||
/// <param name="p0">First endpoint.</param>
|
||||
/// <param name="p1">Second endpoint.</param>
|
||||
public void AddSegment(int p0, int p1)
|
||||
{
|
||||
AddSegment(p0, p1, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a segment to the geometry.
|
||||
/// </summary>
|
||||
/// <param name="p0">First endpoint.</param>
|
||||
/// <param name="p1">Second endpoint.</param>
|
||||
/// <param name="boundary">Segment marker.</param>
|
||||
public void AddSegment(int p0, int p1, int boundary)
|
||||
{
|
||||
if (p0 == p1 || p0 < 0 || p1 < 0)
|
||||
{
|
||||
throw new NotSupportedException("Invalid endpoints.");
|
||||
}
|
||||
|
||||
segments.Add(new Edge(p0, p1, boundary));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,16 +34,16 @@ namespace TriangleNet.Geometry
|
||||
/// Initializes a new instance of the <see cref="Rectangle" /> class
|
||||
/// with predefined bounds.
|
||||
/// </summary>
|
||||
/// <param name="xmin">Minimum x value.</param>
|
||||
/// <param name="ymin">Minimum y value.</param>
|
||||
/// <param name="xmax">Maximum x value.</param>
|
||||
/// <param name="ymax">Maximum y value.</param>
|
||||
public Rectangle(double xmin, double ymin, double xmax, double ymax)
|
||||
/// <param name="x">Minimum x value (left).</param>
|
||||
/// <param name="y">Minimum y value (bottom).</param>
|
||||
/// <param name="width">Width of the rectangle.</param>
|
||||
/// <param name="height">Height of the rectangle.</param>
|
||||
public Rectangle(double x, double y, double width, double height)
|
||||
{
|
||||
this.xmin = xmin;
|
||||
this.xmax = xmax;
|
||||
this.ymin = ymin;
|
||||
this.ymax = ymax;
|
||||
this.xmin = x;
|
||||
this.ymin = y;
|
||||
this.xmax = x + width;
|
||||
this.ymax = y + height;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -129,7 +129,7 @@ namespace TriangleNet.IO
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteGeometry(InputGeometry geometry)
|
||||
private void WriteGeometry(IPolygon geometry)
|
||||
{
|
||||
stream.WriteLine("#!G{0}", this.iteration++);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="filename">The path of the file to read.</param>
|
||||
/// <returns>An instance of the <see cref="IPolygon" /> class.</returns>
|
||||
public static InputGeometry Read(string filename)
|
||||
public static IPolygon Read(string filename)
|
||||
{
|
||||
foreach (IPolygonFormat format in formats)
|
||||
{
|
||||
@@ -53,7 +53,7 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="mesh">An instance of the <see cref="IPolygon" /> class.</param>
|
||||
/// <param name="filename">The path of the file to save.</param>
|
||||
public static void Write(InputGeometry polygon, string filename)
|
||||
public static void Write(IPolygon polygon, string filename)
|
||||
{
|
||||
foreach (IPolygonFormat format in formats)
|
||||
{
|
||||
@@ -75,7 +75,7 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="filename">The path of the file to read.</param>
|
||||
/// <returns>An instance of the <see cref="IMesh" /> interface.</returns>
|
||||
public static Mesh Import(string filename)
|
||||
public static IMesh Import(string filename)
|
||||
{
|
||||
foreach (IMeshFormat format in formats)
|
||||
{
|
||||
@@ -93,7 +93,7 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="mesh">An instance of the <see cref="IMesh" /> interface.</param>
|
||||
/// <param name="filename">The path of the file to save.</param>
|
||||
public static void Write(Mesh mesh, string filename)
|
||||
public static void Write(IMesh mesh, string filename)
|
||||
{
|
||||
foreach (IMeshFormat format in formats)
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
namespace TriangleNet.IO
|
||||
{
|
||||
using System.IO;
|
||||
using TriangleNet.Meshing;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for mesh I/O.
|
||||
@@ -18,20 +19,20 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="filename">The path of the file to read.</param>
|
||||
/// <returns>An instance of the <see cref="IMesh" /> interface.</returns>
|
||||
Mesh Import(string filename);
|
||||
IMesh Import(string filename);
|
||||
|
||||
/// <summary>
|
||||
/// Save a mesh to disk.
|
||||
/// </summary>
|
||||
/// <param name="mesh">An instance of the <see cref="IMesh" /> interface.</param>
|
||||
/// <param name="filename">The path of the file to save.</param>
|
||||
void Write(Mesh mesh, string filename);
|
||||
void Write(IMesh mesh, string filename);
|
||||
|
||||
/// <summary>
|
||||
/// Save a mesh to a <see cref="StreamWriter" />.
|
||||
/// </summary>
|
||||
/// <param name="mesh">An instance of the <see cref="IMesh" /> interface.</param>
|
||||
/// <param name="stream">The stream to save to.</param>
|
||||
void Write(Mesh mesh, StreamWriter stream);
|
||||
void Write(IMesh mesh, StreamWriter stream);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,20 +19,20 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="filename">The path of the file to read.</param>
|
||||
/// <returns>An instance of the <see cref="IPolygon" /> class.</returns>
|
||||
InputGeometry Read(string filename);
|
||||
IPolygon Read(string filename);
|
||||
|
||||
/// <summary>
|
||||
/// Save a polygon geometry to disk.
|
||||
/// </summary>
|
||||
/// <param name="polygon">An instance of the <see cref="IPolygon" /> class.</param>
|
||||
/// <param name="filename">The path of the file to save.</param>
|
||||
void Write(InputGeometry polygon, string filename);
|
||||
void Write(IPolygon polygon, string filename);
|
||||
|
||||
/// <summary>
|
||||
/// Save a polygon geometry to a <see cref="StreamWriter" />.
|
||||
/// </summary>
|
||||
/// <param name="polygon">An instance of the <see cref="IPolygon" /> class.</param>
|
||||
/// <param name="stream">The stream to save to.</param>
|
||||
void Write(InputGeometry polygon, StreamWriter stream);
|
||||
void Write(IPolygon polygon, StreamWriter stream);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,14 +29,14 @@ namespace TriangleNet.IO
|
||||
return false;
|
||||
}
|
||||
|
||||
public Mesh Import(string filename)
|
||||
public IMesh Import(string filename)
|
||||
{
|
||||
string ext = Path.GetExtension(filename);
|
||||
|
||||
if (ext == ".node" || ext == ".poly" || ext == ".ele")
|
||||
{
|
||||
List<ITriangle> triangles;
|
||||
InputGeometry geometry;
|
||||
Polygon geometry;
|
||||
|
||||
TriangleReader.Read(filename, out geometry, out triangles);
|
||||
|
||||
@@ -51,18 +51,18 @@ namespace TriangleNet.IO
|
||||
throw new NotSupportedException("Could not load '" + filename + "' file.");
|
||||
}
|
||||
|
||||
public void Write(Mesh mesh, string filename)
|
||||
public void Write(IMesh mesh, string filename)
|
||||
{
|
||||
TriangleWriter.WritePoly((Mesh)mesh, Path.ChangeExtension(filename, ".poly"));
|
||||
TriangleWriter.WriteElements((Mesh)mesh, Path.ChangeExtension(filename, ".ele"));
|
||||
}
|
||||
|
||||
public void Write(Mesh mesh, StreamWriter stream)
|
||||
public void Write(IMesh mesh, StreamWriter stream)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public InputGeometry Read(string filename)
|
||||
public IPolygon Read(string filename)
|
||||
{
|
||||
string ext = Path.GetExtension(filename);
|
||||
|
||||
@@ -80,12 +80,12 @@ namespace TriangleNet.IO
|
||||
}
|
||||
|
||||
|
||||
public void Write(InputGeometry polygon, string filename)
|
||||
public void Write(IPolygon polygon, string filename)
|
||||
{
|
||||
TriangleWriter.WritePoly(polygon, filename);
|
||||
}
|
||||
|
||||
public void Write(InputGeometry polygon, StreamWriter stream)
|
||||
public void Write(IPolygon polygon, StreamWriter stream)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace TriangleNet.IO
|
||||
/// <param name="line">The current line.</param>
|
||||
/// <param name="attributes">Number of point attributes</param>
|
||||
/// <param name="marks">Number of point markers (0 or 1)</param>
|
||||
static void ReadVertex(InputGeometry data, int index, string[] line, int attributes, int marks)
|
||||
static void ReadVertex(Polygon data, int index, string[] line, int attributes, int marks)
|
||||
{
|
||||
double x = double.Parse(line[1], nfi);
|
||||
double y = double.Parse(line[2], nfi);
|
||||
@@ -81,7 +81,7 @@ namespace TriangleNet.IO
|
||||
mark = int.Parse(line[3 + attributes]);
|
||||
}
|
||||
|
||||
data.AddPoint(x, y, mark, attribs);
|
||||
data.Add(new Vertex(x, y, mark), attribs);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -91,7 +91,7 @@ namespace TriangleNet.IO
|
||||
/// <summary>
|
||||
/// Reads geometry information from .node or .poly files.
|
||||
/// </summary>
|
||||
public static void Read(string filename, out InputGeometry geometry)
|
||||
public static void Read(string filename, out Polygon geometry)
|
||||
{
|
||||
geometry = null;
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace TriangleNet.IO
|
||||
/// <summary>
|
||||
/// Reads a mesh from .node, .poly or .ele files.
|
||||
/// </summary>
|
||||
public static void Read(string filename, out InputGeometry geometry, out List<ITriangle> triangles)
|
||||
public static void Read(string filename, out Polygon geometry, out List<ITriangle> triangles)
|
||||
{
|
||||
triangles = null;
|
||||
|
||||
@@ -128,9 +128,9 @@ namespace TriangleNet.IO
|
||||
/// <summary>
|
||||
/// Reads geometry information from .node or .poly files.
|
||||
/// </summary>
|
||||
public static InputGeometry Read(string filename)
|
||||
public static IPolygon Read(string filename)
|
||||
{
|
||||
InputGeometry geometry = null;
|
||||
Polygon geometry = null;
|
||||
|
||||
TriangleReader.Read(filename, out geometry);
|
||||
|
||||
@@ -144,7 +144,7 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="nodefilename"></param>
|
||||
/// <remarks>Will NOT read associated .ele by default.</remarks>
|
||||
public static InputGeometry ReadNodeFile(string nodefilename)
|
||||
public static Polygon ReadNodeFile(string nodefilename)
|
||||
{
|
||||
return ReadNodeFile(nodefilename, false);
|
||||
}
|
||||
@@ -154,9 +154,9 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="nodefilename"></param>
|
||||
/// <param name="readElements"></param>
|
||||
public static InputGeometry ReadNodeFile(string nodefilename, bool readElements)
|
||||
public static Polygon ReadNodeFile(string nodefilename, bool readElements)
|
||||
{
|
||||
InputGeometry data;
|
||||
Polygon data;
|
||||
|
||||
startIndex = 0;
|
||||
|
||||
@@ -197,7 +197,7 @@ namespace TriangleNet.IO
|
||||
nodemarkers = int.Parse(line[3]);
|
||||
}
|
||||
|
||||
data = new InputGeometry(invertices);
|
||||
data = new Polygon(invertices);
|
||||
|
||||
// Read the vertices.
|
||||
if (invertices > 0)
|
||||
@@ -242,7 +242,7 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="polyfilename"></param>
|
||||
/// <remarks>Will NOT read associated .ele by default.</remarks>
|
||||
public static InputGeometry ReadPolyFile(string polyfilename)
|
||||
public static Polygon ReadPolyFile(string polyfilename)
|
||||
{
|
||||
return ReadPolyFile(polyfilename, false, false);
|
||||
}
|
||||
@@ -253,7 +253,7 @@ namespace TriangleNet.IO
|
||||
/// <param name="polyfilename"></param>
|
||||
/// <param name="readElements">If true, look for an associated .ele file.</param>
|
||||
/// <remarks>Will NOT read associated .area by default.</remarks>
|
||||
public static InputGeometry ReadPolyFile(string polyfilename, bool readElements)
|
||||
public static Polygon ReadPolyFile(string polyfilename, bool readElements)
|
||||
{
|
||||
return ReadPolyFile(polyfilename, readElements, false);
|
||||
}
|
||||
@@ -264,10 +264,10 @@ namespace TriangleNet.IO
|
||||
/// <param name="polyfilename"></param>
|
||||
/// <param name="readElements">If true, look for an associated .ele file.</param>
|
||||
/// <param name="readElements">If true, look for an associated .area file.</param>
|
||||
public static InputGeometry ReadPolyFile(string polyfilename, bool readElements, bool readArea)
|
||||
public static Polygon ReadPolyFile(string polyfilename, bool readElements, bool readArea)
|
||||
{
|
||||
// Read poly file
|
||||
InputGeometry data;
|
||||
Polygon data;
|
||||
|
||||
startIndex = 0;
|
||||
|
||||
@@ -306,7 +306,7 @@ namespace TriangleNet.IO
|
||||
// Read the vertices.
|
||||
if (invertices > 0)
|
||||
{
|
||||
data = new InputGeometry(invertices);
|
||||
data = new Polygon(invertices);
|
||||
|
||||
for (int i = 0; i < invertices; i++)
|
||||
{
|
||||
@@ -335,7 +335,7 @@ namespace TriangleNet.IO
|
||||
// the vertices should be read from a separate .node file.
|
||||
string nodefile = Path.ChangeExtension(polyfilename, ".node");
|
||||
data = ReadNodeFile(nodefile);
|
||||
invertices = data.Count;
|
||||
invertices = data.Points.Count;
|
||||
}
|
||||
|
||||
if (data.Points == null)
|
||||
@@ -401,7 +401,7 @@ namespace TriangleNet.IO
|
||||
}
|
||||
else
|
||||
{
|
||||
data.AddSegment(end1, end2, mark);
|
||||
data.Add(new Edge(end1, end2, mark));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,8 +428,8 @@ namespace TriangleNet.IO
|
||||
throw new Exception("Invalid hole.");
|
||||
}
|
||||
|
||||
data.AddHole(double.Parse(line[1], nfi),
|
||||
double.Parse(line[2], nfi));
|
||||
data.Holes.Add(new Point(double.Parse(line[1], nfi),
|
||||
double.Parse(line[2], nfi)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,12 +452,10 @@ namespace TriangleNet.IO
|
||||
throw new Exception("Invalid region attributes.");
|
||||
}
|
||||
|
||||
data.AddRegion(
|
||||
// Region x and y
|
||||
double.Parse(line[1], nfi),
|
||||
double.Parse(line[2], nfi),
|
||||
// Region id
|
||||
int.Parse(line[3]));
|
||||
data.Regions.Add(new RegionPointer(
|
||||
double.Parse(line[1], nfi), // Region x
|
||||
double.Parse(line[2], nfi), // Region y
|
||||
int.Parse(line[3]))); // Region id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,16 +186,16 @@ namespace TriangleNet.IO
|
||||
/// <remarks>If the nodes should not be written into this file,
|
||||
/// make sure a .node file was written before, so that the nodes
|
||||
/// are numbered right.</remarks>
|
||||
public static void WritePoly(InputGeometry polygon, string filename)
|
||||
public static void WritePoly(IPolygon polygon, string filename)
|
||||
{
|
||||
bool hasMarkers = true;
|
||||
bool hasMarkers = polygon.HasSegmentMarkers;
|
||||
|
||||
using (StreamWriter writer = new StreamWriter(filename))
|
||||
{
|
||||
// TODO: write vertex attributes
|
||||
|
||||
// Write nodes to this file.
|
||||
TriangleWriter.WriteNodes(writer, polygon.points, true, 0, false);
|
||||
TriangleWriter.WriteNodes(writer, polygon.Points, polygon.HasPointMarkers, 0, false);
|
||||
|
||||
// Number of segments, number of boundary markers (zero or one).
|
||||
writer.WriteLine("{0} {1}", polygon.Segments.Count, hasMarkers ? "1" : "0");
|
||||
|
||||
+242
-273
@@ -9,26 +9,23 @@ namespace TriangleNet
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Logging;
|
||||
using TriangleNet.IO;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Meshing.Algorithm;
|
||||
using TriangleNet.Smoothing;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Logging;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Meshing.Iterators;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
/// <summary>
|
||||
/// Mesh data structure.
|
||||
/// </summary>
|
||||
public class Mesh
|
||||
public class Mesh : IMesh
|
||||
{
|
||||
#region Variables
|
||||
|
||||
ILog<LogItem> logger;
|
||||
|
||||
QualityMesher quality;
|
||||
QualityMesher qualityMesher;
|
||||
|
||||
// Stack that maintains a list of recently flipped triangles.
|
||||
Stack<Otri> flipstack;
|
||||
@@ -85,14 +82,6 @@ namespace TriangleNet
|
||||
|
||||
#region Public properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mesh behavior instance.
|
||||
/// </summary>
|
||||
public Behavior Behavior
|
||||
{
|
||||
get { return this.behavior; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mesh bounding box.
|
||||
/// </summary>
|
||||
@@ -140,7 +129,7 @@ namespace TriangleNet
|
||||
{
|
||||
get
|
||||
{
|
||||
EdgeEnumerator e = new EdgeEnumerator(this);
|
||||
var e = new EdgeIterator(this);
|
||||
while (e.MoveNext())
|
||||
{
|
||||
yield return e.Current;
|
||||
@@ -177,17 +166,7 @@ namespace TriangleNet
|
||||
/// Initializes a new instance of the <see cref="Mesh" /> class.
|
||||
/// </summary>
|
||||
public Mesh()
|
||||
: this(new Behavior())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Mesh" /> class.
|
||||
/// </summary>
|
||||
public Mesh(Behavior behavior)
|
||||
{
|
||||
this.behavior = behavior;
|
||||
|
||||
logger = Log.Instance;
|
||||
|
||||
behavior = new Behavior();
|
||||
@@ -201,7 +180,7 @@ namespace TriangleNet
|
||||
holes = new List<Point>();
|
||||
regions = new List<RegionPointer>();
|
||||
|
||||
quality = new QualityMesher(this);
|
||||
qualityMesher = new QualityMesher(this);
|
||||
|
||||
locator = new TriangleLocator(this);
|
||||
|
||||
@@ -214,217 +193,14 @@ namespace TriangleNet
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triangulate given input file (.node or .poly).
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
public void Triangulate(string inputFile)
|
||||
public void Refine(QualityOptions quality)
|
||||
{
|
||||
InputGeometry input = TriangleReader.Read(inputFile);
|
||||
behavior.MinAngle = quality.MinimumAngle;
|
||||
behavior.MaxAngle = quality.MaximumAngle;
|
||||
|
||||
this.Triangulate(input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triangulate given input data.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
public void Triangulate(InputGeometry input)
|
||||
{
|
||||
ResetData();
|
||||
|
||||
behavior.Poly = input.HasSegments;
|
||||
//behavior.useSegments = input.HasSegments;
|
||||
|
||||
//if (input.EdgeMarkers != null)
|
||||
//{
|
||||
// behavior.UseBoundaryMarkers = true;
|
||||
//}
|
||||
|
||||
// TODO: remove
|
||||
if (!behavior.Poly)
|
||||
{
|
||||
// Be careful not to allocate space for element area constraints that
|
||||
// will never be assigned any value (other than the default -1.0).
|
||||
behavior.VarArea = false;
|
||||
|
||||
// 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.useRegions = false;
|
||||
}
|
||||
|
||||
behavior.useRegions = input.Regions.Count > 0;
|
||||
|
||||
steinerleft = behavior.SteinerPoints;
|
||||
|
||||
TransferNodes(input);
|
||||
|
||||
hullsize = Delaunay(); // Triangulate the vertices.
|
||||
|
||||
// Ensure that no vertex can be mistaken for a triangular bounding
|
||||
// box vertex in insertvertex().
|
||||
infvertex1 = null;
|
||||
infvertex2 = null;
|
||||
infvertex3 = null;
|
||||
|
||||
// Insert segments, carving holes.
|
||||
var mesher = new ConstraintMesher(this);
|
||||
|
||||
if (behavior.useSegments)
|
||||
{
|
||||
// Segments will be introduced next.
|
||||
checksegments = true;
|
||||
|
||||
// Insert PSLG segments and/or convex hull segments.
|
||||
mesher.FormSkeleton(input);
|
||||
}
|
||||
|
||||
if (behavior.Poly && (triangles.Count > 0))
|
||||
{
|
||||
// Copy holes
|
||||
foreach (var item in input.holes)
|
||||
{
|
||||
holes.Add(item);
|
||||
}
|
||||
|
||||
// Copy regions
|
||||
foreach (var item in input.regions)
|
||||
{
|
||||
regions.Add(item);
|
||||
}
|
||||
|
||||
//dummytri.neighbors[2].triangle = dummytri;
|
||||
|
||||
// Carve out holes and concavities.
|
||||
mesher.CarveHoles();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Without a PSLG, there can be no holes or regional attributes
|
||||
// or area constraints. The following are set to zero to avoid
|
||||
// an accidental free() later.
|
||||
//
|
||||
// TODO: -
|
||||
holes.Clear();
|
||||
regions.Clear();
|
||||
}
|
||||
|
||||
if ((behavior.Quality || behavior.ConformingDelaunay) && triangles.Count > 0)
|
||||
{
|
||||
quality.EnforceQuality(); // Enforce angle and area constraints.
|
||||
}
|
||||
|
||||
// Calculate the number of edges.
|
||||
edges = (3 * triangles.Count + hullsize) / 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refines the current mesh by finding the maximum triangle area and setting
|
||||
/// the a global area constraint to half its size.
|
||||
/// </summary>
|
||||
public void Refine(bool halfArea)
|
||||
{
|
||||
if (halfArea)
|
||||
{
|
||||
double tmp, maxArea = 0;
|
||||
|
||||
foreach (var t in this.triangles.Values)
|
||||
{
|
||||
tmp = (t.vertices[2].x - t.vertices[0].x) * (t.vertices[1].y - t.vertices[0].y) -
|
||||
(t.vertices[1].x - t.vertices[0].x) * (t.vertices[2].y - t.vertices[0].y);
|
||||
|
||||
tmp = Math.Abs(tmp) / 2.0;
|
||||
|
||||
if (tmp > maxArea)
|
||||
{
|
||||
maxArea = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
this.Refine(maxArea / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
Refine();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refines the current mesh by setting a global area constraint.
|
||||
/// </summary>
|
||||
/// <param name="areaConstraint">Global area constraint.</param>
|
||||
public void Refine(double areaConstraint)
|
||||
{
|
||||
behavior.fixedArea = true;
|
||||
behavior.MaxArea = areaConstraint;
|
||||
behavior.MaxArea = quality.MaximumArea;
|
||||
|
||||
this.Refine();
|
||||
|
||||
// Reset option for sanity
|
||||
behavior.fixedArea = false;
|
||||
behavior.MaxArea = -1.0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refines the current mesh.
|
||||
/// </summary>
|
||||
public void Refine()
|
||||
{
|
||||
inelements = triangles.Count;
|
||||
invertices = vertices.Count;
|
||||
|
||||
// TODO: Set all vertex types to input (i.e. NOT free)?
|
||||
|
||||
if (behavior.Poly)
|
||||
{
|
||||
if (behavior.useSegments)
|
||||
{
|
||||
insegments = subsegs.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
insegments = (int)hullsize;
|
||||
}
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
||||
steinerleft = behavior.SteinerPoints;
|
||||
|
||||
// Ensure that no vertex can be mistaken for a triangular bounding
|
||||
// box vertex in insertvertex().
|
||||
infvertex1 = null;
|
||||
infvertex2 = null;
|
||||
infvertex3 = null;
|
||||
|
||||
if (behavior.useSegments)
|
||||
{
|
||||
checksegments = true;
|
||||
}
|
||||
|
||||
// TODO
|
||||
//holes.Clear();
|
||||
//regions.Clear();
|
||||
|
||||
if (triangles.Count > 0)
|
||||
{
|
||||
// Enforce angle and area constraints.
|
||||
quality.EnforceQuality();
|
||||
}
|
||||
|
||||
// Calculate the number of edges.
|
||||
edges = (3 * triangles.Count + hullsize) / 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Smooth the current mesh.
|
||||
/// </summary>
|
||||
public void Smooth()
|
||||
{
|
||||
numbering = NodeNumbering.None;
|
||||
|
||||
ISmoother smoother = new SimpleSmoother(this);
|
||||
smoother.Smooth();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -481,33 +257,226 @@ namespace TriangleNet
|
||||
|
||||
#region Misc
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Form a Delaunay triangulation.
|
||||
/// Load a mesh from file (.node/poly and .ele).
|
||||
/// </summary>
|
||||
/// <returns>The number of points on the hull.</returns>
|
||||
private int Delaunay()
|
||||
public void Load(string filename)
|
||||
{
|
||||
int hulledges = 0;
|
||||
List<ITriangle> triangles;
|
||||
InputGeometry geometry;
|
||||
|
||||
if (behavior.Algorithm == TriangulationAlgorithm.Dwyer)
|
||||
FileReader.Read(filename, out geometry, out triangles);
|
||||
|
||||
if (geometry != null && triangles != null)
|
||||
{
|
||||
Dwyer alg = new Dwyer();
|
||||
hulledges = alg.Triangulate(this);
|
||||
Load(geometry, triangles);
|
||||
}
|
||||
else if (behavior.Algorithm == TriangulationAlgorithm.SweepLine)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reconstructs a mesh from raw input data.
|
||||
/// </summary>
|
||||
public void Load(InputGeometry input, List<ITriangle> triangles)
|
||||
{
|
||||
if (input == null || triangles == null)
|
||||
{
|
||||
SweepLine alg = new SweepLine();
|
||||
hulledges = alg.Triangulate(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
Incremental alg = new Incremental();
|
||||
hulledges = alg.Triangulate(this);
|
||||
throw new ArgumentException("Invalid input (argument is null).");
|
||||
}
|
||||
|
||||
// The input vertices may all be collinear, so there are
|
||||
// no triangles.
|
||||
return (triangles.Count == 0) ? 0 : hulledges;
|
||||
// Clear all data structures / reset hash seeds
|
||||
this.ResetData();
|
||||
|
||||
if (input.HasSegments)
|
||||
{
|
||||
behavior.Poly = true;
|
||||
|
||||
this.holes.AddRange(input.Holes);
|
||||
}
|
||||
|
||||
//if (input.EdgeMarkers != null)
|
||||
//{
|
||||
// behavior.UseBoundaryMarkers = true;
|
||||
//}
|
||||
|
||||
//if (input.TriangleAreas != null)
|
||||
//{
|
||||
// behavior.VarArea = true;
|
||||
//}
|
||||
|
||||
// TODO: remove
|
||||
if (!behavior.Poly)
|
||||
{
|
||||
// Be careful not to allocate space for element area constraints that
|
||||
// will never be assigned any value (other than the default -1.0).
|
||||
behavior.VarArea = false;
|
||||
|
||||
// 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.useRegions = false;
|
||||
}
|
||||
|
||||
behavior.useRegions = input.Regions.Count > 0;
|
||||
|
||||
TransferNodes(input.points);
|
||||
|
||||
// Read and reconstruct a mesh.
|
||||
hullsize = DataReader.Reconstruct(this, input, triangles.ToArray());
|
||||
|
||||
// Calculate the number of edges.
|
||||
edges = (3 * triangles.Count + hullsize) / 2;
|
||||
}
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Triangulate given input data.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
internal void ApplyConstraints(IPolygon input, ConstraintOptions options, QualityOptions quality)
|
||||
{
|
||||
behavior.Poly = input.Segments.Count > 0;
|
||||
|
||||
// Copy constraint options
|
||||
if (options != null)
|
||||
{
|
||||
behavior.ConformingDelaunay = options.ConformingDelaunay;
|
||||
behavior.Convex = options.Convex;
|
||||
behavior.NoBisect = options.SegmentSplitting;
|
||||
|
||||
if (behavior.ConformingDelaunay)
|
||||
{
|
||||
behavior.Quality = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy quality options
|
||||
if (quality != null)
|
||||
{
|
||||
behavior.MinAngle = quality.MinimumAngle;
|
||||
behavior.MaxAngle = quality.MaximumAngle;
|
||||
behavior.MaxArea = quality.MaximumArea;
|
||||
behavior.UserTest = quality.UserTest;
|
||||
|
||||
behavior.Quality = true;
|
||||
}
|
||||
|
||||
//if (input.EdgeMarkers != null)
|
||||
//{
|
||||
// behavior.UseBoundaryMarkers = true;
|
||||
//}
|
||||
|
||||
// TODO: remove
|
||||
if (!behavior.Poly)
|
||||
{
|
||||
// Be careful not to allocate space for element area constraints that
|
||||
// will never be assigned any value (other than the default -1.0).
|
||||
behavior.VarArea = false;
|
||||
}
|
||||
|
||||
behavior.useRegions = input.Regions.Count > 0;
|
||||
|
||||
steinerleft = behavior.SteinerPoints;
|
||||
|
||||
// Ensure that no vertex can be mistaken for a triangular bounding
|
||||
// box vertex in insertvertex().
|
||||
infvertex1 = null;
|
||||
infvertex2 = null;
|
||||
infvertex3 = null;
|
||||
|
||||
// Insert segments, carving holes.
|
||||
var mesher = new ConstraintMesher(this);
|
||||
|
||||
if (behavior.useSegments)
|
||||
{
|
||||
// Segments will be introduced next.
|
||||
checksegments = true;
|
||||
|
||||
// Insert PSLG segments and/or convex hull segments.
|
||||
mesher.FormSkeleton(input);
|
||||
}
|
||||
|
||||
if (behavior.Poly && (triangles.Count > 0))
|
||||
{
|
||||
// Copy holes
|
||||
foreach (var item in input.Holes)
|
||||
{
|
||||
holes.Add(item);
|
||||
}
|
||||
|
||||
// Copy regions
|
||||
foreach (var item in input.Regions)
|
||||
{
|
||||
regions.Add(item);
|
||||
}
|
||||
|
||||
// Carve out holes and concavities.
|
||||
mesher.CarveHoles();
|
||||
}
|
||||
|
||||
if (behavior.Quality && triangles.Count > 0)
|
||||
{
|
||||
// Enforce angle and area constraints.
|
||||
qualityMesher.EnforceQuality();
|
||||
}
|
||||
|
||||
// Calculate the number of edges.
|
||||
edges = (3 * triangles.Count + hullsize) / 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refines the current mesh.
|
||||
/// </summary>
|
||||
internal void Refine()
|
||||
{
|
||||
inelements = triangles.Count;
|
||||
invertices = vertices.Count;
|
||||
|
||||
// TODO: Set all vertex types to input (i.e. NOT free)?
|
||||
|
||||
if (behavior.Poly)
|
||||
{
|
||||
insegments = behavior.useSegments ? subsegs.Count : hullsize;
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
||||
steinerleft = behavior.SteinerPoints;
|
||||
|
||||
// Ensure that no vertex can be mistaken for a triangular bounding
|
||||
// box vertex in insertvertex().
|
||||
infvertex1 = infvertex2 = infvertex3 = null;
|
||||
|
||||
if (behavior.useSegments)
|
||||
{
|
||||
checksegments = true;
|
||||
}
|
||||
|
||||
if (triangles.Count > 0)
|
||||
{
|
||||
// Enforce angle and area constraints.
|
||||
qualityMesher.EnforceQuality();
|
||||
}
|
||||
|
||||
// Calculate the number of edges.
|
||||
edges = (3 * triangles.Count + hullsize) / 2;
|
||||
}
|
||||
|
||||
internal void CopyTo(Mesh target)
|
||||
{
|
||||
target.vertices = this.vertices;
|
||||
target.triangles = this.triangles;
|
||||
target.subsegs = this.subsegs;
|
||||
|
||||
target.holes = this.holes;
|
||||
target.regions = this.regions;
|
||||
|
||||
target.hash_vtx = this.hash_vtx;
|
||||
target.hash_seg = this.hash_seg;
|
||||
target.hash_tri = this.hash_tri;
|
||||
|
||||
target.numbering = this.numbering;
|
||||
target.hullsize = this.hullsize;
|
||||
target.edges = this.edges;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -625,12 +594,11 @@ namespace TriangleNet
|
||||
/// Read the vertices from memory.
|
||||
/// </summary>
|
||||
/// <param name="data">The input data.</param>
|
||||
internal void TransferNodes(InputGeometry data)
|
||||
internal void TransferNodes(ICollection<Vertex> points)
|
||||
{
|
||||
List<Vertex> points = data.points;
|
||||
|
||||
this.invertices = points.Count;
|
||||
this.mesh_dim = 2;
|
||||
this.bounds = new Rectangle();
|
||||
|
||||
if (this.invertices < 3)
|
||||
{
|
||||
@@ -638,17 +606,21 @@ namespace TriangleNet
|
||||
throw new Exception("Input must have at least three input vertices.");
|
||||
}
|
||||
|
||||
this.nextras = points[0].attributes == null ? 0 : points[0].attributes.Length;
|
||||
bool first = true;
|
||||
|
||||
foreach (Vertex vertex in points)
|
||||
foreach (Vertex p in points)
|
||||
{
|
||||
vertex.hash = this.hash_vtx++;
|
||||
vertex.id = vertex.hash;
|
||||
if (first)
|
||||
{
|
||||
this.nextras = p.attributes == null ? 0 : p.attributes.Length;
|
||||
first = false;
|
||||
}
|
||||
|
||||
this.vertices.Add(vertex.hash, vertex);
|
||||
p.hash = p.id = this.hash_vtx++;
|
||||
|
||||
this.vertices.Add(p.hash, p);
|
||||
this.bounds.Expand(p);
|
||||
}
|
||||
|
||||
this.bounds = data.Bounds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -862,7 +834,7 @@ namespace TriangleNet
|
||||
encroached.org = brokensubseg.Org();
|
||||
encroached.dest = brokensubseg.Dest();
|
||||
|
||||
quality.AddBadSubseg(encroached);
|
||||
qualityMesher.AddBadSubseg(encroached);
|
||||
}
|
||||
}
|
||||
// Return a handle whose primary edge contains the vertex,
|
||||
@@ -1100,7 +1072,7 @@ namespace TriangleNet
|
||||
if (segmentflaws)
|
||||
{
|
||||
// Does the new vertex encroach upon this subsegment?
|
||||
if (quality.CheckSeg4Encroach(ref checksubseg) > 0)
|
||||
if (qualityMesher.CheckSeg4Encroach(ref checksubseg) > 0)
|
||||
{
|
||||
success = InsertVertexResult.Encroaching;
|
||||
}
|
||||
@@ -1266,7 +1238,7 @@ namespace TriangleNet
|
||||
if (triflaws)
|
||||
{
|
||||
// Check the triangle 'horiz' for quality.
|
||||
quality.TestTriangle(ref horiz);
|
||||
qualityMesher.TestTriangle(ref horiz);
|
||||
}
|
||||
|
||||
// Look for the next edge around the newly inserted vertex.
|
||||
@@ -1338,12 +1310,9 @@ namespace TriangleNet
|
||||
oppotri.SegBond(ref newsubseg);
|
||||
newsubseg.seg.boundary = subsegmark;
|
||||
}
|
||||
else
|
||||
else if (newsubseg.seg.boundary == 0)
|
||||
{
|
||||
if (newsubseg.seg.boundary == 0)
|
||||
{
|
||||
newsubseg.seg.boundary = subsegmark;
|
||||
}
|
||||
newsubseg.seg.boundary = subsegmark;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1718,7 +1687,7 @@ namespace TriangleNet
|
||||
{
|
||||
// Check the quality of the newly committed triangle.
|
||||
besttri.Sym(ref testtri);
|
||||
quality.TestTriangle(ref testtri);
|
||||
qualityMesher.TestTriangle(ref testtri);
|
||||
}
|
||||
}
|
||||
// Return the base triangle.
|
||||
@@ -1795,7 +1764,7 @@ namespace TriangleNet
|
||||
deltri.SetOrg(neworg);
|
||||
if (behavior.NoBisect == 0)
|
||||
{
|
||||
quality.TestTriangle(ref deltri);
|
||||
qualityMesher.TestTriangle(ref deltri);
|
||||
}
|
||||
|
||||
// Delete the two spliced-out triangles.
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
namespace TriangleNet.Meshing.Algorithm
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Logging;
|
||||
|
||||
/// <summary>
|
||||
/// Builds a delaunay triangulation using the divide-and-conquer algorithm.
|
||||
@@ -43,7 +43,7 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
/// The bounding box also makes it easy to traverse the convex hull, as the
|
||||
/// divide-and-conquer algorithm needs to do.
|
||||
/// </remarks>
|
||||
class Dwyer
|
||||
public class Dwyer : ITriangulator
|
||||
{
|
||||
static Random rand = new Random(DateTime.Now.Millisecond);
|
||||
|
||||
@@ -52,6 +52,83 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
Vertex[] sortarray;
|
||||
Mesh mesh;
|
||||
|
||||
/// <summary>
|
||||
/// Form a Delaunay triangulation by the divide-and-conquer method.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Sorts the vertices, calls a recursive procedure to triangulate them, and
|
||||
/// removes the bounding box, setting boundary markers as appropriate.
|
||||
/// </remarks>
|
||||
public IMesh Triangulate(ICollection<Vertex> points)
|
||||
{
|
||||
this.mesh = new Mesh();
|
||||
this.mesh.TransferNodes(points);
|
||||
|
||||
Otri hullleft = default(Otri), hullright = default(Otri);
|
||||
int divider;
|
||||
int i, j, n = points.Count;
|
||||
|
||||
//DebugWriter.Session.Start("test-dbg");
|
||||
|
||||
// Allocate an array of pointers to vertices for sorting.
|
||||
// TODO: use ToArray
|
||||
this.sortarray = new Vertex[n];
|
||||
i = 0;
|
||||
foreach (var v in points)
|
||||
{
|
||||
sortarray[i++] = v;
|
||||
}
|
||||
// Sort the vertices.
|
||||
//Array.Sort(sortarray);
|
||||
VertexSort(0, n - 1);
|
||||
// Discard duplicate vertices, which can really mess up the algorithm.
|
||||
i = 0;
|
||||
for (j = 1; j < n; j++)
|
||||
{
|
||||
if ((sortarray[i].x == sortarray[j].x) && (sortarray[i].y == sortarray[j].y))
|
||||
{
|
||||
if (Log.Verbose)
|
||||
{
|
||||
Log.Instance.Warning(
|
||||
String.Format("A duplicate vertex appeared and was ignored (ID {0}).", sortarray[j].hash),
|
||||
"Dwyer.Triangulate()");
|
||||
}
|
||||
sortarray[j].type = VertexType.UndeadVertex;
|
||||
mesh.undeads++;
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
sortarray[i] = sortarray[j];
|
||||
}
|
||||
}
|
||||
i++;
|
||||
if (UseDwyer)
|
||||
{
|
||||
// Re-sort the array of vertices to accommodate alternating cuts.
|
||||
divider = i >> 1;
|
||||
if (i - divider >= 2)
|
||||
{
|
||||
if (divider >= 2)
|
||||
{
|
||||
AlternateAxes(0, divider - 1, 1);
|
||||
}
|
||||
AlternateAxes(divider, i - 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Form the Delaunay triangulation.
|
||||
DivconqRecurse(0, i - 1, 0, ref hullleft, ref hullright);
|
||||
|
||||
//DebugWriter.Session.Write(mesh);
|
||||
//DebugWriter.Session.Finish();
|
||||
|
||||
this.mesh.hullsize = RemoveGhosts(ref hullleft);
|
||||
|
||||
return this.mesh;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sort an array of vertices by x-coordinate, using the y-coordinate as a secondary key.
|
||||
/// </summary>
|
||||
@@ -103,16 +180,14 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
left++;
|
||||
}
|
||||
while ((left <= right) && ((sortarray[left].x < pivotx) ||
|
||||
((sortarray[left].x == pivotx) &&
|
||||
(sortarray[left].y < pivoty))));
|
||||
((sortarray[left].x == pivotx) && (sortarray[left].y < pivoty))));
|
||||
// Search for a vertex whose x-coordinate is too small for the right.
|
||||
do
|
||||
{
|
||||
right--;
|
||||
}
|
||||
while ((left <= right) && ((sortarray[right].x > pivotx) ||
|
||||
((sortarray[right].x == pivotx) &&
|
||||
(sortarray[right].y > pivoty))));
|
||||
((sortarray[right].x == pivotx) && (sortarray[right].y > pivoty))));
|
||||
|
||||
if (left < right)
|
||||
{
|
||||
@@ -183,16 +258,14 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
left++;
|
||||
}
|
||||
while ((left <= right) && ((sortarray[left][axis] < pivot1) ||
|
||||
((sortarray[left][axis] == pivot1) &&
|
||||
(sortarray[left][1 - axis] < pivot2))));
|
||||
((sortarray[left][axis] == pivot1) && (sortarray[left][1 - axis] < pivot2))));
|
||||
// Search for a vertex whose x-coordinate is too small for the right.
|
||||
do
|
||||
{
|
||||
right--;
|
||||
}
|
||||
while ((left <= right) && ((sortarray[right][axis] > pivot1) ||
|
||||
((sortarray[right][axis] == pivot1) &&
|
||||
(sortarray[right][1 - axis] > pivot2))));
|
||||
((sortarray[right][axis] == pivot1) && (sortarray[right][1 - axis] > pivot2))));
|
||||
if (left < right)
|
||||
{
|
||||
// Swap the left and right vertices.
|
||||
@@ -823,80 +896,5 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
|
||||
return hullsize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Form a Delaunay triangulation by the divide-and-conquer method.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Sorts the vertices, calls a recursive procedure to triangulate them, and
|
||||
/// removes the bounding box, setting boundary markers as appropriate.
|
||||
/// </remarks>
|
||||
public int Triangulate(Mesh m)
|
||||
{
|
||||
Otri hullleft = default(Otri), hullright = default(Otri);
|
||||
int divider;
|
||||
int i, j;
|
||||
|
||||
this.mesh = m;
|
||||
|
||||
//DebugWriter.Session.Start("test-dbg");
|
||||
|
||||
// Allocate an array of pointers to vertices for sorting.
|
||||
// TODO: use ToArray
|
||||
this.sortarray = new Vertex[m.invertices];
|
||||
i = 0;
|
||||
foreach (var v in m.vertices.Values)
|
||||
{
|
||||
sortarray[i++] = v;
|
||||
}
|
||||
// Sort the vertices.
|
||||
//Array.Sort(sortarray);
|
||||
VertexSort(0, m.invertices - 1);
|
||||
// Discard duplicate vertices, which can really mess up the algorithm.
|
||||
i = 0;
|
||||
for (j = 1; j < m.invertices; j++)
|
||||
{
|
||||
if ((sortarray[i].x == sortarray[j].x)
|
||||
&& (sortarray[i].y == sortarray[j].y))
|
||||
{
|
||||
if (Log.Verbose)
|
||||
{
|
||||
Log.Instance.Warning(
|
||||
String.Format("A duplicate vertex appeared and was ignored (ID {0}).", sortarray[j].hash),
|
||||
"DivConquer.DivconqDelaunay()");
|
||||
}
|
||||
sortarray[j].type = VertexType.UndeadVertex;
|
||||
m.undeads++;
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
sortarray[i] = sortarray[j];
|
||||
}
|
||||
}
|
||||
i++;
|
||||
if (UseDwyer)
|
||||
{
|
||||
// Re-sort the array of vertices to accommodate alternating cuts.
|
||||
divider = i >> 1;
|
||||
if (i - divider >= 2)
|
||||
{
|
||||
if (divider >= 2)
|
||||
{
|
||||
AlternateAxes(0, divider - 1, 1);
|
||||
}
|
||||
AlternateAxes(divider, i - 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Form the Delaunay triangulation.
|
||||
DivconqRecurse(0, i-1, 0, ref hullleft, ref hullright);
|
||||
|
||||
//DebugWriter.Session.Write(mesh);
|
||||
//DebugWriter.Session.Finish();
|
||||
|
||||
return RemoveGhosts(ref hullleft);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,17 +7,54 @@
|
||||
|
||||
namespace TriangleNet.Meshing.Algorithm
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Logging;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Builds a delaunay triangulation using the incremental algorithm.
|
||||
/// </summary>
|
||||
class Incremental
|
||||
public class Incremental : ITriangulator
|
||||
{
|
||||
Mesh mesh;
|
||||
|
||||
/// <summary>
|
||||
/// Form a Delaunay triangulation by incrementally inserting vertices.
|
||||
/// </summary>
|
||||
/// <returns>Returns the number of edges on the convex hull of the
|
||||
/// triangulation.</returns>
|
||||
public IMesh Triangulate(ICollection<Vertex> points)
|
||||
{
|
||||
this.mesh = new Mesh();
|
||||
this.mesh.TransferNodes(points);
|
||||
|
||||
Otri starttri = new Otri();
|
||||
|
||||
// Create a triangular bounding box.
|
||||
GetBoundingBox();
|
||||
|
||||
foreach (var v in mesh.vertices.Values)
|
||||
{
|
||||
starttri.triangle = Mesh.dummytri;
|
||||
Osub tmp = default(Osub);
|
||||
if (mesh.InsertVertex(v, ref starttri, ref tmp, false, false) == InsertVertexResult.Duplicate)
|
||||
{
|
||||
if (Log.Verbose)
|
||||
{
|
||||
Log.Instance.Warning("A duplicate vertex appeared and was ignored.",
|
||||
"Incremental.IncrementalDelaunay()");
|
||||
}
|
||||
v.type = VertexType.UndeadVertex;
|
||||
mesh.undeads++;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the bounding box.
|
||||
this.mesh.hullsize = RemoveBox();
|
||||
|
||||
return this.mesh;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Form an "infinite" bounding triangle to insert vertices into.
|
||||
/// </summary>
|
||||
@@ -144,38 +181,5 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
|
||||
return hullsize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Form a Delaunay triangulation by incrementally inserting vertices.
|
||||
/// </summary>
|
||||
/// <returns>Returns the number of edges on the convex hull of the
|
||||
/// triangulation.</returns>
|
||||
public int Triangulate(Mesh mesh)
|
||||
{
|
||||
this.mesh = mesh;
|
||||
|
||||
Otri starttri = new Otri();
|
||||
|
||||
// Create a triangular bounding box.
|
||||
GetBoundingBox();
|
||||
|
||||
foreach (var v in mesh.vertices.Values)
|
||||
{
|
||||
starttri.triangle = Mesh.dummytri;
|
||||
Osub tmp = default(Osub);
|
||||
if (mesh.InsertVertex(v, ref starttri, ref tmp, false, false) == InsertVertexResult.Duplicate)
|
||||
{
|
||||
if (Log.Verbose)
|
||||
{
|
||||
Log.Instance.Warning("A duplicate vertex appeared and was ignored.",
|
||||
"Incremental.IncrementalDelaunay()");
|
||||
}
|
||||
v.type = VertexType.UndeadVertex;
|
||||
mesh.undeads++;
|
||||
}
|
||||
}
|
||||
// Remove the bounding box.
|
||||
return RemoveBox();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,18 +11,17 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Logging;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
/// <summary>
|
||||
/// Builds a delaunay triangulation using the sweepline algorithm.
|
||||
/// </summary>
|
||||
class SweepLine
|
||||
public class SweepLine : ITriangulator
|
||||
{
|
||||
static int randomseed = 1;
|
||||
static int SAMPLERATE = 10;
|
||||
|
||||
int randomnation(int choices)
|
||||
static int randomnation(int choices)
|
||||
{
|
||||
randomseed = (randomseed * 1366 + 150889) % 714025;
|
||||
return randomseed / (714025 / choices + 1);
|
||||
@@ -32,6 +31,226 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
double xminextreme; // Nonexistent x value used as a flag in sweepline.
|
||||
List<SplayNode> splaynodes;
|
||||
|
||||
public IMesh Triangulate(ICollection<Vertex> points)
|
||||
{
|
||||
this.mesh = new Mesh();
|
||||
this.mesh.TransferNodes(points);
|
||||
|
||||
// Nonexistent x value used as a flag to mark circle events in sweepline
|
||||
// Delaunay algorithm.
|
||||
xminextreme = 10 * mesh.bounds.Left - 9 * mesh.bounds.Right;
|
||||
|
||||
SweepEvent[] eventheap;
|
||||
|
||||
SweepEvent nextevent;
|
||||
SweepEvent newevent;
|
||||
SplayNode splayroot;
|
||||
Otri bottommost = default(Otri);
|
||||
Otri searchtri = default(Otri);
|
||||
Otri fliptri;
|
||||
Otri lefttri = default(Otri);
|
||||
Otri righttri = default(Otri);
|
||||
Otri farlefttri = default(Otri);
|
||||
Otri farrighttri = default(Otri);
|
||||
Otri inserttri = default(Otri);
|
||||
Vertex firstvertex, secondvertex;
|
||||
Vertex nextvertex, lastvertex;
|
||||
Vertex connectvertex;
|
||||
Vertex leftvertex, midvertex, rightvertex;
|
||||
double lefttest, righttest;
|
||||
int heapsize;
|
||||
bool check4events, farrightflag = false;
|
||||
|
||||
splaynodes = new List<SplayNode>();
|
||||
splayroot = null;
|
||||
|
||||
CreateHeap(out eventheap);//, out events, out freeevents);
|
||||
heapsize = mesh.invertices;
|
||||
|
||||
mesh.MakeTriangle(ref lefttri);
|
||||
mesh.MakeTriangle(ref righttri);
|
||||
lefttri.Bond(ref righttri);
|
||||
lefttri.LnextSelf();
|
||||
righttri.LprevSelf();
|
||||
lefttri.Bond(ref righttri);
|
||||
lefttri.LnextSelf();
|
||||
righttri.LprevSelf();
|
||||
lefttri.Bond(ref righttri);
|
||||
firstvertex = eventheap[0].vertexEvent;
|
||||
|
||||
HeapDelete(eventheap, heapsize, 0);
|
||||
heapsize--;
|
||||
do
|
||||
{
|
||||
if (heapsize == 0)
|
||||
{
|
||||
Log.Instance.Error("Input vertices are all identical.", "SweepLine.Triangulate()");
|
||||
throw new Exception("Input vertices are all identical.");
|
||||
}
|
||||
secondvertex = eventheap[0].vertexEvent;
|
||||
HeapDelete(eventheap, heapsize, 0);
|
||||
heapsize--;
|
||||
if ((firstvertex.x == secondvertex.x) &&
|
||||
(firstvertex.y == secondvertex.y))
|
||||
{
|
||||
if (Log.Verbose)
|
||||
{
|
||||
Log.Instance.Warning("A duplicate vertex appeared and was ignored (ID " + secondvertex.id + ").",
|
||||
"SweepLine.Triangulate().1");
|
||||
}
|
||||
secondvertex.type = VertexType.UndeadVertex;
|
||||
mesh.undeads++;
|
||||
}
|
||||
} while ((firstvertex.x == secondvertex.x) &&
|
||||
(firstvertex.y == secondvertex.y));
|
||||
lefttri.SetOrg(firstvertex);
|
||||
lefttri.SetDest(secondvertex);
|
||||
righttri.SetOrg(secondvertex);
|
||||
righttri.SetDest(firstvertex);
|
||||
lefttri.Lprev(ref bottommost);
|
||||
lastvertex = secondvertex;
|
||||
|
||||
while (heapsize > 0)
|
||||
{
|
||||
nextevent = eventheap[0];
|
||||
HeapDelete(eventheap, heapsize, 0);
|
||||
heapsize--;
|
||||
check4events = true;
|
||||
if (nextevent.xkey < mesh.bounds.Left)
|
||||
{
|
||||
fliptri = nextevent.otriEvent;
|
||||
fliptri.Oprev(ref farlefttri);
|
||||
Check4DeadEvent(ref farlefttri, eventheap, ref heapsize);
|
||||
fliptri.Onext(ref farrighttri);
|
||||
Check4DeadEvent(ref farrighttri, eventheap, ref heapsize);
|
||||
|
||||
if (farlefttri.Equal(bottommost))
|
||||
{
|
||||
fliptri.Lprev(ref bottommost);
|
||||
}
|
||||
mesh.Flip(ref fliptri);
|
||||
fliptri.SetApex(null);
|
||||
fliptri.Lprev(ref lefttri);
|
||||
fliptri.Lnext(ref righttri);
|
||||
lefttri.Sym(ref farlefttri);
|
||||
|
||||
if (randomnation(SAMPLERATE) == 0)
|
||||
{
|
||||
fliptri.SymSelf();
|
||||
leftvertex = fliptri.Dest();
|
||||
midvertex = fliptri.Apex();
|
||||
rightvertex = fliptri.Org();
|
||||
splayroot = CircleTopInsert(splayroot, lefttri, leftvertex, midvertex, rightvertex, nextevent.ykey);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nextvertex = nextevent.vertexEvent;
|
||||
if ((nextvertex.x == lastvertex.x) &&
|
||||
(nextvertex.y == lastvertex.y))
|
||||
{
|
||||
if (Log.Verbose)
|
||||
{
|
||||
Log.Instance.Warning("A duplicate vertex appeared and was ignored (ID " + nextvertex.id + ").",
|
||||
"SweepLine.Triangulate().2");
|
||||
}
|
||||
nextvertex.type = VertexType.UndeadVertex;
|
||||
mesh.undeads++;
|
||||
check4events = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastvertex = nextvertex;
|
||||
|
||||
splayroot = FrontLocate(splayroot, bottommost, nextvertex, ref searchtri, ref farrightflag);
|
||||
|
||||
//bottommost.Copy(ref searchtri);
|
||||
//farrightflag = false;
|
||||
//while (!farrightflag && RightOfHyperbola(ref searchtri, nextvertex))
|
||||
//{
|
||||
// searchtri.OnextSelf();
|
||||
// farrightflag = searchtri.Equal(bottommost);
|
||||
//}
|
||||
|
||||
Check4DeadEvent(ref searchtri, eventheap, ref heapsize);
|
||||
|
||||
searchtri.Copy(ref farrighttri);
|
||||
searchtri.Sym(ref farlefttri);
|
||||
mesh.MakeTriangle(ref lefttri);
|
||||
mesh.MakeTriangle(ref righttri);
|
||||
connectvertex = farrighttri.Dest();
|
||||
lefttri.SetOrg(connectvertex);
|
||||
lefttri.SetDest(nextvertex);
|
||||
righttri.SetOrg(nextvertex);
|
||||
righttri.SetDest(connectvertex);
|
||||
lefttri.Bond(ref righttri);
|
||||
lefttri.LnextSelf();
|
||||
righttri.LprevSelf();
|
||||
lefttri.Bond(ref righttri);
|
||||
lefttri.LnextSelf();
|
||||
righttri.LprevSelf();
|
||||
lefttri.Bond(ref farlefttri);
|
||||
righttri.Bond(ref farrighttri);
|
||||
if (!farrightflag && farrighttri.Equal(bottommost))
|
||||
{
|
||||
lefttri.Copy(ref bottommost);
|
||||
}
|
||||
|
||||
if (randomnation(SAMPLERATE) == 0)
|
||||
{
|
||||
splayroot = SplayInsert(splayroot, lefttri, nextvertex);
|
||||
}
|
||||
else if (randomnation(SAMPLERATE) == 0)
|
||||
{
|
||||
righttri.Lnext(ref inserttri);
|
||||
splayroot = SplayInsert(splayroot, inserttri, nextvertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (check4events)
|
||||
{
|
||||
leftvertex = farlefttri.Apex();
|
||||
midvertex = lefttri.Dest();
|
||||
rightvertex = lefttri.Apex();
|
||||
lefttest = RobustPredicates.CounterClockwise(leftvertex, midvertex, rightvertex);
|
||||
if (lefttest > 0.0)
|
||||
{
|
||||
newevent = new SweepEvent();
|
||||
|
||||
newevent.xkey = xminextreme;
|
||||
newevent.ykey = CircleTop(leftvertex, midvertex, rightvertex, lefttest);
|
||||
newevent.otriEvent = lefttri;
|
||||
HeapInsert(eventheap, heapsize, newevent);
|
||||
heapsize++;
|
||||
lefttri.SetOrg(new SweepEventVertex(newevent));
|
||||
}
|
||||
leftvertex = righttri.Apex();
|
||||
midvertex = righttri.Org();
|
||||
rightvertex = farrighttri.Apex();
|
||||
righttest = RobustPredicates.CounterClockwise(leftvertex, midvertex, rightvertex);
|
||||
if (righttest > 0.0)
|
||||
{
|
||||
newevent = new SweepEvent();
|
||||
|
||||
newevent.xkey = xminextreme;
|
||||
newevent.ykey = CircleTop(leftvertex, midvertex, rightvertex, righttest);
|
||||
newevent.otriEvent = farrighttri;
|
||||
HeapInsert(eventheap, heapsize, newevent);
|
||||
heapsize++;
|
||||
farrighttri.SetOrg(new SweepEventVertex(newevent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
splaynodes.Clear();
|
||||
bottommost.LprevSelf();
|
||||
|
||||
this.mesh.hullsize = RemoveGhosts(ref bottommost);
|
||||
|
||||
return this.mesh;
|
||||
}
|
||||
|
||||
#region Heap
|
||||
|
||||
void HeapInsert(SweepEvent[] heap, int heapsize, SweepEvent newevent)
|
||||
@@ -519,222 +738,6 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
return hullsize;
|
||||
}
|
||||
|
||||
public int Triangulate(Mesh mesh)
|
||||
{
|
||||
this.mesh = mesh;
|
||||
|
||||
// Nonexistent x value used as a flag to mark circle events in sweepline
|
||||
// Delaunay algorithm.
|
||||
xminextreme = 10 * mesh.bounds.Left - 9 * mesh.bounds.Right;
|
||||
|
||||
SweepEvent[] eventheap;
|
||||
|
||||
SweepEvent nextevent;
|
||||
SweepEvent newevent;
|
||||
SplayNode splayroot;
|
||||
Otri bottommost = default(Otri);
|
||||
Otri searchtri = default(Otri);
|
||||
Otri fliptri;
|
||||
Otri lefttri = default(Otri);
|
||||
Otri righttri = default(Otri);
|
||||
Otri farlefttri = default(Otri);
|
||||
Otri farrighttri = default(Otri);
|
||||
Otri inserttri = default(Otri);
|
||||
Vertex firstvertex, secondvertex;
|
||||
Vertex nextvertex, lastvertex;
|
||||
Vertex connectvertex;
|
||||
Vertex leftvertex, midvertex, rightvertex;
|
||||
double lefttest, righttest;
|
||||
int heapsize;
|
||||
bool check4events, farrightflag = false;
|
||||
|
||||
splaynodes = new List<SplayNode>();
|
||||
splayroot = null;
|
||||
|
||||
CreateHeap(out eventheap);//, out events, out freeevents);
|
||||
heapsize = mesh.invertices;
|
||||
|
||||
mesh.MakeTriangle(ref lefttri);
|
||||
mesh.MakeTriangle(ref righttri);
|
||||
lefttri.Bond(ref righttri);
|
||||
lefttri.LnextSelf();
|
||||
righttri.LprevSelf();
|
||||
lefttri.Bond(ref righttri);
|
||||
lefttri.LnextSelf();
|
||||
righttri.LprevSelf();
|
||||
lefttri.Bond(ref righttri);
|
||||
firstvertex = eventheap[0].vertexEvent;
|
||||
|
||||
HeapDelete(eventheap, heapsize, 0);
|
||||
heapsize--;
|
||||
do
|
||||
{
|
||||
if (heapsize == 0)
|
||||
{
|
||||
Log.Instance.Error("Input vertices are all identical.", "SweepLine.Triangulate()");
|
||||
throw new Exception("Input vertices are all identical.");
|
||||
}
|
||||
secondvertex = eventheap[0].vertexEvent;
|
||||
HeapDelete(eventheap, heapsize, 0);
|
||||
heapsize--;
|
||||
if ((firstvertex.x == secondvertex.x) &&
|
||||
(firstvertex.y == secondvertex.y))
|
||||
{
|
||||
if (Log.Verbose)
|
||||
{
|
||||
Log.Instance.Warning("A duplicate vertex appeared and was ignored (ID " + secondvertex.id + ").",
|
||||
"SweepLine.Triangulate().1");
|
||||
}
|
||||
secondvertex.type = VertexType.UndeadVertex;
|
||||
mesh.undeads++;
|
||||
}
|
||||
} while ((firstvertex.x == secondvertex.x) &&
|
||||
(firstvertex.y == secondvertex.y));
|
||||
lefttri.SetOrg(firstvertex);
|
||||
lefttri.SetDest(secondvertex);
|
||||
righttri.SetOrg(secondvertex);
|
||||
righttri.SetDest(firstvertex);
|
||||
lefttri.Lprev(ref bottommost);
|
||||
lastvertex = secondvertex;
|
||||
|
||||
while (heapsize > 0)
|
||||
{
|
||||
nextevent = eventheap[0];
|
||||
HeapDelete(eventheap, heapsize, 0);
|
||||
heapsize--;
|
||||
check4events = true;
|
||||
if (nextevent.xkey < mesh.bounds.Left)
|
||||
{
|
||||
fliptri = nextevent.otriEvent;
|
||||
fliptri.Oprev(ref farlefttri);
|
||||
Check4DeadEvent(ref farlefttri, eventheap, ref heapsize);
|
||||
fliptri.Onext(ref farrighttri);
|
||||
Check4DeadEvent(ref farrighttri, eventheap, ref heapsize);
|
||||
|
||||
if (farlefttri.Equal(bottommost))
|
||||
{
|
||||
fliptri.Lprev(ref bottommost);
|
||||
}
|
||||
mesh.Flip(ref fliptri);
|
||||
fliptri.SetApex(null);
|
||||
fliptri.Lprev(ref lefttri);
|
||||
fliptri.Lnext(ref righttri);
|
||||
lefttri.Sym(ref farlefttri);
|
||||
|
||||
if (randomnation(SAMPLERATE) == 0)
|
||||
{
|
||||
fliptri.SymSelf();
|
||||
leftvertex = fliptri.Dest();
|
||||
midvertex = fliptri.Apex();
|
||||
rightvertex = fliptri.Org();
|
||||
splayroot = CircleTopInsert(splayroot, lefttri, leftvertex, midvertex, rightvertex, nextevent.ykey);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nextvertex = nextevent.vertexEvent;
|
||||
if ((nextvertex.x == lastvertex.x) &&
|
||||
(nextvertex.y == lastvertex.y))
|
||||
{
|
||||
if (Log.Verbose)
|
||||
{
|
||||
Log.Instance.Warning("A duplicate vertex appeared and was ignored (ID " + nextvertex.id + ").",
|
||||
"SweepLine.Triangulate().2");
|
||||
}
|
||||
nextvertex.type = VertexType.UndeadVertex;
|
||||
mesh.undeads++;
|
||||
check4events = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastvertex = nextvertex;
|
||||
|
||||
splayroot = FrontLocate(splayroot, bottommost, nextvertex, ref searchtri, ref farrightflag);
|
||||
|
||||
//bottommost.Copy(ref searchtri);
|
||||
//farrightflag = false;
|
||||
//while (!farrightflag && RightOfHyperbola(ref searchtri, nextvertex))
|
||||
//{
|
||||
// searchtri.OnextSelf();
|
||||
// farrightflag = searchtri.Equal(bottommost);
|
||||
//}
|
||||
|
||||
Check4DeadEvent(ref searchtri, eventheap, ref heapsize);
|
||||
|
||||
searchtri.Copy(ref farrighttri);
|
||||
searchtri.Sym(ref farlefttri);
|
||||
mesh.MakeTriangle(ref lefttri);
|
||||
mesh.MakeTriangle(ref righttri);
|
||||
connectvertex = farrighttri.Dest();
|
||||
lefttri.SetOrg(connectvertex);
|
||||
lefttri.SetDest(nextvertex);
|
||||
righttri.SetOrg(nextvertex);
|
||||
righttri.SetDest(connectvertex);
|
||||
lefttri.Bond(ref righttri);
|
||||
lefttri.LnextSelf();
|
||||
righttri.LprevSelf();
|
||||
lefttri.Bond(ref righttri);
|
||||
lefttri.LnextSelf();
|
||||
righttri.LprevSelf();
|
||||
lefttri.Bond(ref farlefttri);
|
||||
righttri.Bond(ref farrighttri);
|
||||
if (!farrightflag && farrighttri.Equal(bottommost))
|
||||
{
|
||||
lefttri.Copy(ref bottommost);
|
||||
}
|
||||
|
||||
if (randomnation(SAMPLERATE) == 0)
|
||||
{
|
||||
splayroot = SplayInsert(splayroot, lefttri, nextvertex);
|
||||
}
|
||||
else if (randomnation(SAMPLERATE) == 0)
|
||||
{
|
||||
righttri.Lnext(ref inserttri);
|
||||
splayroot = SplayInsert(splayroot, inserttri, nextvertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (check4events)
|
||||
{
|
||||
leftvertex = farlefttri.Apex();
|
||||
midvertex = lefttri.Dest();
|
||||
rightvertex = lefttri.Apex();
|
||||
lefttest = RobustPredicates.CounterClockwise(leftvertex, midvertex, rightvertex);
|
||||
if (lefttest > 0.0)
|
||||
{
|
||||
newevent = new SweepEvent();
|
||||
|
||||
newevent.xkey = xminextreme;
|
||||
newevent.ykey = CircleTop(leftvertex, midvertex, rightvertex, lefttest);
|
||||
newevent.otriEvent = lefttri;
|
||||
HeapInsert(eventheap, heapsize, newevent);
|
||||
heapsize++;
|
||||
lefttri.SetOrg(new SweepEventVertex(newevent));
|
||||
}
|
||||
leftvertex = righttri.Apex();
|
||||
midvertex = righttri.Org();
|
||||
rightvertex = farrighttri.Apex();
|
||||
righttest = RobustPredicates.CounterClockwise(leftvertex, midvertex, rightvertex);
|
||||
if (righttest > 0.0)
|
||||
{
|
||||
newevent = new SweepEvent();
|
||||
|
||||
newevent.xkey = xminextreme;
|
||||
newevent.ykey = CircleTop(leftvertex, midvertex, rightvertex, righttest);
|
||||
newevent.otriEvent = farrighttri;
|
||||
HeapInsert(eventheap, heapsize, newevent);
|
||||
heapsize++;
|
||||
farrighttri.SetOrg(new SweepEventVertex(newevent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
splaynodes.Clear();
|
||||
bottommost.LprevSelf();
|
||||
return RemoveGhosts(ref bottommost);
|
||||
}
|
||||
|
||||
#region Internal classes
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace TriangleNet.Meshing
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Logging;
|
||||
using TriangleNet.Tools;
|
||||
using TriangleNet.Meshing.Iterators;
|
||||
|
||||
internal class ConstraintMesher
|
||||
{
|
||||
@@ -165,7 +165,7 @@ namespace TriangleNet.Meshing
|
||||
/// Create the segments of a triangulation, including PSLG segments and edges
|
||||
/// on the convex hull.
|
||||
/// </summary>
|
||||
public void FormSkeleton(InputGeometry input)
|
||||
public void FormSkeleton(IPolygon input)
|
||||
{
|
||||
Vertex endpoint1, endpoint2;
|
||||
int end1, end2;
|
||||
@@ -184,7 +184,7 @@ namespace TriangleNet.Meshing
|
||||
|
||||
// If segments are to be inserted, compute a mapping
|
||||
// from vertices to triangles.
|
||||
if (input.HasSegments)
|
||||
if (input.Segments.Count > 0)
|
||||
{
|
||||
mesh.MakeVertexMap();
|
||||
}
|
||||
@@ -192,7 +192,7 @@ namespace TriangleNet.Meshing
|
||||
boundmarker = 0;
|
||||
|
||||
// Read and insert the segments.
|
||||
foreach (var seg in input.segments)
|
||||
foreach (var seg in input.Segments)
|
||||
{
|
||||
mesh.insegments++;
|
||||
|
||||
|
||||
@@ -12,14 +12,13 @@ namespace TriangleNet.Meshing
|
||||
using System.Linq;
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Logging;
|
||||
|
||||
/// <summary>
|
||||
/// The DataReader class provides methods for mesh reconstruction.
|
||||
/// </summary>
|
||||
public class Converter
|
||||
{
|
||||
public Mesh ToMesh(InputGeometry polygon, IList<ITriangle> triangles)
|
||||
public Mesh ToMesh(Polygon polygon, IList<ITriangle> triangles)
|
||||
{
|
||||
return ToMesh(polygon, triangles.ToArray());
|
||||
}
|
||||
@@ -46,7 +45,7 @@ namespace TriangleNet.Meshing
|
||||
/// the corresponding pointer is adjusted to refer to a subsegment rather
|
||||
/// than the next triangle of the stack.
|
||||
/// </remarks>
|
||||
public Mesh ToMesh(InputGeometry polygon, ITriangle[] triangles)
|
||||
public Mesh ToMesh(Polygon polygon, ITriangle[] triangles)
|
||||
{
|
||||
Otri tri = default(Otri);
|
||||
Osub subseg = default(Osub);
|
||||
@@ -57,7 +56,7 @@ namespace TriangleNet.Meshing
|
||||
|
||||
var mesh = new Mesh();
|
||||
|
||||
mesh.TransferNodes(polygon);
|
||||
mesh.TransferNodes(polygon.Points);
|
||||
|
||||
mesh.inelements = elements;
|
||||
mesh.regions.AddRange(polygon.Regions);
|
||||
@@ -213,7 +212,7 @@ namespace TriangleNet.Meshing
|
||||
return vertexarray;
|
||||
}
|
||||
|
||||
private static void SetSegments(Mesh mesh, InputGeometry polygon, List<Otri>[] vertexarray)
|
||||
private static void SetSegments(Mesh mesh, Polygon polygon, List<Otri>[] vertexarray)
|
||||
{
|
||||
Otri checktri = default(Otri);
|
||||
Otri nexttri; // Triangle
|
||||
@@ -242,9 +241,9 @@ namespace TriangleNet.Meshing
|
||||
{
|
||||
subseg.seg = item;
|
||||
|
||||
end[0] = polygon.segments[i].P0;
|
||||
end[1] = polygon.segments[i].P1;
|
||||
boundmarker = polygon.segments[i].Boundary;
|
||||
end[0] = polygon.Segments[i].P0;
|
||||
end[1] = polygon.Segments[i].P1;
|
||||
boundmarker = polygon.Segments[i].Boundary;
|
||||
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
|
||||
namespace TriangleNet.Meshing
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.IO;
|
||||
using TriangleNet.Meshing.Algorithm;
|
||||
|
||||
public class GenericMesher : ITriangulator, IConstraintMesher, IQualityMesher
|
||||
{
|
||||
ITriangulator triangulator;
|
||||
|
||||
public GenericMesher()
|
||||
: this(new Dwyer())
|
||||
{
|
||||
}
|
||||
|
||||
public GenericMesher(ITriangulator triangulator)
|
||||
{
|
||||
this.triangulator = triangulator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triangulates a point set.
|
||||
/// </summary>
|
||||
/// <param name="points">Collection of points.</param>
|
||||
/// <returns>Mesh</returns>
|
||||
public IMesh Triangulate(ICollection<Vertex> points)
|
||||
{
|
||||
return triangulator.Triangulate(points);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triangulates a polygon.
|
||||
/// </summary>
|
||||
/// <param name="polygon">The polygon.</param>
|
||||
/// <returns>Mesh</returns>
|
||||
public IMesh Triangulate(IPolygon polygon)
|
||||
{
|
||||
return Triangulate(polygon, null, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triangulates a polygon, applying constraint options.
|
||||
/// </summary>
|
||||
/// <param name="polygon">The polygon.</param>
|
||||
/// <param name="options">Constraint options.</param>
|
||||
/// <returns>Mesh</returns>
|
||||
public IMesh Triangulate(IPolygon polygon, ConstraintOptions options)
|
||||
{
|
||||
return Triangulate(polygon, options, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triangulates a polygon, applying quality options.
|
||||
/// </summary>
|
||||
/// <param name="polygon">The polygon.</param>
|
||||
/// <param name="quality">Quality options.</param>
|
||||
/// <returns>Mesh</returns>
|
||||
public IMesh Triangulate(IPolygon polygon, QualityOptions quality)
|
||||
{
|
||||
return Triangulate(polygon, null, quality);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triangulates a polygon, applying quality and constraint options.
|
||||
/// </summary>
|
||||
/// <param name="polygon">The polygon.</param>
|
||||
/// <param name="options">Constraint options.</param>
|
||||
/// <param name="quality">Quality options.</param>
|
||||
/// <returns>Mesh</returns>
|
||||
public IMesh Triangulate(IPolygon polygon, ConstraintOptions options, QualityOptions quality)
|
||||
{
|
||||
var mesh = (Mesh)triangulator.Triangulate(polygon.Points);
|
||||
|
||||
mesh.ApplyConstraints(polygon, options, quality);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a structured mesh.
|
||||
/// </summary>
|
||||
/// <param name="bounds">Bounds of the mesh.</param>
|
||||
/// <param name="nx">Number of segments in x direction.</param>
|
||||
/// <param name="ny">Number of segments in y direction.</param>
|
||||
/// <returns>Mesh</returns>
|
||||
public IMesh StructurdMesh(Rectangle bounds, int nx, int ny)
|
||||
{
|
||||
var polygon = new Polygon((nx + 1) * (ny + 1));
|
||||
|
||||
double x, y, dx, dy, left, bottom;
|
||||
|
||||
dx = bounds.Width / nx;
|
||||
dy = bounds.Height / ny;
|
||||
|
||||
left = bounds.Left;
|
||||
bottom = bounds.Bottom;
|
||||
|
||||
int i, j, k, l, n;
|
||||
|
||||
// Add vertices.
|
||||
var points = polygon.Points;
|
||||
|
||||
for (i = 0; i <= nx; i++)
|
||||
{
|
||||
x = left + i * dx;
|
||||
|
||||
for (j = 0; j <= ny; j++)
|
||||
{
|
||||
y = bottom + j * dy;
|
||||
|
||||
points.Add(new Vertex(x, y));
|
||||
}
|
||||
}
|
||||
|
||||
n = 0;
|
||||
|
||||
// Set vertex id and hash.
|
||||
foreach (var v in points)
|
||||
{
|
||||
v.id = v.hash = n++;
|
||||
}
|
||||
|
||||
// Add boundary segments.
|
||||
var segments = polygon.Segments;
|
||||
|
||||
segments.Capacity = 2 * (nx + ny);
|
||||
|
||||
for (j = 0; j < ny; j++)
|
||||
{
|
||||
// Left
|
||||
segments.Add(new Edge(j, j + 1));
|
||||
|
||||
// Right
|
||||
segments.Add(new Edge(nx * (ny + 1) + j, nx * (ny + 1) + (j + 1)));
|
||||
}
|
||||
|
||||
for (i = 0; i < nx; i++)
|
||||
{
|
||||
// Bottom
|
||||
segments.Add(new Edge(i * (ny + 1), (i + 1) * (ny + 1)));
|
||||
|
||||
// Top
|
||||
segments.Add(new Edge(i * (ny + 1) + nx, (i + 1) * (ny + 1) + nx));
|
||||
}
|
||||
|
||||
// Add triangles.
|
||||
var triangles = new InputTriangle[2 * nx * ny];
|
||||
|
||||
n = 0;
|
||||
|
||||
for (i = 0; i < nx; i++)
|
||||
{
|
||||
for (j = 0; j < ny; j++)
|
||||
{
|
||||
k = j + (ny + 1) * i;
|
||||
l = j + (ny + 1) * (i + 1);
|
||||
|
||||
triangles[n++] = new InputTriangle(k, l, l + 1);
|
||||
triangles[n++] = new InputTriangle(k, l + 1, k + 1);
|
||||
}
|
||||
}
|
||||
|
||||
var converter = new Converter();
|
||||
|
||||
return converter.ToMesh(polygon, triangles);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace TriangleNet.Meshing
|
||||
|
||||
public interface IConstraintMesher
|
||||
{
|
||||
Mesh Triangulate(IPolygon polygon);
|
||||
Mesh Triangulate(IPolygon polygon, ConstraintOptions options);
|
||||
IMesh Triangulate(IPolygon polygon);
|
||||
IMesh Triangulate(IPolygon polygon, ConstraintOptions options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
namespace TriangleNet.Meshing
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
public interface IMesh
|
||||
{
|
||||
ICollection<Vertex> Vertices { get; }
|
||||
IEnumerable<Edge> Edges { get; }
|
||||
ICollection<Segment> Segments { get; }
|
||||
ICollection<Triangle> Triangles { get; }
|
||||
IList<Point> Holes { get; }
|
||||
|
||||
Rectangle Bounds { get; }
|
||||
|
||||
void Refine(QualityOptions quality);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace TriangleNet.Meshing
|
||||
|
||||
public interface IQualityMesher
|
||||
{
|
||||
Mesh Triangulate(IPolygon polygon, QualityOptions quality);
|
||||
Mesh Triangulate(IPolygon polygon, ConstraintOptions options, QualityOptions quality);
|
||||
IMesh Triangulate(IPolygon polygon, QualityOptions quality);
|
||||
IMesh Triangulate(IPolygon polygon, ConstraintOptions options, QualityOptions quality);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,6 @@ namespace TriangleNet.Meshing
|
||||
/// </summary>
|
||||
public interface ITriangulator
|
||||
{
|
||||
Mesh Triangulate(ICollection<Vertex> points);
|
||||
IMesh Triangulate(ICollection<Vertex> points);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-7
@@ -4,18 +4,16 @@
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Geometry
|
||||
namespace TriangleNet.Meshing.Iterators
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates the edges of a triangulation.
|
||||
/// </summary>
|
||||
public class EdgeEnumerator : IEnumerator<Edge>
|
||||
public class EdgeIterator : IEnumerator<Edge>
|
||||
{
|
||||
IEnumerator<Triangle> triangles;
|
||||
Otri tri = default(Otri);
|
||||
@@ -25,9 +23,9 @@ namespace TriangleNet.Geometry
|
||||
Vertex p1, p2;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EdgeEnumerator" /> class.
|
||||
/// Initializes a new instance of the <see cref="EdgeIterator" /> class.
|
||||
/// </summary>
|
||||
public EdgeEnumerator(Mesh mesh)
|
||||
public EdgeIterator(Mesh mesh)
|
||||
{
|
||||
triangles = mesh.triangles.Values.GetEnumerator();
|
||||
triangles.MoveNext();
|
||||
+1
-3
@@ -5,12 +5,10 @@
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Tools
|
||||
namespace TriangleNet.Meshing.Iterators
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TriangleNet.Data;
|
||||
|
||||
/// <summary>
|
||||
@@ -6,16 +6,14 @@
|
||||
|
||||
namespace TriangleNet.Smoothing
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TriangleNet.Meshing;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for mesh smoothers.
|
||||
/// </summary>
|
||||
public interface ISmoother
|
||||
{
|
||||
void Smooth();
|
||||
void Smooth(IMesh mesh);
|
||||
void Smooth(IMesh mesh, int limit);
|
||||
}
|
||||
}
|
||||
@@ -6,11 +6,8 @@
|
||||
|
||||
namespace TriangleNet.Smoothing
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
/// <summary>
|
||||
@@ -22,35 +19,42 @@ namespace TriangleNet.Smoothing
|
||||
/// </remarks>
|
||||
public class SimpleSmoother : ISmoother
|
||||
{
|
||||
Mesh mesh;
|
||||
ConstraintOptions options;
|
||||
|
||||
public SimpleSmoother(Mesh mesh)
|
||||
public SimpleSmoother()
|
||||
{
|
||||
this.mesh = mesh;
|
||||
this.options = new ConstraintOptions() { ConformingDelaunay = true };
|
||||
}
|
||||
|
||||
public void Smooth()
|
||||
public void Smooth(IMesh mesh)
|
||||
{
|
||||
mesh.behavior.Quality = false;
|
||||
Smooth(mesh, 10);
|
||||
}
|
||||
|
||||
public void Smooth(IMesh mesh, int limit)
|
||||
{
|
||||
var smoothedMesh = (Mesh)mesh;
|
||||
|
||||
// Take a few smoothing rounds.
|
||||
for (int i = 0; i < 5; i++)
|
||||
for (int i = 0; i < limit; i++)
|
||||
{
|
||||
Step();
|
||||
Step(smoothedMesh);
|
||||
|
||||
// Actually, we only want to rebuild, if mesh is no longer
|
||||
// Delaunay. Flipping edges could be the right choice instead
|
||||
// of re-triangulating...
|
||||
mesh.Triangulate(Rebuild());
|
||||
smoothedMesh = (Mesh)Rebuild(smoothedMesh).Triangulate(options);
|
||||
}
|
||||
|
||||
smoothedMesh.CopyTo((Mesh)mesh);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Smooth all free nodes.
|
||||
/// </summary>
|
||||
private void Step()
|
||||
private void Step(Mesh mesh)
|
||||
{
|
||||
BoundedVoronoi voronoi = new BoundedVoronoi(this.mesh, false);
|
||||
BoundedVoronoi voronoi = new BoundedVoronoi(mesh, false);
|
||||
|
||||
var cells = voronoi.Regions;
|
||||
|
||||
@@ -76,31 +80,24 @@ namespace TriangleNet.Smoothing
|
||||
/// <summary>
|
||||
/// Rebuild the input geometry.
|
||||
/// </summary>
|
||||
private InputGeometry Rebuild()
|
||||
private Polygon Rebuild(Mesh mesh)
|
||||
{
|
||||
InputGeometry geometry = new InputGeometry(mesh.vertices.Count);
|
||||
var data = new Polygon(mesh.vertices.Count);
|
||||
|
||||
foreach (var vertex in mesh.vertices.Values)
|
||||
foreach (var v in mesh.vertices.Values)
|
||||
{
|
||||
geometry.AddPoint(vertex.x, vertex.y, vertex.mark);
|
||||
// Reset to input vertex.
|
||||
v.type = VertexType.InputVertex;
|
||||
|
||||
data.Points.Add(v);
|
||||
}
|
||||
|
||||
foreach (var segment in mesh.subsegs.Values)
|
||||
{
|
||||
geometry.AddSegment(segment.P0, segment.P1, segment.Boundary);
|
||||
}
|
||||
data.Segments.AddRange(mesh.subsegs.Values);
|
||||
|
||||
foreach (var hole in mesh.holes)
|
||||
{
|
||||
geometry.AddHole(hole.x, hole.y);
|
||||
}
|
||||
data.Holes.AddRange(mesh.holes);
|
||||
data.Regions.AddRange(mesh.regions);
|
||||
|
||||
foreach (var region in mesh.regions)
|
||||
{
|
||||
geometry.AddRegion(region.point.x, region.point.y, region.id);
|
||||
}
|
||||
|
||||
return geometry;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ namespace TriangleNet.Tools
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
@@ -285,7 +283,7 @@ namespace TriangleNet.Tools
|
||||
|
||||
if (f_init.Org() != vertex)
|
||||
{
|
||||
throw new Exception("ConstructBvdCell: inconsistent topology.");
|
||||
throw new Exception("ConstructCell: inconsistent topology.");
|
||||
}
|
||||
|
||||
// Let f be initialized to f_init
|
||||
@@ -399,7 +397,7 @@ namespace TriangleNet.Tools
|
||||
|
||||
if (f_init.Org() != vertex)
|
||||
{
|
||||
throw new Exception("ConstructBoundaryBvdCell: inconsistent topology.");
|
||||
throw new Exception("ConstructBoundaryCell: inconsistent topology.");
|
||||
}
|
||||
// Let f be initialized to f_init
|
||||
f_init.Copy(ref f);
|
||||
|
||||
@@ -108,6 +108,7 @@ namespace TriangleNet.Tools
|
||||
// Point is inside or on the edge of this triangle.
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -115,315 +116,314 @@ namespace TriangleNet.Tools
|
||||
{
|
||||
return p.X * q.X + p.Y * q.Y;
|
||||
}
|
||||
}
|
||||
|
||||
#region QuadNode class
|
||||
|
||||
/// <summary>
|
||||
/// A node of the quadtree.
|
||||
/// </summary>
|
||||
class QuadNode
|
||||
{
|
||||
const int SW = 0;
|
||||
const int SE = 1;
|
||||
const int NW = 2;
|
||||
const int NE = 3;
|
||||
|
||||
const double EPS = 1e-6;
|
||||
|
||||
static readonly byte[] BITVECTOR = { 0x1, 0x2, 0x4, 0x8 };
|
||||
|
||||
Rectangle bounds;
|
||||
Point pivot;
|
||||
QuadTree tree;
|
||||
QuadNode[] regions;
|
||||
List<int> triangles;
|
||||
|
||||
byte bitRegions;
|
||||
|
||||
public QuadNode(Rectangle box, QuadTree tree)
|
||||
: this(box, tree, false)
|
||||
/// <summary>
|
||||
/// A node of the quadtree.
|
||||
/// </summary>
|
||||
class QuadNode
|
||||
{
|
||||
}
|
||||
const int SW = 0;
|
||||
const int SE = 1;
|
||||
const int NW = 2;
|
||||
const int NE = 3;
|
||||
|
||||
public QuadNode(Rectangle box, QuadTree tree, bool init)
|
||||
{
|
||||
this.tree = tree;
|
||||
const double EPS = 1e-6;
|
||||
|
||||
this.bounds = new Rectangle(box.Left, box.Bottom, box.Right, box.Top);
|
||||
this.pivot = new Point((box.Left + box.Right) / 2, (box.Bottom + box.Top) / 2);
|
||||
static readonly byte[] BITVECTOR = { 0x1, 0x2, 0x4, 0x8 };
|
||||
|
||||
this.bitRegions = 0;
|
||||
Rectangle bounds;
|
||||
Point pivot;
|
||||
QuadTree tree;
|
||||
QuadNode[] regions;
|
||||
List<int> triangles;
|
||||
|
||||
this.regions = new QuadNode[4];
|
||||
this.triangles = new List<int>();
|
||||
byte bitRegions;
|
||||
|
||||
if (init)
|
||||
public QuadNode(Rectangle box, QuadTree tree)
|
||||
: this(box, tree, false)
|
||||
{
|
||||
int count = tree.triangles.Length;
|
||||
}
|
||||
|
||||
// Allocate memory upfront
|
||||
triangles.Capacity = count;
|
||||
public QuadNode(Rectangle box, QuadTree tree, bool init)
|
||||
{
|
||||
this.tree = tree;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
this.bounds = new Rectangle(box.Left, box.Bottom, box.Width, box.Height);
|
||||
this.pivot = new Point((box.Left + box.Right) / 2, (box.Bottom + box.Top) / 2);
|
||||
|
||||
this.bitRegions = 0;
|
||||
|
||||
this.regions = new QuadNode[4];
|
||||
this.triangles = new List<int>();
|
||||
|
||||
if (init)
|
||||
{
|
||||
triangles.Add(i);
|
||||
int count = tree.triangles.Length;
|
||||
|
||||
// Allocate memory upfront
|
||||
triangles.Capacity = count;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
triangles.Add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<int> FindTriangles(Point searchPoint)
|
||||
{
|
||||
int region = FindRegion(searchPoint);
|
||||
if (regions[region] == null)
|
||||
public List<int> FindTriangles(Point searchPoint)
|
||||
{
|
||||
return triangles;
|
||||
}
|
||||
return regions[region].FindTriangles(searchPoint);
|
||||
}
|
||||
|
||||
public void CreateSubRegion(int currentDepth)
|
||||
{
|
||||
// The four sub regions of the quad tree
|
||||
// +--------------+
|
||||
// | nw | ne |
|
||||
// |------+pivot--|
|
||||
// | sw | se |
|
||||
// +--------------+
|
||||
Rectangle box;
|
||||
|
||||
// 1. region south west
|
||||
box = new Rectangle(bounds.Left, bounds.Bottom, pivot.X, pivot.Y);
|
||||
regions[0] = new QuadNode(box, tree);
|
||||
|
||||
// 2. region south east
|
||||
box = new Rectangle(pivot.X, bounds.Bottom, bounds.Right, pivot.Y);
|
||||
regions[1] = new QuadNode(box, tree);
|
||||
|
||||
// 3. region north west
|
||||
box = new Rectangle(bounds.Left, pivot.Y, pivot.X, bounds.Top);
|
||||
regions[2] = new QuadNode(box, tree);
|
||||
|
||||
// 4. region north east
|
||||
box = new Rectangle(pivot.X, pivot.Y, bounds.Right, bounds.Top);
|
||||
regions[3] = new QuadNode(box, tree);
|
||||
|
||||
Point[] triangle = new Point[3];
|
||||
|
||||
// Find region for every triangle vertex
|
||||
foreach (var index in triangles)
|
||||
{
|
||||
ITriangle tri = tree.triangles[index];
|
||||
|
||||
triangle[0] = tri.GetVertex(0);
|
||||
triangle[1] = tri.GetVertex(1);
|
||||
triangle[2] = tri.GetVertex(2);
|
||||
|
||||
AddTriangleToRegion(triangle, index);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (regions[i].triangles.Count > tree.sizeBound && currentDepth < tree.maxDepth)
|
||||
int region = FindRegion(searchPoint);
|
||||
if (regions[region] == null)
|
||||
{
|
||||
regions[i].CreateSubRegion(currentDepth + 1);
|
||||
return triangles;
|
||||
}
|
||||
return regions[region].FindTriangles(searchPoint);
|
||||
}
|
||||
|
||||
public void CreateSubRegion(int currentDepth)
|
||||
{
|
||||
// The four sub regions of the quad tree
|
||||
// +--------------+
|
||||
// | nw | ne |
|
||||
// |------+pivot--|
|
||||
// | sw | se |
|
||||
// +--------------+
|
||||
Rectangle box;
|
||||
|
||||
var width = bounds.Right - pivot.X;
|
||||
var height = bounds.Top - pivot.Y;
|
||||
|
||||
// 1. region south west
|
||||
box = new Rectangle(bounds.Left, bounds.Bottom, width, height);
|
||||
regions[0] = new QuadNode(box, tree);
|
||||
|
||||
// 2. region south east
|
||||
box = new Rectangle(pivot.X, bounds.Bottom, width, height);
|
||||
regions[1] = new QuadNode(box, tree);
|
||||
|
||||
// 3. region north west
|
||||
box = new Rectangle(bounds.Left, pivot.Y, width, height);
|
||||
regions[2] = new QuadNode(box, tree);
|
||||
|
||||
// 4. region north east
|
||||
box = new Rectangle(pivot.X, pivot.Y, width, height);
|
||||
regions[3] = new QuadNode(box, tree);
|
||||
|
||||
Point[] triangle = new Point[3];
|
||||
|
||||
// Find region for every triangle vertex
|
||||
foreach (var index in triangles)
|
||||
{
|
||||
ITriangle tri = tree.triangles[index];
|
||||
|
||||
triangle[0] = tri.GetVertex(0);
|
||||
triangle[1] = tri.GetVertex(1);
|
||||
triangle[2] = tri.GetVertex(2);
|
||||
|
||||
AddTriangleToRegion(triangle, index);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (regions[i].triangles.Count > tree.sizeBound && currentDepth < tree.maxDepth)
|
||||
{
|
||||
regions[i].CreateSubRegion(currentDepth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddTriangleToRegion(Point[] triangle, int index)
|
||||
{
|
||||
bitRegions = 0;
|
||||
if (QuadTree.IsPointInTriangle(pivot, triangle[0], triangle[1], triangle[2]))
|
||||
void AddTriangleToRegion(Point[] triangle, int index)
|
||||
{
|
||||
AddToRegion(index, SW);
|
||||
AddToRegion(index, SE);
|
||||
AddToRegion(index, NW);
|
||||
AddToRegion(index, NE);
|
||||
return;
|
||||
}
|
||||
|
||||
FindTriangleIntersections(triangle, index);
|
||||
|
||||
if (bitRegions == 0)
|
||||
{
|
||||
// we didn't find any intersection so we add this triangle to a point's region
|
||||
int region = FindRegion(triangle[0]);
|
||||
regions[region].triangles.Add(index);
|
||||
}
|
||||
}
|
||||
|
||||
void FindTriangleIntersections(Point[] triangle, int index)
|
||||
{
|
||||
// PLEASE NOTE:
|
||||
// Handling of component comparison is tightly associated with the implementation
|
||||
// of the findRegion() function. That means when the point to be compared equals
|
||||
// the pivot point the triangle must be put at least into region 2.
|
||||
//
|
||||
// Linear equations are in parametric form.
|
||||
// pivot.x = triangle[0].x + t * (triangle[1].x - triangle[0].x)
|
||||
// pivot.y = triangle[0].y + t * (triangle[1].y - triangle[0].y)
|
||||
|
||||
int k = 2;
|
||||
|
||||
double dx, dy;
|
||||
// Iterate through all triangle laterals and find bounding box intersections
|
||||
for (int i = 0; i < 3; k = i++)
|
||||
{
|
||||
dx = triangle[i].X - triangle[k].X;
|
||||
dy = triangle[i].Y - triangle[k].Y;
|
||||
|
||||
if (dx != 0.0)
|
||||
{
|
||||
FindIntersectionsWithX(dx, dy, triangle, index, k);
|
||||
}
|
||||
if (dy != 0.0)
|
||||
{
|
||||
FindIntersectionsWithY(dx, dy, triangle, index, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FindIntersectionsWithX(double dx, double dy, Point[] triangle, int index, int k)
|
||||
{
|
||||
double t;
|
||||
|
||||
// find intersection with plane x = m_pivot.dX
|
||||
t = (pivot.X - triangle[k].X) / dx;
|
||||
if (t < (1 + EPS) && t > -EPS)
|
||||
{
|
||||
// we have an intersection
|
||||
double yComponent = triangle[k].Y + t * dy;
|
||||
|
||||
if (yComponent < pivot.Y && yComponent >= bounds.Bottom)
|
||||
bitRegions = 0;
|
||||
if (QuadTree.IsPointInTriangle(pivot, triangle[0], triangle[1], triangle[2]))
|
||||
{
|
||||
AddToRegion(index, SW);
|
||||
AddToRegion(index, SE);
|
||||
}
|
||||
else if (yComponent <= bounds.Top)
|
||||
{
|
||||
AddToRegion(index, NW);
|
||||
AddToRegion(index, NE);
|
||||
return;
|
||||
}
|
||||
|
||||
FindTriangleIntersections(triangle, index);
|
||||
|
||||
if (bitRegions == 0)
|
||||
{
|
||||
// we didn't find any intersection so we add this triangle to a point's region
|
||||
int region = FindRegion(triangle[0]);
|
||||
regions[region].triangles.Add(index);
|
||||
}
|
||||
}
|
||||
|
||||
// find intersection with plane x = m_boundingBox[0].dX
|
||||
t = (bounds.Left - triangle[k].X) / dx;
|
||||
if (t < (1 + EPS) && t > -EPS)
|
||||
void FindTriangleIntersections(Point[] triangle, int index)
|
||||
{
|
||||
// we have an intersection
|
||||
double yComponent = triangle[k].Y + t * dy;
|
||||
// PLEASE NOTE:
|
||||
// Handling of component comparison is tightly associated with the implementation
|
||||
// of the findRegion() function. That means when the point to be compared equals
|
||||
// the pivot point the triangle must be put at least into region 2.
|
||||
//
|
||||
// Linear equations are in parametric form.
|
||||
// pivot.x = triangle[0].x + t * (triangle[1].x - triangle[0].x)
|
||||
// pivot.y = triangle[0].y + t * (triangle[1].y - triangle[0].y)
|
||||
|
||||
if (yComponent < pivot.Y && yComponent >= bounds.Bottom)
|
||||
int k = 2;
|
||||
|
||||
double dx, dy;
|
||||
// Iterate through all triangle laterals and find bounding box intersections
|
||||
for (int i = 0; i < 3; k = i++)
|
||||
{
|
||||
AddToRegion(index, SW);
|
||||
}
|
||||
else if (yComponent <= bounds.Top) // TODO: check && yComponent >= pivot.Y
|
||||
{
|
||||
AddToRegion(index, NW);
|
||||
dx = triangle[i].X - triangle[k].X;
|
||||
dy = triangle[i].Y - triangle[k].Y;
|
||||
|
||||
if (dx != 0.0)
|
||||
{
|
||||
FindIntersectionsWithX(dx, dy, triangle, index, k);
|
||||
}
|
||||
if (dy != 0.0)
|
||||
{
|
||||
FindIntersectionsWithY(dx, dy, triangle, index, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find intersection with plane x = m_boundingBox[1].dX
|
||||
t = (bounds.Right - triangle[k].X) / dx;
|
||||
if (t < (1 + EPS) && t > -EPS)
|
||||
void FindIntersectionsWithX(double dx, double dy, Point[] triangle, int index, int k)
|
||||
{
|
||||
// we have an intersection
|
||||
double yComponent = triangle[k].Y + t * dy;
|
||||
double t;
|
||||
|
||||
if (yComponent < pivot.Y && yComponent >= bounds.Bottom)
|
||||
// find intersection with plane x = m_pivot.dX
|
||||
t = (pivot.X - triangle[k].X) / dx;
|
||||
if (t < (1 + EPS) && t > -EPS)
|
||||
{
|
||||
AddToRegion(index, SE);
|
||||
// we have an intersection
|
||||
double yComponent = triangle[k].Y + t * dy;
|
||||
|
||||
if (yComponent < pivot.Y && yComponent >= bounds.Bottom)
|
||||
{
|
||||
AddToRegion(index, SW);
|
||||
AddToRegion(index, SE);
|
||||
}
|
||||
else if (yComponent <= bounds.Top)
|
||||
{
|
||||
AddToRegion(index, NW);
|
||||
AddToRegion(index, NE);
|
||||
}
|
||||
}
|
||||
else if (yComponent <= bounds.Top)
|
||||
|
||||
// find intersection with plane x = m_boundingBox[0].dX
|
||||
t = (bounds.Left - triangle[k].X) / dx;
|
||||
if (t < (1 + EPS) && t > -EPS)
|
||||
{
|
||||
AddToRegion(index, NE);
|
||||
// we have an intersection
|
||||
double yComponent = triangle[k].Y + t * dy;
|
||||
|
||||
if (yComponent < pivot.Y && yComponent >= bounds.Bottom)
|
||||
{
|
||||
AddToRegion(index, SW);
|
||||
}
|
||||
else if (yComponent <= bounds.Top) // TODO: check && yComponent >= pivot.Y
|
||||
{
|
||||
AddToRegion(index, NW);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FindIntersectionsWithY(double dx, double dy, Point[] triangle, int index, int k)
|
||||
{
|
||||
double t, xComponent;
|
||||
|
||||
// find intersection with plane y = m_pivot.dY
|
||||
t = (pivot.Y - triangle[k].Y) / dy;
|
||||
if (t < (1 + EPS) && t > -EPS)
|
||||
{
|
||||
// we have an intersection
|
||||
xComponent = triangle[k].X + t * dx;
|
||||
|
||||
if (xComponent > pivot.X && xComponent <= bounds.Right)
|
||||
// find intersection with plane x = m_boundingBox[1].dX
|
||||
t = (bounds.Right - triangle[k].X) / dx;
|
||||
if (t < (1 + EPS) && t > -EPS)
|
||||
{
|
||||
AddToRegion(index, SE);
|
||||
AddToRegion(index, NE);
|
||||
}
|
||||
else if (xComponent >= bounds.Left)
|
||||
{
|
||||
AddToRegion(index, SW);
|
||||
AddToRegion(index, NW);
|
||||
// we have an intersection
|
||||
double yComponent = triangle[k].Y + t * dy;
|
||||
|
||||
if (yComponent < pivot.Y && yComponent >= bounds.Bottom)
|
||||
{
|
||||
AddToRegion(index, SE);
|
||||
}
|
||||
else if (yComponent <= bounds.Top)
|
||||
{
|
||||
AddToRegion(index, NE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find intersection with plane y = m_boundingBox[0].dY
|
||||
t = (bounds.Bottom - triangle[k].Y) / dy;
|
||||
if (t < (1 + EPS) && t > -EPS)
|
||||
void FindIntersectionsWithY(double dx, double dy, Point[] triangle, int index, int k)
|
||||
{
|
||||
// we have an intersection
|
||||
xComponent = triangle[k].X + t * dx;
|
||||
double t, xComponent;
|
||||
|
||||
if (xComponent > pivot.X && xComponent <= bounds.Right)
|
||||
// find intersection with plane y = m_pivot.dY
|
||||
t = (pivot.Y - triangle[k].Y) / dy;
|
||||
if (t < (1 + EPS) && t > -EPS)
|
||||
{
|
||||
AddToRegion(index, SE);
|
||||
// we have an intersection
|
||||
xComponent = triangle[k].X + t * dx;
|
||||
|
||||
if (xComponent > pivot.X && xComponent <= bounds.Right)
|
||||
{
|
||||
AddToRegion(index, SE);
|
||||
AddToRegion(index, NE);
|
||||
}
|
||||
else if (xComponent >= bounds.Left)
|
||||
{
|
||||
AddToRegion(index, SW);
|
||||
AddToRegion(index, NW);
|
||||
}
|
||||
}
|
||||
else if (xComponent >= bounds.Left)
|
||||
|
||||
// find intersection with plane y = m_boundingBox[0].dY
|
||||
t = (bounds.Bottom - triangle[k].Y) / dy;
|
||||
if (t < (1 + EPS) && t > -EPS)
|
||||
{
|
||||
AddToRegion(index, SW);
|
||||
// we have an intersection
|
||||
xComponent = triangle[k].X + t * dx;
|
||||
|
||||
if (xComponent > pivot.X && xComponent <= bounds.Right)
|
||||
{
|
||||
AddToRegion(index, SE);
|
||||
}
|
||||
else if (xComponent >= bounds.Left)
|
||||
{
|
||||
AddToRegion(index, SW);
|
||||
}
|
||||
}
|
||||
|
||||
// find intersection with plane y = m_boundingBox[1].dY
|
||||
t = (bounds.Top - triangle[k].Y) / dy;
|
||||
if (t < (1 + EPS) && t > -EPS)
|
||||
{
|
||||
// we have an intersection
|
||||
xComponent = triangle[k].X + t * dx;
|
||||
|
||||
if (xComponent > pivot.X && xComponent <= bounds.Right)
|
||||
{
|
||||
AddToRegion(index, NE);
|
||||
}
|
||||
else if (xComponent >= bounds.Left)
|
||||
{
|
||||
AddToRegion(index, NW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find intersection with plane y = m_boundingBox[1].dY
|
||||
t = (bounds.Top - triangle[k].Y) / dy;
|
||||
if (t < (1 + EPS) && t > -EPS)
|
||||
int FindRegion(Point point)
|
||||
{
|
||||
// we have an intersection
|
||||
xComponent = triangle[k].X + t * dx;
|
||||
|
||||
if (xComponent > pivot.X && xComponent <= bounds.Right)
|
||||
int b = 2;
|
||||
if (point.Y < pivot.Y)
|
||||
{
|
||||
AddToRegion(index, NE);
|
||||
b = 0;
|
||||
}
|
||||
else if (xComponent >= bounds.Left)
|
||||
if (point.X > pivot.X)
|
||||
{
|
||||
AddToRegion(index, NW);
|
||||
b++;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
int FindRegion(Point point)
|
||||
{
|
||||
int b = 2;
|
||||
if (point.Y < pivot.Y)
|
||||
void AddToRegion(int index, int region)
|
||||
{
|
||||
b = 0;
|
||||
}
|
||||
if (point.X > pivot.X)
|
||||
{
|
||||
b++;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
void AddToRegion(int index, int region)
|
||||
{
|
||||
//if (!(m_bitRegions & BITVECTOR[region]))
|
||||
if ((bitRegions & BITVECTOR[region]) == 0)
|
||||
{
|
||||
regions[region].triangles.Add(index);
|
||||
bitRegions |= BITVECTOR[region];
|
||||
//if (!(m_bitRegions & BITVECTOR[region]))
|
||||
if ((bitRegions & BITVECTOR[region]) == 0)
|
||||
{
|
||||
regions[region].triangles.Add(index);
|
||||
bitRegions |= BITVECTOR[region];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -43,12 +43,15 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="Geometry\IEdge.cs" />
|
||||
<Compile Include="Geometry\IPolygon.cs" />
|
||||
<Compile Include="Geometry\IPolygonExtensions.cs" />
|
||||
<Compile Include="Geometry\Polygon.cs" />
|
||||
<Compile Include="IO\FileProcessor.cs" />
|
||||
<Compile Include="IO\IFileFormat.cs" />
|
||||
<Compile Include="Meshing\ConstraintOptions.cs" />
|
||||
<Compile Include="Meshing\Converter.cs" />
|
||||
<Compile Include="Meshing\GenericMesher.cs" />
|
||||
<Compile Include="Meshing\IConstraintMesher.cs" />
|
||||
<Compile Include="Meshing\IMesh.cs" />
|
||||
<Compile Include="Meshing\IQualityMesher.cs" />
|
||||
<Compile Include="Meshing\ITriangulator.cs" />
|
||||
<Compile Include="Data\BadTriQueue.cs" />
|
||||
@@ -64,8 +67,7 @@
|
||||
<Compile Include="Meshing\Algorithm\Dwyer.cs" />
|
||||
<Compile Include="Geometry\Rectangle.cs" />
|
||||
<Compile Include="Geometry\Edge.cs" />
|
||||
<Compile Include="Geometry\EdgeEnumerator.cs" />
|
||||
<Compile Include="Geometry\InputGeometry.cs" />
|
||||
<Compile Include="Meshing\Iterators\EdgeIterator.cs" />
|
||||
<Compile Include="Geometry\ITriangle.cs" />
|
||||
<Compile Include="Geometry\Point.cs" />
|
||||
<Compile Include="Geometry\RegionPointer.cs" />
|
||||
@@ -99,7 +101,7 @@
|
||||
<Compile Include="Tools\IVoronoi.cs" />
|
||||
<Compile Include="Tools\QuadTree.cs" />
|
||||
<Compile Include="Tools\QualityMeasure.cs" />
|
||||
<Compile Include="Tools\RegionIterator.cs" />
|
||||
<Compile Include="Meshing\Iterators\RegionIterator.cs" />
|
||||
<Compile Include="Tools\Statistic.cs" />
|
||||
<Compile Include="Meshing\Algorithm\SweepLine.cs" />
|
||||
<Compile Include="Tools\Voronoi.cs" />
|
||||
|
||||
Reference in New Issue
Block a user