diff --git a/OpenNest.Core/Plate.cs b/OpenNest.Core/Plate.cs index 674a1159..2c1aa62c 100644 --- a/OpenNest.Core/Plate.cs +++ b/OpenNest.Core/Plate.cs @@ -710,6 +710,14 @@ namespace OpenNest return box; } + /// + /// The offset that centers the parts' combined bounds in the , + /// so uneven edge spacing (such as a wider clamp-side margin) shifts them with it. + /// Zero when the plate has no parts. + /// + public Vector OffsetToCenterPartsInWorkArea() => + Parts.Count == 0 ? new Vector() : WorkArea().Center - Parts.GetBoundingBox().Center; + /// /// Automatically sizes the plate to fit the parts. /// diff --git a/OpenNest.Tests/PlateCenterPartsTests.cs b/OpenNest.Tests/PlateCenterPartsTests.cs new file mode 100644 index 00000000..51d76ad4 --- /dev/null +++ b/OpenNest.Tests/PlateCenterPartsTests.cs @@ -0,0 +1,50 @@ +using OpenNest.CNC; +using OpenNest.Geometry; + +namespace OpenNest.Tests; + +public class PlateCenterPartsTests +{ + private static Part MakeSquare(Vector location) + { + var pgm = new Program(); + pgm.Codes.Add(new RapidMove(new Vector(0, 0))); + pgm.Codes.Add(new LinearMove(new Vector(10, 0))); + pgm.Codes.Add(new LinearMove(new Vector(10, 10))); + pgm.Codes.Add(new LinearMove(new Vector(0, 10))); + pgm.Codes.Add(new LinearMove(new Vector(0, 0))); + return new Part(new Drawing("square", pgm), location); + } + + [Fact] + public void CentersPartsInWorkAreaNotPlate() + { + var plate = new Plate(100, 100) + { + // Wider clamp-side margin at the bottom. + EdgeSpacing = new Spacing(left: 0.25, bottom: 0.75, right: 0.25, top: 0.25), + }; + var part = MakeSquare(new Vector(5, 5)); + plate.Parts.Add(part); + + part.Offset(plate.OffsetToCenterPartsInWorkArea()); + + var box = part.BoundingBox; + // Work area is X 0.25..99.75, Y 0.75..99.75, so the centre sits 0.25 above the plate's. + Assert.Equal(50, box.Center.X, 6); + Assert.Equal(50.25, box.Center.Y, 6); + Assert.Equal(box.Left - 0.25, 99.75 - box.Right, 6); + Assert.Equal(box.Bottom - 0.75, 99.75 - box.Top, 6); + } + + [Fact] + public void EmptyPlateNeedsNoOffset() + { + var plate = new Plate(100, 100) { EdgeSpacing = new Spacing(0.25, 0.75, 0.25, 0.25) }; + + var offset = plate.OffsetToCenterPartsInWorkArea(); + + Assert.Equal(0, offset.X); + Assert.Equal(0, offset.Y); + } +} diff --git a/OpenNest/Forms/MainForm.Tools.cs b/OpenNest/Forms/MainForm.Tools.cs index 30837a40..2a846af6 100644 --- a/OpenNest/Forms/MainForm.Tools.cs +++ b/OpenNest/Forms/MainForm.Tools.cs @@ -229,10 +229,7 @@ namespace OpenNest.Forms if (view?.Plate == null || view.Parts.Count == 0) return; - var plateCenter = view.Plate.BoundingBox(false).Center; - var partsCenter = view.Parts.GetBoundingBox().Center; - - var offset = plateCenter - partsCenter; + var offset = view.Plate.OffsetToCenterPartsInWorkArea(); foreach (var part in view.Parts) part.Offset(offset);