diff --git a/OpenNest.Engine.Tests/Jobs/ClampZoneCommitTests.cs b/OpenNest.Engine.Tests/Jobs/ClampZoneCommitTests.cs index db1e8d0..867eb5c 100644 --- a/OpenNest.Engine.Tests/Jobs/ClampZoneCommitTests.cs +++ b/OpenNest.Engine.Tests/Jobs/ClampZoneCommitTests.cs @@ -93,6 +93,66 @@ public class ClampZoneCommitTests Assert.Equal(0, changes); } + [Theory] + [InlineData(1)] + [InlineData(2)] + [InlineData(3)] + [InlineData(4)] + public void SolvedZonesARailCannotRecreateStopFollowingThatRail(int quadrant) + { + // The nest rail puts a clamp at 6"; the template carries a different explicit zone, + // so the extra sheet the commit creates must not keep following the nest rail. + var drawing = new Drawing("part", TestDrawingFactory.Rectangle()); + var nest = new Nest(); + nest.Drawings.Add(drawing); + nest.PlateDefaults.Size = new Size(48, 96); + nest.PlateDefaults.Quadrant = quadrant; + nest.SetClampRail(new ClampRail(1.5, 0.625, new[] { 6.0 })); + var template = nest.CreatePlate(); + template.SetClampRail(null!); + var manual = new ClampZone("manual", new Box(10, 0, 2, 0.5)); + template.ClampZones.Add(manual); + using var manager = new PlateManager(nest); + + var applied = NestPipelineCommit.ApplyToEmptyPlates( + Result(drawing, quadrant, template.ClampZones.ToArray()), manager); + + Assert.Equal(2, applied.Count); + Assert.All(applied, plate => + { + Assert.Null(plate.ClampRail); + plate.Size = plate.Size; // the Edit Plate dialog assigns Size even when unchanged + plate.Quadrant = plate.Quadrant; + Assert.Equal("manual", Assert.Single(plate.ClampZones).Id); + Assert.Equal("manual", Assert.Single(Assert.Single( + NestStockBuilder.FromTemplate(plate, [new PlateOption { Width = 48, Length = 96 }])).ClampZones).Id); + }); + } + + [Fact] + public void SolvedZonesTheRailRecreatesKeepFollowingIt() + { + var drawing = new Drawing("part", TestDrawingFactory.Rectangle()); + var nest = new Nest(); + nest.Drawings.Add(drawing); + nest.PlateDefaults.Size = new Size(48, 96); + var rail = new ClampRail(1.5, 0.625, new[] { 6.0 }); + nest.SetClampRail(rail); + var template = nest.CreatePlate(); + using var manager = new PlateManager(nest); + + var applied = NestPipelineCommit.ApplyToEmptyPlates( + Result(drawing, 1, template.ClampZones.ToArray()), manager); + + Assert.Equal(2, applied.Count); + Assert.All(applied, plate => + { + Assert.Same(rail, plate.ClampRail); + plate.Size = new Size(48, 4); + Assert.Empty(plate.ClampZones); // still re-resolves: no clamp reaches a 4" sheet + }); + } + [Fact] public void ZonesTheLayoutWasNotSolvedWithAreRemoved() { diff --git a/OpenNest.Engine/Jobs/NestPipelineCommit.cs b/OpenNest.Engine/Jobs/NestPipelineCommit.cs index fbfc476..85a1ae7 100644 --- a/OpenNest.Engine/Jobs/NestPipelineCommit.cs +++ b/OpenNest.Engine/Jobs/NestPipelineCommit.cs @@ -58,7 +58,9 @@ public static class NestPipelineCommit /// The live plate keeps exactly the clamp keep-outs its layout was solved and validated /// against, including sheets created for this commit. Stock zones live in the placement /// frame; plate zones in plate coordinates, so the stock's translation is inverted. Zones - /// already equal in the placement frame are left untouched (no change events). + /// already equal in the placement frame are left untouched (no change events). Replaced + /// zones stay tied to the plate's clamp rail only when that rail recreates them; + /// otherwise a later size or quadrant assignment would silently swap in other clamps. /// private static void SyncClampZones(Plate plate, NestPlateStock stock) { @@ -67,9 +69,12 @@ public static class NestPipelineCommit if (SameInPlacementFrame(plate.ClampZones, stock.ClampZones, left, bottom)) return; - plate.ClampZones.Clear(); + var rail = plate.ClampRail; + plate.SetClampRail(null); // explicit zones from here on foreach (var zone in stock.ClampZones) plate.ClampZones.Add(new ClampZone(zone.Id, zone.Bounds.Translate(-left, -bottom))); + if (rail != null && rail.Matches(plate)) + plate.SetClampRail(rail); } private static bool SameInPlacementFrame(