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;
+ }
+ }
+}