00001
00002
00003
00004 #include <cassert>
00005 #include "quaternion.h"
00006
00008 const math::quaternion math::quaternion::IDENTITY(
00009 0.0, 0.0, 0.0,
00010 1.0
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
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(),
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(),
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(),
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()
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
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
00157 assert( math::equals( magnitude( ), 1.0 ) );
00158
00159
00160 radians = acos( m_w ) * 2.0;
00161
00162
00163 real_t sin_a = sqrt( 1.0 - m_w * m_w );
00164
00165
00166 if( math::equals( sin_a, 0.0 ) ) {
00167 sin_a = 1.0;
00168 }
00169
00170
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
00185 math::dot( qa.v( ), qb.v( ) );
00186 real_t angle = acos( cos_a );
00187
00188 if( math::equals( angle, 0.0 ) ) {
00189
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 }