feat: add option to round lead-in angles for circle holes

Snaps lead-in angles on ArcCircle contours to a configurable
increment (default 5°), reducing unique hole variations from
infinite to 72 max. Rounding happens upstream in EmitContour
so the PlateView and post output stay in sync.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-09 12:41:33 -04:00
parent 3481764416
commit de6877ac48
4 changed files with 62 additions and 1 deletions

View File

@@ -255,7 +255,23 @@ namespace OpenNest.CNC.CuttingStrategy
var leadOut = SelectLeadOut(contourType);
if (contourType == ContourType.ArcCircle && entity is Circle circle)
{
if (Parameters.RoundLeadInAngles && Parameters.LeadInAngleIncrement > 0)
{
var increment = Angle.ToRadians(Parameters.LeadInAngleIncrement);
normal = System.Math.Round(normal / increment) * increment;
normal = Angle.NormalizeRad(normal);
// Recompute contour start point on the circle at the rounded angle.
// For ArcCircle, normal points inward (toward center), so outward = normal - PI.
var outwardAngle = normal - System.Math.PI;
point = new Vector(
circle.Center.X + circle.Radius * System.Math.Cos(outwardAngle),
circle.Center.Y + circle.Radius * System.Math.Sin(outwardAngle));
}
leadIn = ClampLeadInForCircle(leadIn, circle, point, normal);
}
program.Codes.AddRange(leadIn.Generate(point, normal, winding));

View File

@@ -23,6 +23,9 @@ namespace OpenNest.CNC.CuttingStrategy
public double PierceClearance { get; set; } = 0.0625;
public bool RoundLeadInAngles { get; set; }
public double LeadInAngleIncrement { get; set; } = 5.0;
public double AutoTabMinSize { get; set; }
public double AutoTabMaxSize { get; set; }

View File

@@ -28,6 +28,9 @@ namespace OpenNest.Controls
private readonly NumericUpDown nudAutoTabMax;
private readonly NumericUpDown nudPierceClearance;
private readonly CheckBox chkRoundLeadInAngles;
private readonly NumericUpDown nudLeadInAngleIncrement;
private readonly Button btnAutoAssign;
private bool suppressEvents;
@@ -162,7 +165,7 @@ namespace OpenNest.Controls
{
HeaderText = "Pierce",
Dock = DockStyle.Top,
ExpandedHeight = 60,
ExpandedHeight = 90,
IsExpanded = true
};
@@ -176,6 +179,34 @@ namespace OpenNest.Controls
nudPierceClearance = CreateNumeric(130, 3, 0.0625, 0.0625);
piercePanel.ContentPanel.Controls.Add(nudPierceClearance);
chkRoundLeadInAngles = new CheckBox
{
Text = "Round Lead-In Angles",
Location = new Point(12, 32),
AutoSize = true
};
chkRoundLeadInAngles.CheckedChanged += (s, e) =>
{
nudLeadInAngleIncrement.Enabled = chkRoundLeadInAngles.Checked;
OnParametersChanged();
};
piercePanel.ContentPanel.Controls.Add(chkRoundLeadInAngles);
piercePanel.ContentPanel.Controls.Add(new Label
{
Text = "Increment:",
Location = new Point(175, 34),
AutoSize = true
});
nudLeadInAngleIncrement = CreateNumeric(245, 31, 5, 1);
nudLeadInAngleIncrement.DecimalPlaces = 0;
nudLeadInAngleIncrement.Minimum = 1;
nudLeadInAngleIncrement.Maximum = 90;
nudLeadInAngleIncrement.Enabled = false;
nudLeadInAngleIncrement.ValueChanged += (s, e) => OnParametersChanged();
piercePanel.ContentPanel.Controls.Add(nudLeadInAngleIncrement);
// Auto-Assign button — wrapped in a panel for Dock.Top with padding
btnAutoAssign = new Button
{
@@ -218,6 +249,8 @@ namespace OpenNest.Controls
TabsEnabled = chkTabsEnabled.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
};
@@ -238,6 +271,9 @@ namespace OpenNest.Controls
if (p.TabConfig != null)
nudTabWidth.Value = (decimal)p.TabConfig.Size;
nudPierceClearance.Value = (decimal)p.PierceClearance;
chkRoundLeadInAngles.Checked = p.RoundLeadInAngles;
nudLeadInAngleIncrement.Value = (decimal)p.LeadInAngleIncrement;
nudLeadInAngleIncrement.Enabled = p.RoundLeadInAngles;
nudAutoTabMin.Value = (decimal)p.AutoTabMinSize;
nudAutoTabMax.Value = (decimal)p.AutoTabMaxSize;

View File

@@ -24,6 +24,8 @@ namespace OpenNest.Forms
TabsEnabled = p.TabsEnabled,
TabWidth = p.TabConfig?.Size ?? 0.25,
PierceClearance = p.PierceClearance,
RoundLeadInAngles = p.RoundLeadInAngles,
LeadInAngleIncrement = p.LeadInAngleIncrement,
AutoTabMinSize = p.AutoTabMinSize,
AutoTabMaxSize = p.AutoTabMaxSize
};
@@ -47,6 +49,8 @@ namespace OpenNest.Forms
TabsEnabled = dto.TabsEnabled,
TabConfig = new NormalTab { Size = dto.TabWidth },
PierceClearance = dto.PierceClearance,
RoundLeadInAngles = dto.RoundLeadInAngles,
LeadInAngleIncrement = dto.LeadInAngleIncrement > 0 ? dto.LeadInAngleIncrement : 5.0,
AutoTabMinSize = dto.AutoTabMinSize,
AutoTabMaxSize = dto.AutoTabMaxSize
};
@@ -111,6 +115,8 @@ namespace OpenNest.Forms
public bool TabsEnabled { get; set; }
public double TabWidth { get; set; }
public double PierceClearance { get; set; }
public bool RoundLeadInAngles { get; set; }
public double LeadInAngleIncrement { get; set; }
public double AutoTabMinSize { get; set; }
public double AutoTabMaxSize { get; set; }
}