From ca5742c40140ab3b02bcad1ed1be66841ece2e7f Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 12 Oct 2021 11:07:31 +0200 Subject: [PATCH] Tech ENABLE_WORLD_COORDINATE - Gizmo rotate oriented in dependence of the selected coordinate system Fixed conflicts during rebase with master --- src/libslic3r/Geometry.cpp | 2 +- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 48 +++++++++++++----- src/slic3r/GUI/GUI_ObjectManipulation.hpp | 3 +- src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 19 ++------ src/slic3r/GUI/Gizmos/GLGizmoMove.hpp | 3 -- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 59 ++++++++++++++++++----- src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp | 7 +++ src/slic3r/GUI/Selection.cpp | 58 ++++++++++++++++++---- src/slic3r/GUI/Selection.hpp | 10 ++-- 9 files changed, 155 insertions(+), 54 deletions(-) diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 6eae832778..3c35f6bbd9 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -619,7 +619,7 @@ Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) { const Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to)); - const Vec3d axis = angle_axis.axis(); + const Vec3d& axis = angle_axis.axis(); const double angle = angle_axis.angle(); #ifndef NDEBUG if (std::abs(angle) > 1e-8) { diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 1cc35be7f5..3ed3d4bb78 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -278,7 +278,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : return; // Update mirroring at the GLVolumes. - selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL); + selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL); selection.synchronize_unselected_volumes(); // Copy mirroring values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing. canvas->do_mirror(L("Set Mirror")); @@ -379,7 +379,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : return; // Update rotation at the GLVolumes. - selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL); + selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL); selection.synchronize_unselected_volumes(); // Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing. canvas->do_rotate(L("Reset Rotation")); @@ -551,17 +551,23 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_new_position = volume->get_instance_offset(); #endif // ENABLE_WORLD_COORDINATE m_new_rotate_label_string = L("Rotate"); - m_new_rotation = Vec3d::Zero(); - m_new_size = selection.get_scaled_instance_bounding_box().size(); +#if ENABLE_WORLD_COORDINATE + m_new_rotation = volume->get_instance_rotation() * (180.0 / M_PI); +#else + m_new_rotation = Vec3d::Zero(); +#endif // ENABLE_WORLD_COORDINATE + 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; } else { #if ENABLE_WORLD_COORDINATE m_new_position = Vec3d::Zero(); -#endif // ENABLE_WORLD_COORDINATE + m_new_rotation = Vec3d::Zero(); +#else m_new_rotation = volume->get_instance_rotation() * (180.0 / M_PI); +#endif // ENABLE_WORLD_COORDINATE m_new_size = volume->get_instance_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size()); - m_new_scale = volume->get_instance_scaling_factor() * 100.; + m_new_scale = volume->get_instance_scaling_factor() * 100.0; } m_new_enabled = true; @@ -570,7 +576,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) const BoundingBoxf3& box = selection.get_bounding_box(); m_new_position = box.center(); m_new_rotation = Vec3d::Zero(); - m_new_scale = Vec3d(100., 100., 100.); + m_new_scale = Vec3d(100.0, 100.0, 100.0); m_new_size = box.size(); m_new_rotate_label_string = L("Rotate"); m_new_scale_label_string = L("Scale"); @@ -586,7 +592,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) const Vec3d& offset = trafo.get_offset(); const Vec3d& rotation = trafo.get_rotation(); const Vec3d& scaling_factor = trafo.get_scaling_factor(); - const Vec3d& m = trafo.get_mirror(); +// const Vec3d& mirror = trafo.get_mirror(); m_new_position = offset; m_new_rotation = rotation * (180.0 / M_PI); @@ -596,8 +602,8 @@ void ObjectManipulation::update_settings_value(const Selection& selection) else { #endif // ENABLE_WORLD_COORDINATE 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_rotation = volume->get_volume_rotation() * (180.0 / M_PI); + m_new_scale = volume->get_volume_scaling_factor() * 100.0; m_new_size = volume->get_instance_scaling_factor().cwiseProduct(volume->get_volume_scaling_factor().cwiseProduct(volume->bounding_box().size())); #if ENABLE_WORLD_COORDINATE } @@ -712,11 +718,20 @@ void ObjectManipulation::update_reset_buttons_visibility() if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) { const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); +#if ENABLE_WORLD_COORDINATE + Vec3d rotation = Vec3d::Zero(); + Vec3d scale = Vec3d::Ones(); +#else Vec3d rotation; Vec3d scale; - double min_z = 0.; +#endif // ENABLE_WORLD_COORDINATE + double min_z = 0.0; +#if ENABLE_WORLD_COORDINATE + if (selection.is_single_full_instance() && m_world_coordinates) { +#else if (selection.is_single_full_instance()) { +#endif // ENABLE_WORLD_COORDINATE rotation = volume->get_instance_rotation(); scale = volume->get_instance_scaling_factor(); min_z = wxGetApp().model().objects[volume->composite_id.object_id]->bounding_box().min.z(); @@ -728,7 +743,11 @@ void ObjectManipulation::update_reset_buttons_visibility() } show_rotation = !rotation.isApprox(Vec3d::Zero()); show_scale = !scale.isApprox(Vec3d::Ones()); +#if ENABLE_WORLD_COORDINATE + show_drop_to_bed = min_z > EPSILON; +#else show_drop_to_bed = std::abs(min_z) > SINKING_Z_THRESHOLD; +#endif // ENABLE_WORLD_COORDINATE } wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed] { @@ -1042,6 +1061,13 @@ void ObjectManipulation::set_world_coordinates(const bool world_coordinates) canvas->set_as_dirty(); canvas->request_extra_frame(); } + +bool ObjectManipulation::get_world_coordinates() const +{ + const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); + return wxGetApp().get_mode() != comSimple && (selection.is_single_full_instance() || selection.is_single_volume() || selection.is_single_modifier()) ? + m_world_coordinates : true; +} #endif // ENABLE_WORLD_COORDINATE void ObjectManipulation::msw_rescale() diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index 6d0383038e..a4f826feac 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -185,10 +185,11 @@ public: // Does the object manipulation panel work in World or Local coordinates? #if ENABLE_WORLD_COORDINATE void set_world_coordinates(const bool world_coordinates); + bool get_world_coordinates() const; #else void set_world_coordinates(const bool world_coordinates) { m_world_coordinates = world_coordinates; this->UpdateAndShow(true); } -#endif // ENABLE_WORLD_COORDINATE bool get_world_coordinates() const { return m_world_coordinates; } +#endif // ENABLE_WORLD_COORDINATE void reset_cache() { m_cache.reset(); } #ifndef __APPLE__ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index 2e943bbd81..8d44e87d57 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -24,27 +24,18 @@ GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filenam std::string GLGizmoMove3D::get_tooltip() const { - const Selection& selection = m_parent.get_selection(); - const bool show_position = selection.is_single_full_instance(); #if ENABLE_WORLD_COORDINATE - const bool world_coordinates = wxGetApp().obj_manipul()->get_world_coordinates(); - Vec3d position = Vec3d::Zero(); - if (!world_coordinates) { - if (selection.is_single_modifier() || selection.is_single_volume() || selection.is_wipe_tower()) - position = selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_offset(); - } - else - position = selection.get_bounding_box().center(); - if (m_hover_id == 0) - return m_grabbers[0].dragging ? "DX: " + format(m_displacement.x(), 2) : "X: " + format(position.x(), 2); + return "X: " + format(m_displacement.x(), 2); else if (m_hover_id == 1) - return m_grabbers[1].dragging ? "DY: " + format(m_displacement.y(), 2) : "Y: " + format(position.y(), 2); + return "Y: " + format(m_displacement.y(), 2); else if (m_hover_id == 2) - return m_grabbers[2].dragging ? "DZ: " + format(m_displacement.z(), 2) : "Z: " + format(position.z(), 2); + return "Z: " + format(m_displacement.z(), 2); else return ""; #else + const Selection& selection = m_parent.get_selection(); + const bool show_position = selection.is_single_full_instance(); const Vec3d& position = selection.get_bounding_box().center(); if (m_hover_id == 0 || m_grabbers[0].dragging) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp index 2c9e94f07d..fbc9ca0df7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp @@ -60,9 +60,6 @@ protected: virtual bool on_is_activable() const override; virtual void on_start_dragging() override; virtual void on_stop_dragging() override; -#if !ENABLE_WORLD_COORDINATE - virtual void on_start_dragging() override; -#endif // !ENABLE_WORLD_COORDINATE virtual void on_dragging(const UpdateData& data) override; virtual void on_render() override; virtual void on_render_for_picking() override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 6401990192..b6bffac5fe 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -2,15 +2,18 @@ #include "GLGizmoRotate.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/ImGuiWrapper.hpp" - -#include +#if ENABLE_WORLD_COORDINATE +#include "slic3r/GUI/GUI_ObjectManipulation.hpp" +#endif // ENABLE_WORLD_COORDINATE #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/Plater.hpp" +#include "slic3r/GUI/Jobs/RotoptimizeJob.hpp" + #include "libslic3r/PresetBundle.hpp" -#include "slic3r/GUI/Jobs/RotoptimizeJob.hpp" +#include namespace Slic3r { namespace GUI { @@ -99,6 +102,9 @@ bool GLGizmoRotate::on_init() void GLGizmoRotate::on_start_dragging() { +#if ENABLE_WORLD_COORDINATE + init_data_from_selection(m_parent.get_selection()); +#else const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box(); m_center = box.center(); m_radius = Offset + box.radius(); @@ -106,6 +112,7 @@ void GLGizmoRotate::on_start_dragging() m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius; m_snap_fine_in_radius = m_radius; m_snap_fine_out_radius = m_snap_fine_in_radius + m_radius * ScaleLongTooth; +#endif // ENABLE_WORLD_COORDINATE } void GLGizmoRotate::on_dragging(const UpdateData &data) @@ -154,12 +161,16 @@ void GLGizmoRotate::on_render() const BoundingBoxf3& box = selection.get_bounding_box(); if (m_hover_id != 0 && !m_grabbers.front().dragging) { +#if ENABLE_WORLD_COORDINATE + init_data_from_selection(selection); +#else m_center = box.center(); m_radius = Offset + box.radius(); m_snap_coarse_in_radius = m_radius / 3.0f; m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius; m_snap_fine_in_radius = m_radius; m_snap_fine_out_radius = m_radius * (1.0f + ScaleLongTooth); +#endif // ENABLE_WORLD_COORDINATE } const double grabber_radius = (double)m_radius * (1.0 + (double)GrabberOffset); @@ -257,6 +268,24 @@ void GLGizmoRotate::on_render_for_picking() #endif // !ENABLE_GL_SHADERS_ATTRIBUTES } +#if ENABLE_WORLD_COORDINATE +void GLGizmoRotate::init_data_from_selection(const Selection& selection) +{ + const BoundingBoxf3& box = selection.get_bounding_box(); + m_center = box.center(); + m_radius = Offset + box.radius(); + m_snap_coarse_in_radius = m_radius / 3.0f; + m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius; + m_snap_fine_in_radius = m_radius; + m_snap_fine_out_radius = m_snap_fine_in_radius + m_radius * ScaleLongTooth; + + if (wxGetApp().obj_manipul()->get_world_coordinates()) + m_orient_matrix = Transform3d::Identity(); + else + m_orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true); +} +#endif // ENABLE_WORLD_COORDINATE + void GLGizmoRotate3D::on_render_input_window(float x, float y, float bottom_limit) { if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) @@ -317,10 +346,10 @@ void GLGizmoRotate::render_circle() const #else ::glBegin(GL_LINE_LOOP); for (unsigned int i = 0; i < ScaleStepsCount; ++i) { - float angle = (float)i * ScaleStepRad; - float x = ::cos(angle) * m_radius; - float y = ::sin(angle) * m_radius; - float z = 0.0f; + const float angle = (float)i * ScaleStepRad; + const float x = ::cos(angle) * m_radius; + const float y = ::sin(angle) * m_radius; + const float z = 0.0f; ::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z); } glsafe(::glEnd()); @@ -519,10 +548,10 @@ void GLGizmoRotate::render_angle() const #else ::glBegin(GL_LINE_STRIP); for (unsigned int i = 0; i <= AngleResolution; ++i) { - float angle = (float)i * step_angle; - float x = ::cos(angle) * ex_radius; - float y = ::sin(angle) * ex_radius; - float z = 0.0f; + const float angle = (float)i * step_angle; + const float x = ::cos(angle) * ex_radius; + const float y = ::sin(angle) * ex_radius; + const float z = 0.0f; ::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z); } glsafe(::glEnd()); @@ -687,10 +716,14 @@ void GLGizmoRotate::transform_to_local(const Selection& selection) const { glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z())); +#if ENABLE_WORLD_COORDINATE + glsafe(::glMultMatrixd(m_orient_matrix.data())); +#else if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) { const Transform3d orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true); glsafe(::glMultMatrixd(orient_matrix.data())); } +#endif // ENABLE_WORLD_COORDINATE switch (m_axis) { @@ -744,8 +777,12 @@ Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, cons } } +#if ENABLE_WORLD_COORDINATE + m = m * m_orient_matrix.inverse(); +#else if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) m = m * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true).inverse(); +#endif // ENABLE_WORLD_COORDINATE m.translate(-m_center); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index f4594bc334..0e01b4bebc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -34,6 +34,9 @@ private: float m_snap_coarse_out_radius{ 0.0f }; float m_snap_fine_in_radius{ 0.0f }; float m_snap_fine_out_radius{ 0.0f }; +#if ENABLE_WORLD_COORDINATE + Transform3d m_orient_matrix{ Transform3d::Identity() }; +#endif // ENABLE_WORLD_COORDINATE #if !ENABLE_GIZMO_GRABBER_REFACTOR GLModel m_cone; @@ -119,6 +122,10 @@ private: // returns the intersection of the mouse ray with the plane perpendicular to the gizmo axis, in local coordinate Vec3d mouse_position_in_local_plane(const Linef3& mouse_ray, const Selection& selection) const; + +#if ENABLE_WORLD_COORDINATE + void init_data_from_selection(const Selection& selection); +#endif // ENABLE_WORLD_COORDINATE }; class GLGizmoRotate3D : public GLGizmoBase diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index ae261fc7a8..1aacd41bbe 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -734,7 +734,7 @@ void Selection::translate(const Vec3d& displacement, bool local) #if !DISABLE_INSTANCES_SYNCH if (translation_type == Instance) - synchronize_unselected_instances(SYNC_ROTATION_NONE); + synchronize_unselected_instances(SyncRotationType::NONE); else if (translation_type == Volume) synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH @@ -791,7 +791,18 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ } else { // extracts rotations from the composed transformation - Vec3d new_rotation = transformation_type.world() ? +#if ENABLE_WORLD_COORDINATE + const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); + const Vec3d new_rotation = transformation_type.world() ? + Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_instance_rotation_matrix()) : + transformation_type.absolute() ? rotation : Geometry::extract_euler_angles(m_cache.volumes_data[i].get_instance_rotation_matrix() * m); + if (rot_axis_max == 2 && transformation_type.world() && transformation_type.joint()) { + // Only allow rotation of multiple instances as a single rigid body when rotating around the Z axis. + const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), new_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)); + } +#else + const 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()) { @@ -799,6 +810,7 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), new_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)); } +#endif // ENABLE_WORLD_COORDINATE else if (!(m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center).isApprox(Vec3d::Zero())) volume.set_instance_offset(m_cache.dragging_center + Geometry::assemble_transform(Vec3d::Zero(), new_rotation) * m_cache.volumes_data[i].get_instance_rotation_matrix().inverse() * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); @@ -826,8 +838,8 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ rotate_instance(v, i); else if (m_mode == Volume) { // 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()); + const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); + const Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix()); if (transformation_type.joint()) { const Vec3d local_pivot = m_cache.volumes_data[i].get_instance_full_matrix().inverse() * m_cache.dragging_center; const Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() - local_pivot); @@ -840,11 +852,24 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ } #if !DISABLE_INSTANCES_SYNCH +#if ENABLE_WORLD_COORDINATE + if (m_mode == Instance) { + SyncRotationType synch; + if (transformation_type.world() && rot_axis_max == 2) + synch = SyncRotationType::NONE; + else if (transformation_type.local()) + synch = SyncRotationType::FULL; + else + synch = SyncRotationType::GENERAL; + synchronize_unselected_instances(synch); + } +#else if (m_mode == Instance) synchronize_unselected_instances((rot_axis_max == 2) ? SYNC_ROTATION_NONE : SYNC_ROTATION_GENERAL); +#endif // ENABLE_WORLD_COORDINATE else if (m_mode == Volume) synchronize_unselected_volumes(); - #endif // !DISABLE_INSTANCES_SYNCH +#endif // !DISABLE_INSTANCES_SYNCH } else { // it's the wipe tower that's selected and being rotated GLVolume& volume = *((*m_volumes)[*m_list.begin()]); // the wipe tower is always alone in the selection @@ -887,7 +912,7 @@ void Selection::flattening_rotate(const Vec3d& normal) // Apply the same transformation also to other instances, // but respect their possibly diffrent z-rotation. if (m_mode == Instance) - synchronize_unselected_instances(SYNC_ROTATION_GENERAL); + synchronize_unselected_instances(SyncRotationType::GENERAL); #endif // !DISABLE_INSTANCES_SYNCH this->set_bounding_boxes_dirty(); @@ -950,7 +975,7 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type #if !DISABLE_INSTANCES_SYNCH if (m_mode == Instance) - synchronize_unselected_instances(SYNC_ROTATION_NONE); + synchronize_unselected_instances(SyncRotationType::NONE); else if (m_mode == Volume) synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH @@ -1063,7 +1088,7 @@ void Selection::mirror(Axis axis) #if !DISABLE_INSTANCES_SYNCH if (m_mode == Instance) - synchronize_unselected_instances(SYNC_ROTATION_NONE); + synchronize_unselected_instances(SyncRotationType::NONE); else if (m_mode == Volume) synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH @@ -2528,7 +2553,7 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_ assert(is_rotation_xy_synchronized(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation())); switch (sync_rotation_type) { - case SYNC_ROTATION_NONE: { + case SyncRotationType::NONE: { // z only rotation -> synch instance z // The X,Y rotations should be synchronized from start to end of the rotation. assert(is_rotation_xy_synchronized(rotation, v->get_instance_rotation())); @@ -2536,12 +2561,25 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_ v->set_instance_offset(Z, volume->get_instance_offset().z()); break; } - case SYNC_ROTATION_GENERAL: + case SyncRotationType::GENERAL: { // generic rotation -> update instance z with the delta of the rotation. const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation()); v->set_instance_rotation({ rotation.x(), rotation.y(), rotation.z() + z_diff }); break; } +#if ENABLE_WORLD_COORDINATE + case SyncRotationType::FULL: { + // generic rotation -> update instance z with the delta of the rotation. + const Eigen::AngleAxisd angle_axis(Geometry::rotation_xyz_diff(rotation, m_cache.volumes_data[j].get_instance_rotation())); + const Vec3d& axis = angle_axis.axis(); + const double z_diff = (std::abs(axis.x()) > EPSILON || std::abs(axis.y()) > EPSILON) ? + angle_axis.angle() * axis.z() : Geometry::rotation_diff_z(rotation, m_cache.volumes_data[j].get_instance_rotation()); + + v->set_instance_rotation({ rotation.x(), rotation.y(), rotation.z() + z_diff }); + break; + } +#endif // ENABLE_WORLD_COORDINATE + } v->set_instance_scaling_factor(scaling_factor); v->set_instance_mirror(mirror); diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index c9e55cf828..8cd6cdb6f6 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -389,11 +389,15 @@ private: #endif // ENABLE_GL_SHADERS_ATTRIBUTES public: - enum SyncRotationType { + enum class SyncRotationType { // Do not synchronize rotation. Either not rotating at all, or rotating by world Z axis. - SYNC_ROTATION_NONE = 0, + NONE = 0, // Synchronize after rotation by an axis not parallel with Z. - SYNC_ROTATION_GENERAL = 1, + GENERAL = 1, +#if ENABLE_WORLD_COORDINATE + // Fully synchronize rotation. + FULL = 2, +#endif // ENABLE_WORLD_COORDINATE }; void synchronize_unselected_instances(SyncRotationType sync_rotation_type); void synchronize_unselected_volumes();