diff --git a/GuillotineBinPack.cpp b/GuillotineBinPack.cpp index 3cc8755..c3c4ae6 100644 --- a/GuillotineBinPack.cpp +++ b/GuillotineBinPack.cpp @@ -1,10 +1,11 @@ /** @file GuillotineBinPack.cpp - @author Jukka Jylänki + @author Jukka Jyl�nki @brief Implements different bin packer algorithms that use the GUILLOTINE data structure. This work is released to Public Domain, do whatever you want with it. */ +#include #include #include #include @@ -19,25 +20,20 @@ namespace rbp { using namespace std; -GuillotineBinPack::GuillotineBinPack() -:binWidth(0), -binHeight(0) +GuillotineBinPack::GuillotineBinPack() : binWidth(0), binHeight(0) { } -GuillotineBinPack::GuillotineBinPack(int width, int height) +GuillotineBinPack::GuillotineBinPack(int width, int height, bool allowFlip) { - Init(width, height); + Init(width, height, allowFlip); } -void GuillotineBinPack::Init(int width, int height) +void GuillotineBinPack::Init(int width, int height, bool allowFlip) { binWidth = width; binHeight = height; - -#ifdef _DEBUG - disjointRects.Clear(); -#endif + binAllowFlip = allowFlip; // Clear any memory of previously packed rectangles. usedRectangles.clear(); @@ -83,7 +79,7 @@ void GuillotineBinPack::Insert(std::vector &rects, bool merge, 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) + else if (binAllowFlip && rects[j].height == freeRectangles[i].width && rects[j].width == freeRectangles[i].height) { bestFreeRect = i; bestRect = j; @@ -105,7 +101,7 @@ void GuillotineBinPack::Insert(std::vector &rects, bool merge, } } // If not, then perhaps flipping sideways will make it fit? - else if (rects[j].height <= freeRectangles[i].width && rects[j].width <= freeRectangles[i].height) + else if (binAllowFlip && 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) @@ -147,8 +143,6 @@ void GuillotineBinPack::Insert(std::vector &rects, bool merge, // Remember the new used rectangle. usedRectangles.push_back(newNode); - // Check that we're really producing correct packings here. - debug_assert(disjointRects.Add(newNode) == true); } } @@ -358,9 +352,6 @@ Rect GuillotineBinPack::Insert(int width, int height, bool merge, FreeRectChoice // Remember the new used rectangle. usedRectangles.push_back(newRect); - // Check that we're really producing correct packings here. - debug_assert(disjointRects.Add(newRect) == true); - return newRect; } @@ -446,11 +437,10 @@ Rect GuillotineBinPack::FindPositionForNewNode(int width, int height, FreeRectCh bestNode.height = height; bestScore = std::numeric_limits::min(); *nodeIndex = i; - debug_assert(disjointRects.Disjoint(bestNode)); break; } // If this is a perfect fit sideways, choose it. - else if (height == freeRectangles[i].width && width == freeRectangles[i].height) + else if (binAllowFlip && height == freeRectangles[i].width && width == freeRectangles[i].height) { bestNode.x = freeRectangles[i].x; bestNode.y = freeRectangles[i].y; @@ -458,7 +448,6 @@ Rect GuillotineBinPack::FindPositionForNewNode(int width, int height, FreeRectCh bestNode.height = width; bestScore = std::numeric_limits::min(); *nodeIndex = i; - debug_assert(disjointRects.Disjoint(bestNode)); break; } // Does the rectangle fit upright? @@ -474,11 +463,10 @@ Rect GuillotineBinPack::FindPositionForNewNode(int width, int height, FreeRectCh bestNode.height = height; bestScore = score; *nodeIndex = i; - debug_assert(disjointRects.Disjoint(bestNode)); } } // Does the rectangle fit sideways? - else if (height <= freeRectangles[i].width && width <= freeRectangles[i].height) + else if (binAllowFlip && height <= freeRectangles[i].width && width <= freeRectangles[i].height) { int score = ScoreByHeuristic(height, width, freeRectangles[i], rectChoice); @@ -490,7 +478,6 @@ Rect GuillotineBinPack::FindPositionForNewNode(int width, int height, FreeRectCh bestNode.height = width; bestScore = score; *nodeIndex = i; - debug_assert(disjointRects.Disjoint(bestNode)); } } } @@ -579,18 +566,10 @@ void GuillotineBinPack::SplitFreeRectAlongAxis(const Rect &freeRect, const Rect if (right.width > 0 && right.height > 0) freeRectangles.push_back(right); - debug_assert(disjointRects.Disjoint(bottom)); - debug_assert(disjointRects.Disjoint(right)); } void GuillotineBinPack::MergeFreeList() { -#ifdef _DEBUG - DisjointRectCollection test; - for(size_t i = 0; i < freeRectangles.size(); ++i) - assert(test.Add(freeRectangles[i]) == true); -#endif - // Do a Theta(n^2) loop to see if any pair of free rectangles could me merged into one. // Note that we miss any opportunities to merge three rectangles into one. (should call this function again to detect that) for(size_t i = 0; i < freeRectangles.size(); ++i) @@ -630,11 +609,6 @@ void GuillotineBinPack::MergeFreeList() } } -#ifdef _DEBUG - test.Clear(); - for(size_t i = 0; i < freeRectangles.size(); ++i) - assert(test.Add(freeRectangles[i]) == true); -#endif } } diff --git a/GuillotineBinPack.h b/GuillotineBinPack.h index 66ff2c9..84aa866 100644 --- a/GuillotineBinPack.h +++ b/GuillotineBinPack.h @@ -1,5 +1,5 @@ /** @file GuillotineBinPack.h - @author Jukka Jylänki + @author Jukka Jyl�nki @brief Implements different bin packer algorithms that use the GUILLOTINE data structure. @@ -22,11 +22,11 @@ class GuillotineBinPack GuillotineBinPack(); /// Initializes a new bin of the given size. - GuillotineBinPack(int width, int height); + GuillotineBinPack(int width, int height, bool allowFlip = true); /// (Re)initializes the packer to an empty bin of width x height units. Call whenever /// you need to restart with a new bin. - void Init(int width, int height); + void Init(int width, int height, bool allowFlip = true); /// Specifies the different choice heuristics that can be used when deciding which of the free subrectangles /// to place the to-be-packed rectangle into. @@ -92,6 +92,8 @@ class GuillotineBinPack int binWidth; int binHeight; + bool binAllowFlip; + /// Stores a list of all the rectangles that we have packed so far. This is used only to compute the Occupancy ratio, /// so if you want to have the packer consume less memory, this can be removed. std::vector usedRectangles; @@ -99,11 +101,6 @@ class GuillotineBinPack /// Stores a list of rectangles that represents the free area of the bin. This rectangles in this list are disjoint. std::vector freeRectangles; -#ifdef _DEBUG - /// Used to track that the packer produces proper packings. - DisjointRectCollection disjointRects; -#endif - /// Goes through the list of free rectangles and finds the best one to place a rectangle of given size into. /// Running time is Theta(|freeRectangles|). /// @param nodeIndex [out] The index of the free rectangle in the freeRectangles array into which the new