feat: use nest template for BOM import spacing defaults, editable per group
BOM import now loads the nest template to populate plate size, part spacing, edge spacing, and quadrant instead of hard-coding defaults. Spacing columns are shown per material+thickness group on the Groups tab so each combo can be adjusted independently. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
84
OpenNest/Forms/BomImportForm.Designer.cs
generated
84
OpenNest/Forms/BomImportForm.Designer.cs
generated
@@ -50,9 +50,9 @@ namespace OpenNest.Forms
|
||||
((System.ComponentModel.ISupportInitialize)dgvGroups).BeginInit();
|
||||
pnlBottom.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
//
|
||||
// grpInput
|
||||
//
|
||||
//
|
||||
grpInput.Controls.Add(tbl);
|
||||
grpInput.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
grpInput.Location = new System.Drawing.Point(0, 0);
|
||||
@@ -62,9 +62,9 @@ namespace OpenNest.Forms
|
||||
grpInput.TabIndex = 0;
|
||||
grpInput.TabStop = false;
|
||||
grpInput.Text = "Input";
|
||||
//
|
||||
//
|
||||
// tbl
|
||||
//
|
||||
//
|
||||
tbl.ColumnCount = 3;
|
||||
tbl.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
tbl.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
@@ -92,9 +92,9 @@ namespace OpenNest.Forms
|
||||
tbl.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
tbl.Size = new System.Drawing.Size(792, 172);
|
||||
tbl.TabIndex = 0;
|
||||
//
|
||||
//
|
||||
// lblJobName
|
||||
//
|
||||
//
|
||||
lblJobName.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
lblJobName.AutoSize = true;
|
||||
lblJobName.Location = new System.Drawing.Point(6, 13);
|
||||
@@ -103,9 +103,9 @@ namespace OpenNest.Forms
|
||||
lblJobName.Size = new System.Drawing.Size(63, 15);
|
||||
lblJobName.TabIndex = 0;
|
||||
lblJobName.Text = "Job Name:";
|
||||
//
|
||||
//
|
||||
// txtJobName
|
||||
//
|
||||
//
|
||||
tbl.SetColumnSpan(txtJobName, 2);
|
||||
txtJobName.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
txtJobName.Location = new System.Drawing.Point(79, 9);
|
||||
@@ -113,9 +113,9 @@ namespace OpenNest.Forms
|
||||
txtJobName.Name = "txtJobName";
|
||||
txtJobName.Size = new System.Drawing.Size(707, 23);
|
||||
txtJobName.TabIndex = 1;
|
||||
//
|
||||
//
|
||||
// lblBomFile
|
||||
//
|
||||
//
|
||||
lblBomFile.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
lblBomFile.AutoSize = true;
|
||||
lblBomFile.Location = new System.Drawing.Point(6, 45);
|
||||
@@ -124,9 +124,9 @@ namespace OpenNest.Forms
|
||||
lblBomFile.Size = new System.Drawing.Size(58, 15);
|
||||
lblBomFile.TabIndex = 2;
|
||||
lblBomFile.Text = "BOM File:";
|
||||
//
|
||||
//
|
||||
// txtBomFile
|
||||
//
|
||||
//
|
||||
txtBomFile.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
txtBomFile.Location = new System.Drawing.Point(79, 41);
|
||||
txtBomFile.Margin = new System.Windows.Forms.Padding(3, 6, 3, 3);
|
||||
@@ -134,9 +134,9 @@ namespace OpenNest.Forms
|
||||
txtBomFile.ReadOnly = true;
|
||||
txtBomFile.Size = new System.Drawing.Size(669, 23);
|
||||
txtBomFile.TabIndex = 3;
|
||||
//
|
||||
//
|
||||
// btnBrowseBom
|
||||
//
|
||||
//
|
||||
btnBrowseBom.Location = new System.Drawing.Point(751, 40);
|
||||
btnBrowseBom.Margin = new System.Windows.Forms.Padding(0, 5, 3, 3);
|
||||
btnBrowseBom.Name = "btnBrowseBom";
|
||||
@@ -144,9 +144,9 @@ namespace OpenNest.Forms
|
||||
btnBrowseBom.TabIndex = 4;
|
||||
btnBrowseBom.Text = "...";
|
||||
btnBrowseBom.Click += BrowseBom_Click;
|
||||
//
|
||||
//
|
||||
// lblDxfFolder
|
||||
//
|
||||
//
|
||||
lblDxfFolder.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
lblDxfFolder.AutoSize = true;
|
||||
lblDxfFolder.Location = new System.Drawing.Point(6, 78);
|
||||
@@ -155,9 +155,9 @@ namespace OpenNest.Forms
|
||||
lblDxfFolder.Size = new System.Drawing.Size(67, 15);
|
||||
lblDxfFolder.TabIndex = 5;
|
||||
lblDxfFolder.Text = "DXF Folder:";
|
||||
//
|
||||
//
|
||||
// txtDxfFolder
|
||||
//
|
||||
//
|
||||
txtDxfFolder.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
txtDxfFolder.Location = new System.Drawing.Point(79, 74);
|
||||
txtDxfFolder.Margin = new System.Windows.Forms.Padding(3, 6, 3, 3);
|
||||
@@ -165,9 +165,9 @@ namespace OpenNest.Forms
|
||||
txtDxfFolder.ReadOnly = true;
|
||||
txtDxfFolder.Size = new System.Drawing.Size(669, 23);
|
||||
txtDxfFolder.TabIndex = 6;
|
||||
//
|
||||
//
|
||||
// btnBrowseDxf
|
||||
//
|
||||
//
|
||||
btnBrowseDxf.Location = new System.Drawing.Point(751, 73);
|
||||
btnBrowseDxf.Margin = new System.Windows.Forms.Padding(0, 5, 3, 3);
|
||||
btnBrowseDxf.Name = "btnBrowseDxf";
|
||||
@@ -175,9 +175,9 @@ namespace OpenNest.Forms
|
||||
btnBrowseDxf.TabIndex = 7;
|
||||
btnBrowseDxf.Text = "...";
|
||||
btnBrowseDxf.Click += BrowseDxf_Click;
|
||||
//
|
||||
//
|
||||
// lblPlateSize
|
||||
//
|
||||
//
|
||||
lblPlateSize.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
lblPlateSize.AutoSize = true;
|
||||
lblPlateSize.Location = new System.Drawing.Point(6, 112);
|
||||
@@ -186,9 +186,9 @@ namespace OpenNest.Forms
|
||||
lblPlateSize.Size = new System.Drawing.Size(59, 15);
|
||||
lblPlateSize.TabIndex = 8;
|
||||
lblPlateSize.Text = "Plate Size:";
|
||||
//
|
||||
//
|
||||
// platePanel
|
||||
//
|
||||
//
|
||||
platePanel.AutoSize = true;
|
||||
platePanel.Controls.Add(txtPlateWidth);
|
||||
platePanel.Controls.Add(lblPlateX);
|
||||
@@ -199,17 +199,17 @@ namespace OpenNest.Forms
|
||||
platePanel.Size = new System.Drawing.Size(156, 29);
|
||||
platePanel.TabIndex = 9;
|
||||
platePanel.WrapContents = false;
|
||||
//
|
||||
//
|
||||
// txtPlateWidth
|
||||
//
|
||||
//
|
||||
txtPlateWidth.Location = new System.Drawing.Point(3, 3);
|
||||
txtPlateWidth.Name = "txtPlateWidth";
|
||||
txtPlateWidth.Size = new System.Drawing.Size(60, 23);
|
||||
txtPlateWidth.TabIndex = 0;
|
||||
txtPlateWidth.Text = "60";
|
||||
//
|
||||
//
|
||||
// lblPlateX
|
||||
//
|
||||
//
|
||||
lblPlateX.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
lblPlateX.AutoSize = true;
|
||||
lblPlateX.Location = new System.Drawing.Point(69, 7);
|
||||
@@ -217,17 +217,17 @@ namespace OpenNest.Forms
|
||||
lblPlateX.Size = new System.Drawing.Size(18, 15);
|
||||
lblPlateX.TabIndex = 1;
|
||||
lblPlateX.Text = " x ";
|
||||
//
|
||||
//
|
||||
// txtPlateLength
|
||||
//
|
||||
//
|
||||
txtPlateLength.Location = new System.Drawing.Point(93, 3);
|
||||
txtPlateLength.Name = "txtPlateLength";
|
||||
txtPlateLength.Size = new System.Drawing.Size(60, 23);
|
||||
txtPlateLength.TabIndex = 2;
|
||||
txtPlateLength.Text = "120";
|
||||
//
|
||||
//
|
||||
// btnAnalyze
|
||||
//
|
||||
//
|
||||
btnAnalyze.Anchor = System.Windows.Forms.AnchorStyles.Right;
|
||||
tbl.SetColumnSpan(btnAnalyze, 2);
|
||||
btnAnalyze.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
|
||||
@@ -291,9 +291,9 @@ namespace OpenNest.Forms
|
||||
dgvGroups.RowHeadersVisible = false;
|
||||
dgvGroups.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
|
||||
dgvGroups.TabIndex = 0;
|
||||
//
|
||||
//
|
||||
// pnlBottom
|
||||
//
|
||||
//
|
||||
pnlBottom.Controls.Add(lblSummary);
|
||||
pnlBottom.Controls.Add(btnCreateNests);
|
||||
pnlBottom.Controls.Add(btnClose);
|
||||
@@ -303,9 +303,9 @@ namespace OpenNest.Forms
|
||||
pnlBottom.Padding = new System.Windows.Forms.Padding(10);
|
||||
pnlBottom.Size = new System.Drawing.Size(804, 50);
|
||||
pnlBottom.TabIndex = 2;
|
||||
//
|
||||
//
|
||||
// lblSummary
|
||||
//
|
||||
//
|
||||
lblSummary.AutoSize = true;
|
||||
lblSummary.Dock = System.Windows.Forms.DockStyle.Left;
|
||||
lblSummary.ForeColor = System.Drawing.Color.Gray;
|
||||
@@ -314,9 +314,9 @@ namespace OpenNest.Forms
|
||||
lblSummary.Size = new System.Drawing.Size(0, 15);
|
||||
lblSummary.TabIndex = 0;
|
||||
lblSummary.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
//
|
||||
// btnCreateNests
|
||||
//
|
||||
//
|
||||
btnCreateNests.Dock = System.Windows.Forms.DockStyle.Right;
|
||||
btnCreateNests.Enabled = false;
|
||||
btnCreateNests.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
|
||||
@@ -327,9 +327,9 @@ namespace OpenNest.Forms
|
||||
btnCreateNests.TabIndex = 1;
|
||||
btnCreateNests.Text = "Create Nests";
|
||||
btnCreateNests.Click += CreateNests_Click;
|
||||
//
|
||||
//
|
||||
// btnClose
|
||||
//
|
||||
//
|
||||
btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
btnClose.Dock = System.Windows.Forms.DockStyle.Right;
|
||||
btnClose.Location = new System.Drawing.Point(714, 10);
|
||||
@@ -338,9 +338,9 @@ namespace OpenNest.Forms
|
||||
btnClose.TabIndex = 2;
|
||||
btnClose.Text = "Close";
|
||||
btnClose.Click += BtnClose_Click;
|
||||
//
|
||||
//
|
||||
// BomImportForm
|
||||
//
|
||||
//
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
CancelButton = btnClose;
|
||||
|
||||
@@ -16,8 +16,9 @@ namespace OpenNest.Forms
|
||||
public partial class BomImportForm : Form
|
||||
{
|
||||
private List<BomPartRow> _parts;
|
||||
private Dictionary<string, (double Width, double Length)> _plateSizes;
|
||||
private Dictionary<string, GroupSettings> _groupSettings;
|
||||
private bool _suppressRegroup;
|
||||
private Nest.PlateSettings _templateDefaults;
|
||||
|
||||
public Form MdiParentForm { get; set; }
|
||||
|
||||
@@ -25,7 +26,38 @@ namespace OpenNest.Forms
|
||||
{
|
||||
InitializeComponent();
|
||||
_parts = new List<BomPartRow>();
|
||||
_plateSizes = new Dictionary<string, (double, double)>();
|
||||
_groupSettings = new Dictionary<string, GroupSettings>();
|
||||
_templateDefaults = LoadTemplateDefaults();
|
||||
ApplyTemplateDefaults();
|
||||
}
|
||||
|
||||
private Nest.PlateSettings LoadTemplateDefaults()
|
||||
{
|
||||
var templatePath = Properties.Settings.Default.NestTemplatePath;
|
||||
if (File.Exists(templatePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
var nest = new NestReader(templatePath).Read();
|
||||
return nest.PlateDefaults;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
// Fallback defaults matching CreateDefaultNest
|
||||
return new Nest.PlateSettings
|
||||
{
|
||||
Size = new Geometry.Size(100, 100),
|
||||
Quadrant = 1,
|
||||
PartSpacing = 1,
|
||||
EdgeSpacing = new Spacing(1, 1, 1, 1),
|
||||
};
|
||||
}
|
||||
|
||||
private void ApplyTemplateDefaults()
|
||||
{
|
||||
txtPlateWidth.Text = _templateDefaults.Size.Width.ToString("0.####");
|
||||
txtPlateLength.Text = _templateDefaults.Size.Length.ToString("0.####");
|
||||
}
|
||||
|
||||
#region File Browsing
|
||||
@@ -154,7 +186,7 @@ namespace OpenNest.Forms
|
||||
_parts.Add(row);
|
||||
}
|
||||
|
||||
_plateSizes.Clear();
|
||||
_groupSettings.Clear();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -244,11 +276,11 @@ namespace OpenNest.Forms
|
||||
|
||||
private void RebuildGroups()
|
||||
{
|
||||
// Save existing plate sizes before rebuilding
|
||||
SavePlateSizes();
|
||||
// Save existing settings before rebuilding
|
||||
SaveGroupSettings();
|
||||
|
||||
var defaultWidth = double.TryParse(txtPlateWidth.Text, out var w) ? w : 60;
|
||||
var defaultLength = double.TryParse(txtPlateLength.Text, out var l) ? l : 120;
|
||||
var defaultWidth = double.TryParse(txtPlateWidth.Text, out var w) ? w : _templateDefaults.Size.Width;
|
||||
var defaultLength = double.TryParse(txtPlateLength.Text, out var l) ? l : _templateDefaults.Size.Length;
|
||||
|
||||
var groups = _parts
|
||||
.Where(p => p.IsEditable
|
||||
@@ -270,6 +302,11 @@ namespace OpenNest.Forms
|
||||
table.Columns.Add("Total Qty", typeof(int));
|
||||
table.Columns.Add("Plate Width", typeof(double));
|
||||
table.Columns.Add("Plate Length", typeof(double));
|
||||
table.Columns.Add("Part Spacing", typeof(double));
|
||||
table.Columns.Add("Edge Left", typeof(double));
|
||||
table.Columns.Add("Edge Bottom", typeof(double));
|
||||
table.Columns.Add("Edge Right", typeof(double));
|
||||
table.Columns.Add("Edge Top", typeof(double));
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
@@ -277,23 +314,27 @@ namespace OpenNest.Forms
|
||||
var thickness = group.Key.Thickness;
|
||||
var key = GroupKey(material, thickness);
|
||||
|
||||
var plateWidth = _plateSizes.TryGetValue(key, out var size) ? size.Width : defaultWidth;
|
||||
var plateLength = _plateSizes.TryGetValue(key, out _) ? size.Length : defaultLength;
|
||||
var existing = _groupSettings.TryGetValue(key, out var gs);
|
||||
|
||||
table.Rows.Add(
|
||||
material,
|
||||
thickness,
|
||||
group.Count(),
|
||||
group.Sum(p => p.Qty ?? 0),
|
||||
plateWidth,
|
||||
plateLength
|
||||
existing ? gs.PlateWidth : defaultWidth,
|
||||
existing ? gs.PlateLength : defaultLength,
|
||||
existing ? gs.PartSpacing : _templateDefaults.PartSpacing,
|
||||
existing ? gs.EdgeLeft : _templateDefaults.EdgeSpacing.Left,
|
||||
existing ? gs.EdgeBottom : _templateDefaults.EdgeSpacing.Bottom,
|
||||
existing ? gs.EdgeRight : _templateDefaults.EdgeSpacing.Right,
|
||||
existing ? gs.EdgeTop : _templateDefaults.EdgeSpacing.Top
|
||||
);
|
||||
}
|
||||
|
||||
dgvGroups.DataSource = table;
|
||||
|
||||
// Material, Thickness, Parts, Total Qty are read-only
|
||||
if (dgvGroups.Columns.Count >= 6)
|
||||
if (dgvGroups.Columns.Count > 0)
|
||||
{
|
||||
dgvGroups.Columns["Material"].ReadOnly = true;
|
||||
dgvGroups.Columns["Thickness"].ReadOnly = true;
|
||||
@@ -304,22 +345,28 @@ namespace OpenNest.Forms
|
||||
btnCreateNests.Enabled = table.Rows.Count > 0;
|
||||
}
|
||||
|
||||
private void SavePlateSizes()
|
||||
private void SaveGroupSettings()
|
||||
{
|
||||
if (dgvGroups.DataSource is not DataTable table)
|
||||
return;
|
||||
|
||||
_plateSizes.Clear();
|
||||
_groupSettings.Clear();
|
||||
foreach (DataRow row in table.Rows)
|
||||
{
|
||||
var material = row["Material"]?.ToString() ?? "";
|
||||
var thickness = row["Thickness"] is double t ? t : 0;
|
||||
var key = GroupKey(material, thickness);
|
||||
|
||||
var width = row["Plate Width"] is double pw ? pw : 60;
|
||||
var length = row["Plate Length"] is double pl ? pl : 120;
|
||||
|
||||
_plateSizes[key] = (width, length);
|
||||
_groupSettings[key] = new GroupSettings
|
||||
{
|
||||
PlateWidth = row["Plate Width"] is double pw ? pw : _templateDefaults.Size.Width,
|
||||
PlateLength = row["Plate Length"] is double pl ? pl : _templateDefaults.Size.Length,
|
||||
PartSpacing = row["Part Spacing"] is double ps ? ps : _templateDefaults.PartSpacing,
|
||||
EdgeLeft = row["Edge Left"] is double el ? el : _templateDefaults.EdgeSpacing.Left,
|
||||
EdgeBottom = row["Edge Bottom"] is double eb ? eb : _templateDefaults.EdgeSpacing.Bottom,
|
||||
EdgeRight = row["Edge Right"] is double er ? er : _templateDefaults.EdgeSpacing.Right,
|
||||
EdgeTop = row["Edge Top"] is double et ? et : _templateDefaults.EdgeSpacing.Top,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,11 +403,11 @@ namespace OpenNest.Forms
|
||||
if (_parts == null || _parts.Count == 0)
|
||||
return;
|
||||
|
||||
// Save latest plate size edits
|
||||
SavePlateSizes();
|
||||
// Save latest group edits
|
||||
SaveGroupSettings();
|
||||
|
||||
var defaultWidth = double.TryParse(txtPlateWidth.Text, out var dw) ? dw : 60;
|
||||
var defaultLength = double.TryParse(txtPlateLength.Text, out var dl) ? dl : 120;
|
||||
var defaultWidth = double.TryParse(txtPlateWidth.Text, out var dw) ? dw : _templateDefaults.Size.Width;
|
||||
var defaultLength = double.TryParse(txtPlateLength.Text, out var dl) ? dl : _templateDefaults.Size.Length;
|
||||
|
||||
var groups = _parts
|
||||
.Where(p => p.IsEditable
|
||||
@@ -391,8 +438,14 @@ namespace OpenNest.Forms
|
||||
var thickness = group.Key.Thickness;
|
||||
var key = GroupKey(material, thickness);
|
||||
|
||||
var plateWidth = _plateSizes.TryGetValue(key, out var size) ? size.Width : defaultWidth;
|
||||
var plateLength = _plateSizes.TryGetValue(key, out _) ? size.Length : defaultLength;
|
||||
var hasSettings = _groupSettings.TryGetValue(key, out var gs);
|
||||
var plateWidth = hasSettings ? gs.PlateWidth : defaultWidth;
|
||||
var plateLength = hasSettings ? gs.PlateLength : defaultLength;
|
||||
var partSpacing = hasSettings ? gs.PartSpacing : _templateDefaults.PartSpacing;
|
||||
var edgeLeft = hasSettings ? gs.EdgeLeft : _templateDefaults.EdgeSpacing.Left;
|
||||
var edgeBottom = hasSettings ? gs.EdgeBottom : _templateDefaults.EdgeSpacing.Bottom;
|
||||
var edgeRight = hasSettings ? gs.EdgeRight : _templateDefaults.EdgeSpacing.Right;
|
||||
var edgeTop = hasSettings ? gs.EdgeTop : _templateDefaults.EdgeSpacing.Top;
|
||||
|
||||
var nestName = $"{jobName} - {thickness:0.###} {material}";
|
||||
var nest = new Nest(nestName);
|
||||
@@ -401,9 +454,9 @@ namespace OpenNest.Forms
|
||||
nest.PlateDefaults.Size = new Geometry.Size(plateWidth, plateLength);
|
||||
nest.Thickness = thickness;
|
||||
nest.Material = new Material(material);
|
||||
nest.PlateDefaults.Quadrant = 1;
|
||||
nest.PlateDefaults.PartSpacing = 1;
|
||||
nest.PlateDefaults.EdgeSpacing = new Spacing(1, 1, 1, 1);
|
||||
nest.PlateDefaults.Quadrant = _templateDefaults.Quadrant;
|
||||
nest.PlateDefaults.PartSpacing = partSpacing;
|
||||
nest.PlateDefaults.EdgeSpacing = new Spacing(edgeLeft, edgeBottom, edgeRight, edgeTop);
|
||||
|
||||
foreach (var part in group)
|
||||
{
|
||||
@@ -486,4 +539,15 @@ namespace OpenNest.Forms
|
||||
public string Status { get; set; }
|
||||
public bool IsEditable { get; set; }
|
||||
}
|
||||
|
||||
internal class GroupSettings
|
||||
{
|
||||
public double PlateWidth { get; set; }
|
||||
public double PlateLength { get; set; }
|
||||
public double PartSpacing { get; set; }
|
||||
public double EdgeLeft { get; set; }
|
||||
public double EdgeBottom { get; set; }
|
||||
public double EdgeRight { get; set; }
|
||||
public double EdgeTop { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user