From 28d53e6d38765edb396204ea3d9b326bf64043d6 Mon Sep 17 00:00:00 2001 From: AJ Date: Tue, 5 Oct 2021 09:03:14 -0400 Subject: [PATCH] Multi-bin nesting --- CutList/CutList.csproj | 3 + CutList/Forms/MainForm.Designer.cs | 267 ++++++++++++------ CutList/Forms/MainForm.cs | 105 +++---- CutList/Forms/MainForm.resx | 6 + CutList/Helper.cs | 32 +++ CutList/Models/BinInputItem.cs | 66 +++++ CutList/Models/Item.cs | 8 - .../CutList.Models.BinInputItem.datasource | 10 + SawCut/MultiBin.cs | 11 + SawCut/Nesting/BestFitEngine.cs | 19 +- SawCut/Nesting/Engine2.cs | 14 +- SawCut/Nesting/MultiBinEngine.cs | 70 +++++ SawCut/Nesting/Result.cs | 1 + SawCut/SawCut.csproj | 2 + 14 files changed, 439 insertions(+), 175 deletions(-) create mode 100644 CutList/Helper.cs create mode 100644 CutList/Models/BinInputItem.cs create mode 100644 CutList/Properties/DataSources/CutList.Models.BinInputItem.datasource create mode 100644 SawCut/MultiBin.cs create mode 100644 SawCut/Nesting/MultiBinEngine.cs diff --git a/CutList/CutList.csproj b/CutList/CutList.csproj index ea38d2f..de13530 100644 --- a/CutList/CutList.csproj +++ b/CutList/CutList.csproj @@ -98,6 +98,8 @@ ResultsForm.cs + + @@ -121,6 +123,7 @@ + diff --git a/CutList/Forms/MainForm.Designer.cs b/CutList/Forms/MainForm.Designer.cs index eea73ef..d0716f8 100644 --- a/CutList/Forms/MainForm.Designer.cs +++ b/CutList/Forms/MainForm.Designer.cs @@ -29,17 +29,12 @@ private void InitializeComponent() { this.components = new System.ComponentModel.Container(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle(); System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle(); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle4 = new System.Windows.Forms.DataGridViewCellStyle(); this.dataGridView1 = new System.Windows.Forms.DataGridView(); - this.nameDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.lengthDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.quantityDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.TotalLength = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.itemBindingSource = new System.Windows.Forms.BindingSource(this.components); - this.label1 = new System.Windows.Forms.Label(); - this.label2 = new System.Windows.Forms.Label(); this.toolStrip1 = new System.Windows.Forms.ToolStrip(); this.toolStripButton1 = new System.Windows.Forms.ToolStripButton(); this.saveButton = new System.Windows.Forms.ToolStripButton(); @@ -49,20 +44,35 @@ this.textBox1 = new System.Windows.Forms.TextBox(); this.label3 = new System.Windows.Forms.Label(); this.label4 = new System.Windows.Forms.Label(); - this.stockLengthBox = new System.Windows.Forms.TextBox(); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabPage2 = new System.Windows.Forms.TabPage(); + this.tabPage1 = new System.Windows.Forms.TabPage(); + this.dataGridView2 = new System.Windows.Forms.DataGridView(); + this.nameDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.lengthDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.quantityDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.itemBindingSource = new System.Windows.Forms.BindingSource(this.components); + this.binInputItemBindingSource = new System.Windows.Forms.BindingSource(this.components); + this.lengthInputValueDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.quantityDataGridViewTextBoxColumn1 = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.TotalLengthString = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.priorityDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.itemBindingSource)).BeginInit(); this.toolStrip1.SuspendLayout(); + this.tabControl1.SuspendLayout(); + this.tabPage2.SuspendLayout(); + this.tabPage1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.dataGridView2)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.itemBindingSource)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.binInputItemBindingSource)).BeginInit(); this.SuspendLayout(); // // dataGridView1 // this.dataGridView1.AllowUserToResizeRows = false; - this.dataGridView1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); this.dataGridView1.AutoGenerateColumns = false; this.dataGridView1.BackgroundColor = System.Drawing.Color.White; + this.dataGridView1.BorderStyle = System.Windows.Forms.BorderStyle.None; this.dataGridView1.ClipboardCopyMode = System.Windows.Forms.DataGridViewClipboardCopyMode.EnableAlwaysIncludeHeaderText; this.dataGridView1.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; this.dataGridView1.ColumnHeadersHeight = 30; @@ -72,44 +82,20 @@ this.quantityDataGridViewTextBoxColumn, this.TotalLength}); this.dataGridView1.DataSource = this.itemBindingSource; + this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill; this.dataGridView1.GridColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224))))); - this.dataGridView1.Location = new System.Drawing.Point(12, 122); + this.dataGridView1.Location = new System.Drawing.Point(3, 3); this.dataGridView1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); this.dataGridView1.Name = "dataGridView1"; this.dataGridView1.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; this.dataGridView1.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing; this.dataGridView1.RowTemplate.Height = 26; - this.dataGridView1.Size = new System.Drawing.Size(822, 349); + this.dataGridView1.Size = new System.Drawing.Size(842, 459); this.dataGridView1.TabIndex = 11; this.dataGridView1.CellEndEdit += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellEndEdit); - this.dataGridView1.CellValidated += new System.Windows.Forms.DataGridViewCellEventHandler(this.DataGridView1_CellValidated); + this.dataGridView1.CellValidated += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellEndEdit); this.dataGridView1.DataError += new System.Windows.Forms.DataGridViewDataErrorEventHandler(this.dataGridView1_DataError); // - // nameDataGridViewTextBoxColumn - // - this.nameDataGridViewTextBoxColumn.DataPropertyName = "Name"; - this.nameDataGridViewTextBoxColumn.HeaderText = "Name"; - this.nameDataGridViewTextBoxColumn.Name = "nameDataGridViewTextBoxColumn"; - this.nameDataGridViewTextBoxColumn.Width = 200; - // - // lengthDataGridViewTextBoxColumn - // - this.lengthDataGridViewTextBoxColumn.DataPropertyName = "LengthInputValue"; - dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; - this.lengthDataGridViewTextBoxColumn.DefaultCellStyle = dataGridViewCellStyle1; - this.lengthDataGridViewTextBoxColumn.HeaderText = "Length"; - this.lengthDataGridViewTextBoxColumn.Name = "lengthDataGridViewTextBoxColumn"; - this.lengthDataGridViewTextBoxColumn.Width = 120; - // - // quantityDataGridViewTextBoxColumn - // - this.quantityDataGridViewTextBoxColumn.DataPropertyName = "Quantity"; - dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; - this.quantityDataGridViewTextBoxColumn.DefaultCellStyle = dataGridViewCellStyle2; - this.quantityDataGridViewTextBoxColumn.HeaderText = "Qty"; - this.quantityDataGridViewTextBoxColumn.Name = "quantityDataGridViewTextBoxColumn"; - this.quantityDataGridViewTextBoxColumn.Width = 50; - // // TotalLength // this.TotalLength.DataPropertyName = "TotalLength"; @@ -122,32 +108,6 @@ this.TotalLength.ReadOnly = true; this.TotalLength.Width = 150; // - // itemBindingSource - // - this.itemBindingSource.DataSource = typeof(CutList.Models.Item); - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Font = new System.Drawing.Font("Segoe UI Semibold", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label1.ForeColor = System.Drawing.Color.Blue; - this.label1.Location = new System.Drawing.Point(21, 101); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(300, 17); - this.label1.TabIndex = 10; - this.label1.Text = "Enter the lengths that will be cut from the stock"; - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Font = new System.Drawing.Font("Segoe UI Semibold", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label2.ForeColor = System.Drawing.Color.Blue; - this.label2.Location = new System.Drawing.Point(20, 45); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(84, 17); - this.label2.TabIndex = 1; - this.label2.Text = "Stock length"; - // // toolStrip1 // this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -157,7 +117,7 @@ this.runButton}); this.toolStrip1.Location = new System.Drawing.Point(0, 0); this.toolStrip1.Name = "toolStrip1"; - this.toolStrip1.Size = new System.Drawing.Size(846, 39); + this.toolStrip1.Size = new System.Drawing.Size(880, 39); this.toolStrip1.TabIndex = 0; this.toolStrip1.Text = "toolStrip1"; // @@ -206,7 +166,7 @@ // this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.comboBox1.FormattingEnabled = true; - this.comboBox1.Location = new System.Drawing.Point(478, 42); + this.comboBox1.Location = new System.Drawing.Point(107, 22); this.comboBox1.Name = "comboBox1"; this.comboBox1.Size = new System.Drawing.Size(184, 25); this.comboBox1.TabIndex = 7; @@ -214,7 +174,7 @@ // // textBox1 // - this.textBox1.Location = new System.Drawing.Point(478, 73); + this.textBox1.Location = new System.Drawing.Point(107, 53); this.textBox1.Name = "textBox1"; this.textBox1.Size = new System.Drawing.Size(184, 25); this.textBox1.TabIndex = 9; @@ -225,7 +185,7 @@ this.label3.AutoSize = true; this.label3.Font = new System.Drawing.Font("Segoe UI Semibold", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.label3.ForeColor = System.Drawing.Color.Blue; - this.label3.Location = new System.Drawing.Point(391, 45); + this.label3.Location = new System.Drawing.Point(20, 25); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(81, 17); this.label3.TabIndex = 6; @@ -236,44 +196,161 @@ this.label4.AutoSize = true; this.label4.Font = new System.Drawing.Font("Segoe UI Semibold", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.label4.ForeColor = System.Drawing.Color.Blue; - this.label4.Location = new System.Drawing.Point(405, 76); + this.label4.Location = new System.Drawing.Point(34, 56); this.label4.Name = "label4"; this.label4.Size = new System.Drawing.Size(67, 17); this.label4.TabIndex = 8; this.label4.Text = "Cut width"; // - // stockLengthBox + // tabControl1 // - this.stockLengthBox.Location = new System.Drawing.Point(110, 42); - this.stockLengthBox.Name = "stockLengthBox"; - this.stockLengthBox.Size = new System.Drawing.Size(142, 25); - this.stockLengthBox.TabIndex = 2; - this.stockLengthBox.Text = "12ft 0in"; - this.stockLengthBox.TextChanged += new System.EventHandler(this.StockLengthBox_TextChanged); + this.tabControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tabControl1.Controls.Add(this.tabPage2); + this.tabControl1.Controls.Add(this.tabPage1); + this.tabControl1.Location = new System.Drawing.Point(12, 42); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + this.tabControl1.Size = new System.Drawing.Size(856, 495); + this.tabControl1.TabIndex = 12; + // + // tabPage2 + // + this.tabPage2.Controls.Add(this.dataGridView1); + this.tabPage2.Location = new System.Drawing.Point(4, 26); + this.tabPage2.Name = "tabPage2"; + this.tabPage2.Padding = new System.Windows.Forms.Padding(3); + this.tabPage2.Size = new System.Drawing.Size(848, 465); + this.tabPage2.TabIndex = 1; + this.tabPage2.Text = "ITEMS TO NEST"; + this.tabPage2.UseVisualStyleBackColor = true; + // + // tabPage1 + // + this.tabPage1.Controls.Add(this.dataGridView2); + this.tabPage1.Controls.Add(this.textBox1); + this.tabPage1.Controls.Add(this.comboBox1); + this.tabPage1.Controls.Add(this.label4); + this.tabPage1.Controls.Add(this.label3); + this.tabPage1.Location = new System.Drawing.Point(4, 26); + this.tabPage1.Name = "tabPage1"; + this.tabPage1.Padding = new System.Windows.Forms.Padding(3); + this.tabPage1.Size = new System.Drawing.Size(848, 465); + this.tabPage1.TabIndex = 0; + this.tabPage1.Text = "STOCK LENGTHS"; + this.tabPage1.UseVisualStyleBackColor = true; + // + // dataGridView2 + // + this.dataGridView2.AllowUserToResizeRows = false; + this.dataGridView2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.dataGridView2.AutoGenerateColumns = false; + this.dataGridView2.ClipboardCopyMode = System.Windows.Forms.DataGridViewClipboardCopyMode.EnableAlwaysIncludeHeaderText; + this.dataGridView2.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; + this.dataGridView2.ColumnHeadersHeight = 30; + this.dataGridView2.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { + this.lengthInputValueDataGridViewTextBoxColumn, + this.quantityDataGridViewTextBoxColumn1, + this.TotalLengthString, + this.priorityDataGridViewTextBoxColumn}); + this.dataGridView2.DataSource = this.binInputItemBindingSource; + this.dataGridView2.GridColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224))))); + this.dataGridView2.Location = new System.Drawing.Point(6, 103); + this.dataGridView2.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.dataGridView2.Name = "dataGridView2"; + this.dataGridView2.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single; + this.dataGridView2.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing; + this.dataGridView2.RowTemplate.Height = 26; + this.dataGridView2.Size = new System.Drawing.Size(836, 347); + this.dataGridView2.TabIndex = 12; + this.dataGridView2.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView2_CellContentClick); + this.dataGridView2.CellEndEdit += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView2_CellEndEdit); + // + // nameDataGridViewTextBoxColumn + // + this.nameDataGridViewTextBoxColumn.DataPropertyName = "Name"; + this.nameDataGridViewTextBoxColumn.HeaderText = "Name"; + this.nameDataGridViewTextBoxColumn.Name = "nameDataGridViewTextBoxColumn"; + this.nameDataGridViewTextBoxColumn.Width = 200; + // + // lengthDataGridViewTextBoxColumn + // + this.lengthDataGridViewTextBoxColumn.DataPropertyName = "LengthInputValue"; + dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; + this.lengthDataGridViewTextBoxColumn.DefaultCellStyle = dataGridViewCellStyle1; + this.lengthDataGridViewTextBoxColumn.HeaderText = "Length"; + this.lengthDataGridViewTextBoxColumn.Name = "lengthDataGridViewTextBoxColumn"; + this.lengthDataGridViewTextBoxColumn.Width = 120; + // + // quantityDataGridViewTextBoxColumn + // + this.quantityDataGridViewTextBoxColumn.DataPropertyName = "Quantity"; + dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; + this.quantityDataGridViewTextBoxColumn.DefaultCellStyle = dataGridViewCellStyle2; + this.quantityDataGridViewTextBoxColumn.HeaderText = "Qty"; + this.quantityDataGridViewTextBoxColumn.Name = "quantityDataGridViewTextBoxColumn"; + this.quantityDataGridViewTextBoxColumn.Width = 50; + // + // itemBindingSource + // + this.itemBindingSource.DataSource = typeof(CutList.Models.Item); + // + // binInputItemBindingSource + // + this.binInputItemBindingSource.DataSource = typeof(CutList.Models.BinInputItem); + // + // lengthInputValueDataGridViewTextBoxColumn + // + this.lengthInputValueDataGridViewTextBoxColumn.DataPropertyName = "LengthInputValue"; + this.lengthInputValueDataGridViewTextBoxColumn.HeaderText = "Length"; + this.lengthInputValueDataGridViewTextBoxColumn.Name = "lengthInputValueDataGridViewTextBoxColumn"; + // + // quantityDataGridViewTextBoxColumn1 + // + this.quantityDataGridViewTextBoxColumn1.DataPropertyName = "Quantity"; + this.quantityDataGridViewTextBoxColumn1.HeaderText = "Quantity"; + this.quantityDataGridViewTextBoxColumn1.Name = "quantityDataGridViewTextBoxColumn1"; + // + // TotalLengthString + // + this.TotalLengthString.DataPropertyName = "TotalLengthString"; + dataGridViewCellStyle4.BackColor = System.Drawing.SystemColors.Info; + this.TotalLengthString.DefaultCellStyle = dataGridViewCellStyle4; + this.TotalLengthString.HeaderText = "Total Length"; + this.TotalLengthString.Name = "TotalLengthString"; + this.TotalLengthString.ReadOnly = true; + // + // priorityDataGridViewTextBoxColumn + // + this.priorityDataGridViewTextBoxColumn.DataPropertyName = "Priority"; + this.priorityDataGridViewTextBoxColumn.HeaderText = "Priority"; + this.priorityDataGridViewTextBoxColumn.Name = "priorityDataGridViewTextBoxColumn"; // // MainForm // this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; - this.ClientSize = new System.Drawing.Size(846, 484); - this.Controls.Add(this.stockLengthBox); - this.Controls.Add(this.textBox1); - this.Controls.Add(this.comboBox1); + this.ClientSize = new System.Drawing.Size(880, 549); + this.Controls.Add(this.tabControl1); this.Controls.Add(this.toolStrip1); - this.Controls.Add(this.label4); - this.Controls.Add(this.label3); - this.Controls.Add(this.label2); - this.Controls.Add(this.label1); - this.Controls.Add(this.dataGridView1); this.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); this.MinimumSize = new System.Drawing.Size(570, 457); this.Name = "MainForm"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; - this.Text = "Cut To Length"; + this.Text = "Cut List"; ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.itemBindingSource)).EndInit(); this.toolStrip1.ResumeLayout(false); this.toolStrip1.PerformLayout(); + this.tabControl1.ResumeLayout(false); + this.tabPage2.ResumeLayout(false); + this.tabPage1.ResumeLayout(false); + this.tabPage1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.dataGridView2)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.itemBindingSource)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.binInputItemBindingSource)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -282,8 +359,6 @@ #endregion private System.Windows.Forms.DataGridView dataGridView1; private System.Windows.Forms.BindingSource itemBindingSource; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.Label label2; private System.Windows.Forms.ToolStrip toolStrip1; private System.Windows.Forms.ToolStripButton toolStripButton1; private System.Windows.Forms.ToolStripButton saveButton; @@ -293,11 +368,19 @@ private System.Windows.Forms.TextBox textBox1; private System.Windows.Forms.Label label3; private System.Windows.Forms.Label label4; - private System.Windows.Forms.TextBox stockLengthBox; private System.Windows.Forms.DataGridViewTextBoxColumn nameDataGridViewTextBoxColumn; private System.Windows.Forms.DataGridViewTextBoxColumn lengthDataGridViewTextBoxColumn; private System.Windows.Forms.DataGridViewTextBoxColumn quantityDataGridViewTextBoxColumn; private System.Windows.Forms.DataGridViewTextBoxColumn TotalLength; + private System.Windows.Forms.TabControl tabControl1; + private System.Windows.Forms.TabPage tabPage1; + private System.Windows.Forms.TabPage tabPage2; + private System.Windows.Forms.DataGridView dataGridView2; + private System.Windows.Forms.BindingSource binInputItemBindingSource; + private System.Windows.Forms.DataGridViewTextBoxColumn lengthInputValueDataGridViewTextBoxColumn; + private System.Windows.Forms.DataGridViewTextBoxColumn quantityDataGridViewTextBoxColumn1; + private System.Windows.Forms.DataGridViewTextBoxColumn TotalLengthString; + private System.Windows.Forms.DataGridViewTextBoxColumn priorityDataGridViewTextBoxColumn; } } diff --git a/CutList/Forms/MainForm.cs b/CutList/Forms/MainForm.cs index b2a3c72..2e70725 100644 --- a/CutList/Forms/MainForm.cs +++ b/CutList/Forms/MainForm.cs @@ -17,17 +17,21 @@ namespace CutList.Forms public partial class MainForm : Form { private BindingList items; + private BindingList bins; public MainForm() { InitializeComponent(); items = new BindingList(); - items.ListChanged += Items_ListChanged; + bins = new BindingList(); itemBindingSource.DataSource = items; itemBindingSource.ListChanged += ItemBindingSource_ListChanged; + binInputItemBindingSource.DataSource = bins; + binInputItemBindingSource.ListChanged += BinInputItemBindingSource_ListChanged; + if (!File.Exists(ToolsFilePath)) { var tools = new List @@ -46,13 +50,14 @@ namespace CutList.Forms } } - private void ItemBindingSource_ListChanged(object sender, ListChangedEventArgs e) + private void BinInputItemBindingSource_ListChanged(object sender, ListChangedEventArgs e) { UpdateRunButtonState(); } - private void Items_ListChanged(object sender, ListChangedEventArgs e) + private void ItemBindingSource_ListChanged(object sender, ListChangedEventArgs e) { + UpdateRunButtonState(); } protected override void OnLoad(EventArgs e) @@ -74,7 +79,7 @@ namespace CutList.Forms if (!items.Any(i => i.Length > 0 && i.Quantity > 0)) return false; - if (Double.IsNaN(StockLengthInches)) + if (!bins.Any(i => i.Length > 0 && i.Quantity > 0)) return false; for (int rowIndex = 0; rowIndex < dataGridView1.Rows.Count; rowIndex++) @@ -122,44 +127,24 @@ namespace CutList.Forms File.WriteAllText(saveFileDialog.FileName, json); } - private double StockLengthInches - { - get - { - return GetLengthInches(stockLengthBox); - } - } - - private double GetLengthInches(TextBox tb) - { - try - { - double d; - - if (double.TryParse(tb.Text, out d)) - { - return d; - } - - var x = ArchUnits.ParseToInches(tb.Text); - tb.ForeColor = SystemColors.WindowText; - return x; - - } - catch - { - tb.ForeColor = Color.Red; - return double.NaN; - } - } - private void Run() { var cutTool = GetSelectedTool(); + var stockBins = new List(); - var engine = new Engine2(); + foreach (var item in bins) + { + stockBins.Add(new MultiBin + { + Length = item.Length.Value, + Quantity = item.Quantity, + Priority = item.Priority + }); + } + + var engine = new MultiBinEngine(); engine.Spacing = cutTool.Kerf; - engine.StockLength = StockLengthInches; + engine.Bins = stockBins; var items = GetItems(); var result = engine.Pack(items); @@ -167,14 +152,6 @@ namespace CutList.Forms var form = new ResultsForm(); form.Bins = result.Bins; form.ShowDialog(); - - //var saveFileDialog = new SaveFileDialog(); - //saveFileDialog.Filter = "Text File|*.txt"; - - //if (saveFileDialog.ShowDialog() == DialogResult.OK) - //{ - // SaveBins(saveFileDialog.FileName, bins); - //} } private List GetItems() @@ -284,33 +261,6 @@ namespace CutList.Forms } } - private void DataGridView1_CellValidated(object sender, DataGridViewCellEventArgs e) - { - if (e.ColumnIndex == lengthDataGridViewTextBoxColumn.Index) - { - var item = dataGridView1.Rows[e.RowIndex].DataBoundItem as Item; - - if (item == null) - return; - - var errorText = string.Empty; - - if (item.Length == null) - { - errorText = "Length is not in a valid format."; - } - - dataGridView1.Rows[e.RowIndex].ErrorText = errorText; - } - - UpdateRunButtonState(); - } - - private void StockLengthBox_TextChanged(object sender, EventArgs e) - { - UpdateRunButtonState(); - } - private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e) { if (e.ColumnIndex == lengthDataGridViewTextBoxColumn.Index) @@ -322,5 +272,16 @@ namespace CutList.Forms dataGridView1.Rows[e.RowIndex].ErrorText = e.Exception.InnerException?.Message; e.ThrowException = false; } + + private void dataGridView2_CellContentClick(object sender, DataGridViewCellEventArgs e) + { + + } + + private void dataGridView2_CellEndEdit(object sender, DataGridViewCellEventArgs e) + { + if (e.ColumnIndex == lengthInputValueDataGridViewTextBoxColumn.Index) + dataGridView2.Refresh(); + } } } diff --git a/CutList/Forms/MainForm.resx b/CutList/Forms/MainForm.resx index 2ae7c58..070dd8b 100644 --- a/CutList/Forms/MainForm.resx +++ b/CutList/Forms/MainForm.resx @@ -126,4 +126,10 @@ 172, 17 + + True + + + 277, 17 + \ No newline at end of file diff --git a/CutList/Helper.cs b/CutList/Helper.cs new file mode 100644 index 0000000..3697695 --- /dev/null +++ b/CutList/Helper.cs @@ -0,0 +1,32 @@ +using SawCut; +using System.Drawing; +using System.Windows.Forms; + +namespace CutList +{ + static class Helper + { + public static double GetLengthInches(TextBox tb) + { + try + { + double d; + + if (double.TryParse(tb.Text, out d)) + { + return d; + } + + var x = ArchUnits.ParseToInches(tb.Text); + tb.ForeColor = SystemColors.WindowText; + return x; + + } + catch + { + tb.ForeColor = Color.Red; + return double.NaN; + } + } + } +} diff --git a/CutList/Models/BinInputItem.cs b/CutList/Models/BinInputItem.cs new file mode 100644 index 0000000..225ea21 --- /dev/null +++ b/CutList/Models/BinInputItem.cs @@ -0,0 +1,66 @@ +using Newtonsoft.Json; +using SawCut; +using System; + +namespace CutList.Models +{ + public class BinInputItem + { + public BinInputItem() + { + } + + public string LengthInputValue { get; set; } + + public double? Length + { + get + { + try + { + var input = Fraction.ReplaceFractionsWithDecimals(LengthInputValue); + + double d; + + if (double.TryParse(input, out d)) + { + LengthInputValue += "\""; + return d; + } + + return ArchUnits.ParseToInches(LengthInputValue); + } + catch + { + return null; + } + } + } + + [JsonIgnore] + public double? TotalLength + { + get + { + var length = Length; + + if (length == null) + return null; + + return Math.Round(length.Value * Quantity, 8); + } + } + + public string TotalLengthString + { + get + { + return TotalLength.HasValue ? ArchUnits.FormatFromInches(TotalLength.Value) : "-"; + } + } + + public int Quantity { get; set; } = 1; + + public int Priority { get; set; } = 10; + } +} diff --git a/CutList/Models/Item.cs b/CutList/Models/Item.cs index ac9240e..ff811a0 100644 --- a/CutList/Models/Item.cs +++ b/CutList/Models/Item.cs @@ -54,13 +54,5 @@ namespace CutList.Models } public int Quantity { get; set; } = 1; - - private string GetDefaultName() - { - if (Length == 0) - return "-"; - - return string.Format("{0}\" LG", Length); - } } } diff --git a/CutList/Properties/DataSources/CutList.Models.BinInputItem.datasource b/CutList/Properties/DataSources/CutList.Models.BinInputItem.datasource new file mode 100644 index 0000000..702e885 --- /dev/null +++ b/CutList/Properties/DataSources/CutList.Models.BinInputItem.datasource @@ -0,0 +1,10 @@ + + + + CutList.Models.BinInputItem, CutList, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/SawCut/MultiBin.cs b/SawCut/MultiBin.cs new file mode 100644 index 0000000..83b3682 --- /dev/null +++ b/SawCut/MultiBin.cs @@ -0,0 +1,11 @@ +namespace SawCut +{ + public class MultiBin + { + public int Quantity { get; set; } = 1; + + public double Length { get; set; } + + public int Priority { get; set; } + } +} diff --git a/SawCut/Nesting/BestFitEngine.cs b/SawCut/Nesting/BestFitEngine.cs index 986243c..b99030c 100644 --- a/SawCut/Nesting/BestFitEngine.cs +++ b/SawCut/Nesting/BestFitEngine.cs @@ -11,6 +11,8 @@ namespace SawCut.Nesting public double Spacing { get; set; } + public int MaxBinCount { get; set; } = int.MaxValue; + private List Items { get; set; } public Result Pack(List items) @@ -30,6 +32,16 @@ namespace SawCut.Nesting result.Bins = GetBins(); + foreach (var bin in result.Bins) + { + foreach (var item in bin.Items) + { + Items.Remove(item); + } + } + + result.ItemsNotUsed.AddRange(Items); + return result; } @@ -46,8 +58,11 @@ namespace SawCut.Nesting if (item.Length > StockLength) continue; - best_bin = CreateBin(); - bins.Add(best_bin); + if (bins.Count < MaxBinCount) + { + best_bin = CreateBin(); + bins.Add(best_bin); + } } best_bin.Items.Add(item); diff --git a/SawCut/Nesting/Engine2.cs b/SawCut/Nesting/Engine2.cs index 7e4bd7e..2f63ab0 100644 --- a/SawCut/Nesting/Engine2.cs +++ b/SawCut/Nesting/Engine2.cs @@ -11,6 +11,8 @@ namespace SawCut.Nesting public double Spacing { get; set; } + public int MaxBinCount { get; set; } = int.MaxValue; + private List Items { get; set; } public Result Pack(List items) @@ -30,6 +32,16 @@ namespace SawCut.Nesting result.Bins = GetBins(); + foreach (var bin in result.Bins) + { + foreach (var item in bin.Items) + { + Items.Remove(item); + } + } + + result.ItemsNotUsed.AddRange(Items); + return result; } @@ -37,7 +49,7 @@ namespace SawCut.Nesting { var bins = new List(); - while (Items.Count > 0) + while (Items.Count > 0 && bins.Count < MaxBinCount) { var bin = new Bin(StockLength); bin.Spacing = Spacing; diff --git a/SawCut/Nesting/MultiBinEngine.cs b/SawCut/Nesting/MultiBinEngine.cs new file mode 100644 index 0000000..7ac4ace --- /dev/null +++ b/SawCut/Nesting/MultiBinEngine.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace SawCut.Nesting +{ + public class MultiBinEngine : IEngine + { + public List Bins { get; set; } + + public double Spacing { get; set; } + + public Result Pack(List items) + { + var bins = Bins + .Where(b => b.Length > 0) + .OrderByDescending(b => b.Priority) + .ThenBy(b => b.Length) + .ToList(); + + var result = new Result(); + var remainingItems = new List(items); + + foreach (var bin in bins) + { + var e = new Engine2(); + e.MaxBinCount = bin.Quantity; + e.StockLength = bin.Length; + e.Spacing = Spacing; + var r = e.Pack(remainingItems); + + result.Bins.AddRange(r.Bins); + remainingItems = r.ItemsNotUsed; + } + + result.ItemsNotUsed = remainingItems; + + // sanity check + + //var itemsNested = result.Bins.SelectMany(b => b.Items).ToList(); + //var lengths = items.Select(i => i.Length).Distinct(); + + //foreach (var length in lengths) + //{ + // var nameLengthGroups1 = items.Where(i => i.Length == length).GroupBy(i => i.Name).ToList(); + // var nameLengthGroups2 = itemsNested.Where(i => i.Length == length).GroupBy(i => i.Name).ToList(); + + // foreach (var group in nameLengthGroups1) + // { + // var name = group.Key; + + // var nestedWithSameName = nameLengthGroups2.FirstOrDefault(g => g.Key == group.Key); + + // if (group.Count() != nestedWithSameName.Count()) + // { + // throw new Exception("Failed sanity check."); + + // } + // } + + // if (nameLengthGroups1.Count() != nameLengthGroups2.Count()) + // { + // throw new Exception("Failed sanity check."); + // } + //} + + return result; + } + } +} diff --git a/SawCut/Nesting/Result.cs b/SawCut/Nesting/Result.cs index ab79443..baac25a 100644 --- a/SawCut/Nesting/Result.cs +++ b/SawCut/Nesting/Result.cs @@ -7,6 +7,7 @@ namespace SawCut.Nesting public Result() { ItemsNotUsed = new List(); + Bins = new List(); } public List ItemsNotUsed { get; set; } diff --git a/SawCut/SawCut.csproj b/SawCut/SawCut.csproj index 147685a..96a96fe 100644 --- a/SawCut/SawCut.csproj +++ b/SawCut/SawCut.csproj @@ -45,8 +45,10 @@ + +