private void Pack_recursive(PartList parts, BoardList boards, PartList TemporarySolution, double tempSolutionArea) { // loop through remaining parts for (PartNode iPart = parts.Tail; iPart != null; iPart = iPart.Prev) { #region // check if the part is a viable candidate ... // if this part has bigger area than the largest board segment available, go to next part if (iPart.Area > boards.Tail.Area) { continue; } // if the previous part was the same size, pass this one - we already completed this iteration if (iPart != parts.Tail && iPart.Length == iPart.Next.Length && iPart.Width == iPart.Next.Width) { continue; } #endregion #region // Find first board that will fit the part ... // find first board that will accomodate the part BoardNode iBoard = boards.Head; // if even the last (bigest) board had a smaller area than the part, non of the rest will fit while (iPart.Area > iBoard.Area) { iBoard = iBoard.Next; } while (iBoard != null && (iPart.Length > iBoard.Length || iPart.Width > iBoard.Width)) { iBoard = iBoard.Next; } if (iBoard == null) { continue; // if this part cannot fit any board, continue to next part } #endregion #region // place the part ... double newPackedPartsArea = tempSolutionArea + iPart.Area; //append the part to the list of packed parts TemporarySolution.Append(new PartNode(iPart) { Container = iBoard.ID, dWidth = iBoard.dWidth, dLength = iBoard.dLength }); #endregion #region // store best solution ... //if this is a better solution than the current best one ... replace the current best one if (newPackedPartsArea > currentSolutionArea) { currentSolutionArea = newPackedPartsArea; currentSolution = new PartList(TemporarySolution); } #endregion // if there are no more parts, break out of the loop if (parts.Count == 1) { break; } #region // Break association and adjust associate if a board is used that is associated with another to prevent overlapping placements ... BoardNode iAssocBoard = iBoard.AssociatedBoard; double oAssocLength = 0, oAssocWidth = 0; // if the board section used has a buddy from a previous placement, adjust the buddy and break the association if (iAssocBoard != null) { oAssocLength = iAssocBoard.Length; oAssocWidth = iAssocBoard.Width;; //we have to adjust the buddy, so as not to place another part on the overlapping area if (iBoard.dWidth < iAssocBoard.dWidth) { //if this is Rem1 //if the part is wider than the left portion of Rem1 if (iBoard.dWidth + iPart.Width + sawkerf > iAssocBoard.dWidth) { iAssocBoard.Length -= (iBoard.Length + sawkerf); } else { iBoard.Width -= (iAssocBoard.Width + sawkerf); } } else { //if this is Rem2 if (iBoard.dLength + iPart.Length + sawkerf > iAssocBoard.dLength) { iAssocBoard.Width -= (iBoard.Width + sawkerf); } else { iBoard.Length -= (iAssocBoard.Length + sawkerf); } } //then break the pair iAssocBoard.AssociatedBoard = null; iBoard.AssociatedBoard = null; } #endregion #region // remove the current part from the parts list ... parts.Remove(iPart); #endregion #region // replace the used board with 2 overlapping remainder pieces after subtracting the part ... // divide the board into two overlapping remainder sections boards.Remove(iBoard); BoardNode boardSection1 = null; double l = iBoard.Length - iPart.Length - sawkerf; if (l * iBoard.Width >= parts.Head.Area) { boardSection1 = new BoardNode(iBoard.ID, l, iBoard.Width, iBoard.dLength + iPart.Length + sawkerf, iBoard.dWidth); boards.InsertItemSortedbyAreaAsc(boardSection1); } BoardNode boardSection2 = null; double w = iBoard.Width - iPart.Width - sawkerf; if (w * iBoard.Length >= parts.Head.Area) { boardSection2 = new BoardNode(iBoard.ID, iBoard.Length, w, iBoard.dLength, iBoard.dWidth + iPart.Width + sawkerf); boards.InsertItemSortedbyAreaAsc(boardSection2); boardSection2.AssociatedBoard = boardSection1; if (boardSection1 != null) { boardSection1.AssociatedBoard = boardSection2; } } #endregion if (boards.Count > 0) { #region // pack the remaining parts on the remaining boards ... // pack the remaining parts on the remaining boards Pack_recursive(parts, boards, TemporarySolution, newPackedPartsArea); #endregion } #region // undo the placement so we can iterate to the next part and test with it ... // place the current part back in its exact place ... parts.Return(iPart); // remove the remainder board sections we added... if (boardSection1 != null) { boards.Remove(boardSection1); } if (boardSection2 != null) { boards.Remove(boardSection2); } // restore associations, and the original associated board's size if (iAssocBoard != null) { iBoard.AssociatedBoard = iAssocBoard; iAssocBoard.AssociatedBoard = iBoard; iAssocBoard.Length = oAssocLength; iAssocBoard.Width = oAssocWidth; } // place the board back if (iBoard.Prev == null) { boards.Head = iBoard; } else { iBoard.Prev.Next = iBoard; } if (iBoard.Next == null) { boards.Tail = iBoard; } else { iBoard.Next.Prev = iBoard; } boards.Count++; // remove the part from the temporary solution TemporarySolution.Tail = TemporarySolution.Tail.Prev; if (TemporarySolution.Tail != null) { TemporarySolution.Tail.Next = null; } else { TemporarySolution.Head = null; } TemporarySolution.Count--; #endregion } }