Fix of Place on face:
1) Decreased "gimbal lock" epsilon 10x 2) Got rid of unnecessary back and forth conversions which led to numerical inacurracies This should fix issues #5172, #5011 and #5398
This commit is contained in:
parent
fe4f1b15c6
commit
2d6b694261
@ -1223,7 +1223,7 @@ Vec3d extract_euler_angles(const Eigen::Matrix<double, 3, 3, Eigen::DontAlign>&
|
||||
// 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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user