diff --git a/Triangle.NET/TestApp/FormGenerator.cs b/Triangle.NET/TestApp/FormGenerator.cs
index 213f9e0..6bd8356 100644
--- a/Triangle.NET/TestApp/FormGenerator.cs
+++ b/Triangle.NET/TestApp/FormGenerator.cs
@@ -134,6 +134,7 @@ namespace MeshExplorer
darkListBox1.Items.Add(new RandomPointsCircle());
darkListBox1.Items.Add(new StarInBox());
darkListBox1.Items.Add(new RingPolygon());
+ darkListBox1.Items.Add(new BoxWithHole());
darkListBox1.SelectedIndex = 0;
}
diff --git a/Triangle.NET/TestApp/FormLog.Designer.cs b/Triangle.NET/TestApp/FormLog.Designer.cs
index 0e3347e..f680174 100644
--- a/Triangle.NET/TestApp/FormLog.Designer.cs
+++ b/Triangle.NET/TestApp/FormLog.Designer.cs
@@ -51,6 +51,7 @@
this.listLog.UseCompatibleStateImageBehavior = false;
this.listLog.View = System.Windows.Forms.View.Details;
this.listLog.DoubleClick += new System.EventHandler(this.listLog_DoubleClick);
+ this.listLog.KeyDown += new System.Windows.Forms.KeyEventHandler(this.listLog_KeyDown);
//
// colMessage
//
diff --git a/Triangle.NET/TestApp/FormLog.cs b/Triangle.NET/TestApp/FormLog.cs
index d54ab91..32df43a 100644
--- a/Triangle.NET/TestApp/FormLog.cs
+++ b/Triangle.NET/TestApp/FormLog.cs
@@ -74,6 +74,18 @@ namespace MeshExplorer
}
}
+ private void listLog_KeyDown(object sender, KeyEventArgs e)
+ {
+ if (e.KeyCode == Keys.Delete)
+ {
+ if (ModifierKeys == Keys.Control)
+ {
+ listLog.Items.Clear();
+ SimpleLog.Instance.Clear();
+ }
+ }
+ }
+
private void listLog_DoubleClick(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder();
diff --git a/Triangle.NET/TestApp/FormLog.resx b/Triangle.NET/TestApp/FormLog.resx
new file mode 100644
index 0000000..29dcb1b
--- /dev/null
+++ b/Triangle.NET/TestApp/FormLog.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Triangle.NET/TestApp/FormMain.cs b/Triangle.NET/TestApp/FormMain.cs
index 00c6f47..240964c 100644
--- a/Triangle.NET/TestApp/FormMain.cs
+++ b/Triangle.NET/TestApp/FormMain.cs
@@ -289,7 +289,7 @@ namespace MeshExplorer
// Update Statistic view
statisticView.HandleMeshChange(mesh);
- // TODO: Should the Voronoi diagram automaticaly update?
+ // TODO: Should the Voronoi diagram automatically update?
menuViewVoronoi.Checked = false;
// Enable menu items
@@ -534,7 +534,7 @@ namespace MeshExplorer
statisticView.UpdateStatistic(mesh);
- HandleMeshChange();
+ HandleMeshUpdate();
}
catch (Exception ex)
{
@@ -650,8 +650,6 @@ namespace MeshExplorer
voronoi = new Voronoi(mesh);
}
- voronoi.Generate();
-
renderData.SetVoronoi(voronoi);
renderManager.SetData(renderData);
diff --git a/Triangle.NET/TestApp/Generators/BoxWithHole.cs b/Triangle.NET/TestApp/Generators/BoxWithHole.cs
new file mode 100644
index 0000000..6424e9c
--- /dev/null
+++ b/Triangle.NET/TestApp/Generators/BoxWithHole.cs
@@ -0,0 +1,163 @@
+// -----------------------------------------------------------------------
+//
+// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
+//
+// -----------------------------------------------------------------------
+
+namespace MeshExplorer.Generators
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using TriangleNet.Geometry;
+
+ ///
+ /// Generates a star contained in a box.
+ ///
+ public class BoxWithHole : IGenerator
+ {
+ public string Name
+ {
+ get { return "Box with Hole"; }
+ }
+
+ public string Description
+ {
+ get { return ""; }
+ }
+
+ public int ParameterCount
+ {
+ get { return 3; }
+ }
+
+ public string ParameterDescription(int paramIndex)
+ {
+ if (paramIndex == 1)
+ {
+ return "Points on box sides:";
+ }
+
+ if (paramIndex == 2)
+ {
+ return "Points on hole:";
+ }
+
+ if (paramIndex == 3)
+ {
+ return "Radius:";
+ }
+
+ return "";
+ }
+
+ public string ParameterDescription(int paramIndex, double paramValue)
+ {
+ if (paramIndex == 1)
+ {
+ int numPoints = (int)((50.0 - 5.0) / 100.0 * paramValue + 5.0);
+
+ if (numPoints < 5)
+ {
+ numPoints = 5;
+ }
+
+ return numPoints.ToString();
+ }
+
+ if (paramIndex == 2)
+ {
+ int numPoints = (int)((100.0 - 10.0) / 100.0 * paramValue + 10.0);
+ numPoints = (numPoints / 5) * 5;
+
+ if (numPoints < 10)
+ {
+ numPoints = 10;
+ }
+
+ return numPoints.ToString();
+ }
+
+ if (paramIndex == 3)
+ {
+ int radius = (int)((20.0 - 5.0) / 100.0 * paramValue + 5.0);
+
+ return radius.ToString();
+ }
+
+ return "";
+ }
+
+ public InputGeometry Generate(double param1, double param2, double param3)
+ {
+ int numPoints = (int)((100.0 - 10.0) / 100.0 * param2 + 10.0);
+
+ InputGeometry input = new InputGeometry(numPoints + 4);
+
+ double x, y, step = 2 * Math.PI / numPoints;
+
+ double r = (int)((20.0 - 5.0) / 100.0 * param3 + 5.0);
+
+ // Generate circle
+ for (int i = 0; i < numPoints; i++)
+ {
+ x = r * Math.Cos(i * step);
+ y = r * Math.Sin(i * step);
+
+ input.AddPoint(x, y, 2);
+ input.AddSegment(i, (i + 1) % numPoints, 2);
+ }
+
+ numPoints = input.Count;
+
+ int numPointsB = (int)((50.0 - 5.0) / 100.0 * param1 + 5.0);
+
+ // Box sides are 100 units long
+ step = 100.0 / numPointsB;
+
+ // Left box boundary points
+ for (int i = 0; i < numPointsB; i++)
+ {
+ input.AddPoint(-50, -50 + i * step, 1);
+ }
+
+ // Top box boundary points
+ for (int i = 0; i < numPointsB; i++)
+ {
+ input.AddPoint(-50 + i * step, 50, 1);
+ }
+
+ // Right box boundary points
+ for (int i = 0; i < numPointsB; i++)
+ {
+ input.AddPoint(50, 50 - i * step, 1);
+ }
+
+ // Bottom box boundary points
+ for (int i = 0; i < numPointsB; i++)
+ {
+ input.AddPoint(50 - i * step, -50, 1);
+ }
+
+ // Add box segments
+ for (int i = numPoints; i < input.Count - 1; i++)
+ {
+ input.AddSegment(i, i + 1, 1);
+ }
+
+ // Add last segments which closes the box
+ input.AddSegment(input.Count - 1, numPoints, 1);
+
+ // Add hole
+ input.AddHole(0, 0);
+
+ return input;
+ }
+
+ public override string ToString()
+ {
+ return this.Name;
+ }
+ }
+}
diff --git a/Triangle.NET/TestApp/Mesh Explorer.csproj b/Triangle.NET/TestApp/Mesh Explorer.csproj
index 1645317..3845269 100644
--- a/Triangle.NET/TestApp/Mesh Explorer.csproj
+++ b/Triangle.NET/TestApp/Mesh Explorer.csproj
@@ -96,6 +96,7 @@
FormMain.cs
+
@@ -138,6 +139,9 @@
FormGenerator.cs
+
+ FormLog.cs
+
FormMain.cs
diff --git a/Triangle.NET/Triangle/Mesh.cs b/Triangle.NET/Triangle/Mesh.cs
index 0d3214b..ad24ec5 100644
--- a/Triangle.NET/Triangle/Mesh.cs
+++ b/Triangle.NET/Triangle/Mesh.cs
@@ -129,6 +129,21 @@ namespace TriangleNet
get { return this.subsegs.Values; }
}
+ ///
+ /// Gets the mesh edges.
+ ///
+ public IEnumerable Edges
+ {
+ get
+ {
+ EdgeEnumerator e = new EdgeEnumerator(this);
+ while (e.MoveNext())
+ {
+ yield return e.Current;
+ }
+ }
+ }
+
///
/// Gets the number of input vertices.
///
@@ -457,8 +472,8 @@ namespace TriangleNet
{
numbering = NodeNumbering.None;
- //ISmoother smoother = new CvdSmoother(this);
- //smoother.Smooth();
+ ISmoother smoother = new SimpleSmoother(this);
+ smoother.Smooth();
}
///
diff --git a/Triangle.NET/Triangle/Smoothing/SimpleSmoother.cs b/Triangle.NET/Triangle/Smoothing/SimpleSmoother.cs
new file mode 100644
index 0000000..77e4bdd
--- /dev/null
+++ b/Triangle.NET/Triangle/Smoothing/SimpleSmoother.cs
@@ -0,0 +1,98 @@
+// -----------------------------------------------------------------------
+//
+// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
+//
+// -----------------------------------------------------------------------
+
+namespace TriangleNet.Smoothing
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using TriangleNet.Geometry;
+ using TriangleNet.Tools;
+
+ ///
+ /// Simple mesh smoother implementation.
+ ///
+ public class SimpleSmoother : ISmoother
+ {
+ Mesh mesh;
+
+ public SimpleSmoother(Mesh mesh)
+ {
+ this.mesh = mesh;
+ }
+
+ public void Smooth()
+ {
+ // Take a few smoothing rounds.
+ for (int i = 0; i < 5; i++)
+ {
+ Step();
+
+ // Actually, we only want to rebuild, if mesh is no longer
+ // Delaunay. Flipping edges could be the right choice instead
+ // of re-triangulating...
+ var geometry = Rebuild();
+
+ mesh.SetOption(Options.Quality, false);
+ mesh.Triangulate(geometry);
+ }
+ }
+
+ ///
+ /// Smooth all free nodes.
+ ///
+ private void Step()
+ {
+ BoundedVoronoi voronoi = new BoundedVoronoi(this.mesh, false);
+
+ var cells = voronoi.Regions;
+
+ double x, y;
+ int n;
+
+ foreach (var cell in cells)
+ {
+ n = 0;
+ x = y = 0.0;
+ foreach (var p in cell.Vertices)
+ {
+ n++;
+ x += p.x;
+ y += p.y;
+ }
+
+ cell.Generator.x = x / n;
+ cell.Generator.y = y / n;
+ }
+ }
+
+ ///
+ /// Rebuild the input geometry.
+ ///
+ private InputGeometry Rebuild()
+ {
+ InputGeometry geometry = new InputGeometry(mesh.vertices.Count);
+
+ foreach (var vertex in mesh.vertices.Values)
+ {
+ geometry.AddPoint(vertex.x, vertex.y, vertex.mark);
+ }
+
+ foreach (var segment in mesh.subsegs.Values)
+ {
+ geometry.AddSegment(segment.P0, segment.P1, segment.Boundary);
+ }
+
+ foreach (var hole in mesh.holes)
+ {
+ geometry.AddHole(hole.x, hole.y);
+ }
+
+ return geometry;
+ }
+ }
+}
diff --git a/Triangle.NET/Triangle/Tools/BoundedVoronoi.cs b/Triangle.NET/Triangle/Tools/BoundedVoronoi.cs
index 3bce64f..5b357e0 100644
--- a/Triangle.NET/Triangle/Tools/BoundedVoronoi.cs
+++ b/Triangle.NET/Triangle/Tools/BoundedVoronoi.cs
@@ -31,13 +31,27 @@ namespace TriangleNet.Tools
Dictionary subsegMap;
+ bool includeBoundary = true;
+
///
/// Initializes a new instance of the class.
///
/// Mesh instance.
public BoundedVoronoi(Mesh mesh)
+ : this(mesh, true)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Mesh instance.
+ public BoundedVoronoi(Mesh mesh, bool includeBoundary)
{
this.mesh = mesh;
+ this.includeBoundary = includeBoundary;
+
+ Generate();
}
///
@@ -59,7 +73,7 @@ namespace TriangleNet.Tools
///
/// Computes the bounded voronoi diagram.
///
- public void Generate()
+ private void Generate()
{
mesh.Renumber();
mesh.MakeVertexMap();
@@ -79,7 +93,7 @@ namespace TriangleNet.Tools
{
ConstructBvdCell(v);
}
- else
+ else if (includeBoundary)
{
ConstructBoundaryBvdCell(v);
}
diff --git a/Triangle.NET/Triangle/Tools/IVoronoi.cs b/Triangle.NET/Triangle/Tools/IVoronoi.cs
index ca63f50..591efad 100644
--- a/Triangle.NET/Triangle/Tools/IVoronoi.cs
+++ b/Triangle.NET/Triangle/Tools/IVoronoi.cs
@@ -20,10 +20,8 @@ namespace TriangleNet.Tools
Point[] Points { get; }
///
- /// Gets the directions for infinite Voronoi edges.
+ /// Gets the list of Voronoi regions.
///
List Regions { get; }
-
- void Generate();
}
}
diff --git a/Triangle.NET/Triangle/Tools/Voronoi.cs b/Triangle.NET/Triangle/Tools/Voronoi.cs
index 370cd0f..c1e6919 100644
--- a/Triangle.NET/Triangle/Tools/Voronoi.cs
+++ b/Triangle.NET/Triangle/Tools/Voronoi.cs
@@ -34,6 +34,8 @@ namespace TriangleNet.Tools
public Voronoi(Mesh mesh)
{
this.mesh = mesh;
+
+ Generate();
}
///
@@ -63,7 +65,7 @@ namespace TriangleNet.Tools
/// triangles, and the Voronoi edges are listed by traversing the Delaunay
/// edges.
///
- public void Generate()
+ private void Generate()
{
mesh.Renumber();
mesh.MakeVertexMap();
diff --git a/Triangle.NET/Triangle/Triangle.csproj b/Triangle.NET/Triangle/Triangle.csproj
index 7b9aad5..35c3610 100644
--- a/Triangle.NET/Triangle/Triangle.csproj
+++ b/Triangle.NET/Triangle/Triangle.csproj
@@ -81,6 +81,7 @@
+