diff --git a/OpenNest.Data/MachineCuttingDefaults.cs b/OpenNest.Data/MachineCuttingDefaults.cs
index 787bacca..df7fb139 100644
--- a/OpenNest.Data/MachineCuttingDefaults.cs
+++ b/OpenNest.Data/MachineCuttingDefaults.cs
@@ -73,6 +73,25 @@ public static class MachineCuttingDefaults
return true;
}
+ ///
+ /// Whether are stamped with the machine, material, grade and
+ /// thickness would record for
+ /// the nest: they started from the machine's settings for it, and any lead edits since are
+ /// the user's choice for that same job, which the machine's settings must not replace.
+ ///
+ public static bool IsRecordedFor(CuttingParameters parameters, MachineConfig? machine, Nest nest)
+ {
+ ArgumentNullException.ThrowIfNull(parameters);
+ ArgumentNullException.ThrowIfNull(nest);
+ if (Find(machine, nest) == null)
+ return false;
+ var tolerance = ThicknessToleranceInches * Scale(Units.Inches, nest.Units);
+ return string.Equals(parameters.MachineName, machine!.Name, StringComparison.Ordinal)
+ && string.Equals(parameters.MaterialName, nest.Material.Name, StringComparison.Ordinal)
+ && string.Equals(parameters.Grade ?? "", nest.Material.Grade ?? "", StringComparison.Ordinal)
+ && System.Math.Abs(parameters.Thickness - nest.Thickness) <= tolerance;
+ }
+
///
/// Replaces the part clearance, overtravel, minimum segment and direction of
/// with the machine's for the nest; the head-lock choice is kept.
diff --git a/OpenNest.Tests/Data/MachineCuttingDefaultsTests.cs b/OpenNest.Tests/Data/MachineCuttingDefaultsTests.cs
index 88b47aae..a6d96fbe 100644
--- a/OpenNest.Tests/Data/MachineCuttingDefaultsTests.cs
+++ b/OpenNest.Tests/Data/MachineCuttingDefaultsTests.cs
@@ -41,6 +41,19 @@ public class MachineCuttingDefaultsTests
private static readonly LeadConfig LineArc = new() { Type = "Line + Arc", Length = 0.125, Angle = 90, Radius = 0.0625 };
+ [Fact]
+ public void IsRecordedFor_KeepsLeadsEditedAfterTheMachineSettingsWereTaken()
+ {
+ var parameters = new CuttingParameters();
+ Assert.True(MachineCuttingDefaults.ApplyTo(parameters, Machine(LineArc), NestOf(0.25, "A36")));
+ parameters.ExternalLeadOut = new NoLeadOut();
+
+ Assert.True(MachineCuttingDefaults.IsRecordedFor(parameters, Machine(LineArc), NestOf(0.2505, "A36")));
+ Assert.False(MachineCuttingDefaults.IsRecordedFor(parameters, Machine(LineArc), NestOf(0.25, "A572")));
+ Assert.False(MachineCuttingDefaults.IsRecordedFor(parameters, Machine(LineArc), NestOf(0.5, "A36")));
+ Assert.False(MachineCuttingDefaults.IsRecordedFor(new CuttingParameters(), Machine(LineArc), NestOf(0.25, "A36")));
+ }
+
[Fact]
public void ApplyTo_GivesEveryContourTheMachineLeadsAndStampsTheSource()
{
diff --git a/OpenNest.WinForms.Tests/Controls/CuttingPanelTests.cs b/OpenNest.WinForms.Tests/Controls/CuttingPanelTests.cs
new file mode 100644
index 00000000..66e827e2
--- /dev/null
+++ b/OpenNest.WinForms.Tests/Controls/CuttingPanelTests.cs
@@ -0,0 +1,39 @@
+using OpenNest.CNC.CuttingStrategy;
+using OpenNest.Controls;
+
+namespace OpenNest.WinForms.Tests.Controls;
+
+public class CuttingPanelTests
+{
+ [Fact]
+ public void BuildParameters_KeepsTheSettingsThePanelHasNoFieldFor()
+ {
+ StaTestThread.Run(() =>
+ {
+ using var panel = new CuttingPanel();
+ panel.LoadFromParameters(new CuttingParameters
+ {
+ MachineName = "CL-980",
+ MaterialName = "Stainless Steel",
+ Grade = "304",
+ Thickness = 0.075,
+ Kerf = 0.008,
+ ExternalLeadIn = new ArcLeadIn { Radius = 0.0625 },
+ ExternalLeadOut = new NoLeadOut(),
+ TabsEnabled = true,
+ TabConfig = new NormalTab { Size = 0.25 },
+ });
+
+ var built = panel.BuildParameters();
+
+ // Without the stamp, the machine's leads would replace these edits on the next open.
+ Assert.Equal("CL-980", built.MachineName);
+ Assert.Equal("Stainless Steel", built.MaterialName);
+ Assert.Equal("304", built.Grade);
+ Assert.Equal(0.075, built.Thickness);
+ Assert.Equal(0.008, built.Kerf);
+ Assert.IsType(built.ExternalLeadOut);
+ Assert.True(built.TabsEnabled);
+ }, TimeSpan.FromSeconds(30), "The cutting panel did not build its parameters.");
+ }
+}
diff --git a/OpenNest/Controls/CuttingPanel.cs b/OpenNest/Controls/CuttingPanel.cs
index 48f8e064..238d5958 100644
--- a/OpenNest/Controls/CuttingPanel.cs
+++ b/OpenNest/Controls/CuttingPanel.cs
@@ -2,6 +2,7 @@ using System;
using System.Drawing;
using System.Windows.Forms;
using OpenNest.CNC.CuttingStrategy;
+using OpenNest.IO;
namespace OpenNest.Controls
{
@@ -57,6 +58,8 @@ namespace OpenNest.Controls
private readonly NumericUpDown nudPierceClearance;
private readonly NumericUpDown nudPierceDiameter;
+ private CuttingParameters loaded;
+
private readonly CheckBox chkRoundLeadInAngles;
private readonly NumericUpDown nudLeadInAngleIncrement;
@@ -294,30 +297,33 @@ namespace OpenNest.Controls
base.Dispose(disposing);
}
+ // Settings the panel has no field for (kerf, the machine/material/thickness stamp,
+ // sequencing) come back unchanged from the parameters last loaded.
public CuttingParameters BuildParameters()
{
- return new CuttingParameters
- {
- ExternalLeadIn = BuildLeadIn(cboExternalLeadIn, pnlExternalLeadIn),
- ExternalLeadOut = BuildLeadOut(cboExternalLeadOut, pnlExternalLeadOut),
- InternalLeadIn = BuildLeadIn(cboInternalLeadIn, pnlInternalLeadIn),
- InternalLeadOut = BuildLeadOut(cboInternalLeadOut, pnlInternalLeadOut),
- TabsEnabled = chkTabsEnabled.Checked && rbTabAll.Checked,
- TabConfig = new NormalTab { Size = (double)nudTabWidth.Value },
- PierceClearance = (double)nudPierceClearance.Value,
- PierceDiameter = (double)nudPierceDiameter.Value,
- RoundLeadInAngles = chkRoundLeadInAngles.Checked,
- LeadInAngleIncrement = (double)nudLeadInAngleIncrement.Value,
- SupportTabs = chkTabsEnabled.Checked && rbSupportTab.Checked,
- NoBedTabMinWidth = (double)nudNoBedTabMin.Value,
- NoBedTabMaxWidth = (double)nudNoBedTabMax.Value,
- TabHeldMaxLength = (double)nudTabHeldMax.Value,
- };
+ var parameters = loaded == null ? new CuttingParameters()
+ : CuttingParametersSerializer.Deserialize(CuttingParametersSerializer.Serialize(loaded));
+ parameters.ExternalLeadIn = BuildLeadIn(cboExternalLeadIn, pnlExternalLeadIn);
+ parameters.ExternalLeadOut = BuildLeadOut(cboExternalLeadOut, pnlExternalLeadOut);
+ parameters.InternalLeadIn = BuildLeadIn(cboInternalLeadIn, pnlInternalLeadIn);
+ parameters.InternalLeadOut = BuildLeadOut(cboInternalLeadOut, pnlInternalLeadOut);
+ parameters.TabsEnabled = chkTabsEnabled.Checked && rbTabAll.Checked;
+ parameters.TabConfig = new NormalTab { Size = (double)nudTabWidth.Value };
+ parameters.PierceClearance = (double)nudPierceClearance.Value;
+ parameters.PierceDiameter = (double)nudPierceDiameter.Value;
+ parameters.RoundLeadInAngles = chkRoundLeadInAngles.Checked;
+ parameters.LeadInAngleIncrement = (double)nudLeadInAngleIncrement.Value;
+ parameters.SupportTabs = chkTabsEnabled.Checked && rbSupportTab.Checked;
+ parameters.NoBedTabMinWidth = (double)nudNoBedTabMin.Value;
+ parameters.NoBedTabMaxWidth = (double)nudNoBedTabMax.Value;
+ parameters.TabHeldMaxLength = (double)nudTabHeldMax.Value;
+ return parameters;
}
public void LoadFromParameters(CuttingParameters p)
{
suppressEvents = true;
+ loaded = CuttingParametersSerializer.Deserialize(CuttingParametersSerializer.Serialize(p));
LoadLeadIn(cboExternalLeadIn, pnlExternalLeadIn, p.ExternalLeadIn);
LoadLeadOut(cboExternalLeadOut, pnlExternalLeadOut, p.ExternalLeadOut);
diff --git a/OpenNest/Forms/CuttingInspectionPanel.cs b/OpenNest/Forms/CuttingInspectionPanel.cs
index 457b6643..465b6b98 100644
--- a/OpenNest/Forms/CuttingInspectionPanel.cs
+++ b/OpenNest/Forms/CuttingInspectionPanel.cs
@@ -1258,6 +1258,8 @@ internal sealed class CuttingInspectionPanel : UserControl
dialog.LoadParameters(parameters);
if (dialog.ShowDialog(this) != DialogResult.OK || closed || closeRequested) return;
parameters = dialog.GetParameters();
+ // Saved now, not only on Apply: a plate that will not plan must not lose the edit.
+ EditNestForm.SaveCuttingParameters(parameters);
ShowSettings();
RestartPlanning();
}
diff --git a/OpenNest/Forms/EditNestForm.cs b/OpenNest/Forms/EditNestForm.cs
index ddffe263..8607740f 100644
--- a/OpenNest/Forms/EditNestForm.cs
+++ b/OpenNest/Forms/EditNestForm.cs
@@ -1356,7 +1356,7 @@ namespace OpenNest.Forms
PlateView.SetAction(typeof(Actions.ActionLeadIn));
}
- private static void SaveCuttingParameters(CuttingParameters parameters)
+ internal static void SaveCuttingParameters(CuttingParameters parameters)
{
var json = CuttingParametersSerializer.Serialize(parameters);
Properties.Settings.Default.CuttingParametersJson = json;
diff --git a/OpenNest/Forms/MachineSettings.cs b/OpenNest/Forms/MachineSettings.cs
index d9eb82ce..4ec3271e 100644
--- a/OpenNest/Forms/MachineSettings.cs
+++ b/OpenNest/Forms/MachineSettings.cs
@@ -198,12 +198,16 @@ namespace OpenNest.Forms
///
/// The cutting parameters a plate of without its own starts from:
/// the last ones applied (or the built-in defaults), with the lead-ins, lead-outs and kerf
- /// of the nest's machine for its material and thickness when the machine has them.
+ /// of the nest's machine for its material and thickness when the machine has them. Last
+ /// parameters already taken from that machine, material and thickness keep the user's
+ /// edits to them.
///
public static CuttingParameters DefaultCuttingParameters(Nest nest)
{
var parameters = LastCuttingParameters();
- MachineCuttingDefaults.ApplyTo(parameters, FindMachine(nest.Machine), nest);
+ var machine = FindMachine(nest.Machine);
+ if (!MachineCuttingDefaults.IsRecordedFor(parameters, machine, nest))
+ MachineCuttingDefaults.ApplyTo(parameters, machine, nest);
return parameters;
}
diff --git a/docs/machine-cutting-defaults.md b/docs/machine-cutting-defaults.md
index 1b4e5a29..14fce265 100644
--- a/docs/machine-cutting-defaults.md
+++ b/docs/machine-cutting-defaults.md
@@ -19,7 +19,11 @@ machine's units to the nest's.
A plate with no cutting parameters of its own (Plan Cutting, Place Lead-in) starts from the
last applied parameters, as before, with the machine's leads and kerf laid over them and the
-machine, material, grade and thickness recorded on the parameters. A plate that already has
+machine, material, grade and thickness recorded on the parameters. When the last parameters
+already record the same machine, material, grade and thickness, the machine's settings are not
+laid over them again, so lead and tab edits made for that job stick; the cutting panel keeps the
+record (and the kerf) through an edit. Plan Cutting saves its settings as the last parameters as
+soon as its settings dialog is accepted, not only on Apply. A plate that already has
parameters keeps them: changing the machine, material or thickness does not rewrite leads
the plate was planned with.