NEW: add TransformationSVD and some apis in Geometry
Jira:STUDIO-4227 add TransformationSVD and some apis in Geometry for cut tool these code from PrusaSlice,thanks for enricoturri1966 the original commit message: commit 22ccb5657834e1b2fe548dc647a77044bc9c38f4 Author: enricoturri1966 <enricoturri@seznam.cz> Date: Thu Feb 2 09:07:03 2023 +0100 Added class TransformationSVD to detect transformation matrix components using singular value decomposition ... Change-Id: I4ce736449029d1fec22def20ef50fa20e1f48713 (cherry picked from commit da9e8127f5214f095da2db9a7898d2e0e84a0214)
This commit is contained in:
parent
487c86e915
commit
bf23f6f023
|
@ -423,6 +423,26 @@ Transform3d rotation_transform(const Vec3d& rotation)
|
||||||
return transform;
|
return transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void scale_transform(Transform3d &transform, double scale) {
|
||||||
|
return scale_transform(transform, scale * Vec3d::Ones());
|
||||||
|
}
|
||||||
|
|
||||||
|
void scale_transform(Transform3d &transform, const Vec3d &scale)
|
||||||
|
{
|
||||||
|
transform = Transform3d::Identity();
|
||||||
|
transform.scale(scale);
|
||||||
|
}
|
||||||
|
Transform3d scale_transform(double scale) {
|
||||||
|
return scale_transform(scale * Vec3d::Ones());
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform3d scale_transform(const Vec3d &scale)
|
||||||
|
{
|
||||||
|
Transform3d transform;
|
||||||
|
scale_transform(transform, scale);
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
|
||||||
Transformation::Flags::Flags()
|
Transformation::Flags::Flags()
|
||||||
: dont_translate(true)
|
: dont_translate(true)
|
||||||
, dont_rotate(true)
|
, dont_rotate(true)
|
||||||
|
@ -454,7 +474,11 @@ Transformation::Transformation(const Transform3d& transform)
|
||||||
set_from_transform(transform);
|
set_from_transform(transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transformation::set_offset(const Vec3d& offset)
|
Transform3d Transformation::get_offset_matrix() const {
|
||||||
|
return translation_transform(get_offset());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transformation::set_offset(const Vec3d &offset)
|
||||||
{
|
{
|
||||||
set_offset(X, offset(0));
|
set_offset(X, offset(0));
|
||||||
set_offset(Y, offset(1));
|
set_offset(Y, offset(1));
|
||||||
|
@ -470,7 +494,27 @@ void Transformation::set_offset(Axis axis, double offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transformation::set_rotation(const Vec3d& rotation)
|
static Transform3d extract_rotation_matrix(const Transform3d &trafo)
|
||||||
|
{
|
||||||
|
Matrix3d rotation;
|
||||||
|
Matrix3d scale;
|
||||||
|
trafo.computeRotationScaling(&rotation, &scale);
|
||||||
|
return Transform3d(rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Transform3d extract_scale(const Transform3d &trafo)
|
||||||
|
{
|
||||||
|
Matrix3d rotation;
|
||||||
|
Matrix3d scale;
|
||||||
|
trafo.computeRotationScaling(&rotation, &scale);
|
||||||
|
return Transform3d(scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform3d Transformation::get_rotation_matrix() const {
|
||||||
|
return extract_rotation_matrix(m_matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transformation::set_rotation(const Vec3d &rotation)
|
||||||
{
|
{
|
||||||
set_rotation(X, rotation(0));
|
set_rotation(X, rotation(0));
|
||||||
set_rotation(Y, rotation(1));
|
set_rotation(Y, rotation(1));
|
||||||
|
@ -577,6 +621,25 @@ void Transformation::reset()
|
||||||
m_dirty = false;
|
m_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Transformation::reset_rotation() {
|
||||||
|
const Geometry::TransformationSVD svd(*this);
|
||||||
|
m_matrix = get_offset_matrix() * Transform3d(svd.v * svd.s * svd.v.transpose()) * svd.mirror_matrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transformation::reset_scaling_factor() {
|
||||||
|
const Geometry::TransformationSVD svd(*this);
|
||||||
|
m_matrix = get_offset_matrix() * Transform3d(svd.u) * Transform3d(svd.v.transpose()) * svd.mirror_matrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transformation::reset_skew() {
|
||||||
|
auto new_scale_factor = [](const Matrix3d &s) {
|
||||||
|
return pow(s(0, 0) * s(1, 1) * s(2, 2), 1. / 3.); // scale average
|
||||||
|
};
|
||||||
|
|
||||||
|
const Geometry::TransformationSVD svd(*this);
|
||||||
|
m_matrix = get_offset_matrix() * Transform3d(svd.u) * scale_transform(new_scale_factor(svd.s)) * Transform3d(svd.v.transpose()) * svd.mirror_matrix();
|
||||||
|
}
|
||||||
|
|
||||||
const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const
|
const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const
|
||||||
{
|
{
|
||||||
if (m_dirty || m_flags.needs_update(dont_translate, dont_rotate, dont_scale, dont_mirror))
|
if (m_dirty || m_flags.needs_update(dont_translate, dont_rotate, dont_scale, dont_mirror))
|
||||||
|
@ -595,6 +658,20 @@ const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rot
|
||||||
return m_matrix;
|
return m_matrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transform3d Transformation::get_matrix_no_offset() const
|
||||||
|
{
|
||||||
|
Transformation copy(*this);
|
||||||
|
copy.reset_offset();
|
||||||
|
return copy.get_matrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform3d Transformation::get_matrix_no_scaling_factor() const
|
||||||
|
{
|
||||||
|
Transformation copy(*this);
|
||||||
|
copy.reset_scaling_factor();
|
||||||
|
return copy.get_matrix();
|
||||||
|
}
|
||||||
|
|
||||||
Transformation Transformation::operator * (const Transformation& other) const
|
Transformation Transformation::operator * (const Transformation& other) const
|
||||||
{
|
{
|
||||||
return Transformation(get_matrix() * other.get_matrix());
|
return Transformation(get_matrix() * other.get_matrix());
|
||||||
|
@ -709,4 +786,48 @@ double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
|
||||||
return (axis.z() < 0) ? -angle : angle;
|
return (axis.z() < 0) ? -angle : angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
}} // namespace Slic3r::Geometry
|
Geometry::TransformationSVD::TransformationSVD(const Transform3d &trafo)
|
||||||
|
{
|
||||||
|
const auto &m0 = trafo.matrix().block<3, 3>(0, 0);
|
||||||
|
mirror = m0.determinant() < 0.0;
|
||||||
|
|
||||||
|
Matrix3d m;
|
||||||
|
if (mirror)
|
||||||
|
m = m0 * Eigen::DiagonalMatrix<double, 3, 3>(-1.0, 1.0, 1.0);
|
||||||
|
else
|
||||||
|
m = m0;
|
||||||
|
const Eigen::JacobiSVD<Matrix3d> svd(m, Eigen::ComputeFullU | Eigen::ComputeFullV);
|
||||||
|
u = svd.matrixU();
|
||||||
|
v = svd.matrixV();
|
||||||
|
s = svd.singularValues().asDiagonal();
|
||||||
|
|
||||||
|
scale = !s.isApprox(Matrix3d::Identity());
|
||||||
|
anisotropic_scale = !is_approx(s(0, 0), s(1, 1)) || !is_approx(s(1, 1), s(2, 2));
|
||||||
|
rotation = !v.isApprox(u);
|
||||||
|
|
||||||
|
if (anisotropic_scale) {
|
||||||
|
rotation_90_degrees = true;
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
const Vec3d row = v.row(i).cwiseAbs();
|
||||||
|
const size_t num_zeros = is_approx(row[0], 0.) + is_approx(row[1], 0.) + is_approx(row[2], 0.);
|
||||||
|
const size_t num_ones = is_approx(row[0], 1.) + is_approx(row[1], 1.) + is_approx(row[2], 1.);
|
||||||
|
if (num_zeros != 2 || num_ones != 1) {
|
||||||
|
rotation_90_degrees = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Detect skew by brute force: check if the axes are still orthogonal after transformation
|
||||||
|
const Matrix3d trafo_linear = trafo.linear();
|
||||||
|
const std::array<Vec3d, 3> axes = {Vec3d::UnitX(), Vec3d::UnitY(), Vec3d::UnitZ()};
|
||||||
|
std::array<Vec3d, 3> transformed_axes;
|
||||||
|
for (int i = 0; i < 3; ++i) { transformed_axes[i] = trafo_linear * axes[i]; }
|
||||||
|
skew = std::abs(transformed_axes[0].dot(transformed_axes[1])) > EPSILON || std::abs(transformed_axes[1].dot(transformed_axes[2])) > EPSILON ||
|
||||||
|
std::abs(transformed_axes[2].dot(transformed_axes[0])) > EPSILON;
|
||||||
|
|
||||||
|
// This following old code does not work under all conditions. The v matrix can become non diagonal (see SPE-1492)
|
||||||
|
// skew = ! rotation_90_degrees;
|
||||||
|
} else
|
||||||
|
skew = false;
|
||||||
|
}
|
||||||
|
} // namespace Geometry
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
|
@ -356,6 +356,12 @@ Transform3d translation_transform(const Vec3d &translation);
|
||||||
// 2) rotate Y
|
// 2) rotate Y
|
||||||
// 3) rotate Z
|
// 3) rotate Z
|
||||||
Transform3d rotation_transform(const Vec3d &rotation);
|
Transform3d rotation_transform(const Vec3d &rotation);
|
||||||
|
// Sets the given transform by assembling the given scale factors
|
||||||
|
void scale_transform(Transform3d &transform, double scale);
|
||||||
|
void scale_transform(Transform3d &transform, const Vec3d &scale);
|
||||||
|
// Returns the transform obtained by assembling the given scale factors
|
||||||
|
Transform3d scale_transform(double scale);
|
||||||
|
Transform3d scale_transform(const Vec3d &scale);
|
||||||
|
|
||||||
class Transformation
|
class Transformation
|
||||||
{
|
{
|
||||||
|
@ -390,13 +396,13 @@ public:
|
||||||
|
|
||||||
const Vec3d& get_offset() const { return m_offset; }
|
const Vec3d& get_offset() const { return m_offset; }
|
||||||
double get_offset(Axis axis) const { return m_offset(axis); }
|
double get_offset(Axis axis) const { return m_offset(axis); }
|
||||||
|
Transform3d get_offset_matrix() const;
|
||||||
void set_offset(const Vec3d& offset);
|
void set_offset(const Vec3d& offset);
|
||||||
void set_offset(Axis axis, double offset);
|
void set_offset(Axis axis, double offset);
|
||||||
|
|
||||||
const Vec3d& get_rotation() const { return m_rotation; }
|
const Vec3d& get_rotation() const { return m_rotation; }
|
||||||
double get_rotation(Axis axis) const { return m_rotation(axis); }
|
double get_rotation(Axis axis) const { return m_rotation(axis); }
|
||||||
|
Transform3d get_rotation_matrix() const;
|
||||||
void set_rotation(const Vec3d& rotation);
|
void set_rotation(const Vec3d& rotation);
|
||||||
void set_rotation(Axis axis, double rotation);
|
void set_rotation(Axis axis, double rotation);
|
||||||
|
|
||||||
|
@ -417,8 +423,15 @@ public:
|
||||||
void set_from_transform(const Transform3d& transform);
|
void set_from_transform(const Transform3d& transform);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
void reset_offset() { set_offset(Vec3d::Zero()); }
|
||||||
|
void reset_rotation();
|
||||||
|
void reset_scaling_factor();
|
||||||
|
void reset_mirror() { set_mirror(Vec3d::Ones()); }
|
||||||
|
void reset_skew();
|
||||||
|
|
||||||
const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const;
|
const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const;
|
||||||
|
Transform3d get_matrix_no_offset() const;
|
||||||
|
Transform3d get_matrix_no_scaling_factor() const;
|
||||||
|
|
||||||
Transformation operator * (const Transformation& other) const;
|
Transformation operator * (const Transformation& other) const;
|
||||||
|
|
||||||
|
@ -444,6 +457,25 @@ private:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TransformationSVD
|
||||||
|
{
|
||||||
|
Matrix3d u{Matrix3d::Identity()};
|
||||||
|
Matrix3d s{Matrix3d::Identity()};
|
||||||
|
Matrix3d v{Matrix3d::Identity()};
|
||||||
|
|
||||||
|
bool mirror{false};
|
||||||
|
bool scale{false};
|
||||||
|
bool anisotropic_scale{false};
|
||||||
|
bool rotation{false};
|
||||||
|
bool rotation_90_degrees{false};
|
||||||
|
bool skew{false};
|
||||||
|
|
||||||
|
explicit TransformationSVD(const Transformation &trafo) : TransformationSVD(trafo.get_matrix()) {}
|
||||||
|
explicit TransformationSVD(const Transform3d &trafo);
|
||||||
|
|
||||||
|
Eigen::DiagonalMatrix<double, 3, 3> mirror_matrix() const { return Eigen::DiagonalMatrix<double, 3, 3>(this->mirror ? -1. : 1., 1., 1.); }
|
||||||
|
};
|
||||||
|
|
||||||
// For parsing a transformation matrix from 3MF / AMF.
|
// For parsing a transformation matrix from 3MF / AMF.
|
||||||
extern Transform3d transform3d_from_string(const std::string& transform_str);
|
extern Transform3d transform3d_from_string(const std::string& transform_str);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue