From 8854276965eb8757d659bc4a26c2fedb1a752de1 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 18 Dec 2018 10:10:14 +0100 Subject: [PATCH 1/4] Added size fields to sidebar matrix manipulators --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 142 +++++++++++++--------- src/slic3r/GUI/GUI_ObjectManipulation.hpp | 19 ++- 2 files changed, 93 insertions(+), 68 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 30e701907..9bc316deb 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -39,24 +39,43 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : change_rotation_value(new_value); else if (param == "scale") change_scale_value(new_value); + else if (param == "size") + change_size_value(new_value); }; m_og->m_fill_empty_value = [this](const std::string& opt_key) { - if (opt_key == "scale_unit") - return; - std::string param; std::copy(opt_key.begin(), opt_key.end() - 2, std::back_inserter(param)); + + double value = 0.0; + if (param == "position") { int axis = opt_key.back() == 'x' ? 0 : opt_key.back() == 'y' ? 1 : 2; - m_og->set_value(opt_key, double_to_string(cache_position(axis))); - return; + value = cache_position(axis); + } + else if (param == "rotation") { + int axis = opt_key.back() == 'x' ? 0 : + opt_key.back() == 'y' ? 1 : 2; + + value = cache_rotation(axis); + } + else if (param == "scale") { + int axis = opt_key.back() == 'x' ? 0 : + opt_key.back() == 'y' ? 1 : 2; + + value = cache_scale(axis); + } + else if (param == "size") { + int axis = opt_key.back() == 'x' ? 0 : + opt_key.back() == 'y' ? 1 : 2; + + value = cache_size(axis); } - m_og->set_value(opt_key, double_to_string(0.0)); + m_og->set_value(opt_key, double_to_string(value)); }; m_og->m_set_focus = [this](const std::string& opt_key) @@ -94,51 +113,28 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : auto add_og_to_object_settings = [](const std::string& option_name, const std::string& sidetext) { Line line = { _(option_name), "" }; - if (option_name == "Scale") { - line.near_label_widget = [](wxWindow* parent) { - auto btn = new PrusaLockButton(parent, wxID_ANY); - btn->Bind(wxEVT_BUTTON, [btn](wxCommandEvent &event) { - event.Skip(); - wxTheApp->CallAfter([btn]() { - wxGetApp().obj_manipul()->set_uniform_scaling(btn->IsLocked()); - }); - }); - return btn; - }; - } - ConfigOptionDef def; def.type = coFloat; def.default_value = new ConfigOptionFloat(0.0); def.width = 50; if (option_name == "Rotation") + { def.min = -360; + def.max = 360; + } const std::string lower_name = boost::algorithm::to_lower_copy(option_name); std::vector axes{ "x", "y", "z" }; for (auto axis : axes) { - if (axis == "z" && option_name != "Scale") + if (axis == "z") def.sidetext = sidetext; Option option = Option(def, lower_name + "_" + axis); option.opt.full_width = true; line.append_option(option); } - if (option_name == "Scale") - { - def.width = 45; - def.type = coStrings; - def.gui_type = "select_open"; - def.enum_labels.push_back(L("%")); - def.enum_labels.push_back(L("mm")); - def.default_value = new ConfigOptionStrings{ "mm" }; - - const Option option = Option(def, lower_name + "_unit"); - line.append_option(option); - } - return line; }; @@ -146,7 +142,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : // Settings table m_og->append_line(add_og_to_object_settings(L("Position"), L("mm")), &m_move_Label); m_og->append_line(add_og_to_object_settings(L("Rotation"), "°")); - m_og->append_line(add_og_to_object_settings(L("Scale"), "mm")); + m_og->append_line(add_og_to_object_settings(L("Scale"), "%")); + m_og->append_line(add_og_to_object_settings(L("Size"), "mm")); /* Unused parameter at this time def.label = L("Place on bed"); @@ -220,6 +217,7 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele update_position_value(volume->get_instance_offset()); update_rotation_value(volume->get_instance_rotation()); update_scale_value(volume->get_instance_scaling_factor()); + update_size_value(volume->get_instance_transformation().get_matrix(true, true) * volume->bounding_box.size()); #else update_position_value(volume->get_offset()); update_rotation_value(volume->get_rotation()); @@ -250,6 +248,7 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele update_position_value(volume->get_volume_offset()); update_rotation_value(volume->get_volume_rotation()); update_scale_value(volume->get_volume_scaling_factor()); + update_size_value(volume->bounding_box.size()); #else update_position_value(volume->get_offset()); update_rotation_value(volume->get_rotation()); @@ -261,13 +260,13 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele { reset_settings_value(); move_label = _(L("Displacement")); + update_size_value(selection.get_bounding_box().size()); m_og->enable(); } else reset_settings_value(); m_move_Label->SetLabel(move_label); - m_og->get_field("scale_unit")->disable();// temporary decision } void ObjectManipulation::reset_settings_value() @@ -287,7 +286,7 @@ void ObjectManipulation::reset_position_value() m_og->set_value("position_y", def_0); m_og->set_value("position_z", def_0); - cache_position = { 0., 0., 0. }; + cache_position = Vec3d::Zero(); } void ObjectManipulation::reset_rotation_value() @@ -295,15 +294,27 @@ void ObjectManipulation::reset_rotation_value() m_og->set_value("rotation_x", def_0); m_og->set_value("rotation_y", def_0); m_og->set_value("rotation_z", def_0); + + cache_rotation = Vec3d::Zero(); } void ObjectManipulation::reset_scale_value() { - m_is_percent_scale = true; m_og->set_value("scale_unit", _("%")); m_og->set_value("scale_x", def_100); m_og->set_value("scale_y", def_100); m_og->set_value("scale_z", def_100); + + cache_scale = Vec3d(100.0, 100.0, 100.0); +} + +void ObjectManipulation::reset_size_value() +{ + m_og->set_value("size_x", def_0); + m_og->set_value("size_y", def_0); + m_og->set_value("size_z", def_0); + + cache_size = Vec3d::Zero(); } void ObjectManipulation::update_position_value(const Vec3d& position) @@ -317,19 +328,21 @@ void ObjectManipulation::update_position_value(const Vec3d& position) void ObjectManipulation::update_scale_value(const Vec3d& scaling_factor) { - // this is temporary - // to be able to update the values as size - // we need to store somewhere the original size - // or have it passed as parameter - if (!m_is_percent_scale) { - m_is_percent_scale = true; - m_og->set_value("scale_unit", _("%")); - } - auto scale = scaling_factor * 100.0; m_og->set_value("scale_x", double_to_string(scale(0), 2)); m_og->set_value("scale_y", double_to_string(scale(1), 2)); m_og->set_value("scale_z", double_to_string(scale(2), 2)); + + cache_scale = scale; +} + +void ObjectManipulation::update_size_value(const Vec3d& size) +{ + m_og->set_value("size_x", double_to_string(size(0), 2)); + m_og->set_value("size_y", double_to_string(size(1), 2)); + m_og->set_value("size_z", double_to_string(size(2), 2)); + + cache_size = size; } void ObjectManipulation::update_rotation_value(const Vec3d& rotation) @@ -337,6 +350,8 @@ void ObjectManipulation::update_rotation_value(const Vec3d& rotation) m_og->set_value("rotation_x", double_to_string(round_nearest(Geometry::rad2deg(rotation(0)), 0), 2)); m_og->set_value("rotation_y", double_to_string(round_nearest(Geometry::rad2deg(rotation(1)), 0), 2)); m_og->set_value("rotation_z", double_to_string(round_nearest(Geometry::rad2deg(rotation(2)), 0), 2)); + + cache_rotation = rotation; } void ObjectManipulation::change_position_value(const Vec3d& position) @@ -364,27 +379,40 @@ void ObjectManipulation::change_rotation_value(const Vec3d& rotation) void ObjectManipulation::change_scale_value(const Vec3d& scale) { - Vec3d scaling_factor; - if (m_is_percent_scale) - scaling_factor = scale*0.01; - else { - int selection = ol_selection(); - ModelObjectPtrs& objects = *wxGetApp().model_objects(); + Vec3d scaling_factor = scale; + const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); + bool needs_uniform_scale = selection.is_single_full_object() && !selection.is_single_full_instance(); - auto size = objects[selection]->instance_bounding_box(0).size(); - for (size_t i = 0; i < 3; ++i) - scaling_factor(i) = scale(i) / size(i); + if (needs_uniform_scale) + { + double min = scaling_factor.minCoeff(); + double max = scaling_factor.maxCoeff(); + if (min != 100.0) + scaling_factor = Vec3d(min, min, min); + else if (max != 100.0) + scaling_factor = Vec3d(max, max, max); } + scaling_factor *= 0.01; + auto canvas = wxGetApp().plater()->canvas3D(); canvas->get_selection().start_dragging(); canvas->get_selection().scale(scaling_factor, false); canvas->do_scale(); } -void ObjectManipulation::print_cashe_value(const std::string& label, const Vec3d& v) +void ObjectManipulation::change_size_value(const Vec3d& size) { - std::cout << label << " => " << " X:" << v(0) << " Y:" << v(1) << " Z:" << v(2) << std::endl; + const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); + + Vec3d ref_size = cache_size; + if (selection.is_single_full_instance()) + { + const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + ref_size = volume->bounding_box.size(); + } + + change_scale_value(100.0 * Vec3d(size(0) / ref_size(0), size(1) / ref_size(1), size(2) / ref_size(2))); } } //namespace GUI diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index cbc22a2dd..cacceff9d 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -14,11 +14,11 @@ namespace GUI { class ObjectManipulation : public OG_Settings { - bool m_is_percent_scale = false; // true -> percentage scale unit - // false -> uniform scale unit - bool m_is_uniform_scale = false; // It indicates if scale is uniform - Vec3d cache_position { 0., 0., 0. }; + Vec3d cache_rotation { 0., 0., 0. }; + Vec3d cache_scale { 100., 100., 100. }; + Vec3d cache_size { 0., 0., 0. }; + wxStaticText* m_move_Label = nullptr; public: @@ -36,25 +36,22 @@ public: void reset_position_value(); void reset_rotation_value(); void reset_scale_value(); + void reset_size_value(); // update position values displacements or "gizmos" void update_position_value(const Vec3d& position); // update scale values after scale unit changing or "gizmos" void update_scale_value(const Vec3d& scaling_factor); + // update size values after scale unit changing or "gizmos" + void update_size_value(const Vec3d& size); // update rotation value after "gizmos" void update_rotation_value(const Vec3d& rotation); - void set_uniform_scaling(const bool uniform_scale) { m_is_uniform_scale = uniform_scale; } - - // change values void change_position_value(const Vec3d& position); void change_rotation_value(const Vec3d& rotation); void change_scale_value(const Vec3d& scale); - - -private: - void print_cashe_value(const std::string& label, const Vec3d& value); + void change_size_value(const Vec3d& size); }; }} From 334f747fa99274e835d0d5b509ab0032b5854049 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 18 Dec 2018 10:40:53 +0100 Subject: [PATCH 2/4] Sidebar matrix fields focus handling --- src/slic3r/GUI/GLCanvas3D.cpp | 12 ++++++++++++ src/slic3r/GUI/GLCanvas3D.hpp | 3 ++- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 6 ++++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index eecefd381..22c399223 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3581,6 +3581,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) , m_view_toolbar(nullptr) #endif // ENABLE_REMOVE_TABS_FROM_PLATER , m_use_clipping_planes(false) + , m_sidebar_field("") , m_config(nullptr) , m_process(nullptr) , m_model(nullptr) @@ -5566,6 +5567,17 @@ void GLCanvas3D::update_gizmos_on_off_state() m_gizmos.update_on_off_state(get_selection()); } +void GLCanvas3D::handle_sidebar_focus_event(const std::string& opt_key, bool focus_on) +{ + m_sidebar_field = focus_on ? opt_key : ""; + + if (!m_sidebar_field.empty()) + { + m_gizmos.reset_all_states(); + m_dirty = true; + } +} + bool GLCanvas3D::_is_shown_on_screen() const { return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false; diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index e07c60ed2..906412e6a 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -794,6 +794,7 @@ private: ClippingPlane m_clipping_planes[2]; bool m_use_clipping_planes; mutable SlaCap m_sla_caps[2]; + std::string m_sidebar_field; mutable GLVolumeCollection m_volumes; Selection m_selection; @@ -995,7 +996,7 @@ public: void viewport_changed(); #endif // ENABLE_CONSTRAINED_CAMERA_TARGET - void handle_sidebar_focus_event(const std::string& opt_key) {} + void handle_sidebar_focus_event(const std::string& opt_key, bool focus_on); private: bool _is_shown_on_screen() const; diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 9bc316deb..0c07c1fe5 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -41,6 +41,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : change_scale_value(new_value); else if (param == "size") change_size_value(new_value); + + wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, false); }; m_og->m_fill_empty_value = [this](const std::string& opt_key) @@ -76,11 +78,12 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : } m_og->set_value(opt_key, double_to_string(value)); + wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, false); }; m_og->m_set_focus = [this](const std::string& opt_key) { - wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key); + wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, true); }; ConfigOptionDef def; @@ -300,7 +303,6 @@ void ObjectManipulation::reset_rotation_value() void ObjectManipulation::reset_scale_value() { - m_og->set_value("scale_unit", _("%")); m_og->set_value("scale_x", def_100); m_og->set_value("scale_y", def_100); m_og->set_value("scale_z", def_100); From a394e55e0781986b22c09fafae50dd1f8ed1dcc1 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 18 Dec 2018 10:49:22 +0100 Subject: [PATCH 3/4] Added method ModelObject::full_raw_mesh() --- src/libslic3r/Model.cpp | 19 +++++++++++++++++++ src/libslic3r/Model.hpp | 2 ++ 2 files changed, 21 insertions(+) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 07f1b98c1..7ebcbd815 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -809,6 +809,25 @@ TriangleMesh ModelObject::raw_mesh() const return mesh; } +// Non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes. +TriangleMesh ModelObject::full_raw_mesh() const +{ + TriangleMesh mesh; + for (const ModelVolume *v : this->volumes) +#if ENABLE_MODELVOLUME_TRANSFORM + { + TriangleMesh vol_mesh(v->mesh); + vol_mesh.transform(v->get_matrix()); + mesh.merge(vol_mesh); + } +#else + { + mesh.merge(v->mesh); + } +#endif // ENABLE_MODELVOLUME_TRANSFORM + return mesh; +} + // A transformed snug bounding box around the non-modifier object volumes, without the translation applied. // This bounding box is only used for the actual slicing. BoundingBoxf3 ModelObject::raw_bounding_box() const diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index b02862203..b396bd1db 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -218,6 +218,8 @@ public: // Non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes. // Currently used by ModelObject::mesh() and to calculate the 2D envelope for 2D platter. TriangleMesh raw_mesh() const; + // Non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes. + TriangleMesh full_raw_mesh() const; // A transformed snug bounding box around the non-modifier object volumes, without the translation applied. // This bounding box is only used for the actual slicing. BoundingBoxf3 raw_bounding_box() const; From d453b6fb3f777320bab3fb949a3499cccd12a9dc Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 18 Dec 2018 11:11:06 +0100 Subject: [PATCH 4/4] Sidebar matrix field behavior for single full instance selection --- src/slic3r/GUI/GLCanvas3D.cpp | 11 ++++-- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 47 ++++++++++++----------- src/slic3r/GUI/GUI_ObjectManipulation.hpp | 2 + 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 22c399223..f34341a0e 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1549,9 +1549,14 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) if (is_single_full_instance()) #if ENABLE_WORLD_ROTATIONS { - Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); - Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_instance_rotation_matrix()); - (*m_volumes)[i]->set_instance_rotation(new_rotation); + if (local) + (*m_volumes)[i]->set_instance_rotation(rotation); + else + { + Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); + Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_instance_rotation_matrix()); + (*m_volumes)[i]->set_instance_rotation(new_rotation); + } } #else #if ENABLE_MODELVOLUME_TRANSFORM diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 0c07c1fe5..5c049144e 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -144,8 +144,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : // Settings table m_og->append_line(add_og_to_object_settings(L("Position"), L("mm")), &m_move_Label); - m_og->append_line(add_og_to_object_settings(L("Rotation"), "°")); - m_og->append_line(add_og_to_object_settings(L("Scale"), "%")); + m_og->append_line(add_og_to_object_settings(L("Rotation"), "°"), &m_rotate_Label); + m_og->append_line(add_og_to_object_settings(L("Scale"), "%"), &m_scale_Label); m_og->append_line(add_og_to_object_settings(L("Size"), "mm")); /* Unused parameter at this time @@ -192,9 +192,11 @@ int ObjectManipulation::ol_selection() void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& selection) { - wxString move_label = _(L("Position")); + wxString move_label = _(L("Position:")); + wxString rotate_label = _(L("Rotation:")); + wxString scale_label = _(L("Scale factors:")); #if ENABLE_MODELVOLUME_TRANSFORM - if (selection.is_single_full_instance() || selection.is_single_full_object()) + if (selection.is_single_full_instance()) #else if (selection.is_single_full_object()) { @@ -228,19 +230,15 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele #endif // ENABLE_MODELVOLUME_TRANSFORM m_og->enable(); } - else if (selection.is_wipe_tower()) + else if (selection.is_single_full_object()) { - // the selection contains a single volume - const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); -#if ENABLE_MODELVOLUME_TRANSFORM - update_position_value(volume->get_volume_offset()); - update_rotation_value(volume->get_volume_rotation()); - update_scale_value(volume->get_volume_scaling_factor()); -#else - update_position_value(volume->get_offset()); - update_rotation_value(volume->get_rotation()); - update_scale_value(volume->get_scaling_factor()); -#endif // ENABLE_MODELVOLUME_TRANSFORM + const BoundingBoxf3& box = selection.get_bounding_box(); + update_position_value(box.center()); + reset_rotation_value(); + reset_scale_value(); + update_size_value(box.size()); + rotate_label = _(L("Rotate:")); + scale_label = _(L("Scale:")); m_og->enable(); } else if (selection.is_single_modifier() || selection.is_single_volume()) @@ -262,7 +260,7 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele else if (wxGetApp().obj_list()->multiple_selection()) { reset_settings_value(); - move_label = _(L("Displacement")); + move_label = _(L("Translate:")); update_size_value(selection.get_bounding_box().size()); m_og->enable(); } @@ -270,6 +268,8 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele reset_settings_value(); m_move_Label->SetLabel(move_label); + m_rotate_Label->SetLabel(rotate_label); + m_scale_Label->SetLabel(scale_label); } void ObjectManipulation::reset_settings_value() @@ -358,11 +358,9 @@ void ObjectManipulation::update_rotation_value(const Vec3d& rotation) void ObjectManipulation::change_position_value(const Vec3d& position) { - Vec3d displacement(position - cache_position); - auto canvas = wxGetApp().plater()->canvas3D(); canvas->get_selection().start_dragging(); - canvas->get_selection().translate(displacement); + canvas->get_selection().translate(position - cache_position); canvas->do_move(); cache_position = position; @@ -370,12 +368,17 @@ void ObjectManipulation::change_position_value(const Vec3d& position) void ObjectManipulation::change_rotation_value(const Vec3d& rotation) { + GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); + const GLCanvas3D::Selection& selection = canvas->get_selection(); + Vec3d rad_rotation; for (size_t i = 0; i < 3; ++i) + { rad_rotation(i) = Geometry::deg2rad(rotation(i)); - auto canvas = wxGetApp().plater()->canvas3D(); + } + canvas->get_selection().start_dragging(); - canvas->get_selection().rotate(rad_rotation, false); + canvas->get_selection().rotate(rad_rotation, selection.is_single_full_instance()); canvas->do_rotate(); } diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index cacceff9d..0ada37b96 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -20,6 +20,8 @@ class ObjectManipulation : public OG_Settings Vec3d cache_size { 0., 0., 0. }; wxStaticText* m_move_Label = nullptr; + wxStaticText* m_scale_Label = nullptr; + wxStaticText* m_rotate_Label = nullptr; public: ObjectManipulation(wxWindow* parent);