Sirikata
libcore/include/sirikata/core/util/Quaternion.hpp
Go to the documentation of this file.
00001 /*  Sirikata Utilities -- Math Library
00002  *  Quaternion.hpp
00003  *
00004  *  Copyright (c) 2009, Daniel Reiter Horn
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions are
00009  *  met:
00010  *  * Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  *  * Redistributions in binary form must reproduce the above copyright
00013  *    notice, this list of conditions and the following disclaimer in
00014  *    the documentation and/or other materials provided with the
00015  *    distribution.
00016  *  * Neither the name of Sirikata nor the names of its contributors may
00017  *    be used to endorse or promote products derived from this software
00018  *    without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00021  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00022  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00023  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
00024  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00025  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00026  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00027  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00028  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00029  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00030  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031  */
00032 #ifndef _QUATERNION_HPP_
00033 #define _QUATERNION_HPP_
00034 
00035 #include "Vector3.hpp"
00036 #include "Vector4.hpp"
00037 
00038 namespace Sirikata {
00039 namespace QuaternionImpl {
00040 
00041 }
00042 class Quaternion:public Vector4<float> {
00043 public:
00044     typedef float scalar;
00045 private:
00046     Quaternion(const Vector4<scalar>&value):Vector4<scalar>(value){
00047 
00048     }
00049     friend Quaternion operator *(scalar, const Quaternion&);
00050     friend Quaternion operator /(scalar, const Quaternion&);
00051     static void ToRotationMatrix(const Quaternion &q, Matrix3x3<Quaternion::scalar> kRot) {
00052         Quaternion::scalar fTx  = 2.0f*q.x;
00053         Quaternion::scalar fTy  = 2.0f*q.y;
00054         Quaternion::scalar fTz  = 2.0f*q.z;
00055         Quaternion::scalar fTwx = fTx*q.w;
00056         Quaternion::scalar fTwy = fTy*q.w;
00057         Quaternion::scalar fTwz = fTz*q.w;
00058         Quaternion::scalar fTxx = fTx*q.x;
00059         Quaternion::scalar fTxy = fTy*q.x;
00060         Quaternion::scalar fTxz = fTz*q.x;
00061         Quaternion::scalar fTyy = fTy*q.y;
00062         Quaternion::scalar fTyz = fTz*q.y;
00063         Quaternion::scalar fTzz = fTz*q.z;
00064 
00065         kRot(0,0) = 1.0f-(fTyy+fTzz);
00066         kRot(0,1) = fTxy-fTwz;
00067         kRot(0,2) = fTxz+fTwy;
00068         kRot(1,0) = fTxy+fTwz;
00069         kRot(1,1) = 1.0f-(fTxx+fTzz);
00070         kRot(1,2) = fTyz-fTwx;
00071         kRot(2,0) = fTxz-fTwy;
00072         kRot(2,1) = fTyz+fTwx;
00073         kRot(2,2) = 1.0f-(fTxx+fTyy);
00074     }
00075     static void FromRotationMatrix (Quaternion &q, const Matrix3x3<Quaternion::scalar>& kRot) {
00076         /* Shoemake SIGGRAPH 1987 algorithm */
00077         Quaternion::scalar fTrace = kRot(0,0)+kRot(1,1)+kRot(2,2);
00078         Quaternion::scalar fRoot;
00079         if ( fTrace > 0.0 )
00080         {
00081             // |w| > 1/2, may as well choose w > 1/2
00082             fRoot = sqrt(fTrace + 1.0f);  // 2w
00083             q.w = 0.5f*fRoot;
00084             fRoot = 0.5f/fRoot;  // 1/(4w)
00085             q.x = (kRot(2,1)-kRot(1,2))*fRoot;
00086             q.y = (kRot(0,2)-kRot(2,0))*fRoot;
00087             q.z = (kRot(1,0)-kRot(0,1))*fRoot;
00088         }
00089         else
00090         {
00091             // |w| <= 1/2
00092             static unsigned int s_iNext[3] = { 1, 2, 0 };
00093             unsigned int i = 0;
00094             if ( kRot(1,1) > kRot(0,0) )
00095                 i = 1;
00096             if ( kRot(2,2) > kRot(i,i) )
00097                 i = 2;
00098             unsigned int j = s_iNext[i];
00099             unsigned int k = s_iNext[j];
00100             fRoot = sqrt(kRot(i,i)-kRot(j,j)-kRot(k,k) + 1.0f);
00101             Quaternion::scalar* apkQuat[3] = { &q.x, &q.y, &q.z };
00102             *apkQuat[i] = 0.5f*fRoot;
00103             fRoot = 0.5f/fRoot;
00104             q.w = (kRot(k,j)-kRot(j,k))*fRoot;
00105             *apkQuat[j] = (kRot(j,i)+kRot(i,j))*fRoot;
00106             *apkQuat[k] = (kRot(k,i)+kRot(i,k))*fRoot;
00107         }
00108     }
00109 public:
00110     Quaternion(){}
00111     class XYZW{};
00112     class WXYZ{};
00113     Quaternion(scalar x, scalar y, scalar z, scalar w):Vector4<scalar>(x,y,z,w) {
00114 
00115     }
00116     Quaternion(scalar x,scalar y, scalar z, scalar w, XYZW convention):Vector4<scalar>(x,y,z,w) {
00117 
00118     }
00119     Quaternion(scalar w, scalar x,scalar y, scalar z, WXYZ convention):Vector4<scalar>(x,y,z,w) {
00120 
00121     }
00122     Quaternion(const Vector3<scalar>&axis, scalar angle){
00123         Quaternion::scalar sinHalfAngle=(Quaternion::scalar)sin(angle*.5);
00124         x=sinHalfAngle*axis.x;
00125         y=sinHalfAngle*axis.y;
00126         z=sinHalfAngle*axis.z;
00127         w=(Quaternion::scalar)cos(angle*.5);
00128     }
00129     Quaternion(const Vector3<scalar> &xAxis,
00130                const Vector3<scalar> &yAxis,
00131                const Vector3<scalar> &zAxis){
00132         FromRotationMatrix(*this,
00133                            Matrix3x3<Quaternion::scalar>(xAxis,
00134                                                          yAxis,
00135                                                          zAxis,
00136                                                          COLUMNS()));
00137 
00138     }
00139     Quaternion (const Matrix3x3<Quaternion::scalar>& kRot) {
00140         FromRotationMatrix(*this, kRot);
00141     }
00142 
00143     static Quaternion identity() {
00144         Quaternion retval;
00145         retval.w=1.0;
00146         retval.x=retval.y=retval.z=0.0;
00147         return retval;
00148     }
00149     static Quaternion zero() {
00150         return Quaternion(0,0,0,0,WXYZ());
00151     }
00152     void toAngleAxis (scalar& returnAngleRadians,
00153                       Vector3<scalar>& returnAxis) const{
00154         scalar fSqrLength = x*x+y*y+z*z;
00155         scalar tmpw=w;
00156         scalar eps=(scalar)1e-06;
00157         if (tmpw>1.0f&&tmpw<1.0f+eps)
00158             tmpw=1.0f;
00159         if (tmpw<-1.0&&tmpw>-1.0f-eps)
00160             tmpw=-1.0f;
00161         if ( fSqrLength > 1e-08 && tmpw<=1 && tmpw>=-1)
00162         {
00163             returnAngleRadians = 2.0f*acos(tmpw);
00164             scalar length = sqrt(fSqrLength);
00165             returnAxis.x = x/length;
00166             returnAxis.y = y/length;
00167             returnAxis.z = z/length;
00168         }
00169         else
00170         {
00171             returnAngleRadians = 0.0f;
00172             returnAxis.x = 1.0f;
00173             returnAxis.y = 0.0f;
00174             returnAxis.z = 0.0f;
00175         }
00176     }
00177     Quaternion normal()const {
00178         return Quaternion(Vector4<scalar>::normal());
00179     }
00180     Quaternion operator+(const Quaternion&other) const{
00181         return Quaternion(Vector4<scalar>::operator+(other));
00182     }
00183 
00184     Quaternion operator-(const Quaternion&other) const{
00185         return Quaternion(Vector4<scalar>::operator-(other));
00186     }
00187 
00188     Quaternion operator-()const {
00189         return Quaternion(Vector4<scalar>::operator -());
00190     }
00191 
00192     Quaternion operator*(scalar other) const{
00193         return Quaternion(Vector4<scalar>::operator*(other));
00194     }
00195 
00196     Quaternion operator/(scalar other) const{
00197         return Quaternion(Vector4<scalar>::operator/(other));
00198     }
00199 
00200     Quaternion operator*(const Quaternion&other)const {
00201         return Quaternion(
00202             w*other.w - x*other.x - y*other.y - z*other.z,
00203             w*other.x + x*other.w + y*other.z - z*other.y,
00204             w*other.y + y*other.w + z*other.x - x*other.z,
00205             w*other.z + z*other.w + x*other.y - y*other.x, WXYZ());
00206     }
00207 
00208     template<typename myscalar>
00209     Vector3<myscalar> operator *(const Vector3<myscalar>&other)const {
00210         Vector3<myscalar> quat_axis(x,y,z);
00211         Vector3<myscalar>uv = quat_axis.cross(other);
00212         Vector3<myscalar>uuv= quat_axis.cross(uv);
00213         uv *=(2.0f*w);
00214         uuv*=2.0f;
00215         return other + uv + uuv;
00216     }
00217 
00218     Quaternion inverse() const {
00219         scalar len=lengthSquared();
00220         if (len>1e-8) {
00221             return Quaternion(w/len,-x/len,-y/len,-z/len,WXYZ());
00222         }
00223         return zero();
00224     }
00225     Vector3<scalar> xAxis() const{
00226         //scalar fTx  = 2.0*x;
00227         scalar fTy  = 2.0f*y;
00228         scalar fTz  = 2.0f*z;
00229         scalar fTwy = fTy*w;
00230         scalar fTwz = fTz*w;
00231         scalar fTxy = fTy*x;
00232         scalar fTxz = fTz*x;
00233         scalar fTyy = fTy*y;
00234         scalar fTzz = fTz*z;
00235 
00236         return Vector3<scalar>(1.0f-(fTyy+fTzz), fTxy+fTwz, fTxz-fTwy);
00237     }
00238 
00239     Vector3<scalar> yAxis() const{
00240         scalar fTx  = 2.0f*x;
00241         scalar fTy  = 2.0f*y;
00242         scalar fTz  = 2.0f*z;
00243         scalar fTwx = fTx*w;
00244         scalar fTwz = fTz*w;
00245         scalar fTxx = fTx*x;
00246         scalar fTxy = fTy*x;
00247         scalar fTyz = fTz*y;
00248         scalar fTzz = fTz*z;
00249 
00250         return Vector3<scalar>(fTxy-fTwz, 1.0f-(fTxx+fTzz), fTyz+fTwx);
00251 
00252     }
00253     Vector3<scalar> zAxis() const{
00254         scalar fTx  = 2.0f*x;
00255         scalar fTy  = 2.0f*y;
00256         scalar fTz  = 2.0f*z;
00257         scalar fTwx = fTx*w;
00258         scalar fTwy = fTy*w;
00259         scalar fTxx = fTx*x;
00260         scalar fTxz = fTz*x;
00261         scalar fTyy = fTy*y;
00262         scalar fTyz = fTz*y;
00263         return Vector3<scalar>(fTxz+fTwy, fTyz-fTwx, 1.0f-(fTxx+fTyy));
00264     }
00265     void toAxes(Vector3<scalar> &xAxis,
00266                 Vector3<scalar> &yAxis,
00267                 Vector3<scalar> &zAxis)const{
00268         Matrix3x3<Quaternion::scalar> rot;
00269         ToRotationMatrix(*this,rot);
00270         xAxis=rot.getCol(0);
00271         yAxis=rot.getCol(1);
00272         zAxis=rot.getCol(2);
00273     }
00274 
00278     Quaternion exp(float32 n) const {
00279         // FIXME there's probably a much more efficient way to do this
00280         float angle;
00281         Vector3<float32> axis;
00282         toAngleAxis(angle, axis);
00283         return Quaternion(axis, angle*n);
00284     }
00285 };
00286 inline Quaternion operator *(Quaternion::scalar s,const Quaternion&q) {
00287     return Quaternion(s*q.x,s*q.y,s*q.z,s*q.w,Quaternion::XYZW());
00288 }
00289 inline Quaternion operator /(Quaternion::scalar s,const Quaternion&q) {
00290     return Quaternion(s/q.x,s/q.y,s/q.z,s/q.w,Quaternion::XYZW());
00291 }
00292 }
00293 #endif