Fixed issue #9774,

Added higher precision primitives (decimal type, 128bit), 
Fixed mesh import not including holes, 
Some minor changes to UI and rendering

git-svn-id: https://triangle.svn.codeplex.com/svn@71221 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
SND\wo80_cp
2012-12-08 15:06:08 +00:00
parent 2b8de82d97
commit 99d2202fad
9 changed files with 135 additions and 29 deletions
@@ -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;
/// <summary>
/// Initializes a new instance of the <see cref="MeshRenderer" /> class.
/// </summary>
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;
}
/// <summary>
@@ -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]);
@@ -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);
@@ -154,7 +154,6 @@ namespace MeshRenderer.Core
/// </summary>
public void SetVoronoi(IVoronoi voro, int infCount)
{
int i, n = voro.Points.Length;
// Copy points
+6 -4
View File
@@ -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();
}
}
+27
View File
@@ -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;
}
}
@@ -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; }
-3
View File
@@ -53,7 +53,6 @@ namespace TriangleNet.Algorithm
/// <summary>
/// Sort an array of vertices by x-coordinate, using the y-coordinate as a secondary key.
/// </summary>
/// <param name="sortarray"></param>
/// <param name="left"></param>
/// <param name="right"></param>
/// <remarks>
@@ -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.
/// </summary>
/// <param name="sortarray"></param>
/// <param name="left"></param>
/// <param name="right"></param>
/// <param name="median"></param>
@@ -219,7 +217,6 @@ namespace TriangleNet.Algorithm
/// Sorts the vertices as appropriate for the divide-and-conquer algorithm with
/// alternating cuts.
/// </summary>
/// <param name="sortarray"></param>
/// <param name="left"></param>
/// <param name="right"></param>
/// <param name="axis"></param>
+2 -1
View File
@@ -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;
}
+64 -7
View File
@@ -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;
}
/// <summary>
/// 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);
}
/// <summary>