/// Inserts a single rectangle into the bin. The packer might rotate the rectangle, in which case the returned /// struct will have the width and height values swapped. /// @param merge If true, performs free Rectangle Merge procedure after packing the new rectangle. This procedure /// tries to defragment the list of disjoint free rectangles to improve packing performance, but also takes up /// some extra time. /// @param rectChoice The free rectangle choice heuristic rule to use. /// @param splitMethod The free rectangle split heuristic rule to use. public override Rect Insert(RectSize rectSize, GenericOption option) { var opt = option as Option; int width = rectSize.Width; int height = rectSize.Height; // Find where to put the new rectangle. int freeNodeIndex = 0; Rect newRect = FindPositionForNewNode(width, height, opt.FreeRectChoice, ref freeNodeIndex); // Abort if we didn't have enough space in the bin. if (newRect.Height == 0) { return(newRect); } // Remove the space that was just consumed by the new rectangle. SplitFreeRectByHeuristic(freeRectangles[freeNodeIndex], newRect, opt.GuillotineSplit); freeRectangles.RemoveAt(freeNodeIndex); // Perform a Rectangle Merge step if desired. if (opt.Merge) { MergeFreeList(); } // Remember the new used rectangle. UsedRectangles.Add(newRect); // Check that we're really producing correct packings here. disjointRects.Add(newRect); return(newRect); }
/// Places the given rectangle into the bin. private void PlaceRect(Rect node) { int numRectanglesToProcess = freeRectangles.Count; for (int i = 0; i < numRectanglesToProcess; ++i) { if (SplitFreeNode(freeRectangles[i], ref node)) { freeRectangles.RemoveAt(i); --i; --numRectanglesToProcess; } } PruneFreeList(); UsedRectangles.Add(node); }
/// Inserts a single rectangle into the bin, possibly rotated. public override Rect Insert(RectSize rect, GenericOption option) { Rect newNode = new Rect(); // Unused in this function. We don't need to know the score after finding the position. int score1 = int.MaxValue; int score2 = int.MaxValue; int width = rect.Width, height = rect.Height; var optionMaxRectsBinPath = option as Option; switch (optionMaxRectsBinPath.Method) { case FreeRectChoiceHeuristic.RectBestShortSideFit: newNode = FindPositionForNewNodeBestShortSideFit(width, height, ref score1, ref score2); break; case FreeRectChoiceHeuristic.RectBottomLeftRule: newNode = FindPositionForNewNodeBottomLeft(width, height, ref score1, ref score2); break; case FreeRectChoiceHeuristic.RectContactPointRule: newNode = FindPositionForNewNodeContactPoint(width, height, ref score1); break; case FreeRectChoiceHeuristic.RectBestLongSideFit: newNode = FindPositionForNewNodeBestLongSideFit(width, height, ref score2, ref score1); break; case FreeRectChoiceHeuristic.RectBestAreaFit: newNode = FindPositionForNewNodeBestAreaFit(width, height, ref score1, ref score2); break; } if (newNode.Height == 0) { return(newNode); } int numRectanglesToProcess = freeRectangles.Count; for (int i = 0; i < numRectanglesToProcess; ++i) { if (SplitFreeNode(freeRectangles[i], ref newNode)) { freeRectangles.RemoveAt(i); --i; --numRectanglesToProcess; } } PruneFreeList(); UsedRectangles.Add(newNode); return(newNode); }
/// Inserts a list of rectangles into the bin. /// @param rects The list of rectangles to add. This list will be destroyed in the packing process. /// @param merge If true, performs Rectangle Merge operations during the packing process. /// @param rectChoice The free rectangle choice heuristic rule to use. /// @param splitMethod The free rectangle split heuristic rule to use. public void Insert(List <RectSize> rects, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod) { // Remember variables about the best packing choice we have made so far during the iteration process. int bestFreeRect = 0; int bestRect = 0; bool bestFlipped = false; // Pack rectangles one at a time until we have cleared the rects array of all rectangles. // rects will get destroyed in the process. while (rects.Count > 0) { // Stores the penalty score of the best rectangle placement - bigger=worse, smaller=better. int bestScore = int.MaxValue; for (int i = 0; i < freeRectangles.Count; ++i) { for (int j = 0; j < rects.Count; ++j) { // If this rectangle is a perfect match, we pick it instantly. if (rects[j].Width == freeRectangles[i].Width && rects[j].Height == freeRectangles[i].Height) { bestFreeRect = i; bestRect = j; bestFlipped = false; bestScore = int.MinValue; i = freeRectangles.Count; // Force a jump out of the outer loop as well - we got an instant fit. break; } // If flipping this rectangle is a perfect match, pick that then. else if (rects[j].Height == freeRectangles[i].Width && rects[j].Width == freeRectangles[i].Height) { bestFreeRect = i; bestRect = j; bestFlipped = true; bestScore = int.MinValue; i = freeRectangles.Count; // Force a jump out of the outer loop as well - we got an instant fit. break; } // Try if we can fit the rectangle upright. else if (rects[j].Width <= freeRectangles[i].Width && rects[j].Height <= freeRectangles[i].Height) { int score = ScoreByHeuristic(rects[j].Width, rects[j].Height, freeRectangles[i], rectChoice); if (score < bestScore) { bestFreeRect = i; bestRect = j; bestFlipped = false; bestScore = score; } } // If not, then perhaps flipping sideways will make it fit? else if (rects[j].Height <= freeRectangles[i].Width && rects[j].Width <= freeRectangles[i].Height) { int score = ScoreByHeuristic(rects[j].Height, rects[j].Width, freeRectangles[i], rectChoice); if (score < bestScore) { bestFreeRect = i; bestRect = j; bestFlipped = true; bestScore = score; } } } } // If we didn't manage to find any rectangle to pack, abort. if (bestScore == int.MaxValue) { return; } // Otherwise, we're good to go and do the actual packing. Rect newNode = new Rect { X = freeRectangles[bestFreeRect].X, Y = freeRectangles[bestFreeRect].Y, Width = rects[bestRect].Width, Height = rects[bestRect].Height }; if (bestFlipped) { var temp = newNode.Width; newNode.Width = newNode.Height; newNode.Height = temp; } // Remove the free space we lost in the bin. SplitFreeRectByHeuristic(freeRectangles[bestFreeRect], newNode, splitMethod); freeRectangles.RemoveAt(bestFreeRect); // Remove the rectangle we just packed from the input list. rects.RemoveAt(bestRect); // Perform a Rectangle Merge step if desired. if (merge) { MergeFreeList(); } // Remember the new used rectangle. UsedRectangles.Add(newNode); // Check that we're really producing correct packings here. disjointRects.Add(newNode); } }