refactor(sequencing): share the cutoff crossing rule with cutting planning

Move the nominal-span cutoff rule unchanged into CuttingDependencyGraph so
automatic sequencing and the cutting planner apply the same dependency.
This commit is contained in:
aj committed 2026-10-04 23:50:58 -04:00
1 parent 9c530ca7d2
commit f3bca26fb9
2 files changed
+34 -24

No files matched your search

@@ -0,0 +1,31 @@
using OpenNest.Geometry;
using OpenNest.Math;
namespace OpenNest.Engine.CuttingPlanning;
/// <summary>Whole-part cutting prerequisites shared by automatic sequencing and cutting planning.</summary>
internal static class CuttingDependencyGraph
{
/// <summary>
/// Whether a cutoff's nominal line crosses a part's bounds within the cutoff's span. Uses the
/// nominal line, not its trimmed cutting segments (which deliberately skip the parts). Bounds
/// conservatively include edge contacts and concave recesses; limits prevent unrelated
/// dependencies beyond the cutoff's span. Negative coordinates need no special case.
/// </summary>
internal static bool CutOffCrosses(CutOffAxis axis, Vector cutOffPosition, double? startLimit,
double? endLimit, Box part, Box plate)
{
var vertical = axis == CutOffAxis.Vertical;
var position = vertical ? cutOffPosition.X : cutOffPosition.Y;
var acrossMin = vertical ? part.Left : part.Bottom;
var acrossMax = vertical ? part.Right : part.Top;
var alongMin = vertical ? part.Bottom : part.Left;
var alongMax = vertical ? part.Top : part.Right;
var start = startLimit ?? (vertical ? plate.Bottom : plate.Left);
var end = endLimit ?? (vertical ? plate.Top : plate.Right);
return !(position < acrossMin - Tolerance.Epsilon
|| position > acrossMax + Tolerance.Epsilon
|| System.Math.Max(start, end) < alongMin - Tolerance.Epsilon
|| System.Math.Min(start, end) > alongMax + Tolerance.Epsilon);
}
}
+3 -24
View File
@@ -1,8 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using OpenNest.CNC.CuttingStrategy;
using OpenNest.Geometry;
using OpenNest.Math;
using OpenNest.Engine.CuttingPlanning;
namespace OpenNest.Engine.Sequencing
{
@@ -60,7 +59,8 @@ namespace OpenNest.Engine.Sequencing
// An orphaned cutoff still must not follow potentially
// crossed parts when its nominal span cannot be recovered.
if (!definitions.TryGetValue(cut.Part.BaseDrawing, out var definition)
|| CrossesBounds(definition, part.BoundingBox, bounds))
|| CuttingDependencyGraph.CutOffCrosses(definition.Axis, definition.Position,
definition.StartLimit, definition.EndLimit, part.BoundingBox, bounds))
{
result.Add(cut.Part);
emitted[cut.Index] = true;
@@ -77,26 +77,5 @@ namespace OpenNest.Engine.Sequencing
return result;
}
private static bool CrossesBounds(CutOff cutOff, Box part, Box plate)
{
var vertical = cutOff.Axis == CutOffAxis.Vertical;
var position = vertical ? cutOff.Position.X : cutOff.Position.Y;
var acrossMin = vertical ? part.Left : part.Bottom;
var acrossMax = vertical ? part.Right : part.Top;
var alongMin = vertical ? part.Bottom : part.Left;
var alongMax = vertical ? part.Top : part.Right;
var start = cutOff.StartLimit ?? (vertical ? plate.Bottom : plate.Left);
var end = cutOff.EndLimit ?? (vertical ? plate.Top : plate.Right);
// Use the nominal line, not its trimmed cutting segments (which
// deliberately skip the parts). Bounds conservatively include edge
// contacts and concave recesses; limits prevent unrelated dependencies
// beyond the cutoff's span. Negative coordinates need no special case.
return !(position < acrossMin - Tolerance.Epsilon
|| position > acrossMax + Tolerance.Epsilon
|| System.Math.Max(start, end) < alongMin - Tolerance.Epsilon
|| System.Math.Min(start, end) > alongMax + Tolerance.Epsilon);
}
}
}