00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #ifndef _QUATERNION_H_
00013 #define _QUATERNION_H_
00014
00015 #include <celmath/mathlib.h>
00016 #include <celmath/vecmath.h>
00017
00018
00019 #if 0
00020
00021
00022 template<class T> class Quaternion;
00023
00024 template<class T> Quaternion<T> operator+(Quaternion<T>, Quaternion<T>);
00025 template<class T> Quaternion<T> operator-(Quaternion<T>, Quaternion<T>);
00026 template<class T> Quaternion<T> operator*(Quaternion<T>, Quaternion<T>);
00027 template<class T> Quaternion<T> operator*(T, Quaternion<T>);
00028 template<class T> Quaternion<T> operator*(Vector3<T>, Quaternion<T>);
00029 template<class T> bool operator==(Quaternion<T>, Quaternion<T>);
00030 template<class T> bool operator!=(Quaternion<T>, Quaternion<T>);
00031 template<class T> T real(Quaternion<T>);
00032 template<class T> Vector3<T> imag(Quaternion<T>);
00033 #endif
00034
00035 template<class T> class Quaternion
00036 {
00037 public:
00038 inline Quaternion();
00039 inline Quaternion(const Quaternion<T>&);
00040 inline Quaternion(T);
00041 inline Quaternion(const Vector3<T>&);
00042 inline Quaternion(T, const Vector3<T>&);
00043 inline Quaternion(T, T, T, T);
00044
00045 Quaternion(const Matrix3<T>&);
00046
00047 inline Quaternion& operator+=(Quaternion);
00048 inline Quaternion& operator-=(Quaternion);
00049 inline Quaternion& operator*=(T);
00050 Quaternion& operator*=(Quaternion);
00051
00052 inline Quaternion operator~() const;
00053 inline Quaternion operator-() const;
00054 inline Quaternion operator+() const;
00055
00056 void setAxisAngle(Vector3<T> axis, T angle);
00057
00058 void getAxisAngle(Vector3<T>& axis, T& angle) const;
00059 Matrix4<T> toMatrix4() const;
00060 Matrix3<T> toMatrix3() const;
00061
00062 static Quaternion<T> slerp(Quaternion<T>, Quaternion<T>, T);
00063
00064 void rotate(Vector3<T> axis, T angle);
00065 void xrotate(T angle);
00066 void yrotate(T angle);
00067 void zrotate(T angle);
00068
00069 bool isPure() const;
00070 bool isReal() const;
00071 T normalize();
00072
00073 static Quaternion<T> xrotation(T);
00074 static Quaternion<T> yrotation(T);
00075 static Quaternion<T> zrotation(T);
00076 #if 0
00077
00078 #ifndef BROKEN_FRIEND_TEMPLATES
00079
00080
00081
00082 friend Quaternion<T> operator+ <>(Quaternion<T>, Quaternion<T>);
00083 friend Quaternion<T> operator- <>(Quaternion<T>, Quaternion<T>);
00084 friend Quaternion<T> operator* <>(Quaternion<T>, Quaternion<T>);
00085 friend Quaternion<T> operator* <>(T, Quaternion<T>);
00086 friend Quaternion<T> operator* <>(Vector3<T>, Quaternion<T>);
00087
00088 friend bool operator== <>(Quaternion<T>, Quaternion<T>);
00089 friend bool operator!= <>(Quaternion<T>, Quaternion<T>);
00090
00091 friend T real<>(Quaternion<T>);
00092 friend Vector3<T> imag<>(Quaternion<T>);
00093 #else
00094 friend Quaternion<T> operator+(Quaternion<T>, Quaternion<T>);
00095 friend Quaternion<T> operator-(Quaternion<T>, Quaternion<T>);
00096 friend Quaternion<T> operator*(Quaternion<T>, Quaternion<T>);
00097 friend Quaternion<T> operator*(T, Quaternion<T>);
00098 friend Quaternion<T> operator*(Vector3<T>, Quaternion<T>);
00099
00100 friend bool operator==(Quaternion<T>, Quaternion<T>);
00101 friend bool operator!=(Quaternion<T>, Quaternion<T>);
00102
00103 friend T real(Quaternion<T>);
00104 friend Vector3<T> imag(Quaternion<T>);
00105 #endif // BROKEN_FRIEND_TEMPLATES
00106
00107 #endif
00108
00109
00110
00111 T w, x, y, z;
00112 };
00113
00114
00115 typedef Quaternion<float> Quatf;
00116 typedef Quaternion<double> Quatd;
00117
00118
00119 template<class T> Quaternion<T>::Quaternion() : w(0), x(0), y(0), z(0)
00120 {
00121 }
00122
00123 template<class T> Quaternion<T>::Quaternion(const Quaternion<T>& q) :
00124 w(q.w), x(q.x), y(q.y), z(q.z)
00125 {
00126 }
00127
00128 template<class T> Quaternion<T>::Quaternion(T re) :
00129 w(re), x(0), y(0), z(0)
00130 {
00131 }
00132
00133
00134 template<class T> Quaternion<T>::Quaternion(const Vector3<T>& im) :
00135 w(0), x(im.x), y(im.y), z(im.z)
00136 {
00137 }
00138
00139 template<class T> Quaternion<T>::Quaternion(T re, const Vector3<T>& im) :
00140 w(re), x(im.x), y(im.y), z(im.z)
00141 {
00142 }
00143
00144 template<class T> Quaternion<T>::Quaternion(T _w, T _x, T _y, T _z) :
00145 w(_w), x(_x), y(_y), z(_z)
00146 {
00147 }
00148
00149
00150 template<class T> Quaternion<T>::Quaternion(const Matrix3<T>& m)
00151 {
00152 T trace = m[0][0] + m[1][1] + m[2][2];
00153 T root;
00154
00155 if (trace > 0)
00156 {
00157 root = (T) sqrt(trace + 1);
00158 w = (T) 0.5 * root;
00159 root = (T) 0.5 / root;
00160 x = (m[2][1] - m[1][2]) * root;
00161 y = (m[0][2] - m[2][0]) * root;
00162 z = (m[1][0] - m[0][1]) * root;
00163 }
00164 else
00165 {
00166 int i = 0;
00167 if (m[1][1] > m[i][i])
00168 i = 1;
00169 if (m[2][2] > m[i][i])
00170 i = 2;
00171 int j = (i == 2) ? 0 : i + 1;
00172 int k = (j == 2) ? 0 : j + 1;
00173
00174 root = (T) sqrt(m[i][i] - m[j][j] - m[k][k] + 1);
00175 T* xyz[3] = { &x, &y, &z };
00176 *xyz[i] = (T) 0.5 * root;
00177 root = (T) 0.5 / root;
00178 w = (m[k][j] - m[j][k]) * root;
00179 *xyz[j] = (m[j][i] + m[i][j]) * root;
00180 *xyz[k] = (m[k][i] + m[i][k]) * root;
00181 }
00182 }
00183
00184
00185 template<class T> Quaternion<T>& Quaternion<T>::operator+=(Quaternion<T> a)
00186 {
00187 x += a.x; y += a.y; z += a.z; w += a.w;
00188 return *this;
00189 }
00190
00191 template<class T> Quaternion<T>& Quaternion<T>::operator-=(Quaternion<T> a)
00192 {
00193 x -= a.x; y -= a.y; z -= a.z; w -= a.w;
00194 return *this;
00195 }
00196
00197 template<class T> Quaternion<T>& Quaternion<T>::operator*=(Quaternion<T> q)
00198 {
00199 *this = Quaternion<T>(w * q.w - x * q.x - y * q.y - z * q.z,
00200 w * q.x + x * q.w + y * q.z - z * q.y,
00201 w * q.y + y * q.w + z * q.x - x * q.z,
00202 w * q.z + z * q.w + x * q.y - y * q.x);
00203
00204 return *this;
00205 }
00206
00207 template<class T> Quaternion<T>& Quaternion<T>::operator*=(T s)
00208 {
00209 x *= s; y *= s; z *= s; w *= s;
00210 return *this;
00211 }
00212
00213
00214 template<class T> Quaternion<T> Quaternion<T>::operator~() const
00215 {
00216 return Quaternion<T>(w, -x, -y, -z);
00217 }
00218
00219 template<class T> Quaternion<T> Quaternion<T>::operator-() const
00220 {
00221 return Quaternion<T>(-w, -x, -y, -z);
00222 }
00223
00224 template<class T> Quaternion<T> Quaternion<T>::operator+() const
00225 {
00226 return *this;
00227 }
00228
00229
00230 template<class T> Quaternion<T> operator+(Quaternion<T> a, Quaternion<T> b)
00231 {
00232 return Quaternion<T>(a.w + b.w, a.x + b.x, a.y + b.y, a.z + b.z);
00233 }
00234
00235 template<class T> Quaternion<T> operator-(Quaternion<T> a, Quaternion<T> b)
00236 {
00237 return Quaternion<T>(a.w - b.w, a.x - b.x, a.y - b.y, a.z - b.z);
00238 }
00239
00240 template<class T> Quaternion<T> operator*(Quaternion<T> a, Quaternion<T> b)
00241 {
00242 return Quaternion<T>(a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z,
00243 a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
00244 a.w * b.y + a.y * b.w + a.z * b.x - a.x * b.z,
00245 a.w * b.z + a.z * b.w + a.x * b.y - a.y * b.x);
00246 }
00247
00248 template<class T> Quaternion<T> operator*(T s, Quaternion<T> q)
00249 {
00250 return Quaternion<T>(s * q.w, s * q.x, s * q.y, s * q.z);
00251 }
00252
00253 template<class T> Quaternion<T> operator*(Quaternion<T> q, T s)
00254 {
00255 return Quaternion<T>(s * q.w, s * q.x, s * q.y, s * q.z);
00256 }
00257
00258
00259 template<class T> Quaternion<T> operator*(Vector3<T> v, Quaternion<T> q)
00260 {
00261 return Quaternion<T>(-v.x * q.x - v.y * q.y - v.z * q.z,
00262 v.x * q.w + v.y * q.z - v.z * q.y,
00263 v.y * q.w + v.z * q.x - v.x * q.z,
00264 v.z * q.w + v.x * q.y - v.y * q.x);
00265 }
00266
00267 template<class T> Quaternion<T> operator/(Quaternion<T> q, T s)
00268 {
00269 return q * (1 / s);
00270 }
00271
00272 template<class T> Quaternion<T> operator/(Quaternion<T> a, Quaternion<T> b)
00273 {
00274 return a * (~b / abs(b));
00275 }
00276
00277
00278 template<class T> bool operator==(Quaternion<T> a, Quaternion<T> b)
00279 {
00280 return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w;
00281 }
00282
00283 template<class T> bool operator!=(Quaternion<T> a, Quaternion<T> b)
00284 {
00285 return a.x != b.x || a.y != b.y || a.z != b.z || a.w != b.w;
00286 }
00287
00288
00289
00290 template<class T> Quaternion<T> conjugate(Quaternion<T> q)
00291 {
00292 return Quaternion<T>(q.w, -q.x, -q.y, -q.z);
00293 }
00294
00295 template<class T> T norm(Quaternion<T> q)
00296 {
00297 return q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
00298 }
00299
00300 template<class T> T abs(Quaternion<T> q)
00301 {
00302 return (T) sqrt(norm(q));
00303 }
00304
00305 template<class T> Quaternion<T> exp(Quaternion<T> q)
00306 {
00307 if (q.isReal())
00308 {
00309 return Quaternion<T>((T) exp(q.w));
00310 }
00311 else
00312 {
00313 T l = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
00314 T s = (T) sin(l);
00315 T c = (T) cos(l);
00316 T e = (T) exp(q.w);
00317 T t = e * s / l;
00318 return Quaternion<T>(e * c, t * q.x, t * q.y, t * q.z);
00319 }
00320 }
00321
00322 template<class T> Quaternion<T> log(Quaternion<T> q)
00323 {
00324 if (q.isReal())
00325 {
00326 if (q.w > 0)
00327 {
00328 return Quaternion<T>((T) log(q.w));
00329 }
00330 else if (q.w < 0)
00331 {
00332
00333
00334
00335
00336
00337
00338 return Quaternion<T>((T) log(-q.w), (T) PI, 0, 0);
00339 }
00340 else
00341 {
00342
00343 return Quaternion<T>(0);
00344 }
00345 }
00346 else
00347 {
00348 T l = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
00349 T r = (T) sqrt(l * l + q.w * q.w);
00350 T theta = (T) atan2(l, q.w);
00351 T t = theta / l;
00352 return Quaternion<T>((T) log(r), t * q.x, t * q.y, t * q.z);
00353 }
00354 }
00355
00356
00357 template<class T> Quaternion<T> pow(Quaternion<T> q, T s)
00358 {
00359 return exp(s * log(q));
00360 }
00361
00362
00363 template<class T> Quaternion<T> pow(Quaternion<T> q, Quaternion<T> p)
00364 {
00365 return exp(p * log(q));
00366 }
00367
00368
00369 template<class T> Quaternion<T> sin(Quaternion<T> q)
00370 {
00371 if (q.isReal())
00372 {
00373 return Quaternion<T>((T) sin(q.w));
00374 }
00375 else
00376 {
00377 T l = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
00378 T m = q.w;
00379 T s = (T) sin(m);
00380 T c = (T) cos(m);
00381 T il = 1 / l;
00382 T e0 = (T) exp(-l);
00383 T e1 = (T) exp(l);
00384
00385 T c0 = (T) -0.5 * e0 * il * c;
00386 T c1 = (T) 0.5 * e1 * il * c;
00387
00388 return Quaternion<T>((T) 0.5 * e0 * s, c0 * q.x, c0 * q.y, c0 * q.z) +
00389 Quaternion<T>((T) 0.5 * e1 * s, c1 * q.x, c1 * q.y, c1 * q.z);
00390 }
00391 }
00392
00393 template<class T> Quaternion<T> cos(Quaternion<T> q)
00394 {
00395 if (q.isReal())
00396 {
00397 return Quaternion<T>((T) cos(q.w));
00398 }
00399 else
00400 {
00401 T l = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
00402 T m = q.w;
00403 T s = (T) sin(m);
00404 T c = (T) cos(m);
00405 T il = 1 / l;
00406 T e0 = (T) exp(-l);
00407 T e1 = (T) exp(l);
00408
00409 T c0 = (T) 0.5 * e0 * il * s;
00410 T c1 = (T) -0.5 * e1 * il * s;
00411
00412 return Quaternion<T>((T) 0.5 * e0 * c, c0 * q.x, c0 * q.y, c0 * q.z) +
00413 Quaternion<T>((T) 0.5 * e1 * c, c1 * q.x, c1 * q.y, c1 * q.z);
00414 }
00415 }
00416
00417 template<class T> Quaternion<T> sqrt(Quaternion<T> q)
00418 {
00419
00420
00421
00422
00423
00424 if (q.isReal())
00425 {
00426 if (q.w >= 0)
00427 return Quaternion<T>((T) sqrt(q.w), 0, 0, 0);
00428 else
00429 return Quaternion<T>(0, (T) sqrt(-q.w), 0, 0);
00430 }
00431 else
00432 {
00433 T b = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
00434 T r = (T) sqrt(q.w * q.w + b * b);
00435 if (q.w >= 0)
00436 {
00437 T m = (T) sqrt((T) 0.5 * (r + q.w));
00438 T l = b / (2 * m);
00439 T t = l / b;
00440 return Quaternion<T>(m, q.x * t, q.y * t, q.z * t);
00441 }
00442 else
00443 {
00444 T l = (T) sqrt((T) 0.5 * (r - q.w));
00445 T m = b / (2 * l);
00446 T t = l / b;
00447 return Quaternion<T>(m, q.x * t, q.y * t, q.z * t);
00448 }
00449 }
00450 }
00451
00452 template<class T> T real(Quaternion<T> q)
00453 {
00454 return q.w;
00455 }
00456
00457 template<class T> Vector3<T> imag(Quaternion<T> q)
00458 {
00459 return Vector3<T>(q.x, q.y, q.z);
00460 }
00461
00462
00463
00464
00465 template<class T> bool Quaternion<T>::isReal() const
00466 {
00467 return (x == 0 && y == 0 && z == 0);
00468 }
00469
00470 template<class T> bool Quaternion<T>::isPure() const
00471 {
00472 return w == 0;
00473 }
00474
00475 template<class T> T Quaternion<T>::normalize()
00476 {
00477 T s = (T) sqrt(w * w + x * x + y * y + z * z);
00478 T invs = (T) 1 / (T) s;
00479 x *= invs;
00480 y *= invs;
00481 z *= invs;
00482 w *= invs;
00483
00484 return s;
00485 }
00486
00487
00488
00489 template<class T> void Quaternion<T>::setAxisAngle(Vector3<T> axis, T angle)
00490 {
00491 T s, c;
00492
00493 Math<T>::sincos(angle * (T) 0.5, s, c);
00494 x = s * axis.x;
00495 y = s * axis.y;
00496 z = s * axis.z;
00497 w = c;
00498 }
00499
00500
00501
00502
00503 template<class T> void Quaternion<T>::getAxisAngle(Vector3<T>& axis,
00504 T& angle) const
00505 {
00506
00507
00508
00509 T magSquared = x * x + y * y + z * z;
00510 if (magSquared > (T) 1e-10)
00511 {
00512 T s = (T) 1 / (T) sqrt(magSquared);
00513 axis.x = x * s;
00514 axis.y = y * s;
00515 axis.z = z * s;
00516 if (w <= -1 || w >= 1)
00517 angle = 0;
00518 else
00519 angle = (T) acos(w) * 2;
00520 }
00521 else
00522 {
00523
00524 axis.x = 1;
00525 axis.y = 0;
00526 axis.z = 0;
00527 angle = 0;
00528 }
00529 }
00530
00531
00532
00533 template<class T> Matrix4<T> Quaternion<T>::toMatrix4() const
00534 {
00535 T wx = w * x * 2;
00536 T wy = w * y * 2;
00537 T wz = w * z * 2;
00538 T xx = x * x * 2;
00539 T xy = x * y * 2;
00540 T xz = x * z * 2;
00541 T yy = y * y * 2;
00542 T yz = y * z * 2;
00543 T zz = z * z * 2;
00544
00545 return Matrix4<T>(Vector4<T>(1 - yy - zz, xy - wz, xz + wy, 0),
00546 Vector4<T>(xy + wz, 1 - xx - zz, yz - wx, 0),
00547 Vector4<T>(xz - wy, yz + wx, 1 - xx - yy, 0),
00548 Vector4<T>(0, 0, 0, 1));
00549 }
00550
00551
00552
00553 template<class T> Matrix3<T> Quaternion<T>::toMatrix3() const
00554 {
00555 T wx = w * x * 2;
00556 T wy = w * y * 2;
00557 T wz = w * z * 2;
00558 T xx = x * x * 2;
00559 T xy = x * y * 2;
00560 T xz = x * z * 2;
00561 T yy = y * y * 2;
00562 T yz = y * z * 2;
00563 T zz = z * z * 2;
00564
00565 return Matrix3<T>(Vector3<T>(1 - yy - zz, xy - wz, xz + wy),
00566 Vector3<T>(xy + wz, 1 - xx - zz, yz - wx),
00567 Vector3<T>(xz - wy, yz + wx, 1 - xx - yy));
00568 }
00569
00570
00571 template<class T> T dot(Quaternion<T> a, Quaternion<T> b)
00572 {
00573 return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
00574 }
00575
00576
00577 template<class T> Quaternion<T> Quaternion<T>::slerp(Quaternion<T> q0,
00578 Quaternion<T> q1,
00579 T t)
00580 {
00581 T c = dot(q0, q1);
00582
00583
00584 if (c > (T) 1.0)
00585 c = (T) 1.0;
00586 else if (c < (T) -1.0)
00587 c = (T) -1.0;
00588
00589 T angle = (T) acos(c);
00590
00591 if (abs(angle) < (T) 1.0e-5)
00592 return q0;
00593
00594 T s = (T) sin(angle);
00595 T is = (T) 1.0 / s;
00596
00597 return q0 * ((T) sin((1 - t) * angle) * is) +
00598 q1 * ((T) sin(t * angle) * is);
00599 }
00600
00601
00602
00603
00604 template<class T> void Quaternion<T>::rotate(Vector3<T> axis, T angle)
00605 {
00606 Quaternion q;
00607 q.setAxisAngle(axis, angle);
00608 *this = q * *this;
00609 }
00610
00611
00612
00613
00614 template<class T> void Quaternion<T>::xrotate(T angle)
00615 {
00616 T s, c;
00617
00618 Math<T>::sincos(angle * (T) 0.5, s, c);
00619 *this = Quaternion<T>(c, s, 0, 0) * *this;
00620 }
00621
00622
00623
00624 template<class T> void Quaternion<T>::yrotate(T angle)
00625 {
00626 T s, c;
00627
00628 Math<T>::sincos(angle * (T) 0.5, s, c);
00629 *this = Quaternion<T>(c, 0, s, 0) * *this;
00630 }
00631
00632
00633
00634 template<class T> void Quaternion<T>::zrotate(T angle)
00635 {
00636 T s, c;
00637
00638 Math<T>::sincos(angle * (T) 0.5, s, c);
00639 *this = Quaternion<T>(c, 0, 0, s) * *this;
00640 }
00641
00642
00643 template<class T> Quaternion<T> Quaternion<T>::xrotation(T angle)
00644 {
00645 T s, c;
00646 Math<T>::sincos(angle * (T) 0.5, s, c);
00647 return Quaternion<T>(c, s, 0, 0);
00648 }
00649
00650 template<class T> Quaternion<T> Quaternion<T>::yrotation(T angle)
00651 {
00652 T s, c;
00653 Math<T>::sincos(angle * (T) 0.5, s, c);
00654 return Quaternion<T>(c, 0, s, 0);
00655 }
00656
00657 template<class T> Quaternion<T> Quaternion<T>::zrotation(T angle)
00658 {
00659 T s, c;
00660 Math<T>::sincos(angle * (T) 0.5, s, c);
00661 return Quaternion<T>(c, 0, 0, s);
00662 }
00663
00664 #endif // _QUATERNION_H_