diff --git a/OpenNest.Engine/CuttingPlanning/CuttingDependencyGraph.cs b/OpenNest.Engine/CuttingPlanning/CuttingDependencyGraph.cs new file mode 100644 index 0000000..3d14d0f --- /dev/null +++ b/OpenNest.Engine/CuttingPlanning/CuttingDependencyGraph.cs @@ -0,0 +1,31 @@ +using OpenNest.Geometry; +using OpenNest.Math; + +namespace OpenNest.Engine.CuttingPlanning; + +/// Whole-part cutting prerequisites shared by automatic sequencing and cutting planning. +internal static class CuttingDependencyGraph +{ + /// + /// 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. + /// + 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); + } +} diff --git a/OpenNest.Engine/Sequencing/PlateSequencing.cs b/OpenNest.Engine/Sequencing/PlateSequencing.cs index 25f2880..2e9b99f 100644 --- a/OpenNest.Engine/Sequencing/PlateSequencing.cs +++ b/OpenNest.Engine/Sequencing/PlateSequencing.cs @@ -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); - } } }