Coverage Report

Created: 2025-12-25 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/OgreMain/include/OgreMatrix3.h
Line
Count
Source
1
/*
2
-----------------------------------------------------------------------------
3
This source file is part of OGRE
4
    (Object-oriented Graphics Rendering Engine)
5
For the latest info, see http://www.ogre3d.org/
6
7
Copyright (c) 2000-2014 Torus Knot Software Ltd
8
9
Permission is hereby granted, free of charge, to any person obtaining a copy
10
of this software and associated documentation files (the "Software"), to deal
11
in the Software without restriction, including without limitation the rights
12
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
copies of the Software, and to permit persons to whom the Software is
14
furnished to do so, subject to the following conditions:
15
16
The above copyright notice and this permission notice shall be included in
17
all copies or substantial portions of the Software.
18
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
THE SOFTWARE.
26
-----------------------------------------------------------------------------
27
*/
28
#ifndef __Matrix3_H__
29
#define __Matrix3_H__
30
31
#include "OgrePrerequisites.h"
32
33
#include "OgreVector.h"
34
35
// NB All code adapted from Wild Magic 0.2 Matrix math (free source code)
36
// http://www.geometrictools.com/
37
38
// NOTE.  The (x,y,z) coordinate system is assumed to be right-handed.
39
// Coordinate axis rotation matrices are of the form
40
//   RX =    1       0       0
41
//           0     cos(t) -sin(t)
42
//           0     sin(t)  cos(t)
43
// where t > 0 indicates a counterclockwise rotation in the yz-plane
44
//   RY =  cos(t)    0     sin(t)
45
//           0       1       0
46
//        -sin(t)    0     cos(t)
47
// where t > 0 indicates a counterclockwise rotation in the zx-plane
48
//   RZ =  cos(t) -sin(t)    0
49
//         sin(t)  cos(t)    0
50
//           0       0       1
51
// where t > 0 indicates a counterclockwise rotation in the xy-plane.
52
53
namespace Ogre
54
{
55
    /** \addtogroup Core
56
    *  @{
57
    */
58
    /** \addtogroup Math
59
    *  @{
60
    */
61
    /** A 3x3 matrix which can represent rotations around axes.
62
        @note
63
            <b>All the code is adapted from the Wild Magic 0.2 Matrix
64
            library (http://www.geometrictools.com/).</b>
65
        @par
66
            The coordinate system is assumed to be <b>right-handed</b>.
67
    */
68
    class _OgreExport Matrix3
69
    {
70
    public:
71
        /** Default constructor.
72
            @note
73
                It does <b>NOT</b> initialize the matrix for efficiency.
74
        */
75
0
        Matrix3 () {}
76
        explicit Matrix3 (const Real arr[3][3])
77
0
        {
78
0
            memcpy(m,arr,9*sizeof(Real));
79
0
        }
80
81
        Matrix3 (Real fEntry00, Real fEntry01, Real fEntry02,
82
                    Real fEntry10, Real fEntry11, Real fEntry12,
83
                    Real fEntry20, Real fEntry21, Real fEntry22)
84
0
        {
85
0
            m[0][0] = fEntry00;
86
0
            m[0][1] = fEntry01;
87
0
            m[0][2] = fEntry02;
88
0
            m[1][0] = fEntry10;
89
0
            m[1][1] = fEntry11;
90
0
            m[1][2] = fEntry12;
91
0
            m[2][0] = fEntry20;
92
0
            m[2][1] = fEntry21;
93
0
            m[2][2] = fEntry22;
94
0
        }
95
96
        /// Member access, allows use of construct mat[r][c]
97
        const Real* operator[] (size_t iRow) const
98
0
        {
99
0
            return m[iRow];
100
0
        }
101
102
        Real* operator[] (size_t iRow)
103
0
        {
104
0
            return m[iRow];
105
0
        }
106
107
        Vector3 GetColumn(size_t iCol) const
108
0
        {
109
0
            assert(iCol < 3);
110
0
            return Vector3(m[0][iCol], m[1][iCol], m[2][iCol]);
111
0
        }
112
        void SetColumn(size_t iCol, const Vector3& vec)
113
0
        {
114
0
            assert(iCol < 3);
115
0
            m[0][iCol] = vec.x;
116
0
            m[1][iCol] = vec.y;
117
0
            m[2][iCol] = vec.z;
118
0
        }
119
        void FromAxes(const Vector3& xAxis, const Vector3& yAxis, const Vector3& zAxis)
120
0
        {
121
0
            SetColumn(0, xAxis);
122
0
            SetColumn(1, yAxis);
123
0
            SetColumn(2, zAxis);
124
0
        }
125
126
        /** Tests 2 matrices for equality.
127
         */
128
        bool operator== (const Matrix3& rkMatrix) const;
129
130
        /** Tests 2 matrices for inequality.
131
         */
132
        bool operator!= (const Matrix3& rkMatrix) const
133
0
        {
134
0
            return !operator==(rkMatrix);
135
0
        }
136
137
        // arithmetic operations
138
        /** Matrix addition.
139
         */
140
        Matrix3 operator+ (const Matrix3& rkMatrix) const;
141
142
        /** Matrix subtraction.
143
         */
144
        Matrix3 operator- (const Matrix3& rkMatrix) const;
145
146
        /** Matrix concatenation using '*'.
147
         */
148
        Matrix3 operator* (const Matrix3& rkMatrix) const;
149
        Matrix3 operator- () const;
150
151
        /// Vector * matrix [1x3 * 3x3 = 1x3]
152
        _OgreExport friend Vector3 operator* (const Vector3& rkVector,
153
            const Matrix3& rkMatrix);
154
155
        /// Matrix * scalar
156
        Matrix3 operator* (Real fScalar) const;
157
158
        /// Scalar * matrix
159
        _OgreExport friend Matrix3 operator* (Real fScalar, const Matrix3& rkMatrix);
160
161
        // utilities
162
        Matrix3 Transpose () const;
163
        bool Inverse (Matrix3& rkInverse, Real fTolerance = 1e-06f) const;
164
        Matrix3 Inverse (Real fTolerance = 1e-06f) const;
165
0
        Real Determinant() const { return determinant(); }
166
167
0
        Matrix3 transpose() const { return Transpose(); }
168
0
        Matrix3 inverse() const { return Inverse(); }
169
        Real determinant() const
170
0
        {
171
0
            Real fCofactor00 = m[1][1] * m[2][2] - m[1][2] * m[2][1];
172
0
            Real fCofactor10 = m[1][2] * m[2][0] - m[1][0] * m[2][2];
173
0
            Real fCofactor20 = m[1][0] * m[2][1] - m[1][1] * m[2][0];
174
0
175
0
            return m[0][0] * fCofactor00 + m[0][1] * fCofactor10 + m[0][2] * fCofactor20;
176
0
        }
177
178
        /** Determines if this matrix involves a negative scaling. */
179
0
        bool hasNegativeScale() const { return determinant() < 0; }
180
181
        /// Singular value decomposition
182
        void SingularValueDecomposition (Matrix3& rkL, Vector3& rkS,
183
            Matrix3& rkR) const;
184
        void SingularValueComposition (const Matrix3& rkL,
185
            const Vector3& rkS, const Matrix3& rkR);
186
187
        /// Gram-Schmidt orthogonalisation (applied to columns of rotation matrix)
188
        Matrix3 orthonormalised() const
189
0
        {
190
0
            // Algorithm uses Gram-Schmidt orthogonalisation.  If 'this' matrix is
191
0
            // M = [m0|m1|m2], then orthonormal output matrix is Q = [q0|q1|q2],
192
0
            //
193
0
            //   q0 = m0/|m0|
194
0
            //   q1 = (m1-(q0*m1)q0)/|m1-(q0*m1)q0|
195
0
            //   q2 = (m2-(q0*m2)q0-(q1*m2)q1)/|m2-(q0*m2)q0-(q1*m2)q1|
196
0
            //
197
0
            // where |V| indicates length of vector V and A*B indicates dot
198
0
            // product of vectors A and B.
199
0
200
0
            Matrix3 Q;
201
0
            // compute q0
202
0
            Q.SetColumn(0, GetColumn(0) / GetColumn(0).length());
203
0
204
0
            // compute q1
205
0
            Real dot0 = Q.GetColumn(0).dotProduct(GetColumn(1));
206
0
            Q.SetColumn(1, (GetColumn(1) - dot0 * Q.GetColumn(0)).normalisedCopy());
207
0
208
0
            // compute q2
209
0
            Real dot1 = Q.GetColumn(1).dotProduct(GetColumn(2));
210
0
            dot0 = Q.GetColumn(0).dotProduct(GetColumn(2));
211
0
            Q.SetColumn(2, (GetColumn(2) - dot0 * Q.GetColumn(0) + dot1 * Q.GetColumn(1)).normalisedCopy());
212
0
213
0
            return Q;
214
0
        }
215
216
        /// @deprecated
217
0
        OGRE_DEPRECATED void Orthonormalize() { *this = orthonormalised(); }
218
219
        /// Orthogonal Q, diagonal D, upper triangular U stored as (u01,u02,u12)
220
        void QDUDecomposition (Matrix3& rkQ, Vector3& rkD,
221
            Vector3& rkU) const;
222
223
        Real SpectralNorm () const;
224
225
        /// Note: Matrix must be orthonormal
226
        void ToAngleAxis (Vector3& rkAxis, Radian& rfAngle) const;
227
0
        inline void ToAngleAxis (Vector3& rkAxis, Degree& rfAngle) const {
228
0
            Radian r;
229
0
            ToAngleAxis ( rkAxis, r );
230
0
            rfAngle = r;
231
0
        }
232
        void FromAngleAxis (const Vector3& rkAxis, const Radian& fRadians);
233
234
        /**
235
            @name Euler angle conversions
236
            (De-)composes the matrix in/ from yaw, pitch and roll angles,
237
            where yaw is rotation about the Y vector, pitch is rotation about the
238
            X axis, and roll is rotation about the Z axis.
239
240
            The function suffix indicates the (de-)composition order;
241
            e.g. with the YXZ variants the matrix will be (de-)composed as yaw*pitch*roll
242
243
            For ToEulerAngles*, the return value denotes whether the solution is unique.
244
            @note The matrix to be decomposed must be orthonormal.
245
            @{
246
        */
247
        bool ToEulerAnglesXYZ(Radian& xAngle, Radian& yAngle, Radian& zAngle) const;
248
        bool ToEulerAnglesXZY(Radian& xAngle, Radian& zAngle, Radian& yAngle) const;
249
        bool ToEulerAnglesYXZ(Radian& yAngle, Radian& xAngle, Radian& zAngle) const;
250
        bool ToEulerAnglesYZX(Radian& yAngle, Radian& zAngle, Radian& xAngle) const;
251
        bool ToEulerAnglesZXY(Radian& zAngle, Radian& xAngle, Radian& yAngle) const;
252
        bool ToEulerAnglesZYX(Radian& zAngle, Radian& yAngle, Radian& xAngle) const;
253
        void FromEulerAnglesXYZ(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle);
254
        void FromEulerAnglesXZY(const Radian& xAngle, const Radian& zAngle, const Radian& yAngle);
255
        void FromEulerAnglesYXZ(const Radian& yAngle, const Radian& xAngle, const Radian& zAngle);
256
        void FromEulerAnglesYZX(const Radian& yAngle, const Radian& zAngle, const Radian& xAngle);
257
        void FromEulerAnglesZXY(const Radian& zAngle, const Radian& xAngle, const Radian& yAngle);
258
        void FromEulerAnglesZYX(const Radian& zAngle, const Radian& yAngle, const Radian& xAngle);
259
        /// @}
260
        /// Eigensolver, matrix must be symmetric
261
        void EigenSolveSymmetric (Real afEigenvalue[3],
262
            Vector3 akEigenvector[3]) const;
263
264
        static void TensorProduct (const Vector3& rkU, const Vector3& rkV,
265
            Matrix3& rkProduct);
266
267
        /** Determines if this matrix involves a scaling. */
268
        bool hasScale() const
269
0
        {
270
0
            // check magnitude of column vectors (==local axes)
271
0
            Real t = m[0][0] * m[0][0] + m[1][0] * m[1][0] + m[2][0] * m[2][0];
272
0
            if (!Math::RealEqual(t, 1.0, (Real)1e-04))
273
0
                return true;
274
0
            t = m[0][1] * m[0][1] + m[1][1] * m[1][1] + m[2][1] * m[2][1];
275
0
            if (!Math::RealEqual(t, 1.0, (Real)1e-04))
276
0
                return true;
277
0
            t = m[0][2] * m[0][2] + m[1][2] * m[1][2] + m[2][2] * m[2][2];
278
0
            if (!Math::RealEqual(t, 1.0, (Real)1e-04))
279
0
                return true;
280
0
281
0
            return false;
282
0
        }
283
284
        /** Function for writing to a stream.
285
        */
286
        inline friend std::ostream& operator <<
287
            ( std::ostream& o, const Matrix3& mat )
288
0
        {
289
0
            o << "Matrix3(" << mat[0][0] << ", " << mat[0][1] << ", " << mat[0][2] << "; "
290
0
                            << mat[1][0] << ", " << mat[1][1] << ", " << mat[1][2] << "; "
291
0
                            << mat[2][0] << ", " << mat[2][1] << ", " << mat[2][2] << ")";
292
0
            return o;
293
0
        }
294
295
        static const Real EPSILON;
296
        static const Matrix3 ZERO;
297
        static const Matrix3 IDENTITY;
298
299
    private:
300
        // support for eigensolver
301
        void Tridiagonal (Real afDiag[3], Real afSubDiag[3]);
302
        bool QLAlgorithm (Real afDiag[3], Real afSubDiag[3]);
303
304
        // support for singular value decomposition
305
        static const unsigned int msSvdMaxIterations;
306
        static void Bidiagonalize (Matrix3& kA, Matrix3& kL,
307
            Matrix3& kR);
308
        static void GolubKahanStep (Matrix3& kA, Matrix3& kL,
309
            Matrix3& kR);
310
311
        // support for spectral norm
312
        static Real MaxCubicRoot (Real afCoeff[3]);
313
314
        Real m[3][3];
315
316
        // for faster access
317
        friend class Matrix4;
318
    };
319
320
    /// Matrix * vector [3x3 * 3x1 = 3x1]
321
    inline Vector3 operator*(const Matrix3& m, const Vector3& v)
322
0
    {
323
0
        return Vector3(
324
0
                m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z,
325
0
                m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z,
326
0
                m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z);
327
0
    }
328
329
    inline Matrix3 Math::lookRotation(const Vector3& direction, const Vector3& yaw)
330
0
    {
331
0
        Matrix3 ret;
332
0
        // cross twice to rederive, only direction is unaltered
333
0
        const Vector3& xAxis = yaw.crossProduct(direction).normalisedCopy();
334
0
        const Vector3& yAxis = direction.crossProduct(xAxis);
335
0
        ret.FromAxes(xAxis, yAxis, direction);
336
0
        return ret;
337
0
    }
338
    /** @} */
339
    /** @} */
340
}
341
#endif