00001 #ifndef TQUATERNION_H
00002 #define TQUATERNION_H
00003
00004 #include <Base/TinyVec.h>
00005 #include <Base/TinyMat.h>
00006
00007 namespace Spr{;
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 template<class ET>
00028 class TQuaternion:public PTM::TVectorBase<DIMENC(4), TVecDesc<TQuaternion<ET>, ET> >{
00029 public:
00030 typedef TVecDesc<TQuaternion<ET>, ET> desc;
00031 typedef PTM::TVectorBase<DIMENC(4), desc> base_type;
00032
00033 DEF_TVECTOR_BASIC_MEMBER(TQuaternion);
00034 union{
00035 ET data[4];
00036 struct{
00037 ET w,x,y,z;
00038 };
00039 };
00040
00041 ET& item_impl(size_t i){ return data[i]; }
00042
00043 const ET& item_impl(size_t i) const { return data[i]; }
00044
00045 size_t stride_impl() const { return 1; }
00046
00047
00048 typedef PTM::TSubVector<3, desc> vector_type;
00049
00050
00051
00052 const element_type& W() const { return w; }
00053
00054 const element_type& X() const { return x; }
00055
00056 const element_type& Y() const { return y; }
00057
00058 const element_type& Z() const { return z; }
00059
00060 const vector_type& V() const {return sub_vector(vector_type());}
00061
00062
00063 element_type& W(){ return w; }
00064
00065 element_type& X(){ return x; }
00066
00067 element_type& Y(){ return y; }
00068
00069 element_type& Z(){ return z; }
00070
00071 vector_type& V() {return sub_vector(1,vector_type());}
00072
00073 TVec3<ET> rotation_half() {
00074 TQuaternion<ET> tmp;
00075 if (tmp.W() < 0) tmp = -*this;
00076 else tmp = *this;
00077 TVec3<ET> r;
00078 if (tmp.W() > 1) tmp.W() = 1;
00079 ET theta = (ET)( acos(tmp.W()) * 2 );
00080 r = tmp.sub_vector(1, vector_type());
00081 ET len = r.norm();
00082 if (len > 1e-20){
00083 r = r/len;
00084 }
00085 r *= theta;
00086 return r;
00087 }
00088
00089 TVec3<ET> rotation() {
00090
00091 TVec3<ET> r;
00092 if (W() < -1) W() = -1;
00093 if (W() > 1) W() = 1;
00094 ET theta = (ET)( acos(W()) * 2 );
00095 r = sub_vector(1, vector_type());
00096 ET len = r.norm();
00097 if (len > 1e-20){
00098 r = r/len;
00099 }
00100 r *= theta;
00101 return r;
00102 }
00103
00104
00105 TVec3<ET> axis(){
00106 TVec3<ET> r;
00107 r = sub_vector(1, vector_type());
00108 ET len = r.norm();
00109 if (len > 1e-20){
00110 r = r/len;
00111 }
00112 return r;
00113 }
00114
00115
00116 ET theta(){
00117 return (ET)( acos(W()) * 2 );
00118 }
00119
00120
00121
00122
00123
00124 void set_default(){ W() = 1; X() = 0; Y() = 0; Z() = 0;}
00125
00126
00127 TQuaternion(element_type wi, element_type xi, element_type yi, element_type zi){ W() = wi; X() = xi; Y() = yi; Z() = zi;}
00128 template <class B>
00129 void InitDirect(element_type a, const PTM::TVectorBase<DIMENC(3), B> v){
00130 W() = a; V() = v;
00131 }
00132 template <class B>
00133 void InitDirect(element_type a, const PTM::TVectorBase<DIMENC(4), B> v){
00134 W() = v[0]; X() = v[1]; Y() = v[2]; Z() = v[3];
00135 }
00136 static TQuaternion<ET> Rot(element_type angle, const TVec3<element_type>& axis){
00137 TQuaternion<ET> quat;
00138 PTM::init_quaternion(quat, angle, axis);
00139 return quat;
00140 }
00141 static TQuaternion<ET> Rot(element_type angle, char axis){
00142 TQuaternion<ET> quat;
00143 PTM::init_quaternion(quat, angle, axis);
00144 return quat;
00145 }
00146 static TQuaternion<ET> Rot(const TVec3<element_type>& rot){
00147 TQuaternion<ET> quat;
00148 PTM::init_quaternion(quat, rot);
00149 return quat;
00150 }
00151
00152
00153
00154 void conjugate() { V() = -V(); }
00155
00156 TQuaternion conjugated() const { TQuaternion rv(*this); rv.conjugate(); return rv;}
00157
00158 TQuaternion inv() const { return conjugated() / square(); }
00159
00160
00161 template<class AM> void from_matrix(const AM& m)
00162 {
00163 ET tr = m[0][0] + m[1][1] + m[2][2] + 1;
00164 if (tr > 1e-6f){
00165 ET s = ET( 0.5/sqrt(tr) );
00166 W() = ET( 0.25 / s );
00167 X() = ET( (m[2][1] - m[1][2]) * s );
00168 Y() = ET( (m[0][2] - m[2][0]) * s );
00169 Z() = ET( (m[1][0] - m[0][1]) * s );
00170 }else if (m[0][0] > m[1][1] && m[0][0] > m[2][2]) {
00171 ET s = ET(sqrt( 1.0 + m[0][0] - m[1][1] - m[2][2] ) * 2);
00172 X() = ET(0.25) * s;
00173 Y() = (m[0][1] + m[1][0]) / s;
00174 Z() = (m[0][2] + m[2][0]) / s;
00175 W() = (m[1][2] - m[2][1]) / s;
00176 } else if (m[1][1] > m[2][2]) {
00177 ET s = ET( sqrt(1.0 + m[1][1] - m[0][0] - m[2][2] ) * 2);
00178 X() = (m[0][1] + m[1][0] ) / s;
00179 Y() = ET(0.25) * s;
00180 Z() = (m[1][2] + m[2][1] ) / s;
00181 W() = (m[0][2] - m[2][0] ) / s;
00182 } else {
00183 ET s = ET( sqrt( 1.0 + m[2][2] - m[0][0] - m[1][1] ) * 2);
00184 X() = (m[0][2] + m[2][0] ) / s;
00185 Y() = (m[1][2] + m[2][1] ) / s;
00186 Z() = ET(0.25) * s;
00187 W() = (m[0][1] - m[1][0] ) / s;
00188 }
00189 unitize();
00190 }
00191 template<class AM> void to_matrix(AM& mat) const
00192 {
00193 typedef TYPENAME AM::element_type AMET;
00194 mat[0][0] = AMET( 1.0 - 2.0 * (Y()*Y() + Z()*Z()) );
00195 mat[1][0] = AMET( 2.0 * (X()*Y() + Z()*W()) );
00196 mat[2][0] = AMET( 2.0 * (X()*Z() - Y()*W()) );
00197 mat[0][1] = AMET( 2.0 * (Y()*X() - Z()*W()) );
00198 mat[1][1] = AMET( 1.0 - 2.0 * (X()*X() + Z()*Z()) );
00199 mat[2][1] = AMET( 2.0 * (Y()*Z() + X()*W()) );
00200 mat[0][2] = AMET( 2.0 * (X()*Z() + Y()*W()) );
00201 mat[1][2] = AMET( 2.0 * (Y()*Z() - X()*W()) );
00202 mat[2][2] = AMET( 1.0 - 2.0 * (X()*X() + Y()*Y()) );
00203 }
00204
00205 template <class ET> void to_eular(TVec3<ET>& v){
00206 ET poleCheck = X()*Y() + Z()*W();
00207 ET& heading = v[0];
00208 ET& attitude = v[1];
00209 ET& bank = v[2];
00210 if (poleCheck == 0.5){
00211 heading = 2 * atan2(X(),W());
00212 bank = 0;
00213 }else if(poleCheck == -0.5){
00214 heading = -2 * atan2(X(),W());
00215 bank = 0;
00216 }else{
00217 heading = atan2(2*Y()*W()-2*X()*Z() , 1 - 2*Y()2 - 2*Z()2);
00218 attitude = asin(2*X()*Y() + 2*Z()*W());
00219 bank = atan2(2*X()*W()-2*Y()*Z() , 1 - 2*X()2 - 2*Z()2);
00220 }
00221 }
00222
00223 template <class ET> void from_eular(const TVec3<ET>& v){
00224 ET& heading = v[0];
00225 ET& attitude = v[1];
00226 ET& bank = v[2];
00227
00228 ET c1 = cos(heading / 2);
00229 ET c2 = cos(attitude / 2);
00230 ET c3 = cos(bank / 2);
00231 ET s1 = sin(heading / 2);
00232 ET s2 = sin(attitude / 2);
00233 ET s3 = sin(bank / 2);
00234
00235 W() = c1 c2 c3 - s1 s2 s3;
00236 X() = s1 s2 c3 + c1 c2 s3;
00237 Y() = s1 c2 c3 + c1 s2 s3;
00238 Z() = c1 s2 c3 - s1 c2 s3;
00239 }
00240
00241 void rotation_arc(const TVec3<ET>& lhs, const TVec3<ET>& rhs)
00242 {
00243 TVec3<ET> v0, v1, c;
00244 ET d, s;
00245 v0 = lhs.unit();
00246 v1 = rhs.unit();
00247 c = PTM::cross(v0, v1);
00248 d = PTM::dot(v0, v1);
00249 s = sqrt((1.0 + d) * 2.0);
00250 W() = s / 2.0;
00251 V() = c / s;
00252 }
00253
00254
00255 void euler(ET yaw, ET pitch, ET roll) {
00256 ET cosYaw = cos(yaw / 2);
00257 ET sinYaw = sin(yaw / 2);
00258 ET cosPitch = cos(pitch / 2);
00259 ET sinPitch = sin(pitch / 2);
00260 ET cosRoll = cos(roll / 2);
00261 ET sinRoll = sin(roll / 2);
00262 W() = cosRoll * cosPitch * cosYaw - sinRoll * sinPitch * sinYaw;
00263 X() = cosRoll * sinPitch * sinYaw + sinRoll * cosPitch * cosYaw;
00264 Y() = cosRoll * cosPitch * sinYaw + sinRoll * sinPitch * cosYaw;
00265 Z() = cosRoll * sinPitch * cosYaw - sinRoll * cosPitch * sinYaw;
00266 }
00267
00268
00269
00270
00271 TQuaternion<ET> derivative(const TVec3<ET>& w){
00272 return 0.5 * TQuaternion<ET>(0.0, w.X(), w.Y(), w.Z()) * *this;
00273 }
00274 };
00275
00276
00277 template <class A, class B>
00278 TQuaternion<A> operator*(const TQuaternion<A>& q1, const TQuaternion<B>& q2){
00279 TQuaternion<A> rv;
00280 rv.W() = q1.W() * q2.W() - q1.X() * q2.X() - q1.Y() * q2.Y() - q1.Z() * q2.Z();
00281 rv.X() = q1.W() * q2.X() + q1.X() * q2.W() + q1.Y() * q2.Z() - q1.Z() * q2.Y();
00282 rv.Y() = q1.W() * q2.Y() + q1.Y() * q2.W() + q1.Z() * q2.X() - q1.X() * q2.Z();
00283 rv.Z() = q1.W() * q2.Z() + q1.Z() * q2.W() + q1.X() * q2.Y() - q1.Y() * q2.X();
00284 return rv;
00285 }
00286
00287
00288 template <class ET, class BD>
00289 inline TYPENAME BD::ret_type operator*(const TQuaternion<ET>& q, const PTM::TVectorBase<DIMENC(3), BD>& v){
00290 TQuaternion<ET> qv(1, ET(v[0]), ET(v[1]), ET(v[2]));
00291 TYPENAME BD::ret_type r = (q * qv * q.conjugated()).sub_vector(PTM::TSubVectorDim<1,3>());
00292 return r;
00293 }
00294
00295 template <class T1, class T2>
00296 inline T1 dot(const TQuaternion<T1>& q1, const TQuaternion<T2>& q2) {
00297 return q1.X() * q2.X() + q1.Y() * q2.Y() + q1.Z() * q2.Z() + q1.W() * q2.W();
00298 }
00299 template <class T1, class T2>
00300 TQuaternion<T1> interpolate(T1 t, const TQuaternion<T1>& q1, const TQuaternion<T2>& q2){
00301 TQuaternion<T1> ret;
00302 TQuaternion<T1> q3 ;
00303 float dot;
00304
00305 dot = q1.X() * q2.X() + q1.Y() * q2.Y() + q1.Z() * q2.Z() + q1.W() * q2.W();
00306
00307
00308 if (dot < 0.0f){
00309 dot = -dot;
00310 q3 = TQuaternion<T1>(-q2.W(), -q2.X(), -q2.Y(), -q2.Z());
00311 }
00312 else q3 = q2;
00313
00314 if (dot > 1.0f) dot = 1.0f;
00315 if (dot < -1.0f) dot = -1.0f;
00316
00317 float angle = acos(dot);
00318 float sina, sinat, sinaomt;
00319
00320 sina = sin(angle );
00321 sinat = sin(angle * t );
00322 sinaomt = sin(angle * (1 - t));
00323
00324 if (sina){
00325 ret.X() = (q1.X() * sinaomt + q3.X() * sinat) / sina;
00326 ret.Y() = (q1.Y() * sinaomt + q3.Y() * sinat) / sina;
00327 ret.Z() = (q1.Z() * sinaomt + q3.Z() * sinat) / sina;
00328 ret.W() = (q1.W() * sinaomt + q3.W() * sinat) / sina;
00329 }else{
00330 ret = q1;
00331 }
00332 return ret;
00333 }
00334
00335
00336 typedef TQuaternion<float> Quaternionf;
00337
00338 typedef TQuaternion<double> Quaterniond;
00339
00340 }
00341
00342 #endif