/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 |