From 0b46b9848b96b8219dbabceb3ae12b5649190128 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 4 Mar 2024 11:11:29 +0800 Subject: [PATCH] FIX:world cs is displayed incorrectly The value of world coordinate system for model_volume is displayed incorrectly Jira: STUDIO-6399 code is from PrusaSlicer thanks for PrusaSlicer and enricoturri1966 commit 325709c5ae9b937867b36103a41d12a102c99292 Author: enricoturri1966 Date: Thu Jan 26 15:49:00 2023 +0100 SPE-1419 - Fixed reset skew resetting mirror, reset scale resetting mirror, changed labels in Object Manipulator panel, scale of instances using the Object Manipulator panel always made as absolute Change-Id: I30fdd39effd73b8dc027e4263fa7e64937b84326 --- .../GUI/Gizmos/GizmoObjectManipulation.cpp | 56 +++++++++-- .../GUI/Gizmos/GizmoObjectManipulation.hpp | 11 ++- src/slic3r/GUI/Selection.cpp | 95 +++++++++++++++++++ src/slic3r/GUI/Selection.hpp | 22 ++++- 4 files changed, 170 insertions(+), 14 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp index d7e1b8a34..929a65778 100644 --- a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp +++ b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp @@ -12,7 +12,7 @@ #include "libslic3r/Model.hpp" #include "libslic3r/Geometry.hpp" -#include "slic3r/GUI/Selection.hpp" + #include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/MainFrame.hpp" @@ -117,14 +117,34 @@ void GizmoObjectManipulation::update_settings_value(const Selection& selection) m_new_title_string = L("Object Operations"); } else if (selection.is_single_modifier() || selection.is_single_volume()) { - // the selection contains a single volume - const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); - m_new_position = volume->get_volume_offset(); - m_new_rotation = volume->get_volume_rotation() * (180. / M_PI); - m_new_scale = volume->get_volume_scaling_factor() * 100.; - m_new_size = volume->get_instance_transformation().get_scaling_factor().cwiseProduct(volume->get_volume_transformation().get_scaling_factor().cwiseProduct(volume->bounding_box().size())); + const GLVolume *volume = selection.get_first_volume(); + if (is_world_coordinates()) { + const Geometry::Transformation trafo(volume->world_matrix()); + + const Vec3d &offset = trafo.get_offset(); + + m_new_position = offset; + m_new_rotate_label_string = L("Rotate (relative)"); + m_new_scale_label_string = L("Scale"); + m_new_scale = Vec3d(100.0, 100.0, 100.0); + m_new_rotation = Vec3d::Zero(); + m_new_size = selection.get_bounding_box_in_current_reference_system().first.size(); + } else if (is_local_coordinates()) { + m_new_move_label_string = L("Translate (relative) [World]"); + m_new_rotate_label_string = L("Rotate (relative)"); + m_new_position = Vec3d::Zero(); + m_new_rotation = Vec3d::Zero(); + m_new_scale = volume->get_volume_scaling_factor() * 100.0; + m_new_size = selection.get_bounding_box_in_current_reference_system().first.size(); + } else { + m_new_position = volume->get_volume_offset(); + m_new_rotate_label_string = L("Rotate (relative)"); + m_new_rotation = Vec3d::Zero(); + m_new_scale_label_string = L("Scale"); + m_new_scale = Vec3d(100.0, 100.0, 100.0); + m_new_size = selection.get_bounding_box_in_current_reference_system().first.size(); + } m_new_enabled = true; - m_new_title_string = L("Volume Operations"); } else if (obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) { reset_settings_value(); @@ -445,7 +465,7 @@ void GizmoObjectManipulation::reset_scale_value() } void GizmoObjectManipulation::set_uniform_scaling(const bool use_uniform_scale) -{ +{ if (!use_uniform_scale) // Recalculate cached values at this panel, refresh the screen. this->UpdateAndShow(true); @@ -454,6 +474,24 @@ void GizmoObjectManipulation::set_uniform_scaling(const bool use_uniform_scale) set_dirty(); } +void GizmoObjectManipulation::set_coordinates_type(ECoordinatesType type) +{ + if (wxGetApp().get_mode() == comSimple) + type = ECoordinatesType::World; + + if (m_coordinates_type == type) return; + + m_coordinates_type = type; + m_world_coordinates = type == ECoordinatesType::World ? true : false; + //m_word_local_combo->SetSelection((int) m_coordinates_type); + this->UpdateAndShow(true); + GLCanvas3D *canvas = wxGetApp().plater()->canvas3D(); + canvas->get_gizmos_manager().update_data(); + canvas->set_as_dirty(); + canvas->request_extra_frame(); + +} + static const char* label_values[2][3] = { { "##position_x", "##position_y", "##position_z"}, { "##rotation_x", "##rotation_y", "##rotation_z"} diff --git a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp index 39ceee5db..c5e7eb2b5 100644 --- a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp +++ b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp @@ -5,13 +5,12 @@ #include "libslic3r/Point.hpp" #include - +#include "slic3r/GUI/Selection.hpp" //#include "slic3r/GUI/GLCanvas3D.hpp" namespace Slic3r { namespace GUI { -class Selection; class GLCanvas3D; class GizmoObjectManipulation @@ -83,6 +82,7 @@ public: bool m_uniform_scale {true}; // Does the object manipulation panel work in World or Local coordinates? bool m_world_coordinates = true; + ECoordinatesType m_coordinates_type{ECoordinatesType::World}; bool m_show_clear_rotation { false }; bool m_show_clear_scale { false }; @@ -108,8 +108,11 @@ public: void set_uniform_scaling(const bool uniform_scale); bool get_uniform_scaling() const { return m_uniform_scale; } // Does the object manipulation panel work in World or Local coordinates? - void set_world_coordinates(const bool world_coordinates) { m_world_coordinates = world_coordinates; this->UpdateAndShow(true); } - bool get_world_coordinates() const { return m_world_coordinates; } + void set_coordinates_type(ECoordinatesType type); + ECoordinatesType get_coordinates_type() const { return m_coordinates_type; } + bool is_world_coordinates() const { return m_coordinates_type == ECoordinatesType::World; } + bool is_instance_coordinates() const { return m_coordinates_type == ECoordinatesType::Instance; } + bool is_local_coordinates() const { return m_coordinates_type == ECoordinatesType::Local; } void reset_cache() { m_cache.reset(); } diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index c86238e21..f66affeff 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -865,6 +865,101 @@ const BoundingBoxf3& Selection::get_scaled_instance_bounding_box() const return *m_scaled_instance_bounding_box; } +const std::pair &Selection::get_bounding_box_in_current_reference_system() const +{ + static int last_coordinates_type = -1; + + assert(!is_empty()); + + ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type(); + if (m_mode == Instance && coordinates_type == ECoordinatesType::Local) coordinates_type = ECoordinatesType::World; + + if (last_coordinates_type != int(coordinates_type)) const_cast> *>(&m_bounding_box_in_current_reference_system)->reset(); + + if (!m_bounding_box_in_current_reference_system.has_value()) { + last_coordinates_type = int(coordinates_type); + *const_cast> *>(&m_bounding_box_in_current_reference_system) = get_bounding_box_in_reference_system(coordinates_type); + } + + return *m_bounding_box_in_current_reference_system; +} + +std::pair Selection::get_bounding_box_in_reference_system(ECoordinatesType type) const +{ + // + // trafo to current reference system + // + Transform3d trafo; + switch (type) { + case ECoordinatesType::World: { + trafo = Transform3d::Identity(); + break; + } + case ECoordinatesType::Instance: { + trafo = get_first_volume()->get_instance_transformation().get_matrix(); + break; + } + case ECoordinatesType::Local: { + trafo = get_first_volume()->world_matrix(); + break; + } + } + + // + // trafo basis in world coordinates + // + Geometry::Transformation t(trafo); + t.reset_scaling_factor(); + const Transform3d basis_trafo = t.get_matrix_no_offset(); + std::vector axes = {Vec3d::UnitX(), Vec3d::UnitY(), Vec3d::UnitZ()}; + for (size_t i = 0; i < axes.size(); ++i) { axes[i] = basis_trafo * axes[i]; } + + // + // calculate bounding box aligned to trafo basis + // + Vec3d min = {DBL_MAX, DBL_MAX, DBL_MAX}; + Vec3d max = {-DBL_MAX, -DBL_MAX, -DBL_MAX}; + for (unsigned int id : m_list) { + const GLVolume & vol = *get_volume(id); + const Transform3d vol_world_rafo = vol.world_matrix(); + const TriangleMesh *mesh = vol.convex_hull(); + if (mesh == nullptr) mesh = &m_model->objects[vol.object_idx()]->volumes[vol.volume_idx()]->mesh(); + assert(mesh != nullptr); + for (const stl_vertex &v : mesh->its.vertices) { + const Vec3d world_v = vol_world_rafo * v.cast(); + for (int i = 0; i < 3; ++i) { + const double i_comp = world_v.dot(axes[i]); + min(i) = std::min(min(i), i_comp); + max(i) = std::max(max(i), i_comp); + } + } + } + + const Vec3d box_size = max - min; + Vec3d half_box_size = 0.5 * box_size; + Geometry::Transformation out_trafo(trafo); + Vec3d center = 0.5 * (min + max); + + // Fix for non centered volume + // by move with calculated center(to volume center) and extend half box size + // e.g. for right aligned embossed text + if (m_list.size() == 1 && type == ECoordinatesType::Local) { + const GLVolume & vol = *get_volume(*m_list.begin()); + const Transform3d vol_world_trafo = vol.world_matrix(); + Vec3d world_zero = vol_world_trafo * Vec3d::Zero(); + for (size_t i = 0; i < 3; i++) { + // move center to local volume zero + center[i] = world_zero.dot(axes[i]); + // extend half size to bigger distance from center + half_box_size[i] = std::max(abs(center[i] - min[i]), abs(center[i] - max[i])); + } + } + + const BoundingBoxf3 out_box(-half_box_size, half_box_size); + out_trafo.set_offset(basis_trafo * center); + return {out_box, out_trafo.get_matrix_no_scaling_factor()}; +} + void Selection::start_dragging() { if (!m_valid) diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 874e5b5eb..1e3c273b8 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -26,6 +26,12 @@ using ModelObjectPtrs = std::vector; namespace GUI { +enum ECoordinatesType : unsigned char { + World, + Instance, + Local +}; + class TransformationType { public: @@ -214,6 +220,9 @@ private: std::optional m_unscaled_instance_bounding_box; std::optional m_scaled_instance_bounding_box; + // Bounding box aligned to the axis of the currently selected reference system (World/Object/Part) + // and transform to place and orient it in world coordinates + std::optional> m_bounding_box_in_current_reference_system; #if ENABLE_RENDER_SELECTION_CENTER GLModel m_vbo_sphere; #endif // ENABLE_RENDER_SELECTION_CENTER @@ -330,6 +339,13 @@ public: const BoundingBoxf3& get_unscaled_instance_bounding_box() const; const BoundingBoxf3& get_scaled_instance_bounding_box() const; + // Returns the bounding box aligned to the axes of the currently selected reference system (World/Object/Part) + // and the transform to place and orient it in world coordinates + const std::pair &get_bounding_box_in_current_reference_system() const; + // Returns the bounding box aligned to the axes of the given reference system + // and the transform to place and orient it in world coordinates + std::pair get_bounding_box_in_reference_system(ECoordinatesType type) const; + void start_dragging(); void stop_dragging() { m_dragging = false; } bool is_dragging() const { return m_dragging; } @@ -403,7 +419,11 @@ private: void do_remove_volume(unsigned int volume_idx); void do_remove_instance(unsigned int object_idx, unsigned int instance_idx); void do_remove_object(unsigned int object_idx); - void set_bounding_boxes_dirty() { m_bounding_box.reset(); m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset(); } + void set_bounding_boxes_dirty() { + m_bounding_box.reset(); + m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset(); + m_bounding_box_in_current_reference_system.reset(); + } void render_selected_volumes() const; void render_synchronized_volumes() const; void render_bounding_box(const BoundingBoxf3& box, float* color) const;