mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-11-06 14:35:44 -05:00
Fill only tried 0 and 90 degrees for parts classified as rectangles, so a long part filling a 60 x 120 plate four high at 90 degrees left a 55 x 59 strip empty although two more fit tilted about 33 degrees (a reported nest: 4 placed, 6 fit). The second tilted part only fits with its corner tucked beside the grid, in the strip the grid's slack leaves, so a plain rectangular remnant fill finds one. TiltedRemnant runs after the other strategies. It moves the best layout flush to one end so leftover room becomes one remnant, and to either end of the other axis so its slack forms one strip; then tiles the part at the most upright angles that fit the remnant's height and keeps only copies at least the part spacing from the layout. It is skipped when the part fits the remnant upright, for circles, for an explicit rotation range and once the requested quantity is placed. Fill benchmark (--parallel 1): the synthetic set is unchanged (all valid, same cost and plates). The reported part needs 1 sheet instead of 2 for 6 parts and 2 instead of 3 for 12. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
45 lines
1.4 KiB
C#
45 lines
1.4 KiB
C#
using System.Collections.Generic;
|
|
using OpenNest.Engine.Fill;
|
|
using OpenNest.Math;
|
|
|
|
namespace OpenNest.Engine.Strategies;
|
|
|
|
/// <summary>
|
|
/// Runs after the other strategies and adds tilted parts beside their best layout, where the
|
|
/// leftover strip is too narrow for the part at 0 or 90 degrees. See <see cref="TiltedRemnantFiller"/>.
|
|
/// </summary>
|
|
public class TiltedRemnantStrategy : IFillStrategy
|
|
{
|
|
public string Name => "TiltedRemnant";
|
|
public NestPhase Phase => NestPhase.Custom;
|
|
public int Order => 500;
|
|
|
|
public List<Part> Fill(FillContext context)
|
|
{
|
|
var layout = context.CurrentBest;
|
|
if (layout == null || layout.Count == 0 || context.PartType == PartType.Circle)
|
|
return null;
|
|
|
|
// Tilting would break an explicit rotation range.
|
|
var item = context.Item;
|
|
if (!item.RotationStart.IsEqualTo(0) || !item.RotationEnd.IsEqualTo(0))
|
|
return null;
|
|
|
|
var target = context.MaxQuantity > 0 ? context.MaxQuantity : item.Quantity;
|
|
if (target > 0 && layout.Count >= target)
|
|
return null;
|
|
|
|
var filler = new TiltedRemnantFiller(
|
|
context.WorkArea,
|
|
context.Plate.PartSpacing,
|
|
context.Policy.Comparer
|
|
);
|
|
var result = filler.Fill(item.Drawing, layout, context.Token);
|
|
|
|
if (result != null)
|
|
context.ReportProgress(result, $"Tilted remnant: {result.Count} parts");
|
|
|
|
return result;
|
|
}
|
|
}
|