diff --git a/OpenNest.Engine/Fill/PairFiller.cs b/OpenNest.Engine/Fill/PairFiller.cs index 18dc1c6..dfddfbb 100644 --- a/OpenNest.Engine/Fill/PairFiller.cs +++ b/OpenNest.Engine/Fill/PairFiller.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; +using OpenNest.Engine; namespace OpenNest.Engine.Fill { @@ -29,11 +30,13 @@ namespace OpenNest.Engine.Fill private readonly Size plateSize; private readonly double partSpacing; + private readonly IFillComparer comparer; - public PairFiller(Size plateSize, double partSpacing) + public PairFiller(Size plateSize, double partSpacing, IFillComparer comparer = null) { this.plateSize = plateSize; this.partSpacing = partSpacing; + this.comparer = comparer ?? new DefaultFillComparer(); } public PairFillResult Fill(NestItem item, Box workArea, @@ -61,7 +64,6 @@ namespace OpenNest.Engine.Fill int plateNumber, CancellationToken token, IProgress progress) { List best = null; - var bestScore = default(FillScore); var sinceImproved = 0; var effectiveWorkArea = workArea; @@ -72,12 +74,10 @@ namespace OpenNest.Engine.Fill token.ThrowIfCancellationRequested(); var filled = EvaluateCandidate(candidates[i], drawing, effectiveWorkArea); - var score = FillScore.Compute(filled, effectiveWorkArea); - if (score > bestScore) + if (comparer.IsBetter(filled, best, effectiveWorkArea)) { best = filled; - bestScore = score; sinceImproved = 0; effectiveWorkArea = TryReduceWorkArea(filled, targetCount, workArea, effectiveWorkArea); } @@ -87,7 +87,7 @@ namespace OpenNest.Engine.Fill } NestEngineBase.ReportProgress(progress, NestPhase.Pairs, plateNumber, best, workArea, - $"Pairs: {i + 1}/{candidates.Count} candidates, best = {bestScore.Count} parts"); + $"Pairs: {i + 1}/{candidates.Count} candidates, best = {best?.Count ?? 0} parts"); if (i + 1 >= EarlyExitMinTried && sinceImproved >= EarlyExitStaleLimit) { @@ -101,7 +101,7 @@ namespace OpenNest.Engine.Fill Debug.WriteLine("[PairFiller] Cancelled mid-phase, using results so far"); } - Debug.WriteLine($"[PairFiller] Best pair result: {bestScore.Count} parts, density={bestScore.Density:P1}"); + Debug.WriteLine($"[PairFiller] Best pair result: {best?.Count ?? 0} parts"); return best ?? new List(); } @@ -147,7 +147,7 @@ namespace OpenNest.Engine.Fill var pairParts = candidate.BuildParts(drawing); var engine = new FillLinear(workArea, partSpacing); var angles = BuildTilingAngles(candidate); - return FillHelpers.FillPattern(engine, pairParts, angles, workArea); + return FillHelpers.FillPattern(engine, pairParts, angles, workArea, comparer); } private static List BuildTilingAngles(BestFitResult candidate) diff --git a/OpenNest.Engine/Fill/StripeFiller.cs b/OpenNest.Engine/Fill/StripeFiller.cs index a488623..47574a5 100644 --- a/OpenNest.Engine/Fill/StripeFiller.cs +++ b/OpenNest.Engine/Fill/StripeFiller.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading; +using OpenNest.Engine; using OpenNest.Engine.BestFit; using OpenNest.Engine.Strategies; using OpenNest.Geometry; @@ -18,6 +19,7 @@ public class StripeFiller private readonly FillContext _context; private readonly NestDirection _primaryAxis; + private readonly IFillComparer _comparer; /// /// When true, only complete stripes are placed — no partial rows/columns. @@ -35,6 +37,7 @@ public class StripeFiller { _context = context; _primaryAxis = primaryAxis; + _comparer = context.Policy?.Comparer ?? new DefaultFillComparer(); } public List Fill() @@ -49,7 +52,6 @@ public class StripeFiller var strategyName = _primaryAxis == NestDirection.Horizontal ? "Row" : "Column"; List bestParts = null; - var bestScore = default(FillScore); for (var i = 0; i < bestFits.Count; i++) { @@ -82,22 +84,20 @@ public class StripeFiller if (result == null || result.Count == 0) continue; - var score = FillScore.Compute(result, workArea); Debug.WriteLine($"[StripeFiller] {strategyName} candidate {i} {dirLabel}: " + $"angle={Angle.ToDegrees(angle):F1}°, N={count}, waste={waste:F2}, " + $"grid={result.Count} parts"); - if (bestParts == null || score > bestScore) + if (_comparer.IsBetter(result, bestParts, workArea)) { bestParts = result; - bestScore = score; } } } NestEngineBase.ReportProgress(_context.Progress, NestPhase.Custom, _context.PlateNumber, bestParts, workArea, - $"{strategyName}: {i + 1}/{bestFits.Count} pairs, best = {bestScore.Count} parts"); + $"{strategyName}: {i + 1}/{bestFits.Count} pairs, best = {bestParts?.Count ?? 0} parts"); } return bestParts ?? new List(); diff --git a/OpenNest.Engine/Strategies/PairsFillStrategy.cs b/OpenNest.Engine/Strategies/PairsFillStrategy.cs index 862390e..1df3ab9 100644 --- a/OpenNest.Engine/Strategies/PairsFillStrategy.cs +++ b/OpenNest.Engine/Strategies/PairsFillStrategy.cs @@ -11,7 +11,8 @@ namespace OpenNest.Engine.Strategies public List Fill(FillContext context) { - var filler = new PairFiller(context.Plate.Size, context.Plate.PartSpacing); + var comparer = context.Policy?.Comparer; + var filler = new PairFiller(context.Plate.Size, context.Plate.PartSpacing, comparer); var result = filler.Fill(context.Item, context.WorkArea, context.PlateNumber, context.Token, context.Progress);