mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-13 02:41:16 +00:00
Fix scale and mirror of rotated mirrored objects (#16131)
* Fix decomposition of mirrored transformations computeRotationScaling() may place the mirror on any axis, giving unstable rotation/scale for mirrored matrices. Decompose them by flipping each local axis and choosing the one needing the least rotation (lowest axis on ties). Merge the extract helpers into a single extract_rotation_scale() and simplify contains_skew() to check that the scale is diagonal. set_scaling_factor() now preserves the mirror sign on the scaled axis. Selection::scale_and_translate() uses Transformation's rotation and scale instead of calling computeRotationScaling() directly, so scaling a mirrored instance adds no skew. Add tests for mirrored decomposition, scaling, and skew detection. * Use Eigen polar decomposition for instance scaling Selection::scale_and_translate now splits the instance matrix with computeRotationScaling instead of get_rotation_matrix(). Adds a Model test checking that an instance created from another's offset, scale, rotation and mirror reproduces its matrix (as Add instance and Fill bed do). * tidy
This commit is contained in:
+31
-41
@@ -428,55 +428,44 @@ Transform3d Transformation::get_offset_matrix() const
|
||||
return translation_transform(get_offset());
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// computeRotationScaling() may put a mirror on any axis; use the local axis needing the least rotation.
|
||||
static std::pair<Transform3d, Transform3d> extract_rotation_scale(const Transform3d& trafo)
|
||||
{
|
||||
Matrix3d rotation;
|
||||
Matrix3d scale;
|
||||
trafo.computeRotationScaling(&rotation, &scale);
|
||||
if (trafo.linear().determinant() >= 0.0) {
|
||||
trafo.computeRotationScaling(&rotation, &scale);
|
||||
return { Transform3d(rotation), Transform3d(scale) };
|
||||
}
|
||||
for (int axis = 0; axis < 3; ++axis) {
|
||||
Transform3d flipped = trafo;
|
||||
flipped.linear().col(axis) *= -1.0;
|
||||
Matrix3d r;
|
||||
Matrix3d s;
|
||||
flipped.computeRotationScaling(&r, &s);
|
||||
// EPSILON keeps the lowest axis on ties, e.g. a mirror rotated by 90 degrees.
|
||||
if (axis == 0 || r.trace() > rotation.trace() + EPSILON) {
|
||||
rotation = r;
|
||||
scale = s;
|
||||
scale.col(axis) *= -1.0;
|
||||
}
|
||||
}
|
||||
return { Transform3d(rotation), Transform3d(scale) };
|
||||
}
|
||||
|
||||
static Transform3d extract_rotation_matrix(const Transform3d& trafo)
|
||||
{
|
||||
return extract_rotation_scale(trafo).first;
|
||||
}
|
||||
|
||||
static Transform3d extract_scale(const Transform3d& trafo)
|
||||
{
|
||||
return extract_rotation_scale(trafo).second;
|
||||
}
|
||||
|
||||
static bool contains_skew(const Transform3d& trafo)
|
||||
{
|
||||
Matrix3d rotation;
|
||||
Matrix3d scale;
|
||||
trafo.computeRotationScaling(&rotation, &scale);
|
||||
|
||||
if (scale.isDiagonal())
|
||||
return false;
|
||||
|
||||
if (scale.determinant() >= 0.0)
|
||||
return true;
|
||||
|
||||
// the matrix contains mirror
|
||||
const Matrix3d ratio = scale.cwiseQuotient(trafo.matrix().block<3,3>(0,0));
|
||||
|
||||
auto check_skew = [&ratio](int i, int j, bool& skew) {
|
||||
if (!std::isnan(ratio(i, j)) && !std::isnan(ratio(j, i)))
|
||||
skew |= std::abs(ratio(i, j) * ratio(j, i) - 1.0) > EPSILON;
|
||||
};
|
||||
|
||||
bool has_skew = false;
|
||||
check_skew(0, 1, has_skew);
|
||||
check_skew(0, 2, has_skew);
|
||||
check_skew(1, 2, has_skew);
|
||||
return has_skew;
|
||||
return !extract_scale(trafo).linear().isDiagonal();
|
||||
}
|
||||
|
||||
Vec3d Transformation::get_rotation() const
|
||||
@@ -550,7 +539,8 @@ void Transformation::set_scaling_factor(Axis axis, double scaling_factor)
|
||||
assert(scaling_factor > 0.0);
|
||||
|
||||
auto [rotation, scale] = extract_rotation_scale(m_matrix);
|
||||
scale(axis, axis) = scaling_factor;
|
||||
// Keep a mirror that sits on this axis.
|
||||
scale(axis, axis) = std::copysign(scaling_factor, scale(axis, axis));
|
||||
|
||||
const Vec3d offset = get_offset();
|
||||
m_matrix = rotation * scale;
|
||||
|
||||
Reference in New Issue
Block a user