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.
7 #include "Matrix3x3.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.
40 GetRotateZMatrix(Angles
.yaw()) *
41 GetRotateYMatrix(Angles
.pitch()) *
42 GetRotateXMatrix(Angles
.roll()),
47 template<class T
> Matrix3x3T
<T
>::Matrix3x3T(const QuaternionT
<T
>& Quat
)
49 // This is the same code as in the related MatrixT constructor.
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
)
73 template<class T
> Matrix3x3T
<T
> Matrix3x3T
<T
>::GetRotateXMatrix(T Angle
)
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
;
89 template<class T
> Matrix3x3T
<T
> Matrix3x3T
<T
>::GetRotateYMatrix(T Angle
)
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
;
105 template<class T
> Matrix3x3T
<T
> Matrix3x3T
<T
>::GetRotateZMatrix(T Angle
)
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
;
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
);
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
)
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!
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*!)
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
++)
203 template<class T
> void Matrix3x3T
<T
>::Scale_SM(T sx
, T sy
, T sz
)
205 for (unsigned long j
=0; j
<3; j
++)
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];
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
];
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];
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
];
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];
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
];
316 template<class T
> Matrix3x3T
<T
> Matrix3x3T
<T
>::GetInverse(bool* Result
) const
321 // X = the matrix we're looking for
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
++)
334 for (unsigned long j
=0; j
<3; j
++)
337 pOut
[j
+3]=(i
==j
) ? T(1.0) : T(0.0);
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);
353 for (int iTest
=iRow
; iTest
<3; iTest
++)
355 const T fTest
=fabs(mat
[rowMap
[iTest
]][iRow
]);
364 // They're all too small.. sorry.
365 if (iLargest
==-1) return Matrix3x3T();
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).
396 for (int i
=0; i
<3; i
++)
398 const T
* pIn
=mat
[rowMap
[i
]]+3;
401 for (int j
=0; j
<3; j
++) pOut
[j
]=pIn
[j
];
404 if (Result
!=NULL
) Result
[0]=true;
409 template<class T
> Matrix3x3T
<T
> Matrix3x3T
<T
>::GetTranspose() const
413 for (unsigned long i
=0; i
<3; i
++)
414 for (unsigned long j
=0; j
<3; j
++)
421 template<class T
> AnglesT
<T
> Matrix3x3T
<T
>::ToAngles_COMPAT() const
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!
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]);
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]));
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
));
459 template class Matrix3x3T
<float>;
460 template class Matrix3x3T
<double>;