From 19712749c3eedaed1fc25d10e1ec6f66571c3607 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 12 May 2022 09:41:01 +0200 Subject: [PATCH] Tech ENABLE_TRANSFORMATIONS_BY_MATRICES - Added reset button to remove skew, when detected, in object manipulator panel Fixed conflicts during rebase with master --- src/libslic3r/Geometry.cpp | 24 +++++++ src/libslic3r/Geometry.hpp | 1 + src/slic3r/GUI/GLCanvas3D.cpp | 50 ++++++++++++++ src/slic3r/GUI/GLCanvas3D.hpp | 6 ++ src/slic3r/GUI/GUI_ObjectManipulation.cpp | 83 +++++++++++++++++++++++ src/slic3r/GUI/GUI_ObjectManipulation.hpp | 13 +++- src/slic3r/GUI/Plater.cpp | 3 + src/slic3r/GUI/Selection.cpp | 42 +++++++++++- src/slic3r/GUI/Selection.hpp | 1 + 9 files changed, 218 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 61217f4a1..a611e10c0 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -702,6 +702,30 @@ void Transformation::reset() } #if ENABLE_TRANSFORMATIONS_BY_MATRICES +void Transformation::reset_skew() +{ + Matrix3d rotation; + Matrix3d scale; + m_matrix.computeRotationScaling(&rotation, &scale); + + const double average_scale = std::cbrt(scale(0, 0) * scale(1, 1) * scale(2, 2)); + + scale(0, 0) = average_scale; + scale(1, 1) = average_scale; + scale(2, 2) = average_scale; + + scale(0, 1) = 0.0; + scale(0, 2) = 0.0; + scale(1, 0) = 0.0; + scale(1, 2) = 0.0; + scale(2, 0) = 0.0; + scale(2, 1) = 0.0; + + const Vec3d offset = get_offset(); + m_matrix = rotation * scale; + m_matrix.translation() = offset; +} + Transform3d Transformation::get_matrix_no_offset() const { Transformation copy(*this); diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index bbca3a5e3..0d804c52c 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -496,6 +496,7 @@ public: void reset_rotation() { set_rotation(Vec3d::Zero()); } void reset_scaling_factor() { set_scaling_factor(Vec3d::Ones()); } void reset_mirror() { set_mirror(Vec3d::Ones()); } + void reset_skew(); const Transform3d& get_matrix() const { return m_matrix; } Transform3d get_matrix_no_offset() const; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 8a2599866..45ef3c002 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1101,6 +1101,9 @@ wxDEFINE_EVENT(EVT_GLCANVAS_QUESTION_MARK, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_INCREASE_INSTANCES, Event); wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent); +#if ENABLE_TRANSFORMATIONS_BY_MATRICES +wxDEFINE_EVENT(EVT_GLCANVAS_RESET_SKEW, SimpleEvent); +#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_FORCE_UPDATE, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); @@ -4098,9 +4101,17 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type) ModelObject* model_object = m_model->objects[object_idx]; if (model_object != nullptr) { if (selection_mode == Selection::Instance) +#if ENABLE_TRANSFORMATIONS_BY_MATRICES + model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation()); +#else model_object->instances[instance_idx]->set_mirror(v->get_instance_mirror()); +#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES else if (selection_mode == Selection::Volume) +#if ENABLE_TRANSFORMATIONS_BY_MATRICES + model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation()); +#else model_object->volumes[volume_idx]->set_mirror(v->get_volume_mirror()); +#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES model_object->invalidate_bounding_box(); } @@ -4124,6 +4135,45 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type) m_dirty = true; } +#if ENABLE_TRANSFORMATIONS_BY_MATRICES +void GLCanvas3D::do_reset_skew(const std::string& snapshot_type) +{ + if (m_model == nullptr) + return; + + if (!snapshot_type.empty()) + wxGetApp().plater()->take_snapshot(_(snapshot_type)); + + std::set> done; // keeps track of modified instances + + Selection::EMode selection_mode = m_selection.get_mode(); + const Selection::IndicesList& idxs = m_selection.get_volume_idxs(); + + for (unsigned int id : idxs) { + const GLVolume* v = m_volumes.volumes[id]; + int object_idx = v->object_idx(); + if (object_idx < 0 || (int)m_model->objects.size() <= object_idx) + continue; + + int instance_idx = v->instance_idx(); + int volume_idx = v->volume_idx(); + + done.insert(std::pair(object_idx, instance_idx)); + + ModelObject* model_object = m_model->objects[object_idx]; + if (model_object != nullptr) { + model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation()); + model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation()); + model_object->invalidate_bounding_box(); + } + } + + post_event(SimpleEvent(EVT_GLCANVAS_RESET_SKEW)); + + m_dirty = true; +} +#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES + void GLCanvas3D::update_gizmos_on_off_state() { set_as_dirty(); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 1876500e2..2daa10321 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -156,6 +156,9 @@ wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_FORCE_UPDATE, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent); +#if ENABLE_TRANSFORMATIONS_BY_MATRICES +wxDECLARE_EVENT(EVT_GLCANVAS_RESET_SKEW, SimpleEvent); +#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3dEvent); wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event); @@ -807,6 +810,9 @@ public: void do_rotate(const std::string& snapshot_type); void do_scale(const std::string& snapshot_type); void do_mirror(const std::string& snapshot_type); +#if ENABLE_TRANSFORMATIONS_BY_MATRICES + void do_reset_skew(const std::string& snapshot_type); +#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES void update_gizmos_on_off_state(); void reset_all_gizmos() { m_gizmos.reset_all_states(); } diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 141c34c9b..c82e06d7d 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -481,6 +481,25 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : m_main_grid_sizer->Add(editors_grid_sizer, 1, wxEXPAND); +#if ENABLE_TRANSFORMATIONS_BY_MATRICES + m_skew_label = new wxStaticText(parent, wxID_ANY, _L("Skew")); + m_main_grid_sizer->Add(m_skew_label, 1, wxEXPAND); + + m_reset_skew_button = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo")); + m_reset_skew_button->SetToolTip(_L("Reset skew")); + m_reset_skew_button->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) { + GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); + Selection& selection = canvas->get_selection(); + if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) { + selection.setup_cache(); + selection.reset_skew(); + canvas->do_reset_skew(L("Reset skew")); + UpdateAndShow(true); + } + }); + m_main_grid_sizer->Add(m_reset_skew_button); +#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES + m_check_inch = new wxCheckBox(parent, wxID_ANY, _L("Inches")); m_check_inch->SetFont(wxGetApp().normal_font()); @@ -880,6 +899,9 @@ void ObjectManipulation::update_reset_buttons_visibility() bool show_rotation = false; bool show_scale = false; bool show_drop_to_bed = false; +#if ENABLE_TRANSFORMATIONS_BY_MATRICES + bool show_skew = false; +#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES #if ENABLE_WORLD_COORDINATE #if ENABLE_TRANSFORMATIONS_BY_MATRICES @@ -898,8 +920,14 @@ void ObjectManipulation::update_reset_buttons_visibility() if (m_coordinates_type == ECoordinatesType::Local && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier())) { #endif // !ENABLE_TRANSFORMATIONS_BY_MATRICES const GLVolume* volume = selection.get_first_volume(); +#if ENABLE_TRANSFORMATIONS_BY_MATRICES + Transform3d rotation = Transform3d::Identity(); + Transform3d scale = Transform3d::Identity(); + Geometry::Transformation skew; +#else Vec3d rotation = Vec3d::Zero(); Vec3d scale = Vec3d::Ones(); +#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES #else if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) { const GLVolume* volume = selection.get_first_volume(); @@ -909,27 +937,72 @@ void ObjectManipulation::update_reset_buttons_visibility() #endif // ENABLE_WORLD_COORDINATE if (selection.is_single_full_instance()) { +#if ENABLE_TRANSFORMATIONS_BY_MATRICES + const Geometry::Transformation& trafo = volume->get_instance_transformation(); + rotation = trafo.get_rotation_matrix(); + scale = trafo.get_scaling_factor_matrix(); + if (trafo.has_skew()) + // the instance transform contains skew + skew = trafo; + else { + // the world transform contains skew + const Selection::IndicesList& idxs = selection.get_volume_idxs(); + for (unsigned int id : idxs) { + const Geometry::Transformation world_trafo(selection.get_volume(id)->world_matrix()); + if (world_trafo.has_skew()) { + skew = world_trafo; + break; + } + } + } +#else rotation = volume->get_instance_rotation(); scale = volume->get_instance_scaling_factor(); +#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES #if !ENABLE_WORLD_COORDINATE min_z = selection.get_scaled_instance_bounding_box().min.z(); #endif // !ENABLE_WORLD_COORDINATE } else { +#if ENABLE_TRANSFORMATIONS_BY_MATRICES + const Geometry::Transformation& trafo = volume->get_volume_transformation(); + rotation = trafo.get_rotation_matrix(); + scale = trafo.get_scaling_factor_matrix(); + if (trafo.has_skew()) + // the volume transform contains skew + skew = trafo; + else { + // the world transform contains skew + const Geometry::Transformation world_trafo(volume->world_matrix()); + if (world_trafo.has_skew()) + skew = world_trafo; + } +#else rotation = volume->get_volume_rotation(); scale = volume->get_volume_scaling_factor(); +#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES #if !ENABLE_WORLD_COORDINATE min_z = get_volume_min_z(*volume); #endif // !ENABLE_WORLD_COORDINATE } +#if ENABLE_TRANSFORMATIONS_BY_MATRICES + show_rotation = !rotation.isApprox(Transform3d::Identity()); + show_scale = !scale.isApprox(Transform3d::Identity()); + show_skew = skew.has_skew(); +#else show_rotation = !rotation.isApprox(Vec3d::Zero()); show_scale = !scale.isApprox(Vec3d::Ones()); +#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES #if !ENABLE_WORLD_COORDINATE show_drop_to_bed = std::abs(min_z) > SINKING_Z_THRESHOLD; #endif // !ENABLE_WORLD_COORDINATE } +#if ENABLE_TRANSFORMATIONS_BY_MATRICES + wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed, show_skew] { +#else wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed] { +#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES // There is a case (under OSX), when this function is called after the Manipulation panel is hidden // So, let check if Manipulation panel is still shown for this moment if (!this->IsShown()) @@ -937,6 +1010,10 @@ void ObjectManipulation::update_reset_buttons_visibility() m_reset_rotation_button->Show(show_rotation); m_reset_scale_button->Show(show_scale); m_drop_to_bed_button->Show(show_drop_to_bed); +#if ENABLE_TRANSFORMATIONS_BY_MATRICES + m_reset_skew_button->Show(show_skew); + m_skew_label->Show(show_skew); +#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES // Because of CallAfter we need to layout sidebar after Show/hide of reset buttons one more time Sidebar& panel = wxGetApp().sidebar(); @@ -1423,6 +1500,9 @@ void ObjectManipulation::msw_rescale() m_mirror_bitmap_hidden.msw_rescale(); m_reset_scale_button->msw_rescale(); m_reset_rotation_button->msw_rescale(); +#if ENABLE_TRANSFORMATIONS_BY_MATRICES + m_reset_skew_button->msw_rescale(); +#endif /// ENABLE_TRANSFORMATIONS_BY_MATRICES m_drop_to_bed_button->msw_rescale(); m_lock_bnt->msw_rescale(); @@ -1462,6 +1542,9 @@ void ObjectManipulation::sys_color_changed() m_mirror_bitmap_hidden.msw_rescale(); m_reset_scale_button->msw_rescale(); m_reset_rotation_button->msw_rescale(); +#if ENABLE_TRANSFORMATIONS_BY_MATRICES + m_reset_skew_button->msw_rescale(); +#endif /// ENABLE_TRANSFORMATIONS_BY_MATRICES m_drop_to_bed_button->msw_rescale(); m_lock_bnt->msw_rescale(); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index 289485dad..696f75128 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -120,9 +120,12 @@ private: wxStaticText* m_empty_str = nullptr; // Non-owning pointers to the reset buttons, so we can hide and show them. - ScalableButton* m_reset_scale_button = nullptr; - ScalableButton* m_reset_rotation_button = nullptr; - ScalableButton* m_drop_to_bed_button = nullptr; + ScalableButton* m_reset_scale_button{ nullptr }; + ScalableButton* m_reset_rotation_button{ nullptr }; +#if ENABLE_TRANSFORMATIONS_BY_MATRICES + ScalableButton* m_reset_skew_button{ nullptr }; +#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES + ScalableButton* m_drop_to_bed_button{ nullptr }; wxCheckBox* m_check_inch {nullptr}; @@ -176,6 +179,10 @@ private: wxFlexGridSizer* m_main_grid_sizer; wxFlexGridSizer* m_labels_grid_sizer; +#if ENABLE_TRANSFORMATIONS_BY_MATRICES + wxStaticText* m_skew_label{ nullptr }; +#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES + // sizers, used for msw_rescale wxBoxSizer* m_word_local_combo_sizer; std::vector m_rescalable_sizers; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index c7ddf8f78..c9cc7fc22 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2085,6 +2085,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) view3D_canvas->Bind(EVT_GLCANVAS_WIPETOWER_MOVED, &priv::on_wipetower_moved, this); view3D_canvas->Bind(EVT_GLCANVAS_WIPETOWER_ROTATED, &priv::on_wipetower_rotated, this); view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_ROTATED, [this](SimpleEvent&) { update(); }); +#if ENABLE_TRANSFORMATIONS_BY_MATRICES + view3D_canvas->Bind(EVT_GLCANVAS_RESET_SKEW, [this](SimpleEvent&) { update(); }); +#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_SCALED, [this](SimpleEvent&) { update(); }); view3D_canvas->Bind(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, [this](Event& evt) { this->sidebar->enable_buttons(evt.data); }); view3D_canvas->Bind(EVT_GLCANVAS_UPDATE_GEOMETRY, &priv::on_update_geometry, this); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 33ecd2412..346d0fe9b 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1347,8 +1347,6 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation if (!m_valid) return; - std::cout << "Selection::scale_and_translate: " << to_string(scale) << " - " << to_string(translation) << "\n"; - for (unsigned int i : m_list) { GLVolume& v = *(*m_volumes)[i]; const VolumeCache& volume_data = m_cache.volumes_data[i]; @@ -1412,6 +1410,46 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation set_bounding_boxes_dirty(); wxGetApp().plater()->canvas3D()->requires_check_outside_state(); } + +void Selection::reset_skew() +{ + if (!m_valid) + return; + + for (unsigned int i : m_list) { + GLVolume& v = *(*m_volumes)[i]; + const VolumeCache& volume_data = m_cache.volumes_data[i]; + const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform(); + const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform(); + if (m_mode == Instance && inst_trafo.has_skew()) { + Geometry::Transformation trafo = inst_trafo; + trafo.reset_skew(); + v.set_instance_transformation(trafo); + } + else if (m_mode == Volume && vol_trafo.has_skew()) { + Geometry::Transformation trafo = vol_trafo; + trafo.reset_skew(); + v.set_volume_transformation(trafo); + } + else { + const Geometry::Transformation world_trafo = inst_trafo * vol_trafo; + if (world_trafo.has_skew()) { + if (m_mode == Instance) { + // TODO + int a = 0; + } + else { + // TODO + int a = 0; + } + } + } + } + + ensure_on_bed(); + set_bounding_boxes_dirty(); + wxGetApp().plater()->canvas3D()->requires_check_outside_state(); +} #else void Selection::translate(unsigned int object_idx, const Vec3d& displacement) { diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index bd9c9216c..0be33b1e8 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -382,6 +382,7 @@ public: void mirror(Axis axis); #if ENABLE_TRANSFORMATIONS_BY_MATRICES void scale_and_translate(const Vec3d& scale, const Vec3d& translation, TransformationType transformation_type); + void reset_skew(); #endif // ENABLE_TRANSFORMATIONS_BY_MATRICES #if !ENABLE_TRANSFORMATIONS_BY_MATRICES