Added helper functions to extract euler angles from 3d transforms

This commit is contained in:
Enrico Turri 2018-10-12 12:19:57 +02:00
parent d843f1a76f
commit 9bb93cc4f4
4 changed files with 61 additions and 46 deletions

View file

@ -2,6 +2,7 @@
#include "../Model.hpp"
#include "../Utils.hpp"
#include "../GCode.hpp"
#include "../Geometry.hpp"
#include "3mf.hpp"
@ -1253,7 +1254,7 @@ namespace Slic3r {
// translation
#if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
Vec3d offset(transform(0, 3), transform(1, 3), transform(2, 3));
Vec3d offset = transform.matrix().block(0, 3, 3, 1);
#else
double offset_x = transform(0, 3);
double offset_y = transform(1, 3);
@ -1261,50 +1262,41 @@ namespace Slic3r {
#endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
// scale
double sx = ::sqrt(sqr(transform(0, 0)) + sqr(transform(1, 0)) + sqr(transform(2, 0)));
double sy = ::sqrt(sqr(transform(0, 1)) + sqr(transform(1, 1)) + sqr(transform(2, 1)));
double sz = ::sqrt(sqr(transform(0, 2)) + sqr(transform(1, 2)) + sqr(transform(2, 2)));
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> m3x3 = transform.matrix().block(0, 0, 3, 3);
Vec3d scale(m3x3.col(0).norm(), m3x3.col(1).norm(), m3x3.col(2).norm());
// invalid scale value, return
if ((sx == 0.0) || (sy == 0.0) || (sz == 0.0))
if ((scale(0) == 0.0) || (scale(1) == 0.0) || (scale(2) == 0.0))
return;
#if !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
// non-uniform scale value, return
if ((std::abs(sx - sy) > 0.00001) || (std::abs(sx - sz) > 0.00001))
if ((std::abs(scale(0) - scale(1)) > 0.00001) || (std::abs(scale(0) - scale(2)) > 0.00001))
return;
#endif // !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
double inv_sx = 1.0 / sx;
double inv_sy = 1.0 / sy;
double inv_sz = 1.0 / sz;
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> m3x3;
m3x3 << transform(0, 0) * inv_sx, transform(0, 1) * inv_sy, transform(0, 2) * inv_sz,
transform(1, 0) * inv_sx, transform(1, 1) * inv_sy, transform(1, 2) * inv_sz,
transform(2, 0) * inv_sx, transform(2, 1) * inv_sy, transform(2, 2) * inv_sz;
// remove scale
m3x3.col(0).normalize();
m3x3.col(1).normalize();
m3x3.col(2).normalize();
#if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
Vec3d angles = m3x3.eulerAngles(2, 1, 0);
Vec3d rotation(angles(2), angles(1), angles(0));
Vec3d rotation = Slic3r::Geometry::extract_euler_angles(m3x3);
instance.set_offset(offset);
instance.set_scaling_factor(Vec3d(sx, sy, sz));
instance.set_scaling_factor(scale);
instance.set_rotation(rotation);
#else
Eigen::AngleAxisd rotation;
rotation.fromRotationMatrix(m3x3);
Vec3d rotation = Slic3r::Geometry::extract_euler_angles(m3x3);
// invalid rotation axis, we currently handle only rotations around Z axis
if ((rotation.angle() != 0.0) && (rotation.axis() != Vec3d::UnitZ()) && (rotation.axis() != -Vec3d::UnitZ()))
// invalid rotation, we currently handle only rotations around Z axis
if ((rotation(0) != 0.0) || (rotation(1) != 0.0))
return;
double angle_z = (rotation.axis() == Vec3d::UnitZ()) ? rotation.angle() : -rotation.angle();
instance.offset(0) = offset_x;
instance.offset(1) = offset_y;
instance.scaling_factor = sx;
instance.rotation = angle_z;
instance.scaling_factor = scale(0);
instance.rotation = rotation(2);
#endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
}

View file

@ -1183,4 +1183,38 @@ Transform3d assemble_transform(const Vec3d& translation, const Vec3d& rotation,
return transform;
}
Vec3d extract_euler_angles(const Eigen::Matrix<double, 3, 3, Eigen::DontAlign>& rotation_matrix)
{
// see: https://www.learnopencv.com/rotation-matrix-to-euler-angles/
double sy = ::sqrt(sqr(rotation_matrix(0, 0)) + sqr(rotation_matrix(1, 0)));
Vec3d angles = Vec3d::Zero();
if (sy >= 1e-6)
{
angles(0) = ::atan2(rotation_matrix(2, 1), rotation_matrix(2, 2));
angles(1) = ::atan2(-rotation_matrix(2, 0), sy);
angles(2) = ::atan2(rotation_matrix(1, 0), rotation_matrix(0, 0));
}
else
{
angles(0) = ::atan2(-rotation_matrix(1, 2), rotation_matrix(1, 1));
angles(1) = ::atan2(-rotation_matrix(2, 0), sy);
angles(2) = 0.0;
}
return angles;
}
Vec3d extract_euler_angles(const Transform3d& transform)
{
// use only the non-translational part of the transform
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> m = transform.matrix().block(0, 0, 3, 3);
// remove scale
m.col(0).normalize();
m.col(1).normalize();
m.col(2).normalize();
return extract_euler_angles(m);
}
} }

View file

@ -172,6 +172,14 @@ void assemble_transform(Transform3d& transform, const Vec3d& translation = Vec3d
// 4) rotate Z
// 5) translate
Transform3d assemble_transform(const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(), const Vec3d& scale = Vec3d::Ones());
// Returns the euler angles extracted from the given rotation matrix
// Warning -> The matrix should not contain any scale or shear !!!
Vec3d extract_euler_angles(const Eigen::Matrix<double, 3, 3, Eigen::DontAlign>& rotation_matrix);
// Returns the euler angles extracted from the given affine transform
// Warning -> The transform should not contain any shear !!!
Vec3d extract_euler_angles(const Transform3d& transform);
} }
#endif

View file

@ -1413,33 +1413,14 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation)
for (unsigned int i : m_list)
{
Vec3d radius = m * (m_cache.volumes_data[i].get_position() - m_cache.dragging_center);
(*m_volumes)[i]->set_offset(m_cache.dragging_center + radius);
if (single_full_instance)
(*m_volumes)[i]->set_rotation(rotation);
else
{
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> new_rotation_matrix = (m * m_cache.volumes_data[i].get_rotation_matrix()).matrix().block(0, 0, 3, 3);
// extracts euler angles from the composed transformation
// not using Eigen eulerAngles() method because it returns weird results
// see: https://www.learnopencv.com/rotation-matrix-to-euler-angles/
double sy = ::sqrt(sqr(new_rotation_matrix(0, 0)) + sqr(new_rotation_matrix(1, 0)));
Vec3d angles = Vec3d::Zero();
if (sy >= 1e-6)
{
angles(0) = ::atan2(new_rotation_matrix(2, 1), new_rotation_matrix(2, 2));
angles(1) = ::atan2(-new_rotation_matrix(2, 0), sy);
angles(2) = ::atan2(new_rotation_matrix(1, 0), new_rotation_matrix(0, 0));
}
else
{
angles(0) = ::atan2(-new_rotation_matrix(1, 2), new_rotation_matrix(1, 1));
angles(1) = ::atan2(-new_rotation_matrix(2, 0), sy);
angles(2) = 0.0;
}
Vec3d angles = Geometry::extract_euler_angles(new_rotation_matrix);
(*m_volumes)[i]->set_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_position() - m_cache.dragging_center));
(*m_volumes)[i]->set_rotation(Vec3d(angles(0), angles(1), angles(2)));
}
}