BLI: Add 2D transformation matrix decomposition

This patch adds support for 2D transformation matrix decomposition into
translation, rotation, and scale.

Pull Request: https://projects.blender.org/blender/blender/pulls/111178
This commit is contained in:
Omar Emara 2023-08-16 14:47:14 +02:00 committed by Omar Emara
parent 1594f7fb95
commit 85a3f61150
2 changed files with 69 additions and 0 deletions

View File

@ -257,6 +257,7 @@ template<typename MatT, typename VectorT>
* Extract euler rotation from transform matrix.
* \return the rotation with the smallest values from the potential candidates.
*/
template<typename T> [[nodiscard]] inline AngleRadianBase<T> to_angle(const MatBase<T, 2, 2> &mat);
template<typename T> [[nodiscard]] inline EulerXYZBase<T> to_euler(const MatBase<T, 3, 3> &mat);
template<typename T> [[nodiscard]] inline EulerXYZBase<T> to_euler(const MatBase<T, 4, 4> &mat);
template<typename T>
@ -316,6 +317,15 @@ template<bool AllowNegativeScale = false, typename T>
* Rotation and scale values will be flipped if it is negative.
* This is a costly operation so it is disabled by default.
*/
template<bool AllowNegativeScale = false, typename T>
inline void to_rot_scale(const MatBase<T, 2, 2> &mat,
AngleRadianBase<T> &r_rotation,
VecBase<T, 2> &r_scale);
template<bool AllowNegativeScale = false, typename T>
inline void to_loc_rot_scale(const MatBase<T, 3, 3> &mat,
VecBase<T, 2> &r_location,
AngleRadianBase<T> &r_rotation,
VecBase<T, 2> &r_scale);
template<bool AllowNegativeScale = false, typename T, typename RotationT>
inline void to_rot_scale(const MatBase<T, 3, 3> &mat,
RotationT &r_rotation,
@ -705,6 +715,12 @@ template<typename T, int NumCol, int NumRow, typename VectorT>
namespace detail {
template<typename T> AngleRadianBase<T> normalized_to_angle(const MatBase<T, 2, 2> &mat)
{
BLI_assert(math::is_unit_scale(mat));
return AngleRadianBase(mat[0][0], mat[0][1]);
}
template<typename T>
void normalized_to_eul2(const MatBase<T, 3, 3> &mat, EulerXYZBase<T> &eul1, EulerXYZBase<T> &eul2)
{
@ -1070,6 +1086,11 @@ extern template MatBase<float, 4, 4> from_rotation(const AxisAngleCartesian &rot
} // namespace detail
template<typename T> [[nodiscard]] inline AngleRadianBase<T> to_angle(const MatBase<T, 2, 2> &mat)
{
return detail::normalized_to_angle(mat);
}
template<typename T>
[[nodiscard]] inline Euler3Base<T> to_euler(const MatBase<T, 3, 3> &mat, EulerOrder order)
{
@ -1188,6 +1209,12 @@ template<bool AllowNegativeScale, typename T>
/* Implementation details. Use `to_euler` and `to_quaternion` instead. */
namespace detail {
template<typename T>
inline void to_rotation(const MatBase<T, 2, 2> &mat, AngleRadianBase<T> &r_rotation)
{
r_rotation = to_angle<T>(mat);
}
template<typename T>
inline void to_rotation(const MatBase<T, 3, 3> &mat, QuaternionBase<T> &r_rotation)
{
@ -1208,6 +1235,31 @@ inline void to_rotation(const MatBase<T, 3, 3> &mat, Euler3Base<T> &r_rotation)
} // namespace detail
template<bool AllowNegativeScale, typename T>
inline void to_rot_scale(const MatBase<T, 2, 2> &mat,
AngleRadianBase<T> &r_rotation,
VecBase<T, 2> &r_scale)
{
MatBase<T, 2, 2> normalized_mat = normalize_and_get_size(mat, r_scale);
if constexpr (AllowNegativeScale) {
if (UNLIKELY(is_negative(normalized_mat))) {
normalized_mat = -normalized_mat;
r_scale = -r_scale;
}
}
detail::to_rotation<T>(normalized_mat, r_rotation);
}
template<bool AllowNegativeScale, typename T>
inline void to_loc_rot_scale(const MatBase<T, 3, 3> &mat,
VecBase<T, 2> &r_location,
AngleRadianBase<T> &r_rotation,
VecBase<T, 2> &r_scale)
{
r_location = mat.location();
to_rot_scale<AllowNegativeScale>(MatBase<T, 2, 2>(mat), r_rotation, r_scale);
}
template<bool AllowNegativeScale, typename T, typename RotationT>
inline void to_rot_scale(const MatBase<T, 3, 3> &mat,
RotationT &r_rotation,

View File

@ -411,6 +411,23 @@ TEST(math_matrix, MatrixMethods)
EXPECT_V3_NEAR(float3(eul), float3(expect_eul), 0.0002f);
}
TEST(math_matrix, Transformation2DMatrixDecomposition)
{
const float2 translation = float2(1.0f, 2.0f);
const AngleRadian rotation = AngleRadian(0.5f);
const float2 scale = float2(5.0f, 3.0f);
const float3x3 transformation = from_loc_rot_scale<float3x3>(translation, rotation, scale);
AngleRadian decomposed_rotation;
float2 decomposed_translation, decomposed_scale;
to_loc_rot_scale(transformation, decomposed_translation, decomposed_rotation, decomposed_scale);
EXPECT_V2_NEAR(decomposed_translation, translation, 0.00001f);
EXPECT_V2_NEAR(decomposed_scale, scale, 0.00001f);
EXPECT_NEAR(decomposed_rotation.radian(), rotation.radian(), 0.00001f);
}
TEST(math_matrix, MatrixToQuaternionLegacy)
{
float3x3 mat = {{0.808309, -0.578051, -0.111775},