From d009be760914b94829c05f48fa6a1e55f31a347e Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 1 Mar 2019 10:20:12 +0100 Subject: [PATCH] Fixed rotation of single instance -> it works now with absolute values. Added Absolute / relative, World / Local, Rigid body / independent modifier parameter to the object / group rotation. --- src/slic3r/GUI/GLCanvas3D.cpp | 28 ++++++++---- src/slic3r/GUI/GLCanvas3D.hpp | 55 ++++++++++++++++++++++- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 14 +++--- 3 files changed, 82 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 4f456c392..6f80b0165 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1261,17 +1261,21 @@ static double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to return (axis.z() < 0) ? -angle : angle; } -void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) +// Rotate an object around one of the axes. Only one rotation component is expected to be changing. +void GLCanvas3D::Selection::rotate(const Vec3d& rotation, GLCanvas3D::TransformationType transformation_type) { if (!m_valid) return; + // Only relative rotation values are allowed in the world coordinate system. + assert(! transformation_type.world() || transformation_type.relative()); + int rot_axis_max; rotation.cwiseAbs().maxCoeff(&rot_axis_max); // For generic rotation, we want to rotate the first volume in selection, and then to synchronize the other volumes with it. std::vector object_instance_first(m_model->objects.size(), -1); - auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, local](GLVolume &volume, int i) { + auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, transformation_type](GLVolume &volume, int i) { int first_volume_idx = object_instance_first[volume.object_idx()]; if (rot_axis_max != 2 && first_volume_idx != -1) { // Generic rotation, but no rotation around the Z axis. @@ -1283,11 +1287,14 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) volume.set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff)); } else { // extracts rotations from the composed transformation - 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()); - if (rot_axis_max == 2 && !local) + Vec3d new_rotation = transformation_type.world() ? + Geometry::extract_euler_angles(Geometry::assemble_transform(Vec3d::Zero(), rotation) * m_cache.volumes_data[i].get_instance_rotation_matrix()) : + transformation_type.absolute() ? rotation : rotation + m_cache.volumes_data[i].get_instance_rotation(); + if (rot_axis_max == 2 && transformation_type.joint()) { // Only allow rotation of multiple instances as a single rigid body when rotating around the Z axis. - volume.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); + double z_diff = rotation_diff_z(new_rotation, m_cache.volumes_data[i].get_instance_rotation()); + volume.set_instance_offset(m_cache.dragging_center + Eigen::AngleAxisd(z_diff, Vec3d::UnitZ()) * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); + } volume.set_instance_rotation(new_rotation); object_instance_first[volume.object_idx()] = i; } @@ -1300,7 +1307,7 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) rotate_instance(volume, i); else if (is_single_volume() || is_single_modifier()) { - if (local) + if (transformation_type.independent()) volume.set_volume_rotation(volume.get_volume_rotation() + rotation); else { @@ -1318,7 +1325,7 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) // extracts rotations from the composed transformation Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix()); - if (!local) + if (transformation_type.joint()) { Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() + m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center); volume.set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset); @@ -5162,7 +5169,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) case Gizmos::Rotate: { // Apply new temporary rotations - m_selection.rotate(m_gizmos.get_rotation(), evt.AltDown()); + TransformationType transformation_type(TransformationType::World_Relative_Joint); + if (evt.AltDown()) + transformation_type.set_independent(); + m_selection.rotate(m_gizmos.get_rotation(), transformation_type); wxGetApp().obj_manipul()->update_settings_value(m_selection); break; } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 008e77056..06fda3e5c 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -375,6 +375,59 @@ class GLCanvas3D }; public: + class TransformationType + { + public: + enum Enum { + // Transforming in a world coordinate system + World = 0, + // Transforming in a local coordinate system + Local = 1, + // Absolute transformations, allowed in local coordinate system only. + Absolute = 0, + // Relative transformations, allowed in both local and world coordinate system. + Relative = 2, + // For group selection, the transformation is performed as if the group made a single solid body. + Joint = 0, + // For group selection, the transformation is performed on each object independently. + Independent = 4, + + World_Relative_Joint = World | Relative | Joint, + World_Relative_Independent = World | Relative | Independent, + Local_Absolute_Joint = Local | Absolute | Joint, + Local_Absolute_Independent = Local | Absolute | Independent, + Local_Relative_Joint = Local | Relative | Joint, + Local_Relative_Independent = Local | Relative | Independent, + }; + + TransformationType() : m_value(World) {} + TransformationType(Enum value) : m_value(value) {} + TransformationType& operator=(Enum value) { m_value = value; return *this; } + + Enum operator()() const { return m_value; } + bool has(Enum v) const { return ((unsigned int)m_value & (unsigned int)v) != 0; } + + void set_world() { this->remove(Local); } + void set_local() { this->add(Local); } + void set_absolute() { this->remove(Relative); } + void set_relative() { this->add(Relative); } + void set_joint() { this->remove(Independent); } + void set_independent() { this->add(Independent); } + + bool world() const { return ! this->has(Local); } + bool local() const { return this->has(Local); } + bool absolute() const { return ! this->has(Relative); } + bool relative() const { return this->has(Relative); } + bool joint() const { return ! this->has(Independent); } + bool independent() const { return this->has(Independent); } + + private: + void add(Enum v) { m_value = Enum((unsigned int)m_value | (unsigned int)v); } + void remove(Enum v) { m_value = Enum((unsigned int)m_value & (~(unsigned int)v)); } + + Enum m_value; + }; + class Selection { public: @@ -553,7 +606,7 @@ public: void start_dragging(); void translate(const Vec3d& displacement, bool local = false); - void rotate(const Vec3d& rotation, bool local); + void rotate(const Vec3d& rotation, TransformationType transformation_type); void flattening_rotate(const Vec3d& normal); void scale(const Vec3d& scale, bool local); void mirror(Axis axis); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 5afd7ae59..1fa28d65a 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -361,16 +361,20 @@ void ObjectManipulation::change_rotation_value(const Vec3d& rotation) GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); const GLCanvas3D::Selection& selection = canvas->get_selection(); - Vec3d delta_rotation = rotation - m_cache.rotation; + GLCanvas3D::TransformationType transformation_type(GLCanvas3D::TransformationType::World_Relative_Joint); + if (selection.is_single_full_instance() || selection.requires_local_axes()) + transformation_type.set_independent(); + if (selection.is_single_full_instance()) { + transformation_type.set_absolute(); + transformation_type.set_local(); + } Vec3d rad_rotation; for (size_t i = 0; i < 3; ++i) - { - rad_rotation(i) = Geometry::deg2rad(delta_rotation(i)); - } + rad_rotation(i) = Geometry::deg2rad((transformation_type.absolute()) ? rotation(i) : rotation(i) - m_cache.rotation(i)); canvas->get_selection().start_dragging(); - canvas->get_selection().rotate(rad_rotation, selection.is_single_full_instance() || selection.requires_local_axes()); + canvas->get_selection().rotate(rad_rotation, transformation_type); canvas->do_rotate(); m_cache.rotation = rotation;