From 21bbabc1b3a19b70d11362d9dc0335ba5b6eb45a Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 20 Feb 2023 12:42:10 +0100 Subject: [PATCH 01/12] Fixed rotation in Objects Coordinates of parts of mirrored objects --- src/slic3r/GUI/Selection.cpp | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index fd0a5ec59..0f6409cd1 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1024,22 +1024,13 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ } else { if (transformation_type.instance()) { - const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform(); - const Geometry::Transformation world_trafo = inst_trafo * vol_trafo; // ensure proper sign of rotation for mirrored objects - if (world_trafo.is_left_handed() && !rotation.normalized().isApprox(Vec3d::UnitX())) + if (inst_trafo.is_left_handed() && !rotation.normalized().isApprox(Vec3d::UnitX())) rotation_matrix = rotation_matrix.inverse(); // ensure that the volume rotates as a rigid body - const Geometry::TransformationSVD world_svd(world_trafo); - if (world_svd.anisotropic_scale) { - const Transform3d vol_scale_matrix = vol_trafo.get_scaling_factor_matrix(); - rotation_matrix = vol_scale_matrix.inverse() * rotation_matrix * vol_scale_matrix; - } - const Transform3d vol_rotation_matrix = vol_trafo.get_rotation_matrix(); - rotation_matrix = vol_rotation_matrix.inverse() * rotation_matrix * vol_rotation_matrix; - - v.set_volume_transformation(vol_trafo.get_matrix() * rotation_matrix); + const Transform3d inst_scale_matrix = inst_trafo.get_scaling_factor_matrix(); + rotation_matrix = inst_scale_matrix.inverse() * rotation_matrix * inst_scale_matrix; } else { if (transformation_type.local()) { @@ -1056,8 +1047,8 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ rotation_matrix = vol_scale_matrix.inverse() * rotation_matrix * vol_scale_matrix; } } - transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center); } + transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center); } } } From c9f807f4bb94f411ffb15cf44e17be3937ece3bf Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 21 Feb 2023 10:29:02 +0100 Subject: [PATCH 02/12] Fixed rotation of volumes in Part Coordinates when the instance matrix contains anisotropic scale --- src/slic3r/GUI/Selection.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 0f6409cd1..e4f59dcc7 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1041,10 +1041,9 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ rotation_matrix = rotation_matrix.inverse(); // ensure that the volume rotates as a rigid body - const Geometry::TransformationSVD svd(world_trafo); - if (svd.anisotropic_scale) { - const Transform3d vol_scale_matrix = vol_trafo.get_scaling_factor_matrix(); - rotation_matrix = vol_scale_matrix.inverse() * rotation_matrix * vol_scale_matrix; + if (Geometry::TransformationSVD(world_trafo).anisotropic_scale) { + const Transform3d inst_scale_matrix = inst_trafo.get_scaling_factor_matrix(); + rotation_matrix = inst_scale_matrix.inverse() * rotation_matrix * inst_scale_matrix; } } } @@ -2762,6 +2761,7 @@ void Selection::render_debug_window() const return; ImGuiWrapper& imgui = *wxGetApp().imgui(); + ImGui::SetNextWindowCollapsed(true, ImGuiCond_Once); imgui.begin(std::string("Selection matrices"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize); auto volume_name = [this](size_t id) { From 6ca65cf84432487cab84faa8840fa456195115cc Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 22 Feb 2023 14:50:29 +0100 Subject: [PATCH 03/12] Fixed detection of skew in TransformationSVD --- src/libslic3r/Geometry.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index ac4af4828..8065b81da 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -860,14 +860,26 @@ TransformationSVD::TransformationSVD(const Transform3d& trafo) rotation_90_degrees = true; for (int i = 0; i < 3; ++i) { const Vec3d row = v.row(i).cwiseAbs(); - size_t num_zeros = is_approx(row[0], 0.) + is_approx(row[1], 0.) + is_approx(row[2], 0.); - size_t num_ones = is_approx(row[0], 1.) + is_approx(row[1], 1.) + is_approx(row[2], 1.); + const size_t num_zeros = is_approx(row[0], 0.) + is_approx(row[1], 0.) + is_approx(row[2], 0.); + const size_t num_ones = is_approx(row[0], 1.) + is_approx(row[1], 1.) + is_approx(row[2], 1.); if (num_zeros != 2 || num_ones != 1) { rotation_90_degrees = false; break; } } - skew = ! rotation_90_degrees; + // Detect skew by brute force: check if the axes are still orthogonal after transformation + const Matrix3d trafo_linear = trafo.linear(); + const std::array axes = { Vec3d::UnitX(), Vec3d::UnitY(), Vec3d::UnitZ() }; + std::array transformed_axes; + for (int i = 0; i < 3; ++i) { + transformed_axes[i] = trafo_linear * axes[i]; + } + skew = std::abs(transformed_axes[0].dot(transformed_axes[1])) > EPSILON || + std::abs(transformed_axes[1].dot(transformed_axes[2])) > EPSILON || + std::abs(transformed_axes[2].dot(transformed_axes[0])) > EPSILON; + + // This following old code does not work under all conditions. The v matrix can become non diagonal (see SPE-1492) +// skew = ! rotation_90_degrees; } else skew = false; } From 5d38d3363c1b9496fec7f73d25873211357d769f Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 23 Feb 2023 12:55:59 +0100 Subject: [PATCH 04/12] Fixed synchronization of instances/volumes after resetting scale --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 6d4c916f1..531b2a8ce 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -506,6 +506,10 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : else return; + // Synchronize instances/volumes. + selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL); + selection.synchronize_unselected_volumes(); + canvas->do_scale(L("Reset scale")); UpdateAndShow(true); #else From b92735ac3644faf0d86381e2588ee511145ffdcb Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 23 Feb 2023 14:16:55 +0100 Subject: [PATCH 05/12] Fixed synchronization of instances/volumes after resetting skew --- src/slic3r/GUI/GLCanvas3D.cpp | 36 ++++++++++++++++++++++++++++++----- src/slic3r/GUI/Selection.cpp | 9 +++++++++ 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 427c0e99f..677653a7d 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3746,12 +3746,22 @@ void GLCanvas3D::do_reset_skew(const std::string& snapshot_type) if (!snapshot_type.empty()) wxGetApp().plater()->take_snapshot(_(snapshot_type)); + // stores current min_z of instances + std::map, double> min_zs; + if (!snapshot_type.empty()) { + for (int i = 0; i < static_cast(m_model->objects.size()); ++i) { + const ModelObject* obj = m_model->objects[i]; + for (int j = 0; j < static_cast(obj->instances.size()); ++j) { + min_zs[{ i, j }] = obj->instance_bounding_box(j).min.z(); + } + } + } + std::set> done; // keeps track of modified instances - const Selection::IndicesList& idxs = m_selection.get_volume_idxs(); + Selection::EMode selection_mode = m_selection.get_mode(); - for (unsigned int id : idxs) { - const GLVolume* v = m_volumes.volumes[id]; + for (const GLVolume* v : m_volumes.volumes) { int object_idx = v->object_idx(); if (object_idx < 0 || (int)m_model->objects.size() <= object_idx) continue; @@ -3761,14 +3771,30 @@ void GLCanvas3D::do_reset_skew(const std::string& snapshot_type) done.insert(std::pair(object_idx, instance_idx)); + // Mirror instances/volumes 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()); + if (selection_mode == Selection::Instance) + model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation()); + else if (selection_mode == Selection::Volume) + model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation()); model_object->invalidate_bounding_box(); } } + // Fixes sinking/flying instances + for (const std::pair& i : done) { + ModelObject* m = m_model->objects[i.first]; + double shift_z = m->get_instance_min_z(i.second); + // leave sinking instances as sinking + if (min_zs.empty() || min_zs.find({ i.first, i.second })->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD) { + Vec3d shift(0.0, 0.0, -shift_z); + m_selection.translate(i.first, i.second, shift); + m->translate_instance(i.second, shift); + } + wxGetApp().obj_list()->update_info_items(static_cast(i.first)); + } + post_event(SimpleEvent(EVT_GLCANVAS_RESET_SKEW)); m_dirty = true; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index e4f59dcc7..4a5ddb59c 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1543,6 +1543,15 @@ void Selection::reset_skew() } } +#if !DISABLE_INSTANCES_SYNCH + if (m_mode == Instance) + // even if there is no rotation, we pass SyncRotationType::GENERAL to force + // synchronize_unselected_instances() to remove skew from the other instances + synchronize_unselected_instances(SyncRotationType::GENERAL); + else if (m_mode == Volume) + synchronize_unselected_volumes(); +#endif // !DISABLE_INSTANCES_SYNCH + ensure_on_bed(); set_bounding_boxes_dirty(); wxGetApp().plater()->canvas3D()->requires_check_outside_state(); From e5efbbc2c29ac2333590d85d1d15845417b5f8bb Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 24 Feb 2023 09:10:29 +0100 Subject: [PATCH 06/12] Follow-up of 5d38d3363c1b9496fec7f73d25873211357d769f - Completed fix of synchronization of instances/volumes after resetting scale --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 531b2a8ce..69280f7c7 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -490,6 +490,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : #if ENABLE_WORLD_COORDINATE GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); Selection& selection = canvas->get_selection(); + selection.setup_cache(); if (selection.is_single_volume_or_modifier()) { GLVolume* vol = const_cast(selection.get_first_volume()); Geometry::Transformation trafo = vol->get_volume_transformation(); From 2630c62f0414642c0c11c1bf073d71e884353123 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 24 Feb 2023 10:55:36 +0100 Subject: [PATCH 07/12] Fixed synchronization of instances after resetting rotation --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 8 +++++--- src/slic3r/GUI/Selection.cpp | 7 ++++++- src/slic3r/GUI/Selection.hpp | 4 ++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 69280f7c7..72c6a5666 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -446,7 +446,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : m_reset_rotation_button->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) { GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); Selection& selection = canvas->get_selection(); - + selection.setup_cache(); #if ENABLE_WORLD_COORDINATE if (selection.is_single_volume_or_modifier()) { GLVolume* vol = const_cast(selection.get_first_volume()); @@ -468,9 +468,11 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : else return; - // Update rotation at the GLVolumes. - selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL); + // Synchronize instances/volumes. + + selection.synchronize_unselected_instances(Selection::SyncRotationType::RESET); selection.synchronize_unselected_volumes(); + // Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing. canvas->do_rotate(L("Reset Rotation")); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 4a5ddb59c..ed7e0ce30 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -3010,7 +3010,12 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_ const Transform3d& old_inst_trafo_j = m_cache.volumes_data[j].get_instance_transform().get_matrix(); assert(is_rotation_xy_synchronized(old_inst_trafo_i, old_inst_trafo_j)); Transform3d new_inst_trafo_j = volume_j->get_instance_transformation().get_matrix(); - if (sync_rotation_type != SyncRotationType::NONE || mirrored) + if (sync_rotation_type == SyncRotationType::RESET) { + Geometry::Transformation new_inst_trafo_j_no_rotation(new_inst_trafo_j); + new_inst_trafo_j_no_rotation.reset_rotation(); + new_inst_trafo_j = new_inst_trafo_j_no_rotation.get_matrix(); + } + else if (sync_rotation_type != SyncRotationType::NONE || mirrored) new_inst_trafo_j.linear() = (old_inst_trafo_j.linear() * old_inst_trafo_i.linear().inverse()) * curr_inst_trafo_i.linear(); if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) new_inst_trafo_j.translation().z() = curr_inst_trafo_i.translation().z(); diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index c1c97bd2e..4c818f30c 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -499,6 +499,10 @@ public: NONE = 0, // Synchronize after rotation by an axis not parallel with Z. GENERAL = 1, +#if ENABLE_WORLD_COORDINATE + // Synchronize after rotation reset. + RESET = 2 +#endif // ENABLE_WORLD_COORDINATE }; void synchronize_unselected_instances(SyncRotationType sync_rotation_type); void synchronize_unselected_volumes(); From 23f4b6913594e6b4f43e1d007cf89f5717bad3e7 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 24 Feb 2023 12:03:55 +0100 Subject: [PATCH 08/12] Fixed synchronization of instances while rotating in Object Coordinates --- src/slic3r/GUI/Selection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index ed7e0ce30..c6150ed68 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1056,7 +1056,7 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ if (m_mode == Instance) { int rot_axis_max = 0; rotation.cwiseAbs().maxCoeff(&rot_axis_max); - synchronize_unselected_instances((transformation_type.world() && rot_axis_max == 2) ? SyncRotationType::NONE : SyncRotationType::GENERAL); + synchronize_unselected_instances((rot_axis_max == 2) ? SyncRotationType::NONE : SyncRotationType::GENERAL); } else if (m_mode == Volume) synchronize_unselected_volumes(); From 77290b538c117016a288b4ed292ebf165498693a Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 27 Feb 2023 12:58:33 +0100 Subject: [PATCH 09/12] Fixed scale of mirrored objects shown in sidebar panel in Object Coordinates --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 72c6a5666..c16d77751 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -757,7 +757,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_new_rotation = volume->get_instance_rotation() * (180.0 / M_PI); m_new_size = volume->get_instance_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size()); #endif // ENABLE_WORLD_COORDINATE - m_new_scale = volume->get_instance_scaling_factor() * 100.0; + m_new_scale = m_new_size.cwiseQuotient(selection.get_full_unscaled_instance_local_bounding_box().size()) * 100.0; } m_new_enabled = true; From dcec7a8ad40eaad72789f6dba15cafc94664119f Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 28 Feb 2023 08:08:56 +0100 Subject: [PATCH 10/12] Fixed Rotate Gizmo orientation for mirrored objects + ensure that instances and volumes always rotate as rigid body --- src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 8 +--- src/slic3r/GUI/Selection.cpp | 59 ++++++++++++------------- src/slic3r/GUI/Selection.hpp | 2 +- 3 files changed, 30 insertions(+), 39 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index f7951f97c..345d733af 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -238,13 +238,7 @@ void GLGizmoRotate::init_data_from_selection(const Selection& selection) selection.get_bounding_box_in_reference_system(ECoordinatesType::Local) : selection.get_bounding_box_in_current_reference_system(); m_bounding_box = box; m_center = box_trafo.translation(); - m_orient_matrix = Geometry::translation_transform(m_center); - if (!wxGetApp().obj_manipul()->is_world_coordinates() || m_force_local_coordinate) { - const GLVolume& v = *selection.get_first_volume(); - m_orient_matrix = m_orient_matrix * v.get_instance_transformation().get_rotation_matrix(); - if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates() || m_force_local_coordinate) - m_orient_matrix = m_orient_matrix * v.get_volume_transformation().get_rotation_matrix(); - } + m_orient_matrix = box_trafo; m_radius = Offset + m_bounding_box.radius(); m_snap_coarse_in_radius = m_radius / 3.0f; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index c6150ed68..4e9ac43ea 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -918,7 +918,7 @@ void Selection::translate(const Vec3d& displacement, TransformationType transfor v.set_instance_offset(inst_trafo.get_offset() + inst_trafo.get_rotation_matrix() * displacement); } else - transform_instance_relative_world(v, volume_data, transformation_type, Geometry::translation_transform(displacement), m_cache.dragging_center); + transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(displacement), m_cache.dragging_center); } else { if (transformation_type.local() && transformation_type.absolute()) { @@ -998,24 +998,24 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ assert(transformation_type.relative() || (transformation_type.absolute() && transformation_type.local())); - Transform3d rotation_matrix = Geometry::rotation_transform(rotation); - for (unsigned int i : m_list) { + Transform3d rotation_matrix = Geometry::rotation_transform(rotation); GLVolume& v = *(*m_volumes)[i]; const VolumeCache& volume_data = m_cache.volumes_data[i]; const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform(); if (m_mode == Instance && !is_wipe_tower()) { assert(is_from_fully_selected_instance(i)); if (transformation_type.instance()) { - const Vec3d world_inst_pivot = m_cache.dragging_center - inst_trafo.get_offset(); - const Vec3d local_inst_pivot = inst_trafo.get_matrix_no_offset().inverse() * world_inst_pivot; - Matrix3d inst_rotation, inst_scale; - inst_trafo.get_matrix().computeRotationScaling(&inst_rotation, &inst_scale); - const Transform3d trafo = inst_trafo.get_rotation_matrix() * rotation_matrix; - v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * inst_trafo.get_offset_matrix() * trafo * Transform3d(inst_scale) * Geometry::translation_transform(-local_inst_pivot)); + // ensure that the instance rotates as a rigid body + const Transform3d inst_matrix_no_offset = inst_trafo.get_matrix_no_offset(); + const Transform3d inst_rotation_matrix = inst_trafo.get_rotation_matrix(); + rotation_matrix = inst_matrix_no_offset.inverse() * inst_rotation_matrix * rotation_matrix * inst_rotation_matrix.inverse() * inst_matrix_no_offset; + + // rotate around selection center + const Vec3d inst_pivot = inst_trafo.get_matrix_no_offset().inverse() * (m_cache.dragging_center - inst_trafo.get_offset()); + rotation_matrix = Geometry::translation_transform(inst_pivot) * rotation_matrix * Geometry::translation_transform(-inst_pivot); } - else - transform_instance_relative_world(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center); + transform_instance_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center); } else { if (!is_single_volume_or_modifier()) { @@ -1024,27 +1024,19 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ } else { if (transformation_type.instance()) { - // ensure proper sign of rotation for mirrored objects - if (inst_trafo.is_left_handed() && !rotation.normalized().isApprox(Vec3d::UnitX())) - rotation_matrix = rotation_matrix.inverse(); - // ensure that the volume rotates as a rigid body const Transform3d inst_scale_matrix = inst_trafo.get_scaling_factor_matrix(); rotation_matrix = inst_scale_matrix.inverse() * rotation_matrix * inst_scale_matrix; } else { if (transformation_type.local()) { - const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform(); - const Geometry::Transformation world_trafo = inst_trafo * vol_trafo; - // ensure proper sign of rotation for mirrored objects - if (world_trafo.is_left_handed() && !rotation.normalized().isApprox(Vec3d::UnitX())) - rotation_matrix = rotation_matrix.inverse(); - // ensure that the volume rotates as a rigid body - if (Geometry::TransformationSVD(world_trafo).anisotropic_scale) { - const Transform3d inst_scale_matrix = inst_trafo.get_scaling_factor_matrix(); - rotation_matrix = inst_scale_matrix.inverse() * rotation_matrix * inst_scale_matrix; - } + const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform(); + const Transform3d vol_matrix_no_offset = vol_trafo.get_matrix_no_offset(); + const Transform3d inst_scale_matrix = inst_trafo.get_scaling_factor_matrix(); + const Transform3d vol_rotation_matrix = vol_trafo.get_rotation_matrix(); + rotation_matrix = vol_matrix_no_offset.inverse() * inst_scale_matrix.inverse() * vol_rotation_matrix * rotation_matrix * + vol_rotation_matrix.inverse() * inst_scale_matrix * vol_matrix_no_offset; } } transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center); @@ -1458,7 +1450,7 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * offset_trafo * Transform3d(inst_rotation) * scale_trafo * Geometry::translation_transform(-local_inst_pivot)); } else - transform_instance_relative_world(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center); + transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center); } else { if (!is_single_volume_or_modifier()) { @@ -3331,16 +3323,21 @@ void Selection::paste_objects_from_clipboard() } #if ENABLE_WORLD_COORDINATE -void Selection::transform_instance_relative_world(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, +void Selection::transform_instance_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, const Transform3d& transform, const Vec3d& world_pivot) { assert(transformation_type.relative()); - assert(transformation_type.world()); const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform(); - const Vec3d inst_pivot = transformation_type.independent() && !is_from_single_instance() ? inst_trafo.get_offset() : world_pivot; - const Transform3d trafo = Geometry::translation_transform(inst_pivot) * transform * Geometry::translation_transform(-inst_pivot); - volume.set_instance_transformation(trafo * inst_trafo.get_matrix()); + if (transformation_type.world()) { + const Vec3d inst_pivot = transformation_type.independent() && !is_from_single_instance() ? inst_trafo.get_offset() : world_pivot; + const Transform3d trafo = Geometry::translation_transform(inst_pivot) * transform * Geometry::translation_transform(-inst_pivot); + volume.set_instance_transformation(trafo * inst_trafo.get_matrix()); + } + else if (transformation_type.instance()) + volume.set_instance_transformation(inst_trafo.get_matrix() * transform); + else + assert(false); } void Selection::transform_volume_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 4c818f30c..eb69d4491 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -516,7 +516,7 @@ private: void paste_objects_from_clipboard(); #if ENABLE_WORLD_COORDINATE - void transform_instance_relative_world(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, + void transform_instance_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, const Transform3d& transform, const Vec3d& world_pivot); void transform_volume_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, const Transform3d& transform, const Vec3d& world_pivot); From 148732281d1b0cef815972f578e4035ec275eccd Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 28 Feb 2023 11:47:46 +0100 Subject: [PATCH 11/12] Fixed rotation of mirrored objects in Object Coordinates --- src/slic3r/GUI/Selection.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 4e9ac43ea..e45f21467 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1006,9 +1006,17 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ if (m_mode == Instance && !is_wipe_tower()) { assert(is_from_fully_selected_instance(i)); if (transformation_type.instance()) { - // ensure that the instance rotates as a rigid body + // ensure that the instance rotates as a rigid body + Transform3d inst_rotation_matrix = inst_trafo.get_rotation_matrix(); + if (inst_trafo.is_left_handed()) { + Geometry::TransformationSVD inst_svd(inst_trafo); + inst_rotation_matrix = inst_svd.u * inst_svd.v.transpose(); + // ensure the rotation has the proper direction + if (!rotation.normalized().cwiseAbs().isApprox(Vec3d::UnitX())) + rotation_matrix = rotation_matrix.inverse(); + } + const Transform3d inst_matrix_no_offset = inst_trafo.get_matrix_no_offset(); - const Transform3d inst_rotation_matrix = inst_trafo.get_rotation_matrix(); rotation_matrix = inst_matrix_no_offset.inverse() * inst_rotation_matrix * rotation_matrix * inst_rotation_matrix.inverse() * inst_matrix_no_offset; // rotate around selection center From c1348079ed6b41a1f1c8740536f4a3736c64bf3e Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 28 Feb 2023 13:00:08 +0100 Subject: [PATCH 12/12] Fixed rotation of mirrored parts in Part Coordinates --- src/slic3r/GUI/Selection.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index e45f21467..fc2a6e0ea 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1042,7 +1042,14 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform(); const Transform3d vol_matrix_no_offset = vol_trafo.get_matrix_no_offset(); const Transform3d inst_scale_matrix = inst_trafo.get_scaling_factor_matrix(); - const Transform3d vol_rotation_matrix = vol_trafo.get_rotation_matrix(); + Transform3d vol_rotation_matrix = vol_trafo.get_rotation_matrix(); + if (vol_trafo.is_left_handed()) { + Geometry::TransformationSVD vol_svd(vol_trafo); + vol_rotation_matrix = vol_svd.u * vol_svd.v.transpose(); + // ensure the rotation has the proper direction + if (!rotation.normalized().cwiseAbs().isApprox(Vec3d::UnitX())) + rotation_matrix = rotation_matrix.inverse(); + } rotation_matrix = vol_matrix_no_offset.inverse() * inst_scale_matrix.inverse() * vol_rotation_matrix * rotation_matrix * vol_rotation_matrix.inverse() * inst_scale_matrix * vol_matrix_no_offset; }