1 /***************************************************************************
2 * This file is part of Tecorrec. *
3 * Copyright 2008 James Hogan <james@albanarts.com> *
5 * Tecorrec is free software: you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation, either version 2 of the License, or *
8 * (at your option) any later version. *
10 * Tecorrec is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with Tecorrec. If not, write to the Free Software Foundation, *
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ***************************************************************************/
22 * @brief Quaternion class for orientations and rotations.
23 * @author James Hogan (james@albanarts.com)
24 * @note Copyright (C) 2007
26 * @version 1 : From Computer Graphics and Visualisation Open Assessment.
29 #ifndef _maths_Quaternion_h
30 #define _maths_Quaternion_h
32 #include "TemplateMaths.h"
39 // These aren't always used.
40 template <int N
, typename T
>
42 template <int N
, typename T
>
47 /// Get a rotation quaterion between two vectors.
49 Quaternion
<T
> rotationArc(const Vector
<3,T
> & a
, const Vector
<3,T
> & b
)
57 return Quaternion
<T
>(c
[0] / s
,
62 // 180 degrees, Result would ordinarily be not a number.
63 return Quaternion
<T
>((T
)1, (T
)0, (T
)0, (T
)0);
67 /// Get a rotation quaterion between two vectors.
69 Quaternion
<T
> rotationArc(const Vector
<3,T
> & a
, const Vector
<3,T
> & b
, bool * pDeterminate
)
75 bool determinate
= s2
;
77 *pDeterminate
= determinate
;
81 return Quaternion
<T
>(c
[0] / s
,
86 // 180 degrees, Result would ordinarily be not a number.
87 return Quaternion
<T
>((T
)1, (T
)0, (T
)0, (T
)0);
91 /// Quaternion orientation.
93 * @param T typename Type of the components of the quaternion.
102 /// Default constructor (does not initialise values)
107 inline explicit Quaternion(const T
* quat
)
109 for (int i
= 0; i
< 4; ++i
) {
113 inline explicit Quaternion(T x
, T y
, T z
, T w
)
120 inline explicit Quaternion(const Vector
<3, T
> & vec
)
122 for (int i
= 0; i
< 3; ++i
) {
128 template <typename U
> inline explicit Quaternion(const Quaternion
<U
> & copy
)
130 for (int i
= 0; i
< 4; ++i
) {
135 /// Construct from a 3 by 3 matrix with the same component types.
137 * Taken from game programming gems 1 i think
139 inline explicit Quaternion(const Matrix
<3,T
> & m
)
142 tr
= m
[0][0] + m
[1][1] + m
[2][2];
148 q
[0] = (m
[2][1] - m
[1][2]) * s
;
149 q
[1] = (m
[0][2] - m
[2][0]) * s
;
150 q
[2] = (m
[1][0] - m
[0][1]) * s
;
153 if (m
[1][1] > m
[0][0])
155 if (m
[2][2] > m
[i
][i
])
159 s
= sqrt((m
[0][0] - (m
[1][1] + m
[2][2])) + (T
)1);
162 q
[1] = (m
[0][1] + m
[1][0]) * s
;
163 q
[2] = (m
[2][0] + m
[0][2]) * s
;
164 q
[3] = (m
[2][1] - m
[1][2]) * s
;
167 s
= sqrt((m
[1][1] - (m
[2][2] + m
[0][0])) + (T
)1);
170 q
[2] = (m
[1][2] + m
[2][1]) * s
;
171 q
[0] = (m
[0][1] + m
[1][0]) * s
;
172 q
[3] = (m
[0][2] - m
[2][0]) * s
;
175 s
= sqrt((m
[2][2] - (m
[0][0] + m
[1][1])) + (T
)1);
178 q
[0] = (m
[2][0] + m
[0][2]) * s
;
179 q
[1] = (m
[1][2] + m
[2][1]) * s
;
180 q
[3] = (m
[1][0] - m
[0][1]) * s
;
186 /// Convert to a 3 by 3 rotation matrix.
187 inline Matrix
<3, T
> toMatrix3()
196 setVector3(mat
[0].v
, 1-2*(yy
+zz
), 2*(xy
+zw
), 2*(xz
-yw
));
200 setVector3(mat
[1].v
, 2*(xy
-zw
), 1-2*(xx
+zz
), 2*(yz
+xw
));
201 setVector3(mat
[2].v
, 2*(xz
+yw
), 2*(yz
-xw
), 1-2*(xx
+yy
));
205 inline T
& operator [] (int index
)
209 inline const T
& operator [] (int index
) const
214 inline operator T
* ()
218 inline operator const T
* () const
223 // Construct a quaternion from a set of euler angles
224 /*explicit Quaternion(const mlEulerf & E);
225 // Construct a quaternion from a rotation matrix
226 explicit Quaternion(const maths::Matrix<3,float> & M);
227 // Construct a pure quaternion with V as {x,y,z}
228 explicit inline Quaternion(const Vector3f & V)
229 : x(V.q[0]), y(V.q[1]), z(V.q[2]), w((T)0)
233 // Quick setter, returns self reference
234 /*inline Quaternion & Set(R fX = (T)0, R fY = (T)0, R fZ = (T)0, R fW = (T)0)
247 for (int i
= 0; i
< 4; ++i
)
254 return sqrt
<T
>(sqr());
258 inline Quaternion
& normalize()
260 return operator /= (mag());
262 inline Quaternion
normalized()
264 return operator / (this, mag());
267 inline Quaternion
& resize(T tLength
)
269 return operator *= (tLength
/ mag());
271 inline Quaternion
resized(T tLength
)
273 return operator * (this, tLength
/ mag());
276 inline Quaternion
& conjugate()
278 for (int i
= 0; i
< 3; ++i
)
282 inline Quaternion
conjugated()
284 Quaternion ret
= *this;
285 return ret
.conjugate();
288 inline Quaternion
& identity()
290 for (int i
= 0; i
< 3; ++i
)
297 inline friend Quaternion
operator * (const Quaternion
& lhs
, const Quaternion
& rhs
)
299 return Quaternion(lhs
.q
[3]*rhs
.q
[0] + lhs
.q
[0]*rhs
.q
[3] + lhs
.q
[1]*rhs
.q
[2] - lhs
.q
[2]*rhs
.q
[1],
300 lhs
.q
[3]*rhs
.q
[1] - lhs
.q
[0]*rhs
.q
[2] + lhs
.q
[1]*rhs
.q
[3] + lhs
.q
[2]*rhs
.q
[0],
301 lhs
.q
[3]*rhs
.q
[2] + lhs
.q
[0]*rhs
.q
[1] - lhs
.q
[1]*rhs
.q
[0] + lhs
.q
[2]*rhs
.q
[3],
302 lhs
.q
[3]*rhs
.q
[3] - lhs
.q
[0]*rhs
.q
[0] - lhs
.q
[1]*rhs
.q
[1] - lhs
.q
[2]*rhs
.q
[2]);
304 inline Quaternion
& operator *=(const Quaternion
& rhs
)
306 q
[0] = q
[3]*rhs
.q
[0] + q
[0]*rhs
.q
[3] + q
[1]*rhs
.q
[2] - q
[2]*rhs
.q
[1];
307 q
[1] = q
[3]*rhs
.q
[1] - q
[0]*rhs
.q
[2] + q
[1]*rhs
.q
[3] + q
[2]*rhs
.q
[0];
308 q
[2] = q
[3]*rhs
.q
[2] + q
[0]*rhs
.q
[1] - q
[1]*rhs
.q
[0] + q
[2]*rhs
.q
[3];
309 q
[3] = q
[3]*rhs
.q
[3] - q
[0]*rhs
.q
[0] - q
[1]*rhs
.q
[1] - q
[2]*rhs
.q
[2];
313 // Multiplications: Real * Quaternion or Quaternion * Real
314 inline friend Quaternion
operator *(const Quaternion
& lhs
, T rhs
)
316 return Quaternion(lhs
.q
[0] * rhs
,
321 inline friend Quaternion
operator *(T lhs
, const Quaternion
& rhs
)
323 return Quaternion(lhs
* rhs
.q
[0],
328 inline Quaternion
operator *=(T rhs
)
338 inline friend Quaternion
operator /(const Quaternion
& lhs
, const Quaternion
& rhs
)
340 T rhsSqr
= rhs
.sqr();
341 return Quaternion((-lhs
.q
[3]*rhs
.q
[0] + lhs
.q
[0]*rhs
.q
[3] - lhs
.q
[1]*rhs
.q
[2] + lhs
.q
[2]*rhs
.q
[1]) / rhsSqr
,
342 (-lhs
.q
[3]*rhs
.q
[1] + lhs
.q
[0]*rhs
.q
[2] + lhs
.q
[1]*rhs
.q
[3] - lhs
.q
[2]*rhs
.q
[0]) / rhsSqr
,
343 (-lhs
.q
[3]*rhs
.q
[2] - lhs
.q
[0]*rhs
.q
[1] + lhs
.q
[1]*rhs
.q
[0] + lhs
.q
[2]*rhs
.q
[3]) / rhsSqr
,
344 ( lhs
.q
[3]*rhs
.q
[3] + lhs
.q
[0]*rhs
.q
[0] + lhs
.q
[1]*rhs
.q
[1] + lhs
.q
[2]*rhs
.q
[2]) / rhsSqr
);
346 inline Quaternion
& operator /=(const Quaternion
& den
)
348 return operator=(operator/(*this,den
));
351 // Divisions: Quaternion / Real
352 inline friend Quaternion
operator /(const Quaternion
& lhs
, T rhs
)
354 return Quaternion(lhs
.q
[0] / rhs
,
359 inline Quaternion
& operator /=(T rhs
)
369 inline Quaternion
& negate()
377 inline friend Quaternion
operator - (const Quaternion
& quat
)
379 return Quaternion(-quat
.q
[0],
386 inline friend Quaternion
operator +(const Quaternion
& lhs
, const Quaternion
& rhs
)
388 return Quaternion(lhs
.q
[0] + rhs
.q
[0],
391 lhs
.q
[3] + rhs
.q
[3]);
393 inline Quaternion
& operator +=(const Quaternion
& rhs
)
395 q
[0] = q
[0] + rhs
.q
[0];
396 q
[1] = q
[1] + rhs
.q
[1];
397 q
[2] = q
[2] + rhs
.q
[2];
398 q
[3] = q
[3] + rhs
.q
[3];
403 inline friend Quaternion
operator -(const Quaternion
& lhs
, const Quaternion
& rhs
)
405 return Quaternion(lhs
.q
[0] - rhs
.q
[0],
408 lhs
.q
[3] - rhs
.q
[3]);
410 inline Quaternion
& operator -=(const Quaternion
& rhs
)
412 q
[0] = q
[0] - rhs
.q
[0];
413 q
[1] = q
[1] - rhs
.q
[1];
414 q
[2] = q
[2] - rhs
.q
[2];
415 q
[3] = q
[3] - rhs
.q
[3];
420 s/c = sin(Th/2)/cos(Th/2) = tan(Th/2)
423 s = c.sin(arccos(c))/cos(arccos(c))
425 VAxis = [x/s, y/s, z/s]
427 // Get the axis of rotation
428 inline Vector
<3,T
> AxisOfRotation() const
430 T c
= (q
[3]>1) ? 1 : (q
[3]<-1) ? -1 : q
[3];
431 T s
= 1/sinf(acos(c
));
432 return Vector
<3,T
>(q
[0]*s
,q
[1]*s
,q
[2]*s
);
434 // Get the angle of rotation
435 inline T
AngleOfRotation() const
437 T c
= (q
[3]>1) ? 1 : (q
[3]<-1) ? -1 : q
[3];
438 //T c = (q[3]>1) ? 1 : q[3];
442 // Get the axis and angle or rotation represented in the form of a non unit quaternion
443 inline Quaternion
ToAxisAngle() const
445 T c
= (q
[3]>1) ? 1 : (q
[3]<-1) ? -1 : q
[3];
447 return Quaternion((T
)0, (T
)0, (T
)0, (T
)0);
449 else if (c
<= (T
)-1) {
450 return Quaternion((T
)1, (T
)0, (T
)0, (T
)M_PI
);
454 T s
= (T
)1/sin(theta
);
455 return Quaternion(q
[0]*s
,q
[1]*s
,q
[2]*s
,2*theta
);
459 // Exponentials / Logarithms
460 // Logarithm of a quaternion, given as:
461 // log(q) = v*a where q = [cos(a),v*sin(a)]
462 inline friend Quaternion
log(const Quaternion
& q
)
469 ret
.q
[0] = a
*q
.q
[0]/sina
;
470 ret
.q
[1] = a
*q
.q
[1]/sina
;
471 ret
.q
[2] = a
*q
.q
[2]/sina
;
473 ret
.q
[0] = ret
.q
[1] = ret
.q
[2] = (T
)0;
478 // e^quaternion given as:
479 // exp(v*a) = [cos(a),vsin(a)]
480 inline friend Quaternion
exp(const Quaternion
& q
)
483 T sinaoa
= sinf(a
)/a
;
489 ret
.q
[0] = sinaoa
* q
.q
[0];
490 ret
.q
[1] = sinaoa
* q
.q
[1];
491 ret
.q
[2] = sinaoa
* q
.q
[2];
493 ret
.q
[0] = ret
.q
[1] = ret
.q
[2] = (T
)0;
499 // Linear interpolation between two quaternions
500 inline friend Quaternion
lerp(const Quaternion
& q1
, const Quaternion
& q2
, T t
)
502 return Quaternion(q1
.q
[0]+t
*(q2
.q
[0]-q1
.q
[0]),
503 q1
.q
[1]+t
*(q2
.q
[1]-q1
.q
[1]),
504 q1
.q
[2]+t
*(q2
.q
[2]-q1
.q
[2]),
505 q1
.q
[3]+t
*(q2
.q
[3]-q1
.q
[3])).normalize();
508 // Spherical Linear interpolation between two quaternions
509 inline friend Quaternion
slerp(const Quaternion
& q1
, const Quaternion
& q2
, T t
)
512 T dot
= q1
.q
[0]*q2
.q
[0] + q1
.q
[1]*q2
.q
[1] + q1
.q
[2]*q2
.q
[2] + q1
.q
[3]*q2
.q
[3];
515 // if (dot < 0), q1 and q2 are more than 90 degrees apart,
516 // so we can invert one to reduce spinning
525 T angle
= acosf(dot
);
526 T sina
= sinf(angle
);
527 T sinat
= sinf(angle
*t
);
528 T sinaomt
= sinf(angle
*((T
)1-t
));
529 return (q1
*sinaomt
+q3
*sinat
)/sina
;
531 // if the angle is small, use linear interpolation
532 return lerp(q1
,q3
,t
);
536 // This version of slerp, used by squad, does not check for theta > 90.
537 inline friend Quaternion
slerp_no_invert(const Quaternion
& q1
, const Quaternion
& q2
, T t
)
539 T dot
= q1
.q
[0]*q2
.q
[0] + q1
.q
[1]*q2
.q
[1] + q1
.q
[2]*q2
.q
[2] + q1
.q
[3]*q2
.q
[3];
541 if (dot
> (T
)-0.95 && dot
< (T
)0.95) {
544 sinat
= sin(angle
*t
),
545 sinaomt
= sin(angle
*((T
)1-t
));
546 return (q1
*sinaomt
+q2
*sinat
)/sina
;
548 // if the angle is small, use linear interpolation
549 return lerp(q1
,q2
,t
);
553 // Spherical cubic interpolation
554 inline friend Quaternion
squad(const Quaternion
& q1
, const Quaternion
& q2
,
555 const Quaternion
& a
, const Quaternion
& b
, T t
)
557 Quaternion
c(slerp_no_invert(q1
,q2
,t
)),
558 d(slerp_no_invert(a
, b
, t
));
559 return slerp_no_invert(c
,d
,2*t
*((T
)1-t
));
562 // Given 3 quaternions, qn-1,qn and qn+1, calculate a control point to be used in spline interpolation
563 inline friend Quaternion
spline(const Quaternion
& qnm1
,const Quaternion
& qn
,const Quaternion
& qnp1
)
567 return qn
*exp((log(qni
*qnm1
)+log(qni
*qnp1
))*((T
)-0.25));
569 }; // ::maths::Quaternion
571 /// Write a vector to an output stream.
572 template <typename T
>
573 inline std::ostream
& operator << (std::ostream
& out
, const Quaternion
<T
> & v
)
576 for (int i
= 1; i
< 4; ++i
) {