From 842229842f7fe7ce48215d6cfe55aaf4b46cfe56 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 25 Jan 2023 15:46:22 +0100 Subject: [PATCH] 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 7366d22335..25db3cce09 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 a5df1e6791..acaad6af31 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 96e8f52e03..76bbd825cf 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());