From 24babe353e5385fab570304c437d146af77f7612 Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Fri, 10 Apr 2026 08:37:46 -0400 Subject: [PATCH] fix: show both offset and rotation in SubProgramCall.ToString The either/or format meant a SubProgramCall with both a non-zero Offset and non-zero Rotation would only show the Offset, hiding the rotation metadata. The data model supports both independently, so the display should too. Also fixes a zero-field leak where the old fallback emitted `G65 P_ R0` for calls with no rotation. Now each field is only shown when non-zero, and `G65 P_` with no arguments is emitted when neither is set. Note: SubProgramCall.ToString is purely a debug/display aid. The Cincinnati post emits sub-calls via the G52 + M98 bracket, not via G65, so this format doesn't correspond to real machine output. Co-Authored-By: Claude Opus 4.6 (1M context) --- OpenNest.Core/CNC/SubProgramCall.cs | 11 ++++++++--- .../CuttingStrategy/HoleSubProgramTests.cs | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/OpenNest.Core/CNC/SubProgramCall.cs b/OpenNest.Core/CNC/SubProgramCall.cs index 0c9223a..647ac44 100644 --- a/OpenNest.Core/CNC/SubProgramCall.cs +++ b/OpenNest.Core/CNC/SubProgramCall.cs @@ -1,4 +1,5 @@ -using OpenNest.Geometry; +using System.Text; +using OpenNest.Geometry; using OpenNest.Math; namespace OpenNest.CNC @@ -90,9 +91,13 @@ namespace OpenNest.CNC public override string ToString() { + var sb = new StringBuilder(); + sb.Append($"G65 P{Id}"); if (Offset.X != 0 || Offset.Y != 0) - return string.Format("G65 P{0} X{1} Y{2}", Id, Offset.X, Offset.Y); - return string.Format("G65 P{0} R{1}", Id, Rotation); + sb.Append($" X{Offset.X} Y{Offset.Y}"); + if (Rotation != 0) + sb.Append($" R{Rotation}"); + return sb.ToString(); } } } diff --git a/OpenNest.Tests/CuttingStrategy/HoleSubProgramTests.cs b/OpenNest.Tests/CuttingStrategy/HoleSubProgramTests.cs index 6ade4cd..abeefb7 100644 --- a/OpenNest.Tests/CuttingStrategy/HoleSubProgramTests.cs +++ b/OpenNest.Tests/CuttingStrategy/HoleSubProgramTests.cs @@ -44,6 +44,25 @@ public class HoleSubProgramTests Assert.Contains("Y2.5", str); } + [Fact] + public void SubProgramCall_ToString_IncludesOffsetAndRotation() + { + var call = new SubProgramCall { Id = 1000, Offset = new Vector(1.5, 2.5), Rotation = 30 }; + var str = call.ToString(); + Assert.Contains("P1000", str); + Assert.Contains("X1.5", str); + Assert.Contains("Y2.5", str); + Assert.Contains("R30", str); + } + + [Fact] + public void SubProgramCall_ToString_OmitsZeroFields() + { + var call = new SubProgramCall { Id = 1000 }; + var str = call.ToString(); + Assert.Equal("G65 P1000", str); + } + [Fact] public void Program_SubPrograms_EmptyByDefault() {