diff --git a/OpenNest.WinForms.Tests/Controls/LayoutPartViewCacheTests.cs b/OpenNest.WinForms.Tests/Controls/LayoutPartViewCacheTests.cs index 5d3c3a58..e3ebb750 100644 --- a/OpenNest.WinForms.Tests/Controls/LayoutPartViewCacheTests.cs +++ b/OpenNest.WinForms.Tests/Controls/LayoutPartViewCacheTests.cs @@ -57,6 +57,42 @@ public class LayoutPartViewCacheTests AssertMatchesFreshBuild(layout, view); }, TimeSpan.FromMinutes(1), "Layout part rebuild test timed out."); + [Fact] + public void LabelFollowsAReplacedDrawingProgram() => StaTestThread.Run(() => + { + // Editing a drawing replaces its program, possibly in another frame; the part's sequence + // label must be found again in the new frame, not kept from the old program. + var drawing = new Drawing("Door stop", LShape(Vector.Zero)); + var part = new Part(drawing, new Vector(5, 7)); + using var view = new PlateView(ColorSchemeRegistry.Get("Workshop")); + view.Matrix = new Matrix(2, 0, 0, -2, 0, 0); + var layout = LayoutPart.Create(part, view); + var before = layout.LabelScreenPoint; + + drawing.Program = LShape(new Vector(-10, -5)); + layout.IsDirty = true; + layout.UpdateView(view); + + var fresh = LayoutPart.Create(part, view); + Assert.NotEqual(before, fresh.LabelScreenPoint); + Assert.Equal(fresh.LabelScreenPoint.X, layout.LabelScreenPoint.X, 2); + Assert.Equal(fresh.LabelScreenPoint.Y, layout.LabelScreenPoint.Y, 2); + fresh.ReleaseDisplayResources(); + }, TimeSpan.FromMinutes(1), "Layout part label test timed out."); + + private static Program LShape(Vector origin) + { + var program = new Program(); + program.MoveTo(origin.X, origin.Y); + program.LineTo(origin.X + 10, origin.Y); + program.LineTo(origin.X + 10, origin.Y + 30); + program.LineTo(origin.X + 40, origin.Y + 30); + program.LineTo(origin.X + 40, origin.Y + 40); + program.LineTo(origin.X, origin.Y + 40); + program.LineTo(origin.X, origin.Y); + return program; + } + private static void AssertMatchesFreshBuild(LayoutPart layout, PlateView view) { var fresh = LayoutPart.Create(layout.BasePart, view); diff --git a/OpenNest/LayoutPart.cs b/OpenNest/LayoutPart.cs index 3828614a..119a7c8e 100644 --- a/OpenNest/LayoutPart.cs +++ b/OpenNest/LayoutPart.cs @@ -34,7 +34,11 @@ namespace OpenNest private double _cachedOffsetTolerance; private double _cachedOffsetRotation = double.NaN; + // The label point is in the frame of the drawing program it was computed from; editing a + // drawing replaces that program, so the cache is kept only while the program is the same. private Vector? _labelPoint; + private CNC.Program _labelProgram; + private double _labelProgramRotation; private PointF _labelScreenPoint; internal PointF LabelScreenPoint => _labelScreenPoint; @@ -456,8 +460,16 @@ namespace OpenNest private Vector PlacedLabelPoint() { - _labelPoint ??= ComputeLabelPoint(); - var baseRotation = BasePart.BaseDrawing.Program.Rotation; + var drawingProgram = BasePart.BaseDrawing.Program; + var baseRotation = drawingProgram.Rotation; + if (_labelPoint == null + || !ReferenceEquals(_labelProgram, drawingProgram) + || _labelProgramRotation != baseRotation) + { + _labelPoint = ComputeLabelPoint(); + _labelProgram = drawingProgram; + _labelProgramRotation = baseRotation; + } return _labelPoint.Value.Rotate(BasePart.Rotation - baseRotation) + BasePart.Location; }