fix(cutting): restrict tabs to external perimeter and clarify tab UI

Tabs were being applied to internal cutouts and circle holes, which is
incorrect — only the external perimeter should be tabbed. Restructured
the Tabs panel to use radio buttons ("Tab all parts" vs "Auto-tab by
smallest dimension") so the two modes are clearly mutually exclusive
instead of the confusing implicit override behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-16 08:55:30 -04:00
parent bd48f57ce0
commit 7c3246c6e7
2 changed files with 58 additions and 22 deletions
@@ -305,9 +305,6 @@ namespace OpenNest.CNC.CuttingStrategy
subPgm.Codes.AddRange(leadIn.Generate(relativePoint, normal, winding));
var reindexed = relativeShape.ReindexAt(relativePoint, relativeCircle);
if (Parameters.TabsEnabled && Parameters.TabConfig != null)
reindexed = TrimShapeForTab(reindexed, relativePoint, Parameters.TabConfig.Size);
subPgm.Codes.AddRange(ConvertShapeToMoves(reindexed, relativePoint));
subPgm.Codes.AddRange(leadOut.Generate(relativePoint, normal, winding));
subPgm.Mode = Mode.Incremental;
@@ -331,7 +328,7 @@ namespace OpenNest.CNC.CuttingStrategy
var reindexedShape = shape.ReindexAt(point, entity);
if (Parameters.TabsEnabled && Parameters.TabConfig != null)
if (Parameters.TabsEnabled && Parameters.TabConfig != null && contourType == ContourType.External)
reindexedShape = TrimShapeForTab(reindexedShape, point, Parameters.TabConfig.Size);
program.Codes.AddRange(ConvertShapeToMoves(reindexedShape, point));
+57 -18
View File
@@ -24,6 +24,8 @@ namespace OpenNest.Controls
private readonly CheckBox chkTabsEnabled;
private readonly NumericUpDown nudTabWidth;
private readonly RadioButton rbTabAll;
private readonly RadioButton rbAutoTab;
private readonly NumericUpDown nudAutoTabMin;
private readonly NumericUpDown nudAutoTabMax;
private readonly NumericUpDown nudPierceClearance;
@@ -112,7 +114,7 @@ namespace OpenNest.Controls
{
HeaderText = "Tabs",
Dock = DockStyle.Top,
ExpandedHeight = 120,
ExpandedHeight = 160,
IsExpanded = false
};
@@ -122,44 +124,78 @@ namespace OpenNest.Controls
Location = new Point(12, 4),
AutoSize = true
};
chkTabsEnabled.CheckedChanged += (s, e) =>
{
nudTabWidth.Enabled = chkTabsEnabled.Checked;
OnParametersChanged();
};
tabsPanel.ContentPanel.Controls.Add(chkTabsEnabled);
tabsPanel.ContentPanel.Controls.Add(new Label
{
Text = "Width:",
Text = "Tab Size:",
Location = new Point(160, 6),
AutoSize = true
});
nudTabWidth = CreateNumeric(215, 3, 0.25, 0.0625);
nudTabWidth = CreateNumeric(225, 3, 0.25, 0.0625);
nudTabWidth.Enabled = false;
tabsPanel.ContentPanel.Controls.Add(nudTabWidth);
rbTabAll = new RadioButton
{
Text = "Tab all parts",
Location = new Point(28, 28),
AutoSize = true,
Enabled = false,
Checked = true
};
tabsPanel.ContentPanel.Controls.Add(rbTabAll);
rbAutoTab = new RadioButton
{
Text = "Auto-tab when smallest part dimension is between:",
Location = new Point(28, 50),
AutoSize = true,
Enabled = false
};
tabsPanel.ContentPanel.Controls.Add(rbAutoTab);
tabsPanel.ContentPanel.Controls.Add(new Label
{
Text = "Auto-Tab Min Size:",
Location = new Point(12, 32),
Text = "Min:",
Location = new Point(44, 76),
AutoSize = true
});
nudAutoTabMin = CreateNumeric(140, 29, 0, 0.0625);
nudAutoTabMin = CreateNumeric(77, 73, 0, 0.0625);
nudAutoTabMin.Enabled = false;
tabsPanel.ContentPanel.Controls.Add(nudAutoTabMin);
tabsPanel.ContentPanel.Controls.Add(new Label
{
Text = "Auto-Tab Max Size:",
Location = new Point(12, 58),
Text = "Max:",
Location = new Point(210, 76),
AutoSize = true
});
nudAutoTabMax = CreateNumeric(140, 55, 0, 0.0625);
nudAutoTabMax = CreateNumeric(245, 73, 0, 0.0625);
nudAutoTabMax.Enabled = false;
tabsPanel.ContentPanel.Controls.Add(nudAutoTabMax);
chkTabsEnabled.CheckedChanged += (s, e) =>
{
var enabled = chkTabsEnabled.Checked;
nudTabWidth.Enabled = enabled;
rbTabAll.Enabled = enabled;
rbAutoTab.Enabled = enabled;
nudAutoTabMin.Enabled = enabled && rbAutoTab.Checked;
nudAutoTabMax.Enabled = enabled && rbAutoTab.Checked;
OnParametersChanged();
};
rbTabAll.CheckedChanged += (s, e) =>
{
nudAutoTabMin.Enabled = chkTabsEnabled.Checked && rbAutoTab.Checked;
nudAutoTabMax.Enabled = chkTabsEnabled.Checked && rbAutoTab.Checked;
OnParametersChanged();
};
// Pierce section
var piercePanel = new CollapsiblePanel
{
@@ -246,13 +282,13 @@ namespace OpenNest.Controls
InternalLeadOut = BuildLeadOut(cboInternalLeadOut, pnlInternalLeadOut),
ArcCircleLeadIn = BuildLeadIn(cboArcCircleLeadIn, pnlArcCircleLeadIn),
ArcCircleLeadOut = BuildLeadOut(cboArcCircleLeadOut, pnlArcCircleLeadOut),
TabsEnabled = chkTabsEnabled.Checked,
TabsEnabled = chkTabsEnabled.Checked && rbTabAll.Checked,
TabConfig = new NormalTab { Size = (double)nudTabWidth.Value },
PierceClearance = (double)nudPierceClearance.Value,
RoundLeadInAngles = chkRoundLeadInAngles.Checked,
LeadInAngleIncrement = (double)nudLeadInAngleIncrement.Value,
AutoTabMinSize = (double)nudAutoTabMin.Value,
AutoTabMaxSize = (double)nudAutoTabMax.Value
AutoTabMinSize = chkTabsEnabled.Checked && rbAutoTab.Checked ? (double)nudAutoTabMin.Value : 0,
AutoTabMaxSize = chkTabsEnabled.Checked && rbAutoTab.Checked ? (double)nudAutoTabMax.Value : 0
};
}
@@ -267,7 +303,10 @@ namespace OpenNest.Controls
LoadLeadIn(cboArcCircleLeadIn, pnlArcCircleLeadIn, p.ArcCircleLeadIn);
LoadLeadOut(cboArcCircleLeadOut, pnlArcCircleLeadOut, p.ArcCircleLeadOut);
chkTabsEnabled.Checked = p.TabsEnabled;
var hasAutoTab = p.AutoTabMinSize > 0 || p.AutoTabMaxSize > 0;
chkTabsEnabled.Checked = p.TabsEnabled || hasAutoTab;
rbAutoTab.Checked = hasAutoTab;
rbTabAll.Checked = !hasAutoTab;
if (p.TabConfig != null)
nudTabWidth.Value = (decimal)p.TabConfig.Size;
nudPierceClearance.Value = (decimal)p.PierceClearance;