From 665c8f6d445026d28239d138d6ef1b486dd6104b Mon Sep 17 00:00:00 2001 From: Remi Gillig Date: Sat, 6 Feb 2016 07:32:20 +0000 Subject: [PATCH] Add NoEmptyPolygons on Tess instance to remove zero area polygons. --- LibTessDotNet/Sources/MeshUtils.cs | 15 +++++++++++++++ LibTessDotNet/Sources/Tess.cs | 29 +++++++++++++++++++++++------ TessBed/MainForm.Designer.cs | 14 ++++++++++++++ TessBed/MainForm.cs | 6 ++++++ TessBed/UnitTests.cs | 27 +++++++++++++++++++++++++++ 5 files changed, 85 insertions(+), 6 deletions(-) diff --git a/LibTessDotNet/Sources/MeshUtils.cs b/LibTessDotNet/Sources/MeshUtils.cs index 17fbad3..b633593 100644 --- a/LibTessDotNet/Sources/MeshUtils.cs +++ b/LibTessDotNet/Sources/MeshUtils.cs @@ -371,5 +371,20 @@ public static void KillFace(Face fDel, Face newLFace) fNext._prev = fPrev; fPrev._next = fNext; } + + /// + /// Return signed area of face. + /// + public static float FaceArea(Face f) + { + float area = 0.0f; + var e = f._anEdge; + do + { + area += (e._Org._s - e._Dst._s) * (e._Org._t + e._Dst._t); + e = e._Lnext; + } while (e != f._anEdge); + return area; + } } } diff --git a/LibTessDotNet/Sources/Tess.cs b/LibTessDotNet/Sources/Tess.cs index 93990f8..5a51d3a 100644 --- a/LibTessDotNet/Sources/Tess.cs +++ b/LibTessDotNet/Sources/Tess.cs @@ -31,6 +31,7 @@ ** LibTessDotNet: Remi Gillig, https://github.com/speps/LibTessDotNet */ +using System; using System.Diagnostics; namespace LibTessDotNet @@ -99,6 +100,8 @@ public partial class Tess public float SUnitY = 0.0f; public float SentinelCoord = 4e30f; + public bool NoEmptyPolygons = false; + public ContourVertex[] Vertices { get { return _vertices; } } public int VertexCount { get { return _vertexCount; } } @@ -187,15 +190,11 @@ private void CheckOrientation() float area = 0.0f; for (var f = _mesh._fHead._next; f != _mesh._fHead; f = f._next) { - var e = f._anEdge; - if (e._winding <= 0) + if (f._anEdge._winding <= 0) { continue; } - do { - area += (e._Org._s - e._Dst._s) * (e._Org._t + e._Dst._t); - e = e._Lnext; - } while (e != f._anEdge); + area += MeshUtils.FaceArea(f); } if (area < 0.0f) { @@ -455,6 +454,15 @@ private void OutputPolymesh(ElementType elementType, int polySize) f._n = MeshUtils.Undef; if (!f._inside) continue; + if (NoEmptyPolygons) + { + float area = MeshUtils.FaceArea(f); + if (Math.Abs(area) < float.Epsilon) + { + continue; + } + } + edge = f._anEdge; faceVerts = 0; do { @@ -500,6 +508,15 @@ private void OutputPolymesh(ElementType elementType, int polySize) { if (!f._inside) continue; + if (NoEmptyPolygons) + { + float area = MeshUtils.FaceArea(f); + if (Math.Abs(area) < float.Epsilon) + { + continue; + } + } + // Store polygon edge = f._anEdge; faceVerts = 0; diff --git a/TessBed/MainForm.Designer.cs b/TessBed/MainForm.Designer.cs index fe61097..0220305 100644 --- a/TessBed/MainForm.Designer.cs +++ b/TessBed/MainForm.Designer.cs @@ -43,6 +43,7 @@ private void InitializeComponent() this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); this.toolStripButtonShowInput = new System.Windows.Forms.ToolStripButton(); this.toolStripButtonShowWinding = new System.Windows.Forms.ToolStripButton(); + this.toolStripButtonNoEmpty = new System.Windows.Forms.ToolStripButton(); this.toolStripButtonBench = new System.Windows.Forms.ToolStripButton(); this.toolStripButtonOpen = new System.Windows.Forms.ToolStripButton(); this.panel = new System.Windows.Forms.Panel(); @@ -79,6 +80,7 @@ private void InitializeComponent() this.toolStripSeparator3, this.toolStripButtonShowInput, this.toolStripButtonShowWinding, + this.toolStripButtonNoEmpty, this.toolStripButtonBench, this.toolStripButtonOpen}); this.toolStrip.Location = new System.Drawing.Point(0, 0); @@ -157,6 +159,17 @@ private void InitializeComponent() this.toolStripButtonShowWinding.Size = new System.Drawing.Size(86, 22); this.toolStripButtonShowWinding.Text = "Show winding"; // + // toolStripButtonNoEmpty + // + this.toolStripButtonNoEmpty.CheckOnClick = true; + this.toolStripButtonNoEmpty.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.toolStripButtonNoEmpty.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButtonNoEmpty.Image"))); + this.toolStripButtonNoEmpty.ImageTransparentColor = System.Drawing.Color.Magenta; + this.toolStripButtonNoEmpty.Name = "toolStripButtonNoEmpty"; + this.toolStripButtonNoEmpty.Size = new System.Drawing.Size(86, 22); + this.toolStripButtonNoEmpty.Text = "No empty"; + this.toolStripButtonNoEmpty.ToolTipText = "Remove empty polygons"; + // // toolStripButtonBench // this.toolStripButtonBench.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; @@ -220,6 +233,7 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripTextBox toolStripPolySize; private System.Windows.Forms.ToolStripButton toolStripButtonShowInput; private System.Windows.Forms.ToolStripButton toolStripButtonShowWinding; + private System.Windows.Forms.ToolStripButton toolStripButtonNoEmpty; private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; private System.Windows.Forms.ToolStripButton toolStripButtonBench; private System.Windows.Forms.ToolStripButton toolStripButtonOpen; diff --git a/TessBed/MainForm.cs b/TessBed/MainForm.cs index 405ba4e..36566a3 100644 --- a/TessBed/MainForm.cs +++ b/TessBed/MainForm.cs @@ -72,6 +72,12 @@ public MainForm() RefreshAsset(toolStripAssets.SelectedIndex); }; + toolStripButtonNoEmpty.CheckedChanged += delegate(object sender, EventArgs e) + { + _tess.NoEmptyPolygons = toolStripButtonNoEmpty.Checked; + RefreshAsset(toolStripAssets.SelectedIndex); + }; + toolStripButtonBench.Click += delegate(object sender, EventArgs e) { new BenchForm().ShowDialog(this); diff --git a/TessBed/UnitTests.cs b/TessBed/UnitTests.cs index c214e80..2ad9438 100644 --- a/TessBed/UnitTests.cs +++ b/TessBed/UnitTests.cs @@ -104,6 +104,33 @@ public void Tesselate_WithIssue1Quad_ReturnsSameResultAsLibtess2() } } + [Test] + // From https://github.com/speps/LibTessDotNet/issues/1 + public void Tesselate_WithNoEmptyPolygonsTrue_RemovesEmptyPolygons() + { + string data = "2,0,4\n2,0,2\n4,0,2\n4,0,0\n0,0,0\n0,0,4"; + var indices = new List(); + var expectedIndices = new int[] { 0, 1, 2, 2, 3, 4, 3, 1, 5 }; + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(data))) + { + var pset = DataLoader.LoadDat(stream); + var tess = new Tess(); + PolyConvert.ToTess(pset, tess); + tess.NoEmptyPolygons = true; + tess.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3); + indices.Clear(); + for (int i = 0; i < tess.ElementCount; i++) + { + for (int j = 0; j < 3; j++) + { + int index = tess.Elements[i * 3 + j]; + indices.Add(index); + } + } + Assert.AreEqual(expectedIndices, indices.ToArray()); + } + } + [Test] public void Tesselate_CalledTwiceOnSameInstance_DoesNotCrash() {