From 07d6f08e8b68b6bfbc389d129cd42042c655d9e8 Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Sun, 22 Mar 2026 19:43:29 -0400 Subject: [PATCH] feat: engine-specific TrimAxis and rename ShrinkAxis.Height to Length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make quantity trimming direction-aware: DefaultNestEngine uses TrimAxis (virtual property on NestEngineBase) so HorizontalRemnantEngine removes topmost parts instead of rightmost. Rename ShrinkAxis.Height → Length for consistency with Width/Length naming used throughout the codebase. Co-Authored-By: Claude Opus 4.6 (1M context) --- OpenNest.Engine/DefaultNestEngine.cs | 2 +- OpenNest.Engine/Fill/IterativeShrinkFiller.cs | 4 ++-- OpenNest.Engine/Fill/ShrinkFiller.cs | 6 +++--- OpenNest.Engine/HorizontalRemnantEngine.cs | 2 ++ OpenNest.Engine/NestEngineBase.cs | 2 ++ OpenNest.Tests/ShrinkFillerTests.cs | 8 ++++---- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/OpenNest.Engine/DefaultNestEngine.cs b/OpenNest.Engine/DefaultNestEngine.cs index 0039bde..dfa7558 100644 --- a/OpenNest.Engine/DefaultNestEngine.cs +++ b/OpenNest.Engine/DefaultNestEngine.cs @@ -64,7 +64,7 @@ namespace OpenNest var best = context.CurrentBest ?? new List(); if (item.Quantity > 0 && best.Count > item.Quantity) - best = ShrinkFiller.TrimToCount(best, item.Quantity, ShrinkAxis.Width); + best = ShrinkFiller.TrimToCount(best, item.Quantity, TrimAxis); ReportProgress(progress, new ProgressReport { diff --git a/OpenNest.Engine/Fill/IterativeShrinkFiller.cs b/OpenNest.Engine/Fill/IterativeShrinkFiller.cs index 50f9bd7..a1034b4 100644 --- a/OpenNest.Engine/Fill/IterativeShrinkFiller.cs +++ b/OpenNest.Engine/Fill/IterativeShrinkFiller.cs @@ -18,7 +18,7 @@ namespace OpenNest.Engine.Fill /// /// Composes and with /// dual-direction shrink selection. Wraps the caller's fill function in a - /// closure that tries both and + /// closure that tries both and /// , picks the better , /// and passes the wrapper to . /// @@ -85,7 +85,7 @@ namespace OpenNest.Engine.Fill ShrinkResult widthResult = null; Parallel.Invoke( - () => heightResult = ShrinkFiller.Shrink(fillFunc, ni, box, spacing, ShrinkAxis.Height, token, + () => heightResult = ShrinkFiller.Shrink(fillFunc, ni, box, spacing, ShrinkAxis.Length, token, targetCount: target, progress: progress, plateNumber: plateNumber, placedParts: placedSoFar), () => widthResult = ShrinkFiller.Shrink(wFillFunc, ni, box, spacing, ShrinkAxis.Width, token, targetCount: target, progress: progress, plateNumber: plateNumber, placedParts: placedSoFar) diff --git a/OpenNest.Engine/Fill/ShrinkFiller.cs b/OpenNest.Engine/Fill/ShrinkFiller.cs index 19172a6..b772454 100644 --- a/OpenNest.Engine/Fill/ShrinkFiller.cs +++ b/OpenNest.Engine/Fill/ShrinkFiller.cs @@ -7,7 +7,7 @@ using System.Threading; namespace OpenNest.Engine.Fill { - public enum ShrinkAxis { Width, Height } + public enum ShrinkAxis { Width, Length } public class ShrinkResult { @@ -101,7 +101,7 @@ namespace OpenNest.Engine.Fill if (bbox.Width <= 0 || bbox.Length <= 0) return box; - var maxDim = axis == ShrinkAxis.Height ? box.Length : box.Width; + var maxDim = axis == ShrinkAxis.Length ? box.Length : box.Width; // Use FillBestFit for a fast, accurate rectangle count on the full box. var bin = new Bin { Size = new Size(box.Width, box.Length) }; @@ -121,7 +121,7 @@ namespace OpenNest.Engine.Fill if (estimate <= 0 || estimate >= maxDim) return box; - return axis == ShrinkAxis.Height + return axis == ShrinkAxis.Length ? new Box(box.X, box.Y, box.Width, estimate) : new Box(box.X, box.Y, estimate, box.Length); } diff --git a/OpenNest.Engine/HorizontalRemnantEngine.cs b/OpenNest.Engine/HorizontalRemnantEngine.cs index 1cadd19..6218a9a 100644 --- a/OpenNest.Engine/HorizontalRemnantEngine.cs +++ b/OpenNest.Engine/HorizontalRemnantEngine.cs @@ -24,6 +24,8 @@ namespace OpenNest public override NestDirection? PreferredDirection => NestDirection.Vertical; + public override ShrinkAxis TrimAxis => ShrinkAxis.Length; + public override List BuildAngles(NestItem item, double bestRotation, Box workArea) { var baseAngles = new List { bestRotation, bestRotation + Angle.HalfPI }; diff --git a/OpenNest.Engine/NestEngineBase.cs b/OpenNest.Engine/NestEngineBase.cs index eaf58e8..b60fd0d 100644 --- a/OpenNest.Engine/NestEngineBase.cs +++ b/OpenNest.Engine/NestEngineBase.cs @@ -43,6 +43,8 @@ namespace OpenNest public virtual NestDirection? PreferredDirection => null; + public virtual ShrinkAxis TrimAxis => ShrinkAxis.Width; + public virtual List BuildAngles(NestItem item, double bestRotation, Box workArea) { return new List { bestRotation, bestRotation + OpenNest.Math.Angle.HalfPI }; diff --git a/OpenNest.Tests/ShrinkFillerTests.cs b/OpenNest.Tests/ShrinkFillerTests.cs index 93b3b5d..1345562 100644 --- a/OpenNest.Tests/ShrinkFillerTests.cs +++ b/OpenNest.Tests/ShrinkFillerTests.cs @@ -30,7 +30,7 @@ public class ShrinkFillerTests return engine.Fill(ni, b, null, System.Threading.CancellationToken.None); }; - var result = ShrinkFiller.Shrink(fillFunc, item, box, 1.0, ShrinkAxis.Height); + var result = ShrinkFiller.Shrink(fillFunc, item, box, 1.0, ShrinkAxis.Length); Assert.NotNull(result); Assert.True(result.Parts.Count > 0); @@ -73,7 +73,7 @@ public class ShrinkFillerTests new List { TestHelpers.MakePartAt(0, 0, 10) }; var result = ShrinkFiller.Shrink(fillFunc, item, box, 1.0, - ShrinkAxis.Height, token: cts.Token); + ShrinkAxis.Length, token: cts.Token); Assert.NotNull(result); Assert.True(result.Parts.Count > 0); @@ -97,7 +97,7 @@ public class ShrinkFillerTests } [Fact] - public void TrimToCount_Height_KeepsPartsNearestToOrigin() + public void TrimToCount_Length_KeepsPartsNearestToOrigin() { var parts = new List { @@ -107,7 +107,7 @@ public class ShrinkFillerTests TestHelpers.MakePartAt(0, 30, 5), // Top = 35 }; - var trimmed = ShrinkFiller.TrimToCount(parts, 2, ShrinkAxis.Height); + var trimmed = ShrinkFiller.TrimToCount(parts, 2, ShrinkAxis.Length); Assert.Equal(2, trimmed.Count); Assert.True(trimmed.All(p => p.BoundingBox.Top <= 15));