00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <cassert>
00027 #include "fob/quaternion.h"
00028
00030 const math::quaternion math::quaternion::IDENTITY(
00031 0.0, 0.0, 0.0,
00032 1.0
00033 );
00034
00036 void
00037 math::quaternion::get_rotation_matrix( math::matrix4& m ) const
00038 {
00039 real_t x2 = m_v.x( ) + m_v.x( );
00040 real_t y2 = m_v.y( ) + m_v.y( );
00041 real_t z2 = m_v.z( ) + m_v.z( );
00042
00043 real_t xx = m_v.x( ) * x2;
00044 real_t xy = m_v.x( ) * y2;
00045 real_t xz = m_v.x( ) * z2;
00046 real_t xw = x2 * m_w;
00047
00048 real_t yy = m_v.y( ) * y2;
00049 real_t yz = m_v.y( ) * z2;
00050 real_t yw = y2 * m_w;
00051
00052 real_t zz = m_v.z( ) * z2;
00053 real_t zw = z2 * m_w;
00054
00055 m.set( 0, 0, 1.0 - ( yy + zz ) );
00056 m.set( 0, 1, ( xy - zw ) );
00057 m.set( 0, 2, ( xz + yw ) );
00058 m.set( 0, 3, 0.0 );
00059
00060 m.set( 1, 0, ( xy + zw ) );
00061 m.set( 1, 1, 1.0 - ( xx + zz ) );
00062 m.set( 1, 2, ( yz - xw ) );
00063 m.set( 1, 3, 0.0 );
00064
00065 m.set( 2, 0, ( xz - yw ) );
00066 m.set( 2, 1, ( yz + xw ) );
00067 m.set( 2, 2, 1.0 - ( xx + yy ) );
00068 m.set( 2, 3, 0.0 );
00069
00070 m.set( 3, 0, 0.0 );
00071 m.set( 3, 1, 0.0 );
00072 m.set( 3, 2, 0.0 );
00073 m.set( 3, 3, 1.0 );
00074 }
00075
00077 math::matrix4
00078 math::quaternion::get_rotation_matrix( void ) const
00079 {
00080 math::matrix4 m;
00081 get_rotation_matrix( m );
00082 return m;
00083 }
00084
00086 void
00087 math::quaternion::get_transposed_rotation_matrix( math::matrix4& m ) const
00088 {
00089 real_t x2 = m_v.x( ) + m_v.x( );
00090 real_t y2 = m_v.y( ) + m_v.y( );
00091 real_t z2 = m_v.z( ) + m_v.z( );
00092
00093 real_t xx = m_v.x( ) * x2;
00094 real_t xy = m_v.x( ) * y2;
00095 real_t xz = m_v.x( ) * z2;
00096 real_t xw = x2 * m_w;
00097
00098 real_t yy = m_v.y( ) * y2;
00099 real_t yz = m_v.y( ) * z2;
00100 real_t yw = y2 * m_w;
00101
00102 real_t zz = m_v.z( ) * z2;
00103 real_t zw = z2 * m_w;
00104
00105 m.set( 0, 0, 1.0 - ( yy + zz ) );
00106 m.set( 0, 1, ( xy + zw ) );
00107 m.set( 0, 2, ( xz - yw ) );
00108 m.set( 0, 3, 0.0 );
00109
00110 m.set( 1, 0, ( xy - zw ) );
00111 m.set( 1, 1, 1.0 - ( xx + zz ) );
00112 m.set( 1, 2, ( yz + xw ) );
00113 m.set( 1, 3, 0.0 );
00114
00115 m.set( 2, 0, ( xz + yw ) );
00116 m.set( 2, 1, ( yz - xw ) );
00117 m.set( 2, 2, 1.0 - ( xx + yy ) );
00118 m.set( 2, 3, 0.0 );
00119
00120 m.set( 3, 0, 0.0 );
00121 m.set( 3, 1, 0.0 );
00122 m.set( 3, 2, 0.0 );
00123 m.set( 3, 3, 1.0 );
00124 }
00125
00127 math::matrix4
00128 math::quaternion::get_transposed_rotation_matrix( void ) const
00129 {
00130 math::matrix4 m;
00131 get_transposed_rotation_matrix( m );
00132 return m;
00133 }
00134
00136
00137 math::quaternion
00138 math::quaternion::operator* ( const math::quaternion& rhs ) const
00139 {
00140 return math::quaternion(
00141 rhs.m_w * m_v.x() + rhs.m_v.x() * m_w +
00142 rhs.m_v.z() * m_v.y() - rhs.m_v.y() * m_v.z(),
00143 rhs.m_w * m_v.y() + rhs.m_v.y() * m_w +
00144 rhs.m_v.x() * m_v.z() - rhs.m_v.z() * m_v.x(),
00145 rhs.m_w * m_v.z() + rhs.m_v.z() * m_w +
00146 rhs.m_v.y() * m_v.x() - rhs.m_v.x() * m_v.y(),
00147 rhs.m_w * m_w - rhs.m_v.x() * m_v.x() -
00148 rhs.m_v.y() * m_v.y() - rhs.m_v.z() * m_v.z()
00149 );
00150 }
00151
00153 math::vector3
00154 math::quaternion::operator* ( const math::vector3& rhs ) const
00155 {
00156 math::matrix4 rotation;
00157 get_rotation_matrix( rotation );
00158 return rotation * rhs;
00159 }
00160
00161
00163 void
00164 math::quaternion::from_angle_axis( real_t radians, const math::vector3& axis )
00165 {
00166
00167 assert( math::equals( axis.length( ), 1.0 ) );
00168
00169 radians *= 0.5;
00170 math::multiply( m_v, axis, sin( radians ) );
00171 m_w = cos( radians );
00172 }
00173
00175 void
00176 math::quaternion::get_angle_axis( real_t& radians, math::vector3& axis ) const
00177 {
00178
00179 assert( math::equals( magnitude( ), 1.0 ) );
00180
00181
00182 radians = acos( m_w ) * 2.0;
00183
00184
00185 real_t sin_a = sqrt( 1.0 - m_w * m_w );
00186
00187
00188 if( math::equals( sin_a, 0.0 ) ) {
00189 sin_a = 1.0;
00190 }
00191
00192
00193 axis.set(
00194 m_v.x( ) / sin_a,
00195 m_v.y( ) / sin_a,
00196 m_v.z( ) / sin_a
00197 );
00198 }
00199
00201
00202 void
00203 math::quaternion::from_angles( real_t x_rad, real_t y_rad,
00204 real_t z_rad )
00205 {
00206 math::quaternion q1, q2;
00207 q1.from_angle_axis( x_rad, math::vector3::X_AXIS );
00208 q2.from_angle_axis( y_rad, math::vector3::Y_AXIS );
00209 q1 = q1 * q2;
00210 q2.from_angle_axis( z_rad, math::vector3::Z_AXIS );
00211 q1 = q1 * q2;
00212 q1.normalize( );
00213 *this = q1;
00214 }
00215
00217
00218
00219
00220 void
00221 math::quaternion::from_matrix3( const real_t *mat )
00222 {
00223
00224 real_t s;
00225 real_t t = 1.0 + mat[ 0 ] + mat[ 4 ] + mat[ 8 ];
00226 if( t > 0.000001 ) {
00227
00228 s = sqrt( t ) * 2.0;
00229 m_v.x( (mat[ 7 ] - mat[ 5 ]) / s );
00230 m_v.y( (mat[ 2 ] - mat[ 6 ]) / s );
00231 m_v.z( (mat[ 3 ] - mat[ 1 ]) / s );
00232 m_w = 0.25 * s;
00233 return;
00234 }
00235
00236 if( mat[ 0 ] > mat[ 4 ] && mat[ 0 ] > mat[ 8 ] ) {
00237 s = sqrt( 1.0 + mat[ 0 ] - mat[ 4 ] - mat[ 8 ] ) * 2.0;
00238 m_v.x( 0.25 * s );
00239 m_v.y( (mat[ 3 ] + mat[ 1 ]) / s );
00240 m_v.z( (mat[ 2 ] + mat[ 6 ]) / s );
00241 m_w = (mat[ 7 ] - mat[ 5 ]) / s;
00242 } else if( mat[ 4 ] > mat[ 8 ] ) {
00243 s = sqrt( 1.0 + mat[ 4 ] - mat[ 0 ] - mat[ 8 ]) * 2;
00244 m_v.x( (mat[ 3 ] + mat[ 1 ]) / s );
00245 m_v.y( 0.25 * s );
00246 m_v.z( (mat[ 7 ] + mat[ 5 ]) / s );
00247 m_w = (mat[ 2 ] - mat[ 6 ]) / s;
00248 } else {
00249 s = sqrt( 1.0 + mat[ 8 ] - mat[ 0 ] - mat[ 4 ]) * 2;
00250 m_v.x( (mat[ 2 ] + mat[ 6 ]) / s );
00251 m_v.y( (mat[ 7 ] + mat[ 5 ]) / s );
00252 m_v.z( 0.25 * s );
00253 m_w = (mat[ 3 ] - mat[ 1 ]) / s;
00254 }
00255 }
00256
00258
00259
00260
00261 void
00262 math::quaternion::from_matrix4( const real_t *mat )
00263 {
00264
00265 real_t s;
00266 real_t t = 1.0 + mat[ 0 ] + mat[ 5 ] + mat[ 10 ];
00267 if( t > 0.000001 ) {
00268
00269 s = sqrt( t ) * 2.0;
00270 m_v.x( (mat[ 9 ] - mat[ 6 ]) / s );
00271 m_v.y( (mat[ 2 ] - mat[ 8 ]) / s );
00272 m_v.z( (mat[ 4 ] - mat[ 1 ]) / s );
00273 m_w = 0.25 * s;
00274 return;
00275 }
00276
00277 if( mat[ 0 ] > mat[ 5 ] && mat[ 0 ] > mat[ 10 ] ) {
00278 s = sqrt( 1.0 + mat[ 0 ] - mat[ 5 ] - mat[ 10 ] ) * 2.0;
00279 m_v.x( 0.25 * s );
00280 m_v.y( (mat[ 4 ] + mat[ 1 ]) / s );
00281 m_v.z( (mat[ 2 ] + mat[ 8 ]) / s );
00282 m_w = (mat[ 9 ] - mat[ 6 ]) / s;
00283 } else if( mat[ 5 ] > mat[ 10 ] ) {
00284 s = sqrt( 1.0 + mat[ 5 ] - mat[ 0 ] - mat[ 10 ]) * 2;
00285 m_v.x( (mat[ 4 ] + mat[ 1 ]) / s );
00286 m_v.y( 0.25 * s );
00287 m_v.z( (mat[ 9 ] + mat[ 6 ]) / s );
00288 m_w = (mat[ 2 ] - mat[ 8 ]) / s;
00289 } else {
00290 s = sqrt( 1.0 + mat[ 10 ] - mat[ 0 ] - mat[ 5 ]) * 2;
00291 m_v.x( (mat[ 2 ] + mat[ 8 ]) / s );
00292 m_v.y( (mat[ 9 ] + mat[ 6 ]) / s );
00293 m_v.z( 0.25 * s );
00294 m_w = (mat[ 4 ] - mat[ 1 ]) / s;
00295 }
00296 }
00297
00299
00300 math::quaternion
00301 math::quaternion::slerp( real_t percent, const math::quaternion& qa,
00302 math::quaternion qb )
00303 {
00304
00305 if( math::equals( qa.w( ), qb.w( ) ) && qa.v( ) == qb.v( ) ) {
00306 return qa;
00307 }
00308
00309 real_t cos_a = qa.w( ) * qb.w( ) + math::dot( qa.v( ), qb.v( ) );
00310 if( cos_a < 0.0 ) {
00311 qb.m_v.negate( );
00312 qb.m_w *= -1.0;
00313 cos_a = -cos_a;
00314 }
00315
00316
00317 real_t a = 1.0 - percent;
00318 real_t b = percent;
00319
00320
00321 if( 1 - cos_a > 0.1 ) {
00322 real_t angle = acos( cos_a );
00323 real_t inverse_sin = 1.0 / sin( angle );
00324 a = sin( (1.0 - percent) * angle ) * inverse_sin;
00325 b = sin( percent * angle) * inverse_sin;
00326 }
00327
00328 return math::quaternion(
00329 a * qa.x( ) + b * qb.x( ),
00330 a * qa.y( ) + b * qb.y( ),
00331 a * qa.z( ) + b * qb.z( ),
00332 a * qa.w( ) + b * qb.w( )
00333 );
00334 }
00335
00337 std::ostream&
00338 math::operator<< ( std::ostream& o, const math::quaternion& q )
00339 {
00340 return o << q.m_v << " " << q.m_w;
00341 }