From 388ecdd0aaa26a0dcad526ca026e56bfa019a96e Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 25 Jan 2023 10:12:47 +0100 Subject: [PATCH 1/5] Experimental new implementation for Selection::synchronize_unselected_instances() --- src/slic3r/GUI/Selection.cpp | 311 +++++++++++++++++++++++++++++++---- 1 file changed, 283 insertions(+), 28 deletions(-) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 261604524..96e8f52e0 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -2889,6 +2889,225 @@ static void verify_instances_rotation_synchronized(const Model &model, const GLV } #endif /* NDEBUG */ +#if ENABLE_WORLD_COORDINATE +#define NO_TEST 0 +#define TEST_1 1 +#define TEST_2 2 +#define TEST_3 3 +#define USE_ALGORITHM TEST_3 + +#if USE_ALGORITHM == TEST_1 +void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_type) +{ + std::set done; // prevent processing volumes twice + done.insert(m_list.begin(), m_list.end()); + + for (unsigned int i : m_list) { + if (done.size() == m_volumes->size()) + break; + + const GLVolume& volume_i = *(*m_volumes)[i]; + if (volume_i.is_wipe_tower) + continue; + + const Geometry::Transformation& trafo_inst_i = volume_i.get_instance_transformation(); + const Vec3d offset_i = trafo_inst_i.get_offset(); + const double rotation_z_i = trafo_inst_i.get_rotation().z(); + + // Process unselected instances. + for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) { + if (done.size() == m_volumes->size()) + break; + + if (done.find(j) != done.end()) + continue; + + GLVolume& volume_j = *(*m_volumes)[j]; + if (volume_j.object_idx() != volume_i.object_idx() || volume_j.instance_idx() == volume_i.instance_idx()) + continue; + + const Geometry::Transformation& trafo_inst_j = m_cache.volumes_data[j].get_instance_transform(); + const Vec3d offset_j = trafo_inst_j.get_offset(); + const double rotation_z_j = trafo_inst_j.get_rotation().z(); + const double diff_rotation_z = rotation_z_j - rotation_z_i; + + const Transform3d new_matrix_inst_j = Geometry::translation_transform(offset_j) * Geometry::rotation_transform(diff_rotation_z * Vec3d::UnitZ()) * + Geometry::translation_transform(-offset_i) * trafo_inst_i.get_matrix(); + + volume_j.set_instance_transformation(Geometry::Transformation(new_matrix_inst_j)); + done.insert(j); + } + } + +//#ifndef NDEBUG +// verify_instances_rotation_synchronized(*m_model, *m_volumes); +//#endif /* NDEBUG */ +} +#elif USE_ALGORITHM == TEST_2 +void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_type) +{ + auto fix_rotation = [](const Vec3d& rotation) { + const bool x = std::abs(std::abs(rotation.x()) - (double)PI) < EPSILON; + const bool y = std::abs(std::abs(rotation.y()) - (double)PI) < EPSILON; + const bool z = std::abs(std::abs(rotation.z()) - (double)PI) < EPSILON; + + Vec3d ret = rotation; + if ((x && y) || (x && z) || (y && z)) { + ret += (double)PI * Vec3d::Ones(); + if (ret.x() >= 2.0f * (double)PI) ret.x() -= 2.0f * (double)PI; + if (ret.y() >= 2.0f * (double)PI) ret.y() -= 2.0f * (double)PI; + if (ret.z() >= 2.0f * (double)PI) ret.z() -= 2.0f * (double)PI; + } + + return ret; + }; + + std::set done; // prevent processing volumes twice + done.insert(m_list.begin(), m_list.end()); + + for (unsigned int i : m_list) { + if (done.size() == m_volumes->size()) + break; + + const GLVolume& volume_i = *(*m_volumes)[i]; + if (volume_i.is_wipe_tower) + continue; + + const Geometry::Transformation& trafo_inst_i = volume_i.get_instance_transformation(); + const Vec3d offset_i = trafo_inst_i.get_offset(); + const double rotation_z_i = fix_rotation(trafo_inst_i.get_rotation()).z(); + + // Process unselected instances. + for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) { + if (done.size() == m_volumes->size()) + break; + + if (done.find(j) != done.end()) + continue; + + GLVolume& volume_j = *(*m_volumes)[j]; + if (volume_j.object_idx() != volume_i.object_idx() || volume_j.instance_idx() == volume_i.instance_idx()) + continue; + + const Geometry::Transformation& trafo_inst_j = m_cache.volumes_data[j].get_instance_transform(); + const Vec3d offset_j = trafo_inst_j.get_offset(); + const double rotation_z_j = fix_rotation(trafo_inst_j.get_rotation()).z(); + const double diff_rotation_z = rotation_z_j - rotation_z_i; + + const Transform3d new_matrix_inst_j = Geometry::translation_transform(offset_j) * Geometry::rotation_transform(diff_rotation_z * Vec3d::UnitZ()) * + Geometry::translation_transform(-offset_i) * trafo_inst_i.get_matrix(); + + volume_j.set_instance_transformation(Geometry::Transformation(new_matrix_inst_j)); + done.insert(j); + } + } + +//#ifndef NDEBUG +// verify_instances_rotation_synchronized(*m_model, *m_volumes); +//#endif /* NDEBUG */ +} +#elif USE_ALGORITHM == TEST_3 +#define APPLY_FIX_ROTATION 1 +#define APPLY_FIX_ROTATION_2 2 && APPLY_FIX_ROTATION +void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_type) +{ +#if APPLY_FIX_ROTATION + auto fix_rotation = [](const Vec3d& rotation) { + const bool x = std::abs(std::abs(rotation.x()) - (double)PI) < EPSILON; + const bool y = std::abs(std::abs(rotation.y()) - (double)PI) < EPSILON; + const bool z = std::abs(std::abs(rotation.z()) - (double)PI) < EPSILON; + + Vec3d ret = rotation; + if ((x && y) || (x && z) || (y && z)) { + ret += (double)PI * Vec3d::Ones(); + if (ret.x() >= 2.0f * (double)PI) ret.x() -= 2.0f * (double)PI; + if (ret.y() >= 2.0f * (double)PI) ret.y() -= 2.0f * (double)PI; + if (ret.z() >= 2.0f * (double)PI) ret.z() -= 2.0f * (double)PI; + } + + return ret; + }; + +#if APPLY_FIX_ROTATION_2 + auto fix_rotation_2 = [](const Vec3d& rotation) { + Vec3d ret = rotation; + if (0.5 * (double)PI <= rotation.y() && rotation.y() <= 1.5 * (double)PI) + ret.y() = 2.0 * (double)PI - ret.y(); + return ret; + }; +#endif // APPLY_FIX_ROTATION_2 +#endif // APPLY_FIX_ROTATION + + std::set done; // prevent processing volumes twice + done.insert(m_list.begin(), m_list.end()); + + for (unsigned int i : m_list) { + if (done.size() == m_volumes->size()) + break; + + const GLVolume& volume_i = *(*m_volumes)[i]; + if (volume_i.is_wipe_tower) + continue; + + const Geometry::Transformation& cached_trafo_inst_i = m_cache.volumes_data[i].get_instance_transform(); + const Geometry::Transformation& trafo_inst_i = volume_i.get_instance_transformation(); + Geometry::Transformation trafo_i = Geometry::Transformation(trafo_inst_i.get_matrix() * cached_trafo_inst_i.get_matrix().inverse()); + + Matrix3d rotation_comp_i; + Matrix3d scale_comp_i; + trafo_i.get_matrix().computeRotationScaling(&rotation_comp_i, &scale_comp_i); +#if APPLY_FIX_ROTATION +#if APPLY_FIX_ROTATION_2 + const Vec3d rotation_i = fix_rotation_2(fix_rotation(Geometry::extract_rotation(Transform3d(rotation_comp_i)))); +#else + const Vec3d rotation_i = fix_rotation(Geometry::extract_rotation(Transform3d(rotation_comp_i))); +#endif // APPLY_FIX_ROTATION_2 +#else + const Vec3d rotation_i = Geometry::extract_rotation(Transform3d(rotation_comp_i)); +#endif // APPLY_FIX_ROTATION + + std::cout << "rotation_i: " << to_string(rotation_i); + + const Vec3d rotation_no_z_i(rotation_i.x(), rotation_i.y(), 0.0); + + trafo_i = Geometry::Transformation(Geometry::rotation_transform(rotation_no_z_i) * Transform3d(scale_comp_i)); + + // Process unselected instances. + for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) { + if (done.size() == m_volumes->size()) + break; + + if (done.find(j) != done.end()) + continue; + + GLVolume& volume_j = *(*m_volumes)[j]; + if (volume_j.object_idx() != volume_i.object_idx() || volume_j.instance_idx() == volume_i.instance_idx()) + continue; + + const Geometry::Transformation& cached_trafo_inst_j = m_cache.volumes_data[j].get_instance_transform(); +#if APPLY_FIX_ROTATION + const Vec3d rotation_cached_trafo_inst_j = fix_rotation(cached_trafo_inst_j.get_rotation()); +#else + const Vec3d rotation_cached_trafo_inst_j = cached_trafo_inst_j.get_rotation(); +#endif // APPLY_FIX_ROTATION + + std::cout << " - rotation_cached_trafo_inst_j: " << to_string(rotation_cached_trafo_inst_j) << "\n"; + + const Transform3d rotation_z_cached_trafo_inst_j = Geometry::rotation_transform({ 0.0, 0.0, rotation_cached_trafo_inst_j.z() }); + + const Transform3d new_matrix_inst_j = cached_trafo_inst_j.get_offset_matrix() * rotation_z_cached_trafo_inst_j * trafo_i.get_matrix() * + rotation_z_cached_trafo_inst_j.inverse() * cached_trafo_inst_j.get_matrix_no_offset(); + + volume_j.set_instance_transformation(Geometry::Transformation(new_matrix_inst_j)); + done.insert(j); + } + } + +//#ifndef NDEBUG +// verify_instances_rotation_synchronized(*m_model, *m_volumes); +//#endif /* NDEBUG */ +} +#else void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_type) { std::set done; // prevent processing volumes twice @@ -2904,17 +3123,11 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_ const int object_idx = volume_i->object_idx(); const int instance_idx = volume_i->instance_idx(); -#if ENABLE_WORLD_COORDINATE const Geometry::Transformation& curr_inst_trafo_i = volume_i->get_instance_transformation(); const Vec3d curr_inst_rotation_i = curr_inst_trafo_i.get_rotation(); const Vec3d& curr_inst_scaling_factor_i = curr_inst_trafo_i.get_scaling_factor(); const Vec3d& curr_inst_mirror_i = curr_inst_trafo_i.get_mirror(); const Vec3d old_inst_rotation_i = m_cache.volumes_data[i].get_instance_transform().get_rotation(); -#else - const Vec3d& rotation = volume_i->get_instance_rotation(); - const Vec3d& scaling_factor = volume_i->get_instance_scaling_factor(); - const Vec3d& mirror = volume_i->get_instance_mirror(); -#endif // ENABLE_WORLD_COORDINATE // Process unselected instances. for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) { @@ -2928,44 +3141,28 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_ if (volume_j->object_idx() != object_idx || volume_j->instance_idx() == instance_idx) continue; -#if ENABLE_WORLD_COORDINATE const Vec3d old_inst_rotation_j = m_cache.volumes_data[j].get_instance_transform().get_rotation(); assert(is_rotation_xy_synchronized(old_inst_rotation_i, old_inst_rotation_j)); const Geometry::Transformation& curr_inst_trafo_j = volume_j->get_instance_transformation(); const Vec3d curr_inst_rotation_j = curr_inst_trafo_j.get_rotation(); Vec3d new_inst_offset_j = curr_inst_trafo_j.get_offset(); Vec3d new_inst_rotation_j = curr_inst_rotation_j; -#else - assert(is_rotation_xy_synchronized(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation())); -#endif // ENABLE_WORLD_COORDINATE switch (sync_rotation_type) { case SyncRotationType::NONE: { // z only rotation -> synch instance z // The X,Y rotations should be synchronized from start to end of the rotation. -#if ENABLE_WORLD_COORDINATE assert(is_rotation_xy_synchronized(curr_inst_rotation_i, curr_inst_rotation_j)); if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) new_inst_offset_j.z() = curr_inst_trafo_i.get_offset().z(); -#else - assert(is_rotation_xy_synchronized(rotation, volume_j->get_instance_rotation())); - if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) - volume_j->set_instance_offset(Z, volume_i->get_instance_offset().z()); -#endif // ENABLE_WORLD_COORDINATE break; } case SyncRotationType::GENERAL: { // generic rotation -> update instance z with the delta of the rotation. -#if ENABLE_WORLD_COORDINATE const double z_diff = Geometry::rotation_diff_z(old_inst_rotation_i, old_inst_rotation_j); new_inst_rotation_j = curr_inst_rotation_i + z_diff * Vec3d::UnitZ(); -#else - const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation()); - volume_j->set_instance_rotation({ rotation.x(), rotation.y(), rotation.z() + z_diff }); -#endif // ENABLE_WORLD_COORDINATE 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(curr_inst_rotation_i, old_inst_rotation_j)); @@ -2976,16 +3173,10 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_ new_inst_rotation_j = curr_inst_rotation_i + z_diff * Vec3d::UnitZ(); break; } -#endif // ENABLE_WORLD_COORDINATE } -#if ENABLE_WORLD_COORDINATE volume_j->set_instance_transformation(Geometry::assemble_transform(new_inst_offset_j, new_inst_rotation_j, curr_inst_scaling_factor_i, curr_inst_mirror_i)); -#else - volume_j->set_instance_scaling_factor(scaling_factor); - volume_j->set_instance_mirror(mirror); -#endif // ENABLE_WORLD_COORDINATE done.insert(j); } @@ -2995,6 +3186,70 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_ verify_instances_rotation_synchronized(*m_model, *m_volumes); #endif /* NDEBUG */ } +#endif // USE_ALGORITHM +#else +void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_type) +{ + std::set done; // prevent processing volumes twice + done.insert(m_list.begin(), m_list.end()); + + for (unsigned int i : m_list) { + if (done.size() == m_volumes->size()) + break; + + const GLVolume* volume_i = (*m_volumes)[i]; + if (volume_i->is_wipe_tower) + continue; + + const int object_idx = volume_i->object_idx(); + const int instance_idx = volume_i->instance_idx(); + const Vec3d& rotation = volume_i->get_instance_rotation(); + const Vec3d& scaling_factor = volume_i->get_instance_scaling_factor(); + const Vec3d& mirror = volume_i->get_instance_mirror(); + + // Process unselected instances. + for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) { + if (done.size() == m_volumes->size()) + break; + + if (done.find(j) != done.end()) + continue; + + GLVolume* volume_j = (*m_volumes)[j]; + if (volume_j->object_idx() != object_idx || volume_j->instance_idx() == instance_idx) + continue; + + 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 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, volume_j->get_instance_rotation())); + if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) + volume_j->set_instance_offset(Z, volume_i->get_instance_offset().z()); + break; + } + 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()); + volume_j->set_instance_rotation({ rotation.x(), rotation.y(), rotation.z() + z_diff }); + break; + } + } + + volume_j->set_instance_scaling_factor(scaling_factor); + volume_j->set_instance_mirror(mirror); + + done.insert(j); + } + } + +#ifndef NDEBUG + verify_instances_rotation_synchronized(*m_model, *m_volumes); +#endif /* NDEBUG */ +} +#endif // ENABLE_WORLD_COORDINATE void Selection::synchronize_unselected_volumes() { From 842229842f7fe7ce48215d6cfe55aaf4b46cfe56 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 25 Jan 2023 15:46:22 +0100 Subject: [PATCH 2/5] WIP Synchronization of mirroring --- src/libslic3r/Geometry.cpp | 3 +- src/libslic3r/Geometry.hpp | 3 +- src/slic3r/GUI/Selection.cpp | 109 +++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 7366d2233..25db3cce0 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -877,7 +877,8 @@ 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 double angle = angle_axis.angle(); -#ifndef NDEBUG +#if 0 +//#ifndef NDEBUG if (std::abs(angle) > 1e-8) { assert(std::abs(axis.x()) < 1e-8); assert(std::abs(axis.y()) < 1e-8); diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index a5df1e679..acaad6af3 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -470,8 +470,7 @@ public: Transform3d get_mirror_matrix() const; bool is_left_handed() const { - const Vec3d mirror = get_mirror(); - return mirror.x() * mirror.y() * mirror.z() < 0.0; + return m_matrix.affine().determinant() < 0; } #else bool is_scaling_uniform() const { return std::abs(m_scaling_factor.x() - m_scaling_factor.y()) < 1e-8 && std::abs(m_scaling_factor.x() - m_scaling_factor.z()) < 1e-8; } diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 96e8f52e0..76bbd825c 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -2852,6 +2852,16 @@ void Selection::render_debug_window() const } #endif // ENABLE_WORLD_COORDINATE_DEBUG +static bool is_left_handed(const Transform3d::ConstLinearPart& m) +{ + return m.determinant() < 0; +} + +static bool is_left_handed(const Transform3d& m) +{ + return is_left_handed(m.linear()); +} + #ifndef NDEBUG static bool is_rotation_xy_synchronized(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) { @@ -2866,6 +2876,7 @@ static bool is_rotation_xy_synchronized(const Vec3d &rot_xyz_from, const Vec3d & return std::abs(axis.x()) < 1e-8 && std::abs(axis.y()) < 1e-8 && std::abs(std::abs(axis.z()) - 1.) < 1e-8; } +#if 0 static void verify_instances_rotation_synchronized(const Model &model, const GLVolumePtrs &volumes) { for (int idx_object = 0; idx_object < int(model.objects.size()); ++idx_object) { @@ -2887,6 +2898,55 @@ static void verify_instances_rotation_synchronized(const Model &model, const GLV } } } +#endif + +static bool is_rotation_xy_synchronized(const Transform3d::ConstLinearPart &trafo_from, const Transform3d::ConstLinearPart &trafo_to) +{ + auto rot = trafo_to * trafo_from.inverse(); + static constexpr const double eps = EPSILON; + return + // Looks like a rotation around Z: block(0..1, 0..1) + no change of Z component. + is_approx(rot(0, 0), rot(1, 1), eps) && + is_approx(rot(0, 1), - rot(1, 0), eps) && + is_approx(rot(2, 2), 1., eps) && + // Rest should be zeros. + is_approx(rot(0, 2), 0., eps) && + is_approx(rot(1, 2), 0., eps) && + is_approx(rot(2, 0), 0., eps) && + is_approx(rot(2, 1), 0., eps) && + // Determinant equals 1 + is_approx(rot.determinant(), 1., eps) && + // and finally the rotated X and Y axes shall be perpendicular. + is_approx(rot(0, 0) * rot(0, 1) + rot(1, 0) * rot(1, 1), 0., eps); +} + +static bool is_rotation_xy_synchronized(const Transform3d& trafo_from, const Transform3d& trafo_to) +{ + return is_rotation_xy_synchronized(trafo_from.linear(), trafo_to.linear()); +} + +static void verify_instances_rotation_synchronized(const Model &model, const GLVolumePtrs &volumes) +{ + for (int idx_object = 0; idx_object < int(model.objects.size()); ++idx_object) { + int idx_volume_first = -1; + for (int i = 0; i < (int)volumes.size(); ++i) { + if (volumes[i]->object_idx() == idx_object) { + idx_volume_first = i; + break; + } + } + assert(idx_volume_first != -1); // object without instances? + if (idx_volume_first == -1) + continue; + const Transform3d::ConstLinearPart &rotation0 = volumes[idx_volume_first]->get_instance_transformation().get_matrix().linear(); + for (int i = idx_volume_first + 1; i < (int)volumes.size(); ++i) + if (volumes[i]->object_idx() == idx_object) { + const Transform3d::ConstLinearPart &rotation = volumes[i]->get_instance_transformation().get_matrix().linear(); + assert(is_rotation_xy_synchronized(rotation, rotation0)); + } + } +} + #endif /* NDEBUG */ #if ENABLE_WORLD_COORDINATE @@ -3007,6 +3067,9 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_ //#endif /* NDEBUG */ } #elif USE_ALGORITHM == TEST_3 + + +#if 0 #define APPLY_FIX_ROTATION 1 #define APPLY_FIX_ROTATION_2 2 && APPLY_FIX_ROTATION void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_type) @@ -3109,6 +3172,52 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_ } #else void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_type) +{ + std::set done; // prevent processing volumes twice + done.insert(m_list.begin(), m_list.end()); + for (unsigned int i : m_list) { + if (done.size() == m_volumes->size()) + break; + const GLVolume* volume_i = (*m_volumes)[i]; + if (volume_i->is_wipe_tower) + continue; + + const int object_idx = volume_i->object_idx(); + const int instance_idx = volume_i->instance_idx(); + const Transform3d& curr_inst_trafo_i = volume_i->get_instance_transformation().get_matrix(); + const bool curr_inst_left_handed = is_left_handed(curr_inst_trafo_i); + const Transform3d& old_inst_trafo_i = m_cache.volumes_data[i].get_instance_transform().get_matrix(); + bool mirrored = is_left_handed(curr_inst_trafo_i) != is_left_handed(old_inst_trafo_i); +// bool mirrored = curr_inst_trafo_i.linear().determinant() * old_inst_trafo_i.linear().determinant() < 0; + + // Process unselected instances. + for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) { + if (done.size() == m_volumes->size()) + break; + if (done.find(j) != done.end()) + continue; + GLVolume* volume_j = (*m_volumes)[j]; + if (volume_j->object_idx() != object_idx || volume_j->instance_idx() == instance_idx) + continue; + 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) + 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(); + assert(is_rotation_xy_synchronized(curr_inst_trafo_i, new_inst_trafo_j)); + volume_j->set_instance_transformation(new_inst_trafo_j); + done.insert(j); + } + } +#ifndef NDEBUG + verify_instances_rotation_synchronized(*m_model, *m_volumes); +#endif /* NDEBUG */ +} +#endif +#else +void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_type) { std::set done; // prevent processing volumes twice done.insert(m_list.begin(), m_list.end()); From a784be24e7b4e2883bc64726b39cdcc7ee413640 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 25 Jan 2023 18:51:53 +0100 Subject: [PATCH 3/5] Follow-up to 842229842f7fe7ce48215d6cfe55aaf4b46cfe56 WIP Synchronization of mirroring Fixed mirroring at the FDM and SLA back-end. --- src/libslic3r/Geometry.cpp | 14 ++++++++++++-- src/libslic3r/Geometry.hpp | 1 + src/libslic3r/Print.cpp | 2 +- src/libslic3r/SLAPrint.cpp | 5 ++--- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 25db3cce0..7bab0ed7a 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -877,8 +877,7 @@ 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 double angle = angle_axis.angle(); -#if 0 -//#ifndef NDEBUG +#ifndef NDEBUG if (std::abs(angle) > 1e-8) { assert(std::abs(axis.x()) < 1e-8); assert(std::abs(axis.y()) < 1e-8); @@ -887,4 +886,15 @@ double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) return (axis.z() < 0) ? -angle : angle; } +double rotation_diff_z(const Transform3d &trafo_from, const Transform3d &trafo_to) +{ + auto m = trafo_to.linear() * trafo_from.linear().inverse(); + assert(std::abs(m.determinant() - 1)); + Vec3d vx = m * Vec3d(1., 0., 0); + // Verify that the linear part of rotation from trafo_from to trafo_to rotates around Z and is unity. + assert(std::abs(std::hypot(vx.x(), vx.y()) - 1.) < 1e-5); + assert(std::abs(vx.z()) < 1e-5); + return atan2(vx.y(), vx.x()); +} + }} // namespace Slic3r::Geometry diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index acaad6af3..d7cf32611 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -547,6 +547,7 @@ extern Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec // Rotation by Z to align rot_xyz_from to rot_xyz_to. // This should only be called if it is known, that the two rotations only differ in rotation around the Z axis. extern double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to); +extern double rotation_diff_z(const Transform3d &trafo_from, const Transform3d &trafo_to); // Is the angle close to a multiple of 90 degrees? inline bool is_rotation_ninety_degrees(double a) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index e7305234f..eff0bcd45 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -404,7 +404,7 @@ bool Print::sequential_print_horizontal_clearance_valid(const Print& print, Poly } // Make a copy, so it may be rotated for instances. Polygon convex_hull0 = it_convex_hull->second; - const double z_diff = Geometry::rotation_diff_z(model_instance0->get_rotation(), print_object->instances().front().model_instance->get_rotation()); + const double z_diff = Geometry::rotation_diff_z(model_instance0->get_matrix(), print_object->instances().front().model_instance->get_matrix()); if (std::abs(z_diff) > EPSILON) convex_hull0.rotate(z_diff); // Now we check that no instance of convex_hull intersects any of the previously checked object instances. diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index d4023f64d..dc5e2b519 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -190,14 +190,13 @@ static std::vector sla_instances(const ModelObject &mo std::vector instances; assert(! model_object.instances.empty()); if (! model_object.instances.empty()) { - Vec3d rotation0 = model_object.instances.front()->get_rotation(); - rotation0(2) = 0.; + const Transform3d& trafo0 = model_object.instances.front()->get_matrix(); for (ModelInstance *model_instance : model_object.instances) if (model_instance->is_printable()) { instances.emplace_back( model_instance->id(), Point::new_scale(model_instance->get_offset(X), model_instance->get_offset(Y)), - float(Geometry::rotation_diff_z(rotation0, model_instance->get_rotation()))); + float(Geometry::rotation_diff_z(trafo0, model_instance->get_matrix()))); } } return instances; From 643d50813d62004f8ad7cf3f2aa6ecfc582d839c Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 26 Jan 2023 10:00:35 +0100 Subject: [PATCH 4/5] Removed function double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) and remaining code using it --- src/libslic3r/Geometry.cpp | 16 +--------------- src/libslic3r/Geometry.hpp | 1 - src/libslic3r/Model.cpp | 2 +- src/libslic3r/PrintObject.cpp | 4 ++-- 4 files changed, 4 insertions(+), 19 deletions(-) diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 7bab0ed7a..441825654 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -872,24 +872,10 @@ Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot } // This should only be called if it is known, that the two rotations only differ in rotation around the Z axis. -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 double angle = angle_axis.angle(); -#ifndef NDEBUG - if (std::abs(angle) > 1e-8) { - assert(std::abs(axis.x()) < 1e-8); - assert(std::abs(axis.y()) < 1e-8); - } -#endif /* NDEBUG */ - return (axis.z() < 0) ? -angle : angle; -} - double rotation_diff_z(const Transform3d &trafo_from, const Transform3d &trafo_to) { auto m = trafo_to.linear() * trafo_from.linear().inverse(); - assert(std::abs(m.determinant() - 1)); + assert(std::abs(m.determinant() - 1) < EPSILON); Vec3d vx = m * Vec3d(1., 0., 0); // Verify that the linear part of rotation from trafo_from to trafo_to rotates around Z and is unity. assert(std::abs(std::hypot(vx.x(), vx.y()) - 1.) < 1e-5); diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index d7cf32611..0421c0806 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -546,7 +546,6 @@ extern Transform3d transform3d_from_string(const std::string& transform_str); extern Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to); // Rotation by Z to align rot_xyz_from to rot_xyz_to. // This should only be called if it is known, that the two rotations only differ in rotation around the Z axis. -extern double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to); extern double rotation_diff_z(const Transform3d &trafo_from, const Transform3d &trafo_to); // Is the angle close to a multiple of 90 degrees? diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index b823eb4fa..bdd9bfd70 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1780,7 +1780,7 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx) // Adjust the instances. for (size_t i = 0; i < this->instances.size(); ++ i) { ModelInstance &model_instance = *this->instances[i]; - model_instance.set_rotation(Vec3d(0., 0., Geometry::rotation_diff_z(reference_trafo.get_rotation(), model_instance.get_rotation()))); + model_instance.set_rotation(Vec3d(0., 0., Geometry::rotation_diff_z(reference_trafo.get_matrix(), model_instance.get_matrix()))); model_instance.set_scaling_factor(Vec3d(new_scaling_factor, new_scaling_factor, new_scaling_factor)); model_instance.set_mirror(Vec3d(1., 1., 1.)); } diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index dc75fb8a3..dfa280f45 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -69,8 +69,8 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Transfor BoundingBoxf3 bbox = model_object->raw_bounding_box(); Vec3d bbox_center = bbox.center(); // We may need to rotate the bbox / bbox_center from the original instance to the current instance. - double z_diff = Geometry::rotation_diff_z(model_object->instances.front()->get_rotation(), instances.front().model_instance->get_rotation()); - if (std::abs(z_diff) > EPSILON) { + double z_diff = Geometry::rotation_diff_z(model_object->instances.front()->get_matrix(), instances.front().model_instance->get_matrix()); + if (std::abs(z_diff) > EPSILON) { auto z_rot = Eigen::AngleAxisd(z_diff, Vec3d::UnitZ()); bbox = bbox.transformed(Transform3d(z_rot)); bbox_center = (z_rot * bbox_center).eval(); From 25a941d8e7939f7adb38f8870524bb59cbefdded Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 26 Jan 2023 10:23:50 +0100 Subject: [PATCH 5/5] Code cleanup --- src/slic3r/GUI/Selection.cpp | 302 ----------------------------------- 1 file changed, 302 deletions(-) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 76bbd825c..5678008d3 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -2950,227 +2950,6 @@ static void verify_instances_rotation_synchronized(const Model &model, const GLV #endif /* NDEBUG */ #if ENABLE_WORLD_COORDINATE -#define NO_TEST 0 -#define TEST_1 1 -#define TEST_2 2 -#define TEST_3 3 -#define USE_ALGORITHM TEST_3 - -#if USE_ALGORITHM == TEST_1 -void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_type) -{ - std::set done; // prevent processing volumes twice - done.insert(m_list.begin(), m_list.end()); - - for (unsigned int i : m_list) { - if (done.size() == m_volumes->size()) - break; - - const GLVolume& volume_i = *(*m_volumes)[i]; - if (volume_i.is_wipe_tower) - continue; - - const Geometry::Transformation& trafo_inst_i = volume_i.get_instance_transformation(); - const Vec3d offset_i = trafo_inst_i.get_offset(); - const double rotation_z_i = trafo_inst_i.get_rotation().z(); - - // Process unselected instances. - for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) { - if (done.size() == m_volumes->size()) - break; - - if (done.find(j) != done.end()) - continue; - - GLVolume& volume_j = *(*m_volumes)[j]; - if (volume_j.object_idx() != volume_i.object_idx() || volume_j.instance_idx() == volume_i.instance_idx()) - continue; - - const Geometry::Transformation& trafo_inst_j = m_cache.volumes_data[j].get_instance_transform(); - const Vec3d offset_j = trafo_inst_j.get_offset(); - const double rotation_z_j = trafo_inst_j.get_rotation().z(); - const double diff_rotation_z = rotation_z_j - rotation_z_i; - - const Transform3d new_matrix_inst_j = Geometry::translation_transform(offset_j) * Geometry::rotation_transform(diff_rotation_z * Vec3d::UnitZ()) * - Geometry::translation_transform(-offset_i) * trafo_inst_i.get_matrix(); - - volume_j.set_instance_transformation(Geometry::Transformation(new_matrix_inst_j)); - done.insert(j); - } - } - -//#ifndef NDEBUG -// verify_instances_rotation_synchronized(*m_model, *m_volumes); -//#endif /* NDEBUG */ -} -#elif USE_ALGORITHM == TEST_2 -void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_type) -{ - auto fix_rotation = [](const Vec3d& rotation) { - const bool x = std::abs(std::abs(rotation.x()) - (double)PI) < EPSILON; - const bool y = std::abs(std::abs(rotation.y()) - (double)PI) < EPSILON; - const bool z = std::abs(std::abs(rotation.z()) - (double)PI) < EPSILON; - - Vec3d ret = rotation; - if ((x && y) || (x && z) || (y && z)) { - ret += (double)PI * Vec3d::Ones(); - if (ret.x() >= 2.0f * (double)PI) ret.x() -= 2.0f * (double)PI; - if (ret.y() >= 2.0f * (double)PI) ret.y() -= 2.0f * (double)PI; - if (ret.z() >= 2.0f * (double)PI) ret.z() -= 2.0f * (double)PI; - } - - return ret; - }; - - std::set done; // prevent processing volumes twice - done.insert(m_list.begin(), m_list.end()); - - for (unsigned int i : m_list) { - if (done.size() == m_volumes->size()) - break; - - const GLVolume& volume_i = *(*m_volumes)[i]; - if (volume_i.is_wipe_tower) - continue; - - const Geometry::Transformation& trafo_inst_i = volume_i.get_instance_transformation(); - const Vec3d offset_i = trafo_inst_i.get_offset(); - const double rotation_z_i = fix_rotation(trafo_inst_i.get_rotation()).z(); - - // Process unselected instances. - for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) { - if (done.size() == m_volumes->size()) - break; - - if (done.find(j) != done.end()) - continue; - - GLVolume& volume_j = *(*m_volumes)[j]; - if (volume_j.object_idx() != volume_i.object_idx() || volume_j.instance_idx() == volume_i.instance_idx()) - continue; - - const Geometry::Transformation& trafo_inst_j = m_cache.volumes_data[j].get_instance_transform(); - const Vec3d offset_j = trafo_inst_j.get_offset(); - const double rotation_z_j = fix_rotation(trafo_inst_j.get_rotation()).z(); - const double diff_rotation_z = rotation_z_j - rotation_z_i; - - const Transform3d new_matrix_inst_j = Geometry::translation_transform(offset_j) * Geometry::rotation_transform(diff_rotation_z * Vec3d::UnitZ()) * - Geometry::translation_transform(-offset_i) * trafo_inst_i.get_matrix(); - - volume_j.set_instance_transformation(Geometry::Transformation(new_matrix_inst_j)); - done.insert(j); - } - } - -//#ifndef NDEBUG -// verify_instances_rotation_synchronized(*m_model, *m_volumes); -//#endif /* NDEBUG */ -} -#elif USE_ALGORITHM == TEST_3 - - -#if 0 -#define APPLY_FIX_ROTATION 1 -#define APPLY_FIX_ROTATION_2 2 && APPLY_FIX_ROTATION -void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_type) -{ -#if APPLY_FIX_ROTATION - auto fix_rotation = [](const Vec3d& rotation) { - const bool x = std::abs(std::abs(rotation.x()) - (double)PI) < EPSILON; - const bool y = std::abs(std::abs(rotation.y()) - (double)PI) < EPSILON; - const bool z = std::abs(std::abs(rotation.z()) - (double)PI) < EPSILON; - - Vec3d ret = rotation; - if ((x && y) || (x && z) || (y && z)) { - ret += (double)PI * Vec3d::Ones(); - if (ret.x() >= 2.0f * (double)PI) ret.x() -= 2.0f * (double)PI; - if (ret.y() >= 2.0f * (double)PI) ret.y() -= 2.0f * (double)PI; - if (ret.z() >= 2.0f * (double)PI) ret.z() -= 2.0f * (double)PI; - } - - return ret; - }; - -#if APPLY_FIX_ROTATION_2 - auto fix_rotation_2 = [](const Vec3d& rotation) { - Vec3d ret = rotation; - if (0.5 * (double)PI <= rotation.y() && rotation.y() <= 1.5 * (double)PI) - ret.y() = 2.0 * (double)PI - ret.y(); - return ret; - }; -#endif // APPLY_FIX_ROTATION_2 -#endif // APPLY_FIX_ROTATION - - std::set done; // prevent processing volumes twice - done.insert(m_list.begin(), m_list.end()); - - for (unsigned int i : m_list) { - if (done.size() == m_volumes->size()) - break; - - const GLVolume& volume_i = *(*m_volumes)[i]; - if (volume_i.is_wipe_tower) - continue; - - const Geometry::Transformation& cached_trafo_inst_i = m_cache.volumes_data[i].get_instance_transform(); - const Geometry::Transformation& trafo_inst_i = volume_i.get_instance_transformation(); - Geometry::Transformation trafo_i = Geometry::Transformation(trafo_inst_i.get_matrix() * cached_trafo_inst_i.get_matrix().inverse()); - - Matrix3d rotation_comp_i; - Matrix3d scale_comp_i; - trafo_i.get_matrix().computeRotationScaling(&rotation_comp_i, &scale_comp_i); -#if APPLY_FIX_ROTATION -#if APPLY_FIX_ROTATION_2 - const Vec3d rotation_i = fix_rotation_2(fix_rotation(Geometry::extract_rotation(Transform3d(rotation_comp_i)))); -#else - const Vec3d rotation_i = fix_rotation(Geometry::extract_rotation(Transform3d(rotation_comp_i))); -#endif // APPLY_FIX_ROTATION_2 -#else - const Vec3d rotation_i = Geometry::extract_rotation(Transform3d(rotation_comp_i)); -#endif // APPLY_FIX_ROTATION - - std::cout << "rotation_i: " << to_string(rotation_i); - - const Vec3d rotation_no_z_i(rotation_i.x(), rotation_i.y(), 0.0); - - trafo_i = Geometry::Transformation(Geometry::rotation_transform(rotation_no_z_i) * Transform3d(scale_comp_i)); - - // Process unselected instances. - for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) { - if (done.size() == m_volumes->size()) - break; - - if (done.find(j) != done.end()) - continue; - - GLVolume& volume_j = *(*m_volumes)[j]; - if (volume_j.object_idx() != volume_i.object_idx() || volume_j.instance_idx() == volume_i.instance_idx()) - continue; - - const Geometry::Transformation& cached_trafo_inst_j = m_cache.volumes_data[j].get_instance_transform(); -#if APPLY_FIX_ROTATION - const Vec3d rotation_cached_trafo_inst_j = fix_rotation(cached_trafo_inst_j.get_rotation()); -#else - const Vec3d rotation_cached_trafo_inst_j = cached_trafo_inst_j.get_rotation(); -#endif // APPLY_FIX_ROTATION - - std::cout << " - rotation_cached_trafo_inst_j: " << to_string(rotation_cached_trafo_inst_j) << "\n"; - - const Transform3d rotation_z_cached_trafo_inst_j = Geometry::rotation_transform({ 0.0, 0.0, rotation_cached_trafo_inst_j.z() }); - - const Transform3d new_matrix_inst_j = cached_trafo_inst_j.get_offset_matrix() * rotation_z_cached_trafo_inst_j * trafo_i.get_matrix() * - rotation_z_cached_trafo_inst_j.inverse() * cached_trafo_inst_j.get_matrix_no_offset(); - - volume_j.set_instance_transformation(Geometry::Transformation(new_matrix_inst_j)); - done.insert(j); - } - } - -//#ifndef NDEBUG -// verify_instances_rotation_synchronized(*m_model, *m_volumes); -//#endif /* NDEBUG */ -} -#else void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_type) { std::set done; // prevent processing volumes twice @@ -3215,87 +2994,6 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_ verify_instances_rotation_synchronized(*m_model, *m_volumes); #endif /* NDEBUG */ } -#endif -#else -void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_type) -{ - std::set done; // prevent processing volumes twice - done.insert(m_list.begin(), m_list.end()); - - for (unsigned int i : m_list) { - if (done.size() == m_volumes->size()) - break; - - const GLVolume* volume_i = (*m_volumes)[i]; - if (volume_i->is_wipe_tower) - continue; - - const int object_idx = volume_i->object_idx(); - const int instance_idx = volume_i->instance_idx(); - const Geometry::Transformation& curr_inst_trafo_i = volume_i->get_instance_transformation(); - const Vec3d curr_inst_rotation_i = curr_inst_trafo_i.get_rotation(); - const Vec3d& curr_inst_scaling_factor_i = curr_inst_trafo_i.get_scaling_factor(); - const Vec3d& curr_inst_mirror_i = curr_inst_trafo_i.get_mirror(); - const Vec3d old_inst_rotation_i = m_cache.volumes_data[i].get_instance_transform().get_rotation(); - - // Process unselected instances. - for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) { - if (done.size() == m_volumes->size()) - break; - - if (done.find(j) != done.end()) - continue; - - GLVolume* volume_j = (*m_volumes)[j]; - if (volume_j->object_idx() != object_idx || volume_j->instance_idx() == instance_idx) - continue; - - const Vec3d old_inst_rotation_j = m_cache.volumes_data[j].get_instance_transform().get_rotation(); - assert(is_rotation_xy_synchronized(old_inst_rotation_i, old_inst_rotation_j)); - const Geometry::Transformation& curr_inst_trafo_j = volume_j->get_instance_transformation(); - const Vec3d curr_inst_rotation_j = curr_inst_trafo_j.get_rotation(); - Vec3d new_inst_offset_j = curr_inst_trafo_j.get_offset(); - Vec3d new_inst_rotation_j = curr_inst_rotation_j; - - switch (sync_rotation_type) { - 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(curr_inst_rotation_i, curr_inst_rotation_j)); - if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) - new_inst_offset_j.z() = curr_inst_trafo_i.get_offset().z(); - break; - } - case SyncRotationType::GENERAL: { - // generic rotation -> update instance z with the delta of the rotation. - const double z_diff = Geometry::rotation_diff_z(old_inst_rotation_i, old_inst_rotation_j); - new_inst_rotation_j = curr_inst_rotation_i + z_diff * Vec3d::UnitZ(); - break; - } - case SyncRotationType::FULL: { - // generic rotation -> update instance z with the delta of the rotation. - const Eigen::AngleAxisd angle_axis(Geometry::rotation_xyz_diff(curr_inst_rotation_i, old_inst_rotation_j)); - 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(curr_inst_rotation_i, old_inst_rotation_j); - - new_inst_rotation_j = curr_inst_rotation_i + z_diff * Vec3d::UnitZ(); - break; - } - } - - volume_j->set_instance_transformation(Geometry::assemble_transform(new_inst_offset_j, new_inst_rotation_j, - curr_inst_scaling_factor_i, curr_inst_mirror_i)); - - done.insert(j); - } - } - -#ifndef NDEBUG - verify_instances_rotation_synchronized(*m_model, *m_volumes); -#endif /* NDEBUG */ -} -#endif // USE_ALGORITHM #else void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_type) {