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:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user