From 670058fa3c1afb9afababec32afad204dbb7216f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 10 Jan 2016 21:54:28 -0600 Subject: [PATCH] Switch to the bottom-left picker for the Skyline Bin Packer --- src/SkylineBinPack.cpp | 69 +++++++++++++++++++++++++++++++++++++++++- src/SkylineBinPack.h | 3 ++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/SkylineBinPack.cpp b/src/SkylineBinPack.cpp index 33f862043..4e9de153e 100644 --- a/src/SkylineBinPack.cpp +++ b/src/SkylineBinPack.cpp @@ -119,7 +119,7 @@ Rect SkylineBinPack::Insert(int width, int height) return newNode; } - return InsertMinWaste(width, height); + return InsertBottomLeft(width, height); } bool SkylineBinPack::RectangleFits(int skylineNodeIndex, int width, int height, int &y) const @@ -254,6 +254,73 @@ void SkylineBinPack::MergeSkylines() } } +Rect SkylineBinPack::InsertBottomLeft(int width, int height) +{ + int bestHeight; + int bestWidth; + int bestIndex; + Rect newNode = FindPositionForNewNodeBottomLeft(width, height, bestHeight, bestWidth, bestIndex); + + if (bestIndex != -1) + { + assert(disjointRects.Disjoint(newNode)); + // Perform the actual packing. + AddSkylineLevel(bestIndex, newNode); + + usedSurfaceArea += width * height; +#ifdef _DEBUG + disjointRects.Add(newNode); +#endif + } + else + memset(&newNode, 0, sizeof(Rect)); + + return newNode; +} + +Rect SkylineBinPack::FindPositionForNewNodeBottomLeft(int width, int height, int &bestHeight, int &bestWidth, int &bestIndex) const +{ + bestHeight = INT_MAX; + bestIndex = -1; + // Used to break ties if there are nodes at the same level. Then pick the narrowest one. + bestWidth = INT_MAX; + Rect newNode = { 0, 0, 0, 0 }; + for(unsigned i = 0; i < skyLine.Size(); ++i) + { + int y; + if (RectangleFits(i, width, height, y)) + { + if (y + height < bestHeight || (y + height == bestHeight && skyLine[i].width < bestWidth)) + { + bestHeight = y + height; + bestIndex = i; + bestWidth = skyLine[i].width; + newNode.x = skyLine[i].x; + newNode.y = y; + newNode.width = width; + newNode.height = height; + assert(disjointRects.Disjoint(newNode)); + } + } +/* if (RectangleFits(i, height, width, y)) + { + if (y + width < bestHeight || (y + width == bestHeight && skyLine[i].width < bestWidth)) + { + bestHeight = y + width; + bestIndex = i; + bestWidth = skyLine[i].width; + newNode.x = skyLine[i].x; + newNode.y = y; + newNode.width = height; + newNode.height = width; + assert(disjointRects.Disjoint(newNode)); + } + } +*/ } + + return newNode; +} + Rect SkylineBinPack::InsertMinWaste(int width, int height) { int bestHeight; diff --git a/src/SkylineBinPack.h b/src/SkylineBinPack.h index f93ddd29d..937c88de6 100644 --- a/src/SkylineBinPack.h +++ b/src/SkylineBinPack.h @@ -72,7 +72,10 @@ private: bool useWasteMap; GuillotineBinPack wasteMap; + Rect InsertBottomLeft(int width, int height); Rect InsertMinWaste(int width, int height); + + Rect FindPositionForNewNodeBottomLeft(int width, int height, int &bestHeight, int &bestWidth, int &bestIndex) const; Rect FindPositionForNewNodeMinWaste(int width, int height, int &bestHeight, int &bestWastedArea, int &bestIndex) const; bool RectangleFits(int skylineNodeIndex, int width, int height, int &y) const;