From a854e34a3d8299b2fb3675a46b1d8b0084e6b1ef Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Wed, 30 Sep 2026 22:02:46 -0400 Subject: [PATCH] test(geometry): pin near-zero-sweep arc bounds without a local DXF DxfImport_ArcBoundingBoxes_Diagnostic read a drawing from one user's desktop, returned early elsewhere and asserted nothing, so the near-zero sweep bounding-box fix (4053f1f) had no regression test that could fail. Replace it with ArcBoundingBoxTests: a forward and a reversed arc with a sweep below Tolerance.Epsilon must be bounded by its endpoints, and an ordinary arc crossing 90 degrees must still reach the top of its circle. With the 4053f1f guard reverted, both near-zero cases fail (the box grows to the full circle); with it in place all three pass. --- .../Geometry/ArcBoundingBoxTests.cs | 54 +++++++++++++++++++ .../Geometry/EllipseConverterTests.cs | 29 ---------- 2 files changed, 54 insertions(+), 29 deletions(-) create mode 100644 OpenNest.Tests/Geometry/ArcBoundingBoxTests.cs diff --git a/OpenNest.Tests/Geometry/ArcBoundingBoxTests.cs b/OpenNest.Tests/Geometry/ArcBoundingBoxTests.cs new file mode 100644 index 0000000..ef363fe --- /dev/null +++ b/OpenNest.Tests/Geometry/ArcBoundingBoxTests.cs @@ -0,0 +1,54 @@ +using OpenNest.Geometry; + +namespace OpenNest.Tests.Geometry; + +/// +/// An arc whose sweep is below Tolerance.Epsilon must not be bounded as a full +/// circle: its box covers only the endpoints. Ordinary arcs still reach the cardinal +/// extents they cross. +/// +public class ArcBoundingBoxTests +{ + private const double Tol = 1e-9; + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void NearZeroSweep_BoundsCoverOnlyTheEndpoints(bool reversed) + { + var center = new Vector(10, 20); + const double radius = 50; + const double a = 0.3; + const double b = 0.3 + 1e-6; // sweep well below Tolerance.Epsilon (1e-5) + + var arc = reversed + ? new Arc(center, radius, b, a, reversed: true) + : new Arc(center, radius, a, b); + + var x1 = center.X + radius * System.Math.Cos(a); + var y1 = center.Y + radius * System.Math.Sin(a); + var x2 = center.X + radius * System.Math.Cos(b); + var y2 = center.Y + radius * System.Math.Sin(b); + var box = arc.BoundingBox; + + Assert.Equal(System.Math.Min(x1, x2), box.X, Tol); + Assert.Equal(System.Math.Min(y1, y2), box.Y, Tol); + Assert.Equal(System.Math.Max(x1, x2), box.X + box.Length, Tol); + Assert.Equal(System.Math.Max(y1, y2), box.Y + box.Width, Tol); + } + + [Fact] + public void ArcCrossingQuarterTurn_StillReachesTopOfCircle() + { + const double radius = 10; + const double a = 0.1; + var arc = new Arc(new Vector(0, 0), radius, a, System.Math.PI - a); + + var box = arc.BoundingBox; + + Assert.Equal(-radius * System.Math.Cos(a), box.X, Tol); + Assert.Equal(radius * System.Math.Sin(a), box.Y, Tol); + Assert.Equal(radius * System.Math.Cos(a), box.X + box.Length, Tol); + Assert.Equal(radius, box.Y + box.Width, Tol); + } +} diff --git a/OpenNest.Tests/Geometry/EllipseConverterTests.cs b/OpenNest.Tests/Geometry/EllipseConverterTests.cs index 92a4bd8..f0f4913 100644 --- a/OpenNest.Tests/Geometry/EllipseConverterTests.cs +++ b/OpenNest.Tests/Geometry/EllipseConverterTests.cs @@ -3,17 +3,13 @@ using OpenNest.Geometry; using OpenNest.IO; using OpenNest.Math; using Xunit; -using Xunit.Abstractions; namespace OpenNest.Tests.Geometry; public class EllipseConverterTests { - private readonly ITestOutputHelper _output; private const double Tol = 1e-10; - public EllipseConverterTests(ITestOutputHelper output) => _output = output; - [Fact] public void EvaluatePoint_AtZero_ReturnsMajorAxisEnd() { @@ -293,31 +289,6 @@ public class EllipseConverterTests } } - [Fact] - public void DxfImport_ArcBoundingBoxes_Diagnostic() - { - var path = @"C:\Users\aisaacs\Desktop\11ga tab.dxf"; - if (!System.IO.File.Exists(path)) - return; - - var result = Dxf.Import(path); - var all = (System.Collections.Generic.IEnumerable)result.Entities; - var bbox = all.GetBoundingBox(); - _output.WriteLine( - $"Overall: X={bbox.X:F4} Y={bbox.Y:F4} W={bbox.Length:F4} H={bbox.Width:F4}" - ); - - for (var i = 0; i < result.Entities.Count; i++) - { - var e = result.Entities[i]; - var b = e.BoundingBox; - var flag = (b.Length > 1 || b.Width > 1) ? " ***" : ""; - _output.WriteLine( - $"{i + 1,3}. {e.GetType().Name,-8} X={b.X:F4} Y={b.Y:F4} W={b.Length:F4} H={b.Width:F4}{flag}" - ); - } - } - [Fact] public void ToOpenNest_FlippedNormalZ_ProducesCorrectArcs() {