fix(opus55): honor part priority and use host scoring and tolerances
Opus55 ignored NestJobPart.Priority, so the shared contract test (lower number wins scarce stock) failed; lower-number priority now precedes its placement score. SheetEconomics is replaced by the host's NestJobCost so it optimizes exactly what the benchmark scores, and its footprint margin comes from NestTolerances.SafeClearanceMargin plus four Clipper grid units - the same 0.003 total as before, which keeps its contact points. Synthetic benchmark (5 jobs, salvage 0.5): all valid, cost unchanged at 5452.79, time 611 -> 456 ms. Co-Authored-By: Codex <noreply@openai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -63,25 +63,9 @@ internal sealed class FrontierPacker
|
||||
this.stock = stock;
|
||||
this.axis = axis;
|
||||
this.beta = beta;
|
||||
work = WorkArea(stock);
|
||||
work = stock.WorkArea;
|
||||
}
|
||||
|
||||
public static Box WorkArea(NestPlateStock stock)
|
||||
{
|
||||
var left = stock.Quadrant is 1 or 4 ? 0 : -stock.Size.Length;
|
||||
var bottom = stock.Quadrant is 1 or 2 ? 0 : -stock.Size.Width;
|
||||
return new Box(
|
||||
left + stock.EdgeSpacing.Left,
|
||||
bottom + stock.EdgeSpacing.Bottom,
|
||||
stock.Size.Length - stock.EdgeSpacing.Left - stock.EdgeSpacing.Right,
|
||||
stock.Size.Width - stock.EdgeSpacing.Bottom - stock.EdgeSpacing.Top
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>True when the orientation's bounds fit the work area at all (Box.Length is the X extent).</summary>
|
||||
public static bool Fits(Orientation o, Box work) =>
|
||||
o.Width <= work.Length + 1e-9 && o.Height <= work.Width + 1e-9;
|
||||
|
||||
public SheetFill Fill(IReadOnlyList<int> remaining, CancellationToken token)
|
||||
{
|
||||
var left = remaining.ToArray();
|
||||
@@ -91,7 +75,7 @@ internal sealed class FrontierPacker
|
||||
if (left[type.Index] <= 0)
|
||||
continue;
|
||||
foreach (var o in type.Orientations)
|
||||
if (Fits(o, work))
|
||||
if (stock.Fits(o.Width, o.Height))
|
||||
states.Add(new Region(o, work));
|
||||
}
|
||||
|
||||
@@ -140,17 +124,21 @@ internal sealed class FrontierPacker
|
||||
var bestValue = double.PositiveInfinity;
|
||||
var bestSide = double.PositiveInfinity;
|
||||
var bestLead = double.PositiveInfinity;
|
||||
var bestPriority = int.MaxValue;
|
||||
|
||||
foreach (var region in states)
|
||||
{
|
||||
if (!region.TryLowest(axis, front, out var point, out var advance, out var side, out var lead))
|
||||
continue;
|
||||
var area = types[region.Orientation.TypeIndex].Area;
|
||||
var priority = types[region.Orientation.TypeIndex].Part.Priority;
|
||||
if (priority > bestPriority) continue;
|
||||
var fills = advance <= Tie;
|
||||
// Gap fill prefers bigger parts (negated area); advance prefers least advance per area.
|
||||
var value = fills ? -area : advance / System.Math.Pow(System.Math.Max(area, 1e-12), beta);
|
||||
|
||||
var better = bestRegion == null
|
||||
|| priority < bestPriority
|
||||
|| (fills && !bestFills)
|
||||
|| (
|
||||
fills == bestFills
|
||||
@@ -165,6 +153,7 @@ internal sealed class FrontierPacker
|
||||
if (!better)
|
||||
continue;
|
||||
bestRegion = region;
|
||||
bestPriority = priority;
|
||||
bestPoint = point;
|
||||
bestFills = fills;
|
||||
bestValue = value;
|
||||
|
||||
Reference in New Issue
Block a user