#pragma once #include #include #include #include #include #include "insert_and_split.h" #include "empty_spaces.h" #include "empty_space_allocators.h" #include "best_bin_finder.h" namespace rectpack2D { template using output_rect_t = typename empty_spaces_type::output_rect_type; template 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 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 { max_bin_side, discard_step, std::forward(handle_successful_insertion), std::forward(handle_unsuccessful_insertion), flipping_mode }; }; /* Finds the best packing for the rectangles, just in the order that they were passed. */ template rect_wh find_best_packing_dont_sort( Subjects& subjects, const finder_input& input ) { using order_type = std::remove_reference_t; return find_best_packing_impl( [&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 rect_wh find_best_packing( Subjects& subjects, const finder_input& input, Comparator comparator, Comparators... comparators ) { using rect_type = output_rect_t; using order_type = std::vector; constexpr auto count_orders = 1 + sizeof...(Comparators); thread_local std::array 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) { auto& r = s.get_rect(); if (r.area() > 0) { initial_pointers.emplace_back(std::addressof(r)); } } 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( [&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 rect_wh find_best_packing( Subjects& subjects, const finder_input& input ) { using rect_type = output_rect_t; return find_best_packing( 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; } ); } }