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.