Merge branch 'chore/csharpier-sweep'
# Conflicts: # OpenNest.Core/Geometry/ArcFit.cs # OpenNest.Core/Geometry/GeometrySimplifier.cs # OpenNest.Posts.GravographIS/GravographISWriter.cs # OpenNest.Posts.GravographIS/NestPolylineExtractor.cs
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using OpenNest.Geometry;
|
||||
using OpenNest.Math;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenNest.Tests.Geometry;
|
||||
|
||||
@@ -141,8 +141,8 @@ public class CollisionTests
|
||||
public void CheckAll_MultiplePolygons_FindsAllOverlaps()
|
||||
{
|
||||
var a = MakeSquare(0, 0, 1, 1);
|
||||
var b = MakeSquare(0.5, 0, 1.5, 1); // overlaps A
|
||||
var c = MakeSquare(5, 5, 6, 6); // overlaps nobody
|
||||
var b = MakeSquare(0.5, 0, 1.5, 1); // overlaps A
|
||||
var c = MakeSquare(5, 5, 6, 6); // overlaps nobody
|
||||
|
||||
var results = Collision.CheckAll(new List<Polygon> { a, b, c });
|
||||
|
||||
|
||||
@@ -67,11 +67,7 @@ public class ContourClassificationTests
|
||||
[Fact]
|
||||
public void Classify_identifies_etch_layer_shapes()
|
||||
{
|
||||
var shapes = new List<Shape>
|
||||
{
|
||||
MakeRectShape(0, 0, 100, 50),
|
||||
MakeEtchShape(),
|
||||
};
|
||||
var shapes = new List<Shape> { MakeRectShape(0, 0, 100, 50), MakeEtchShape() };
|
||||
|
||||
var contours = ContourInfo.Classify(shapes);
|
||||
|
||||
@@ -86,11 +82,7 @@ public class ContourClassificationTests
|
||||
openShape.Entities.Add(new Line(new Vector(10, 0), new Vector(10, 5)));
|
||||
// Not closed — doesn't return to (0,0)
|
||||
|
||||
var shapes = new List<Shape>
|
||||
{
|
||||
MakeRectShape(0, 0, 100, 50),
|
||||
openShape,
|
||||
};
|
||||
var shapes = new List<Shape> { MakeRectShape(0, 0, 100, 50), openShape };
|
||||
|
||||
var contours = ContourInfo.Classify(shapes);
|
||||
|
||||
@@ -100,11 +92,7 @@ public class ContourClassificationTests
|
||||
[Fact]
|
||||
public void Classify_orders_holes_first_perimeter_last()
|
||||
{
|
||||
var shapes = new List<Shape>
|
||||
{
|
||||
MakeRectShape(0, 0, 100, 50),
|
||||
MakeCircleShape(25, 25, 5),
|
||||
};
|
||||
var shapes = new List<Shape> { MakeRectShape(0, 0, 100, 50), MakeCircleShape(25, 25, 5) };
|
||||
|
||||
var contours = ContourInfo.Classify(shapes);
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System.Linq;
|
||||
using OpenNest.Geometry;
|
||||
using OpenNest.IO;
|
||||
using OpenNest.Math;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenNest.Tests.Geometry;
|
||||
|
||||
@@ -89,8 +89,14 @@ public class EllipseConverterTests
|
||||
public void Convert_Circle_ProducesOneOrTwoArcs()
|
||||
{
|
||||
var result = EllipseConverter.Convert(
|
||||
new Vector(0, 0), semiMajor: 10, semiMinor: 10, rotation: 0,
|
||||
startParam: 0, endParam: Angle.TwoPI, tolerance: 0.001);
|
||||
new Vector(0, 0),
|
||||
semiMajor: 10,
|
||||
semiMinor: 10,
|
||||
rotation: 0,
|
||||
startParam: 0,
|
||||
endParam: Angle.TwoPI,
|
||||
tolerance: 0.001
|
||||
);
|
||||
|
||||
Assert.All(result, e => Assert.IsType<Arc>(e));
|
||||
Assert.InRange(result.Count, 1, 4);
|
||||
@@ -103,8 +109,14 @@ public class EllipseConverterTests
|
||||
var b = 7.0;
|
||||
var tolerance = 0.001;
|
||||
var result = EllipseConverter.Convert(
|
||||
new Vector(0, 0), a, b, rotation: 0,
|
||||
startParam: 0, endParam: Angle.TwoPI, tolerance: tolerance);
|
||||
new Vector(0, 0),
|
||||
a,
|
||||
b,
|
||||
rotation: 0,
|
||||
startParam: 0,
|
||||
endParam: Angle.TwoPI,
|
||||
tolerance: tolerance
|
||||
);
|
||||
|
||||
Assert.True(result.Count >= 4, $"Expected at least 4 arcs, got {result.Count}");
|
||||
Assert.All(result, e => Assert.IsType<Arc>(e));
|
||||
@@ -113,9 +125,11 @@ public class EllipseConverterTests
|
||||
{
|
||||
var arc = (Arc)entity;
|
||||
var maxDev = MaxDeviationFromEllipse(arc, new Vector(0, 0), a, b, 0, 50);
|
||||
Assert.True(maxDev <= tolerance,
|
||||
$"Arc at center ({arc.Center.X:F4},{arc.Center.Y:F4}) r={arc.Radius:F4} " +
|
||||
$"deviates {maxDev:F6} from ellipse (tolerance={tolerance})");
|
||||
Assert.True(
|
||||
maxDev <= tolerance,
|
||||
$"Arc at center ({arc.Center.X:F4},{arc.Center.Y:F4}) r={arc.Radius:F4} "
|
||||
+ $"deviates {maxDev:F6} from ellipse (tolerance={tolerance})"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,18 +140,29 @@ public class EllipseConverterTests
|
||||
var b = 3.0;
|
||||
var tolerance = 0.001;
|
||||
var result = EllipseConverter.Convert(
|
||||
new Vector(0, 0), a, b, rotation: 0,
|
||||
startParam: 0, endParam: Angle.TwoPI, tolerance: tolerance);
|
||||
new Vector(0, 0),
|
||||
a,
|
||||
b,
|
||||
rotation: 0,
|
||||
startParam: 0,
|
||||
endParam: Angle.TwoPI,
|
||||
tolerance: tolerance
|
||||
);
|
||||
|
||||
Assert.True(result.Count >= 8, $"Expected at least 8 arcs for eccentric ellipse, got {result.Count}");
|
||||
Assert.True(
|
||||
result.Count >= 8,
|
||||
$"Expected at least 8 arcs for eccentric ellipse, got {result.Count}"
|
||||
);
|
||||
Assert.All(result, e => Assert.IsType<Arc>(e));
|
||||
|
||||
foreach (var entity in result)
|
||||
{
|
||||
var arc = (Arc)entity;
|
||||
var maxDev = MaxDeviationFromEllipse(arc, new Vector(0, 0), a, b, 0, 50);
|
||||
Assert.True(maxDev <= tolerance,
|
||||
$"Deviation {maxDev:F6} exceeds tolerance {tolerance}");
|
||||
Assert.True(
|
||||
maxDev <= tolerance,
|
||||
$"Deviation {maxDev:F6} exceeds tolerance {tolerance}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,8 +173,14 @@ public class EllipseConverterTests
|
||||
var b = 5.0;
|
||||
var tolerance = 0.001;
|
||||
var result = EllipseConverter.Convert(
|
||||
new Vector(0, 0), a, b, rotation: 0,
|
||||
startParam: 0, endParam: System.Math.PI / 2, tolerance: tolerance);
|
||||
new Vector(0, 0),
|
||||
a,
|
||||
b,
|
||||
rotation: 0,
|
||||
startParam: 0,
|
||||
endParam: System.Math.PI / 2,
|
||||
tolerance: tolerance
|
||||
);
|
||||
|
||||
Assert.NotEmpty(result);
|
||||
Assert.All(result, e => Assert.IsType<Arc>(e));
|
||||
@@ -169,23 +200,27 @@ public class EllipseConverterTests
|
||||
public void Convert_EndpointContinuity_ArcsConnect()
|
||||
{
|
||||
var result = EllipseConverter.Convert(
|
||||
new Vector(5, 10), semiMajor: 15, semiMinor: 8, rotation: 0.5,
|
||||
startParam: 0, endParam: Angle.TwoPI, tolerance: 0.001);
|
||||
new Vector(5, 10),
|
||||
semiMajor: 15,
|
||||
semiMinor: 8,
|
||||
rotation: 0.5,
|
||||
startParam: 0,
|
||||
endParam: Angle.TwoPI,
|
||||
tolerance: 0.001
|
||||
);
|
||||
|
||||
for (var i = 0; i < result.Count - 1; i++)
|
||||
{
|
||||
var current = (Arc)result[i];
|
||||
var next = (Arc)result[i + 1];
|
||||
var gap = current.EndPoint().DistanceTo(next.StartPoint());
|
||||
Assert.True(gap < 1e-6,
|
||||
$"Gap of {gap:E4} between arc {i} and arc {i + 1}");
|
||||
Assert.True(gap < 1e-6, $"Gap of {gap:E4} between arc {i} and arc {i + 1}");
|
||||
}
|
||||
|
||||
var lastArc = (Arc)result[^1];
|
||||
var firstArc = (Arc)result[0];
|
||||
var closingGap = lastArc.EndPoint().DistanceTo(firstArc.StartPoint());
|
||||
Assert.True(closingGap < 1e-6,
|
||||
$"Closing gap of {closingGap:E4}");
|
||||
Assert.True(closingGap < 1e-6, $"Closing gap of {closingGap:E4}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -197,16 +232,25 @@ public class EllipseConverterTests
|
||||
var b = 6.0;
|
||||
var tolerance = 0.001;
|
||||
|
||||
var result = EllipseConverter.Convert(center, a, b, rotation,
|
||||
startParam: 0, endParam: Angle.TwoPI, tolerance: tolerance);
|
||||
var result = EllipseConverter.Convert(
|
||||
center,
|
||||
a,
|
||||
b,
|
||||
rotation,
|
||||
startParam: 0,
|
||||
endParam: Angle.TwoPI,
|
||||
tolerance: tolerance
|
||||
);
|
||||
|
||||
Assert.NotEmpty(result);
|
||||
foreach (var entity in result)
|
||||
{
|
||||
var arc = (Arc)entity;
|
||||
var maxDev = MaxDeviationFromEllipse(arc, center, a, b, rotation, 50);
|
||||
Assert.True(maxDev <= tolerance,
|
||||
$"Deviation {maxDev:F6} exceeds tolerance {tolerance}");
|
||||
Assert.True(
|
||||
maxDev <= tolerance,
|
||||
$"Deviation {maxDev:F6} exceeds tolerance {tolerance}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +265,7 @@ public class EllipseConverterTests
|
||||
MajorAxisEndPoint = new CSMath.XYZ(10, 0, 0),
|
||||
RadiusRatio = 0.6,
|
||||
StartParameter = 0,
|
||||
EndParameter = System.Math.PI * 2
|
||||
EndParameter = System.Math.PI * 2,
|
||||
};
|
||||
doc.Entities.Add(ellipse);
|
||||
|
||||
@@ -253,19 +297,24 @@ public class EllipseConverterTests
|
||||
public void DxfImport_ArcBoundingBoxes_Diagnostic()
|
||||
{
|
||||
var path = @"C:\Users\aisaacs\Desktop\11ga tab.dxf";
|
||||
if (!System.IO.File.Exists(path)) return;
|
||||
if (!System.IO.File.Exists(path))
|
||||
return;
|
||||
|
||||
var result = Dxf.Import(path);
|
||||
var all = (System.Collections.Generic.IEnumerable<IBoundable>)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}");
|
||||
_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}");
|
||||
_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}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +328,7 @@ public class EllipseConverterTests
|
||||
RadiusRatio = 0.28,
|
||||
StartParameter = 0.017,
|
||||
EndParameter = 1.571,
|
||||
Normal = new CSMath.XYZ(0, 0, 1)
|
||||
Normal = new CSMath.XYZ(0, 0, 1),
|
||||
};
|
||||
|
||||
var flipped = new ACadSharp.Entities.Ellipse
|
||||
@@ -289,7 +338,7 @@ public class EllipseConverterTests
|
||||
RadiusRatio = 0.28,
|
||||
StartParameter = 0.017,
|
||||
EndParameter = 1.571,
|
||||
Normal = new CSMath.XYZ(0, 0, -1)
|
||||
Normal = new CSMath.XYZ(0, 0, -1),
|
||||
};
|
||||
|
||||
var normalArcs = normal.ToOpenNest();
|
||||
@@ -305,13 +354,25 @@ public class EllipseConverterTests
|
||||
var normalStart = GetArcStart(normalFirst);
|
||||
var flippedStart = GetArcStart(flippedFirst);
|
||||
|
||||
Assert.True(normalStart.X < 0, $"Normal ellipse start X should be negative, got {normalStart.X}");
|
||||
Assert.True(flippedStart.X > 0, $"Flipped ellipse should bulge right, got {flippedStart.X}");
|
||||
Assert.True(
|
||||
normalStart.X < 0,
|
||||
$"Normal ellipse start X should be negative, got {normalStart.X}"
|
||||
);
|
||||
Assert.True(
|
||||
flippedStart.X > 0,
|
||||
$"Flipped ellipse should bulge right, got {flippedStart.X}"
|
||||
);
|
||||
|
||||
var normalBbox = GetBoundingBox(normalArcs.Cast<Arc>());
|
||||
var flippedBbox = GetBoundingBox(flippedArcs.Cast<Arc>());
|
||||
Assert.True(flippedBbox.minX > 0, $"Flipped ellipse should stay on positive X side, minX={flippedBbox.minX}");
|
||||
Assert.True(normalBbox.maxX < 0, $"Normal ellipse should stay on negative X side, maxX={normalBbox.maxX}");
|
||||
Assert.True(
|
||||
flippedBbox.minX > 0,
|
||||
$"Flipped ellipse should stay on positive X side, minX={flippedBbox.minX}"
|
||||
);
|
||||
Assert.True(
|
||||
normalBbox.maxX < 0,
|
||||
$"Normal ellipse should stay on negative X side, maxX={normalBbox.maxX}"
|
||||
);
|
||||
}
|
||||
|
||||
private static (double minX, double maxX) GetBoundingBox(IEnumerable<Arc> arcs)
|
||||
@@ -333,7 +394,8 @@ public class EllipseConverterTests
|
||||
var angle = arc.IsReversed ? arc.EndAngle : arc.StartAngle;
|
||||
return new Vector(
|
||||
arc.Center.X + arc.Radius * System.Math.Cos(angle),
|
||||
arc.Center.Y + arc.Radius * System.Math.Sin(angle));
|
||||
arc.Center.Y + arc.Radius * System.Math.Sin(angle)
|
||||
);
|
||||
}
|
||||
|
||||
private static Vector GetArcEnd(Arc arc)
|
||||
@@ -341,11 +403,18 @@ public class EllipseConverterTests
|
||||
var angle = arc.IsReversed ? arc.StartAngle : arc.EndAngle;
|
||||
return new Vector(
|
||||
arc.Center.X + arc.Radius * System.Math.Cos(angle),
|
||||
arc.Center.Y + arc.Radius * System.Math.Sin(angle));
|
||||
arc.Center.Y + arc.Radius * System.Math.Sin(angle)
|
||||
);
|
||||
}
|
||||
|
||||
private static double MaxDeviationFromEllipse(Arc arc, Vector ellipseCenter,
|
||||
double semiMajor, double semiMinor, double rotation, int samples)
|
||||
private static double MaxDeviationFromEllipse(
|
||||
Arc arc,
|
||||
Vector ellipseCenter,
|
||||
double semiMajor,
|
||||
double semiMinor,
|
||||
double rotation,
|
||||
int samples
|
||||
)
|
||||
{
|
||||
var maxDev = 0.0;
|
||||
var sweep = arc.SweepAngle();
|
||||
@@ -367,9 +436,19 @@ public class EllipseConverterTests
|
||||
for (var j = 0; j <= 1000; j++)
|
||||
{
|
||||
var t = (double)j / 1000 * Angle.TwoPI;
|
||||
var ep2 = EllipseConverter.EvaluatePoint(semiMajor, semiMinor, rotation, ellipseCenter, t);
|
||||
var ep2 = EllipseConverter.EvaluatePoint(
|
||||
semiMajor,
|
||||
semiMinor,
|
||||
rotation,
|
||||
ellipseCenter,
|
||||
t
|
||||
);
|
||||
var dist = arcPoint.DistanceTo(ep2);
|
||||
if (dist < minDist) { minDist = dist; bestT = t; }
|
||||
if (dist < minDist)
|
||||
{
|
||||
minDist = dist;
|
||||
bestT = t;
|
||||
}
|
||||
}
|
||||
|
||||
// Refine with local bisection around bestT
|
||||
@@ -379,12 +458,40 @@ public class EllipseConverterTests
|
||||
{
|
||||
var t1 = lo + (hi - lo) / 3;
|
||||
var t2 = lo + 2 * (hi - lo) / 3;
|
||||
var d1 = arcPoint.DistanceTo(EllipseConverter.EvaluatePoint(semiMajor, semiMinor, rotation, ellipseCenter, t1));
|
||||
var d2 = arcPoint.DistanceTo(EllipseConverter.EvaluatePoint(semiMajor, semiMinor, rotation, ellipseCenter, t2));
|
||||
if (d1 < d2) hi = t2; else lo = t1;
|
||||
var d1 = arcPoint.DistanceTo(
|
||||
EllipseConverter.EvaluatePoint(
|
||||
semiMajor,
|
||||
semiMinor,
|
||||
rotation,
|
||||
ellipseCenter,
|
||||
t1
|
||||
)
|
||||
);
|
||||
var d2 = arcPoint.DistanceTo(
|
||||
EllipseConverter.EvaluatePoint(
|
||||
semiMajor,
|
||||
semiMinor,
|
||||
rotation,
|
||||
ellipseCenter,
|
||||
t2
|
||||
)
|
||||
);
|
||||
if (d1 < d2)
|
||||
hi = t2;
|
||||
else
|
||||
lo = t1;
|
||||
}
|
||||
var bestDist = arcPoint.DistanceTo(EllipseConverter.EvaluatePoint(semiMajor, semiMinor, rotation, ellipseCenter, (lo + hi) / 2));
|
||||
if (bestDist > maxDev) maxDev = bestDist;
|
||||
var bestDist = arcPoint.DistanceTo(
|
||||
EllipseConverter.EvaluatePoint(
|
||||
semiMajor,
|
||||
semiMinor,
|
||||
rotation,
|
||||
ellipseCenter,
|
||||
(lo + hi) / 2
|
||||
)
|
||||
);
|
||||
if (bestDist > maxDev)
|
||||
maxDev = bestDist;
|
||||
}
|
||||
|
||||
return maxDev;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using OpenNest.Geometry;
|
||||
using OpenNest.IO;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenNest.Geometry;
|
||||
using OpenNest.IO;
|
||||
using Xunit;
|
||||
|
||||
namespace OpenNest.Tests.Geometry;
|
||||
@@ -251,7 +251,8 @@ public class GeometrySimplifierTests
|
||||
foreach (var shape in shapes)
|
||||
{
|
||||
var candidates = simplifier.Analyze(shape);
|
||||
if (candidates.Count == 0) continue;
|
||||
if (candidates.Count == 0)
|
||||
continue;
|
||||
|
||||
var simplified = simplifier.Apply(shape, candidates);
|
||||
|
||||
@@ -265,20 +266,23 @@ public class GeometrySimplifierTests
|
||||
{
|
||||
Line l => l.EndPoint,
|
||||
Arc a => a.EndPoint(),
|
||||
_ => Vector.Invalid
|
||||
_ => Vector.Invalid,
|
||||
};
|
||||
var nextStart = next switch
|
||||
{
|
||||
Line l => l.StartPoint,
|
||||
Arc a => a.StartPoint(),
|
||||
_ => Vector.Invalid
|
||||
_ => Vector.Invalid,
|
||||
};
|
||||
|
||||
if (!currentEnd.IsValid() || !nextStart.IsValid()) continue;
|
||||
if (!currentEnd.IsValid() || !nextStart.IsValid())
|
||||
continue;
|
||||
|
||||
var gap = currentEnd.DistanceTo(nextStart);
|
||||
Assert.True(gap < 0.005,
|
||||
$"Gap of {gap:F4} between entities {i} ({current.GetType().Name}) and {i + 1} ({next.GetType().Name})");
|
||||
Assert.True(
|
||||
gap < 0.005,
|
||||
$"Gap of {gap:F4} between entities {i} ({current.GetType().Name}) and {i + 1} ({next.GetType().Name})"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,10 +30,13 @@ public class PolygonHelperTests
|
||||
// OffsetSide.Left offsets outward or inward depending on winding,
|
||||
// but either way the result must be a different size.
|
||||
Assert.True(
|
||||
System.Math.Abs(withSpacing.Polygon.BoundingBox.Width - noSpacing.Polygon.BoundingBox.Width) > 0.5,
|
||||
$"Expected polygon width to differ by >0.5 with 1mm spacing. " +
|
||||
$"No-spacing width: {noSpacing.Polygon.BoundingBox.Width:F3}, " +
|
||||
$"With-spacing width: {withSpacing.Polygon.BoundingBox.Width:F3}");
|
||||
System.Math.Abs(
|
||||
withSpacing.Polygon.BoundingBox.Width - noSpacing.Polygon.BoundingBox.Width
|
||||
) > 0.5,
|
||||
$"Expected polygon width to differ by >0.5 with 1mm spacing. "
|
||||
+ $"No-spacing width: {noSpacing.Polygon.BoundingBox.Width:F3}, "
|
||||
+ $"With-spacing width: {withSpacing.Polygon.BoundingBox.Width:F3}"
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -47,10 +50,14 @@ public class PolygonHelperTests
|
||||
noSpacing.Polygon.UpdateBounds();
|
||||
withSpacing.Polygon.UpdateBounds();
|
||||
|
||||
Assert.True(withSpacing.Polygon.BoundingBox.Width > noSpacing.Polygon.BoundingBox.Width,
|
||||
$"Inflated width {withSpacing.Polygon.BoundingBox.Width:F3} should be > original {noSpacing.Polygon.BoundingBox.Width:F3}");
|
||||
Assert.True(withSpacing.Polygon.BoundingBox.Length > noSpacing.Polygon.BoundingBox.Length,
|
||||
$"Inflated length {withSpacing.Polygon.BoundingBox.Length:F3} should be > original {noSpacing.Polygon.BoundingBox.Length:F3}");
|
||||
Assert.True(
|
||||
withSpacing.Polygon.BoundingBox.Width > noSpacing.Polygon.BoundingBox.Width,
|
||||
$"Inflated width {withSpacing.Polygon.BoundingBox.Width:F3} should be > original {noSpacing.Polygon.BoundingBox.Width:F3}"
|
||||
);
|
||||
Assert.True(
|
||||
withSpacing.Polygon.BoundingBox.Length > noSpacing.Polygon.BoundingBox.Length,
|
||||
$"Inflated length {withSpacing.Polygon.BoundingBox.Length:F3} should be > original {noSpacing.Polygon.BoundingBox.Length:F3}"
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -71,10 +78,14 @@ public class PolygonHelperTests
|
||||
noSpacing.Polygon.UpdateBounds();
|
||||
withSpacing.Polygon.UpdateBounds();
|
||||
|
||||
Assert.True(withSpacing.Polygon.BoundingBox.Width > noSpacing.Polygon.BoundingBox.Width,
|
||||
$"Inflated width {withSpacing.Polygon.BoundingBox.Width:F3} should be > original {noSpacing.Polygon.BoundingBox.Width:F3}");
|
||||
Assert.True(withSpacing.Polygon.BoundingBox.Length > noSpacing.Polygon.BoundingBox.Length,
|
||||
$"Inflated length {withSpacing.Polygon.BoundingBox.Length:F3} should be > original {noSpacing.Polygon.BoundingBox.Length:F3}");
|
||||
Assert.True(
|
||||
withSpacing.Polygon.BoundingBox.Width > noSpacing.Polygon.BoundingBox.Width,
|
||||
$"Inflated width {withSpacing.Polygon.BoundingBox.Width:F3} should be > original {noSpacing.Polygon.BoundingBox.Width:F3}"
|
||||
);
|
||||
Assert.True(
|
||||
withSpacing.Polygon.BoundingBox.Length > noSpacing.Polygon.BoundingBox.Length,
|
||||
$"Inflated length {withSpacing.Polygon.BoundingBox.Length:F3} should be > original {noSpacing.Polygon.BoundingBox.Length:F3}"
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using OpenNest.Geometry;
|
||||
using OpenNest.Math;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenNest.Tests.Geometry;
|
||||
|
||||
@@ -45,9 +45,19 @@ public class SpatialQueryTests
|
||||
foreach (var e in entities)
|
||||
{
|
||||
if (e is Line line)
|
||||
result.Add(new Line(line.pt1.X + dx, line.pt1.Y + dy, line.pt2.X + dx, line.pt2.Y + dy));
|
||||
result.Add(
|
||||
new Line(line.pt1.X + dx, line.pt1.Y + dy, line.pt2.X + dx, line.pt2.Y + dy)
|
||||
);
|
||||
else if (e is Arc arc)
|
||||
result.Add(new Arc(arc.Center.X + dx, arc.Center.Y + dy, arc.Radius, arc.StartAngle, arc.EndAngle));
|
||||
result.Add(
|
||||
new Arc(
|
||||
arc.Center.X + dx,
|
||||
arc.Center.Y + dy,
|
||||
arc.Radius,
|
||||
arc.StartAngle,
|
||||
arc.EndAngle
|
||||
)
|
||||
);
|
||||
else if (e is Circle circle)
|
||||
result.Add(new Circle(circle.Center.X + dx, circle.Center.Y + dy, circle.Radius));
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class SplineConverterTests
|
||||
var points = new System.Collections.Generic.List<Vector>
|
||||
{
|
||||
new Vector(0, 0),
|
||||
new Vector(10, 5)
|
||||
new Vector(10, 5),
|
||||
};
|
||||
|
||||
var result = SplineConverter.Convert(points, isClosed: false, tolerance: 0.001);
|
||||
@@ -89,16 +89,18 @@ public class SplineConverterTests
|
||||
var endPt = GetEndPoint(result[i]);
|
||||
var startPt = GetStartPoint(result[i + 1]);
|
||||
var gap = endPt.DistanceTo(startPt);
|
||||
Assert.True(gap < 0.001,
|
||||
$"Gap of {gap:F6} between entity {i} and {i + 1}");
|
||||
Assert.True(gap < 0.001, $"Gap of {gap:F6} between entity {i} and {i + 1}");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Convert_EmptyPoints_ReturnsEmpty()
|
||||
{
|
||||
var result = SplineConverter.Convert(new System.Collections.Generic.List<Vector>(),
|
||||
isClosed: false, tolerance: 0.001);
|
||||
var result = SplineConverter.Convert(
|
||||
new System.Collections.Generic.List<Vector>(),
|
||||
isClosed: false,
|
||||
tolerance: 0.001
|
||||
);
|
||||
Assert.Empty(result);
|
||||
}
|
||||
|
||||
@@ -116,7 +118,7 @@ public class SplineConverterTests
|
||||
{
|
||||
Arc a => a.StartPoint(),
|
||||
Line l => l.StartPoint,
|
||||
_ => throw new System.Exception("Unexpected entity type")
|
||||
_ => throw new System.Exception("Unexpected entity type"),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -126,7 +128,7 @@ public class SplineConverterTests
|
||||
{
|
||||
Arc a => a.EndPoint(),
|
||||
Line l => l.EndPoint,
|
||||
_ => throw new System.Exception("Unexpected entity type")
|
||||
_ => throw new System.Exception("Unexpected entity type"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user