diff --git a/OpenNest.WinForms.Tests/Controls/BendLinePlacementTests.cs b/OpenNest.WinForms.Tests/Controls/BendLinePlacementTests.cs new file mode 100644 index 00000000..a1f088cc --- /dev/null +++ b/OpenNest.WinForms.Tests/Controls/BendLinePlacementTests.cs @@ -0,0 +1,40 @@ +using OpenNest.Bending; +using OpenNest.Controls; +using OpenNest.Geometry; +using OpenNest.Math; + +namespace OpenNest.WinForms.Tests.Controls; + +/// +/// Bends are kept in the drawing's source frame while its program starts at the origin, so a +/// placed part draws them with Source.Offset removed. +/// +public class BendLinePlacementTests +{ + [Fact] + public void BendToWorld_RemovesSourceOffsetBeforePlacing() + { + var drawing = new Drawing("bent", new CNC.Program()); + drawing.Source.Offset = new Vector(100, 50); + // In the source frame the bend runs across the part at local x = 5. + var bend = new Bend { StartPoint = new Vector(105, 50), EndPoint = new Vector(105, 60) }; + var part = new Part(drawing, new Vector(10, 20)); + + Assert.Equal(new Vector(15, 20), PlateRenderer.BendToWorld(part, bend.StartPoint)); + Assert.Equal(new Vector(15, 30), PlateRenderer.BendToWorld(part, bend.EndPoint)); + } + + [Fact] + public void BendToWorld_RotatesAboutTheProgramOrigin() + { + var drawing = new Drawing("bent", new CNC.Program()); + drawing.Source.Offset = new Vector(100, 50); + var part = new Part(drawing, new Vector(10, 20)); + part.Rotate(Angle.HalfPI, part.Location); + + var world = PlateRenderer.BendToWorld(part, new Vector(105, 50)); + + Assert.Equal(10, world.X, 9); + Assert.Equal(25, world.Y, 9); + } +} diff --git a/OpenNest/Controls/PlateRenderer.cs b/OpenNest/Controls/PlateRenderer.cs index bed86480..e80781c7 100644 --- a/OpenNest/Controls/PlateRenderer.cs +++ b/OpenNest/Controls/PlateRenderer.cs @@ -465,25 +465,25 @@ namespace OpenNest.Controls foreach (var bend in part.BaseDrawing.Bends) { - var start = bend.StartPoint; - var end = bend.EndPoint; - - if (part.Rotation != 0) - { - start = start.Rotate(part.Rotation); - end = end.Rotate(part.Rotation); - } - - start = start + part.Location; - end = end + part.Location; - - var pt1 = view.PointWorldToGraph(start); - var pt2 = view.PointWorldToGraph(end); + var pt1 = view.PointWorldToGraph(BendToWorld(part, bend.StartPoint)); + var pt2 = view.PointWorldToGraph(BendToWorld(part, bend.EndPoint)); g.DrawLine(bendPen, pt1, pt2); } } + /// + /// Maps a bend point to world space. Bends stay in the drawing's source frame while the + /// program is moved by -Source.Offset, so the offset comes off before placing. + /// + internal static Vector BendToWorld(Part part, Vector point) + { + var local = point - part.BaseDrawing.Source.Offset; + if (part.Rotation != 0) + local = local.Rotate(part.Rotation); + return local + part.Location; + } + private void DrawEtchMarks(Graphics g, Part part, bool muted) { if ( @@ -501,17 +501,8 @@ namespace OpenNest.Controls if (bend.Direction != BendDirection.Up) continue; - var start = bend.StartPoint; - var end = bend.EndPoint; - - if (part.Rotation != 0) - { - start = start.Rotate(part.Rotation); - end = end.Rotate(part.Rotation); - } - - start = start + part.Location; - end = end + part.Location; + var start = BendToWorld(part, bend.StartPoint); + var end = BendToWorld(part, bend.EndPoint); var length = bend.Length; var angle = bend.StartPoint.AngleTo(bend.EndPoint) + part.Rotation;