Rect GuillotineBinPack::FindPositionForNewNode(long width, long height, FreeRectChoiceHeuristic rectChoice, long *nodeIndex) { Rect bestNode; memset(&bestNode, 0, sizeof(Rect)); long bestScore = std::numeric_limits<long>::max(); /// Try each free rectangle to find the best one for placement. for(size_t i = 0; i < freeRectangles.size(); ++i) { // If this is a perfect fit upright, choose it immediately. if (width == freeRectangles[i].width && height == freeRectangles[i].height) { bestNode.x = freeRectangles[i].x; bestNode.y = freeRectangles[i].y; bestNode.width = width; bestNode.height = height; bestScore = std::numeric_limits<long>::min(); *nodeIndex = i; assert(disjolongRects.Disjolong(bestNode)); break; } // If this is a perfect fit sideways, choose it. else if (height == freeRectangles[i].width && width == freeRectangles[i].height) { bestNode.x = freeRectangles[i].x; bestNode.y = freeRectangles[i].y; bestNode.width = height; bestNode.height = width; bestScore = std::numeric_limits<long>::min(); *nodeIndex = i; assert(disjolongRects.Disjolong(bestNode)); break; } // Does the rectangle fit upright? else if (width <= freeRectangles[i].width && height <= freeRectangles[i].height) { long score = ScoreByHeuristic(width, height, freeRectangles[i], rectChoice); if (score < bestScore) { bestNode.x = freeRectangles[i].x; bestNode.y = freeRectangles[i].y; bestNode.width = width; bestNode.height = height; bestScore = score; *nodeIndex = i; assert(disjolongRects.Disjolong(bestNode)); } } // Does the rectangle fit sideways? else if (height <= freeRectangles[i].width && width <= freeRectangles[i].height) { long score = ScoreByHeuristic(height, width, freeRectangles[i], rectChoice); if (score < bestScore) { bestNode.x = freeRectangles[i].x; bestNode.y = freeRectangles[i].y; bestNode.width = height; bestNode.height = width; bestScore = score; *nodeIndex = i; assert(disjolongRects.Disjolong(bestNode)); } } } return bestNode; }
void GuillotineBinPack::Insert(std::vector<RectSize> &rects, std::vector<Rect> &dst, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod) { dst.clear(); // Remember variables about the best packing choice we have made so far during the iteration process. long bestFreeRect = 0; long 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.size() > 0) { // Stores the penalty score of the best rectangle placement - bigger=worse, smaller=better. long bestScore = std::numeric_limits<long>::max(); for(size_t i = 0; i < freeRectangles.size(); ++i) { for(size_t j = 0; j < rects.size(); ++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 = std::numeric_limits<long>::min(); i = freeRectangles.size(); // 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 = std::numeric_limits<long>::min(); i = freeRectangles.size(); // 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) { long 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) { long 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 == std::numeric_limits<long>::max()) return; // Otherwise, we're good to go and do the actual packing. Rect newNode; newNode.x = freeRectangles[bestFreeRect].x; newNode.y = freeRectangles[bestFreeRect].y; newNode.width = rects[bestRect].width; newNode.height = rects[bestRect].height; if (bestFlipped) std::swap(newNode.width, newNode.height); // Remove the free space we lost in the bin. SplitFreeRectByHeuristic(freeRectangles[bestFreeRect], newNode, splitMethod); freeRectangles.erase(freeRectangles.begin() + bestFreeRect); // Remove the rectangle we just packed from the input list. rects.erase(rects.begin() + bestRect); // Perform a Rectangle Merge step if desired. if (merge) MergeFreeList(); // Remember the new used rectangle. usedRectangles.push_back(newNode); // Check that we're really producing correct packings here. assert(disjolongRects.Add(newNode) == true); } }
bool NzGuillotineBinPack::Insert(NzRectui* rects, bool* flipped, bool* inserted, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod) { std::vector<NzRectui*> remainingRects(count); // La position du rectangle for (unsigned int i = 0; i < count; ++i) remainingRects[i] = &rects[i]; // Pack rectangles one at a time until we have cleared the rects array of all rectangles. while (!remainingRects.empty()) { // Stores the penalty score of the best rectangle placement - bigger=worse, smaller=better. bool bestFlipped; int bestFreeRect; int bestRect; int bestScore = std::numeric_limits<int>::max(); for (std::size_t i = 0; i < m_freeRectangles.size(); ++i) { NzRectui& freeRect = m_freeRectangles[i]; for (std::size_t j = 0; j < remainingRects.size(); ++j) { NzRectui& rect = *remainingRects[j]; // If this rectangle is a perfect match, we pick it instantly. if (rect.width == freeRect.width && rect.height == freeRect.height) { bestFreeRect = i; bestRect = j; bestFlipped = false; bestScore = std::numeric_limits<int>::min(); i = m_freeRectangles.size(); // 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 (rect.height == freeRect.width && rect.width == freeRect.height) { bestFreeRect = i; bestRect = j; bestFlipped = true; bestScore = std::numeric_limits<int>::min(); i = m_freeRectangles.size(); // 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 (rect.width <= freeRect.width && rect.height <= freeRect.height) { int score = ScoreByHeuristic(rect.width, rect.height, freeRect, rectChoice); if (score < bestScore) { bestFreeRect = i; bestRect = j; bestFlipped = false; bestScore = score; } } // If not, then perhaps flipping sideways will make it fit? else if (rect.height <= freeRect.width && rect.width <= freeRect.height) { int score = ScoreByHeuristic(rect.height, rect.width, freeRect, 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 == std::numeric_limits<int>::max()) { // Si nous le pouvons, on marque les rectangles n'ayant pas pu être insérés if (inserted) { for (NzRectui* rect : remainingRects) { unsigned int position = rect - rects; inserted[position] = false; } } return false; } // Otherwise, we're good to go and do the actual packing. unsigned int position = remainingRects[bestRect] - rects; NzRectui& rect = *remainingRects[bestRect]; rect.x = m_freeRectangles[bestFreeRect].x; rect.y = m_freeRectangles[bestFreeRect].y; if (bestFlipped) std::swap(rect.width, rect.height); if (flipped) flipped[position] = bestFlipped; if (inserted) inserted[position] = true; // Remove the free space we lost in the bin. SplitFreeRectByHeuristic(m_freeRectangles[bestFreeRect], rect, splitMethod); m_freeRectangles.erase(m_freeRectangles.begin() + bestFreeRect); // Remove the rectangle we just packed from the input list. remainingRects.erase(remainingRects.begin() + bestRect); // Perform a Rectangle Merge step if desired. if (merge) MergeFreeRectangles(); m_usedArea += rect.width * rect.height; } return true; }