From 601ded964323668a6206662876c322b20037a965 Mon Sep 17 00:00:00 2001 From: wo80 Date: Sat, 28 May 2022 16:41:40 +0200 Subject: [PATCH] Add more tests. --- .../Meshing/GenericMesherTest.cs | 40 ++++++ .../Meshing/Iterators/VertexCirculatorTest.cs | 78 ++++++++++ .../Tools/AdjacencyMatrixTest.cs | 79 +++++++++++ .../Tools/IntersectionHelperTest.cs | 134 ++++++++++++++++++ src/Triangle.Tests/Tools/StatisticTest.cs | 61 ++++++++ src/Triangle.Tests/TrianglePoolTest.cs | 130 +++++++++++++++++ 6 files changed, 522 insertions(+) create mode 100644 src/Triangle.Tests/Meshing/GenericMesherTest.cs create mode 100644 src/Triangle.Tests/Meshing/Iterators/VertexCirculatorTest.cs create mode 100644 src/Triangle.Tests/Tools/AdjacencyMatrixTest.cs create mode 100644 src/Triangle.Tests/Tools/StatisticTest.cs create mode 100644 src/Triangle.Tests/TrianglePoolTest.cs diff --git a/src/Triangle.Tests/Meshing/GenericMesherTest.cs b/src/Triangle.Tests/Meshing/GenericMesherTest.cs new file mode 100644 index 0000000..36fe2f6 --- /dev/null +++ b/src/Triangle.Tests/Meshing/GenericMesherTest.cs @@ -0,0 +1,40 @@ +using NUnit.Framework; +using System.Collections.Generic; +using System.Linq; +using TriangleNet.Geometry; +using TriangleNet.Meshing; + +namespace TriangleNet.Tests.Meshing +{ + public class GenericMesherTest + { + [Test] + public void TestTriangulateDwyer() + { + var m = new GenericMesher(); + + var vertices = GetVertices(); + + var mesh = m.Triangulate(vertices); + + Assert.AreEqual(6, vertices.Count); + Assert.AreEqual(6, mesh.Vertices.Count); + Assert.AreEqual(1, mesh.Vertices + .Where(v => v.Type == VertexType.UndeadVertex) + .Count()); + } + + private List GetVertices() + { + return new List() + { + new Vertex(0.0, 0.0), + new Vertex(1.0, 0.0), + new Vertex(1.0, 1.0), + new Vertex(1.0, 1.0), // duplicate + new Vertex(0.0, 1.0), + new Vertex(0.5, 0.5) + }; + } + } +} diff --git a/src/Triangle.Tests/Meshing/Iterators/VertexCirculatorTest.cs b/src/Triangle.Tests/Meshing/Iterators/VertexCirculatorTest.cs new file mode 100644 index 0000000..84a40e1 --- /dev/null +++ b/src/Triangle.Tests/Meshing/Iterators/VertexCirculatorTest.cs @@ -0,0 +1,78 @@ +using NUnit.Framework; +using System.Linq; +using TriangleNet.Geometry; +using TriangleNet.IO; +using TriangleNet.Meshing; +using TriangleNet.Meshing.Iterators; + +namespace TriangleNet.Tests.Meshing.Iterators +{ + public class VertexCirculatorTest + { + [Test] + public void TestEnumerateVertices() + { + // 5 + // /\ + // / \ + // / \ + // 3/______\4 + // /\ /\ + // / \ / \ + // / \ / \ + // 0/______\/______\2 + // 1 + + var mesh = CreateMesh(out var vertices); + + var circulator = new VertexCirculator(mesh); + + var p = vertices[0]; + + var list = circulator.EnumerateVertices(p).ToList(); + + Assert.AreEqual(2, list.Count); + } + + [Test] + public void TestEnumerateTriangles() + { + var mesh = CreateMesh(out var vertices); + + var circulator = new VertexCirculator(mesh); + + var p = vertices[0]; + + var list = circulator.EnumerateTriangles(p).ToList(); + + Assert.AreEqual(1, list.Count); + } + + private Mesh CreateMesh(out Vertex[] vertices) + { + var poly = new Polygon(); + + vertices = new Vertex[] + { + new Vertex(-2.0, 0.0, 0), + new Vertex(0.0, 0.0, 1), + new Vertex(2.0, 0.0, 2), + new Vertex(-1.0, 1.0, 3), + new Vertex(1.0, 1.0, 4), + new Vertex(0.0, 2.0, 5) + }; + + poly.Points.AddRange(vertices); + + var triangles = new InputTriangle[] + { + new InputTriangle(3, 0, 1) { ID = 1 }, + new InputTriangle(3, 1, 4) { ID = 2 }, + new InputTriangle(4, 1, 2) { ID = 3 }, + new InputTriangle(5, 3, 4) { ID = 4 }, + }; + + return Converter.Instance.ToMesh(poly, triangles); + } + } +} diff --git a/src/Triangle.Tests/Tools/AdjacencyMatrixTest.cs b/src/Triangle.Tests/Tools/AdjacencyMatrixTest.cs new file mode 100644 index 0000000..6d0dc19 --- /dev/null +++ b/src/Triangle.Tests/Tools/AdjacencyMatrixTest.cs @@ -0,0 +1,79 @@ +using NUnit.Framework; +using System.Collections.Generic; +using System.Linq; +using TriangleNet.Geometry; +using TriangleNet.Meshing; +using TriangleNet.Tools; + +namespace TriangleNet.Tests.Tools +{ + public class AdjacencyMatrixTest + { + [Test] + public void TestAdjacencyMatrix() + { + var p = GetVertices(false); + var mesher = new GenericMesher(); + var mesh = (Mesh)mesher.Triangulate(p); + + Assert.AreEqual(5, mesh.Vertices.Max(v => v.ID)); + + mesh.Renumber(); + + var matrix = new AdjacencyMatrix(mesh); + + // Highest vertex id after renumbering is 4, since there + // is no duplicate vertex. + Assert.AreEqual(4, matrix.RowIndices.Max()); + } + + [Test] + public void TestAdjacencyMatrixDuplicate() + { + var p = GetVertices(true); + var mesher = new GenericMesher(); + var mesh = (Mesh)mesher.Triangulate(p); + + mesh.Renumber(); + + var matrix = new AdjacencyMatrix(mesh); + + var ai = matrix.RowIndices; + + // Highest vertex id after renumbering is 5, since the duplicate + // vertex is still present in the mesh vertices list. + Assert.AreEqual(5, ai.Max()); + + // Get the single, duplicate vertex. + var dup = mesh.Vertices + .Where(v => v.Type == VertexType.UndeadVertex) + .Single(); + + // The duplicate vertex is part of the matrix, since it is assumed + // to be adjacent to itself. + Assert.AreEqual(1, ai.Count(i => i == dup.id)); + + // TODO: fix AdjacencyMatrix!!! + } + + private List GetVertices(bool includeDuplicate) + { + var list = new List() + { + new Vertex(0.0, 0.0) { ID = 5 }, + new Vertex(1.0, 0.0) { ID = 4 }, + new Vertex(1.0, 1.0) { ID = 3 } + }; + + if (includeDuplicate) + { + list.Add(new Vertex(1.0, 1.0) { ID = 2 }); + } + + list.Add(new Vertex(0.0, 1.0) { ID = 1 }); + list.Add(new Vertex(0.5, 0.5) { ID = 0 }); + + return list; + } + } +} \ No newline at end of file diff --git a/src/Triangle.Tests/Tools/IntersectionHelperTest.cs b/src/Triangle.Tests/Tools/IntersectionHelperTest.cs index d8f2c69..158e405 100644 --- a/src/Triangle.Tests/Tools/IntersectionHelperTest.cs +++ b/src/Triangle.Tests/Tools/IntersectionHelperTest.cs @@ -1,4 +1,5 @@ using NUnit.Framework; +using System; using TriangleNet.Geometry; using TriangleNet.Tools; @@ -6,6 +7,139 @@ namespace TriangleNet.Tests.Tools { public class IntersectionHelperTest { + private const double EPS = 1e-8; + + Rectangle box; + Point p; + + [SetUp] + public void Initialize() + { + // Square centered at origin. + box = new Rectangle(-1.0, -1.0, 2.0, 2.0); + + // Starting point of ray for box-ray intersection. + p = new Point(0.0, 0.0); + } + + [Test] + public void TestBoxRayIntersectionCorners() + { + var c = new Point(0.0, 0.0); + + var check = (Point c, double x, double y) => Math.Abs(c.X - x) < EPS && Math.Abs(c.Y - y) < EPS; + + IntersectionHelper.BoxRayIntersection(box, p, -0.2, -0.2, ref c); + Assert.IsTrue(check(c, -1.0, -1.0)); + IntersectionHelper.BoxRayIntersection(box, p, 0.2, -0.2, ref c); + Assert.IsTrue(check(c, 1.0, -1.0)); + IntersectionHelper.BoxRayIntersection(box, p, 0.2, 0.2, ref c); + Assert.IsTrue(check(c, 1.0, 1.0)); + IntersectionHelper.BoxRayIntersection(box, p, -0.2, 0.2, ref c); + Assert.IsTrue(check(c, -1.0, 1.0)); + } + + [Test] + public void TestBoxRayIntersectionHorizontalVertical() + { + var a = new Point(0.0, 0.0); + + var check = (Point c, double x, double y) => Math.Abs(c.X - x) < EPS && Math.Abs(c.Y - y) < EPS; + + IntersectionHelper.BoxRayIntersection(box, p, -0.2, 0.0, ref a); + Assert.IsTrue(check(a, -1.0, 0.0)); + IntersectionHelper.BoxRayIntersection(box, p, 0.2, 0.0, ref a); + Assert.IsTrue(check(a, 1.0, 0.0)); + IntersectionHelper.BoxRayIntersection(box, p, 0.0, -0.2, ref a); + Assert.IsTrue(check(a, 0.0, -1.0)); + IntersectionHelper.BoxRayIntersection(box, p, 0.0, 0.2, ref a); + Assert.IsTrue(check(a, 0.0, 1.0)); + } + + [Test] + public void TestBoxRayIntersectionBottom() + { + var a = new Point(0.0, 0.0); + + var check = (Point c, Rectangle r) => Math.Abs(c.Y - r.Bottom) < EPS && c.X > r.Left - EPS && c.X < r.Right + EPS; + + IntersectionHelper.BoxRayIntersection(box, p, -0.4, -0.5, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, -0.2, -0.5, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, -0.1, -0.5, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, 0.1, -0.5, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, 0.2, -0.5, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, 0.4, -0.5, ref a); + Assert.IsTrue(check(a, box)); + } + + [Test] + public void TestBoxRayIntersectionTop() + { + var a = new Point(0.0, 0.0); + + var check = (Point c, Rectangle r) => Math.Abs(c.Y - r.Top) < EPS && c.X > r.Left - EPS && c.X < r.Right + EPS; + + IntersectionHelper.BoxRayIntersection(box, p, -0.4, 0.5, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, -0.2, 0.5, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, -0.1, 0.5, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, 0.1, 0.5, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, 0.2, 0.5, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, 0.4, 0.5, ref a); + Assert.IsTrue(check(a, box)); + } + + [Test] + public void TestBoxRayIntersectionLeft() + { + var a = new Point(0.0, 0.0); + + var check = (Point c, Rectangle r) => Math.Abs(c.X - r.Left) < EPS && c.Y > r.Bottom - EPS && c.Y < r.Top + EPS; + + IntersectionHelper.BoxRayIntersection(box, p, -0.5, -0.4, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, -0.5, -0.2, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, -0.5, -0.1, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, -0.5, 0.1, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, -0.5, 0.2, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, -0.5, 0.4, ref a); + Assert.IsTrue(check(a, box)); + } + + [Test] + public void TestBoxRayIntersectionRight() + { + var a = new Point(0.0, 0.0); + + var check = (Point c, Rectangle r) => Math.Abs(c.X - r.Right) < EPS && c.Y > r.Bottom - EPS && c.Y < r.Top + EPS; + + IntersectionHelper.BoxRayIntersection(box, p, 0.5, -0.4, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, 0.5, -0.2, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, 0.5, -0.1, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, 0.5, 0.1, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, 0.5, 0.2, ref a); + Assert.IsTrue(check(a, box)); + IntersectionHelper.BoxRayIntersection(box, p, 0.5, 0.4, ref a); + Assert.IsTrue(check(a, box)); + } + [Test] public void TestIsPointOnSegment() { diff --git a/src/Triangle.Tests/Tools/StatisticTest.cs b/src/Triangle.Tests/Tools/StatisticTest.cs new file mode 100644 index 0000000..d381e33 --- /dev/null +++ b/src/Triangle.Tests/Tools/StatisticTest.cs @@ -0,0 +1,61 @@ +using NUnit.Framework; +using System; +using TriangleNet.Geometry; +using TriangleNet.Tools; + +namespace TriangleNet.Tests.Tools +{ + public class StatisticTest + { + [Test, DefaultFloatingPointTolerance(1e-1)] + public void TestComputeAngles() + { + // Angles: 90, 45, 45 + var t = Helper.CreateTriangle(1 ,new Vertex(0.0, 0.0), new Vertex(1.0, 0.0), new Vertex(0.0, 1.0)); + var a = ComputeAngles(t); + + Assert.AreEqual(45.0, a.min); + Assert.AreEqual(90.0, a.max); + + // Angles: 135, 14, 31 + t = Helper.CreateTriangle(1 ,new Vertex(0.0, 0.0), new Vertex(3.0, 0.0), new Vertex(-1.0, 1.0)); + a = ComputeAngles(t); + + Assert.AreEqual(14.0, a.min); + Assert.AreEqual(135.0, a.max); + + // Angles: 60, 60, 60 + t = Helper.CreateTriangle(1 ,new Vertex(0.0, 0.0), new Vertex(2.0, 0.0), new Vertex(1.0, 1.73)); + a = ComputeAngles(t); + + Assert.AreEqual(60.0, a.min); + Assert.AreEqual(60.0, a.max); + + // Angles: 180 + t = Helper.CreateTriangle(1 ,new Vertex(0.0, 0.0), new Vertex(10000.0, 1.0), new Vertex(-10000.0, 1.0)); + a = ComputeAngles(t); + + Assert.AreEqual(0.0, a.min); + Assert.AreEqual(180.0, a.max); + } + + /// + /// Returns the minimum and maximum angle of given triangle (in degrees). + /// + private (double min, double max) ComputeAngles(ITriangle triangle) + { + var data = new double[6]; + + Statistic.ComputeAngles(triangle, data); + + bool acute = data[2] > 0; + + double min = Math.Acos(Math.Sqrt(data[0])); + double max = Math.Acos(Math.Sqrt(data[1])); + + const double deg = 180.0 / Math.PI; + + return (deg * min, acute ? deg * max : deg * (Math.PI - max)); + } + } +} diff --git a/src/Triangle.Tests/TrianglePoolTest.cs b/src/Triangle.Tests/TrianglePoolTest.cs new file mode 100644 index 0000000..d2cf6aa --- /dev/null +++ b/src/Triangle.Tests/TrianglePoolTest.cs @@ -0,0 +1,130 @@ +using NUnit.Framework; +using System.Linq; + +namespace TriangleNet.Tests +{ + class TrianglePoolTest + { + [Test] + public void TestGetRelease() + { + var pool = new TrianglePool(); + + var t0 = pool.Get(); + var t1 = pool.Get(); + var t2 = pool.Get(); + + Assert.AreEqual(0, t0.ID); + Assert.AreEqual(1, t1.ID); + Assert.AreEqual(2, t2.ID); + + Assert.AreEqual(3, pool.Count); + + pool.Release(t0); + + Assert.AreEqual(2, pool.Count); + Assert.Less(t0.GetHashCode(), 0); + + pool.Release(t1); + + Assert.AreEqual(1, pool.Count); + Assert.Less(t1.GetHashCode(), 0); + + var t4 = pool.Get(); + + Assert.AreEqual(2, pool.Count); + Assert.AreEqual(t1.ID, t4.ID); + + var t5 = pool.Get(); + + Assert.AreEqual(3, pool.Count); + Assert.AreEqual(t0.ID, t5.ID); + + var t6 = pool.Get(); + + Assert.AreEqual(4, pool.Count); + Assert.AreEqual(3, t6.ID); + } + + [Test] + public void TestToArray() + { + var pool = new TrianglePool(); + + // Create 4 triangles. + pool.Get(); + pool.Get(); + pool.Get(); + pool.Get(); + + var a = pool.ToArray(); + + Assert.AreEqual(4, a.Length); + Assert.AreEqual(0, a[0].ID); + Assert.AreEqual(1, a[1].ID); + Assert.AreEqual(2, a[2].ID); + Assert.AreEqual(3, a[3].ID); + + pool.Release(a[1]); + + a = pool.ToArray(); + + Assert.AreEqual(3, a.Length); + Assert.AreEqual(0, a[0].ID); + Assert.AreEqual(2, a[1].ID); + Assert.AreEqual(3, a[2].ID); + + pool.Release(a[1]); + + a = pool.ToArray(); + + Assert.AreEqual(2, a.Length); + Assert.AreEqual(0, a[0].ID); + Assert.AreEqual(3, a[1].ID); + + var t2 = pool.Get(); + + a = pool.ToArray(); + + Assert.AreEqual(3, a.Length); + Assert.AreEqual(0, a[0].ID); + Assert.AreEqual(2, a[1].ID); + Assert.AreEqual(2, t2.ID); + Assert.AreEqual(3, a[2].ID); + + var t1 = pool.Get(); + + a = pool.ToArray(); + + Assert.AreEqual(4, a.Length); + Assert.AreEqual(0, a[0].ID); + Assert.AreEqual(1, a[1].ID); + Assert.AreEqual(1, t1.ID); + Assert.AreEqual(2, a[2].ID); + Assert.AreEqual(3, a[3].ID); + } + + [Test] + public void TestRestart() + { + var pool = new TrianglePool(); + + Assert.AreEqual(0, pool.Count); + Assert.AreEqual(0, pool.Capacity); + + int n = 10; + + for (int i = 0; i < n; i++) + { + Assert.AreEqual(i, pool.Get().ID); + } + + Assert.AreEqual(n, pool.Count); + + pool.Restart(); + + Assert.AreEqual(0, pool.Count); + Assert.AreEqual(10, pool.Capacity); + } + } +}