23 #include "base/integral_types.h"
29 using math::Vector2ui;
40 class BinPacker::Skyline {
43 typedef BinPacker::Rectangle Rectangle;
45 explicit Skyline(
const Vector2ui& bin_size);
46 explicit Skyline(
const Skyline& from)
47 : bin_size_(from.bin_size_),
48 levels_(from.levels_) {}
50 const Vector2ui& GetBinSize()
const {
return bin_size_; }
54 bool Insert(Rectangle* rect);
59 Level() : x(0), y(0),
width(0) {}
60 Level(
int x_in,
int y_in,
int width_in)
61 : x(x_in), y(y_in),
width(width_in) {}
71 bool FindLevel(Rectangle* rect,
size_t* level_index)
const;
76 void AddLevel(
size_t index,
const Rectangle& rect);
81 bool RectangleFits(
size_t level_index,
const Vector2ui& size,
87 const Vector2ui bin_size_;
88 std::vector<Level> levels_;
91 BinPacker::Skyline::Skyline(
const Vector2ui& bin_size)
92 : bin_size_(bin_size) {
94 levels_.push_back(Level(0, 0, bin_size[0]));
97 bool BinPacker::Skyline::Insert(Rectangle* rect) {
99 if (FindLevel(rect, &level_index)) {
100 AddLevel(level_index, *rect);
106 bool BinPacker::Skyline::FindLevel(Rectangle* rect,
size_t* level_index)
const {
108 int32 best_width = std::numeric_limits<int32>::max();
109 int32 best_height = std::numeric_limits<int32>::max();
113 const size_t num_levels = levels_.size();
114 for (
size_t i = 0; i < num_levels; ++i) {
116 if (RectangleFits(i, rect->size, &y)) {
117 const Level&
level = levels_[i];
118 const int32 height = y +
static_cast<int32
>(rect->size[1]);
119 if (height < best_height ||
120 (height == best_height && level.width < best_width)) {
121 best_height = height;
123 best_width = level.width;
124 rect->bottom_left.Set(level.x, y);
131 *level_index = best_index;
136 void BinPacker::Skyline::AddLevel(
size_t index,
const Rectangle& rect) {
137 const Level
level(rect.bottom_left[0],
138 rect.bottom_left[1] + rect.size[1],
140 levels_.insert(levels_.begin() + index,
level);
142 DCHECK_LE(level.x + level.width, static_cast<int32>(bin_size_[0]));
143 DCHECK_LE(level.y, static_cast<int32>(bin_size_[1]));
145 for (
size_t i = index + 1; i < levels_.size(); ++i) {
146 const Level& prev_level = levels_[i - 1];
147 Level& cur_level = levels_[i];
149 const int x_diff = prev_level.x + prev_level.width - cur_level.x;
152 cur_level.x += x_diff;
153 cur_level.width -= x_diff;
154 if (cur_level.width > 0)
156 levels_.erase(levels_.begin() + i);
162 bool BinPacker::Skyline::RectangleFits(
163 size_t level_index,
const Vector2ui& size, int32* y)
const {
164 const int x = levels_[level_index].x;
165 if (x + size[0] > bin_size_[0])
168 int width_remaining = size[0];
169 size_t i = level_index;
170 *y = levels_[level_index].y;
171 while (width_remaining > 0) {
173 const Level& level = levels_[i];
174 *y = std::max(*y, level.y);
175 if (*y + size[1] > bin_size_[1])
177 width_remaining -= level.width;
183 void BinPacker::Skyline::MergeLevels() {
184 for (
size_t i = 1; i < levels_.size(); ++i) {
185 if (levels_[i - 1].y == levels_[i].y) {
186 levels_[i - 1].width += levels_[i].width;
187 levels_.erase(levels_.begin() + i);
201 BinPacker::BinPacker() : num_rectangles_packed_(0) {}
208 rectangles_ = from.rectangles_;
209 if (from.skyline_.get())
210 skyline_.reset(
new Skyline(*from.skyline_));
211 num_rectangles_packed_ = from.num_rectangles_packed_;
216 if (!skyline_.get() || skyline_->GetBinSize() != bin_size) {
217 skyline_.reset(
new Skyline(bin_size));
218 num_rectangles_packed_ = 0;
223 for (
size_t i = num_rectangles_packed_; i < rectangles_.size(); ++i) {
225 if (!skyline_->Insert(&rectangles_[i]))
227 ++num_rectangles_packed_;
229 return num_rectangles_packed_ == rectangles_.size();
BinPacker()
BinPacker functions.
const size_t kInvalidIndex
kInvalidIndex is a size_t value that is very unlikely to be a valid index.
bool Pack(const math::Vector2ui &bin_size)
Tries to pack all of the rectangles into a bin of the given size.
This class implements generic 2D bin-packing using a modified version of the Skyline Bottom-Left algo...
BinPacker & operator=(const BinPacker &from)
Copyright 2016 Google Inc.
#define DCHECK_LE(val1, val2)
#define DCHECK_LT(val1, val2)