Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions src/rectpack2D/best_bin_finder.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#pragma once
#include <variant>
#include <cassert>
#include <optional>
#include "rect_structs.h"

namespace rectpack2D {
Expand Down Expand Up @@ -227,16 +226,18 @@ namespace rectpack2D {
class empty_spaces_type,
class order_type,
class F,
class G,
class I
>
rect_wh find_best_packing_impl(F for_each_order, const I input) {
rect_wh find_best_packing_impl(F for_each_order, G best_callback, const I input, order_type best_order) {
const auto max_bin = rect_wh(input.max_bin_side, input.max_bin_side);

std::optional<order_type> best_order;

int best_total_inserted = -1;
auto best_bin = max_bin;

// Poor man's std::optional, since the best order storage is provided by the caller.
bool best_order_has_value = false;

/*
The root node is re-used on the TLS.
It is always reset before any packing attempt.
Expand All @@ -258,27 +259,29 @@ namespace rectpack2D {
Track which function inserts the most area in total,
just in case that all orders will fail to fit into the largest allowed bin.
*/
if (!best_order.has_value()) {
if (!best_order_has_value) {
if (*total_inserted > best_total_inserted) {
best_order = current_order;
best_order_has_value = true;
best_total_inserted = *total_inserted;
best_callback();
}
}
}
else if (const auto result_bin = std::get_if<rect_wh>(&packing)) {
/* Save the function if it performed the best. */
if (result_bin->area() <= best_bin.area()) {
best_order = current_order;
best_order_has_value = true;
best_bin = *result_bin;
best_callback();
}
}
});

assert(best_order.has_value());
assert(best_order_has_value);

root.reset(best_bin);

for (auto& rr : *best_order) {
for (auto& rr : best_order) {
auto& rect = dereference(rr).get_rect();

if (const auto ret = root.insert(rect.get_wh())) {
Expand Down
66 changes: 23 additions & 43 deletions src/rectpack2D/finders_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,13 @@ namespace rectpack2D {
using iterator_type = decltype(std::begin(subjects));
using order_type = rectpack2D::span<iterator_type>;

order_type ord(std::begin(subjects), std::end(subjects));

return find_best_packing_impl<empty_spaces_type, order_type>(
[&subjects](auto callback) { callback(order_type(std::begin(subjects), std::end(subjects))); },
input
[=](auto callback) { callback(ord); },
[]() {},
input,
ord
);
}

Expand All @@ -74,12 +78,11 @@ namespace rectpack2D {
using rect_type = output_rect_t<empty_spaces_type>;
using order_type = rectpack2D::span<rect_type**>;

constexpr auto count_orders = 1 + sizeof...(Comparators);
std::size_t count_valid_subjects = 0;

// Allocate space assuming no rectangle has an area of zero.
// We fill orders with valid rectangles only.
auto orders = std::make_unique<rect_type*[]>(count_orders * std::size(subjects));
auto orders = std::make_unique<rect_type*[]>(2 * std::size(subjects));

for (auto& s : subjects) {
auto& r = s.get_rect();
Expand All @@ -91,48 +94,25 @@ namespace rectpack2D {
orders[count_valid_subjects++] = std::addressof(r);
}

auto ith_order = [&orders, n = count_valid_subjects](const std::size_t i) {
return order_type(
orders.get() + i * n,
orders.get() + (i + 1) * n
);
};

{
/*
Zero-th order is already filled.
We duplicate it to all other orders.
*/
const auto first_order = ith_order(0);

for (std::size_t i = 1; i < count_orders; ++i) {
std::copy(
first_order.begin(),
first_order.end(),
ith_order(i).begin()
);
}
}

{
std::size_t i = 0;

auto make_order = [&i, ith_order](auto& predicate) {
const auto o = ith_order(i++);
std::sort(o.begin(), o.end(), predicate);
};

make_order(comparator);
(make_order(comparators), ...);
}
auto orders_begin = orders.get();
auto orders_separator = orders_begin + count_valid_subjects;
auto orders_end = orders_separator + count_valid_subjects;

return find_best_packing_impl<empty_spaces_type, order_type>(
[ith_order](auto callback) {
for (std::size_t i = 0; i < count_orders; ++i) {
callback(ith_order(i));
}
// Predicates can be expensive-to-copy objects such as std::function,
// so capture them by reference just to be sure.
[=, &comparator, &comparators...](auto callback) {
auto make_order = [=](auto predicate) {
std::sort(orders_begin, orders_separator, predicate);
callback({orders_begin, orders_separator});
};

make_order(comparator);
(make_order(comparators), ...);
},
input
[=]() { std::copy(orders_begin, orders_separator, orders_separator); },
input,
{ orders_separator, orders_end }
);
}

Expand Down
Loading