kicad/thirdparty/rectpack2d/rectpack2d/finders_interface.h

156 lines
4.1 KiB
C++

#pragma once
#include <optional>
#include <vector>
#include <array>
#include <variant>
#include <algorithm>
#include "insert_and_split.h"
#include "empty_spaces.h"
#include "empty_space_allocators.h"
#include "best_bin_finder.h"
namespace rectpack2D {
template <class empty_spaces_type>
using output_rect_t = typename empty_spaces_type::output_rect_type;
template <class F, class G>
struct finder_input {
const int max_bin_side;
const int discard_step;
F handle_successful_insertion;
G handle_unsuccessful_insertion;
const flipping_option flipping_mode;
};
template <class F, class G>
auto make_finder_input(
const int max_bin_side,
const int discard_step,
F&& handle_successful_insertion,
G&& handle_unsuccessful_insertion,
const flipping_option flipping_mode
) {
return finder_input<F, G> {
max_bin_side,
discard_step,
std::forward<F>(handle_successful_insertion),
std::forward<G>(handle_unsuccessful_insertion),
flipping_mode
};
};
/*
Finds the best packing for the rectangles,
just in the order that they were passed.
*/
template <class empty_spaces_type, class F, class G>
rect_wh find_best_packing_dont_sort(
std::vector<output_rect_t<empty_spaces_type>>& subjects,
const finder_input<F, G>& input
) {
using order_type = std::remove_reference_t<decltype(subjects)>;
return find_best_packing_impl<empty_spaces_type, order_type>(
[&subjects](auto callback) { callback(subjects); },
input
);
}
/*
Finds the best packing for the rectangles.
Accepts a list of predicates able to compare two input rectangles.
The function will try to pack the rectangles in all orders generated by the predicates,
and will only write the x, y coordinates of the best packing found among the orders.
*/
template <class empty_spaces_type, class F, class G, class Comparator, class... Comparators>
std::optional<rect_wh> find_best_packing(
std::vector<output_rect_t<empty_spaces_type>>& subjects,
const finder_input<F, G>& input,
Comparator comparator,
Comparators... comparators
) {
using rect_type = output_rect_t<empty_spaces_type>;
using order_type = std::vector<rect_type*>;
constexpr auto count_orders = 1 + sizeof...(Comparators);
thread_local std::array<order_type, count_orders> orders;
{
/* order[0] will always exist since this overload requires at least one comparator */
auto& initial_pointers = orders[0];
initial_pointers.clear();
for (auto& s : subjects) {
if (s.area() > 0) {
initial_pointers.emplace_back(std::addressof(s));
}
}
for (std::size_t i = 1; i < count_orders; ++i) {
orders[i] = initial_pointers;
}
}
std::size_t f = 0;
auto& orders_ref = orders;
auto make_order = [&f, &orders_ref](auto& predicate) {
std::sort(orders_ref[f].begin(), orders_ref[f].end(), predicate);
++f;
};
make_order(comparator);
(make_order(comparators), ...);
return find_best_packing_impl<empty_spaces_type, order_type>(
[&orders_ref](auto callback){ for (auto& o : orders_ref) { callback(o); } },
input
);
}
/*
Finds the best packing for the rectangles.
Provides a list of several sensible comparison predicates.
*/
template <class empty_spaces_type, class F, class G>
std::optional<rect_wh> find_best_packing(
std::vector<output_rect_t<empty_spaces_type>>& subjects,
const finder_input<F, G>& input
) {
using rect_type = output_rect_t<empty_spaces_type>;
return find_best_packing<empty_spaces_type>(
subjects,
input,
[](const rect_type* const a, const rect_type* const b) {
return a->area() > b->area();
},
[](const rect_type* const a, const rect_type* const b) {
return a->perimeter() > b->perimeter();
},
[](const rect_type* const a, const rect_type* const b) {
return std::max(a->w, a->h) > std::max(b->w, b->h);
},
[](const rect_type* const a, const rect_type* const b) {
return a->w > b->w;
},
[](const rect_type* const a, const rect_type* const b) {
return a->h > b->h;
},
[](const rect_type* const a, const rect_type* const b) {
return a->get_wh().pathological_mult() > b->get_wh().pathological_mult();
}
);
}
}