diff --git a/Triangle.NET/MeshRenderer.Core/GDI/MeshRenderer.cs b/Triangle.NET/MeshRenderer.Core/GDI/MeshRenderer.cs
index 1b4a66f..68ec82a 100644
--- a/Triangle.NET/MeshRenderer.Core/GDI/MeshRenderer.cs
+++ b/Triangle.NET/MeshRenderer.Core/GDI/MeshRenderer.cs
@@ -22,12 +22,28 @@ namespace MeshRenderer.Core.GDI
RenderData data;
ColorManager renderColors;
+ // If true, even geometry parts outside of bounds will be rendered.
+ bool ignoreBounds;
+
///
/// Initializes a new instance of the class.
///
public MeshRenderer(RenderData data)
{
this.data = data;
+
+ int featureCount = data.Points.Length;
+
+ if (data.MeshEdges != null)
+ {
+ featureCount += data.MeshEdges.Length;
+ }
+ else if (data.Triangles != null)
+ {
+ featureCount += 2 * data.Triangles.Length;
+ }
+
+ this.ignoreBounds = featureCount < 1000;
}
///
@@ -106,7 +122,7 @@ namespace MeshRenderer.Core.GDI
for (i = 0; i < n; i++)
{
k = 2 * i;
- if (zoom.ViewportContains(pts[k], pts[k + 1]))
+ if (ignoreBounds || zoom.ViewportContains(pts[k], pts[k + 1]))
{
pt = zoom.WorldToScreen(pts[k], pts[k + 1]);
g.FillEllipse(renderColors.Point, pt.X - 1.5f, pt.Y - 1.5f, 3, 3);
@@ -118,7 +134,7 @@ namespace MeshRenderer.Core.GDI
for (; i < n; i++)
{
k = 2 * i;
- if (zoom.ViewportContains(pts[k], pts[k + 1]))
+ if (ignoreBounds || zoom.ViewportContains(pts[k], pts[k + 1]))
{
pt = zoom.WorldToScreen(pts[k], pts[k + 1]);
g.FillEllipse(renderColors.SteinerPoint, pt.X - 1.5f, pt.Y - 1.5f, 3, 3);
@@ -140,9 +156,10 @@ namespace MeshRenderer.Core.GDI
k1 = 2 * data.Triangles[3 * i + 1];
k2 = 2 * data.Triangles[3 * i + 2];
- if (zoom.ViewportContains(pts[k0], pts[k0 + 1]) ||
+ if (ignoreBounds ||
+ (zoom.ViewportContains(pts[k0], pts[k0 + 1]) ||
zoom.ViewportContains(pts[k1], pts[k1 + 1]) ||
- zoom.ViewportContains(pts[k2], pts[k2 + 1]))
+ zoom.ViewportContains(pts[k2], pts[k2 + 1])))
{
p0 = zoom.WorldToScreen(pts[k0], pts[k0 + 1]);
p1 = zoom.WorldToScreen(pts[k1], pts[k1 + 1]);
@@ -168,8 +185,9 @@ namespace MeshRenderer.Core.GDI
k0 = 2 * data.MeshEdges[2 * i];
k1 = 2 * data.MeshEdges[2 * i + 1];
- if (zoom.ViewportContains(pts[k0], pts[k0 + 1]) ||
- zoom.ViewportContains(pts[k1], pts[k1 + 1]))
+ if (ignoreBounds ||
+ (zoom.ViewportContains(pts[k0], pts[k0 + 1]) ||
+ zoom.ViewportContains(pts[k1], pts[k1 + 1])))
{
p0 = zoom.WorldToScreen(pts[k0], pts[k0 + 1]);
p1 = zoom.WorldToScreen(pts[k1], pts[k1 + 1]);
@@ -192,8 +210,9 @@ namespace MeshRenderer.Core.GDI
k0 = 2 * data.Segments[2 * i];
k1 = 2 * data.Segments[2 * i + 1];
- if (zoom.ViewportContains(pts[k0], pts[k0 + 1]) ||
- zoom.ViewportContains(pts[k1], pts[k1 + 1]))
+ if (ignoreBounds ||
+ (zoom.ViewportContains(pts[k0], pts[k0 + 1]) ||
+ zoom.ViewportContains(pts[k1], pts[k1 + 1])))
{
p0 = zoom.WorldToScreen(pts[k0], pts[k0 + 1]);
p1 = zoom.WorldToScreen(pts[k1], pts[k1 + 1]);
diff --git a/Triangle.NET/MeshRenderer.Core/GDI/RenderControl.cs b/Triangle.NET/MeshRenderer.Core/GDI/RenderControl.cs
index 016011a..9c22657 100644
--- a/Triangle.NET/MeshRenderer.Core/GDI/RenderControl.cs
+++ b/Triangle.NET/MeshRenderer.Core/GDI/RenderControl.cs
@@ -224,19 +224,18 @@ namespace MeshRenderer.Core.GDI
}
else if (e.Button == MouseButtons.Left)
{
- /*
- // Just in case ...
timer.Stop();
+ var nfi = System.Globalization.CultureInfo.InvariantCulture.NumberFormat;
+
PointF c = zoom.ScreenToWorld((float)e.X / this.Width, (float)e.Y / this.Height);
coordinate = String.Format("X:{0} Y:{1}",
- c.X.ToString(Util.Nfi),
- c.Y.ToString(Util.Nfi));
+ c.X.ToString(nfi),
+ c.Y.ToString(nfi));
this.Invalidate();
timer.Start();
- * */
}
base.OnMouseClick(e);
diff --git a/Triangle.NET/MeshRenderer.Core/RenderData.cs b/Triangle.NET/MeshRenderer.Core/RenderData.cs
index c97dc96..953476a 100644
--- a/Triangle.NET/MeshRenderer.Core/RenderData.cs
+++ b/Triangle.NET/MeshRenderer.Core/RenderData.cs
@@ -154,7 +154,6 @@ namespace MeshRenderer.Core
///
public void SetVoronoi(IVoronoi voro, int infCount)
{
-
int i, n = voro.Points.Length;
// Copy points
diff --git a/Triangle.NET/TestApp/FormMain.cs b/Triangle.NET/TestApp/FormMain.cs
index c51fb46..555a21d 100644
--- a/Triangle.NET/TestApp/FormMain.cs
+++ b/Triangle.NET/TestApp/FormMain.cs
@@ -441,6 +441,11 @@ namespace MeshExplorer
mesh.SetOption(Options.ConformingDelaunay, true);
}
+ if (meshControlView.ParamSweeplineChecked)
+ {
+ mesh.SetOption(Options.TriangulationAlgorithm, TriangulationAlgorithm.SweepLine);
+ }
+
if (meshControlView.ParamQualityChecked)
{
mesh.SetOption(Options.Quality, true);
@@ -705,10 +710,7 @@ namespace MeshExplorer
bool isConsistent, isDelaunay;
mesh.Check(out isConsistent, out isDelaunay);
- if (!isConsistent || !isDelaunay)
- {
- ShowLog();
- }
+ ShowLog();
}
}
diff --git a/Triangle.NET/TestApp/Views/MeshControlView.Designer.cs b/Triangle.NET/TestApp/Views/MeshControlView.Designer.cs
index 7117dc4..7f4d56b 100644
--- a/Triangle.NET/TestApp/Views/MeshControlView.Designer.cs
+++ b/Triangle.NET/TestApp/Views/MeshControlView.Designer.cs
@@ -40,6 +40,8 @@
this.cbConformDel = new MeshExplorer.Controls.DarkCheckBox();
this.cbConvex = new MeshExplorer.Controls.DarkCheckBox();
this.cbQuality = new MeshExplorer.Controls.DarkCheckBox();
+ this.cbSweepline = new MeshExplorer.Controls.DarkCheckBox();
+ this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// lbMaxArea
@@ -175,6 +177,27 @@
this.cbQuality.Text = "Quality mesh";
this.cbQuality.UseVisualStyleBackColor = false;
//
+ // cbSweepline
+ //
+ this.cbSweepline.BackColor = System.Drawing.Color.DimGray;
+ this.cbSweepline.Checked = false;
+ this.cbSweepline.Location = new System.Drawing.Point(11, 260);
+ this.cbSweepline.Name = "cbSweepline";
+ this.cbSweepline.Size = new System.Drawing.Size(187, 17);
+ this.cbSweepline.TabIndex = 15;
+ this.cbSweepline.Text = "Use Sweepline algorithm";
+ this.cbSweepline.UseVisualStyleBackColor = false;
+ //
+ // label1
+ //
+ this.label1.BackColor = System.Drawing.Color.DimGray;
+ this.label1.ForeColor = System.Drawing.Color.DarkGray;
+ this.label1.Location = new System.Drawing.Point(8, 280);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(258, 33);
+ this.label1.TabIndex = 26;
+ this.label1.Text = "Use Sweepline algorithm for triangulation instead of default Divide && Conquer.";
+ //
// MeshControlView
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -184,12 +207,14 @@
this.Controls.Add(this.label6);
this.Controls.Add(this.lbMinAngle);
this.Controls.Add(this.label23);
+ this.Controls.Add(this.label1);
this.Controls.Add(this.label9);
this.Controls.Add(this.label8);
this.Controls.Add(this.label5);
this.Controls.Add(this.slMaxArea);
this.Controls.Add(this.slMinAngle);
this.Controls.Add(this.cbConformDel);
+ this.Controls.Add(this.cbSweepline);
this.Controls.Add(this.cbConvex);
this.Controls.Add(this.cbQuality);
this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
@@ -215,5 +240,7 @@
private Controls.DarkCheckBox cbConformDel;
private Controls.DarkCheckBox cbConvex;
private Controls.DarkCheckBox cbQuality;
+ private Controls.DarkCheckBox cbSweepline;
+ private System.Windows.Forms.Label label1;
}
}
diff --git a/Triangle.NET/TestApp/Views/MeshControlView.cs b/Triangle.NET/TestApp/Views/MeshControlView.cs
index 0b30bc4..dbb311c 100644
--- a/Triangle.NET/TestApp/Views/MeshControlView.cs
+++ b/Triangle.NET/TestApp/Views/MeshControlView.cs
@@ -33,6 +33,11 @@ namespace MeshExplorer.Views
get { return cbConformDel.Checked; }
}
+ public bool ParamSweeplineChecked
+ {
+ get { return cbSweepline.Checked; }
+ }
+
public int ParamMinAngleValue
{
get { return (slMinAngle.Value * 40) / 100; }
diff --git a/Triangle.NET/Triangle/Algorithm/Dwyer.cs b/Triangle.NET/Triangle/Algorithm/Dwyer.cs
index 12e03c9..edf0b79 100644
--- a/Triangle.NET/Triangle/Algorithm/Dwyer.cs
+++ b/Triangle.NET/Triangle/Algorithm/Dwyer.cs
@@ -53,7 +53,6 @@ namespace TriangleNet.Algorithm
///
/// Sort an array of vertices by x-coordinate, using the y-coordinate as a secondary key.
///
- ///
///
///
///
@@ -137,7 +136,6 @@ namespace TriangleNet.Algorithm
/// An order statistic algorithm, almost. Shuffles an array of vertices so that
/// the first 'median' vertices occur lexicographically before the remaining vertices.
///
- ///
///
///
///
@@ -219,7 +217,6 @@ namespace TriangleNet.Algorithm
/// Sorts the vertices as appropriate for the divide-and-conquer algorithm with
/// alternating cuts.
///
- ///
///
///
///
diff --git a/Triangle.NET/Triangle/Mesh.cs b/Triangle.NET/Triangle/Mesh.cs
index e36d14e..5c5a6f5 100644
--- a/Triangle.NET/Triangle/Mesh.cs
+++ b/Triangle.NET/Triangle/Mesh.cs
@@ -233,6 +233,8 @@ namespace TriangleNet
if (input.HasSegments)
{
behavior.Poly = true;
+
+ this.holes.AddRange(input.Holes);
}
//if (input.EdgeMarkers != null)
@@ -261,7 +263,6 @@ namespace TriangleNet
// Read and reconstruct a mesh.
hullsize = DataReader.Reconstruct(this, input, triangles.ToArray());
-
// Calculate the number of edges.
edges = (3 * triangles.Count + hullsize) / 2;
}
diff --git a/Triangle.NET/Triangle/Primitives.cs b/Triangle.NET/Triangle/Primitives.cs
index 1f40079..a08f2a9 100644
--- a/Triangle.NET/Triangle/Primitives.cs
+++ b/Triangle.NET/Triangle/Primitives.cs
@@ -147,12 +147,42 @@ namespace TriangleNet
return det;
}
- return det;
-
- // TODO: throw new Exception();
- // return counterclockwiseadapt(pa, pb, pc, detsum);
+ return (double)CounterClockwiseDecimal(pa, pb, pc);
}
+ private static decimal CounterClockwiseDecimal(Point pa, Point pb, Point pc)
+ {
+ decimal detleft, detright, det, detsum;
+
+ detleft = ((decimal)pa.x - (decimal)pc.x) * ((decimal)pb.y - (decimal)pc.y);
+ detright = ((decimal)pa.y - (decimal)pc.y) * ((decimal)pb.x - (decimal)pc.x);
+ det = detleft - detright;
+
+ if (detleft > 0.0m)
+ {
+ if (detright <= 0.0m)
+ {
+ return det;
+ }
+ else
+ {
+ detsum = detleft + detright;
+ }
+ }
+ else if (detleft < 0.0m)
+ {
+ if (detright >= 0.0m)
+ {
+ return det;
+ }
+ else
+ {
+ detsum = -detleft - detright;
+ }
+ }
+
+ return det;
+ }
///
/// Check if the point pd lies inside the circle passing through pa, pb, and pc. The
@@ -223,10 +253,37 @@ namespace TriangleNet
return det;
}
- return det;
+ return (double)InCircleDecimal(pa, pb, pc, pd);
+ }
- // TODO: throw new Exception();
- //return incircleadapt(pa, pb, pc, pd, permanent);
+ private static decimal InCircleDecimal(Point pa, Point pb, Point pc, Point pd)
+ {
+ decimal adx, bdx, cdx, ady, bdy, cdy;
+ decimal bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
+ decimal alift, blift, clift;
+
+ adx = (decimal)pa.x - (decimal)pd.x;
+ bdx = (decimal)pb.x - (decimal)pd.x;
+ cdx = (decimal)pc.x - (decimal)pd.x;
+ ady = (decimal)pa.y - (decimal)pd.y;
+ bdy = (decimal)pb.y - (decimal)pd.y;
+ cdy = (decimal)pc.y - (decimal)pd.y;
+
+ bdxcdy = bdx * cdy;
+ cdxbdy = cdx * bdy;
+ alift = adx * adx + ady * ady;
+
+ cdxady = cdx * ady;
+ adxcdy = adx * cdy;
+ blift = bdx * bdx + bdy * bdy;
+
+ adxbdy = adx * bdy;
+ bdxady = bdx * ady;
+ clift = cdx * cdx + cdy * cdy;
+
+ return alift * (bdxcdy - cdxbdy)
+ + blift * (cdxady - adxcdy)
+ + clift * (adxbdy - bdxady);
}
///