From c270d8ea763d8cf3088bb49e4a184eb7324a616e Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Thu, 9 Apr 2026 14:26:55 -0400 Subject: [PATCH] feat: add Offset property to SubProgramCall for hole positioning Co-Authored-By: Claude Sonnet 4.6 --- OpenNest.Core/CNC/SubProgramCall.cs | 13 +++++- .../CuttingStrategy/HoleSubProgramTests.cs | 43 +++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 OpenNest.Tests/CuttingStrategy/HoleSubProgramTests.cs diff --git a/OpenNest.Core/CNC/SubProgramCall.cs b/OpenNest.Core/CNC/SubProgramCall.cs index 07246f1..0c9223a 100644 --- a/OpenNest.Core/CNC/SubProgramCall.cs +++ b/OpenNest.Core/CNC/SubProgramCall.cs @@ -1,4 +1,5 @@ -using OpenNest.Math; +using OpenNest.Geometry; +using OpenNest.Math; namespace OpenNest.CNC { @@ -35,6 +36,12 @@ namespace OpenNest.CNC } } + /// + /// Gets or sets the offset (position) at which the sub-program is executed. + /// For hole sub-programs, this is the hole center. + /// + public Vector Offset { get; set; } + /// /// Gets or sets the rotation of the program in degrees. /// @@ -78,11 +85,13 @@ namespace OpenNest.CNC /// public ICode Clone() { - return new SubProgramCall(program, Rotation); + return new SubProgramCall(program, Rotation) { Id = Id, Offset = Offset }; } public override string ToString() { + 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); } } diff --git a/OpenNest.Tests/CuttingStrategy/HoleSubProgramTests.cs b/OpenNest.Tests/CuttingStrategy/HoleSubProgramTests.cs new file mode 100644 index 0000000..dadc3c1 --- /dev/null +++ b/OpenNest.Tests/CuttingStrategy/HoleSubProgramTests.cs @@ -0,0 +1,43 @@ +using OpenNest.CNC; +using OpenNest.Geometry; + +namespace OpenNest.Tests.CuttingStrategy; + +public class HoleSubProgramTests +{ + [Fact] + public void SubProgramCall_Offset_DefaultsToZero() + { + var call = new SubProgramCall(); + Assert.Equal(0, call.Offset.X); + Assert.Equal(0, call.Offset.Y); + } + + [Fact] + public void SubProgramCall_Offset_StoresValue() + { + var call = new SubProgramCall { Offset = new Vector(1.5, 2.5) }; + Assert.Equal(1.5, call.Offset.X); + Assert.Equal(2.5, call.Offset.Y); + } + + [Fact] + public void SubProgramCall_Clone_CopiesOffset() + { + var call = new SubProgramCall { Id = 1, Offset = new Vector(3, 4) }; + var clone = (SubProgramCall)call.Clone(); + Assert.Equal(3, clone.Offset.X); + Assert.Equal(4, clone.Offset.Y); + Assert.Equal(1, clone.Id); + } + + [Fact] + public void SubProgramCall_ToString_IncludesOffset() + { + var call = new SubProgramCall { Id = 1000, Offset = new Vector(1.5, 2.5) }; + var str = call.ToString(); + Assert.Contains("P1000", str); + Assert.Contains("X1.5", str); + Assert.Contains("Y2.5", str); + } +}