From db852fe74f74f76180065f5695c7f4ad5247aeb6 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 18 Feb 2022 08:57:26 +0100 Subject: [PATCH] Tech ENABLE_WORLD_COORDINATE_SCALE_REVISITED - Alternate implementation of manipulating scale for instances and volumes using gizmo scale and sidebar object manipulator fields - 1st installment --- src/libslic3r/Model.cpp | 2 + src/libslic3r/Technologies.hpp | 2 + src/slic3r/GUI/GUI_ObjectManipulation.cpp | 112 ++++++++++++++++++++-- src/slic3r/GUI/GUI_ObjectManipulation.hpp | 5 +- src/slic3r/GUI/Gizmos/GLGizmoScale.hpp | 4 + src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 40 +++++++- src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 4 +- src/slic3r/GUI/Selection.cpp | 72 +++++++++++++- src/slic3r/GUI/Selection.hpp | 9 ++ src/slic3r/GUI/wxExtensions.cpp | 4 + 10 files changed, 238 insertions(+), 16 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 67450fb11..9b9300c8b 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1412,9 +1412,11 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx) assert(instance_idx < this->instances.size()); const Geometry::Transformation reference_trafo = this->instances[instance_idx]->get_transformation(); +#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED if (Geometry::is_rotation_ninety_degrees(reference_trafo.get_rotation())) // nothing to do, scaling in the world coordinate space is possible in the representation of Geometry::Transformation. return; +#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED bool left_handed = reference_trafo.is_left_handed(); bool has_mirrorring = ! reference_trafo.get_mirror().isApprox(Vec3d(1., 1., 1.)); diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index bb55befab..fda5e6c67 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -86,6 +86,8 @@ #define ENABLE_COORDINATE_DEPENDENT_SELECTION_BOX (1 && ENABLE_WORLD_COORDINATE) // Enable showing the axes of the current reference system when sidebar hints are active #define ENABLE_WORLD_COORDINATE_SHOW_AXES (1 && ENABLE_WORLD_COORDINATE) +// Enable alternate implementation of manipulating scale for instances and volumes +#define ENABLE_WORLD_COORDINATE_SCALE_REVISITED (1 && ENABLE_WORLD_COORDINATE) #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index a4ba9a361..80c274093 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -627,10 +627,17 @@ void ObjectManipulation::update_settings_value(const Selection& selection) if (m_world_coordinates) { #endif // ENABLE_WORLD_COORDINATE m_new_rotate_label_string = L("Rotate"); +#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED + m_new_scale_label_string = L("Scale"); +#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED m_new_rotation = Vec3d::Zero(); m_new_size = selection.get_scaled_instance_bounding_box().size(); - m_new_scale = m_new_size.cwiseProduct(selection.get_unscaled_instance_bounding_box().size().cwiseInverse()) * 100.0; - } +#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED + m_new_scale = Vec3d(100.0, 100.0, 100.0); +#else + m_new_scale = m_new_size.cwiseProduct(selection.get_unscaled_instance_bounding_box().size().cwiseInverse()) * 100.0; +#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED + } else { #if ENABLE_WORLD_COORDINATE m_new_move_label_string = L("Translate"); @@ -672,9 +679,16 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_new_position = offset; m_new_rotate_label_string = L("Rotate"); +#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED + m_new_scale_label_string = L("Scale"); +#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED m_new_rotation = Vec3d::Zero(); m_new_size = volume->transformed_convex_hull_bounding_box(trafo.get_matrix()).size(); +#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED + m_new_scale = Vec3d(100.0, 100.0, 100.0); +#else m_new_scale = m_new_size.cwiseProduct(volume->transformed_convex_hull_bounding_box(volume->get_instance_transformation().get_matrix() * volume->get_volume_transformation().get_matrix(false, false, true, false)).size().cwiseInverse()) * 100.0; +#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED } else if (is_local_coordinates()) { m_new_move_label_string = L("Translate"); @@ -687,10 +701,17 @@ void ObjectManipulation::update_settings_value(const Selection& selection) #endif // ENABLE_WORLD_COORDINATE m_new_position = volume->get_volume_offset(); m_new_rotate_label_string = L("Rotate"); +#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED + m_new_scale_label_string = L("Scale"); +#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED m_new_rotation = Vec3d::Zero(); #if ENABLE_WORLD_COORDINATE m_new_size = volume->transformed_convex_hull_bounding_box(volume->get_volume_transformation().get_matrix()).size(); +#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED + m_new_scale = Vec3d(100.0, 100.0, 100.0); +#else m_new_scale = m_new_size.cwiseProduct(volume->transformed_convex_hull_bounding_box(volume->get_volume_transformation().get_matrix(false, false, true, false)).size().cwiseInverse()) * 100.0; +#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED } #else m_new_scale = volume->get_volume_scaling_factor() * 100.0; @@ -767,20 +788,26 @@ void ObjectManipulation::update_if_dirty() #else if (selection.requires_uniform_scale()) { #endif // ENABLE_WORLD_COORDINATE +#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED m_lock_bnt->SetLock(true); +#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED #if ENABLE_WORLD_COORDINATE wxString tooltip; if (selection.is_single_volume_or_modifier()) { +#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED if (reason == Selection::EUniformScaleRequiredReason::VolumeNotAxisAligned_Instance) tooltip = _L("You cannot use non-uniform scaling mode for parts non aligned with the instance local axes"); else if (reason == Selection::EUniformScaleRequiredReason::VolumeNotAxisAligned_World) tooltip = _L("You cannot use non-uniform scaling mode for parts non aligned with the printer axes"); +#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED } else if (selection.is_single_full_instance()) { +#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED if (reason == Selection::EUniformScaleRequiredReason::InstanceNotAxisAligned_World) tooltip = _L("You cannot use non-uniform scaling mode for instances non aligned with the printer axes"); else if (reason == Selection::EUniformScaleRequiredReason::VolumeNotAxisAligned_Instance) tooltip = _L("You cannot use non-uniform scaling mode for instances containing non locally axis-aligned parts"); +#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED } else tooltip = _L("You cannot use non-uniform scaling mode for multiple objects/parts selection"); @@ -789,7 +816,9 @@ void ObjectManipulation::update_if_dirty() #else m_lock_bnt->SetToolTip(_L("You cannot use non-uniform scaling mode for multiple objects/parts selection")); #endif // ENABLE_WORLD_COORDINATE +#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED m_lock_bnt->disable(); +#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED } else { m_lock_bnt->SetLock(m_uniform_scale); @@ -1110,7 +1139,11 @@ void ObjectManipulation::change_size_value(int axis, double value) selection.get_unscaled_instance_bounding_box().size() : wxGetApp().model().objects[selection.get_volume(*selection.get_volume_idxs().begin())->object_idx()]->raw_mesh_bounding_box().size(); +#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED + this->do_size(axis, size.cwiseQuotient(ref_size)); +#else this->do_scale(axis, size.cwiseQuotient(ref_size)); +#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED m_cache.size = size; m_cache.size_rounded(axis) = DBL_MAX; @@ -1126,8 +1159,18 @@ void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const #if ENABLE_WORLD_COORDINATE TransformationType transformation_type; +#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED + if (is_local_coordinates()) + transformation_type.set_local(); + else if (is_instance_coordinates()) + transformation_type.set_instance(); + + if (!is_local_coordinates()) + transformation_type.set_relative(); +#else if (!is_world_coordinates()) transformation_type.set_local(); +#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED bool uniform_scale = m_uniform_scale || selection.requires_uniform_scale(); Vec3d scaling_factor = uniform_scale ? scale(axis) * Vec3d::Ones() : scale; @@ -1159,6 +1202,37 @@ void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const wxGetApp().plater()->canvas3D()->do_scale(L("Set Scale")); } +#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED +void ObjectManipulation::do_size(int axis, const Vec3d& scale) const +{ + Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); + + TransformationType transformation_type; + if (is_local_coordinates()) + transformation_type.set_local(); + else if (is_instance_coordinates()) + transformation_type.set_instance(); + + bool uniform_scale = m_uniform_scale || selection.requires_uniform_scale(); + Vec3d scaling_factor = uniform_scale ? scale(axis) * Vec3d::Ones() : scale; + + if (!uniform_scale && is_world_coordinates()) { + if (selection.is_single_full_instance()) + scaling_factor = (Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation()).inverse() * scaling_factor).cwiseAbs(); + else if (selection.is_single_volume_or_modifier()) { + const Transform3d mi = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation()).inverse(); + const Transform3d mv = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_rotation()).inverse(); + scaling_factor = (mv * mi * scaling_factor).cwiseAbs(); + } + } + + selection.start_dragging(); + selection.scale(scaling_factor, transformation_type); + selection.stop_dragging(); + wxGetApp().plater()->canvas3D()->do_scale(L("Set Size")); +} +#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED + void ObjectManipulation::on_change(const std::string& opt_key, int axis, double new_value) { if (!m_cache.is_valid()) @@ -1193,21 +1267,37 @@ void ObjectManipulation::on_change(const std::string& opt_key, int axis, double } } -void ObjectManipulation::set_uniform_scaling(const bool new_value) +void ObjectManipulation::set_uniform_scaling(const bool use_uniform_scale) { const Selection &selection = wxGetApp().plater()->canvas3D()->get_selection(); -#if ENABLE_WORLD_COORDINATE - if (selection.is_single_full_instance() && is_world_coordinates() && !new_value) { +#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED + if (!use_uniform_scale) { + int res = selection.bake_transform_if_needed(false); + if (res == -1) { + // Enforce uniform scaling. + m_lock_bnt->SetLock(true); + return; + } + else if (res == 0) { + // Recalculate cached values at this panel, refresh the screen. + this->UpdateAndShow(true); + } + } + + m_uniform_scale = use_uniform_scale; #else - if (selection.is_single_full_instance() && m_world_coordinates && !new_value) { +#if ENABLE_WORLD_COORDINATE + if (selection.is_single_full_instance() && is_world_coordinates() && !use_uniform_scale) { +#else + if (selection.is_single_full_instance() && m_world_coordinates && !use_uniform_scale) { #endif // ENABLE_WORLD_COORDINATE // Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible. // all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); // Is the angle close to a multiple of 90 degrees? - if (! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) { + if (!Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) { // Cannot apply scaling in the world coordinate system. - //wxMessageDialog dlg(GUI::wxGetApp().mainframe, + //wxMessageDialog dlg(GUI::wxGetApp().mainframe, MessageDialog dlg(GUI::wxGetApp().mainframe, _L("The currently manipulated object is tilted (rotation angles are not multiples of 90°).\n" "Non-uniform scaling of tilted objects is only possible in the World coordinate system,\n" @@ -1215,7 +1305,7 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value) _L("This operation is irreversible.\n" "Do you want to proceed?"), SLIC3R_APP_NAME, - wxYES_NO | wxCANCEL | wxCANCEL_DEFAULT | wxICON_QUESTION); + wxYES_NO | wxCANCEL | wxCANCEL_DEFAULT | wxICON_QUESTION); if (dlg.ShowModal() != wxID_YES) { // Enforce uniform scaling. m_lock_bnt->SetLock(true); @@ -1229,7 +1319,9 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value) this->UpdateAndShow(true); } } - m_uniform_scale = new_value; + + m_uniform_scale = use_uniform_scale; +#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED } #if ENABLE_WORLD_COORDINATE diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index 19d2c1808..289485dad 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -196,7 +196,7 @@ public: // Called from the App to update the UI if dirty. void update_if_dirty(); - void set_uniform_scaling(const bool uniform_scale); + void set_uniform_scaling(const bool use_uniform_scale); bool get_uniform_scaling() const { return m_uniform_scale; } #if ENABLE_WORLD_COORDINATE void set_coordinates_type(ECoordinatesType type); @@ -256,6 +256,9 @@ private: void change_scale_value(int axis, double value); void change_size_value(int axis, double value); void do_scale(int axis, const Vec3d &scale) const; +#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED + void do_size(int axis, const Vec3d& scale) const; +#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED #if ENABLE_WORLD_COORDINATE void set_coordinates_type(const wxString& type_string); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp index 60e5444b5..41efbe575 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp @@ -62,6 +62,10 @@ public: const Vec3d& get_scale() const { return m_scale; } void set_scale(const Vec3d& scale) { m_starting.scale = scale; m_scale = scale; } +#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED + const Vec3d& get_starting_scale() const { return m_starting.scale; } +#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED + const Vec3d& get_offset() const { return m_offset; } std::string get_tooltip() const override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index e11b38c59..e5cf18338 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -242,13 +242,17 @@ void GLGizmosManager::update_data() enable_grabber(Rotate, 1, !is_wipe_tower); #if ENABLE_WORLD_COORDINATE +#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED bool enable_scale_xyz = !selection.requires_uniform_scale(); +#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED #else bool enable_scale_xyz = selection.is_single_full_instance() || selection.is_single_volume() || selection.is_single_modifier(); #endif // ENABLE_WORLD_COORDINATE +#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED for (unsigned int i = 0; i < 6; ++i) { enable_grabber(Scale, i, enable_scale_xyz); } +#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED if (m_common_gizmos_data) m_common_gizmos_data->update(get_current() @@ -370,6 +374,16 @@ void GLGizmosManager::set_scale(const Vec3d& scale) dynamic_cast(m_gizmos[Scale].get())->set_scale(scale); } +#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED +Vec3d GLGizmosManager::get_starting_scale() const +{ + if (!m_enabled) + return Vec3d::Ones(); + + return dynamic_cast(m_gizmos[Scale].get())->get_starting_scale(); +} +#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED + Vec3d GLGizmosManager::get_scale_offset() const { if (!m_enabled || m_gizmos.empty()) @@ -553,7 +567,8 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt) m_tooltip = update_hover_state(mouse_pos); if (m_current == MmuSegmentation || m_current == FdmSupports) gizmo_event(SLAGizmoEventType::Moving, mouse_pos, evt.ShiftDown(), evt.AltDown()); - } else if (evt.LeftUp()) { + } + else if (evt.LeftUp()) { if (m_mouse_capture.left) { processed = true; m_mouse_capture.left = false; @@ -561,7 +576,30 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt) else if (is_dragging()) { switch (m_current) { case Move: { m_parent.do_move(L("Gizmo-Move")); break; } +#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED + case Scale: { + const Vec3d scale = get_scale(); + const Vec3d starting_scale = get_starting_scale(); + wxGetApp().CallAfter([this, &selection, scale, starting_scale]() { + int res = 1; + if (scale.x() != scale.y() || scale.x() != scale.z()) + res = selection.bake_transform_if_needed(L("Gizmo-Scale")); + + if (res == 1) + m_parent.do_scale(L("Gizmo-Scale")); + else if (res == -1) { + TransformationType transformation_type; + if (!wxGetApp().obj_manipul()->is_world_coordinates()) + transformation_type.set_local(); + selection.scale(starting_scale, transformation_type); + } + } + ); + break; + } +#else case Scale: { m_parent.do_scale(L("Gizmo-Scale")); break; } +#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED case Rotate: { m_parent.do_rotate(L("Gizmo-Rotate")); break; } default: break; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 8d268723b..336c2b1bb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -209,7 +209,9 @@ public: Vec3d get_scale() const; void set_scale(const Vec3d& scale); - +#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED + Vec3d get_starting_scale() const; +#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED Vec3d get_scale_offset() const; Vec3d get_rotation() const; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 0ba20a38b..0d7aa2d67 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -7,9 +7,14 @@ #include "GUI.hpp" #include "GUI_ObjectManipulation.hpp" #include "GUI_ObjectList.hpp" -#include "Gizmos/GLGizmoBase.hpp" #include "Camera.hpp" #include "Plater.hpp" +#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED +#include "MsgDialog.hpp" +#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED + +#include "Gizmos/GLGizmoBase.hpp" + #include "slic3r/Utils/UndoRedo.hpp" #include "libslic3r/LocalesUtils.hpp" @@ -605,6 +610,9 @@ bool Selection::requires_uniform_scale() const #endif // ENABLE_WORLD_COORDINATE { #if ENABLE_WORLD_COORDINATE + if (is_empty()) + return false; + ECoordinatesType coord_type = wxGetApp().obj_manipul()->get_coordinates_type(); if (is_single_volume_or_modifier()) { if (coord_type == ECoordinatesType::World) { @@ -639,7 +647,6 @@ bool Selection::requires_uniform_scale() const } } } - return false; } else { for (unsigned int i : m_list) { @@ -649,8 +656,8 @@ bool Selection::requires_uniform_scale() const return true; } } - return false; } + return false; } if (reason != nullptr) @@ -1301,6 +1308,65 @@ void Selection::translate(unsigned int object_idx, unsigned int instance_idx, co this->set_bounding_boxes_dirty(); } +#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED +int Selection::bake_transform_if_needed(bool apply_scale) const +{ + if ((is_single_full_instance() && wxGetApp().obj_manipul()->is_world_coordinates()) || + (is_single_volume_or_modifier() && !wxGetApp().obj_manipul()->is_local_coordinates())) { + // Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible. + // all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one + const GLVolume& volume = *get_volume(*get_volume_idxs().begin()); + bool needs_baking = false; + if (is_single_full_instance()) { + // Is the instance angle close to a multiple of 90 degrees? + needs_baking |= !Geometry::is_rotation_ninety_degrees(volume.get_instance_rotation()); + // Are all volumes angles close to a multiple of 90 degrees? + for (unsigned int id : get_volume_idxs()) { + if (needs_baking) + break; + needs_baking |= !Geometry::is_rotation_ninety_degrees(get_volume(id)->get_volume_rotation()); + } + } + else if (is_single_volume_or_modifier()) { + // is the volume angle close to a multiple of 90 degrees? + needs_baking |= !Geometry::is_rotation_ninety_degrees(volume.get_volume_rotation()); + if (wxGetApp().obj_manipul()->is_world_coordinates()) + // Is the instance angle close to a multiple of 90 degrees? + needs_baking |= !Geometry::is_rotation_ninety_degrees(volume.get_instance_rotation()); + } + + if (needs_baking) { + MessageDialog dlg((wxWindow*)wxGetApp().mainframe, + _L("The currently manipulated object is tilted or contains tilted parts (rotation angles are not multiples of 90°). " + "Non-uniform scaling of tilted objects is only possible in non-local coordinate systems, " + "once the rotation is embedded into the object coordinates.") + "\n" + + _L("This operation is irreversible.") + "\n" + + _L("Do you want to proceed?"), + SLIC3R_APP_NAME, + wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION); + if (dlg.ShowModal() != wxID_YES) + return -1; + + if (apply_scale) { + wxGetApp().plater()->get_current_canvas3D()->do_scale(L("Scale + Bake transform")); + Plater::SuppressSnapshots suppress(wxGetApp().plater()); + wxGetApp().plater()->take_snapshot(_("Bake transform")); + } + else + wxGetApp().plater()->take_snapshot(_("Bake transform")); + + // Bake the rotation into the meshes of the object. + wxGetApp().model().objects[volume.composite_id.object_id]->bake_xy_rotation_into_meshes(volume.composite_id.instance_id); + // Update the 3D scene, selections etc. + wxGetApp().plater()->update(); + return 0; + } + } + + return 1; +} +#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED + void Selection::erase() { if (!m_valid) diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index a967225fe..55bad60ee 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -369,6 +369,15 @@ public: void translate(unsigned int object_idx, const Vec3d& displacement); void translate(unsigned int object_idx, unsigned int instance_idx, const Vec3d& displacement); +#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED + // returns: + // -1 if the user refused to proceed with baking when asked + // 0 if the baking was performed + // 1 if no baking was needed + // if apply_scale == true the scaling of the current selection is applied + int bake_transform_if_needed(bool apply_scale) const; +#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED + void erase(); void render(float scale_factor = 1.0); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index dc177ade3..bacdb1f9c 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -581,8 +581,12 @@ void LockButton::OnButton(wxCommandEvent& event) if (m_disabled) return; +#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED + SetLock(!m_is_pushed); +#else m_is_pushed = !m_is_pushed; update_button_bitmaps(); +#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED event.Skip(); }