Sirikata
|
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