00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifndef __SGL_QUATERNION_HPP
00027 #define __SGL_QUATERNION_HPP
00028
00029 #include <sgl.h>
00030 #include <sglVector.hpp>
00031 #include <sglMatrix.hpp>
00032
00033
00034 template <class T>
00035 class sglQuaternion
00036 {
00037 public:
00038
00039 sglQuaternion() {};
00040
00041 sglQuaternion(T i, T j, T k, T w)
00042 {
00043 m_quat[0] = i; m_quat[1] = j;
00044 m_quat[2] = k; m_quat[3] = w;
00045 }
00046
00047 template <class S>
00048 sglQuaternion(const sglQuaternion<S>& v)
00049 {
00050 m_quat[0] = v[0];
00051 m_quat[1] = v[1];
00052 m_quat[2] = v[2];
00053 m_quat[3] = v[3];
00054 }
00055
00056 template <class S>
00057 sglQuaternion(const sglVec4<S>& v)
00058 {
00059 m_quat[0] = v[0];
00060 m_quat[1] = v[1];
00061 m_quat[2] = v[2];
00062 m_quat[3] = v[3];
00063 }
00064
00065
00066 template <class S>
00067 sglQuaternion(const sglVec3<S>& v, S a)
00068 {
00069 S len = v.length();
00070 if (len > 0.0)
00071 {
00072 double s = sin( (double)a/2.0 );
00073 m_quat[0] = (T)s * v[0]/len;
00074 m_quat[1] = (T)s * v[1]/len;
00075 m_quat[2] = (T)s * v[2]/len;
00076 m_quat[3] = (T)cos( (double)a/2.0 );
00077 }
00078 else
00079 {
00080 m_quat[0] = m_quat[1] = m_quat[2] = 0.0;
00081 m_quat[3] = 1.0;
00082 }
00083 }
00084
00085
00086 ~sglQuaternion() {};
00087
00088
00089 inline T& operator[](unsigned int i) { return m_quat[i]; }
00090 inline const T& operator[](unsigned int i) const { return m_quat[i]; }
00091
00092
00093 template <class S>
00094 inline void set(S i, S j, S k, S w)
00095 {
00096 m_quat[0] = (T)i; m_quat[1] = (T)j;
00097 m_quat[2] = (T)k; m_quat[3] = (T)w;
00098 }
00099
00100 template <class S>
00101 inline void set(const sglVec3<S> &v, S a)
00102 {
00103 S len = v.length();
00104 if (len > 0.0)
00105 {
00106 double s = sin( (double)a/2.0 );
00107 m_quat[0] = (T)s * v[0]/len;
00108 m_quat[1] = (T)s * v[1]/len;
00109 m_quat[2] = (T)s * v[2]/len;
00110 m_quat[3] = (T)cos( (double)a/2.0 );
00111 }
00112 else
00113 {
00114 m_quat[0] = m_quat[1] = m_quat[2] = 0.0;
00115 m_quat[3] = 1.0;
00116 }
00117 }
00118
00119
00120 #ifndef WIN32
00121 inline sglQuaternion& operator=(const sglQuaternion& q)
00122 {
00123 m_quat[0] = q[0];
00124 m_quat[1] = q[1];
00125 m_quat[2] = q[2];
00126 m_quat[3] = q[3];
00127 return *this;
00128 }
00129 #endif
00130
00131 template <class S>
00132 inline sglQuaternion &operator=(const sglQuaternion<S>& q)
00133 {
00134 m_quat[0] = (T)q[0];
00135 m_quat[1] = (T)q[1];
00136 m_quat[2] = (T)q[2];
00137 m_quat[3] = (T)q[3];
00138 return *this;
00139 }
00140
00141 template <class S>
00142 inline sglQuaternion &operator=(const sglVec4<S>& v)
00143 {
00144 m_quat[0] = v[0];
00145 m_quat[1] = v[1];
00146 m_quat[2] = v[2];
00147 m_quat[3] = v[3];
00148
00149 return *this;
00150 }
00151
00152
00153
00154 template <class S>
00155 inline bool operator==(const sglQuaternion<S>& q) const
00156 {
00157 return (m_quat[0] == (T)q[0] && m_quat[1] == (T)q[1] &&
00158 m_quat[2] == (T)q[2] && m_quat[3] == (T)q[3]);
00159 }
00160
00161 template <class S>
00162 inline bool operator!=(const sglQuaternion<S>& q) const
00163 {
00164 return (m_quat[0] != (T)q[0] || m_quat[1] != (T)q[1] ||
00165 m_quat[2] != (T)q[2] || m_quat[3] != (T)q[3]);
00166 }
00167
00168
00169 template <class S>
00170 inline sglQuaternion& operator+=(const sglQuaternion<S>& q)
00171 {
00172 m_quat[0] += (T)q[0]; m_quat[1] += (T)q[1];
00173 m_quat[2] += (T)q[2]; m_quat[3] += (T)q[3];
00174 return *this;
00175 }
00176
00177 template <class S>
00178 inline sglQuaternion& operator-=(const sglQuaternion<S>& q)
00179 {
00180 m_quat[0] -= (T)q[0]; m_quat[1] -= (T)q[1];
00181 m_quat[2] -= (T)q[2]; m_quat[3] -= (T)q[3];
00182 return *this;
00183 }
00184
00185 inline sglQuaternion& operator*=(const T s)
00186 {
00187 m_quat[0]*=s; m_quat[1]*=s; m_quat[2]*=s; m_quat[3]*=s;
00188 return *this;
00189 }
00190
00191 template <class S>
00192 inline sglQuaternion& operator*=(const sglQuaternion<S> &rhs)
00193 {
00194 T q0 = (m_quat[3]*(T)rhs[0] +
00195 m_quat[0]*(T)rhs[3] +
00196 m_quat[1]*(T)rhs[2] -
00197 m_quat[2]*(T)rhs[1]);
00198 T q1 = (m_quat[3]*(T)rhs[1] +
00199 m_quat[1]*(T)rhs[3] +
00200 m_quat[2]*(T)rhs[0] -
00201 m_quat[0]*(T)rhs[2]);
00202 T q2 = (m_quat[3]*(T)rhs[2] +
00203 m_quat[2]*(T)rhs[3] +
00204 m_quat[0]*(T)rhs[1] -
00205 m_quat[1]*(T)rhs[0]);
00206 T q3 = (m_quat[3]*(T)rhs[3] -
00207 m_quat[0]*(T)rhs[0] -
00208 m_quat[1]*(T)rhs[1] -
00209 m_quat[2]*(T)rhs[2]);
00210 set(q0, q1, q2, q3);
00211
00212 return *this;
00213 }
00214
00215 template <class S>
00216 inline const sglQuaternion<T> operator+(const sglQuaternion<S> &rhs) const
00217 {
00218 return sglQuaternion(m_quat[0]+(T)rhs[0],
00219 m_quat[1]+(T)rhs[1],
00220 m_quat[2]+(T)rhs[2],
00221 m_quat[3]+(T)rhs[3]);
00222 }
00223
00224 template <class S>
00225 inline const sglQuaternion<T> operator-(const sglQuaternion<S> &rhs) const
00226 {
00227 return sglQuaternion(m_quat[0]-(T)rhs[0],
00228 m_quat[1]-(T)rhs[1],
00229 m_quat[2]-(T)rhs[2],
00230 m_quat[3]-(T)rhs[3]);
00231 }
00232
00233 inline const sglQuaternion<T> operator*(T scalar) const
00234 {
00235 return sglQuaternion(m_quat[0]*scalar,
00236 m_quat[1]*scalar,
00237 m_quat[2]*scalar,
00238 m_quat[3]*scalar);
00239 }
00240
00241
00242 template <class S>
00243 inline const sglQuaternion<T> operator*(const sglQuaternion<S> &rhs) const
00244 {
00245 return sglQuaternion(m_quat[3]*(T)rhs[0] +
00246 m_quat[0]*(T)rhs[3] +
00247 m_quat[1]*(T)rhs[2] -
00248 m_quat[2]*(T)rhs[1],
00249
00250 m_quat[3]*(T)rhs[1] +
00251 m_quat[1]*(T)rhs[3] +
00252 m_quat[2]*(T)rhs[0] -
00253 m_quat[0]*(T)rhs[2],
00254
00255 m_quat[3]*(T)rhs[2] +
00256 m_quat[2]*(T)rhs[3] +
00257 m_quat[0]*(T)rhs[1] -
00258 m_quat[1]*(T)rhs[0],
00259
00260 m_quat[3]*(T)rhs[3] -
00261 m_quat[0]*(T)rhs[0] -
00262 m_quat[1]*(T)rhs[1] -
00263 m_quat[2]*(T)rhs[2]);
00264 }
00265
00266
00267 template <class S1, class S2>
00268 inline void add(const sglQuaternion<S1> &q1, const sglQuaternion<S2> &q2)
00269 {
00270 m_quat[0] = (T)q1[0] + (T)q2[0];
00271 m_quat[1] = (T)q1[1] + (T)q2[1];
00272 m_quat[2] = (T)q1[2] + (T)q2[2];
00273 m_quat[3] = (T)q1[3] + (T)q2[3];
00274 }
00275
00276 template <class S1, class S2>
00277 inline void sub(const sglQuaternion<S1>& q1,
00278 const sglQuaternion<S2>& q2)
00279 {
00280 m_quat[0] = (T)q1[0] - (T)q2[0];
00281 m_quat[1] = (T)q1[1] - (T)q2[1];
00282 m_quat[2] = (T)q1[2] - (T)q2[2];
00283 m_quat[3] = (T)q1[3] - (T)q2[3];
00284 }
00285
00286 template <class S>
00287 inline void scale(const sglQuaternion<S> &q, T s)
00288 {
00289 m_quat[0] = (T)q[0]*s;
00290 m_quat[1] = (T)q[1]*s;
00291 m_quat[2] = (T)q[2]*s;
00292 m_quat[3] = (T)q[3]*s;
00293 }
00294
00295
00296 template <class S>
00297 inline void mul(const sglQuaternion<S> &rhs)
00298 {
00299 T q0 = (m_quat[3]*(T)rhs[0] +
00300 m_quat[0]*(T)rhs[3] +
00301 m_quat[1]*(T)rhs[2] -
00302 m_quat[2]*(T)rhs[1]);
00303 T q1 = (m_quat[3]*(T)rhs[1] +
00304 m_quat[1]*(T)rhs[3] +
00305 m_quat[2]*(T)rhs[0] -
00306 m_quat[0]*(T)rhs[2]);
00307 T q2 = (m_quat[3]*(T)rhs[2] +
00308 m_quat[2]*(T)rhs[3] +
00309 m_quat[0]*(T)rhs[1] -
00310 m_quat[1]*(T)rhs[0]);
00311 T q3 = (m_quat[3]*(T)rhs[3] -
00312 m_quat[0]*(T)rhs[0] -
00313 m_quat[1]*(T)rhs[1] -
00314 m_quat[2]*(T)rhs[2]);
00315 set(q0, q1, q2, q3);
00316 }
00317
00318
00319 template <class S>
00320 inline bool almostEqual(const sglQuaternion<S>& q, double eps) const
00321 {
00322 return (SGL_ALMOST_EQUAL(m_quat[0], q[0], eps) &&
00323 SGL_ALMOST_EQUAL(m_quat[1], q[1], eps) &&
00324 SGL_ALMOST_EQUAL(m_quat[2], q[2], eps) &&
00325 SGL_ALMOST_EQUAL(m_quat[3], q[3], eps));
00326 }
00327
00328
00329 template <class S>
00330 inline T dot(const sglQuaternion<S>& q) const
00331 {
00332 return (m_quat[0]*(T)q[0] + m_quat[1]*(T)q[1] +
00333 m_quat[2]*(T)q[2] + m_quat[3]*(T)q[3]);
00334 }
00335
00336 template <class S, class R>
00337 inline static R dot(const sglQuaternion<R>& q1, const sglQuaternion<S>& q2)
00338 {
00339 return (q1[0]*(R)q2[0] + q1[1]*(R)q2[1] +
00340 q1[2]*(R)q2[2] + q1[3]*(R)q2[3]);
00341 }
00342
00343 inline T norm() const
00344 {
00345 return (T) sqrt(dot(*this));
00346 }
00347
00348 inline T normalize()
00349 {
00350 T len = norm();
00351 if ( len != 0.0 )
00352 *this *= (1.0/len);
00353 return len;
00354 }
00355
00356 template <class S>
00357 inline T normalize(const sglQuaternion<S> &q)
00358 {
00359 T len = (T)q.norm();
00360 if (len > 0.0)
00361 scale(q, 1.0/len);
00362 return len;
00363 }
00364
00365 inline void invert()
00366 {
00367 T len = norm();
00368 if (len > 0.0)
00369 {
00370 set(-m_quat[0]/len,
00371 -m_quat[1]/len,
00372 -m_quat[2]/len,
00373 m_quat[3]/len);
00374 }
00375 else
00376 buildIdentity();
00377 }
00378
00379 inline const sglQuaternion<T> conjugate( void ) const
00380 {
00381 T len = norm();
00382 if (len > 0.0)
00383 {
00384 return sglQuaternion(-m_quat[0]/len,
00385 -m_quat[1]/len,
00386 -m_quat[2]/len,
00387 m_quat[3]/len);
00388 }
00389 else
00390 return sglQuaternion(0.0, 0.0, 0.0, 1.0);
00391 }
00392
00393
00394
00395 inline void buildIdentity()
00396 {
00397 m_quat[0] = m_quat[1] = m_quat[2] = 0.0;
00398 m_quat[1] = 1.0;
00399 }
00400
00401 template <class S>
00402 inline void buildFromAxisAngle(const sglVec4<S> &v, S angle)
00403 {
00404 S len = v.norm();
00405 if (len > 0.0)
00406 {
00407 double s = sin( (T)angle/2.0 );
00408 m_quat[0] = s * (T)v[0]/len;
00409 m_quat[1] = s * (T)v[1]/len;
00410 m_quat[2] = s * (T)v[2]/len;
00411 m_quat[3] = cos( (T)angle/2.0 );
00412 }
00413 else
00414 {
00415 m_quat[0] = m_quat[1] = m_quat[2] = 0.0;
00416 m_quat[3] = 1.0;
00417 }
00418 }
00419
00420 template <class S>
00421 inline void buildFromTransformation(const sglMat4<S> &mat)
00422 {
00423 double trace = mat[0][0] + mat[1][1] + mat[2][2];
00424 if (trace > 0.)
00425 {
00426 double s = sqrt(trace + 1.);
00427 m_quat[3] = (T)(s*0.5);
00428 s = 0.5/s;
00429 m_quat[0] = (T)((mat[1][2] - mat[2][1])*s);
00430 m_quat[1] = (T)((mat[2][0] - mat[0][2])*s);
00431 m_quat[2] = (T)((mat[0][1] - mat[1][0])*s);
00432 }
00433 else
00434 {
00435 unsigned int ix = 0;
00436 if (mat[1][1] > mat[0][0]) ix = 1;
00437 if (mat[2][2] > mat[1][1]) ix = 2;
00438 unsigned int iy = (ix+1)%3;
00439 unsigned int iz = (iy+1)%3;
00440
00441 double s = sqrt((mat[ix][ix] - (mat[iy][iy] + mat[iz][iz])) + 1.);
00442 m_quat[ix] = (T)(s*0.5);
00443
00444 if (s != 0.) s = 0.5/s;
00445 m_quat[3] = (T)((mat[iy][iz] - mat[iz][iy])*s);
00446 m_quat[iy] = (T)((mat[ix][iy] + mat[iy][ix])*s);
00447 m_quat[iz] = (T)((mat[ix][iz] + mat[iz][ix])*s);
00448 }
00449 }
00450
00451
00452
00453
00454
00455 template <class S>
00456 inline void getAxisAngle(sglVec3<S> &axis, S &angle) const
00457 {
00458 if (SGL_ALMOST_EQUAL(norm(), 1.0, 1.0e-4))
00459 {
00460 double st2 = sqrt(m_quat[0]*m_quat[0] +
00461 m_quat[1]*m_quat[1] +
00462 m_quat[2]*m_quat[2]);
00463 angle = 2.0*atan2(st2, m_quat[3]);
00464
00465 if (st2 > 1.0e-5)
00466 {
00467 axis.set((S)m_quat[0]/st2,
00468 (S)m_quat[1]/st2,
00469 (S)m_quat[2]/st2);
00470 }
00471 else
00472 {
00473 axis.set(1,0,0);
00474 }
00475 }
00476 else
00477 {
00478 axis.set(0,0,0);
00479 angle = 0;
00480 }
00481 }
00482
00483 inline const sglMat4<T> getTransformation( void ) const
00484 {
00485 T Nq = dot( *this );
00486 T s = (Nq > 0.0) ? (2.0 / Nq) : 0.0;
00487 T xs = m_quat[0] * s;
00488 T ys = m_quat[1] * s;
00489 T zs = m_quat[2] * s;
00490 T wx = m_quat[3] * xs;
00491 T wy = m_quat[3] * ys;
00492 T wz = m_quat[3] * zs;
00493 T xx = m_quat[0] * xs;
00494 T xy = m_quat[0] * ys;
00495 T xz = m_quat[0] * zs;
00496 T yy = m_quat[1] * ys;
00497 T yz = m_quat[1] * zs;
00498 T zz = m_quat[2] * zs;
00499
00500 return sglMat4<T>(1.0-(yy + zz), xy + wz, xz - wy, 0.0,
00501 xy - wz, 1.0-(xx + zz), yz + wx, 0.0,
00502 xz + wy, yz - wx, 1.0-(xx + yy), 0.0,
00503 0.0, 0.0, 0.0, 1.0);
00504 }
00505
00506 template <class S>
00507 inline sglVec3<S> rotate(const sglVec3<S> &vec) const
00508 {
00509 if (SGL_ALMOST_EQUAL(norm(), 1.0, 1.0e-4))
00510 {
00511 S ss = (S)m_quat[3]*m_quat[3];
00512 S vdotn = (vec[0]*(S)m_quat[0] +
00513 vec[1]*(S)m_quat[1] +
00514 vec[2]*(S)m_quat[2]);
00515 sglVec3<S> ncrossv((S)m_quat[1]*vec[2] - (S)m_quat[2]*vec[1],
00516 (S)m_quat[2]*vec[0] - (S)m_quat[0]*vec[2],
00517 (S)m_quat[0]*vec[1] - (S)m_quat[1]*vec[0]);
00518 sglVec3<S> svnv(m_quat[3]*vec[0] + ncrossv[0],
00519 m_quat[3]*vec[1] + ncrossv[1],
00520 m_quat[3]*vec[2] + ncrossv[2]);
00521
00522 return sglVec3<S>(
00523 ss*vec[0] + m_quat[3]*ncrossv[0] + vdotn*m_quat[0] +
00524 m_quat[1]*svnv[2] - m_quat[2]*svnv[1],
00525 ss*vec[1] + m_quat[3]*ncrossv[1] + vdotn*m_quat[1] +
00526 m_quat[2]*svnv[0] - m_quat[0]*svnv[2],
00527 ss*vec[2] + m_quat[3]*ncrossv[2] + vdotn*m_quat[2] +
00528 m_quat[0]*svnv[1] - m_quat[1]*svnv[0]);
00529 }
00530 else
00531 {
00532
00533 sglQuaternion<S> result =
00534 *this * sglQuaternion<S>(vec, (S)0.0) * (*this).conjugate();
00535 return sglVec3<S>((S)result[0], (S)result[1], (S)result[2]);
00536 }
00537 }
00538
00539
00540 #if defined(TEMPLATE_OSTREAM_HACK)
00541 template <class S>
00542 friend ostream& operator<<(ostream& ostrm, const sglQuaternion<S>& q);
00543
00544 template <class S>
00545 friend istream& operator>>(istream& istrm, sglQuaternion<S>& q);
00546 #else
00547 friend ostream& operator<<(ostream& ostrm, const sglQuaternion<T>& q)
00548 {
00549 return (ostrm << "(" << q[0] << ", " << q[1] << ", "
00550 << q[2] << " : " << q[3] << ")");
00551 }
00552
00553 friend istream& operator>>(istream& istrm, sglQuaternion<T>& q)
00554 {
00555 return (istrm >> q[0] >> q[1] >> q[2] >> q[3]);
00556 }
00557 #endif
00558 private:
00559 T m_quat[4];
00560 };
00561
00562
00563 #if defined(TEMPLATE_OSTREAM_HACK)
00564 template <class T>
00565 inline ostream& operator<<(ostream& ostrm, const sglQuaternion<T>& q)
00566 {
00567 return (ostrm << "(" << q[0] << ", " << q[1] << ", "
00568 << q[2] << " : " << q[3] << ")");
00569 }
00570
00571 template <class T>
00572 inline istream& operator>>(istream& istrm, sglQuaternion<T>& vec)
00573 {
00574 return (istrm >> q[0] >> q[1] >> q[2] >> q[3]);
00575 }
00576 #endif
00577
00578 typedef sglQuaternion<double> sglQuaterniond;
00579 typedef sglQuaternion<float> sglQuaternionf;
00580
00581 #endif