diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index e61f11517..00656a629 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -83,7 +83,7 @@ const double BIG_ITEM_TRESHOLD = 0.02; // Fill in the placer algorithm configuration with values carefully chosen for // Slic3r. template<class PConf> -void fill_config(PConf& pcfg) { +void fill_config(PConf& pcfg, const ArrangeParams ¶ms) { // Align the arranged pile into the center of the bin pcfg.alignment = PConf::Alignment::CENTER; @@ -93,14 +93,17 @@ void fill_config(PConf& pcfg) { // TODO cannot use rotations until multiple objects of same geometry can // handle different rotations. - pcfg.rotations = { 0.0 }; + if (params.allow_rotations) + pcfg.rotations = {0., PI / 2., PI, 3. * PI / 2. }; + else + pcfg.rotations = {0.}; // The accuracy of optimization. // Goes from 0.0 to 1.0 and scales performance as well - pcfg.accuracy = 0.65f; + pcfg.accuracy = params.accuracy; // Allow parallel execution. - pcfg.parallel = true; + pcfg.parallel = params.parallel; } // Apply penalty to object function result. This is used only when alignment @@ -304,15 +307,15 @@ protected: public: AutoArranger(const TBin & bin, - Distance dist, + const ArrangeParams ¶ms, std::function<void(unsigned)> progressind, std::function<bool(void)> stopcond) - : m_pck(bin, dist) + : m_pck(bin, params.min_obj_distance) , m_bin(bin) , m_bin_area(sl::area(bin)) , m_norm(std::sqrt(m_bin_area)) { - fill_config(m_pconf); + fill_config(m_pconf, params); // Set up a callback that is called just before arranging starts // This functionality is provided by the Nester class (m_pack). @@ -349,12 +352,6 @@ public: m_pck.configure(m_pconf); } - - AutoArranger(const TBin & bin, - std::function<void(unsigned)> progressind, - std::function<bool(void)> stopcond) - : AutoArranger{bin, 0 /* no min distance */, progressind, stopcond} - {} template<class It> inline void operator()(It from, It to) { m_rtree.clear(); @@ -457,7 +454,7 @@ void _arrange( std::vector<Item> & shapes, std::vector<Item> & excludes, const BinT & bin, - const ArrangeParams & params, + const ArrangeParams ¶ms, std::function<void(unsigned)> progressfn, std::function<bool()> stopfn) { @@ -467,11 +464,10 @@ void _arrange( auto corrected_bin = bin; sl::offset(corrected_bin, md); - - AutoArranger<BinT> arranger{corrected_bin, progressfn, stopfn}; - - arranger.config().accuracy = params.accuracy; - arranger.config().parallel = params.parallel; + ArrangeParams mod_params = params; + mod_params.min_obj_distance = 0; + + AutoArranger<BinT> arranger{corrected_bin, mod_params, progressfn, stopfn}; auto infl = coord_t(std::ceil(params.min_obj_distance / 2.0)); for (Item& itm : shapes) itm.inflate(infl); diff --git a/src/libslic3r/Arrange.hpp b/src/libslic3r/Arrange.hpp index 7630ab3e8..65c3984d5 100644 --- a/src/libslic3r/Arrange.hpp +++ b/src/libslic3r/Arrange.hpp @@ -78,6 +78,8 @@ struct ArrangeParams { /// Allow parallel execution. bool parallel = true; + + bool allow_rotations = false; /// Progress indicator callback called when an object gets packed. /// The unsigned argument is the number of items remaining to pack. diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index cd82878c2..ae08d40d9 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -170,7 +170,7 @@ void GLCanvas3D::LayersEditing::init() } void GLCanvas3D::LayersEditing::set_config(const DynamicPrintConfig* config) -{ +{ m_config = config; delete m_slicing_parameters; m_slicing_parameters = nullptr; @@ -1325,6 +1325,9 @@ void GLCanvas3D::update_instance_printable_state_for_objects(std::vector<size_t> void GLCanvas3D::set_config(const DynamicPrintConfig* config) { + if (!m_config) + m_arrange_settings.distance = min_object_distance(*config); + m_config = config; m_layers_editing.set_config(config); } @@ -3847,6 +3850,30 @@ bool GLCanvas3D::_render_search_list(float pos_x) const return action_taken; } +bool GLCanvas3D::_render_arrange_popup() +{ + ImGuiWrapper *imgui = wxGetApp().imgui(); + + float x = 0.5f * (float)get_canvas_size().get_width(); + imgui->set_next_window_pos(x, m_main_toolbar.get_height(), ImGuiCond_Always, 0.5f, 0.0f); + + imgui->begin(_(L("Arrange options")), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); + ArrangeSettings settings = m_arrange_settings; + + if (imgui->slider_float(_(L("Gap size")), &settings.distance, 0.f, 100.f)) + m_arrange_settings.distance = settings.distance; + + if (imgui->slider_float(_(L("Accuracy")), &settings.accuracy, 0.f, 1.f)) + m_arrange_settings.accuracy = settings.accuracy; + + if (imgui->checkbox(_(L("Enable rotations")), settings.enable_rotation)) + m_arrange_settings.enable_rotation = settings.enable_rotation; + + imgui->end(); + + return false; +} + #define ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT 0 #if ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT static void debug_output_thumbnail(const ThumbnailData& thumbnail_data) @@ -4263,6 +4290,13 @@ bool GLCanvas3D::_init_main_toolbar() item.sprite_id = 3; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ARRANGE)); }; item.enabling_callback = []()->bool { return wxGetApp().plater()->can_arrange(); }; + item.right.toggable = true; + item.right.render_callback = [this](float left, float right, float, float) { + if (m_canvas != nullptr) + { + _render_arrange_popup(); + } + }; if (!m_main_toolbar.add_item(item)) return false; diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 0975e59a0..c760dc323 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -381,6 +381,13 @@ public: Cross }; + struct ArrangeSettings + { + float distance = 6.; + float accuracy = 0.65f; + bool enable_rotation = false; + }; + private: wxGLCanvas* m_canvas; wxGLContext* m_context; @@ -452,6 +459,8 @@ private: mutable bool m_tooltip_enabled{ true }; Slope m_slope; + ArrangeSettings m_arrange_settings; + public: explicit GLCanvas3D(wxGLCanvas* canvas); ~GLCanvas3D(); @@ -671,6 +680,8 @@ public: void use_slope(bool use) { m_slope.use(use); } void set_slope_normal_angle(float angle_in_deg) { m_slope.set_normal_angle(angle_in_deg); } + const ArrangeSettings& get_arrange_settings() const { return m_arrange_settings; } + private: bool _is_shown_on_screen() const; @@ -717,6 +728,7 @@ private: void _render_selection_sidebar_hints() const; bool _render_undo_redo_stack(const bool is_undo, float pos_x) const; bool _render_search_list(float pos_x) const; + bool _render_arrange_popup(); void _render_thumbnail_internal(ThumbnailData& thumbnail_data, bool printable_only, bool parts_only, bool show_bed, bool transparent_background) const; // render thumbnail using an off-screen framebuffer void _render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background) const; diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.cpp b/src/slic3r/GUI/Jobs/ArrangeJob.cpp index 41fd717da..9bb26e096 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.cpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.cpp @@ -147,11 +147,13 @@ void ArrangeJob::prepare() void ArrangeJob::process() { static const auto arrangestr = _(L("Arranging")); - - double dist = min_object_distance(*m_plater->config()); + + GLCanvas3D::ArrangeSettings settings = + m_plater->canvas3D()->get_arrange_settings(); arrangement::ArrangeParams params; - params.min_obj_distance = scaled(dist); + params.min_obj_distance = scaled(settings.distance); + params.allow_rotations = settings.enable_rotation; auto count = unsigned(m_selected.size() + m_unprintable.size()); Points bedpts = get_bed_shape(*m_plater->config());