diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index b263aecfd..45730dd9f 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -1223,7 +1223,7 @@ Vec3d extract_euler_angles(const Eigen::Matrix& // reference: http://www.gregslabaugh.net/publications/euler.pdf Vec3d angles1 = Vec3d::Zero(); Vec3d angles2 = Vec3d::Zero(); - if (is_approx(std::abs(rotation_matrix(2, 0)), 1.0)) + if (std::abs(std::abs(rotation_matrix(2, 0)) - 1.0) < 1e-5) { angles1(2) = 0.0; if (rotation_matrix(2, 0) < 0.0) // == -1.0 diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 610881aed..cdd3ebe85 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -841,41 +841,14 @@ void Selection::flattening_rotate(const Vec3d& normal) for (unsigned int i : m_list) { - Transform3d wst = m_cache.volumes_data[i].get_instance_scale_matrix(); - Vec3d scaling_factor = Vec3d(1. / wst(0, 0), 1. / wst(1, 1), 1. / wst(2, 2)); - - Transform3d wmt = m_cache.volumes_data[i].get_instance_mirror_matrix(); - Vec3d mirror(wmt(0, 0), wmt(1, 1), wmt(2, 2)); - - Vec3d rotation = Geometry::extract_euler_angles(m_cache.volumes_data[i].get_instance_rotation_matrix()); - Vec3d tnormal = Geometry::assemble_transform(Vec3d::Zero(), rotation, scaling_factor, mirror) * normal; - tnormal.normalize(); - - // Calculate rotation axis. It shall be perpendicular to "down" direction - // and the normal, so the rotation is the shortest possible and logical. - Vec3d axis = tnormal.cross(-Vec3d::UnitZ()); - - // Make sure the axis is not zero and normalize it. "Almost" zero is not interesting. - // In case the vectors are almost colinear, the rotation axis does not matter much. - if (axis == Vec3d::Zero()) - axis = Vec3d::UnitX(); - axis.normalize(); - - // Calculate the angle using the component where we achieve more precision. - // Cosine of small angles is const in first order. No good. - double angle = 0.; - if (std::abs(tnormal.z()) < std::sqrt(2.)/2.) - angle = std::acos(-tnormal.z()); - else { - double xy = std::hypot(tnormal.x(), tnormal.y()); - angle = PI/2. + std::acos(xy * (tnormal.z() > 0.)); - } - - Transform3d extra_rotation = Transform3d::Identity(); - extra_rotation.rotate(Eigen::AngleAxisd(angle, axis)); - - Vec3d new_rotation = Geometry::extract_euler_angles(extra_rotation * m_cache.volumes_data[i].get_instance_rotation_matrix()); - (*m_volumes)[i]->set_instance_rotation(new_rotation); + // Normal transformed from the object coordinate space to the world coordinate space. + const auto &voldata = m_cache.volumes_data[i]; + Vec3d tnormal = (Geometry::assemble_transform( + Vec3d::Zero(), voldata.get_instance_rotation(), + voldata.get_instance_scaling_factor().cwiseInverse(), voldata.get_instance_mirror()) * normal).normalized(); + // Additional rotation to align tnormal with the down vector in the world coordinate space. + auto extra_rotation = Eigen::Quaterniond().setFromTwoVectors(tnormal, - Vec3d::UnitZ()); + (*m_volumes)[i]->set_instance_rotation(Geometry::extract_euler_angles(extra_rotation.toRotationMatrix() * m_cache.volumes_data[i].get_instance_rotation_matrix())); } #if !DISABLE_INSTANCES_SYNCH