/* * Copyright (C) 2008 * Robert Bosch LLC * Research and Technology Center North America * Palo Alto, California * * All rights reserved. * *------------------------------------------------------------------------------ * project ....: Autonomous Technologies * file .......: rtcQuaternion.h * authors ....: Benjamin Pitzer * organization: Robert Bosch LLC * creation ...: 08/16/2006 * modified ...: $Date: 2009-01-21 18:19:16 -0800 (Wed, 21 Jan 2009) $ * changed by .: $Author: benjaminpitzer $ * revision ...: $Revision: 14 $ */ #ifndef RTC_QUATERNION_H #define RTC_QUATERNION_H //== INCLUDES ================================================================== #include "rtcMath.h" #include "rtcEulerAngles.h" #include "rtcRotation.h" #include "rtcTransform.h" #include "rtcSMat3.h" #include "rtcSMat4.h" #include "rtcVec3.h" #include "rtcVec4.h" //== NAMESPACES ================================================================ namespace rtc { // Forward declarations template class EulerAngles; // Euler angles template class Rotation; // Rotation matrix (3x3) template class Transform; // Rigid tranform matrix (4x4) template class Quaternion; // Quaternion template class SMat3; // 3x3 Matrix template class SMat4; // 4x4 Matrix template class Vec3; // 3d Vector /** * The Quaternion Class * * Defines quaternion class that derives from Vec and knows * how to construct itself from several other common rotation representations, * such as rotation matrices, axis angles, and euler angles. * */ template class Quaternion: public Vec4 { public: // Inherited from parent using Vec4::x; using Vec4::set; using Vec4::normalize; using Vec4::operator *=; using Vec4::operator *; /// Constructor Quaternion(); Quaternion(const T x0, const T x1, const T x2, const T x3); Quaternion(const Vec& v); Quaternion(const Vec& n, const T theta); // axis angle Quaternion(const EulerAngles& e); Quaternion(const Rotation& r); /// Mutators void set(const Vec& n, const T theta); // axis angle void set(const EulerAngles& e); void set(const Rotation& r); /// Accessors T angle() const; Vec axis() const; /// Quaternion operations Quaternion operator * (const Quaternion& q) const; void operator *= (const Quaternion& q); Quaternion conjugated() const; void conjugate(); Quaternion inverted() const; void invert(); /// Quaternion derivatives and matrices SMat3 drot_dqj(const int j) const; static SMat3 d2rot_dqkdqj(int k, int j); static SMat4 dquatMat_dqj(const int j); SMat4 quatMat(); SMat4 quatMatT(); SMat4 quatMatBar(); SMat4 quatMatBarT(); /// Quaternion rotations void rotate(Vec& v) const; Vec rotated(const Vec& v) const; }; // Declare a few common typdefs typedef Quaternion Quaternionf; typedef Quaternion Quaterniond; //============================================================================== // Quaternion //============================================================================== // Constructors /** Ctor that intializes to a zero-rotation unit quaternion. */ template inline Quaternion::Quaternion() { set(T(1),T(0),T(0),T(0)); } /** Ctor that initializes vector entries directly. */ template inline Quaternion::Quaternion(const T x0, const T x1, const T x2, const T x3) { set(x0,x1,x2,x3); } /** Ctor that initializes from a Vec. */ template inline Quaternion::Quaternion(const Vec& v) : Vec4(v) {} /** Ctor that builds a unit quaternion from an axis and an angle of rotation. * @param n the axis of rotation * @param theta the angle of rotation */ template inline Quaternion::Quaternion(const Vec& n, const T theta) { set(n,theta); } /** Ctor that builds a unit quaternion from a set of EulerAngles. * @param e is a set of EulerAngles */ template inline Quaternion::Quaternion(const EulerAngles& e) { set(e); } /** Ctor that builds a unit quaternion from a rotation matrix. * Precondition: r must have unit norm for the quaternion to have unit length * @param r is a rotation matrix */ template inline Quaternion::Quaternion(const Rotation& r) { set(r); } // Mutators /** Set the quaternion according to the passed axis and angle. * @param n the axis of rotation * @param theta the angle of rotation */ template inline void Quaternion::set(const Vec& n, const T theta) { T s = sin(theta/T(2)); Vec nn = n.normalized(); set(cos(theta/T(2)),s*nn.x[0],s*nn.x[1],s*nn.x[2]); normalize(); } /** Set the quaternion according to the passed EulerAngles. * @param e is a set of EulerAngles */ template inline void Quaternion::set(const EulerAngles& e) { using namespace std; T cr = cos(T(0.5)*e.x[0]); T sr = sin(T(0.5)*e.x[0]); T cp = cos(T(0.5)*e.x[1]); T sp = sin(T(0.5)*e.x[1]); T cy = cos(T(0.5)*e.x[2]); T sy = sin(T(0.5)*e.x[2]); T w = cy*cp*cr + sy*sp*sr; if (w<0) set(-w,sy*sp*cr-cy*cp*sr,-cy*sp*cr-sy*cp*sr,cy*sp*sr-sy*cp*cr); else set(w,cy*cp*sr-sy*sp*cr,cy*sp*cr+sy*cp*sr,sy*cp*cr-cy*sp*sr); } /** Set the quaternion according to the passed axis and angle. * Precondition: r must have unit norm for the quaternion to have unit length * @param r is a rotation matrix */ template inline void Quaternion::set(const Rotation& r) { T n4; T tr = r.trace(); if (tr > T(0)) { set(tr + T(1), -(r(1,2) - r(2,1)), -(r(2,0) - r(0,2)), -(r(0,1) - r(1,0))); n4 = x[0]; } else if ((r(0,0) > r(1,1)) && (r(0,0) > r(2,2))) { set(r(1,2) - r(2,1), -(1.0f + r(0,0) - r(1,1) - r(2,2)), -(r(1,0) + r(0,1)), -(r(2,0) + r(0,2))); n4 = -x[1]; } else if (r(1,1) > r(2,2)) { set(r(2,0) - r(0,2), -(r(1,0) + r(0,1)), -(1.0f + r(1,1) - r(0,0) - r(2,2)), -(r(2,1) + r(1,2))); n4 = -x[2]; } else { set(r(0,1) - r(1,0), -(r(2,0) + r(0,2)), -(r(2,1) + r(1,2)), -(1.0f + r(2,2) - r(0,0) - r(1,1))); n4 = -x[3]; } if (x[0] < T(0)) operator *= (T(-0.5)/T(sqrt(n4))); else operator *= (T(0.5)/T(sqrt(n4))); } // Accessors /** Get the angle of rotation. */ template inline T Quaternion::angle() const { return T(2.0)*acos(x[0]); } /** Gets the axis of rotation. */ template inline Vec Quaternion::axis() const { Vec3 n(x[1],x[2],x[3]); n.normalize(); return n; } // Quaternion operations /** Quaternion multiplication. */ template inline Quaternion Quaternion::operator*(const Quaternion& q) const { return Quaternion(x[0]*q.x[0] - x[1]*q.x[1] - x[2]*q.x[2] - x[3]*q.x[3], x[0]*q.x[1] + x[1]*q.x[0] + x[2]*q.x[3] - x[3]*q.x[2], x[0]*q.x[2] - x[1]*q.x[3] + x[2]*q.x[0] + x[3]*q.x[1], x[0]*q.x[3] + x[1]*q.x[2] - x[2]*q.x[1] + x[3]*q.x[0]); } /** Quaternion multiplication assignment operator. */ template inline void Quaternion::operator *= (const Quaternion& q) { set(x[0]*q.x[0] - x[1]*q.x[1] - x[2]*q.x[2] - x[3]*q.x[3], x[0]*q.x[1] + x[1]*q.x[0] + x[2]*q.x[3] - x[3]*q.x[2], x[0]*q.x[2] - x[1]*q.x[3] + x[2]*q.x[0] + x[3]*q.x[1], x[0]*q.x[3] + x[1]*q.x[2] - x[2]*q.x[1] + x[3]*q.x[0]); } /** Quaternion conjugate. * returns the conjuate quaternion */ template inline Quaternion Quaternion::conjugated() const { return Quaternion(x[0],-x[1],-x[2],-x[3]); } /** Quaternion conjugate. * conjugates this quaternion */ template inline void Quaternion::conjugate() { x[1] = -x[1]; x[2] = -x[2]; x[3] = -x[3]; } /** Quaternion inverse. * returns the inverse quaternion */ template inline Quaternion Quaternion::inverted() const { T l2 = x[0]*x[0] + x[1]*x[1] + x[2]*x[2] + x[3]*x[3]; return Quaternion(x[0]/l2,-x[1]/l2,-x[2]/l2,-x[3]/l2); } /** Quaternion inverse. * inverts this quaternion */ template inline void Quaternion::invert() { T l2 = x[0]*x[0] + x[1]*x[1] + x[2]*x[2] + x[3]*x[3]; x[0] = x[0]/l2; x[1] = -x[1]/l2; x[2] = -x[2]/l2; x[3] = -x[3]/l2; } // Quaternion derivatives and matrices /** Compute the rotation matrix derivative. * returns the derivative: dR(q) dq_j */ template inline SMat3 Quaternion::drot_dqj(const int j) const { switch(j) { case 0: return SMat3(2*x[0], -2*x[3], 2*x[2], 2*x[3], 2*x[0], -2*x[1], -2*x[2], 2*x[1], 2*x[0]); case 1: return SMat3( 2*x[1], 2*x[2], 2*x[3], 2*x[2], -2*x[1], -2*x[0], 2*x[3], 2*x[0], -2*x[1]); case 2: return SMat3(-2*x[2], 2*x[1], 2*x[0], 2*x[1], 2*x[2], 2*x[3], -2*x[0], 2*x[3], -2*x[2]); case 3: return SMat3(-2*x[3], -2*x[0], 2*x[1], 2*x[0], -2*x[3], 2*x[2], 2*x[1], 2*x[2], 2*x[3]); } return SMat3(T(0)); } /** Compute the rotation matrix second derivative. * returns the second derivative, dR(q) / dq_j dq_k */ template inline SMat3 Quaternion::d2rot_dqkdqj(int k, int j) { if (j>k) { int temp = j; j=k; k=temp; } if (j==0 && k==0) return SMat3(1,0,0, 0,1,0, 0,0,1); if (j==0 && k==1) return SMat3(0,0,0, 0,0,-1, 0,1,0); if (j==0 && k==2) return SMat3(0,0,1, 0,0,0, -1,0,0); if (j==0 && k==3) return SMat3(0,-1,0, 1,0,0, 0,0,0); if (j==1 && k==1) return SMat3(1,0,0, 0,-1,0, 0,0,-1); if (j==1 && k==2) return SMat3(0,1,0, 1,0,0, 0,0,0); if (j==1 && k==3) return SMat3(0,0,1, 0,0,0, 1,0,0); if (j==2 && k==2) return SMat3(-1,0,0, 0,1,0, 0,0,-1); if (j==2 && k==3) return SMat3(0,0,0, 0,0,1, 0,1,0); if (j==3 && k==3) return SMat3(-1,0,0, 0,-1,0, 0,0,1); return SMat3(T(0)); } /** Return the quaternion matrix. * returns the matrix such that q1*q2 = q1.quatMat()*q2 */ template inline SMat4 Quaternion::quatMat() { return SMat4(x[0], -x[1], -x[2], -x[3], x[1], x[0], -x[3], x[2], x[2], x[3], x[0], -x[1], x[3], -x[2], x[1], x[0]); } /** Returns the transpose of the quaternion matrix. */ template inline SMat4 Quaternion::quatMatT() { return SMat4(x[0], x[1], x[2], x[3], -x[1], x[0], x[3], -x[2], -x[2], -x[3], x[0], x[1], -x[3], x[2], -x[1], x[0]); } /** Returns the conjugate quaternion matrix. */ template inline SMat4 Quaternion::quatMatBar() { return SMat4(x[0], -x[1], -x[2], -x[3], x[1], x[0], x[3], -x[2], x[2], -x[3], x[0], x[1], x[3], x[2], -x[1], x[0]); } /** Returns the transpose of the conjugate quaternion matrix. */ template inline SMat4 Quaternion::quatMatBarT() { return SMat4(x[0], x[1], x[2], x[3], -x[1], x[0], -x[3], x[2], -x[2], x[3], x[0], -x[1], -x[3], -x[2], x[1], x[0]); } /** Returns the derivate: dQ(q) / dq_j. */ template inline SMat4 Quaternion::dquatMat_dqj(const int j) { switch(j) { case 0: return SMat4(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1); case 1: return SMat4(0,-1,0,0,1,0,0,0,0,0,0,-1,0,0,1,0); case 2: return SMat4(0,0,-1,0,0,0,0,1,1,0,0,0,0,-1,0,0); case 4: return SMat4(0,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,0); } return SMat4(T(0)); } /** Rotates the given vector. */ template inline void Quaternion::rotate(Vec& v) const { T a = T(2)*x[0]*x[0] - T(1); T b = T(2)*(x[1]*v.x[0] + x[2]*v.x[1] + x[3]*v.x[2]); T u0 = a*v.x[0] + b*x[1] + T(2)*x[0]*(x[2]*v.x[2] - x[3]*v.x[1]); T u1 = a*v.x[1] + b*x[2] + T(2)*x[0]*(x[3]*v.x[0] - x[1]*v.x[2]); T u2 = a*v.x[2] + b*x[3] + T(2)*x[0]*(x[1]*v.x[1] - x[2]*v.x[0]); v.x[0] = u0; v.x[1] = u1; v.x[2] = u2; } /** Returns a rotated version of the passed vector. */ template inline Vec Quaternion::rotated(const Vec& v) const { T a = T(2)*x[0]*x[0] - T(1); T b = T(2)*(x[1]*v.x[0] + x[2]*v.x[1] + x[3]*v.x[2]); return Vec3(a*v.x[0] + b*x[1] + 2*x[0]*(x[2]*v.x[2] - x[3]*v.x[1]), a*v.x[1] + b*x[2] + 2*x[0]*(x[3]*v.x[0] - x[1]*v.x[2]), a*v.x[2] + b*x[3] + 2*x[0]*(x[1]*v.x[1] - x[2]*v.x[0])); } //============================================================================== } // namespace rtc //============================================================================== #endif // RTC_QUATERNION_H defined //==============================================================================