mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-27 06:01:06 -04:00
Cut planning should rank routes safest first, then fastest, but a plate whose
strict search hit its expansion budget was simply refused ("no plan found
within the search limit"), even when a route with a few reviewable rapid
crossings existed. Scrap cut-offs make this common: their trimmed segments
can wall off a column of parts, and rapids are straight.
When both the free-order and current-order searches stop at the limit, the
batch now walks a greedy safest route from each input, replays it with fresh
checks, and keeps the one with fewer violations (material first, then rapid
crossings, then the rest), then less rapid travel. A route that passes every
check is an ordinary Ready plan; otherwise it is an unverified BestEffort
that lists every violation and applies only with explicit acceptance. Routes
with any motion into material are never offered, so the strict refusal and
its lead-in advice stand.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
52 lines
1.9 KiB
C#
52 lines
1.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using OpenNest.Diagnostics;
|
|
|
|
namespace OpenNest.Engine.CuttingPlanning;
|
|
|
|
/// <summary>
|
|
/// How unsafe a route is, compared most severe first: motions into material (leads through a
|
|
/// part, cut-order or nested-lead conflicts, incomplete checks), then rapids across cut
|
|
/// contours, then everything else. The default is a route that breaks no check.
|
|
/// </summary>
|
|
internal readonly record struct RouteSeverity(int Severe, int Rapids, int Minor) : IComparable<RouteSeverity>
|
|
{
|
|
internal bool IsClear => Severe == 0 && Rapids == 0 && Minor == 0;
|
|
|
|
internal int Count => Severe + Rapids + Minor;
|
|
|
|
public int CompareTo(RouteSeverity other) =>
|
|
Severe != other.Severe ? Severe.CompareTo(other.Severe)
|
|
: Rapids != other.Rapids ? Rapids.CompareTo(other.Rapids)
|
|
: Minor.CompareTo(other.Minor);
|
|
|
|
public static bool operator <(RouteSeverity left, RouteSeverity right) => left.CompareTo(right) < 0;
|
|
|
|
public static bool operator >(RouteSeverity left, RouteSeverity right) => left.CompareTo(right) > 0;
|
|
|
|
/// <summary>A finding without a kind is a refused lead path (into material or a pierce zone).</summary>
|
|
internal static RouteSeverity Of(IEnumerable<PostVerificationKind?> kinds)
|
|
{
|
|
var severe = 0;
|
|
var rapids = 0;
|
|
var minor = 0;
|
|
foreach (var kind in kinds)
|
|
{
|
|
switch (kind)
|
|
{
|
|
case null or PostVerificationKind.Overlap or PostVerificationKind.NestedCutOrder
|
|
or PostVerificationKind.NestedLead or PostVerificationKind.Incomplete:
|
|
severe++;
|
|
break;
|
|
case PostVerificationKind.RapidCrossing:
|
|
rapids++;
|
|
break;
|
|
default:
|
|
minor++;
|
|
break;
|
|
}
|
|
}
|
|
return new(severe, rapids, minor);
|
|
}
|
|
}
|