Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

Quaternion.cpp

00001 /*************************************************************************** 00002 * This file is part of OpenCAL: Open Computer Animation Library * 00003 * I created OpenCAL as my master's thesis Computer Science (multimedia) * 00004 * at the tUL university in Diepenbeek, Belgium * 00005 * * 00006 * Copyright (C) 2003-2004 by Jeroen Dierckx * 00007 * jeroen.dierckx@student.luc.ac.be * 00008 * * 00009 ***************************************************************************/ 00010 00011 // Includes 00012 #include "Quaternion.h" 00013 using namespace OpenCAL::Utils; 00014 00015 #include <math.h> 00016 00017 using namespace std; 00018 00019 00020 // Static members 00021 const Quaternion Quaternion::identity(1.0f, Vector3::zero); 00022 00023 00024 /****************************** 00025 * Constructors and destructor * 00026 ******************************/ 00027 00028 Quaternion::Quaternion() 00029 : m_scalar(1.0f), m_vector(0.0f, 0.0f, 0.0f) 00030 { 00031 } 00032 00033 Quaternion::Quaternion(float scalar, const Vector3 &vector) 00034 : m_scalar(scalar), m_vector(vector) 00035 { 00036 } 00037 00038 Quaternion::~Quaternion() 00039 { 00040 } 00041 00042 00043 /************************ 00044 * Get and set functions * 00045 ************************/ 00046 00047 00048 /********************* 00049 * Operator functions * 00050 *********************/ 00051 00056 Quaternion Quaternion::operator+(const Quaternion &q) const 00057 { 00058 return Quaternion( 00059 m_scalar + q.m_scalar, 00060 m_vector + q.m_vector 00061 ); 00062 } 00063 00064 Quaternion Quaternion::operator-(const Quaternion &q) const 00065 { 00066 return Quaternion( 00067 m_scalar - q.m_scalar, 00068 m_vector - q.m_vector 00069 ); 00070 } 00071 00082 Quaternion Quaternion::operator*(const Quaternion &q) const 00083 { 00084 return Quaternion( 00085 m_scalar * q.m_scalar - m_vector.dotProduct(q.m_vector), 00086 m_scalar * q.m_vector + q.m_scalar * m_vector + m_vector.crossProduct(q.m_vector) 00087 ); 00088 } 00089 00090 Quaternion Quaternion::operator*(const Vector3 &v) const 00091 { 00092 return operator*(Quaternion(0, v)); 00093 } 00094 00095 Quaternion Quaternion::operator*(float factor) const 00096 { 00097 return Quaternion( 00098 m_scalar * factor, 00099 m_vector * factor 00100 ); 00101 } 00102 00103 Quaternion Quaternion::operator/(float factor) const 00104 { 00105 return Quaternion( 00106 m_scalar / factor, 00107 m_vector / factor 00108 ); 00109 } 00110 00111 void Quaternion::operator+=(const Quaternion &q) 00112 { 00113 m_scalar += q.m_scalar; 00114 m_vector += q.m_vector; 00115 } 00116 00117 void Quaternion::operator-=(const Quaternion &q) 00118 { 00119 m_scalar -= q.m_scalar; 00120 m_vector -= q.m_vector; 00121 } 00122 00123 void Quaternion::operator*=(const Quaternion &q) 00124 { 00125 float scalar = m_scalar * q.m_scalar - m_vector.dotProduct(q.m_vector); 00126 m_vector = m_scalar * q.m_vector + q.m_scalar * m_vector + m_vector.crossProduct(q.m_vector); 00127 m_scalar = scalar; 00128 } 00129 00130 void Quaternion::operator*=(const Vector3 &v) 00131 { 00132 operator*=(Quaternion(0, v)); 00133 } 00134 00135 void Quaternion::operator*=(float factor) 00136 { 00137 m_scalar *= factor; 00138 m_vector *= factor; 00139 } 00140 00141 void Quaternion::operator/=(float factor) 00142 { 00143 m_scalar /= factor; 00144 m_vector /= factor; 00145 } 00146 00147 Quaternion Quaternion::operator-() const 00148 { 00149 return Quaternion( 00150 -m_scalar, 00151 -m_vector 00152 ); 00153 } 00154 00155 bool Quaternion::operator==(const Quaternion &q) const 00156 { 00157 return m_scalar == q.m_scalar && m_vector == q.m_vector; 00158 } 00159 00160 bool Quaternion::operator!=(const Quaternion &q) const 00161 { 00162 return m_scalar != q.m_scalar || m_vector != q.m_vector; 00163 } 00164 00165 // Friend functions 00166 Quaternion OpenCAL::Utils::operator*(const Vector3 &v, const Quaternion &q) 00167 { 00168 return Quaternion(0, v) * q; 00169 } 00170 00171 Quaternion OpenCAL::Utils::operator*(float factor, const Quaternion &q) 00172 { 00173 return Quaternion( 00174 factor * q.m_scalar, 00175 factor * q.m_vector 00176 ); 00177 } 00178 00179 Quaternion OpenCAL::Utils::operator/(float factor, const Quaternion &q) 00180 { 00181 return Quaternion( 00182 factor / q.m_scalar, 00183 factor / q.m_vector 00184 ); 00185 } 00186 00187 00188 /************ 00189 * Magnitude * 00190 ************/ 00191 00196 float Quaternion::magnitude() const 00197 { 00198 return sqrtf( 00199 m_scalar * m_scalar + 00200 m_vector.getX() * m_vector.getX() + 00201 m_vector.getY() * m_vector.getY() + 00202 m_vector.getZ() * m_vector.getZ() 00203 ); 00204 } 00205 00206 float Quaternion::magnitudeSquared() const 00207 { 00208 return ( 00209 m_scalar * m_scalar + 00210 m_vector.getX() * m_vector.getX() + 00211 m_vector.getY() * m_vector.getY() + 00212 m_vector.getZ() * m_vector.getZ() 00213 ); 00214 } 00215 00225 void Quaternion::inverse() 00226 { 00227 float msi = 1.0f / magnitudeSquared(); 00228 00229 m_scalar *= msi; 00230 m_vector *= -msi; 00231 } 00232 00236 Quaternion Quaternion::inversed() const 00237 { 00238 float msi = 1.0f / magnitudeSquared(); 00239 00240 return Quaternion(m_scalar * msi, -m_vector * msi); 00241 } 00242 00246 void Quaternion::inversed(Quaternion *q) const 00247 { 00248 float msi = 1.0f / magnitudeSquared(); 00249 00250 q->setScalar(m_scalar * msi); 00251 q->setVector(-m_vector * msi); 00252 } 00253 00259 void Quaternion::normalize() 00260 { 00261 float mag = magnitude(); 00262 00263 m_scalar /= mag; 00264 m_vector /= mag; 00265 } 00266 00267 Quaternion Quaternion::normalized() const 00268 { 00269 float mag = magnitude(); 00270 00271 return Quaternion(m_scalar / mag, m_vector / mag); 00272 } 00273 00274 void Quaternion::normalized(Quaternion *q) const 00275 { 00276 float mag = magnitude(); 00277 00278 q->setScalar(m_scalar / mag); 00279 q->setVector(m_vector / mag); 00280 } 00281 00282 00283 /************** 00284 * Dot product * 00285 **************/ 00286 00287 float Quaternion::dotProduct(const Quaternion &q) const 00288 { 00289 return m_scalar * q.m_scalar + m_vector.dotProduct(q.m_vector); 00290 } 00291 00292 00300 Quaternion Quaternion::slerped(float u, const Quaternion &source, const Quaternion &dest) const 00301 { 00302 float cosAngle = source.dotProduct(dest); 00303 float angle, sinAngle, a, b; 00304 00305 if(cosAngle > 0) // Interpolate to dest 00306 { 00307 angle = acosf(cosAngle); 00308 sinAngle = sinf(angle); 00309 a = sinf((1.0f - u) * angle) / sinAngle; 00310 b = sinf(u * angle) / sinAngle; 00311 } 00312 else // Interpolate to -dest 00313 { 00314 angle = 2 * Math::pi - acosf(cosAngle); 00315 sinAngle = sinf(angle); 00316 a = sinf((1.0f - u) * angle) / sinAngle; 00317 b = -sinf(u * angle) / sinAngle; 00318 } 00319 00320 return (a * source + b * dest).normalized(); 00321 } 00322 00323 00324 /************************ 00325 * Axis - Angle rotation * 00326 ************************/ 00327 00328 Quaternion Quaternion::createFromAxisAngle(const Vector3 &axis, float degrees) 00329 { 00330 while(degrees < 0.0f) 00331 degrees += 360.0f; 00332 while(degrees >= 360.0f) 00333 degrees -= 360.0f; 00334 00335 float halfAngle = Math::degToRad(degrees * 0.5f); 00336 00337 return Quaternion( 00338 cosf(halfAngle), 00339 sinf(halfAngle) * axis 00340 ); 00341 } 00342 00349 void Quaternion::fromAxisAngle(const Vector3 &axis, float degrees) 00350 { 00351 while(degrees < 0.0f) 00352 degrees += 360.0f; 00353 while(degrees >= 360.0f) 00354 degrees -= 360.0f; 00355 00356 float halfAngle = Math::degToRad(degrees * 0.5f); 00357 00358 m_scalar = cosf(halfAngle); 00359 m_vector = sinf(halfAngle) * axis; 00360 } 00361 00362 void Quaternion::toAxisAngle(Vector3 *axis, float *degrees) const 00363 { 00364 /* 00365 float halfAngle = acosf(m_scalar); 00366 cout << "Half Angle: " << halfAngle << endl; 00367 00368 *degrees = 2 * halfAngle * RADTODEG; 00369 *axis = m_vector / sinf(halfAngle); 00371 */ 00372 00373 /* 00374 // From Euclideanspace.com 00375 float s = sqrtf(1 - m_scalar * m_scalar); 00376 if(s > -0.001f && s < 0.001f) s = 1.0f; 00377 00378 *degrees = 2 * acosf(m_scalar) * RADTODEG; 00379 *axis = m_vector / s; 00380 */ 00381 00382 // From http://www.magic-software.com 00383 if(m_scalar > 1 || m_scalar < -1) // This can't happen if the quaternion is normalized 00384 { 00385 cerr << "The quaternion isn't normalized while converting to axis-angle!!" << endl; 00386 return; 00387 } 00388 00389 if(m_scalar == 1 || m_scalar == -1) // No rotation 00390 { 00391 *degrees = 0.0f; 00392 *axis = Vector3(1,0,0); 00393 } 00394 else 00395 { 00396 *degrees = Math::radToDeg(2 * acosf(m_scalar)); 00397 *axis = m_vector / sqrtf(1.0f - Math::squared(m_scalar)); 00398 } 00399 } 00400 00401 00402 /*********************** 00403 * Euler angle rotation * 00404 ***********************/ 00405 00406 void Quaternion::fromEulerAngle(float rotX, float rotY, float rotZ) 00407 { 00408 Quaternion x, y, z; 00409 x.fromAxisAngle(Vector3(1.0f, 0.0f, 0.0f), rotX); 00410 y.fromAxisAngle(Vector3(0.0f, 1.0f, 0.0f), rotY); 00411 z.fromAxisAngle(Vector3(0.0f, 0.0f, 1.0f), rotZ); 00412 00413 *this = z * y * x; 00414 } 00415 00416 void Quaternion::fromEulerAngle(const Vector3 &rot) 00417 { 00418 fromEulerAngle(rot.getX(), rot.getY(), rot.getZ()); 00419 } 00420 00421 Vector3 Quaternion::toEulerAngle() const 00422 { 00424 return Vector3::zero; 00425 } 00426 00427 void Quaternion::toEulerAngle(float *rotX, float *rotY, float *rotZ) const 00428 { 00430 *rotX = *rotY = *rotZ = 0.0f; 00431 } 00432 00433 void Quaternion::toEulerAngle(Vector3 *rot) const 00434 { 00436 *rot = Vector3::zero; 00437 } 00438 00439 00440 /****************** 00441 * Matrix rotation * 00442 ******************/ 00443 00444 void Quaternion::fromMatrix33(const Matrix33 &matrix) 00445 { 00446 float m00 = matrix.get(0,0); 00447 float m11 = matrix.get(1,1); 00448 float m22 = matrix.get(2,2); 00449 00450 m_scalar = sqrtf(m00 + m11 + m22 + 1.0f) * 0.5f; 00451 00452 float temp = 1 - 2 * m_scalar * m_scalar; 00453 m_vector.setX(sqrtf((m00 + temp) * 0.5f)); 00454 m_vector.setY(sqrtf((m11 + temp) * 0.5f)); 00455 m_vector.setZ(sqrtf((m22 + temp) * 0.5f)); 00456 } 00457 00458 Matrix33 Quaternion::toMatrix33() const 00459 { 00460 Matrix33 result; 00461 toMatrix33(&result); 00462 return result; 00463 } 00464 00469 void Quaternion::toMatrix33(Matrix33 *matrix) const 00470 { 00471 matrix->identity(); 00472 00473 float x2 = m_vector.getX() * m_vector.getX(); 00474 float y2 = m_vector.getY() * m_vector.getY(); 00475 float z2 = m_vector.getZ() * m_vector.getZ(); 00476 00477 float xy = m_vector.getX() * m_vector.getY(); 00478 float xz = m_vector.getX() * m_vector.getZ(); 00479 float yz = m_vector.getY() * m_vector.getZ(); 00480 00481 float sx = m_scalar * m_vector.getX(); 00482 float sy = m_scalar * m_vector.getY(); 00483 float sz = m_scalar * m_vector.getZ(); 00484 00485 00486 matrix->set(0, 1 - 2 * (y2 + z2)); 00487 matrix->set(1, 2 * (xy - sz)); 00488 matrix->set(2, 2 * (xz + sy)); 00489 00490 matrix->set(3, 2 * (xy + sz)); 00491 matrix->set(4, 1 - 2 * (x2 + z2)); 00492 matrix->set(5, 2 * (yz - sx)); 00493 00494 matrix->set(6, 2 * (xz - sy)); 00495 matrix->set(7, 2 * (yz + sx)); 00496 matrix->set(8, 1 - 2 * (x2 + y2)); 00497 } 00498 00499 00500 /****************** 00501 * Other functions * 00502 ******************/ 00503 00504 void Quaternion::print() const 00505 { 00506 cout << m_scalar << ", ("; 00507 cout << m_vector.getX() << ", "; 00508 cout << m_vector.getY() << ", "; 00509 cout << m_vector.getZ() << ")" << endl; 00510 } 00511 00512 ostream &OpenCAL::Utils::operator<<(ostream &stream, const Quaternion &q) 00513 { 00514 stream << "[" << q.m_scalar << ", " << q.m_vector << "]"; 00515 return stream; 00516 }

Generated on Sun Aug 15 19:19:23 2004 for OpenCAL: Open Computer Animation Library by doxygen 1.3.8