diff --git a/OpenNest.Core/Diagnostics/OverlapGeometryStamp.cs b/OpenNest.Core/Diagnostics/OverlapGeometryStamp.cs index 54fff1d..ceae55b 100644 --- a/OpenNest.Core/Diagnostics/OverlapGeometryStamp.cs +++ b/OpenNest.Core/Diagnostics/OverlapGeometryStamp.cs @@ -24,20 +24,23 @@ public sealed class OverlapGeometryStamp entries[i] = new Entry(plate.Parts[i]); zones = new (string, long, long, long, long)[plate.ClampZones.Count]; for (var i = 0; i < zones.Length; i++) - { - var zone = plate.ClampZones[i]; - var box = zone.Bounds; - zones[i] = (zone.Id, Bits(box.X), Bits(box.Y), Bits(box.Length), Bits(box.Width)); - } + zones[i] = ZoneState(plate.ClampZones[i]); cutoffs = new (CutOff, CutOffAxis, long, long, long?, long?)[plate.CutOffs.Count]; for (var i = 0; i < cutoffs.Length; i++) cutoffs[i] = CutOffState(plate.CutOffs[i]); } + // Missing entries are malformed input the analysis itself reports; freshness must not + // throw first (the desktop captures it before its error boundary). + private static (string, long, long, long, long) ZoneState(ClampZone zone) => + zone?.Bounds is not { } box ? default + : (zone.Id, Bits(box.X), Bits(box.Y), Bits(box.Length), Bits(box.Width)); + private static (CutOff, CutOffAxis, long, long, long?, long?) CutOffState(CutOff cut) => - (cut, cut.Axis, Bits(cut.Position.X), Bits(cut.Position.Y), - cut.StartLimit.HasValue ? Bits(cut.StartLimit.Value) : null, - cut.EndLimit.HasValue ? Bits(cut.EndLimit.Value) : null); + cut == null ? default + : (cut, cut.Axis, Bits(cut.Position.X), Bits(cut.Position.Y), + cut.StartLimit.HasValue ? Bits(cut.StartLimit.Value) : null, + cut.EndLimit.HasValue ? Bits(cut.EndLimit.Value) : null); private static long Bits(double value) => BitConverter.DoubleToInt64Bits(value); @@ -54,12 +57,8 @@ public sealed class OverlapGeometryStamp || sheet != SheetState(current)) return false; for (var i = 0; i < zones.Length; i++) - { - var zone = current.ClampZones[i]; - var box = zone.Bounds; - if (zones[i] != (zone.Id, Bits(box.X), Bits(box.Y), Bits(box.Length), Bits(box.Width))) + if (zones[i] != ZoneState(current.ClampZones[i])) return false; - } return true; } diff --git a/OpenNest.Tests/Diagnostics/ClampZonePlacementFrameTests.cs b/OpenNest.Tests/Diagnostics/ClampZonePlacementFrameTests.cs index 83e0fb7..face1a7 100644 --- a/OpenNest.Tests/Diagnostics/ClampZonePlacementFrameTests.cs +++ b/OpenNest.Tests/Diagnostics/ClampZonePlacementFrameTests.cs @@ -273,6 +273,31 @@ public class ClampZonePlacementFrameTests Assert.Throws(() => PlateOverlapAnalyzer.CapturePlate(plate)); } + [Fact] + public void FreshnessCaptureToleratesMissingCutOffsAndZones() + { + var plate = new Plate(24, 48); + plate.CutOffs.Add(null!); + plate.ClampZones.Add(null!); + + var stamp = OverlapGeometryStamp.Capture(plate); + var state = new OverlapReportState(); + state.Begin(plate); + + Assert.True(stamp.Matches(plate)); + // The whole-plate capture refuses the malformed input inside the desktop's error boundary. + Assert.Throws(() => PlateOverlapAnalyzer.CapturePlate(plate)); + plate.CutOffs.Clear(); + plate.CutOffs.Add(new CutOff(new Vector(5, 0), CutOffAxis.Vertical)); + Assert.False(stamp.Matches(plate)); + plate.CutOffs.Clear(); + plate.CutOffs.Add(null!); + Assert.True(stamp.Matches(plate)); + plate.ClampZones.Clear(); + plate.ClampZones.Add(new ClampZone("front", new Box(10, 0, 1.5, 0.625))); + Assert.False(stamp.Matches(plate)); + } + [Fact] public void QuadrantChangeMovesExplicitZonesAndStalesDisplayedClampFindings() {