feat: add groove depth and weld gap options to spike-groove split

- SpikeParameters: added GrooveDepth (how deep groove cuts into
  receiving part) and SpikeWeldGap (gap between spike tip and groove)
- SpikeGrooveSplit: groove uses its own depth (wider/deeper than spike),
  spike tip stops short by weld gap amount
- UI: added Groove Depth and Weld Gap fields to spike parameters panel
- Changed default pair count to 2 (one near each end)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-24 13:30:39 -04:00
parent 5d93ddb2c4
commit ba7aa39941
4 changed files with 76 additions and 16 deletions
+14 -7
View File
@@ -16,9 +16,12 @@ public class SpikeGrooveSplit : ISplitFeature
{ {
var extent = extentEnd - extentStart; var extent = extentEnd - extentStart;
var pairCount = parameters.SpikePairCount; var pairCount = parameters.SpikePairCount;
var depth = parameters.SpikeDepth; var spikeDepth = parameters.SpikeDepth;
var grooveDepth = parameters.GrooveDepth;
var weldGap = parameters.SpikeWeldGap;
var angleRad = OpenNest.Math.Angle.ToRadians(parameters.SpikeAngle / 2); var angleRad = OpenNest.Math.Angle.ToRadians(parameters.SpikeAngle / 2);
var halfWidth = depth * System.Math.Tan(angleRad); var spikeHalfWidth = spikeDepth * System.Math.Tan(angleRad);
var grooveHalfWidth = grooveDepth * System.Math.Tan(angleRad);
var isVertical = line.Axis == CutOffAxis.Vertical; var isVertical = line.Axis == CutOffAxis.Vertical;
var pos = line.Position; var pos = line.Position;
@@ -37,8 +40,10 @@ public class SpikeGrooveSplit : ISplitFeature
pairPositions.Add(extentStart + margin + usable * i / (pairCount - 1)); pairPositions.Add(extentStart + margin + usable * i / (pairCount - 1));
} }
var negEntities = BuildGrooveSide(pairPositions, halfWidth, depth, extentStart, extentEnd, pos, isVertical); // Groove side: V-groove cut deeper than the spike so the spike fits inside
var posEntities = BuildSpikeSide(pairPositions, halfWidth, depth, extentStart, extentEnd, pos, isVertical); var negEntities = BuildGrooveSide(pairPositions, grooveHalfWidth, grooveDepth, extentStart, extentEnd, pos, isVertical);
// Spike side: spike protrudes but stops short of the split line by weldGap
var posEntities = BuildSpikeSide(pairPositions, spikeHalfWidth, spikeDepth, weldGap, extentStart, extentEnd, pos, isVertical);
return new SplitFeatureResult(negEntities, posEntities); return new SplitFeatureResult(negEntities, posEntities);
} }
@@ -70,8 +75,10 @@ public class SpikeGrooveSplit : ISplitFeature
} }
private static List<Entity> BuildSpikeSide(List<double> pairPositions, double halfWidth, double depth, private static List<Entity> BuildSpikeSide(List<double> pairPositions, double halfWidth, double depth,
double extentStart, double extentEnd, double pos, bool isVertical) double weldGap, double extentStart, double extentEnd, double pos, bool isVertical)
{ {
// Spike tip stops short of the split line by weldGap
var tipDepth = depth - weldGap;
var entities = new List<Entity>(); var entities = new List<Entity>();
var cursor = extentEnd; var cursor = extentEnd;
@@ -84,8 +91,8 @@ public class SpikeGrooveSplit : ISplitFeature
if (cursor > spikeEnd + OpenNest.Math.Tolerance.Epsilon) if (cursor > spikeEnd + OpenNest.Math.Tolerance.Epsilon)
entities.Add(MakeLine(pos, cursor, pos, spikeEnd, isVertical)); entities.Add(MakeLine(pos, cursor, pos, spikeEnd, isVertical));
entities.Add(MakeLine(pos, spikeEnd, pos - depth, center, isVertical)); entities.Add(MakeLine(pos, spikeEnd, pos - tipDepth, center, isVertical));
entities.Add(MakeLine(pos - depth, center, pos, spikeStart, isVertical)); entities.Add(MakeLine(pos - tipDepth, center, pos, spikeStart, isVertical));
cursor = spikeStart; cursor = spikeStart;
} }
+3 -1
View File
@@ -18,6 +18,8 @@ public class SplitParameters
// Spike/Groove parameters // Spike/Groove parameters
public double SpikeDepth { get; set; } = 0.5; public double SpikeDepth { get; set; } = 0.5;
public double GrooveDepth { get; set; } = 0.625;
public double SpikeWeldGap { get; set; } = 0.125;
public double SpikeAngle { get; set; } = 60.0; // degrees public double SpikeAngle { get; set; } = 60.0; // degrees
public int SpikePairCount { get; set; } = 2; public int SpikePairCount { get; set; } = 2;
@@ -27,7 +29,7 @@ public class SplitParameters
public double FeatureOverhang => Type switch public double FeatureOverhang => Type switch
{ {
SplitType.WeldGapTabs => TabHeight, SplitType.WeldGapTabs => TabHeight,
SplitType.SpikeGroove => SpikeDepth, SplitType.SpikeGroove => System.Math.Max(SpikeDepth, GrooveDepth),
_ => 0 _ => 0
}; };
} }
+57 -8
View File
@@ -84,6 +84,10 @@ namespace OpenNest.Forms
this.nudSpikeAngle = new System.Windows.Forms.NumericUpDown(); this.nudSpikeAngle = new System.Windows.Forms.NumericUpDown();
this.lblSpikePairCount = new System.Windows.Forms.Label(); this.lblSpikePairCount = new System.Windows.Forms.Label();
this.nudSpikePairCount = new System.Windows.Forms.NumericUpDown(); this.nudSpikePairCount = new System.Windows.Forms.NumericUpDown();
this.lblGrooveDepth = new System.Windows.Forms.Label();
this.nudGrooveDepth = new System.Windows.Forms.NumericUpDown();
this.lblSpikeWeldGap = new System.Windows.Forms.Label();
this.nudSpikeWeldGap = new System.Windows.Forms.NumericUpDown();
// OK/Cancel buttons // OK/Cancel buttons
this.btnOK = new System.Windows.Forms.Button(); this.btnOK = new System.Windows.Forms.Button();
@@ -101,6 +105,8 @@ namespace OpenNest.Forms
((System.ComponentModel.ISupportInitialize)(this.nudSpikeDepth)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.nudSpikeDepth)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.nudSpikeAngle)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.nudSpikeAngle)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.nudSpikePairCount)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.nudSpikePairCount)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.nudGrooveDepth)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.nudSpikeWeldGap)).BeginInit();
this.pnlSettings.SuspendLayout(); this.pnlSettings.SuspendLayout();
this.grpMethod.SuspendLayout(); this.grpMethod.SuspendLayout();
this.grpAutoFit.SuspendLayout(); this.grpAutoFit.SuspendLayout();
@@ -464,13 +470,17 @@ namespace OpenNest.Forms
this.grpSpikeParams.Dock = System.Windows.Forms.DockStyle.Top; this.grpSpikeParams.Dock = System.Windows.Forms.DockStyle.Top;
this.grpSpikeParams.Location = new System.Drawing.Point(6, 484); this.grpSpikeParams.Location = new System.Drawing.Point(6, 484);
this.grpSpikeParams.Name = "grpSpikeParams"; this.grpSpikeParams.Name = "grpSpikeParams";
this.grpSpikeParams.Size = new System.Drawing.Size(208, 105); this.grpSpikeParams.Size = new System.Drawing.Size(208, 159);
this.grpSpikeParams.TabIndex = 5; this.grpSpikeParams.TabIndex = 5;
this.grpSpikeParams.TabStop = false; this.grpSpikeParams.TabStop = false;
this.grpSpikeParams.Text = "Spike Parameters"; this.grpSpikeParams.Text = "Spike Parameters";
this.grpSpikeParams.Visible = false; this.grpSpikeParams.Visible = false;
this.grpSpikeParams.Controls.Add(this.nudSpikePairCount); this.grpSpikeParams.Controls.Add(this.nudSpikePairCount);
this.grpSpikeParams.Controls.Add(this.lblSpikePairCount); this.grpSpikeParams.Controls.Add(this.lblSpikePairCount);
this.grpSpikeParams.Controls.Add(this.nudSpikeWeldGap);
this.grpSpikeParams.Controls.Add(this.lblSpikeWeldGap);
this.grpSpikeParams.Controls.Add(this.nudGrooveDepth);
this.grpSpikeParams.Controls.Add(this.lblGrooveDepth);
this.grpSpikeParams.Controls.Add(this.nudSpikeAngle); this.grpSpikeParams.Controls.Add(this.nudSpikeAngle);
this.grpSpikeParams.Controls.Add(this.lblSpikeAngle); this.grpSpikeParams.Controls.Add(this.lblSpikeAngle);
this.grpSpikeParams.Controls.Add(this.nudSpikeDepth); this.grpSpikeParams.Controls.Add(this.nudSpikeDepth);
@@ -493,38 +503,71 @@ namespace OpenNest.Forms
this.nudSpikeDepth.TabIndex = 0; this.nudSpikeDepth.TabIndex = 0;
this.nudSpikeDepth.Value = new decimal(new int[] { 5, 0, 0, 65536 }); this.nudSpikeDepth.Value = new decimal(new int[] { 5, 0, 0, 65536 });
// lblGrooveDepth
this.lblGrooveDepth.AutoSize = true;
this.lblGrooveDepth.Location = new System.Drawing.Point(10, 49);
this.lblGrooveDepth.Name = "lblGrooveDepth";
this.lblGrooveDepth.Size = new System.Drawing.Size(84, 15);
this.lblGrooveDepth.Text = "Groove Depth:";
// nudGrooveDepth
this.nudGrooveDepth.DecimalPlaces = 3;
this.nudGrooveDepth.Location = new System.Drawing.Point(110, 47);
this.nudGrooveDepth.Maximum = new decimal(new int[] { 100, 0, 0, 0 });
this.nudGrooveDepth.Minimum = new decimal(new int[] { 1, 0, 0, 131072 });
this.nudGrooveDepth.Name = "nudGrooveDepth";
this.nudGrooveDepth.Size = new System.Drawing.Size(88, 23);
this.nudGrooveDepth.TabIndex = 1;
this.nudGrooveDepth.Value = new decimal(new int[] { 625, 0, 0, 196608 });
// lblSpikeWeldGap
this.lblSpikeWeldGap.AutoSize = true;
this.lblSpikeWeldGap.Location = new System.Drawing.Point(10, 76);
this.lblSpikeWeldGap.Name = "lblSpikeWeldGap";
this.lblSpikeWeldGap.Size = new System.Drawing.Size(64, 15);
this.lblSpikeWeldGap.Text = "Weld Gap:";
// nudSpikeWeldGap
this.nudSpikeWeldGap.DecimalPlaces = 3;
this.nudSpikeWeldGap.Location = new System.Drawing.Point(110, 74);
this.nudSpikeWeldGap.Maximum = new decimal(new int[] { 10, 0, 0, 0 });
this.nudSpikeWeldGap.Name = "nudSpikeWeldGap";
this.nudSpikeWeldGap.Size = new System.Drawing.Size(88, 23);
this.nudSpikeWeldGap.TabIndex = 2;
this.nudSpikeWeldGap.Value = new decimal(new int[] { 125, 0, 0, 196608 });
// lblSpikeAngle // lblSpikeAngle
this.lblSpikeAngle.AutoSize = true; this.lblSpikeAngle.AutoSize = true;
this.lblSpikeAngle.Location = new System.Drawing.Point(10, 49); this.lblSpikeAngle.Location = new System.Drawing.Point(10, 103);
this.lblSpikeAngle.Name = "lblSpikeAngle"; this.lblSpikeAngle.Name = "lblSpikeAngle";
this.lblSpikeAngle.Size = new System.Drawing.Size(74, 15); this.lblSpikeAngle.Size = new System.Drawing.Size(74, 15);
this.lblSpikeAngle.Text = "Spike Angle:"; this.lblSpikeAngle.Text = "Spike Angle:";
// nudSpikeAngle // nudSpikeAngle
this.nudSpikeAngle.DecimalPlaces = 1; this.nudSpikeAngle.DecimalPlaces = 1;
this.nudSpikeAngle.Location = new System.Drawing.Point(110, 47); this.nudSpikeAngle.Location = new System.Drawing.Point(110, 101);
this.nudSpikeAngle.Maximum = new decimal(new int[] { 89, 0, 0, 0 }); this.nudSpikeAngle.Maximum = new decimal(new int[] { 89, 0, 0, 0 });
this.nudSpikeAngle.Minimum = new decimal(new int[] { 10, 0, 0, 0 }); this.nudSpikeAngle.Minimum = new decimal(new int[] { 10, 0, 0, 0 });
this.nudSpikeAngle.Name = "nudSpikeAngle"; this.nudSpikeAngle.Name = "nudSpikeAngle";
this.nudSpikeAngle.Size = new System.Drawing.Size(88, 23); this.nudSpikeAngle.Size = new System.Drawing.Size(88, 23);
this.nudSpikeAngle.TabIndex = 1; this.nudSpikeAngle.TabIndex = 3;
this.nudSpikeAngle.Value = new decimal(new int[] { 45, 0, 0, 0 }); this.nudSpikeAngle.Value = new decimal(new int[] { 45, 0, 0, 0 });
// lblSpikePairCount // lblSpikePairCount
this.lblSpikePairCount.AutoSize = true; this.lblSpikePairCount.AutoSize = true;
this.lblSpikePairCount.Location = new System.Drawing.Point(10, 76); this.lblSpikePairCount.Location = new System.Drawing.Point(10, 130);
this.lblSpikePairCount.Name = "lblSpikePairCount"; this.lblSpikePairCount.Name = "lblSpikePairCount";
this.lblSpikePairCount.Size = new System.Drawing.Size(65, 15); this.lblSpikePairCount.Size = new System.Drawing.Size(65, 15);
this.lblSpikePairCount.Text = "Pair Count:"; this.lblSpikePairCount.Text = "Pair Count:";
// nudSpikePairCount // nudSpikePairCount
this.nudSpikePairCount.Location = new System.Drawing.Point(110, 74); this.nudSpikePairCount.Location = new System.Drawing.Point(110, 128);
this.nudSpikePairCount.Maximum = new decimal(new int[] { 50, 0, 0, 0 }); this.nudSpikePairCount.Maximum = new decimal(new int[] { 50, 0, 0, 0 });
this.nudSpikePairCount.Minimum = new decimal(new int[] { 1, 0, 0, 0 }); this.nudSpikePairCount.Minimum = new decimal(new int[] { 1, 0, 0, 0 });
this.nudSpikePairCount.Name = "nudSpikePairCount"; this.nudSpikePairCount.Name = "nudSpikePairCount";
this.nudSpikePairCount.Size = new System.Drawing.Size(88, 23); this.nudSpikePairCount.Size = new System.Drawing.Size(88, 23);
this.nudSpikePairCount.TabIndex = 2; this.nudSpikePairCount.TabIndex = 4;
this.nudSpikePairCount.Value = new decimal(new int[] { 3, 0, 0, 0 }); this.nudSpikePairCount.Value = new decimal(new int[] { 2, 0, 0, 0 });
// ---- OK / Cancel Buttons ---- // ---- OK / Cancel Buttons ----
this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
@@ -584,6 +627,8 @@ namespace OpenNest.Forms
((System.ComponentModel.ISupportInitialize)(this.nudSpikeDepth)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.nudSpikeDepth)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.nudSpikeAngle)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.nudSpikeAngle)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.nudSpikePairCount)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.nudSpikePairCount)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.nudGrooveDepth)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.nudSpikeWeldGap)).EndInit();
this.pnlSettings.ResumeLayout(false); this.pnlSettings.ResumeLayout(false);
this.grpMethod.ResumeLayout(false); this.grpMethod.ResumeLayout(false);
this.grpMethod.PerformLayout(); this.grpMethod.PerformLayout();
@@ -657,6 +702,10 @@ namespace OpenNest.Forms
private System.Windows.Forms.NumericUpDown nudSpikeAngle; private System.Windows.Forms.NumericUpDown nudSpikeAngle;
private System.Windows.Forms.Label lblSpikePairCount; private System.Windows.Forms.Label lblSpikePairCount;
private System.Windows.Forms.NumericUpDown nudSpikePairCount; private System.Windows.Forms.NumericUpDown nudSpikePairCount;
private System.Windows.Forms.Label lblGrooveDepth;
private System.Windows.Forms.NumericUpDown nudGrooveDepth;
private System.Windows.Forms.Label lblSpikeWeldGap;
private System.Windows.Forms.NumericUpDown nudSpikeWeldGap;
private System.Windows.Forms.Button btnOK; private System.Windows.Forms.Button btnOK;
private System.Windows.Forms.Button btnCancel; private System.Windows.Forms.Button btnCancel;
+2
View File
@@ -153,6 +153,8 @@ public partial class SplitDrawingForm : Form
{ {
p.Type = SplitType.SpikeGroove; p.Type = SplitType.SpikeGroove;
p.SpikeDepth = (double)nudSpikeDepth.Value; p.SpikeDepth = (double)nudSpikeDepth.Value;
p.GrooveDepth = (double)nudGrooveDepth.Value;
p.SpikeWeldGap = (double)nudSpikeWeldGap.Value;
p.SpikeAngle = (double)nudSpikeAngle.Value; p.SpikeAngle = (double)nudSpikeAngle.Value;
p.SpikePairCount = (int)nudSpikePairCount.Value; p.SpikePairCount = (int)nudSpikePairCount.Value;
} }