Fix issue in Rocket.lua script.
[Cafu-Engine.git] / Libs / Math3D / Matrix3x3.cpp
blob066df5fabe9ba1a92a011dd4fb771fda1ca9855e
1 /*
2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
5 */
7 #include "Matrix3x3.hpp"
8 #include "Angles.hpp"
9 #include "Quaternion.hpp"
12 using namespace cf::math;
15 // The static identity instance of this matrix type.
16 template<class T> const Matrix3x3T<T> Matrix3x3T<T>::Identity;
19 template<class T> Matrix3x3T<T>::Matrix3x3T(const AnglesT<T>& Angles)
21 const T RadH = AnglesT<T>::DegToRad(Angles.yaw());
22 const T SinH = sin(RadH);
23 const T CosH = cos(RadH);
25 const T RadP = AnglesT<T>::DegToRad(Angles.pitch());
26 const T SinP = sin(RadP);
27 const T CosP = cos(RadP);
29 const T RadB = AnglesT<T>::DegToRad(Angles.roll());
30 const T SinB = sin(RadB);
31 const T CosB = cos(RadB);
33 // Refer to http://de.wikipedia.org/wiki/Rotationsmatrix for the correct start matrices.
34 m[0][0] = CosP*CosH; m[0][1] = SinB*SinP*CosH - CosB*SinH; m[0][2] = CosB*SinP*CosH + SinB*SinH;
35 m[1][0] = CosP*SinH; m[1][1] = SinB*SinP*SinH + CosB*CosH; m[1][2] = CosB*SinP*SinH - SinB*CosH;
36 m[2][0] = -SinP; m[2][1] = SinB*CosP; m[2][2] = CosB*CosP;
38 // This is not a check for accuracy, but for principal correctness of the above computations.
39 assert(this->IsEqual(
40 GetRotateZMatrix(Angles.yaw()) *
41 GetRotateYMatrix(Angles.pitch()) *
42 GetRotateXMatrix(Angles.roll()),
43 0.001f));
47 template<class T> Matrix3x3T<T>::Matrix3x3T(const QuaternionT<T>& Quat)
49 // This is the same code as in the related MatrixT constructor.
50 const T x = Quat.x;
51 const T y = Quat.y;
52 const T z = Quat.z;
53 const T w = Quat.w;
55 m[0][0] = 1 - 2 * y * y - 2 * z * z; m[0][1] = 2 * x * y - 2 * w * z; m[0][2] = 2 * x * z + 2 * w * y;
56 m[1][0] = 2 * x * y + 2 * w * z; m[1][1] = 1 - 2 * x * x - 2 * z * z; m[1][2] = 2 * y * z - 2 * w * x;
57 m[2][0] = 2 * x * z - 2 * w * y; m[2][1] = 2 * y * z + 2 * w * x; m[2][2] = 1 - 2 * x * x - 2 * y * y;
61 template<class T> Matrix3x3T<T> Matrix3x3T<T>::GetScaleMatrix(T sx, T sy, T sz)
63 Matrix3x3T<T> M;
65 M.m[0][0]=sx;
66 M.m[1][1]=sy;
67 M.m[2][2]=sz;
69 return M;
73 template<class T> Matrix3x3T<T> Matrix3x3T<T>::GetRotateXMatrix(T Angle)
75 Matrix3x3T<T> M;
77 const T RadAngle=AnglesT<T>::DegToRad(Angle);
78 const T SinAngle=sin(RadAngle);
79 const T CosAngle=cos(RadAngle);
81 // Refer to http://de.wikipedia.org/wiki/Rotationsmatrix especially for the correctness of the signs.
82 M.m[1][1]=CosAngle; M.m[1][2]=-SinAngle;
83 M.m[2][1]=SinAngle; M.m[2][2]= CosAngle;
85 return M;
89 template<class T> Matrix3x3T<T> Matrix3x3T<T>::GetRotateYMatrix(T Angle)
91 Matrix3x3T<T> M;
93 const T RadAngle=AnglesT<T>::DegToRad(Angle);
94 const T SinAngle=sin(RadAngle);
95 const T CosAngle=cos(RadAngle);
97 // Refer to http://de.wikipedia.org/wiki/Rotationsmatrix especially for the correctness of the signs.
98 M.m[0][0]= CosAngle; M.m[0][2]=SinAngle;
99 M.m[2][0]=-SinAngle; M.m[2][2]=CosAngle;
101 return M;
105 template<class T> Matrix3x3T<T> Matrix3x3T<T>::GetRotateZMatrix(T Angle)
107 Matrix3x3T<T> M;
109 const T RadAngle=AnglesT<T>::DegToRad(Angle);
110 const T SinAngle=sin(RadAngle);
111 const T CosAngle=cos(RadAngle);
113 // Refer to http://de.wikipedia.org/wiki/Rotationsmatrix especially for the correctness of the signs.
114 M.m[0][0]=CosAngle; M.m[0][1]=-SinAngle;
115 M.m[1][0]=SinAngle; M.m[1][1]= CosAngle;
117 return M;
121 template<class T> Matrix3x3T<T> Matrix3x3T<T>::GetRotateMatrix(T Angle, const Vector3T<T>& Axis)
123 const T RadAngle=AnglesT<T>::DegToRad(Angle);
124 const T s =sin(RadAngle);
125 const T c =cos(RadAngle);
126 const T t =T(1.0)-c;
128 const T Ax=Axis.x;
129 const T Ay=Axis.y;
130 const T Az=Axis.z;
132 const T tx=t*Ax; const T ty=t*Ay; const T tz=t*Az;
133 const T sx=s*Ax; const T sy=s*Ay; const T sz=s*Az;
135 return Matrix3x3T<T>(tx*Ax + c, tx*Ay - sz, tx*Az + sy,
136 tx*Ay + sz, ty*Ay + c, ty*Az - sx,
137 tx*Az - sy, ty*Az + sx, tz*Az + c);
141 // This code is kept for compatibility reasons with old CaWE code.
142 // It rotates around the axes in a different order than the Matrix3x3T(const AnglesT<T>& Angles) ctor above.
143 template<class T> Matrix3x3T<T> Matrix3x3T<T>::GetFromAngles_COMPAT(const AnglesT<T>& Angles)
145 // !!!
146 // !!! This method is only for compatibility with old code in CaWE!
147 // !!! It uses a different understanding for the axes than what is defined at the AnglesT class
148 // !!! (i.e. y and z swapped, z negated) and should therefore NOT be used in new code,
149 // !!! and eventually be replaced by equivalent code that implements the proper axes orientations!
150 // !!!
151 // !!! (Funnily enough, it seems to turn out that this is not so old and obsolete as initially thought,
152 // !!! it's only the order or names of the *angles* that is different from our new, "canonical"
153 // !!! method, not the order or orientation or something of the actual *transformations*!)
154 // !!!
155 enum { PITCH=0, YAW, ROLL };
157 const T RadH=AnglesT<T>::DegToRad(Angles[YAW]);
158 const T SinH=sin(RadH);
159 const T CosH=cos(RadH);
161 const T RadP=AnglesT<T>::DegToRad(Angles[PITCH]);
162 const T SinP=sin(RadP);
163 const T CosP=cos(RadP);
165 const T RadB=AnglesT<T>::DegToRad(Angles[ROLL]);
166 const T SinB=sin(RadB);
167 const T CosB=cos(RadB);
169 return Matrix3x3T<T>(CosP*CosH, SinB*SinP*CosH + CosB*-SinH, CosB*SinP*CosH + -SinB*-SinH,
170 CosP*SinH, SinB*SinP*SinH + CosB*CosH, CosB*SinP*SinH + -SinB*CosH,
171 -SinP, SinB*CosP, CosB*CosP);
175 template<class T> Matrix3x3T<T> Matrix3x3T<T>::operator * (const Matrix3x3T<T>& vm) const
177 return Matrix3x3T<T>(
178 m[0][0]*vm.m[0][0] + m[0][1]*vm.m[1][0] + m[0][2]*vm.m[2][0],
179 m[0][0]*vm.m[0][1] + m[0][1]*vm.m[1][1] + m[0][2]*vm.m[2][1],
180 m[0][0]*vm.m[0][2] + m[0][1]*vm.m[1][2] + m[0][2]*vm.m[2][2],
182 m[1][0]*vm.m[0][0] + m[1][1]*vm.m[1][0] + m[1][2]*vm.m[2][0],
183 m[1][0]*vm.m[0][1] + m[1][1]*vm.m[1][1] + m[1][2]*vm.m[2][1],
184 m[1][0]*vm.m[0][2] + m[1][1]*vm.m[1][2] + m[1][2]*vm.m[2][2],
186 m[2][0]*vm.m[0][0] + m[2][1]*vm.m[1][0] + m[2][2]*vm.m[2][0],
187 m[2][0]*vm.m[0][1] + m[2][1]*vm.m[1][1] + m[2][2]*vm.m[2][1],
188 m[2][0]*vm.m[0][2] + m[2][1]*vm.m[1][2] + m[2][2]*vm.m[2][2]);
192 template<class T> void Matrix3x3T<T>::Scale_MS(T sx, T sy, T sz)
194 for (unsigned long i=0; i<3; i++)
196 m[i][0]*=sx;
197 m[i][1]*=sy;
198 m[i][2]*=sz;
203 template<class T> void Matrix3x3T<T>::Scale_SM(T sx, T sy, T sz)
205 for (unsigned long j=0; j<3; j++)
207 m[0][j]*=sx;
208 m[1][j]*=sy;
209 m[2][j]*=sz;
214 template<class T> void Matrix3x3T<T>::RotateX_MR(T Angle)
216 const T RadAngle=AnglesT<T>::DegToRad(Angle);
217 const T SinAngle=sin(RadAngle);
218 const T CosAngle=cos(RadAngle);
220 for (unsigned long i=0; i<3; i++)
222 const T y= CosAngle*m[i][1] + SinAngle*m[i][2];
223 const T z=-SinAngle*m[i][1] + CosAngle*m[i][2];
225 m[i][1]=y;
226 m[i][2]=z;
231 template<class T> void Matrix3x3T<T>::RotateX_RM(T Angle)
233 const T RadAngle=AnglesT<T>::DegToRad(Angle);
234 const T SinAngle=sin(RadAngle);
235 const T CosAngle=cos(RadAngle);
237 for (unsigned long j=0; j<3; j++)
239 const T a=CosAngle*m[1][j] - SinAngle*m[2][j];
240 const T b=SinAngle*m[1][j] + CosAngle*m[2][j];
242 m[1][j]=a;
243 m[2][j]=b;
248 template<class T> void Matrix3x3T<T>::RotateY_MR(T Angle)
250 const T RadAngle=AnglesT<T>::DegToRad(Angle);
251 const T SinAngle=sin(RadAngle);
252 const T CosAngle=cos(RadAngle);
254 for (unsigned long i=0; i<3; i++)
256 const T x=CosAngle*m[i][0] - SinAngle*m[i][2];
257 const T z=SinAngle*m[i][0] + CosAngle*m[i][2];
259 m[i][0]=x;
260 m[i][2]=z;
265 template<class T> void Matrix3x3T<T>::RotateY_RM(T Angle)
267 const T RadAngle=AnglesT<T>::DegToRad(Angle);
268 const T SinAngle=sin(RadAngle);
269 const T CosAngle=cos(RadAngle);
271 for (unsigned long j=0; j<3; j++)
273 const T a= CosAngle*m[0][j] + SinAngle*m[2][j];
274 const T b=-SinAngle*m[0][j] + CosAngle*m[2][j];
276 m[0][j]=a;
277 m[2][j]=b;
282 template<class T> void Matrix3x3T<T>::RotateZ_MR(T Angle)
284 const T RadAngle=AnglesT<T>::DegToRad(Angle);
285 const T SinAngle=sin(RadAngle);
286 const T CosAngle=cos(RadAngle);
288 for (unsigned long i=0; i<3; i++)
290 const T x= CosAngle*m[i][0] + SinAngle*m[i][1];
291 const T y=-SinAngle*m[i][0] + CosAngle*m[i][1];
293 m[i][0]=x;
294 m[i][1]=y;
299 template<class T> void Matrix3x3T<T>::RotateZ_RM(T Angle)
301 const T RadAngle=AnglesT<T>::DegToRad(Angle);
302 const T SinAngle=sin(RadAngle);
303 const T CosAngle=cos(RadAngle);
305 for (unsigned long j=0; j<3; j++)
307 const T a=CosAngle*m[0][j] - SinAngle*m[1][j];
308 const T b=SinAngle*m[0][j] + CosAngle*m[1][j];
310 m[0][j]=a;
311 m[1][j]=b;
316 template<class T> Matrix3x3T<T> Matrix3x3T<T>::GetInverse(bool* Result) const
318 // How it's done:
319 // AX = I
320 // A = this
321 // X = the matrix we're looking for
322 // I = identity
323 T mat[3][6];
324 int rowMap[3];
326 if (Result!=NULL) Result[0]=false;
328 // Copy this matrix into the left half of mat and the identity matrix into the right half, so that "mat=AI".
329 for (unsigned long i=0; i<3; i++)
331 const T* pIn =m[i];
332 T* pOut=mat[i];
334 for (unsigned long j=0; j<3; j++)
336 pOut[j ]=pIn[j];
337 pOut[j+3]=(i==j) ? T(1.0) : T(0.0);
340 rowMap[i]=i;
343 // Use row operations to get to reduced row-echelon form using these rules:
344 // 1. Multiply or divide a row by a nonzero number.
345 // 2. Add a multiple of one row to another.
346 // 3. Interchange two rows.
347 for (int iRow=0; iRow<3; iRow++)
349 // Find the row with the largest element in this column.
350 T fLargest = T(0.001);
351 int iLargest = -1;
353 for (int iTest=iRow; iTest<3; iTest++)
355 const T fTest=fabs(mat[rowMap[iTest]][iRow]);
357 if (fTest>fLargest)
359 iLargest = iTest;
360 fLargest = fTest;
364 // They're all too small.. sorry.
365 if (iLargest==-1) return Matrix3x3T();
367 // Swap the rows.
368 int iTemp = rowMap[iLargest];
369 rowMap[iLargest] = rowMap[iRow];
370 rowMap[iRow] = iTemp;
372 T* pRow = mat[rowMap[iRow]];
374 // Divide this row by the element.
375 const T mul=T(1.0)/pRow[iRow];
376 for (int j=0; j<6; j++) pRow[j]*=mul;
377 pRow[iRow]=T(1.0); // Preserve accuracy...
379 // Eliminate this element from the other rows using operation 2.
380 for (int i=0; i<3; i++)
382 if (i==iRow) continue;
384 T* pScaleRow = mat[rowMap[i]];
386 // Multiply this row by -(iRow*the element).
387 const T mul_=-pScaleRow[iRow];
388 for (int j=0; j<6; j++) pScaleRow[j]+=pRow[j]*mul_;
389 pScaleRow[iRow]=0.0; // Preserve accuracy...
393 // The inverse is on the right side of AX now (the identity is on the left).
394 Matrix3x3T<T> dst;
396 for (int i=0; i<3; i++)
398 const T* pIn =mat[rowMap[i]]+3;
399 T* pOut=dst.m[i];
401 for (int j=0; j<3; j++) pOut[j]=pIn[j];
404 if (Result!=NULL) Result[0]=true;
405 return dst;
409 template<class T> Matrix3x3T<T> Matrix3x3T<T>::GetTranspose() const
411 Matrix3x3T<T> mt;
413 for (unsigned long i=0; i<3; i++)
414 for (unsigned long j=0; j<3; j++)
415 mt.m[i][j]=m[j][i];
417 return mt;
421 template<class T> AnglesT<T> Matrix3x3T<T>::ToAngles_COMPAT() const
423 // !!!
424 // !!! This method is only for compatibility with old code in CaWE!
425 // !!! It uses a different understanding for the axes than what is defined at the AnglesT class
426 // !!! (i.e. y and z swapped, z negated) and should therefore NOT be used in new code,
427 // !!! and eventually be replaced by equivalent code that implements the proper axes orientations!
428 // !!!
429 enum { PITCH=0, YAW, ROLL };
431 // Extract the basis vectors from the matrix.
432 const Vector3T<T> forward(m[0][0], m[1][0], m[2][0]); // First column, x-axis.
433 const Vector3T<T> left (m[0][1], m[1][1], m[2][1]); // Second column.
434 const Vector3T<T> up (m[0][2], m[1][2], m[2][2]); // Third column.
436 const T xyDist=sqrt(forward[0]*forward[0] + forward[1]*forward[1]);
437 AnglesT<T> Angles;
439 if (xyDist>0.001f)
441 Angles[YAW ]=AnglesT<T>::RadToDeg(atan2( forward[1], forward[0]));
442 Angles[PITCH]=AnglesT<T>::RadToDeg(atan2(-forward[2], xyDist));
443 Angles[ROLL ]=AnglesT<T>::RadToDeg(atan2( left[2], up[2]));
445 else
447 // The forward vector points mostly along the z-axis,
448 // which means that we have a Gimbal Lock, http://de.wikipedia.org/wiki/Gimbal_Lock
449 Angles[YAW ]=AnglesT<T>::RadToDeg(atan2(-left[0], left[1]));
450 Angles[PITCH]=AnglesT<T>::RadToDeg(atan2(-forward[2], xyDist));
451 Angles[ROLL ]=0; // No roll, because one degree of freedom has been lost (that is, yaw==roll).
454 assert(GetFromAngles_COMPAT(Angles).IsEqual(*this, 0.001f));
455 return Angles;
459 template class Matrix3x3T<float>;
460 template class Matrix3x3T<double>;