feat: engine-specific TrimAxis and rename ShrinkAxis.Height to Length
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) <noreply@anthropic.com>
This commit is contained in:
@@ -64,7 +64,7 @@ namespace OpenNest
|
|||||||
var best = context.CurrentBest ?? new List<Part>();
|
var best = context.CurrentBest ?? new List<Part>();
|
||||||
|
|
||||||
if (item.Quantity > 0 && best.Count > item.Quantity)
|
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
|
ReportProgress(progress, new ProgressReport
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace OpenNest.Engine.Fill
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Composes <see cref="RemnantFiller"/> and <see cref="ShrinkFiller"/> with
|
/// Composes <see cref="RemnantFiller"/> and <see cref="ShrinkFiller"/> with
|
||||||
/// dual-direction shrink selection. Wraps the caller's fill function in a
|
/// dual-direction shrink selection. Wraps the caller's fill function in a
|
||||||
/// closure that tries both <see cref="ShrinkAxis.Height"/> and
|
/// closure that tries both <see cref="ShrinkAxis.Length"/> and
|
||||||
/// <see cref="ShrinkAxis.Width"/>, picks the better <see cref="FillScore"/>,
|
/// <see cref="ShrinkAxis.Width"/>, picks the better <see cref="FillScore"/>,
|
||||||
/// and passes the wrapper to <see cref="RemnantFiller.FillItems"/>.
|
/// and passes the wrapper to <see cref="RemnantFiller.FillItems"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -85,7 +85,7 @@ namespace OpenNest.Engine.Fill
|
|||||||
ShrinkResult widthResult = null;
|
ShrinkResult widthResult = null;
|
||||||
|
|
||||||
Parallel.Invoke(
|
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),
|
targetCount: target, progress: progress, plateNumber: plateNumber, placedParts: placedSoFar),
|
||||||
() => widthResult = ShrinkFiller.Shrink(wFillFunc, ni, box, spacing, ShrinkAxis.Width, token,
|
() => widthResult = ShrinkFiller.Shrink(wFillFunc, ni, box, spacing, ShrinkAxis.Width, token,
|
||||||
targetCount: target, progress: progress, plateNumber: plateNumber, placedParts: placedSoFar)
|
targetCount: target, progress: progress, plateNumber: plateNumber, placedParts: placedSoFar)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using System.Threading;
|
|||||||
|
|
||||||
namespace OpenNest.Engine.Fill
|
namespace OpenNest.Engine.Fill
|
||||||
{
|
{
|
||||||
public enum ShrinkAxis { Width, Height }
|
public enum ShrinkAxis { Width, Length }
|
||||||
|
|
||||||
public class ShrinkResult
|
public class ShrinkResult
|
||||||
{
|
{
|
||||||
@@ -101,7 +101,7 @@ namespace OpenNest.Engine.Fill
|
|||||||
if (bbox.Width <= 0 || bbox.Length <= 0)
|
if (bbox.Width <= 0 || bbox.Length <= 0)
|
||||||
return box;
|
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.
|
// Use FillBestFit for a fast, accurate rectangle count on the full box.
|
||||||
var bin = new Bin { Size = new Size(box.Width, box.Length) };
|
var bin = new Bin { Size = new Size(box.Width, box.Length) };
|
||||||
@@ -121,7 +121,7 @@ namespace OpenNest.Engine.Fill
|
|||||||
if (estimate <= 0 || estimate >= maxDim)
|
if (estimate <= 0 || estimate >= maxDim)
|
||||||
return box;
|
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, box.Width, estimate)
|
||||||
: new Box(box.X, box.Y, estimate, box.Length);
|
: new Box(box.X, box.Y, estimate, box.Length);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ namespace OpenNest
|
|||||||
|
|
||||||
public override NestDirection? PreferredDirection => NestDirection.Vertical;
|
public override NestDirection? PreferredDirection => NestDirection.Vertical;
|
||||||
|
|
||||||
|
public override ShrinkAxis TrimAxis => ShrinkAxis.Length;
|
||||||
|
|
||||||
public override List<double> BuildAngles(NestItem item, double bestRotation, Box workArea)
|
public override List<double> BuildAngles(NestItem item, double bestRotation, Box workArea)
|
||||||
{
|
{
|
||||||
var baseAngles = new List<double> { bestRotation, bestRotation + Angle.HalfPI };
|
var baseAngles = new List<double> { bestRotation, bestRotation + Angle.HalfPI };
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ namespace OpenNest
|
|||||||
|
|
||||||
public virtual NestDirection? PreferredDirection => null;
|
public virtual NestDirection? PreferredDirection => null;
|
||||||
|
|
||||||
|
public virtual ShrinkAxis TrimAxis => ShrinkAxis.Width;
|
||||||
|
|
||||||
public virtual List<double> BuildAngles(NestItem item, double bestRotation, Box workArea)
|
public virtual List<double> BuildAngles(NestItem item, double bestRotation, Box workArea)
|
||||||
{
|
{
|
||||||
return new List<double> { bestRotation, bestRotation + OpenNest.Math.Angle.HalfPI };
|
return new List<double> { bestRotation, bestRotation + OpenNest.Math.Angle.HalfPI };
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public class ShrinkFillerTests
|
|||||||
return engine.Fill(ni, b, null, System.Threading.CancellationToken.None);
|
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.NotNull(result);
|
||||||
Assert.True(result.Parts.Count > 0);
|
Assert.True(result.Parts.Count > 0);
|
||||||
@@ -73,7 +73,7 @@ public class ShrinkFillerTests
|
|||||||
new List<Part> { TestHelpers.MakePartAt(0, 0, 10) };
|
new List<Part> { TestHelpers.MakePartAt(0, 0, 10) };
|
||||||
|
|
||||||
var result = ShrinkFiller.Shrink(fillFunc, item, box, 1.0,
|
var result = ShrinkFiller.Shrink(fillFunc, item, box, 1.0,
|
||||||
ShrinkAxis.Height, token: cts.Token);
|
ShrinkAxis.Length, token: cts.Token);
|
||||||
|
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.True(result.Parts.Count > 0);
|
Assert.True(result.Parts.Count > 0);
|
||||||
@@ -97,7 +97,7 @@ public class ShrinkFillerTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TrimToCount_Height_KeepsPartsNearestToOrigin()
|
public void TrimToCount_Length_KeepsPartsNearestToOrigin()
|
||||||
{
|
{
|
||||||
var parts = new List<Part>
|
var parts = new List<Part>
|
||||||
{
|
{
|
||||||
@@ -107,7 +107,7 @@ public class ShrinkFillerTests
|
|||||||
TestHelpers.MakePartAt(0, 30, 5), // Top = 35
|
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.Equal(2, trimmed.Count);
|
||||||
Assert.True(trimmed.All(p => p.BoundingBox.Top <= 15));
|
Assert.True(trimmed.All(p => p.BoundingBox.Top <= 15));
|
||||||
|
|||||||
Reference in New Issue
Block a user