@@ -24,6 +24,9 @@ namespace Common {
2424 max
2525 };
2626
27+ template <typename T>
28+ struct Quaternion ;
29+
2730 // matrix stored in row-major
2831 template <typename T, uint8_t R, uint8_t C>
2932 requires ValidMatDims<R, C>
@@ -115,6 +118,10 @@ namespace Common {
115118 bool CanInverse () const ;
116119 Mat Inverse () const ;
117120 T Determinant () const ;
121+
122+ Vec<T, 3 > ExtractTranslation () const ;
123+ Vec<T, 3 > ExtractScale () const ;
124+ Quaternion<T> ExtractRotation () const ;
118125 };
119126
120127 template <typename T, uint8_t R, uint8_t C>
@@ -812,6 +819,82 @@ namespace Common {
812819 return result;
813820 }
814821
822+ template <typename T, uint8_t R, uint8_t C>
823+ Vec<T, 3 > Mat<T, R, C>::ExtractTranslation() const
824+ {
825+ static_assert ( R == 4 && C == 4 );
826+ Vec<T, 3 > ret = Vec<T, 3 >(this ->data [3 ], this ->data [7 ], this ->data [11 ]);
827+ return ret;
828+ }
829+
830+ template <typename T, uint8_t R, uint8_t C>
831+ Quaternion<T> Mat<T, R, C>::ExtractRotation() const
832+ {
833+ static_assert ( R == 4 && C == 4 );
834+ Quaternion<T> ret = Quaternion<T>(1 , 0 , 0 , 0 );
835+
836+ T sx = Vec<T, 3 >(this ->data [0 ], this ->data [4 ], this ->data [8 ]).Model ();
837+ T sy = Vec<T, 3 >(this ->data [1 ], this ->data [5 ], this ->data [9 ]).Model ();
838+ T sz = Vec<T, 3 >(this ->data [2 ], this ->data [6 ], this ->data [10 ]).Model ();
839+ T det = this ->Determinant ();
840+ if (det < 0 ) {
841+ sx = -sx;
842+ }
843+
844+ T m11 = this ->data [0 ] / sx, m21 = this ->data [4 ] / sx, m31 = this ->data [8 ] / sx;
845+ T m12 = this ->data [1 ] / sy, m22 = this ->data [5 ] / sy, m32 = this ->data [9 ] / sy;
846+ T m13 = this ->data [2 ] / sz, m23 = this ->data [6 ] / sz, m33 = this ->data [10 ] / sz;
847+
848+ // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
849+ // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
850+ T trace = m11 + m22 + m33;
851+ if (trace > 0 ) {
852+ T s = 0.5 / std::sqrt (trace + 1.0 );
853+ ret.w = 0.25 / s;
854+ ret.x = (m32 - m23) * s;
855+ ret.y = (m13 - m31) * s;
856+ ret.z = (m21 - m12) * s;
857+ } else if (m11 > m22 && m11 > m33) {
858+ T s = 2.0 * std::sqrt (1.0 + m11 - m22 - m33);
859+ ret.w = ( m32 - m23 ) / s;
860+ ret.x = 0.25 * s;
861+ ret.y = ( m12 + m21 ) / s;
862+ ret.z = ( m13 + m31 ) / s;
863+ } else if (m22 > m33) {
864+ T s = 2.0 * std::sqrt ( 1.0 + m22 - m11 - m33 );
865+ ret.w = ( m13 - m31 ) / s;
866+ ret.x = ( m12 + m21 ) / s;
867+ ret.y = 0.25 * s;
868+ ret.z = ( m23 + m32 ) / s;
869+ } else {
870+ T s = 2.0 * std::sqrt ( 1.0 + m33 - m11 - m22 );
871+ ret.w = ( m21 - m12 ) / s;
872+ ret.x = ( m13 + m31 ) / s;
873+ ret.y = ( m23 + m32 ) / s;
874+ ret.z = 0.25 * s;
875+ }
876+
877+ return ret;
878+ }
879+
880+ template <typename T, uint8_t R, uint8_t C>
881+ Vec<T, 3 > Mat<T, R, C>::ExtractScale() const
882+ {
883+ static_assert ( R == 4 && C == 4 );
884+
885+ T sx = Vec<T, 3 >(this ->data [0 ], this ->data [4 ], this ->data [8 ]).Model ();
886+ T sy = Vec<T, 3 >(this ->data [1 ], this ->data [5 ], this ->data [9 ]).Model ();
887+ T sz = Vec<T, 3 >(this ->data [2 ], this ->data [6 ], this ->data [10 ]).Model ();
888+
889+ T det = this ->Determinant ();
890+ if (det < 0 ) {
891+ sx = -sx;
892+ }
893+ Vec<T, 3 > ret = Vec<T, 3 >(sx, sy, sz);
894+
895+ return ret;
896+ }
897+
815898 template <typename T, uint8_t R, uint8_t C>
816899 template <uint8_t DR, uint8_t DC>
817900 requires ValidSubMatDims<DR, DC, R, C>
0 commit comments