feat(engine): add CanonicalFrame helper for drawing-to-canonical rotation
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.Engine;
|
||||
using OpenNest.Geometry;
|
||||
using OpenNest.Math;
|
||||
|
||||
namespace OpenNest.Tests.Engine;
|
||||
|
||||
public class CanonicalFrameTests
|
||||
{
|
||||
private static Drawing MakeRect(double w, double h, double rotation)
|
||||
{
|
||||
var pgm = new OpenNest.CNC.Program();
|
||||
pgm.Codes.Add(new RapidMove(new Vector(0, 0)));
|
||||
pgm.Codes.Add(new LinearMove(new Vector(w, 0)));
|
||||
pgm.Codes.Add(new LinearMove(new Vector(w, h)));
|
||||
pgm.Codes.Add(new LinearMove(new Vector(0, h)));
|
||||
pgm.Codes.Add(new LinearMove(new Vector(0, 0)));
|
||||
if (!Tolerance.IsEqualTo(rotation, 0))
|
||||
pgm.Rotate(rotation, pgm.BoundingBox().Center);
|
||||
return new Drawing("rect", pgm) { Source = new SourceInfo { Angle = -rotation } };
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AsCanonicalCopy_AxisAlignsMbr()
|
||||
{
|
||||
var d = MakeRect(100, 50, 0.6);
|
||||
var canonical = CanonicalFrame.AsCanonicalCopy(d);
|
||||
|
||||
var bb = canonical.Program.BoundingBox();
|
||||
var longer = System.Math.Max(bb.Length, bb.Width);
|
||||
var shorter = System.Math.Min(bb.Length, bb.Width);
|
||||
Assert.InRange(longer, 100 - 0.1, 100 + 0.1);
|
||||
Assert.InRange(shorter, 50 - 0.1, 50 + 0.1);
|
||||
Assert.Equal(0.0, canonical.Source.Angle, precision: 6);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AsCanonicalCopy_DoesNotMutateSource()
|
||||
{
|
||||
var d = MakeRect(100, 50, 0.6);
|
||||
var originalBbox = d.Program.BoundingBox();
|
||||
var originalAngle = d.Source.Angle;
|
||||
|
||||
CanonicalFrame.AsCanonicalCopy(d);
|
||||
|
||||
var afterBbox = d.Program.BoundingBox();
|
||||
Assert.Equal(originalBbox.Width, afterBbox.Width, precision: 6);
|
||||
Assert.Equal(originalBbox.Length, afterBbox.Length, precision: 6);
|
||||
Assert.Equal(originalAngle, d.Source.Angle, precision: 6);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FromCanonical_ComposesSourceAngleOntoRotation()
|
||||
{
|
||||
var d = MakeRect(100, 50, 0.0);
|
||||
var part = new Part(d);
|
||||
part.Rotate(0.2); // engine returned a canonical-frame part at R = 0.2
|
||||
|
||||
var placed = CanonicalFrame.FromCanonical(new List<Part> { part }, sourceAngle: -0.5);
|
||||
|
||||
// R' = R + sourceAngle = 0.2 + (-0.5) = -0.3
|
||||
// Part.Rotation comes from Program.Rotation which is normalized to [0, 2PI),
|
||||
// so compare after normalizing the expected value as well.
|
||||
Assert.Single(placed);
|
||||
Assert.Equal(Angle.NormalizeRad(-0.3), placed[0].Rotation, precision: 4);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RoundTrip_RestoresGeometry()
|
||||
{
|
||||
var d = MakeRect(100, 50, 0.4);
|
||||
var canonical = CanonicalFrame.AsCanonicalCopy(d);
|
||||
|
||||
// Place a part at origin in the canonical frame.
|
||||
var part = Part.CreateAtOrigin(canonical);
|
||||
var canonicalBbox = part.BoundingBox;
|
||||
|
||||
var placed = CanonicalFrame.FromCanonical(new List<Part> { part }, d.Source.Angle);
|
||||
|
||||
var originalBbox = d.Program.BoundingBox();
|
||||
Assert.Equal(originalBbox.Width, placed[0].BoundingBox.Width, precision: 2);
|
||||
Assert.Equal(originalBbox.Length, placed[0].BoundingBox.Length, precision: 2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user