24 #include "quaternion.h"
37 const double epsilon = 1E-10f;
42 if ((fromSqNorm < epsilon) || (toSqNorm < epsilon))
49 Vec axis = cross(from, to);
53 if (axisSqNorm < epsilon)
56 double angle = asin(sqrt(axisSqNorm / (fromSqNorm * toSqNorm)));
61 setAxisAngle(axis, angle);
70 return inverse().rotate(v);
78 const double q00 = 2.0l * q[0] * q[0];
79 const double q11 = 2.0l * q[1] * q[1];
80 const double q22 = 2.0l * q[2] * q[2];
82 const double q01 = 2.0l * q[0] * q[1];
83 const double q02 = 2.0l * q[0] * q[2];
84 const double q03 = 2.0l * q[0] * q[3];
86 const double q12 = 2.0l * q[1] * q[2];
87 const double q13 = 2.0l * q[1] * q[3];
89 const double q23 = 2.0l * q[2] * q[3];
91 return Vec((1.0 - q11 - q22)*v[0] + ( q01 - q23)*v[1] + ( q02 + q13)*v[2],
92 ( q01 + q23)*v[0] + (1.0 - q22 - q00)*v[1] + ( q12 - q03)*v[2],
93 ( q02 - q13)*v[0] + ( q12 + q03)*v[1] + (1.0 - q11 - q00)*v[2] );
104 void Quaternion::setFromRotationMatrix(
const double m[3][3])
107 const double onePlusTrace = 1.0 + m[0][0] + m[1][1] + m[2][2];
109 if (onePlusTrace > 1E-5)
112 const double s = sqrt(onePlusTrace) * 2.0;
113 q[0] = (m[2][1] - m[1][2]) / s;
114 q[1] = (m[0][2] - m[2][0]) / s;
115 q[2] = (m[1][0] - m[0][1]) / s;
121 if ((m[0][0] > m[1][1])&(m[0][0] > m[2][2]))
123 const double s = sqrt(1.0 + m[0][0] - m[1][1] - m[2][2]) * 2.0;
125 q[1] = (m[0][1] + m[1][0]) / s;
126 q[2] = (m[0][2] + m[2][0]) / s;
127 q[3] = (m[1][2] - m[2][1]) / s;
130 if (m[1][1] > m[2][2])
132 const double s = sqrt(1.0 + m[1][1] - m[0][0] - m[2][2]) * 2.0;
133 q[0] = (m[0][1] + m[1][0]) / s;
135 q[2] = (m[1][2] + m[2][1]) / s;
136 q[3] = (m[0][2] - m[2][0]) / s;
140 const double s = sqrt(1.0 + m[2][2] - m[0][0] - m[1][1]) * 2.0;
141 q[0] = (m[0][2] + m[2][0]) / s;
142 q[1] = (m[1][2] + m[2][1]) / s;
144 q[3] = (m[0][1] - m[1][0]) / s;
151 void Quaternion::setFromRotationMatrix(
const float m[3][3])
153 qWarning(
"setFromRotationMatrix now waits for a double[3][3] parameter");
156 for (
int i=0; i<3; ++i)
157 for (
int j=0; j<3; ++j)
158 mat[i][j] =
double(m[i][j]);
160 setFromRotationMatrix(mat);
163 void Quaternion::setFromRotatedBase(
const Vec& X,
const Vec& Y,
const Vec& Z)
165 qWarning(
"setFromRotatedBase is deprecated, use setFromRotatedBasis instead");
166 setFromRotatedBasis(X,Y,Z);
185 double normX = X.
norm();
186 double normY = Y.
norm();
187 double normZ = Z.
norm();
189 for (
int i=0; i<3; ++i)
191 m[i][0] = X[i] / normX;
192 m[i][1] = Y[i] / normY;
193 m[i][2] = Z[i] / normZ;
196 setFromRotationMatrix(m);
203 angle = 2.0*acos(q[3]);
204 axis =
Vec(q[0], q[1], q[2]);
205 const double sinus = axis.
norm();
211 angle = 2.0*M_PI - angle;
221 Vec res =
Vec(q[0], q[1], q[2]);
222 const double sinus = res.
norm();
225 return (acos(q[3]) <= M_PI/2.0) ? res : -res;
236 const double angle = 2.0 * acos(q[3]);
237 return (angle <= M_PI) ? angle : 2.0*M_PI - angle;
258 QDomElement de = document.createElement(name);
259 de.setAttribute(
"q0", QString::number(q[0]));
260 de.setAttribute(
"q1", QString::number(q[1]));
261 de.setAttribute(
"q2", QString::number(q[2]));
262 de.setAttribute(
"q3", QString::number(q[3]));
288 QStringList attribute;
289 attribute <<
"q0" <<
"q1" <<
"q2" <<
"q3";
290 for (
int i=0; i<attribute.size(); ++i)
291 q[i] = DomUtils::doubleFromDom(element, attribute[i], ((i<3)?0.0f:1.0f));
308 static GLdouble m[4][4];
310 return (
const GLdouble*)(m);
319 const double q00 = 2.0l * q[0] * q[0];
320 const double q11 = 2.0l * q[1] * q[1];
321 const double q22 = 2.0l * q[2] * q[2];
323 const double q01 = 2.0l * q[0] * q[1];
324 const double q02 = 2.0l * q[0] * q[2];
325 const double q03 = 2.0l * q[0] * q[3];
327 const double q12 = 2.0l * q[1] * q[2];
328 const double q13 = 2.0l * q[1] * q[3];
330 const double q23 = 2.0l * q[2] * q[3];
332 m[0][0] = 1.0l - q11 - q22;
337 m[1][1] = 1.0l - q22 - q00;
342 m[2][2] = 1.0l - q11 - q00;
357 static GLdouble mat[4][4];
360 for (
int i=0; i<4; ++i)
361 for (
int j=0; j<4; ++j)
362 m[count++] = mat[i][j];
373 static GLdouble mat[4][4];
375 for (
int i=0; i<3; ++i)
376 for (
int j=0; j<3; ++j)
391 static GLdouble m[4][4];
393 return (
const GLdouble*)(m);
402 inverse().getMatrix(m);
408 inverse().getMatrix(m);
417 static GLdouble mat[4][4];
418 getInverseMatrix(mat);
419 for (
int i=0; i<3; ++i)
420 for (
int j=0; j<3; ++j)
439 if ((1.0 - fabs(cosAngle)) < 0.01)
447 double angle = acos(fabs(cosAngle));
448 double sinAngle = sin(angle);
449 c1 = sin(angle * (1.0 - t)) / sinAngle;
450 c2 = sin(angle * t) / sinAngle;
454 if (allowFlip && (cosAngle < 0.0))
457 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]);
477 double len = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2]);
483 double coef = acos(q[3]) / len;
484 return Quaternion(q[0]*coef, q[1]*coef, q[2]*coef, 0.0);
491 double theta = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2]);
494 return Quaternion(q[0], q[1], q[2], cos(theta));
497 double coef = sin(theta) / theta;
498 return Quaternion(q[0]*coef, q[1]*coef, q[2]*coef, cos(theta));
518 for (
int i=0; i<4; ++i)
519 e.q[i] = -0.25 * (l1.q[i] + l2.q[i]);
520 e = center*(e.
exp());
528 ostream& operator<<(ostream& o,
const Quaternion& Q)
530 return o << Q[0] <<
'\t' << Q[1] <<
'\t' << Q[2] <<
'\t' << Q[3];
546 double seed = rand()/(double)RAND_MAX;
547 double r1 = sqrt(1.0 - seed);
548 double r2 = sqrt(seed);
549 double t1 = 2.0 * M_PI * (rand()/(double)RAND_MAX);
550 double t2 = 2.0 * M_PI * (rand()/(double)RAND_MAX);
551 return Quaternion(sin(t1)*r1, cos(t1)*r1, sin(t2)*r2, cos(t2)*r2);
const GLdouble * inverseMatrix() const
Returns the associated 4x4 OpenGL inverse rotation matrix.
Quaternion inverse() const
Returns the inverse Quaternion (inverse rotation).
double squaredNorm() const
Returns the squared norm of the Vec.
static double dot(const Quaternion &a, const Quaternion &b)
Returns the "dot" product of a and b: a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*b[3].
Quaternion log()
Returns the logarithm of the Quaternion.
double norm() const
Returns the norm of the vector.
Vec orthogonalVec() const
Returns a Vec orthogonal to the Vec.
static Quaternion squadTangent(const Quaternion &before, const Quaternion ¢er, const Quaternion &after)
Returns a tangent Quaternion for center, defined by before and after Quaternions. ...
QDomElement domElement(const QString &name, QDomDocument &document) const
Returns an XML QDomElement that represents the Quaternion.
static Quaternion lnDif(const Quaternion &a, const Quaternion &b)
Returns log(a.
static Quaternion squad(const Quaternion &a, const Quaternion &tgA, const Quaternion &tgB, const Quaternion &b, float t)
Returns the slerp interpolation of the two Quaternions a and b, at time t, using tangents tgA and tgB...
The Vec class represents 3D positions and 3D vectors.
Quaternion exp()
Returns the exponential of the Quaternion.
void getAxisAngle(Vec &axis, float &angle) const
Returns the axis vector and the angle (in radians) of the rotation represented by the Quaternion...
static Quaternion slerp(const Quaternion &a, const Quaternion &b, float t, bool allowFlip=true)
Returns the slerp interpolation of Quaternions a and b, at time t.
void setFromRotatedBasis(const Vec &X, const Vec &Y, const Vec &Z)
Sets the Quaternion from the three rotated vectors of an orthogonal basis.
void getMatrix(GLdouble m[4][4]) const
Fills m with the OpenGL representation of the Quaternion rotation.
Vec inverseRotate(const Vec &v) const
Returns the image of v by the Quaternion inverse() rotation.
Quaternion()
Default constructor, builds an identity rotation.
double angle() const
Returns the angle (in radians) of the rotation represented by the Quaternion.
The Quaternion class represents 3D rotations and orientations.
static Quaternion randomQuaternion()
Returns a random unit Quaternion.
Vec axis() const
Returns the normalized axis direction of the rotation represented by the Quaternion.
void getInverseRotationMatrix(float m[3][3]) const
m is set to the 3x3 inverse rotation matrix associated with the Quaternion.
Vec rotate(const Vec &v) const
Returns the image of v by the Quaternion rotation.
double normalize()
Normalizes the Quaternion coefficients.
void initFromDOMElement(const QDomElement &element)
Restores the Quaternion state from a QDomElement created by domElement().
void getInverseMatrix(GLdouble m[4][4]) const
Fills m with the OpenGL matrix corresponding to the inverse() rotation.
const GLdouble * matrix() const
Returns the Quaternion associated 4x4 OpenGL rotation matrix.
void getRotationMatrix(float m[3][3]) const
Fills m with the 3x3 rotation matrix associated with the Quaternion.