diff --git a/CutToLength/BestFitEngine.cs b/CutToLength/BestFitEngine.cs index f9f7314..e9e369a 100644 --- a/CutToLength/BestFitEngine.cs +++ b/CutToLength/BestFitEngine.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Data; using System.Linq; @@ -8,21 +9,41 @@ namespace CutToLength { public double StockLength { get; set; } - public Tool CutTool { get; set; } + public double Spacing { get; set; } - public List GetResults(List items) + private List Items { get; set; } + + public Result Pack(List items) { - var items2 = items.OrderByDescending(i => i.Length); - var bins = new List(); - var length = StockLength; + if (StockLength <= 0) + throw new Exception("Stock length must be greater than 0"); - foreach (var item in items2) + Items = items.OrderByDescending(i => i.Length).ToList(); + + var result = new Result(); + result.ItemsNotUsed = Items.Where(i => i.Length > StockLength).ToList(); + + foreach (var item in result.ItemsNotUsed) + { + Items.Remove(item); + } + + result.Bins = GetBins(); + + return result; + } + + private List GetBins() + { + var bins = new List(); + + foreach (var item in Items) { Bin best_bin; if (!FindBin(bins.ToArray(), item.Length, out best_bin)) { - if (item.Length > length) + if (item.Length > StockLength) continue; best_bin = CreateBin(); @@ -38,11 +59,10 @@ namespace CutToLength private Bin CreateBin() { var length = StockLength; - var spacing = CutTool.Kerf; return new Bin(length) { - Spacing = spacing + Spacing = Spacing }; } @@ -66,8 +86,169 @@ namespace CutToLength } } + public class Engine2 : IEngine + { + public double StockLength { get; set; } + + public double Spacing { get; set; } + + private List Items { get; set; } + + public Result Pack(List items) + { + if (StockLength <= 0) + throw new Exception("Stock length must be greater than 0"); + + Items = items.OrderByDescending(i => i.Length).ToList(); + + var result = new Result(); + result.ItemsNotUsed = Items.Where(i => i.Length > StockLength).ToList(); + + foreach (var item in result.ItemsNotUsed) + { + Items.Remove(item); + } + + result.Bins = GetBins(); + + return result; + } + + private List GetBins() + { + var bins = new List(); + + while (Items.Count > 0) + { + var bin = new Bin(StockLength); + bin.Spacing = Spacing; + + FillBin(bin); + + int count = 0; + + while (TryImprovePacking(bin)) + { + count++; + } + + bins.Add(bin); + } + + return bins; + } + + private void FillBin(Bin bin) + { + for (int i = 0; i < Items.Count; i++) + { + var item = Items[i]; + + if (bin.RemainingLength >= item.Length) + bin.Items.Add(item); + } + + foreach (var item in bin.Items) + { + Items.Remove(item); + } + } + + private bool TryImprovePacking(Bin bin) + { + if (bin.Items.Count == 0) + return false; + + if (Items.Count < 2) + return false; + + var lengthGroups = bin.Items + .OrderByDescending(i => i.Length) + .GroupBy(i => i.Length) + .Skip(1); + + var minItemLength = Items.Min(i => i.Length); + + foreach (var group in lengthGroups) + { + var minRemainingLength = bin.RemainingLength; + + var firstItem = group.First(); + bin.Items.Remove(firstItem); + + for (int i = 0; i < Items.Count; i++) + { + var item1 = Items[i]; + + if (Items[i].Length > bin.RemainingLength) + continue; + + var bin2 = new Bin(bin.RemainingLength); + bin2.Spacing = bin.Spacing; + bin2.Items.Add(item1); + + for (int j = i + 1; j < Items.Count; j++) + { + if (bin2.RemainingLength < minItemLength) + break; + + var item2 = Items[j]; + + if (item2.Length > bin2.RemainingLength) + continue; + + bin2.Items.Add(item2); + } + + if (bin2.RemainingLength < minRemainingLength) + { + Items.Add(firstItem); + bin.Items.AddRange(bin2.Items); + + foreach (var item in bin2.Items) + { + Items.Remove(item); + } + + // improvement made + return true; + } + } + + bin.Items.Add(firstItem); + } + + return false; + } + } + + class OptimizeResult + { + public OptimizeResult() + { + OldItems = new List(); + NewItems = new List(); + } + + public List OldItems { get; set; } + + public List NewItems { get; set; } + } + public interface IEngine { - List GetResults(List items); + Result Pack(List items); + } + + public class Result + { + public Result() + { + ItemsNotUsed = new List(); + } + + public List ItemsNotUsed { get; set; } + + public List Bins { get; set; } } } diff --git a/CutToLength/MainForm.cs b/CutToLength/MainForm.cs index ef11c7d..7ec367e 100644 --- a/CutToLength/MainForm.cs +++ b/CutToLength/MainForm.cs @@ -128,15 +128,17 @@ namespace CutToLength private void Run() { - var engine = new BestFitEngine(); - engine.CutTool = GetSelectedTool(); + var cutTool = GetSelectedTool(); + + var engine = new Engine2(); + engine.Spacing = cutTool.Kerf; engine.StockLength = StockLengthInches; var items = GetItems(); - var bins = engine.GetResults(items); + var result = engine.Pack(items); var form = new ResultsForm(); - form.Bins = bins; + form.Bins = result.Bins; form.ShowDialog(); //var saveFileDialog = new SaveFileDialog();