00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef WQUATERNION_H
00021 #define WQUATERNION_H
00022
00023 #include "worldsimconfig.h"
00024 #include "wvector.h"
00025
00026 namespace farsa {
00027
00028 class wMatrix;
00029
00041 class FARSA_WSIM_TEMPLATE wQuaternion {
00042 public:
00044 wQuaternion();
00046 wQuaternion( const wMatrix &matrix);
00048 wQuaternion( real q0, real q1, real q2, real q3 );
00050 wQuaternion( const wVector &unit_Axis, real Angle = 0.0 );
00051
00052 void scale( real scale );
00053 void normalize();
00054 real dotProduct( const wQuaternion &QB ) const;
00055 wQuaternion inverse() const;
00056
00057 wVector rotateVector( const wVector& vector) const;
00058 wVector unrotateVector( const wVector& vector ) const;
00059
00060 wVector getEuleroAngles() const;
00061 wQuaternion slerp( const wQuaternion &q1, real t ) const;
00062 wVector calcAverageOmega( const wQuaternion &q1, real dt ) const;
00063
00064 wQuaternion operator*( const wQuaternion &B ) const;
00065 wQuaternion operator+( const wQuaternion &B ) const;
00066 wQuaternion operator-( const wQuaternion &B ) const;
00067
00068 real q0;
00069 real q1;
00070 real q2;
00071 real q3;
00072 };
00073
00074 }
00075
00076
00077 #include "wmatrix.h"
00078
00079 namespace farsa {
00080
00081 inline wQuaternion::wQuaternion() {
00082 q0 = 1.0;
00083 q1 = 0.0;
00084 q2 = 0.0;
00085 q3 = 0.0;
00086 }
00087
00088 inline wQuaternion::wQuaternion( const wMatrix &matrix ) {
00089 enum QUAT_INDEX {
00090 X_INDEX=0,
00091 Y_INDEX=1,
00092 Z_INDEX=2
00093 };
00094 static QUAT_INDEX QIndex [] = {Y_INDEX, Z_INDEX, X_INDEX};
00095
00096 real *ptr;
00097 real trace;
00098 QUAT_INDEX i;
00099 QUAT_INDEX j;
00100 QUAT_INDEX k;
00101
00102 trace = matrix[0][0] + matrix[1][1] + matrix[2][2];
00103
00104 if( trace > 0.0 ) {
00105 trace = sqrt( trace + 1.0 );
00106 q0 = 0.5*trace;
00107 trace = 0.5/trace;
00108 q1 = (matrix[1][2] - matrix[2][1]) * trace;
00109 q2 = (matrix[2][0] - matrix[0][2]) * trace;
00110 q3 = (matrix[0][1] - matrix[1][0]) * trace;
00111 } else {
00112 i = X_INDEX;
00113 if( matrix[Y_INDEX][Y_INDEX] > matrix[X_INDEX][X_INDEX] ) {
00114 i = Y_INDEX;
00115 }
00116 if( matrix[Z_INDEX][Z_INDEX] > matrix[i][i] ) {
00117 i = Z_INDEX;
00118 }
00119 j = QIndex[i];
00120 k = QIndex[j];
00121
00122 trace = 1.0 + matrix[i][i] - matrix[j][j] - matrix[k][k];
00123 trace = sqrt(trace);
00124
00125 ptr = &q1;
00126 ptr[i] = 0.5*trace;
00127 trace = 0.5/trace;
00128 q0 = (matrix[j][k] - matrix[k][j]) * trace;
00129 ptr[j] = (matrix[i][j] + matrix[j][i]) * trace;
00130 ptr[k] = (matrix[i][k] + matrix[k][i]) * trace;
00131 }
00132 }
00133
00134 inline wQuaternion::wQuaternion(real Q0, real Q1, real Q2, real Q3) {
00135 q0 = Q0;
00136 q1 = Q1;
00137 q2 = Q2;
00138 q3 = Q3;
00139
00140 }
00141
00142 inline wQuaternion::wQuaternion( const wVector &unitAxis, real angle ) {
00143 angle *= 0.5;
00144 q0 = cos( angle );
00145 real sinAng = sin( angle );
00146
00147 q1 = unitAxis.x * sinAng;
00148 q2 = unitAxis.y * sinAng;
00149 q3 = unitAxis.z * sinAng;
00150 }
00151
00152 inline void wQuaternion::scale(real scale) {
00153 q0 *= scale;
00154 q1 *= scale;
00155 q2 *= scale;
00156 q3 *= scale;
00157 }
00158
00159 inline void wQuaternion::normalize() {
00160 scale( 1.0/sqrt( dotProduct(*this)) );
00161 }
00162
00163 inline real wQuaternion::dotProduct( const wQuaternion &QB ) const {
00164 return q0*QB.q0 + q1*QB.q1 + q2*QB.q2 + q3*QB.q3;
00165 }
00166
00167 inline wQuaternion wQuaternion::inverse() const {
00168 return wQuaternion(q0, -q1, -q2, -q3);
00169 }
00170
00171 inline wVector wQuaternion::rotateVector( const wVector& vector ) const {
00172 wMatrix matrix( *this, wVector( 0.0f, 0.0f, 0.0f, 1.0f ) );
00173 return matrix.rotateVector( vector );
00174 }
00175
00176 inline wVector wQuaternion::unrotateVector( const wVector& vector ) const {
00177 wMatrix matrix( *this, wVector( 0.0f, 0.0f, 0.0f, 1.0f ) );
00178 return matrix.unrotateVector( vector );
00179 }
00180
00181 inline wQuaternion wQuaternion::operator+(const wQuaternion &B) const {
00182 return wQuaternion( q0+B.q0, q1+B.q1, q2+B.q2, q3+B.q3);
00183 }
00184
00185 inline wQuaternion wQuaternion::operator-( const wQuaternion &B ) const {
00186 return wQuaternion( q0-B.q0, q1-B.q1, q2-B.q2, q3-B.q3);
00187 }
00188
00189 inline wQuaternion wQuaternion::operator*( const wQuaternion &B ) const {
00190 return wQuaternion( B.q0*q0 - B.q1*q1 - B.q2*q2 - B.q3*q3,
00191 B.q1*q0 + B.q0*q1 - B.q3*q2 + B.q2*q3,
00192 B.q2*q0 + B.q3*q1 + B.q0*q2 - B.q1*q3,
00193 B.q3*q0 - B.q2*q1 + B.q1*q2 + B.q0*q3 );
00194 }
00195
00196 inline wVector wQuaternion::getEuleroAngles() const {
00197 real val;
00198 real pitch;
00199 real yaw;
00200 real roll;
00201
00202 val = 2.0f*( q2*q0 - q3*q1 );
00203 if( val >= 0.99995f ) {
00204 pitch = 2.0f*atan2( q1, q0 );
00205 yaw = 0.5f*PI_GRECO;
00206 roll = 0.0f;
00207 } else if( val <= -0.99995f ) {
00208 pitch = 2.0f*atan2( q1, q0 );
00209 yaw = -0.5f*PI_GRECO;
00210 roll = 0.0f;
00211 } else {
00212 yaw = sin (val);
00213 pitch = atan2( 2.0f*( q1*q0 + q3*q2 ), 1.0f-2.0f*( q1*q1 + q2*q2) );
00214 roll = atan2( 2.0f*( q3*q0 + q1*q2 ), 1.0f-2.0f*( q2*q2 + q3*q3) );
00215 }
00216 return wVector(pitch, yaw, roll);
00217 }
00218
00219 inline wVector wQuaternion::calcAverageOmega( const wQuaternion &QB, real dt ) const {
00220 wQuaternion dq( inverse()*QB );
00221 wVector omegaDir( dq.q1, dq.q2, dq.q3 );
00222 real dirMag2 = omegaDir % omegaDir;
00223 if( dirMag2 < 1.0e-10 ) {
00224 return wVector( 0.0, 0.0, 0.0, 0.0 );
00225 }
00226 real dirMagInv = 1.0/sqrt( dirMag2 );
00227 real dirMag = dirMag2 * dirMagInv;
00228 real omegaMag = 2.0*atan2( dirMag, dq.q0 )/dt;
00229
00230 return omegaDir.scale( dirMagInv * omegaMag );
00231 }
00232
00233 inline wQuaternion wQuaternion::slerp( const wQuaternion &QB, real t ) const {
00234 real dot;
00235 real ang;
00236 real Sclp;
00237 real Sclq;
00238 real den;
00239 real sinAng;
00240 wQuaternion Q;
00241
00242 dot = dotProduct( QB );
00243
00244 if( (dot+1.0) > 1.0e-5f ) {
00245 if( dot < 0.995f ) {
00246 ang = cos( dot );
00247 sinAng = sin( ang );
00248 den = 1.0/sinAng;
00249 Sclp = sin( (1.0-t) * ang ) * den;
00250 Sclq = sin( t*ang ) * den;
00251 } else {
00252 Sclp = 1.0-t;
00253 Sclq = t;
00254 }
00255 Q.q0 = q0*Sclp + QB.q0*Sclq;
00256 Q.q1 = q1*Sclp + QB.q1*Sclq;
00257 Q.q2 = q2*Sclp + QB.q2*Sclq;
00258 Q.q3 = q3*Sclp + QB.q3*Sclq;
00259 } else {
00260 Q.q0 = q3;
00261 Q.q1 = -q2;
00262 Q.q2 = q1;
00263 Q.q3 = q0;
00264
00265 Sclp = sin(1.0-t) * PI_GRECO * 0.5;
00266 Sclq = sin( t * PI_GRECO * 0.5 );
00267
00268 Q.q0 = q0*Sclp + Q.q0*Sclq;
00269 Q.q1 = q1*Sclp + Q.q1*Sclq;
00270 Q.q2 = q2*Sclp + Q.q2*Sclq;
00271 Q.q3 = q3*Sclp + Q.q3*Sclq;
00272 }
00273
00274 dot = Q.dotProduct( Q );
00275 if( dot < (1.0-1.0e-4f) ) {
00276 dot = 1.0/sqrt( dot );
00277 Q.q0 *= dot;
00278 Q.q1 *= dot;
00279 Q.q2 *= dot;
00280 Q.q3 *= dot;
00281 }
00282 return Q;
00283 }
00284
00285 }
00286
00287 #endif