mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-11-03 09:01:34 -05:00
feat(machines): set spacing per thickness and save defaults from a nest
Plate > Set as Default and Nest > Edit's Defaults tab only changed the open nest, so new nests never picked up the values. Set as Default now also saves the new-nest defaults, and the Defaults tab gains an opt-in "Use these defaults for new nests" check. Machine thicknesses can now set part and edge spacing. A nest takes them when its material, grade, thickness or machine changes and when a release creates it; BOM import seeds its groups from them. Spacing edited in the same dialog stays, and only an untouched trailing sheet follows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
817c4482eb
commit
59d4c8d727
20 files changed
+457
-44
No files matched your search
@@ -0,0 +1,10 @@
|
||||
namespace OpenNest.Data;
|
||||
|
||||
/// <summary>A thickness's distance kept from each sheet edge, in the machine's units.</summary>
|
||||
public class EdgeSpacingConfig
|
||||
{
|
||||
public double Left { get; set; }
|
||||
public double Bottom { get; set; }
|
||||
public double Right { get; set; }
|
||||
public double Top { get; set; }
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using OpenNest.CNC.CuttingStrategy;
|
||||
using OpenNest.Geometry;
|
||||
|
||||
namespace OpenNest.Data;
|
||||
|
||||
@@ -64,6 +65,53 @@ public static class MachineCuttingDefaults
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gives the nest's plate defaults the part and edge spacing the machine has for its
|
||||
/// material and thickness. Spacing the machine leaves unset stays as it was. Returns false,
|
||||
/// changing nothing, when the machine sets neither.
|
||||
/// </summary>
|
||||
public static bool ApplySpacingTo(Nest nest, MachineConfig? machine)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(nest);
|
||||
var settings = Find(machine, nest);
|
||||
if (settings?.PartSpacing == null && settings?.EdgeSpacing == null)
|
||||
return false;
|
||||
|
||||
var scale = Scale(machine!.Units, nest.Units);
|
||||
if (settings.PartSpacing is { } partSpacing)
|
||||
nest.PlateDefaults.PartSpacing = partSpacing * scale;
|
||||
if (settings.EdgeSpacing is { } edge)
|
||||
nest.PlateDefaults.EdgeSpacing = new Spacing(edge.Left * scale, edge.Bottom * scale, edge.Right * scale, edge.Top * scale);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs <paramref name="edit"/>, then, when it changed the nest's material, grade or
|
||||
/// thickness, applies the machine's spacing for them (<see cref="ApplySpacingTo"/>). A
|
||||
/// spacing the edit changed itself is the user's choice and stays.
|
||||
/// </summary>
|
||||
public static void ApplySpacingAfter(Nest nest, MachineConfig? machine, Action edit)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(nest);
|
||||
ArgumentNullException.ThrowIfNull(edit);
|
||||
var job = (nest.Material?.Name, nest.Material?.Grade, nest.Thickness);
|
||||
var plate = nest.PlateDefaults;
|
||||
var (partBefore, edgeBefore) = (plate.PartSpacing, plate.EdgeSpacing);
|
||||
|
||||
edit();
|
||||
|
||||
if (job == (nest.Material?.Name, nest.Material?.Grade, nest.Thickness))
|
||||
return;
|
||||
|
||||
plate = nest.PlateDefaults;
|
||||
var (partEdited, edgeEdited) = (plate.PartSpacing, plate.EdgeSpacing);
|
||||
ApplySpacingTo(nest, machine);
|
||||
if (partEdited != partBefore)
|
||||
plate.PartSpacing = partEdited;
|
||||
if (!edgeEdited.Equals(edgeBefore))
|
||||
plate.EdgeSpacing = edgeEdited;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The leads <paramref name="settings"/> give, in the machine's units, for previewing them:
|
||||
/// a lead the machine leaves as it was (Line + Line, or Clean Hole on outside cuts) is none.
|
||||
|
||||
@@ -26,4 +26,10 @@ public class ThicknessConfig
|
||||
|
||||
public CutOffConfig CutOff { get; set; } = new();
|
||||
public List<string> PlateSizes { get; set; } = new();
|
||||
|
||||
/// <summary>The part spacing of nests in this thickness; null keeps the nest defaults'.</summary>
|
||||
public double? PartSpacing { get; set; }
|
||||
|
||||
/// <summary>The edge spacing of nests in this thickness; null keeps the nest defaults'.</summary>
|
||||
public EdgeSpacingConfig? EdgeSpacing { get; set; }
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using OpenNest.CNC.CuttingStrategy;
|
||||
using OpenNest.Data;
|
||||
using OpenNest.Geometry;
|
||||
|
||||
namespace OpenNest.Tests.Data;
|
||||
|
||||
@@ -41,6 +42,119 @@ public class MachineCuttingDefaultsTests
|
||||
|
||||
private static readonly LeadConfig LineArc = new() { Type = "Line + Arc", Length = 0.125, Angle = 90, Radius = 0.0625 };
|
||||
|
||||
private static MachineConfig SpacedMachine(UnitSystem units = UnitSystem.Inches)
|
||||
{
|
||||
var machine = Machine(LineArc, units: units);
|
||||
var thickness = machine.Materials[0].Thicknesses[0];
|
||||
thickness.PartSpacing = 0.5;
|
||||
thickness.EdgeSpacing = new EdgeSpacingConfig { Left = 1, Bottom = 2, Right = 3, Top = 4 };
|
||||
return machine;
|
||||
}
|
||||
|
||||
private static Nest SpacedNest(double thickness = 0.25, Units units = Units.Inches)
|
||||
{
|
||||
var nest = NestOf(thickness, "A36", units);
|
||||
nest.PlateDefaults.PartSpacing = 0.1;
|
||||
nest.PlateDefaults.EdgeSpacing = new Spacing(0.2, 0.2, 0.2, 0.2);
|
||||
return nest;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplySpacingTo_SetsTheMachinesSpacing()
|
||||
{
|
||||
var nest = SpacedNest();
|
||||
|
||||
Assert.True(MachineCuttingDefaults.ApplySpacingTo(nest, SpacedMachine()));
|
||||
|
||||
Assert.Equal(0.5, nest.PlateDefaults.PartSpacing);
|
||||
Assert.Equal(new Spacing(1, 2, 3, 4), nest.PlateDefaults.EdgeSpacing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplySpacingTo_ConvertsToTheNestsUnits()
|
||||
{
|
||||
var nest = SpacedNest(6.35, Units.Millimeters);
|
||||
|
||||
Assert.True(MachineCuttingDefaults.ApplySpacingTo(nest, SpacedMachine()));
|
||||
|
||||
Assert.Equal(12.7, nest.PlateDefaults.PartSpacing, 6);
|
||||
Assert.Equal(25.4, nest.PlateDefaults.EdgeSpacing.Left, 6);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplySpacingTo_KeepsWhatTheThicknessLeavesUnset()
|
||||
{
|
||||
var machine = SpacedMachine();
|
||||
machine.Materials[0].Thicknesses[0].EdgeSpacing = null;
|
||||
var nest = SpacedNest();
|
||||
|
||||
Assert.True(MachineCuttingDefaults.ApplySpacingTo(nest, machine));
|
||||
|
||||
Assert.Equal(0.5, nest.PlateDefaults.PartSpacing);
|
||||
Assert.Equal(new Spacing(0.2, 0.2, 0.2, 0.2), nest.PlateDefaults.EdgeSpacing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplySpacingTo_WithoutSpacingOnFile_ChangesNothing()
|
||||
{
|
||||
var nest = SpacedNest();
|
||||
|
||||
Assert.False(MachineCuttingDefaults.ApplySpacingTo(nest, Machine(LineArc)));
|
||||
Assert.False(MachineCuttingDefaults.ApplySpacingTo(nest, null));
|
||||
Assert.False(MachineCuttingDefaults.ApplySpacingTo(SpacedNest(0.5), SpacedMachine()));
|
||||
|
||||
Assert.Equal(0.1, nest.PlateDefaults.PartSpacing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplySpacingAfter_FollowsAChangedThicknessOnly()
|
||||
{
|
||||
var nest = SpacedNest(0.5);
|
||||
|
||||
MachineCuttingDefaults.ApplySpacingAfter(nest, SpacedMachine(), () => nest.Customer = "Acme");
|
||||
Assert.Equal(0.1, nest.PlateDefaults.PartSpacing);
|
||||
|
||||
MachineCuttingDefaults.ApplySpacingAfter(nest, SpacedMachine(), () => nest.Thickness = 0.25);
|
||||
Assert.Equal(0.5, nest.PlateDefaults.PartSpacing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplySpacingAfter_KeepsSpacingTheEditChanged()
|
||||
{
|
||||
var nest = SpacedNest(0.5);
|
||||
|
||||
MachineCuttingDefaults.ApplySpacingAfter(nest, SpacedMachine(), () =>
|
||||
{
|
||||
nest.Thickness = 0.25;
|
||||
nest.PlateDefaults.PartSpacing = 0.3;
|
||||
});
|
||||
|
||||
Assert.Equal(0.3, nest.PlateDefaults.PartSpacing);
|
||||
Assert.Equal(new Spacing(1, 2, 3, 4), nest.PlateDefaults.EdgeSpacing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Spacing_SurvivesTheMachineFile()
|
||||
{
|
||||
var directory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
||||
try
|
||||
{
|
||||
var provider = new LocalJsonProvider(directory);
|
||||
var machine = SpacedMachine();
|
||||
provider.SaveMachine(machine);
|
||||
|
||||
var thickness = provider.GetMachine(machine.Id)!.Materials[0].Thicknesses[0];
|
||||
|
||||
Assert.Equal(0.5, thickness.PartSpacing);
|
||||
Assert.Equal(4, thickness.EdgeSpacing!.Top);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Directory.Exists(directory))
|
||||
Directory.Delete(directory, true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsRecordedFor_KeepsLeadsEditedAfterTheMachineSettingsWereTaken()
|
||||
{
|
||||
|
||||
@@ -74,6 +74,25 @@ public class EditNestInfoFormTests
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NewNestDefaultsChoice_NeedsTheOfferAndTheCheck()
|
||||
{
|
||||
RunSta(() =>
|
||||
{
|
||||
using var form = new EditNestInfoForm();
|
||||
var box = (CheckBox)form.Controls.Find("useForNewNestsBox", true).Single();
|
||||
|
||||
box.Checked = true;
|
||||
Assert.False(form.UseForNewNests);
|
||||
|
||||
form.OfferNewNestDefaults = true;
|
||||
Assert.True(form.UseForNewNests);
|
||||
|
||||
box.Checked = false;
|
||||
Assert.False(form.UseForNewNests);
|
||||
});
|
||||
}
|
||||
|
||||
private static Nest AcceptanceNest()
|
||||
{
|
||||
var nest = new Nest("Acceptance nest")
|
||||
|
||||
@@ -10,6 +10,57 @@ namespace OpenNest.WinForms.Tests.Forms;
|
||||
/// </summary>
|
||||
public class MachineCutsFormsTests
|
||||
{
|
||||
[Fact]
|
||||
public void SpacingTab_SetsOnlyTheCheckedSpacing()
|
||||
{
|
||||
RunSta(() =>
|
||||
{
|
||||
var directory = Path.Combine(Path.GetTempPath(), "OpenNestTests", Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(directory);
|
||||
try
|
||||
{
|
||||
var provider = new LocalJsonProvider(directory);
|
||||
provider.SaveMachine(new MachineConfig
|
||||
{
|
||||
Name = "Laser",
|
||||
Materials = { new MaterialConfig { Name = "Mild Steel", Thicknesses = { new ThicknessConfig { Value = 0.25 } } } },
|
||||
});
|
||||
|
||||
using var form = new MachineConfigForm(provider);
|
||||
var node = Descendants(Find<TreeView>(form, "_tree").Nodes).Single(n => n.Tag is ThicknessConfig);
|
||||
typeof(MachineConfigForm)
|
||||
.GetMethod("Tree_AfterSelect", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)!
|
||||
.Invoke(form, new object[] { null, new TreeViewEventArgs(node) });
|
||||
var shown = (ThicknessConfig)node.Tag;
|
||||
|
||||
var page = All<TabControl>(form).Single().TabPages.Cast<TabPage>().Single(p => p.Text == "Spacing");
|
||||
var checks = All<CheckBox>(page).ToList();
|
||||
var boxes = All<NumericUpDown>(page).ToList();
|
||||
Assert.Equal(2, checks.Count);
|
||||
Assert.Equal(5, boxes.Count);
|
||||
Assert.All(boxes, b => Assert.False(b.Enabled));
|
||||
|
||||
checks[0].Checked = true;
|
||||
boxes[0].Value = 0.5m;
|
||||
Assert.Equal(0.5, shown.PartSpacing);
|
||||
Assert.Null(shown.EdgeSpacing);
|
||||
|
||||
checks[1].Checked = true;
|
||||
boxes[4].Value = 2m;
|
||||
Assert.Equal(2, shown.EdgeSpacing!.Top);
|
||||
|
||||
checks[0].Checked = false;
|
||||
checks[1].Checked = false;
|
||||
Assert.Null(shown.PartSpacing);
|
||||
Assert.Null(shown.EdgeSpacing);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(directory, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InsideCutsTab_GivesHolesTheirOwnLeads()
|
||||
{
|
||||
|
||||
@@ -116,7 +116,7 @@ namespace OpenNest.Controls
|
||||
nestAfterReleaseCheckBox.Checked = Properties.Settings.Default.ReleaseNestAfter;
|
||||
nestAfterReleaseCheckBox.Click += NestAfterReleaseCheckBox_Click;
|
||||
ShowMessage = (text, buttons, icon) => MessageBox.Show(FindForm(), text, "Release", buttons, icon);
|
||||
CreateNest = (group, _) => NewNestFactory.CreateAsync(FindForm(), group.Units);
|
||||
CreateNest = (group, _) => NewNestFactory.CreateAsync(FindForm(), group);
|
||||
EditDrawing = edit =>
|
||||
{
|
||||
using var form = new EditLibraryDrawingForm(edit);
|
||||
|
||||
@@ -280,6 +280,7 @@ namespace OpenNest.Forms
|
||||
: _defaults.Size.Length;
|
||||
|
||||
var groups = BomImportGroups.Build(_parts);
|
||||
var machine = MachineSettings.DefaultMachine(_defaults, MachineSettings.LoadMachines());
|
||||
|
||||
var table = new DataTable();
|
||||
table.Columns.Add("Material", typeof(string));
|
||||
@@ -297,6 +298,7 @@ namespace OpenNest.Forms
|
||||
foreach (var group in groups)
|
||||
{
|
||||
var existing = _groupSettings.TryGetValue(group.Key, out var gs);
|
||||
var defaults = GroupDefaults(group, machine);
|
||||
|
||||
table.Rows.Add(
|
||||
group.Material,
|
||||
@@ -305,11 +307,11 @@ namespace OpenNest.Forms
|
||||
group.TotalQty,
|
||||
existing ? gs.PlateWidth : defaultWidth,
|
||||
existing ? gs.PlateLength : defaultLength,
|
||||
existing ? gs.PartSpacing : _defaults.PartSpacing,
|
||||
existing ? gs.EdgeLeft : _defaults.EdgeSpacing.Left,
|
||||
existing ? gs.EdgeBottom : _defaults.EdgeSpacing.Bottom,
|
||||
existing ? gs.EdgeRight : _defaults.EdgeSpacing.Right,
|
||||
existing ? gs.EdgeTop : _defaults.EdgeSpacing.Top
|
||||
existing ? gs.PartSpacing : defaults.PartSpacing,
|
||||
existing ? gs.EdgeLeft : defaults.EdgeSpacing.Left,
|
||||
existing ? gs.EdgeBottom : defaults.EdgeSpacing.Bottom,
|
||||
existing ? gs.EdgeRight : defaults.EdgeSpacing.Right,
|
||||
existing ? gs.EdgeTop : defaults.EdgeSpacing.Top
|
||||
);
|
||||
}
|
||||
|
||||
@@ -327,6 +329,15 @@ namespace OpenNest.Forms
|
||||
btnCreateNests.Enabled = table.Rows.Count > 0;
|
||||
}
|
||||
|
||||
// The saved defaults with the machine's spacing for the group's material and thickness.
|
||||
private NestDefaults GroupDefaults(BomImportGroup group, MachineConfig machine)
|
||||
{
|
||||
var nest = new Nest { Thickness = group.Thickness, Material = new Material(group.Material) };
|
||||
_defaults.ApplyTo(nest);
|
||||
MachineCuttingDefaults.ApplySpacingTo(nest, machine);
|
||||
return NestDefaults.FromNest(nest);
|
||||
}
|
||||
|
||||
private void SaveGroupSettings()
|
||||
{
|
||||
if (dgvGroups.DataSource is not DataTable table)
|
||||
@@ -416,15 +427,16 @@ namespace OpenNest.Forms
|
||||
{
|
||||
if (!_groupSettings.TryGetValue(group.Key, out var plate))
|
||||
{
|
||||
var defaults = GroupDefaults(group, machine);
|
||||
plate = new BomGroupPlateSettings
|
||||
{
|
||||
PlateWidth = defaultWidth,
|
||||
PlateLength = defaultLength,
|
||||
PartSpacing = _defaults.PartSpacing,
|
||||
EdgeLeft = _defaults.EdgeSpacing.Left,
|
||||
EdgeBottom = _defaults.EdgeSpacing.Bottom,
|
||||
EdgeRight = _defaults.EdgeSpacing.Right,
|
||||
EdgeTop = _defaults.EdgeSpacing.Top,
|
||||
PartSpacing = defaults.PartSpacing,
|
||||
EdgeLeft = defaults.EdgeSpacing.Left,
|
||||
EdgeBottom = defaults.EdgeSpacing.Bottom,
|
||||
EdgeRight = defaults.EdgeSpacing.Right,
|
||||
EdgeTop = defaults.EdgeSpacing.Top,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -826,7 +826,11 @@ namespace OpenNest.Forms
|
||||
|
||||
public async Task ShowNestInfoEditorAsync()
|
||||
{
|
||||
var form = new EditNestInfoForm { AllowRename = NestStorage.Settings.IsDatabaseMode };
|
||||
var form = new EditNestInfoForm
|
||||
{
|
||||
AllowRename = NestStorage.Settings.IsDatabaseMode,
|
||||
OfferNewNestDefaults = true,
|
||||
};
|
||||
form.SetMaterialCatalog(MachineSettings.LoadMaterials());
|
||||
form.LoadNestInfo(Nest);
|
||||
_ = ShowReleaseOriginAsync(form);
|
||||
@@ -843,13 +847,15 @@ namespace OpenNest.Forms
|
||||
using (var change = BeginChange("Nest Info"))
|
||||
{
|
||||
var before = UndoableNestInfo();
|
||||
PlateManager.ChangePlateDefaults(() => form.SaveNestInfo(Nest));
|
||||
MachineSettings.SaveNestInfo(PlateManager, form, Nest);
|
||||
if (UndoableNestInfo() != before)
|
||||
change.MarkChanged();
|
||||
// The material, thickness or units may have changed.
|
||||
MachineSettings.ApplyCutOffDefaults(PlateView, Nest);
|
||||
change.Complete();
|
||||
}
|
||||
if (form.UseForNewNests)
|
||||
MachineSettings.SaveNestDefaults(this, NestDefaults.FromNest(Nest), Nest.Machine);
|
||||
Text = Nest.Name;
|
||||
drawingListBox1.Units = Nest.Units;
|
||||
drawingListBox1.Invalidate();
|
||||
|
||||
+13
@@ -47,6 +47,7 @@
|
||||
this.partSpacingBox = new OpenNest.Controls.NumericUpDown();
|
||||
this.labelThk = new System.Windows.Forms.Label();
|
||||
this.groupBox3 = new System.Windows.Forms.GroupBox();
|
||||
this.useForNewNestsBox = new System.Windows.Forms.CheckBox();
|
||||
this.quadrantSelect1 = new OpenNest.Controls.QuadrantSelect();
|
||||
this.tabControl1 = new System.Windows.Forms.TabControl();
|
||||
this.tabPage1 = new System.Windows.Forms.TabPage();
|
||||
@@ -631,6 +632,7 @@
|
||||
//
|
||||
// tabPage2
|
||||
//
|
||||
this.tabPage2.Controls.Add(this.useForNewNestsBox);
|
||||
this.tabPage2.Controls.Add(this.groupBox3);
|
||||
this.tabPage2.Controls.Add(this.groupBox1);
|
||||
this.tabPage2.Controls.Add(this.tableLayoutPanel1);
|
||||
@@ -642,6 +644,16 @@
|
||||
this.tabPage2.Text = "Defaults";
|
||||
this.tabPage2.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// useForNewNestsBox
|
||||
//
|
||||
this.useForNewNestsBox.AutoSize = true;
|
||||
this.useForNewNestsBox.Location = new System.Drawing.Point(12, 288);
|
||||
this.useForNewNestsBox.Name = "useForNewNestsBox";
|
||||
this.useForNewNestsBox.TabIndex = 8;
|
||||
this.useForNewNestsBox.Text = "Use these defaults for new nests";
|
||||
this.useForNewNestsBox.UseVisualStyleBackColor = true;
|
||||
this.useForNewNestsBox.Visible = false;
|
||||
//
|
||||
// tabPage3
|
||||
//
|
||||
this.tabPage3.Controls.Add(this.notesBox);
|
||||
@@ -772,6 +784,7 @@
|
||||
private Controls.NumericUpDown partSpacingBox;
|
||||
private Controls.BottomPanel bottomPanel1;
|
||||
private System.Windows.Forms.GroupBox groupBox3;
|
||||
private System.Windows.Forms.CheckBox useForNewNestsBox;
|
||||
private Controls.QuadrantSelect quadrantSelect1;
|
||||
private System.Windows.Forms.Button applyButton;
|
||||
private System.Windows.Forms.Label releaseLabel;
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace OpenNest.Forms
|
||||
private DateTime dateLastModified;
|
||||
private List<MaterialConfig> materialCatalog = new();
|
||||
private string gradeMaterialKey = "";
|
||||
private bool offerNewNestDefaults;
|
||||
|
||||
public EditNestInfoForm()
|
||||
{
|
||||
@@ -58,6 +59,24 @@ namespace OpenNest.Forms
|
||||
set { nameBox.ReadOnly = !value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the Defaults tab's choice to also start new nests from these values. Hidden
|
||||
/// by default: the tab otherwise edits only this nest.
|
||||
/// </summary>
|
||||
public bool OfferNewNestDefaults
|
||||
{
|
||||
// Not read back from the box: Visible is false once the dialog has closed.
|
||||
get { return offerNewNestDefaults; }
|
||||
set
|
||||
{
|
||||
offerNewNestDefaults = value;
|
||||
useForNewNestsBox.Visible = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>The user chose to save the Defaults tab for new nests.</summary>
|
||||
public bool UseForNewNests => OfferNewNestDefaults && useForNewNestsBox.Checked;
|
||||
|
||||
/// <summary>
|
||||
/// The drawing set release this nest came from (Database mode), shown beside the
|
||||
/// buttons; blank for none.
|
||||
|
||||
@@ -621,6 +621,7 @@ namespace OpenNest.Forms
|
||||
tabs.TabPages.Add(CreateTab("Outside Cuts", BuildOutsideCutsTab(thickness)));
|
||||
tabs.TabPages.Add(CreateTab("Inside Cuts", BuildInsideCutsTab(thickness)));
|
||||
tabs.TabPages.Add(CreateTab("Cut Off", BuildCutOffTab(thickness.CutOff)));
|
||||
tabs.TabPages.Add(CreateTab("Spacing", BuildSpacingTab(thickness)));
|
||||
tabs.TabPages.Add(CreateTab("Plate Sizes", BuildPlateSizesTab(thickness)));
|
||||
RememberTab(tabs, _thicknessTab, t => _thicknessTab = t);
|
||||
|
||||
@@ -701,6 +702,76 @@ namespace OpenNest.Forms
|
||||
return panel;
|
||||
}
|
||||
|
||||
// Unchecked leaves the spacing to the nest defaults, so a thickness need not set both.
|
||||
private Control BuildSpacingTab(ThicknessConfig thickness)
|
||||
{
|
||||
var layout = CreateDetailLayout();
|
||||
var row = 0;
|
||||
|
||||
var partBox = new CheckBox
|
||||
{
|
||||
Text = "Use for this thickness",
|
||||
AutoSize = true,
|
||||
Checked = thickness.PartSpacing.HasValue,
|
||||
};
|
||||
var part = CreateNumericBox(thickness.PartSpacing ?? 0, v =>
|
||||
{
|
||||
thickness.PartSpacing = partBox.Checked ? v : null;
|
||||
MarkDirty();
|
||||
}, 4, 1000, 0.0625m);
|
||||
part.Enabled = partBox.Checked;
|
||||
partBox.CheckedChanged += (s, e) =>
|
||||
{
|
||||
part.Enabled = partBox.Checked;
|
||||
thickness.PartSpacing = partBox.Checked ? (double)part.Value : null;
|
||||
MarkDirty();
|
||||
};
|
||||
AddField(layout, ref row, "Part Spacing:", partBox);
|
||||
AddField(layout, ref row, $"Spacing ({LengthUnitSuffix(null)}):", part);
|
||||
|
||||
var edge = thickness.EdgeSpacing;
|
||||
var edgeBox = new CheckBox
|
||||
{
|
||||
Text = "Use for this thickness",
|
||||
AutoSize = true,
|
||||
Checked = edge != null,
|
||||
};
|
||||
var sides = new NumericUpDown[4];
|
||||
void StoreEdge()
|
||||
{
|
||||
thickness.EdgeSpacing = edgeBox.Checked
|
||||
? new EdgeSpacingConfig
|
||||
{
|
||||
Left = (double)sides[0].Value,
|
||||
Bottom = (double)sides[1].Value,
|
||||
Right = (double)sides[2].Value,
|
||||
Top = (double)sides[3].Value,
|
||||
}
|
||||
: null;
|
||||
MarkDirty();
|
||||
}
|
||||
AddField(layout, ref row, "Edge Spacing:", edgeBox);
|
||||
var values = new[] { edge?.Left ?? 0, edge?.Bottom ?? 0, edge?.Right ?? 0, edge?.Top ?? 0 };
|
||||
var labels = new[] { "Left", "Bottom", "Right", "Top" }
|
||||
.Select(side => $"{side} ({LengthUnitSuffix(null)}):").ToArray();
|
||||
for (var i = 0; i < sides.Length; i++)
|
||||
{
|
||||
sides[i] = CreateNumericBox(values[i], _ => StoreEdge(), 4, 1000, 0.0625m);
|
||||
sides[i].Enabled = edgeBox.Checked;
|
||||
AddField(layout, ref row, labels[i], sides[i]);
|
||||
}
|
||||
edgeBox.CheckedChanged += (s, e) =>
|
||||
{
|
||||
foreach (var side in sides)
|
||||
side.Enabled = edgeBox.Checked;
|
||||
StoreEdge();
|
||||
};
|
||||
|
||||
var panel = new Panel { Dock = DockStyle.Fill, Padding = new Padding(10) };
|
||||
panel.Controls.Add(layout);
|
||||
return panel;
|
||||
}
|
||||
|
||||
private Control BuildOutsideCutsTab(ThicknessConfig thickness)
|
||||
{
|
||||
var editor = CreateLeadsEditor(CNC.CuttingStrategy.ContourType.External);
|
||||
|
||||
@@ -241,6 +241,14 @@ namespace OpenNest.Forms
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a Nest Info dialog to <paramref name="nest"/>: a changed material or thickness
|
||||
/// takes the machine's spacing, and an untouched trailing sheet follows the new defaults.
|
||||
/// </summary>
|
||||
public static void SaveNestInfo(PlateManager manager, EditNestInfoForm form, Nest nest) =>
|
||||
manager.ChangePlateDefaults(() => MachineCuttingDefaults.ApplySpacingAfter(
|
||||
nest, FindMachine(nest.Machine), () => form.SaveNestInfo(nest)));
|
||||
|
||||
/// <summary>
|
||||
/// Gives <paramref name="view"/> the cut-off clearance, overtravel, minimum segment and
|
||||
/// direction of the nest's machine for its material and thickness, when the machine has
|
||||
@@ -317,6 +325,30 @@ namespace OpenNest.Forms
|
||||
defaults.Save(NestDefaults.DefaultPath);
|
||||
}
|
||||
|
||||
/// <summary>Saves the nest defaults, telling the user when they could not be saved.</summary>
|
||||
public static void SaveNestDefaults(IWin32Window owner, NestDefaults defaults)
|
||||
{
|
||||
try
|
||||
{
|
||||
SaveNestDefaults(defaults);
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
|
||||
{
|
||||
MessageBox.Show(owner, "The nest defaults could not be saved.\n\n" + ex.Message, "Nest Defaults",
|
||||
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes values taken from an open nest the defaults new nests start from. The nest's
|
||||
/// machine becomes the default; a nest without one keeps the saved choice.
|
||||
/// </summary>
|
||||
public static void SaveNestDefaults(IWin32Window owner, NestDefaults defaults, NestMachine machine)
|
||||
{
|
||||
defaults.MachineId = machine?.Id ?? LoadSavedNestDefaults(out _).MachineId;
|
||||
SaveNestDefaults(owner, defaults);
|
||||
}
|
||||
|
||||
private static SharedSettingRecord SharedNestDefaults() =>
|
||||
SharedSettings.Find(SharedSettingKinds.NestDefaults, SharedSettingKinds.DefaultKey);
|
||||
}
|
||||
|
||||
@@ -79,8 +79,9 @@ namespace OpenNest.Forms
|
||||
items.Add(new ToolStripMenuItem("(no machines; see Tools > Machine Configuration)") { Enabled = false });
|
||||
}
|
||||
|
||||
// Assigning a machine also puts every sheet on that machine's support grid and gives
|
||||
// the views its cut-off settings; plates' own cutting parameters are kept.
|
||||
// Assigning a machine also puts every sheet on that machine's support grid, gives the
|
||||
// views its cut-off settings and the nest its spacing; plates' own cutting parameters are
|
||||
// kept, and of the sheets only an untouched trailing one takes the spacing.
|
||||
private void AssignMachine(MachineConfig machine)
|
||||
{
|
||||
var editForm = activeForm;
|
||||
@@ -101,6 +102,7 @@ namespace OpenNest.Forms
|
||||
MachineSettings.AssignMachine(nest, machine);
|
||||
foreach (var view in views)
|
||||
MachineSettings.ApplyCutOffDefaults(view, nest);
|
||||
editForm.PlateManager.ChangePlateDefaults(() => MachineCuttingDefaults.ApplySpacingTo(nest, machine));
|
||||
});
|
||||
foreach (var view in views)
|
||||
view.Invalidate();
|
||||
|
||||
@@ -9,7 +9,12 @@ namespace OpenNest.Forms
|
||||
{
|
||||
#region Plate Menu Events
|
||||
|
||||
private void SetAsNestDefault_Click(object sender, EventArgs e) => WithActive(f => f.SetCurrentPlateAsNestDefault());
|
||||
// Both this nest's next plates and every new nest start from the current plate.
|
||||
private void SetAsNestDefault_Click(object sender, EventArgs e)
|
||||
{
|
||||
WithActive(f => f.SetCurrentPlateAsNestDefault());
|
||||
SaveCurrentAsDefaults_Click(sender, e);
|
||||
}
|
||||
|
||||
private void AddPlate_Click(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using OpenNest.Actions;
|
||||
using OpenNest.Data;
|
||||
@@ -185,20 +184,7 @@ namespace OpenNest.Forms
|
||||
using (var form = new NestDefaultsForm(defaults, MachineSettings.LoadMachines(), SharedSettings.NestDefaultsSource()))
|
||||
{
|
||||
if (form.ShowDialog(this) == DialogResult.OK)
|
||||
SaveNestDefaults(form.GetDefaults());
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveNestDefaults(NestDefaults defaults)
|
||||
{
|
||||
try
|
||||
{
|
||||
MachineSettings.SaveNestDefaults(defaults);
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
|
||||
{
|
||||
MessageBox.Show(this, "The nest defaults could not be saved.\n\n" + ex.Message, "Nest Defaults",
|
||||
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
MachineSettings.SaveNestDefaults(this, form.GetDefaults());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,10 +193,8 @@ namespace OpenNest.Forms
|
||||
if (activeForm == null)
|
||||
return;
|
||||
|
||||
var defaults = NestDefaults.FromPlate(activeForm.Nest.Units, activeForm.PlateView.Plate);
|
||||
// The nest's machine becomes the default; a nest without one keeps the saved choice.
|
||||
defaults.MachineId = activeForm.Nest.Machine?.Id ?? MachineSettings.LoadSavedNestDefaults(out _).MachineId;
|
||||
SaveNestDefaults(defaults);
|
||||
MachineSettings.SaveNestDefaults(this, NestDefaults.FromPlate(activeForm.Nest.Units, activeForm.PlateView.Plate),
|
||||
activeForm.Nest.Machine);
|
||||
}
|
||||
|
||||
private void MachineConfig_Click(object sender, EventArgs e)
|
||||
|
||||
@@ -19,13 +19,14 @@ namespace OpenNest.Forms
|
||||
{
|
||||
private static readonly TimeSpan ServerTimeout = TimeSpan.FromSeconds(3);
|
||||
|
||||
/// <param name="units">
|
||||
/// The new nest's units, with the saved plate defaults converted to them (a drawing set
|
||||
/// release group drawn in other units); null uses the defaults as saved.
|
||||
/// <param name="release">
|
||||
/// The drawing set release group the nest is for: its units, with the saved plate
|
||||
/// defaults converted to them, its material and thickness, and the machine's spacing for
|
||||
/// those. Null uses the defaults as saved.
|
||||
/// </param>
|
||||
public static async Task<Nest> CreateAsync(IWin32Window owner, Units? units = null)
|
||||
public static async Task<Nest> CreateAsync(IWin32Window owner, SetReleaseGroup release = null)
|
||||
{
|
||||
var nest = CreateDefaultNest(owner, units);
|
||||
var nest = CreateDefaultNest(release);
|
||||
var now = DateTime.Now;
|
||||
|
||||
nest.DateCreated = now;
|
||||
@@ -34,15 +35,21 @@ namespace OpenNest.Forms
|
||||
return nest;
|
||||
}
|
||||
|
||||
private static Nest CreateDefaultNest(IWin32Window owner, Units? units)
|
||||
private static Nest CreateDefaultNest(SetReleaseGroup release)
|
||||
{
|
||||
var nest = new Nest();
|
||||
var defaults = MachineSettings.LoadNestDefaults();
|
||||
(units is { } converted ? defaults.ConvertedTo(converted) : defaults).ApplyTo(nest);
|
||||
(release != null ? defaults.ConvertedTo(release.Units) : defaults).ApplyTo(nest);
|
||||
// After the defaults so the rail and grid are converted to the new nest's units.
|
||||
var machine = MachineSettings.DefaultMachine(defaults, MachineSettings.LoadMachines());
|
||||
MachineSettings.LoadClampSettings(machine).ApplyToNewNest(nest);
|
||||
MachineSettings.AssignMachine(nest, machine);
|
||||
if (release != null)
|
||||
{
|
||||
nest.Material = new Material(release.MaterialName, release.MaterialGrade);
|
||||
nest.Thickness = release.Thickness;
|
||||
MachineCuttingDefaults.ApplySpacingTo(nest, machine);
|
||||
}
|
||||
return nest;
|
||||
}
|
||||
|
||||
|
||||
@@ -872,7 +872,7 @@ public sealed class SavedNestsForm : Form
|
||||
}
|
||||
// Same default propagation as Nest > Nest Info in the open editor.
|
||||
using var manager = new PlateManager(nest);
|
||||
manager.ChangePlateDefaults(() => dialog.SaveNestInfo(nest));
|
||||
MachineSettings.SaveNestInfo(manager, dialog, nest);
|
||||
nest.DateLastModified = DateTime.Now;
|
||||
summaryLabel.Text = "Saving nest information...";
|
||||
var bytes = await Task.Run(() =>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Machine cutting defaults
|
||||
|
||||
A nest's assigned machine (`Nest.Machine`, see [nest file format](nest-file-format.md))
|
||||
supplies the starting lead-ins, lead-outs, kerf and cut-off settings for the nest's
|
||||
supplies the starting lead-ins, lead-outs, kerf, cut-off settings and spacing for the nest's
|
||||
material and thickness, from that machine's Tools > Machine Configuration entry (in
|
||||
Database mode, the server's [shared machines](shared-settings.md) once it holds them).
|
||||
`MachineCuttingDefaults` (OpenNest.Data) holds the mapping; the desktop applies it.
|
||||
@@ -47,6 +47,16 @@ which comes from the thickness). Types map as follows:
|
||||
|
||||
Lead-outs map None, Line (length, angle) and Arc (radius); any other type is none.
|
||||
|
||||
## Spacing
|
||||
|
||||
Each thickness can set a part spacing and an edge spacing (the Spacing tab), each optional:
|
||||
one left unset stays at the nest defaults' value. The machine's spacing replaces the nest's
|
||||
plate defaults when Nest > Edit or Nest Information changes the material, grade or thickness
|
||||
(a spacing edited in the same dialog stays), when Nest > Machine changes the machine, and when a
|
||||
drawing set release creates a nest. BOM import starts each group's row from it. File > New has
|
||||
no material yet, so a new nest starts from the nest defaults. Plates are kept as they are, except
|
||||
an untouched trailing empty sheet, which follows the plate defaults.
|
||||
|
||||
## Cut-offs
|
||||
|
||||
The plate view's part clearance, overtravel, minimum segment length and direction come from
|
||||
|
||||
@@ -13,6 +13,10 @@ building nests and posts the same way:
|
||||
|
||||
File mode, the console, MCP and API front ends use only this PC's copies.
|
||||
|
||||
Nest defaults are saved by Tools > Nest Defaults, Tools > Save Current Plate as Defaults,
|
||||
Plate > Set as Default, and Nest > Edit's Defaults tab with "Use these defaults for new nests"
|
||||
checked. Without that check the tab changes only the open nest.
|
||||
|
||||
## Which copy is used
|
||||
|
||||
Each kind is read from the server once the server holds it, and from this PC's copy until
|
||||
|
||||
Reference in new issue
Block a user