Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

quaternion.cpp

00001 //FILE:         quaternion.cpp
00002 //AUTHOR:       Nathan Cournia <nathan@cournia.com>
00003 
00004 #include <cassert>
00005 #include "quaternion.h"
00006 
00008 const math::quaternion math::quaternion::IDENTITY( 
00009         0.0, 0.0, 0.0, //xyz
00010         1.0 //w
00011 );
00012 
00014 void
00015 math::quaternion::get_rotation_matrix( math::matrix4& m ) const
00016 {
00017         real_t x2 = m_v.x( ) + m_v.x( );
00018         real_t y2 = m_v.y( ) + m_v.y( );
00019         real_t z2 = m_v.z( ) + m_v.z( );
00020 
00021         real_t xx = m_v.x( ) * x2;
00022         real_t xy = m_v.x( ) * y2;
00023         real_t xz = m_v.x( ) * z2;
00024         real_t xw = x2 * m_w;
00025 
00026         real_t yy = m_v.y( ) * y2;
00027         real_t yz = m_v.y( ) * z2;
00028         real_t yw = y2 * m_w;
00029 
00030         real_t zz = m_v.z( ) * z2;
00031         real_t zw = z2 * m_w;
00032 
00033         m.set( 0, 0, 1.0 - ( yy + zz ) );
00034         m.set( 0, 1, ( xy - zw ) );
00035         m.set( 0, 2, ( xz + yw ) );
00036         m.set( 0, 3, 0.0 );
00037 
00038         m.set( 1, 0, ( xy + zw ) );
00039         m.set( 1, 1, 1.0 - ( xx + zz ) );
00040         m.set( 1, 2, ( yz - xw ) );
00041         m.set( 1, 3, 0.0 );
00042 
00043         m.set( 2, 0, ( xz - yw ) );
00044         m.set( 2, 1, ( yz + xw ) );
00045         m.set( 2, 2, 1.0 - ( xx + yy ) );
00046         m.set( 2, 3, 0.0 );
00047 
00048         m.set( 3, 0, 0.0 );
00049         m.set( 3, 1, 0.0 );
00050         m.set( 3, 2, 0.0 );
00051         m.set( 3, 3, 1.0 );
00052 }
00053 
00055 math::matrix4
00056 math::quaternion::get_rotation_matrix( void ) const
00057 {
00058         math::matrix4 m;
00059         get_rotation_matrix( m );
00060         return m;
00061 }
00062 
00064 void
00065 math::quaternion::get_transposed_rotation_matrix( math::matrix4& m ) const
00066 {
00067         real_t x2 = m_v.x( ) + m_v.x( );
00068         real_t y2 = m_v.y( ) + m_v.y( );
00069         real_t z2 = m_v.z( ) + m_v.z( );
00070 
00071         real_t xx = m_v.x( ) * x2;
00072         real_t xy = m_v.x( ) * y2;
00073         real_t xz = m_v.x( ) * z2;
00074         real_t xw = x2 * m_w;
00075 
00076         real_t yy = m_v.y( ) * y2;
00077         real_t yz = m_v.y( ) * z2;
00078         real_t yw = y2 * m_w;
00079 
00080         real_t zz = m_v.z( ) * z2;
00081         real_t zw = z2 * m_w;
00082 
00083         m.set( 0, 0, 1.0 - ( yy + zz ) );
00084         m.set( 0, 1, ( xy + zw ) );
00085         m.set( 0, 2, ( xz - yw ) );
00086         m.set( 0, 3, 0.0 );
00087 
00088         m.set( 1, 0, ( xy - zw ) );
00089         m.set( 1, 1, 1.0 - ( xx + zz ) );
00090         m.set( 1, 2, ( yz + xw ) );
00091         m.set( 1, 3, 0.0 );
00092 
00093         m.set( 2, 0, ( xz + yw ) );
00094         m.set( 2, 1, ( yz - xw ) );
00095         m.set( 2, 2, 1.0 - ( xx + yy ) );
00096         m.set( 2, 3, 0.0 );
00097 
00098         m.set( 3, 0, 0.0 );
00099         m.set( 3, 1, 0.0 );
00100         m.set( 3, 2, 0.0 );
00101         m.set( 3, 3, 1.0 );
00102 }
00103 
00105 math::matrix4
00106 math::quaternion::get_transposed_rotation_matrix( void ) const
00107 {
00108         math::matrix4 m;
00109         get_transposed_rotation_matrix( m );
00110         return m;
00111 }
00112 
00114 //not communative
00115 math::quaternion
00116 math::quaternion::operator* ( const math::quaternion& rhs ) const
00117 {
00118         return math::quaternion( 
00119                 rhs.m_w * m_v.x() + rhs.m_v.x() * m_w + 
00120                         rhs.m_v.z() * m_v.y() - rhs.m_v.y() * m_v.z(), //x
00121                 rhs.m_w * m_v.y() + rhs.m_v.y() * m_w + 
00122                         rhs.m_v.x() * m_v.z() - rhs.m_v.z() * m_v.x(), //y
00123                 rhs.m_w * m_v.z() + rhs.m_v.z() * m_w + 
00124                         rhs.m_v.y() * m_v.x() - rhs.m_v.x() * m_v.y(),  //z
00125                 rhs.m_w * m_w - rhs.m_v.x() * m_v.x() - 
00126                         rhs.m_v.y() * m_v.y() - rhs.m_v.z() * m_v.z() //w
00127                 );
00128 }
00129 
00131 math::vector3 
00132 math::quaternion::operator* ( const math::vector3& rhs ) const
00133 {
00134         math::matrix4 rotation;
00135         get_rotation_matrix( rotation );
00136         return rotation * rhs;
00137 }
00138         
00139 
00141 void
00142 math::quaternion::from_angle_axis( real_t radians, const math::vector3& axis )
00143 {
00144         //axis should be normalized
00145         assert( math::equals( axis.length( ), 1.0 ) );
00146 
00147         radians *= 0.5;
00148         math::multiply( m_v, axis, sin( radians ) );
00149         m_w = cos( radians );
00150 }
00151         
00153 void
00154 math::quaternion::get_angle_axis( real_t& radians, math::vector3& axis ) const
00155 {
00156         //math::quaternion should be normalized
00157         assert( math::equals( magnitude( ), 1.0 ) );
00158 
00159         //angle
00160         radians = acos( m_w ) * 2.0;
00161 
00162         //axis
00163         real_t sin_a = sqrt( 1.0 - m_w * m_w );
00164 
00165         //make sure we don't divide by zero
00166         if( math::equals( sin_a, 0.0 ) ) {
00167                 sin_a = 1.0;
00168         }
00169 
00170         //set the axis
00171         axis.set( 
00172                 m_v.x( ) / sin_a, 
00173                 m_v.y( ) / sin_a, 
00174                 m_v.z( ) / sin_a 
00175         );
00176 }
00177 
00179 math::quaternion
00180 math::quaternion::slerp( real_t percent, const math::quaternion& qa, 
00181         const math::quaternion& qb )
00182 {
00183         real_t cos_a = qa.w( ) * qb.w( ) + 
00184         //real_t cos_a = qa.m_w * qb.m_w + 
00185                 math::dot( qa.v( ), qb.v( ) );
00186         real_t angle = acos( cos_a );
00187 
00188         if( math::equals( angle, 0.0 ) ) {
00189                 //same
00190                 return qa;
00191         }
00192 
00193         real_t sin_a = sin( angle );
00194         real_t inverse_sin = 1.0 / sin_a;
00195         real_t a = sin( (1.0 - percent) * angle ) * inverse_sin;
00196         real_t b = sin( percent * angle) * inverse_sin;
00197         return math::quaternion( 
00198                         a * qa.x( ) + b * qb.x( ),
00199                         a * qa.y( ) + b * qb.y( ),
00200                         a * qa.z( ) + b * qb.z( ),
00201                         a * qa.w( ) + b * qb.w( )
00202                 );
00203 }
00204 
00206 std::ostream& 
00207 operator<< ( std::ostream& o, const math::quaternion& q )
00208 {
00209         return o << q.m_v << " " << q.m_w;
00210 }

Generated on Tue Feb 11 18:49:41 2003 for uber by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002