From 7f8c708d3f0d1a30022ecb6d06c5d4e80816d51d Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Mon, 30 Mar 2026 13:36:41 -0400 Subject: [PATCH] feat: add CuttingParametersForm dialog for lead-in/lead-out configuration Co-Authored-By: Claude Opus 4.6 (1M context) --- .../Forms/CuttingParametersForm.Designer.cs | 156 ++++++++ OpenNest/Forms/CuttingParametersForm.cs | 347 ++++++++++++++++++ 2 files changed, 503 insertions(+) create mode 100644 OpenNest/Forms/CuttingParametersForm.Designer.cs create mode 100644 OpenNest/Forms/CuttingParametersForm.cs diff --git a/OpenNest/Forms/CuttingParametersForm.Designer.cs b/OpenNest/Forms/CuttingParametersForm.Designer.cs new file mode 100644 index 0000000..4fd7c4d --- /dev/null +++ b/OpenNest/Forms/CuttingParametersForm.Designer.cs @@ -0,0 +1,156 @@ +namespace OpenNest.Forms +{ + partial class CuttingParametersForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.tabControl = new System.Windows.Forms.TabControl(); + this.tabExternal = new System.Windows.Forms.TabPage(); + this.tabInternal = new System.Windows.Forms.TabPage(); + this.tabArcCircle = new System.Windows.Forms.TabPage(); + this.acceptButton = new System.Windows.Forms.Button(); + this.cancelButton = new System.Windows.Forms.Button(); + this.bottomPanel = new OpenNest.Controls.BottomPanel(); + this.tabControl.SuspendLayout(); + this.bottomPanel.SuspendLayout(); + this.SuspendLayout(); + // + // tabControl + // + this.tabControl.Controls.Add(this.tabExternal); + this.tabControl.Controls.Add(this.tabInternal); + this.tabControl.Controls.Add(this.tabArcCircle); + this.tabControl.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl.Location = new System.Drawing.Point(0, 0); + this.tabControl.Margin = new System.Windows.Forms.Padding(4); + this.tabControl.Name = "tabControl"; + this.tabControl.SelectedIndex = 0; + this.tabControl.Size = new System.Drawing.Size(368, 290); + this.tabControl.TabIndex = 0; + // + // tabExternal + // + this.tabExternal.Location = new System.Drawing.Point(4, 25); + this.tabExternal.Margin = new System.Windows.Forms.Padding(4); + this.tabExternal.Name = "tabExternal"; + this.tabExternal.Padding = new System.Windows.Forms.Padding(8); + this.tabExternal.Size = new System.Drawing.Size(360, 261); + this.tabExternal.TabIndex = 0; + this.tabExternal.Text = "External"; + this.tabExternal.UseVisualStyleBackColor = true; + // + // tabInternal + // + this.tabInternal.Location = new System.Drawing.Point(4, 25); + this.tabInternal.Margin = new System.Windows.Forms.Padding(4); + this.tabInternal.Name = "tabInternal"; + this.tabInternal.Padding = new System.Windows.Forms.Padding(8); + this.tabInternal.Size = new System.Drawing.Size(360, 261); + this.tabInternal.TabIndex = 1; + this.tabInternal.Text = "Internal"; + this.tabInternal.UseVisualStyleBackColor = true; + // + // tabArcCircle + // + this.tabArcCircle.Location = new System.Drawing.Point(4, 25); + this.tabArcCircle.Margin = new System.Windows.Forms.Padding(4); + this.tabArcCircle.Name = "tabArcCircle"; + this.tabArcCircle.Padding = new System.Windows.Forms.Padding(8); + this.tabArcCircle.Size = new System.Drawing.Size(360, 261); + this.tabArcCircle.TabIndex = 2; + this.tabArcCircle.Text = "Arc / Circle"; + this.tabArcCircle.UseVisualStyleBackColor = true; + // + // acceptButton + // + this.acceptButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.acceptButton.DialogResult = System.Windows.Forms.DialogResult.OK; + this.acceptButton.Location = new System.Drawing.Point(165, 11); + this.acceptButton.Margin = new System.Windows.Forms.Padding(4); + this.acceptButton.Name = "acceptButton"; + this.acceptButton.Size = new System.Drawing.Size(90, 28); + this.acceptButton.TabIndex = 8; + this.acceptButton.Text = "OK"; + this.acceptButton.UseVisualStyleBackColor = true; + // + // cancelButton + // + this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancelButton.Location = new System.Drawing.Point(263, 11); + this.cancelButton.Margin = new System.Windows.Forms.Padding(4); + this.cancelButton.Name = "cancelButton"; + this.cancelButton.Size = new System.Drawing.Size(90, 28); + this.cancelButton.TabIndex = 9; + this.cancelButton.Text = "Cancel"; + this.cancelButton.UseVisualStyleBackColor = true; + // + // bottomPanel + // + this.bottomPanel.Controls.Add(this.acceptButton); + this.bottomPanel.Controls.Add(this.cancelButton); + this.bottomPanel.Dock = System.Windows.Forms.DockStyle.Bottom; + this.bottomPanel.Location = new System.Drawing.Point(0, 290); + this.bottomPanel.Name = "bottomPanel"; + this.bottomPanel.Size = new System.Drawing.Size(368, 50); + this.bottomPanel.TabIndex = 1; + // + // CuttingParametersForm + // + this.AcceptButton = this.acceptButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cancelButton; + this.ClientSize = new System.Drawing.Size(368, 340); + this.Controls.Add(this.tabControl); + this.Controls.Add(this.bottomPanel); + this.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.Margin = new System.Windows.Forms.Padding(4); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "CuttingParametersForm"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Cutting Parameters"; + this.tabControl.ResumeLayout(false); + this.bottomPanel.ResumeLayout(false); + this.ResumeLayout(false); + } + + #endregion + + private System.Windows.Forms.TabControl tabControl; + private System.Windows.Forms.TabPage tabExternal; + private System.Windows.Forms.TabPage tabInternal; + private System.Windows.Forms.TabPage tabArcCircle; + private Controls.BottomPanel bottomPanel; + private System.Windows.Forms.Button acceptButton; + private System.Windows.Forms.Button cancelButton; + } +} diff --git a/OpenNest/Forms/CuttingParametersForm.cs b/OpenNest/Forms/CuttingParametersForm.cs new file mode 100644 index 0000000..94ad430 --- /dev/null +++ b/OpenNest/Forms/CuttingParametersForm.cs @@ -0,0 +1,347 @@ +using OpenNest.CNC.CuttingStrategy; +using System; +using System.Windows.Forms; + +namespace OpenNest.Forms +{ + public partial class CuttingParametersForm : Form + { + private static readonly string[] LeadInTypes = + { "None", "Line", "Arc", "Line + Arc", "Clean Hole", "Line + Line" }; + + private static readonly string[] LeadOutTypes = + { "None", "Line", "Arc", "Microtab" }; + + private ComboBox cboExternalLeadIn, cboExternalLeadOut; + private ComboBox cboInternalLeadIn, cboInternalLeadOut; + private ComboBox cboArcCircleLeadIn, cboArcCircleLeadOut; + + private Panel pnlExternalParams, pnlInternalParams, pnlArcCircleParams; + + public CuttingParameters Parameters { get; set; } = new CuttingParameters(); + + public CuttingParametersForm() + { + InitializeComponent(); + + SetupTab(tabExternal, out cboExternalLeadIn, out cboExternalLeadOut, out pnlExternalParams); + SetupTab(tabInternal, out cboInternalLeadIn, out cboInternalLeadOut, out pnlInternalParams); + SetupTab(tabArcCircle, out cboArcCircleLeadIn, out cboArcCircleLeadOut, out pnlArcCircleParams); + + PopulateDropdowns(); + + cboExternalLeadIn.SelectedIndexChanged += OnLeadInTypeChanged; + cboInternalLeadIn.SelectedIndexChanged += OnLeadInTypeChanged; + cboArcCircleLeadIn.SelectedIndexChanged += OnLeadInTypeChanged; + } + + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + LoadFromParameters(Parameters); + } + + private static void SetupTab(TabPage tab, out ComboBox leadInCombo, + out ComboBox leadOutCombo, out Panel paramPanel) + { + var y = 12; + + var lblLeadIn = new Label + { + Text = "Lead-In:", + Location = new System.Drawing.Point(8, y + 3), + AutoSize = true + }; + tab.Controls.Add(lblLeadIn); + + leadInCombo = new ComboBox + { + DropDownStyle = ComboBoxStyle.DropDownList, + Location = new System.Drawing.Point(100, y), + Size = new System.Drawing.Size(240, 24) + }; + tab.Controls.Add(leadInCombo); + + y += 32; + + var lblLeadOut = new Label + { + Text = "Lead-Out:", + Location = new System.Drawing.Point(8, y + 3), + AutoSize = true + }; + tab.Controls.Add(lblLeadOut); + + leadOutCombo = new ComboBox + { + DropDownStyle = ComboBoxStyle.DropDownList, + Location = new System.Drawing.Point(100, y), + Size = new System.Drawing.Size(240, 24) + }; + tab.Controls.Add(leadOutCombo); + + y += 40; + + paramPanel = new Panel + { + Location = new System.Drawing.Point(8, y), + Size = new System.Drawing.Size(332, 170), + AutoScroll = true + }; + tab.Controls.Add(paramPanel); + } + + private void PopulateDropdowns() + { + foreach (var combo in new[] { cboExternalLeadIn, cboInternalLeadIn, cboArcCircleLeadIn }) + { + combo.Items.AddRange(LeadInTypes); + combo.SelectedIndex = 0; + } + + foreach (var combo in new[] { cboExternalLeadOut, cboInternalLeadOut, cboArcCircleLeadOut }) + { + combo.Items.AddRange(LeadOutTypes); + combo.SelectedIndex = 0; + } + } + + private void OnLeadInTypeChanged(object sender, EventArgs e) + { + var combo = (ComboBox)sender; + var panel = GetParamPanel(combo); + if (panel != null) + BuildParamControls(panel, combo.SelectedIndex); + } + + private Panel GetParamPanel(ComboBox combo) + { + if (combo == cboExternalLeadIn) return pnlExternalParams; + if (combo == cboInternalLeadIn) return pnlInternalParams; + if (combo == cboArcCircleLeadIn) return pnlArcCircleParams; + return null; + } + + private static void BuildParamControls(Panel panel, int typeIndex) + { + panel.Controls.Clear(); + var y = 0; + + switch (typeIndex) + { + case 1: // Line + AddNumericField(panel, "Length:", 0.25, ref y, "Length"); + AddNumericField(panel, "Approach Angle:", 90, ref y, "ApproachAngle"); + break; + case 2: // Arc + AddNumericField(panel, "Radius:", 0.25, ref y, "Radius"); + break; + case 3: // Line + Arc + AddNumericField(panel, "Line Length:", 0.25, ref y, "LineLength"); + AddNumericField(panel, "Arc Radius:", 0.125, ref y, "ArcRadius"); + AddNumericField(panel, "Approach Angle:", 135, ref y, "ApproachAngle"); + break; + case 4: // Clean Hole + AddNumericField(panel, "Line Length:", 0.25, ref y, "LineLength"); + AddNumericField(panel, "Arc Radius:", 0.125, ref y, "ArcRadius"); + AddNumericField(panel, "Kerf:", 0.06, ref y, "Kerf"); + break; + case 5: // Line + Line + AddNumericField(panel, "Length 1:", 0.25, ref y, "Length1"); + AddNumericField(panel, "Angle 1:", 90, ref y, "Angle1"); + AddNumericField(panel, "Length 2:", 0.25, ref y, "Length2"); + AddNumericField(panel, "Angle 2:", 90, ref y, "Angle2"); + break; + } + } + + private static void AddNumericField(Panel panel, string label, double defaultValue, + ref int y, string tag) + { + var lbl = new Label + { + Text = label, + Location = new System.Drawing.Point(0, y + 3), + AutoSize = true + }; + panel.Controls.Add(lbl); + + var nud = new System.Windows.Forms.NumericUpDown + { + Location = new System.Drawing.Point(130, y), + Size = new System.Drawing.Size(120, 22), + DecimalPlaces = 4, + Increment = 0.0625m, + Minimum = 0, + Maximum = 9999, + Value = (decimal)defaultValue, + Tag = tag + }; + panel.Controls.Add(nud); + + y += 30; + } + + private void LoadFromParameters(CuttingParameters p) + { + LoadLeadIn(cboExternalLeadIn, pnlExternalParams, p.ExternalLeadIn); + LoadLeadOut(cboExternalLeadOut, p.ExternalLeadOut); + + LoadLeadIn(cboInternalLeadIn, pnlInternalParams, p.InternalLeadIn); + LoadLeadOut(cboInternalLeadOut, p.InternalLeadOut); + + LoadLeadIn(cboArcCircleLeadIn, pnlArcCircleParams, p.ArcCircleLeadIn); + LoadLeadOut(cboArcCircleLeadOut, p.ArcCircleLeadOut); + } + + private static void LoadLeadIn(ComboBox combo, Panel panel, LeadIn leadIn) + { + switch (leadIn) + { + case LineLeadIn line: + combo.SelectedIndex = 1; + SetParam(panel, "Length", line.Length); + SetParam(panel, "ApproachAngle", line.ApproachAngle); + break; + case ArcLeadIn arc: + combo.SelectedIndex = 2; + SetParam(panel, "Radius", arc.Radius); + break; + case LineArcLeadIn lineArc: + combo.SelectedIndex = 3; + SetParam(panel, "LineLength", lineArc.LineLength); + SetParam(panel, "ArcRadius", lineArc.ArcRadius); + SetParam(panel, "ApproachAngle", lineArc.ApproachAngle); + break; + case CleanHoleLeadIn cleanHole: + combo.SelectedIndex = 4; + SetParam(panel, "LineLength", cleanHole.LineLength); + SetParam(panel, "ArcRadius", cleanHole.ArcRadius); + SetParam(panel, "Kerf", cleanHole.Kerf); + break; + case LineLineLeadIn lineLine: + combo.SelectedIndex = 5; + SetParam(panel, "Length1", lineLine.Length1); + SetParam(panel, "Angle1", lineLine.ApproachAngle1); + SetParam(panel, "Length2", lineLine.Length2); + SetParam(panel, "Angle2", lineLine.ApproachAngle2); + break; + default: + combo.SelectedIndex = 0; + break; + } + } + + private static void LoadLeadOut(ComboBox combo, LeadOut leadOut) + { + switch (leadOut) + { + case LineLeadOut _: + combo.SelectedIndex = 1; + break; + case ArcLeadOut _: + combo.SelectedIndex = 2; + break; + case MicrotabLeadOut _: + combo.SelectedIndex = 3; + break; + default: + combo.SelectedIndex = 0; + break; + } + } + + public CuttingParameters BuildParameters() + { + var p = new CuttingParameters + { + ExternalLeadIn = BuildLeadIn(cboExternalLeadIn, pnlExternalParams), + ExternalLeadOut = BuildLeadOut(cboExternalLeadOut), + InternalLeadIn = BuildLeadIn(cboInternalLeadIn, pnlInternalParams), + InternalLeadOut = BuildLeadOut(cboInternalLeadOut), + ArcCircleLeadIn = BuildLeadIn(cboArcCircleLeadIn, pnlArcCircleParams), + ArcCircleLeadOut = BuildLeadOut(cboArcCircleLeadOut) + }; + return p; + } + + private static LeadIn BuildLeadIn(ComboBox combo, Panel panel) + { + switch (combo.SelectedIndex) + { + case 1: + return new LineLeadIn + { + Length = GetParam(panel, "Length", 0.25), + ApproachAngle = GetParam(panel, "ApproachAngle", 90) + }; + case 2: + return new ArcLeadIn + { + Radius = GetParam(panel, "Radius", 0.25) + }; + case 3: + return new LineArcLeadIn + { + LineLength = GetParam(panel, "LineLength", 0.25), + ArcRadius = GetParam(panel, "ArcRadius", 0.125), + ApproachAngle = GetParam(panel, "ApproachAngle", 135) + }; + case 4: + return new CleanHoleLeadIn + { + LineLength = GetParam(panel, "LineLength", 0.25), + ArcRadius = GetParam(panel, "ArcRadius", 0.125), + Kerf = GetParam(panel, "Kerf", 0.06) + }; + case 5: + return new LineLineLeadIn + { + Length1 = GetParam(panel, "Length1", 0.25), + ApproachAngle1 = GetParam(panel, "Angle1", 90), + Length2 = GetParam(panel, "Length2", 0.25), + ApproachAngle2 = GetParam(panel, "Angle2", 90) + }; + default: + return new NoLeadIn(); + } + } + + private static LeadOut BuildLeadOut(ComboBox combo) + { + switch (combo.SelectedIndex) + { + case 1: + return new LineLeadOut { Length = 0.25, ApproachAngle = 90 }; + case 2: + return new ArcLeadOut { Radius = 0.25 }; + case 3: + return new MicrotabLeadOut(); + default: + return new NoLeadOut(); + } + } + + private static void SetParam(Panel panel, string tag, double value) + { + foreach (Control c in panel.Controls) + { + if (c is System.Windows.Forms.NumericUpDown nud && (string)nud.Tag == tag) + { + nud.Value = (decimal)value; + return; + } + } + } + + private static double GetParam(Panel panel, string tag, double defaultValue) + { + foreach (Control c in panel.Controls) + { + if (c is System.Windows.Forms.NumericUpDown nud && (string)nud.Tag == tag) + return (double)nud.Value; + } + return defaultValue; + } + } +}