00001 #ifndef __QUAT_H__
00002 #define __QUAT_H__
00003
00004 #include <cmath>
00005
00006 #ifdef PHYSX
00007 #include <PxPhysicsAPI.h>
00008 #endif
00009
00010 #include <math/config.hpp>
00011 #include <math/free.hpp>
00012 #include <math/vec3.hpp>
00013
00014 namespace math {
00015 template <typename T> class quat {
00016 public:
00017
00018 quat() {
00019 loadZero();
00020 }
00021 quat(double nx, double ny, double nz, double nw): w(nw),x(nx),y(ny),z(nz) {}
00022 quat(double angleRadians, vec3<double> const & axis) {
00023 vec3<double> unitAxis(axis);
00024
00025 unitAxis.Normalize();
00026
00027 const double a = angleRadians * 0.5f;
00028 const double s = sin(a);
00029 w = cos(a);
00030 x = unitAxis.v[0] * s;
00031 y = unitAxis.v[1] * s;
00032 z = unitAxis.v[2] * s;
00033 }
00034 quat(math::quat<T> const & v): w(v.w), x(v.x), y(v.y), z(v.z) {}
00035 quat(math::vec3<double> const & u, math::vec3<double> const & v) {
00036 math::vec3<double> a(u);
00037 math::vec3<double> b(v);
00038
00039 a.Normalize();
00040 b.Normalize();
00041
00042 math::vec3<double> c = a.cross(b);
00043
00044 x = c.v[0];
00045 y = c.v[1];
00046 z = c.v[2];
00047
00048 w = a.dot(b);
00049
00050 if(!isSane()) {
00051 printf("a b c\n");
00052 a.print();
00053 b.print();
00054 c.print();
00055 throw;
00056 }
00057 }
00058 quat(mat44<T> const & m) {
00059 double m00 = m.entries[0];
00060 double m01 = m.entries[1];
00061 double m02 = m.entries[2];
00062 double m10 = m.entries[4];
00063 double m11 = m.entries[5];
00064 double m12 = m.entries[6];
00065 double m20 = m.entries[8];
00066 double m21 = m.entries[9];
00067 double m22 = m.entries[10];
00068
00069 double tr = m00 + m11 + m22;
00070
00071 if (tr > 0)
00072 {
00073 double S = sqrt(tr+1.0) * 2;
00074 w = 0.25 * S;
00075 x = (m21 - m12) / S;
00076 y = (m02 - m20) / S;
00077 z = (m10 - m01) / S;
00078 }
00079 else if ((m00 > m11)&(m00 > m22))
00080 {
00081 double S = sqrt(1.0 + m00 - m11 - m22) * 2;
00082 w = (m21 - m12) / S;
00083 x = 0.25 * S;
00084 y = (m01 + m10) / S;
00085 z = (m02 + m20) / S;
00086 }
00087 else if (m11 > m22)
00088 {
00089 double S = sqrt(1.0 + m11 - m00 - m22) * 2;
00090 w = (m02 - m20) / S;
00091 x = (m01 + m10) / S;
00092 y = 0.25 * S;
00093 z = (m12 + m21) / S;
00094 }
00095 else
00096 {
00097 double S = sqrt(1.0 + m22 - m00 - m11) * 2;
00098 w = (m10 - m01) / S;
00099 x = (m02 + m20) / S;
00100 y = (m12 + m21) / S;
00101 z = 0.25 * S;
00102 }
00103 }
00104 void loadZero() {
00105 x = y = z = 0.0;
00106 w = 1.0;
00107 }
00108 bool isFinite() const
00109 {
00110 return std::isfinite(x)
00111 && std::isfinite(y)
00112 && std::isfinite(z)
00113 && std::isfinite(w);
00114 }
00115 bool isUnit() const
00116 {
00117 const double unitTolerance = 1e-4;
00118 return isFinite() && (std::abs(magnitude()-1) < unitTolerance);
00119 }
00120 bool isSane() const
00121 {
00122 const double unitTolerance = double(1e-4);
00123 if(!isFinite()) return false;
00124
00125 if(std::abs(magnitude()-1) < unitTolerance) {
00126 return true;
00127 } else {
00128 printf("%lf\n", magnitude()-1);
00129 return false;
00130 }
00131 }
00132 void toRadiansAndUnitAxis(double& angle, vec3<double>& axis) const
00133 {
00134 const double Epsilon = (double(1.0e-8f));
00135 const double s2 = x*x+y*y+z*z;
00136 if(s2 < (Epsilon*Epsilon)) {
00137 angle = 0;
00138 axis = vec3<double>(1,0,0);
00139 } else {
00140 const double s = math::recipsqrt(s2);
00141 axis = vec3<double>(x,y,z) * s;
00142 angle = (std::abs(w) < Epsilon) ? M_PI : atan((s2*s)/w) * 2;
00143 }
00144
00145 }
00146 double getAngle() const
00147 {
00148 const double unitTolerance = 1e-6;
00149
00150 if(w > 1.0) {
00151 if(fabs(w - 1.0) < unitTolerance) {
00152 return 0.0;
00153 }
00154
00155 printf("quat<T> getAngle\n");
00156 printf("w %e\n",w-1.0);
00157 throw;
00158 }
00159
00160 if(w < -1.0) {
00161 if(fabs(w + 1.0) < unitTolerance) {
00162 return M_PI;
00163 }
00164
00165 printf("quat<T> getAngle\n");
00166 printf("w %e\n",w+1.0);
00167 throw;
00168 }
00169
00170 if(isnan(acos(w))) {
00171 printf("%f\n",w);
00172 throw;
00173 }
00174
00175 return acos(w) * double(2);
00176 }
00177 double getAngle(const math::quat<T>& q) const
00178 {
00179 return acos(dot(q)) * double(2);
00180 }
00181 double magnitudeSquared() const
00182 {
00183 return x*x + y*y + z*z + w*w;
00184 }
00185 double dot(const math::quat<T>& v) const
00186 {
00187 return x * v.x + y * v.y + z * v.z + w * v.w;
00188 }
00189 math::quat<T> getNormalized() const
00190 {
00191 const double s = 1.0f / magnitude();
00192 return math::quat<T>(x*s, y*s, z*s, w*s);
00193 }
00194 double magnitude() const
00195 {
00196 return sqrt(magnitudeSquared());
00197 }
00198 double normalize()
00199 {
00200 const double mag = magnitude();
00201 if(mag)
00202 {
00203 const double imag = 1.0f / mag;
00204
00205 x *= imag;
00206 y *= imag;
00207 z *= imag;
00208 w *= imag;
00209 }
00210 return mag;
00211 }
00212 math::quat<T> getConjugate() const
00213 {
00214 return math::quat<T>(-x,-y,-z,w);
00215 }
00216 math::vec3<double> getImaginaryPart() const
00217 {
00218 return math::vec3<double>(x,y,z);
00219 }
00220 math::vec3<double> getBasisVector0() const
00221 {
00222
00223 const double x2 = x*2.0f;
00224 const double w2 = w*2.0f;
00225 return math::vec3<double>(
00226 (w * w2) - 1.0f + x*x2,
00227 (z * w2) + y*x2,
00228 (-y * w2) + z*x2);
00229 }
00230 math::vec3<double> getBasisVector1() const
00231 {
00232
00233 const double y2 = y*2.0f;
00234 const double w2 = w*2.0f;
00235 return math::vec3<double>(
00236 (-z * w2) + x*y2,
00237 (w * w2) - 1.0f + y*y2,
00238 (x * w2) + z*y2);
00239 }
00240 math::vec3<double> getBasisVector2() const
00241 {
00242
00243 const double z2 = z*2.0f;
00244 const double w2 = w*2.0f;
00245 return math::vec3<double>(
00246 (y * w2) + x*z2,
00247 (-x * w2) + y*z2,
00248 (w * w2) - 1.0f + z*z2);
00249 }
00250 const math::vec3<double> rotate(const math::vec3<double>& v) const
00251 {
00252 const double vx = 2.0f*v.v[0];
00253 const double vy = 2.0f*v.v[1];
00254 const double vz = 2.0f*v.v[2];
00255 const double w2 = w*w-0.5f;
00256 const double dot2 = (x*vx + y*vy +z*vz);
00257 return math::vec3<double>
00258 (
00259 (vx*w2 + (y * vz - z * vy)*w + x*dot2),
00260 (vy*w2 + (z * vx - x * vz)*w + y*dot2),
00261 (vz*w2 + (x * vy - y * vx)*w + z*dot2)
00262 );
00263
00264
00265
00266
00267 }
00268 const math::vec3<double> rotateInv(const math::vec3<double>& v) const
00269 {
00270 const double vx = 2.0f*v.v[0];
00271 const double vy = 2.0f*v.v[1];
00272 const double vz = 2.0f*v.v[2];
00273 const double w2 = w*w-0.5f;
00274 const double dot2 = (x*vx + y*vy +z*vz);
00275 return math::vec3<double>
00276 (
00277 (vx*w2 - (y * vz - z * vy)*w + x*dot2),
00278 (vy*w2 - (z * vx - x * vz)*w + y*dot2),
00279 (vz*w2 - (x * vy - y * vx)*w + z*dot2)
00280 );
00281
00282
00283 }
00284 math::quat<T>& operator=(const math::quat<T>& p) {
00285 x = p.x; y = p.y; z = p.z; w = p.w; return *this;
00286 }
00287 math::quat<T>& operator*= (const math::quat<T>& q) {
00288 const double tx = w*q.x + q.w*x + y*q.z - q.y*z;
00289 const double ty = w*q.y + q.w*y + z*q.x - q.z*x;
00290 const double tz = w*q.z + q.w*z + x*q.y - q.x*y;
00291
00292 w = w*q.w - q.x*x - y*q.y - q.z*z;
00293 x = tx;
00294 y = ty;
00295 z = tz;
00296
00297 return *this;
00298 }
00299 math::quat<T>& operator+= (const math::quat<T>& q) {
00300 x+=q.x;
00301 y+=q.y;
00302 z+=q.z;
00303 w+=q.w;
00304 return *this;
00305 }
00306 math::quat<T>& operator-= (const math::quat<T>& q) {
00307 x-=q.x;
00308 y-=q.y;
00309 z-=q.z;
00310 w-=q.w;
00311 return *this;
00312 }
00313 math::quat<T>& operator*= (const double s) {
00314 x*=s;
00315 y*=s;
00316 z*=s;
00317 w*=s;
00318 return *this;
00319 }
00320 math::quat<T> operator*(const math::quat<T>& q) const {
00321 return math::quat<T>(w*q.x + q.w*x + y*q.z - q.y*z,
00322 w*q.y + q.w*y + z*q.x - q.z*x,
00323 w*q.z + q.w*z + x*q.y - q.x*y,
00324 w*q.w - x*q.x - y*q.y - z*q.z);
00325 }
00326 math::quat<T> operator+(const math::quat<T>& q) const
00327 {
00328 return math::quat<T>(x+q.x,y+q.y,z+q.z,w+q.w);
00329 }
00330 math::quat<T> operator-() const
00331 {
00332 return math::quat<T>(-x,-y,-z,-w);
00333 }
00334 math::quat<T> operator-(const math::quat<T>& q) const
00335 {
00336 return math::quat<T>(x-q.x,y-q.y,z-q.z,w-q.w);
00337 }
00338 math::quat<T> operator*(double r) const {
00339 return math::quat<T>(x*r,y*r,z*r,w*r);
00340 }
00341 math::quat<T> createIdentity() {
00342 return math::quat<T>(0,0,0,1);
00343 }
00344 void print() {
00345 printf("%f %f %f %f\n", x, y, z, w);
00346 }
00347 math::vec3<double> getOmega(double dt) {
00348 vec3<double> v = getImaginaryPart();
00349
00350 vec3<double> omega;
00351
00352 if (v.magnitude() > 1.0) {
00353 printf("%e\n",v.magnitude() - 1.0);
00354 throw;
00355 }
00356
00357 if (v.magnitude() > 0.0) {
00358 v.Normalize();
00359 omega = v * getAngle() / dt;
00360 }
00361
00362 if(omega.IsNan()) throw;
00363
00364 return omega;
00365 }
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378 quat(T nx, T ny, T nz, T nw);
00379 quat(T angleRadians, vec3<T> const & axis);
00380 quat(vec3<T> const &, vec3<T> const &);
00381
00388 quat<T> slerp(math::quat<T> q1, float u) {
00389 math::quat<T> q0(*this);
00390
00391 q0.normalize();
00392 q1.normalize();
00393
00394 math::quat<T> z = q0 * q1.getConjugate();
00395 float t = acos(z.w);
00396
00397 math::quat<T> q = q0 * (sin((1-u)*t) / sin(t)) + q1 * (sin(u*t) / sin(t));
00398
00399 return q;
00400 }
00405 void toRadiansAndUnitAxis(T& angle, vec3<T>& axis) const;
00406 const vec3<T> rotate(const vec3<T>& v) const;
00407 const vec3<T> rotateInv(const vec3<T>& v) const;
00408 quat<T>& operator*= (const T s);
00409 quat<T> operator*(T r) const;
00410 #ifdef PHYSX
00411
00412 operator physx::PxQuat() const { return physx::PxQuat(x,y,z,w); }
00413 quat<T>& operator=(physx::PxQuat const & rhs) {
00414 x=rhs.x;
00415 y=rhs.y;
00416 z=rhs.z;
00417 w=rhs.w;
00418 return *this;
00419 }
00420 #endif
00421
00422 vec3<T> getOmega(T dt);
00423
00424
00425 T w,x,y,z;
00426 };
00427 }
00428
00430 #endif // PX_FOUNDATION_PX_QUAT_H