using System; using System.Collections.Generic; using OpenNest.Diagnostics; namespace OpenNest.Engine.CuttingPlanning; /// /// 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. /// internal readonly record struct RouteSeverity(int Severe, int Rapids, int Minor) : IComparable { 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; /// A finding without a kind is a refused lead path (into material or a pierce zone). internal static RouteSeverity Of(IEnumerable 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); } }