Exemple #1
0
 public void InflateAll(double deltaWidth, double deltaHeight)
 {
     for (PartNode iPart = Head; iPart != null; iPart = iPart.Next)
     {
         iPart.Inflate(deltaWidth, deltaHeight);
     }
 }
Exemple #2
0
 public void Remove(PartNode part)
 {
     if (part == Head)
     {
         if (part == Tail)
         {
             Head  = null;
             Tail  = null;
             Count = 0;
         }
         else
         {
             Head      = Head.Next;
             Head.Prev = null;
             Count--;
         }
     }
     else
     {
         if (part == Tail)
         {
             Tail      = Tail.Prev;
             Tail.Next = null;
             Count--;
         }
         else
         {
             part.Prev.Next = part.Next;
             part.Next.Prev = part.Prev;
             Count--;
         }
     }
 }
Exemple #3
0
 public PartNode(PartNode original)
 {
     ID        = original.ID;
     dWidth    = original.dWidth;
     dLength   = original.dLength;
     Length    = original.Length;
     Width     = original.Width;
     Area      = original.Area;
     Container = original.Container;
 }
Exemple #4
0
        public PartList OrderredByArea()
        {
            PartList orderredList = new PartList();

            for (PartNode iPart = Head; iPart != null; iPart = iPart.Next)
            {
                orderredList.InsertItemSortedbyAreaAsc(new PartNode(iPart));
            }

            return(orderredList);
        }
Exemple #5
0
 public PartList(PartList original)
 {
     Head  = new PartNode(original.Head);
     Tail  = Head;
     Count = original.Count;
     for (PartNode iPart = original.Head.Next; iPart != null; iPart = iPart.Next)
     {
         var newPart = new PartNode(iPart);
         newPart.Prev = Tail;
         Tail.Next    = newPart;
         Tail         = newPart;
     }
 }
Exemple #6
0
 public void Append(PartList list)
 {
     if (Head == null)
     {
         Head  = list.Head;
         Tail  = list.Tail;
         Count = list.Count;
     }
     else
     {
         Tail.Next      = list.Head;
         list.Head.Prev = Tail;
         Tail           = list.Tail;
         Count         += list.Count;
     }
 }
Exemple #7
0
        public void InsertItemSortedbyAreaAsc(PartNode part)
        {
            if (Head == null)   // list is empty
            {
                part.Prev = null;
                part.Next = null;
                Head      = part;
                Tail      = part;
                Count     = 1;
                return;
            }

            PartNode iPart = Head;

            while (iPart != null && iPart.Area < part.Area)
            {
                iPart = iPart.Next;
            }

            if (iPart == null)  //passed the end of the list
            {
                part.Prev = Tail;
                Tail.Next = part;
                Tail      = part;
            }
            else
            {                      // not past the end
                if (iPart == Head) // at the head
                {
                    part.Prev = null;
                    part.Next = Head;
                    Head.Prev = part;
                    Head      = part;
                }
                else
                {
                    part.Prev       = iPart.Prev;
                    part.Next       = iPart;
                    iPart.Prev.Next = part;
                    iPart.Prev      = part;
                }
            }

            Count++;
        }
Exemple #8
0
 public void Append(PartNode part)
 {
     if (Head == null)
     {
         part.Next = null;
         part.Prev = null;
         Head      = part;
         Tail      = part;
         Count     = 1;
     }
     else
     {
         part.Next = null;
         part.Prev = Tail;
         Tail.Next = part;
         Tail      = part;
         Count++;
     }
 }
Exemple #9
0
        public PartList(params PartNode[] parts)
        {
            if (parts == null || parts.Length == 0 || parts[0] == null)
            {
                return;
            }
            Head  = parts[0];
            Tail  = Head;
            Count = 1;
            int i = 0;

            while (++i < parts.Length && parts[i] != null)
            {
                parts[i].Prev = Tail;
                Tail.Next     = parts[i];
                Tail          = parts[i];
                Count++;
            }
        }
Exemple #10
0
        public void Remove(string id)
        {
            PartNode iPart = Head;

            while (iPart.ID != id)
            {
                iPart = iPart.Next;
            }

            if (iPart == Head)
            {
                if (iPart == Tail)
                {
                    Head  = null;
                    Tail  = null;
                    Count = 0;
                }
                else
                {
                    Head      = Head.Next;
                    Head.Prev = null;
                    Count--;
                }
            }
            else
            {
                if (iPart == Tail)
                {
                    Tail      = Tail.Prev;
                    Tail.Next = null;
                    Count--;
                }
                else
                {
                    iPart.Prev.Next = iPart.Next;
                    iPart.Next.Prev = iPart.Prev;
                    Count--;
                }
            }
        }
Exemple #11
0
        public void Return(PartNode part)
        {
            if (part.Next == null)
            {
                Tail = part;
            }
            else
            {
                part.Next.Prev = part;
            }

            if (part.Prev == null)
            {
                Head = part;
            }
            else
            {
                part.Prev.Next = part;
            }

            Count++;
        }
Exemple #12
0
        public static Bitmap Draw(BoardList boards, PartList parts, bool usedstockonly = true)
        {
            double xOffset      = 0;
            double imageHeight  = 0;
            double boardSpacing = 70;
            double xMargin      = 50;
            double yMargin      = 50;
            double imageWidth   = 2 * xMargin - boardSpacing;
            Font   boardFont    = new Font(new FontFamily("Consolas"), 15.0f);

            // create list of boards to draw
            List <BoardNode> boardsToDraw = new List <BoardNode>(boards.ToArray);

            if (usedstockonly)
            {
                List <string> usedboardnames = parts.ToArray.Select(t => t.Container).Distinct().ToList();
                boardsToDraw.RemoveAll(t => !usedboardnames.Contains(t.ID));
            }

            // calculate width & height required for the bitmap
            foreach (var iBoard in boardsToDraw)
            {
                if (iBoard.Length > imageHeight)
                {
                    imageHeight = iBoard.Length;
                }
                imageWidth += iBoard.Width + boardSpacing;
            }
            imageHeight += 2 * yMargin;

            // create bitmap
            Bitmap   bitmap = new Bitmap((int)imageWidth, (int)imageHeight);
            Graphics g      = Graphics.FromImage(bitmap);

            // fill the background with black
            g.FillRectangle(Brushes.Black, 0, 0, (int)imageWidth, (int)imageHeight);

            // loop through all the boards to be drawn
            xOffset = xMargin;
            foreach (var iBoard in boardsToDraw)
            {
                // draw the board
                g.FillRectangle(Brushes.DarkRed, (float)(xOffset), (float)yMargin, (float)iBoard.Width, (float)iBoard.Length);
                string boardheader   = $"{iBoard.ID} [{iBoard.Length}x{iBoard.Width}]";
                SizeF  textSizeBoard = g.MeasureString(boardheader, boardFont);
                g.DrawString(boardheader, boardFont, Brushes.White, (float)(xOffset + iBoard.Width / 2 - textSizeBoard.Width / 2), (float)(yMargin / 2 - textSizeBoard.Height / 2));

                // loop through all the parts and draw the ones on the current board
                string overflowtext = "";
                for (PartNode iPlacement = parts.Head; iPlacement != null; iPlacement = iPlacement.Next)
                {
                    // continue with next part if this part was placed on another board
                    if (iPlacement.Container != iBoard.ID)
                    {
                        continue;
                    }

                    // draw the part
                    g.FillRectangle(Brushes.Green, (float)(xOffset + iPlacement.dWidth), (float)(iPlacement.dLength + yMargin), (float)iPlacement.Width, (float)iPlacement.Length);

                    // print the part text
                    string text1  = $"{iPlacement.ID} [{iPlacement.Length} x {iPlacement.Width}]";
                    string text2a = $"{iPlacement.ID}";
                    string text2b = $"[{iPlacement.Length} x {iPlacement.Width}]";
                    g.TranslateTransform((float)(xOffset + iPlacement.dWidth + iPlacement.Width / 2), (float)(iPlacement.dLength + iPlacement.Length / 2 + yMargin));
                    g.RotateTransform(-90);

                    int sz = 16;
                    do
                    {
                        Font  partFont = new Font(new FontFamily("Consolas"), --sz);
                        SizeF textSize = g.MeasureString(text1, partFont);
                        if (textSize.Width < iPlacement.Length && textSize.Height < iPlacement.Width)
                        {
                            g.DrawString(text1, partFont, Brushes.White, -(textSize.Width / 2), -(textSize.Height / 2));
                            break;
                        }
                        textSize = g.MeasureString(text2a, partFont);
                        SizeF textSize2 = g.MeasureString(text2b, partFont);
                        if (Math.Max(textSize.Width, textSize2.Width) < iPlacement.Length && textSize.Height + textSize2.Height < iPlacement.Width)
                        {
                            g.DrawString(text2a, partFont, Brushes.White, -(textSize.Width / 2), -textSize.Height);
                            g.DrawString(text2b, partFont, Brushes.White, -(textSize2.Width / 2), 0);
                            break;
                        }
                        if (textSize.Width < iPlacement.Length && textSize.Height < iPlacement.Width)
                        {
                            g.DrawString(text2a, partFont, Brushes.White, -(textSize.Width / 2), -(textSize.Height / 2));
                            overflowtext += text1 + ", ";
                            break;
                        }
                    } while (sz > 1);


                    g.RotateTransform(90);
                    g.TranslateTransform(-((float)xOffset + (float)(iPlacement.dWidth + iPlacement.Width / 2)), -((float)(iPlacement.dLength + iPlacement.Length / 2 + yMargin)));
                }

                g.TranslateTransform((float)(xOffset + iBoard.Width), (float)(iBoard.Length + yMargin));
                g.RotateTransform(-90);
                g.DrawString(overflowtext.TrimEnd(',', ' '), boardFont, Brushes.White, 0, 0);
                g.RotateTransform(90);
                g.TranslateTransform(-(float)(xOffset + iBoard.Width), -(float)(iBoard.Length + yMargin));

                xOffset += iBoard.Width + boardSpacing;
            }

            g.Flush();
            bitmap.RotateFlip(RotateFlipType.Rotate90FlipNone);
            return(bitmap);
        }
Exemple #13
0
        static void Main(string[] args)
        {
            #region // Gather the inputs to the solution ...
            double boardMargins_length = 0;
            double boardMargins_Width  = 0;
            double PartPadding_Length  = 0;
            double PartPadding_Width   = 0;
            double SawKerf             = 3.2;


            BoardList boards = new BoardList(
                //new BoardNode("A", 2100, 193),
                //new BoardNode("B", 2100, 150),
                //new BoardNode("C", 2100, 143),
                //new BoardNode("D", 2100, 170),
                //new BoardNode("E", 2100, 185),
                new BoardNode("F", 2100, 210),
                //new BoardNode("G", 2100, 135),
                //new BoardNode("H", 2100, 225),
                null
                );

            PartList parts = new PartList(
                new PartNode("001", 1721.7, 100.0),
                new PartNode("002", 284.5, 100.0),
                new PartNode("003", 1721.7, 100.0),
                new PartNode("004", 284.5, 100.0),
                new PartNode("005", 955.0, 69.3),
                new PartNode("006", 955.0, 60.0),
                new PartNode("007", 955.0, 69.6),
                new PartNode("008", 955.0, 80.0),
                new PartNode("009", 955.0, 60.0),
                new PartNode("010", 955.0, 60.0),
                new PartNode("011", 310.0, 100.0),
                new PartNode("012", 310.0, 100.0),
                new PartNode("013", 310.0, 36.0),
                new PartNode("014", 310.0, 36.0),
                new PartNode("015", 354.5, 36.0),
                new PartNode("016", 354.5, 36.0),
                new PartNode("017", 299.0, 20.0),
                new PartNode("018", 299.0, 20.0),
                new PartNode("019", 299.0, 20.0),
                new PartNode("020", 299.0, 20.0),
                new PartNode("021", 327.5, 20.0),
                new PartNode("022", 327.5, 20.0),
                //new PartNode("023", 955.0, 80.0),
                //new PartNode("024", 310.0, 100.0),
                //new PartNode("025", 310.0, 100.0),
                //new PartNode("026", 310.0, 36.0),
                //new PartNode("027", 310.0, 36.0),
                //new PartNode("028", 354.5, 36.0),
                //new PartNode("029", 354.5, 36.0),
                //new PartNode("030", 299.0, 20.0),
                //new PartNode("031", 327.5, 20.0),
                //new PartNode("032", 327.5, 20.0),
                //new PartNode("033", 955.0, 80.0),
                //new PartNode("034", 310.0, 100.0),
                //new PartNode("035", 310.0, 100.0),
                //new PartNode("036", 310.0, 36.0),
                //new PartNode("037", 310.0, 36.0),
                //new PartNode("038", 354.5, 36.0),
                //new PartNode("039", 354.5, 36.0),
                //new PartNode("040", 299.0, 20.0),
                //new PartNode("041", 327.5, 20.0),
                //new PartNode("042", 327.5, 20.0),
                //new PartNode("043", 955.0, 80.0),
                //new PartNode("044", 310.0, 100.0),
                //new PartNode("045", 310.0, 100.0),
                //new PartNode("046", 310.0, 36.0),
                //new PartNode("047", 310.0, 36.0),
                //new PartNode("048", 354.5, 36.0),
                //new PartNode("049", 354.5, 36.0),
                //new PartNode("050", 299.0, 20.0),
                null
                );
            if (args[0].StartsWith("-clp:"))
            {
                string path = args[0].Replace("-clp:", "");
                if (System.IO.File.Exists(path))
                {
                    Import.FromCutlistPlusCSV(path, out parts, out boards);
                }
            }
            if (args[0].StartsWith("-csv:"))
            {
                string path = args[0].Replace("-csv:", "");
                if (System.IO.File.Exists(path))
                {
                    Import.FromCSV(path, out parts, out boards);
                }
            }
            #endregion

            //PartNode[] partsarray = parts.ToArray;
            //List<PartNode> partsList = new List<PartNode>(partsarray);
            //Stopwatch swt = new Stopwatch();
            //swt.Start();
            //for (int i = 0; i < 120000000; i++)
            //{
            //    //Array
            //    PartNode iPart;
            //    for (int j = 0; j < partsarray.Length; j++) { iPart = partsarray[j]; }

            //    //linked list
            //    //for (var iPart = parts.Head; iPart != null; iPart = iPart.Next) ;

            //    //List
            //    //foreach (var iPart in partsList) ;
            //    //PartNode iPart;
            //    //for (int j = 0; j < partsList.Count; j++) iPart = partsList[j];
            //}
            //swt.Stop();
            //Trace.WriteLine(swt.ElapsedMilliseconds);


            #region // Print starting parameters ...
            Trace.WriteLine($"Packing started @ {DateTime.Now} with the following:");
            Trace.WriteLine($"------------------------------------------------");
            Trace.WriteLine($"  Board margins (w x l) : {boardMargins_Width} mm x {boardMargins_length} mm");
            Trace.WriteLine($"  Part padding  (w x l) : {PartPadding_Width} mm x {PartPadding_Length} mm");
            Trace.WriteLine($"  Saw blade kerf        : {SawKerf} mm");
            Trace.WriteLine($"  {boards.Count} Boards:");
            for (BoardNode iBoard = boards.Head; iBoard != null; iBoard = iBoard.Next)
            {
                Trace.WriteLine($"{iBoard.ID,6} [{iBoard.Length,7:0.0} x {iBoard.Width,5:0.0}]");
            }
            Trace.WriteLine($"  {parts.Count} Parts:");
            for (PartNode iPart = parts.Head; iPart != null; iPart = iPart.Next)
            {
                Trace.WriteLine($"{iPart.ID,6} [{iPart.Length,7:0.0} x {iPart.Width,5:0.0}]");
            }
            #endregion

            #region // Find the solution ...
            Stopwatch sw = new Stopwatch();
            sw.Start();
            var solution = Packer.Pack(parts, boards,
                                       sawkerf: SawKerf,
                                       boardMarginLength: boardMargins_length,
                                       boardMarginWidth: boardMargins_Width,
                                       partPaddingLength: PartPadding_Length,
                                       partPaddingWidth: PartPadding_Width);
            sw.Stop();
            #endregion

            #region // Print the solution ...
            // calculate the total area of all used boards
            List <string> usedBoardIDs  = solution.ToArray.Select(t => t.Container).Distinct().ToList();
            double        UsedStockArea = boards.ToArray.Where(q => usedBoardIDs.Contains(q.ID)).Sum(t => t.Area);

            Trace.WriteLine("Solution:");
            Trace.WriteLine("----------------");
            if (solution.Count < parts.Count)
            {
                Trace.WriteLine("WARNING: All parts could not be placed!\r\n");
            }

            for (var iBoard = boards.Head; iBoard != null; iBoard = iBoard.Next)
            {
                if (iBoard.Solution == null)
                {
                    Trace.WriteLine($"   Board {iBoard.ID} [{iBoard.Length,6:0.0} x {iBoard.Width,5:0.0}] : not used.");
                }
                else
                {
                    Trace.WriteLine($"   Board {iBoard.ID} [{iBoard.Length,6:0.0} x {iBoard.Width,5:0.0}] ({(iBoard.Solution == null ? 0 : iBoard.Solution.TotalArea / iBoard.Area):00.0 %}) :\r\n{iBoard.Solution?.ToString()}");
                }
            }
            Trace.WriteLine("===========================================================");
            Trace.WriteLine("Solution summary");
            Trace.WriteLine("----------------");
            Trace.WriteLine($"   Processing time: {sw.ElapsedMilliseconds,5:0} ms");
            Trace.WriteLine($"   Boards         : {boards.Count,5:0}    ({boards.TotalArea / 1000000,6:0.000} m\u00b2)");
            Trace.WriteLine($"   Used boards    : {usedBoardIDs.Count,5:0}    ({UsedStockArea / 1000000,6:0.000} m\u00b2)");
            Trace.WriteLine($"   Parts          : {parts.Count,5:0}    ({parts.TotalArea / 1000000,6:0.000} m\u00b2)");
            Trace.WriteLine($"   Placed parts   : {solution.Count,5:0}    ({solution.TotalArea / 1000000,6:0.000} m\u00b2)");
            Trace.WriteLine($"   Waste          : {(UsedStockArea - solution.TotalArea) / UsedStockArea,7:0.0 %}  ({(UsedStockArea - solution.TotalArea) / 1000000,6:0.000} m\u00b2)");
            Trace.WriteLine($"   Coverage       : {solution.TotalArea / UsedStockArea,7:0.0 %}  ({(solution.TotalArea) / 1000000,6:0.000} m\u00b2)");
            #endregion

            #region // Draw solution to an image ...
            Bitmap bmp = Draw(boards, solution);
            bmp.Save("out.bmp");
            Console.WriteLine("Launch output image (Y/N):");
            string s = Console.ReadLine();
            if (s.ToLower() == "y")
            {
                Process.Start("out.bmp");
            }
            #endregion
        }