00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "domUtils.h"
00024 #include "quaternion.h"
00025 #include <stdlib.h>
00026
00027
00028 using namespace qglviewer;
00029 using namespace std;
00030
00035 Quaternion::Quaternion(const Vec& from, const Vec& to)
00036 {
00037 const double epsilon = 1E-10f;
00038
00039 const double fromSqNorm = from.squaredNorm();
00040 const double toSqNorm = to.squaredNorm();
00041
00042 if ((fromSqNorm < epsilon) || (toSqNorm < epsilon))
00043 {
00044 q[0]=q[1]=q[2]=0.0;
00045 q[3]=1.0;
00046 }
00047 else
00048 {
00049 Vec axis = cross(from, to);
00050 const double axisSqNorm = axis.squaredNorm();
00051
00052
00053 if (axisSqNorm < epsilon)
00054 axis = from.orthogonalVec();
00055
00056 double angle = asin(sqrt(axisSqNorm / (fromSqNorm * toSqNorm)));
00057
00058 if (from*to < 0.0)
00059 angle = M_PI-angle;
00060
00061 setAxisAngle(axis, angle);
00062 }
00063 }
00064
00068 Vec Quaternion::inverseRotate(const Vec& v) const
00069 {
00070 return inverse().rotate(v);
00071 }
00072
00076 Vec Quaternion::rotate(const Vec& v) const
00077 {
00078 const double q00 = 2.0l * q[0] * q[0];
00079 const double q11 = 2.0l * q[1] * q[1];
00080 const double q22 = 2.0l * q[2] * q[2];
00081
00082 const double q01 = 2.0l * q[0] * q[1];
00083 const double q02 = 2.0l * q[0] * q[2];
00084 const double q03 = 2.0l * q[0] * q[3];
00085
00086 const double q12 = 2.0l * q[1] * q[2];
00087 const double q13 = 2.0l * q[1] * q[3];
00088
00089 const double q23 = 2.0l * q[2] * q[3];
00090
00091 return Vec((1.0 - q11 - q22)*v[0] + ( q01 - q23)*v[1] + ( q02 + q13)*v[2],
00092 ( q01 + q23)*v[0] + (1.0 - q22 - q00)*v[1] + ( q12 - q03)*v[2],
00093 ( q02 - q13)*v[0] + ( q12 + q03)*v[1] + (1.0 - q11 - q00)*v[2] );
00094 }
00095
00104 void Quaternion::setFromRotationMatrix(const double m[3][3])
00105 {
00106
00107 const double onePlusTrace = 1.0 + m[0][0] + m[1][1] + m[2][2];
00108
00109 if (onePlusTrace > 1E-5)
00110 {
00111
00112 const double s = sqrt(onePlusTrace) * 2.0;
00113 q[0] = (m[2][1] - m[1][2]) / s;
00114 q[1] = (m[0][2] - m[2][0]) / s;
00115 q[2] = (m[1][0] - m[0][1]) / s;
00116 q[3] = 0.25 * s;
00117 }
00118 else
00119 {
00120
00121 if ((m[0][0] > m[1][1])&(m[0][0] > m[2][2]))
00122 {
00123 const double s = sqrt(1.0 + m[0][0] - m[1][1] - m[2][2]) * 2.0;
00124 q[0] = 0.25 * s;
00125 q[1] = (m[0][1] + m[1][0]) / s;
00126 q[2] = (m[0][2] + m[2][0]) / s;
00127 q[3] = (m[1][2] - m[2][1]) / s;
00128 }
00129 else
00130 if (m[1][1] > m[2][2])
00131 {
00132 const double s = sqrt(1.0 + m[1][1] - m[0][0] - m[2][2]) * 2.0;
00133 q[0] = (m[0][1] + m[1][0]) / s;
00134 q[1] = 0.25 * s;
00135 q[2] = (m[1][2] + m[2][1]) / s;
00136 q[3] = (m[0][2] - m[2][0]) / s;
00137 }
00138 else
00139 {
00140 const double s = sqrt(1.0 + m[2][2] - m[0][0] - m[1][1]) * 2.0;
00141 q[0] = (m[0][2] + m[2][0]) / s;
00142 q[1] = (m[1][2] + m[2][1]) / s;
00143 q[2] = 0.25 * s;
00144 q[3] = (m[0][1] - m[1][0]) / s;
00145 }
00146 }
00147 normalize();
00148 }
00149
00150 #ifndef DOXYGEN
00151 void Quaternion::setFromRotationMatrix(const float m[3][3])
00152 {
00153 qWarning("setFromRotationMatrix now waits for a double[3][3] parameter");
00154
00155 double mat[3][3];
00156 for (int i=0; i<3; ++i)
00157 for (int j=0; j<3; ++j)
00158 mat[i][j] = double(m[i][j]);
00159
00160 setFromRotationMatrix(mat);
00161 }
00162
00163 void Quaternion::setFromRotatedBase(const Vec& X, const Vec& Y, const Vec& Z)
00164 {
00165 qWarning("setFromRotatedBase is deprecated, use setFromRotatedBasis instead");
00166 setFromRotatedBasis(X,Y,Z);
00167 }
00168 #endif
00169
00182 void Quaternion::setFromRotatedBasis(const Vec& X, const Vec& Y, const Vec& Z)
00183 {
00184 double m[3][3];
00185 double normX = X.norm();
00186 double normY = Y.norm();
00187 double normZ = Z.norm();
00188
00189 for (int i=0; i<3; ++i)
00190 {
00191 m[i][0] = X[i] / normX;
00192 m[i][1] = Y[i] / normY;
00193 m[i][2] = Z[i] / normZ;
00194 }
00195
00196 setFromRotationMatrix(m);
00197 }
00198
00201 void Quaternion::getAxisAngle(Vec& axis, float& angle) const
00202 {
00203 angle = 2.0*acos(q[3]);
00204 axis = Vec(q[0], q[1], q[2]);
00205 const double sinus = axis.norm();
00206 if (sinus > 1E-8)
00207 axis /= sinus;
00208
00209 if (angle > M_PI)
00210 {
00211 angle = 2.0*M_PI - angle;
00212 axis = -axis;
00213 }
00214 }
00215
00219 Vec Quaternion::axis() const
00220 {
00221 Vec res = Vec(q[0], q[1], q[2]);
00222 const double sinus = res.norm();
00223 if (sinus > 1E-8)
00224 res /= sinus;
00225 return (acos(q[3]) <= M_PI/2.0) ? res : -res;
00226 }
00227
00234 double Quaternion::angle() const
00235 {
00236 const double angle = 2.0 * acos(q[3]);
00237 return (angle <= M_PI) ? angle : 2.0*M_PI - angle;
00238 }
00239
00256 QDomElement Quaternion::domElement(const QString& name, QDomDocument& document) const
00257 {
00258 QDomElement de = document.createElement(name);
00259 de.setAttribute("q0", QString::number(q[0]));
00260 de.setAttribute("q1", QString::number(q[1]));
00261 de.setAttribute("q2", QString::number(q[2]));
00262 de.setAttribute("q3", QString::number(q[3]));
00263 return de;
00264 }
00265
00273 void Quaternion::initFromDOMElement(const QDomElement& element)
00274 {
00275 Quaternion q(element);
00276 *this = q;
00277 }
00278
00286 Quaternion::Quaternion(const QDomElement& element)
00287 {
00288 QStringList attribute;
00289 attribute << "q0" << "q1" << "q2" << "q3";
00290 #if QT_VERSION >= 0x040000
00291 for (int i=0; i<attribute.size(); ++i)
00292 #else
00293 for (unsigned int i=0; i<attribute.count(); ++i)
00294 #endif
00295 q[i] = DomUtils::doubleFromDom(element, attribute[i], ((i<3)?0.0f:1.0f));
00296 }
00297
00310 const GLdouble* Quaternion::matrix() const
00311 {
00312 static GLdouble m[4][4];
00313 getMatrix(m);
00314 return (const GLdouble*)(m);
00315 }
00316
00321 void Quaternion::getMatrix(GLdouble m[4][4]) const
00322 {
00323 const double q00 = 2.0l * q[0] * q[0];
00324 const double q11 = 2.0l * q[1] * q[1];
00325 const double q22 = 2.0l * q[2] * q[2];
00326
00327 const double q01 = 2.0l * q[0] * q[1];
00328 const double q02 = 2.0l * q[0] * q[2];
00329 const double q03 = 2.0l * q[0] * q[3];
00330
00331 const double q12 = 2.0l * q[1] * q[2];
00332 const double q13 = 2.0l * q[1] * q[3];
00333
00334 const double q23 = 2.0l * q[2] * q[3];
00335
00336 m[0][0] = 1.0l - q11 - q22;
00337 m[1][0] = q01 - q23;
00338 m[2][0] = q02 + q13;
00339
00340 m[0][1] = q01 + q23;
00341 m[1][1] = 1.0l - q22 - q00;
00342 m[2][1] = q12 - q03;
00343
00344 m[0][2] = q02 - q13;
00345 m[1][2] = q12 + q03;
00346 m[2][2] = 1.0l - q11 - q00;
00347
00348 m[0][3] = 0.0l;
00349 m[1][3] = 0.0l;
00350 m[2][3] = 0.0l;
00351
00352 m[3][0] = 0.0l;
00353 m[3][1] = 0.0l;
00354 m[3][2] = 0.0l;
00355 m[3][3] = 1.0l;
00356 }
00357
00359 void Quaternion::getMatrix(GLdouble m[16]) const
00360 {
00361 static GLdouble mat[4][4];
00362 getMatrix(mat);
00363 int count = 0;
00364 for (int i=0; i<4; ++i)
00365 for (int j=0; j<4; ++j)
00366 m[count++] = mat[i][j];
00367 }
00368
00375 void Quaternion::getRotationMatrix(float m[3][3]) const
00376 {
00377 static GLdouble mat[4][4];
00378 getMatrix(mat);
00379 for (int i=0; i<3; ++i)
00380 for (int j=0; j<3; ++j)
00381
00382 m[i][j] = mat[j][i];
00383 }
00384
00393 const GLdouble* Quaternion::inverseMatrix() const
00394 {
00395 static GLdouble m[4][4];
00396 getInverseMatrix(m);
00397 return (const GLdouble*)(m);
00398 }
00399
00404 void Quaternion::getInverseMatrix(GLdouble m[4][4]) const
00405 {
00406 inverse().getMatrix(m);
00407 }
00408
00410 void Quaternion::getInverseMatrix(GLdouble m[16]) const
00411 {
00412 inverse().getMatrix(m);
00413 }
00414
00419 void Quaternion::getInverseRotationMatrix(float m[3][3]) const
00420 {
00421 static GLdouble mat[4][4];
00422 getInverseMatrix(mat);
00423 for (int i=0; i<3; ++i)
00424 for (int j=0; j<3; ++j)
00425
00426 m[i][j] = mat[j][i];
00427 }
00428
00429
00437 Quaternion Quaternion::slerp(const Quaternion& a, const Quaternion& b, float t, bool allowFlip)
00438 {
00439 double cosAngle = Quaternion::dot(a, b);
00440
00441 double c1, c2;
00442
00443 if ((1.0 - fabs(cosAngle)) < 0.01)
00444 {
00445 c1 = 1.0 - t;
00446 c2 = t;
00447 }
00448 else
00449 {
00450
00451 double angle = acos(fabs(cosAngle));
00452 double sinAngle = sin(angle);
00453 c1 = sin(angle * (1.0 - t)) / sinAngle;
00454 c2 = sin(angle * t) / sinAngle;
00455 }
00456
00457
00458 if (allowFlip && (cosAngle < 0.0))
00459 c1 = -c1;
00460
00461 return Quaternion(c1*a[0] + c2*b[0], c1*a[1] + c2*b[1], c1*a[2] + c2*b[2], c1*a[3] + c2*b[3]);
00462 }
00463
00471 Quaternion Quaternion::squad(const Quaternion& a, const Quaternion& tgA, const Quaternion& tgB, const Quaternion& b, float t)
00472 {
00473 Quaternion ab = Quaternion::slerp(a, b, t);
00474 Quaternion tg = Quaternion::slerp(tgA, tgB, t, false);
00475 return Quaternion::slerp(ab, tg, 2.0*t*(1.0-t), false);
00476 }
00477
00479 Quaternion Quaternion::log()
00480 {
00481 double len = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2]);
00482
00483 if (len < 1E-6)
00484 return Quaternion(q[0], q[1], q[2], 0.0);
00485 else
00486 {
00487 double coef = acos(q[3]) / len;
00488 return Quaternion(q[0]*coef, q[1]*coef, q[2]*coef, 0.0);
00489 }
00490 }
00491
00493 Quaternion Quaternion::exp()
00494 {
00495 double theta = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2]);
00496
00497 if (theta < 1E-6)
00498 return Quaternion(q[0], q[1], q[2], cos(theta));
00499 else
00500 {
00501 double coef = sin(theta) / theta;
00502 return Quaternion(q[0]*coef, q[1]*coef, q[2]*coef, cos(theta));
00503 }
00504 }
00505
00507 Quaternion Quaternion::lnDif(const Quaternion& a, const Quaternion& b)
00508 {
00509 Quaternion dif = a.inverse()*b;
00510 dif.normalize();
00511 return dif.log();
00512 }
00513
00517 Quaternion Quaternion::squadTangent(const Quaternion& before, const Quaternion& center, const Quaternion& after)
00518 {
00519 Quaternion l1 = Quaternion::lnDif(center,before);
00520 Quaternion l2 = Quaternion::lnDif(center,after);
00521 Quaternion e;
00522 for (int i=0; i<4; ++i)
00523 e.q[i] = -0.25 * (l1.q[i] + l2.q[i]);
00524 e = center*(e.exp());
00525
00526
00527
00528
00529 return e;
00530 }
00531
00532 ostream& operator<<(ostream& o, const Quaternion& Q)
00533 {
00534 return o << Q[0] << '\t' << Q[1] << '\t' << Q[2] << '\t' << Q[3];
00535 }
00536
00546 Quaternion Quaternion::randomQuaternion()
00547 {
00548
00549
00550 double seed = rand()/(double)RAND_MAX;
00551 double r1 = sqrt(1.0 - seed);
00552 double r2 = sqrt(seed);
00553 double t1 = 2.0 * M_PI * (rand()/(double)RAND_MAX);
00554 double t2 = 2.0 * M_PI * (rand()/(double)RAND_MAX);
00555 return Quaternion(sin(t1)*r1, cos(t1)*r1, sin(t2)*r2, cos(t2)*r2);
00556 }