Files
OpenNest/OpenNest.Engine/Jobs/Cutouts/CutoutSeatedArea.cs
T
ajandClaude Opus 5.5 62e5410cdb fix(cutouts): maximize material seated in cutouts, not copies
Compare cutout proposals, frame angles and bundles by insert outline area,
and add bounded largest-first packer candidates so big parts get the first
move in an empty hole. On the real job the four frames go from 54-70% to
77-81% filled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 23:42:26 -05:00

41 lines
1.8 KiB
C#

#nullable enable
using System;
using System.Collections.Generic;
namespace OpenNest.Engine.Jobs.Cutouts;
/// <summary>What cutout filling maximizes: the job's material seated in cutouts, read as insert
/// outline area, since every square inch in a hole is one the sheet no longer has to give.
/// Copy count plays no part, so one large part beats a handful of tiny ones of less area.</summary>
internal static class CutoutSeatedArea
{
private const double Tie = 1e-6;
/// <summary>The area a part takes off a sheet: its outline, holes included.</summary>
internal static double Outline(JobPartGeometry geometry) => System.Math.Abs(geometry.Perimeter.Area());
internal static double Of(IReadOnlyList<NestJobPlacement> poses, Func<string, JobPartGeometry> geometry)
{
var area = 0.0;
foreach (var pose in poses)
area += Outline(geometry(pose.PartId));
return area;
}
/// <summary>True when <paramref name="candidate"/> seats more area, beyond rounding: areas
/// summed in another order count as the same.</summary>
internal static bool More(double candidate, double incumbent) =>
candidate - incumbent > Tie * System.Math.Max(candidate, incumbent);
/// <summary>True when <paramref name="candidate"/> should replace
/// <paramref name="incumbent"/>: it seats more area, or the same area more compactly.</summary>
internal static bool Better(IReadOnlyList<NestJobPlacement> candidate,
IReadOnlyList<NestJobPlacement> incumbent, Func<string, JobPartGeometry> geometry)
{
var area = Of(candidate, geometry);
var other = Of(incumbent, geometry);
return More(area, other)
|| (!More(other, area) && CutoutPackerProposal.Tighter(candidate, incumbent, geometry));
}
}