diff --git a/CutList/Forms/Document.cs b/CutList/Forms/Document.cs index e44ef5f..5323259 100644 --- a/CutList/Forms/Document.cs +++ b/CutList/Forms/Document.cs @@ -25,53 +25,5 @@ namespace CutList.Forms public List StockBins { get; set; } public Tool Tool { get; set; } - - public void Save(string filePath) - { - try - { - var json = JsonConvert.SerializeObject(this, Formatting.Indented); - File.WriteAllText(filePath, json); - LastFilePath = filePath; - } - catch (Exception ex) - { - MessageBox.Show($"Failed to save file: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - - public static Document Load(string filePath) - { - try - { - var json = File.ReadAllText(filePath); - var document = JsonConvert.DeserializeObject(json); - document.LastFilePath = filePath; - return document; - } - catch (Exception ex) - { - MessageBox.Show($"Failed to load file: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return null; - } - } - - public bool Validate(out string validationMessage) - { - if (PartsToNest == null || !PartsToNest.Any()) - { - validationMessage = "No parts to nest."; - return false; - } - - if (StockBins == null || !StockBins.Any()) - { - validationMessage = "No stock bins available."; - return false; - } - - validationMessage = string.Empty; - return true; - } } } \ No newline at end of file diff --git a/CutList/Forms/MainForm.cs b/CutList/Forms/MainForm.cs index 599e939..2c6a642 100644 --- a/CutList/Forms/MainForm.cs +++ b/CutList/Forms/MainForm.cs @@ -1,6 +1,5 @@ using CutList.Models; -using Newtonsoft.Json; -using SawCut; +using CutList.Services; using SawCut.Nesting; using System; using System.Collections.Generic; @@ -21,11 +20,16 @@ namespace CutList.Forms private BindingList bins; private Toolbox toolbox; private Document currentDocument; + private readonly CutListService cutListService; + private readonly DocumentService documentService; public MainForm() { InitializeComponent(); + cutListService = new CutListService(); + documentService = new DocumentService(); + dataGridView1.DrawRowNumbers(); dataGridView2.DrawRowNumbers(); @@ -90,7 +94,7 @@ namespace CutList.Forms if (openFileDialog.ShowDialog() == DialogResult.OK) { - currentDocument = Document.Load(openFileDialog.FileName); + currentDocument = documentService.Load(openFileDialog.FileName); if (currentDocument == null) return; @@ -138,23 +142,30 @@ namespace CutList.Forms private void Save() { - SyncDocumentFromUI(); - - if (!currentDocument.Validate(out string validationMessage)) + try { - MessageBox.Show(validationMessage, "Validation Error", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return; + SyncDocumentFromUI(); + + if (!documentService.Validate(currentDocument, out string validationMessage)) + { + MessageBox.Show(validationMessage, "Validation Error", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + var saveFileDialog = new SaveFileDialog + { + FileName = currentDocument.LastFilePath == null ? "NewDocument.json" : Path.GetFileName(currentDocument.LastFilePath), + Filter = "Json File|*.json" + }; + + if (saveFileDialog.ShowDialog() == DialogResult.OK) + { + documentService.Save(currentDocument, saveFileDialog.FileName); + } } - - var saveFileDialog = new SaveFileDialog + catch (Exception ex) { - FileName = currentDocument.LastFilePath == null ? "NewDocument.json" : Path.GetFileName(currentDocument.LastFilePath), - Filter = "Json File|*.json" - }; - - if (saveFileDialog.ShowDialog() == DialogResult.OK) - { - currentDocument.Save(saveFileDialog.FileName); + MessageBox.Show($"Failed to save file: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } @@ -164,28 +175,11 @@ namespace CutList.Forms dataGridView2.EndEdit(); var cutTool = GetSelectedTool(); - var stockBins = new List(); - - 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.Bins = stockBins; - - var items = GetItems(); - var result = engine.Pack(items); + var result = cutListService.Pack(parts.ToList(), bins.ToList(), cutTool); var filename = GetResultsSaveName(); var form = new ResultsForm(filename); - form.Bins = result.Bins; + form.Bins = result.Bins.ToList(); form.ShowDialog(); } @@ -200,28 +194,6 @@ namespace CutList.Forms return name; } - private List GetItems() - { - var items2 = new List(); - - foreach (var item in parts) - { - if (item.Length == null || item.Length == 0) - continue; - - for (int i = 0; i < item.Quantity; i++) - { - items2.Add(new BinItem - { - Name = item.Name, - Length = item.Length.Value - }); - } - } - - return items2; - } - public Tool GetSelectedTool() { return cutMethodComboBox.SelectedItem as Tool; diff --git a/CutList/Services/CutListService.cs b/CutList/Services/CutListService.cs new file mode 100644 index 0000000..dde5d1e --- /dev/null +++ b/CutList/Services/CutListService.cs @@ -0,0 +1,74 @@ +using CutList.Models; +using SawCut; +using SawCut.Nesting; +using System.Collections.Generic; + +namespace CutList.Services +{ + /// + /// Service class that handles the core business logic for cut list optimization. + /// Separates business logic from UI concerns. + /// + public class CutListService + { + /// + /// Runs the bin packing algorithm to optimize cut lists. + /// + /// The parts to be nested + /// The available stock bins + /// The cutting tool to use (determines kerf/spacing) + /// The packing result with optimized bins and unused items + public Result Pack(List parts, List stockBins, Tool cuttingTool) + { + var multiBins = ConvertToMultiBins(stockBins); + var binItems = ConvertToBinItems(parts); + + var engine = new MultiBinEngine + { + Spacing = cuttingTool.Kerf, + Bins = multiBins + }; + + return engine.Pack(binItems); + } + + private List ConvertToMultiBins(List stockBins) + { + var multiBins = new List(); + + foreach (var item in stockBins) + { + multiBins.Add(new MultiBin + { + Length = item.Length.Value, + Quantity = item.Quantity, + Priority = item.Priority + }); + } + + return multiBins; + } + + private List ConvertToBinItems(List parts) + { + var binItems = new List(); + + foreach (var part in parts) + { + if (part.Length == null || part.Length == 0) + continue; + + for (int i = 0; i < part.Quantity; i++) + { + binItems.Add(new BinItem + { + Name = part.Name, + Length = part.Length.Value + }); + } + } + + return binItems; + } + } +} diff --git a/CutList/Services/DocumentService.cs b/CutList/Services/DocumentService.cs new file mode 100644 index 0000000..460cae5 --- /dev/null +++ b/CutList/Services/DocumentService.cs @@ -0,0 +1,64 @@ +using CutList.Forms; +using Newtonsoft.Json; +using System; +using System.IO; + +namespace CutList.Services +{ + /// + /// Service class that handles document persistence operations. + /// Separates file I/O logic from UI concerns. + /// + public class DocumentService + { + /// + /// Saves a document to the specified file path. + /// + /// The document to save + /// The file path to save to + /// Thrown when file cannot be saved + public void Save(Document document, string filePath) + { + var json = JsonConvert.SerializeObject(document, Formatting.Indented); + File.WriteAllText(filePath, json); + } + + /// + /// Loads a document from the specified file path. + /// + /// The file path to load from + /// The loaded document + /// Thrown when file cannot be read + /// Thrown when file contains invalid JSON + public Document Load(string filePath) + { + var json = File.ReadAllText(filePath); + var document = JsonConvert.DeserializeObject(json); + return document; + } + + /// + /// Validates that a document has the minimum required data. + /// + /// The document to validate + /// Output parameter containing validation error message + /// True if document is valid, false otherwise + public bool Validate(Document document, out string validationMessage) + { + if (document.PartsToNest == null || document.PartsToNest.Count == 0) + { + validationMessage = "No parts to nest."; + return false; + } + + if (document.StockBins == null || document.StockBins.Count == 0) + { + validationMessage = "No stock bins available."; + return false; + } + + validationMessage = string.Empty; + return true; + } + } +}