33 #ifndef __VMML__QUATERNION__HPP__
34 #define __VMML__QUATERNION__HPP__
36 #include <vmmlib/enable_if.hpp>
37 #include <vmmlib/math.hpp>
38 #include <vmmlib/types.hpp>
39 #include <vmmlib/vector.hpp>
52 #define QUATERNION_TRACE_EPSILON 1e-5
76 T tolerance = std::numeric_limits< T >::epsilon( ))
const;
78 T x()
const {
return array[0]; }
79 T y()
const {
return array[1]; }
80 T z()
const {
return array[2]; }
81 T w()
const {
return array[3]; }
86 template<
size_t D >
void set(
const matrix< D, D, T >& rotation_matrix_ );
88 bool operator==(
const T& a )
const;
89 bool operator!=(
const T& a )
const;
95 const T& delta = std::numeric_limits< T >::epsilon() );
101 T squared_abs()
const;
114 quaternion operator+(
const quaternion< T >& a )
const;
115 quaternion operator-(
const quaternion< T >& a )
const;
117 quaternion operator*(
const quaternion< T >& a )
const;
118 void operator+=(
const quaternion< T >& a );
119 void operator-=(
const quaternion< T >& a );
121 void operator*=(
const quaternion< T >& a );
129 void operator*=( T a );
130 void operator/=( T a );
135 T dot(
const quaternion< T >& a )
const;
136 static T dot(
const quaternion< T >& a,
const quaternion< T >& b );
145 const quaternion& q,
const T epsilon = 1e-13 );
147 matrix< 3, 3, T > get_rotation_matrix()
const;
149 template<
size_t D >
void get_rotation_matrix( matrix< D, D, T >& result )
const;
156 friend std::ostream& operator<< ( std::ostream& os,
const quaternion& q )
158 const std::ios::fmtflags flags = os.flags();
159 const int prec = os.precision();
161 os.setf( std::ios::right, std::ios::adjustfield );
165 << std::setw(10) << q.x() <<
" "
166 << std::setw(10) << q.y() <<
" "
167 << std::setw(10) << q.z() <<
" "
168 << std::setw(10) << q.w() <<
" "
171 os.precision( prec );
181 #include <vmmlib/matrix.hpp>
187 template <
typename T >
188 const quaternion< T > quaternion< T >::IDENTITY( 0, 0, 0, 1 );
190 template <
typename T >
191 const quaternion< T > quaternion< T >::QUATERI( 1, 0, 0, 0 );
193 template <
typename T >
194 const quaternion< T > quaternion< T >::QUATERJ( 0, 1, 0, 0 );
196 template <
typename T >
197 const quaternion< T > quaternion< T >::QUATERK( 0, 0, 1, 0 );
199 template <
typename T >
209 template<
typename T >
template<
size_t M >
211 typename enable_if< M >= 3 >::type* )
213 this->
template set< M >( rotation_matrix_ );
216 template<
typename T >
220 const T sinAngle2 = std::sin( angle * 0.5 );
221 array[0] = axis.x() * sinAngle2;
222 array[1] = axis.y() * sinAngle2;
223 array[2] = axis.z() * sinAngle2;
224 array[3] = std::cos( angle * 0.5 );
227 template<
typename T >
230 return std::abs( array[0] - other.array[0] ) <= tolerance &&
231 std::abs( array[1] - other.array[1] ) <= tolerance &&
232 std::abs( array[2] - other.array[2] ) <= tolerance &&
233 std::abs( array[3] - other.array[3] ) <= tolerance;
238 template <
typename T >
template<
size_t D >
241 T trace = M( 0, 0 ) + M( 1, 1 ) + M( 2,2 ) + 1.0;
244 if( trace > QUATERNION_TRACE_EPSILON )
246 T s = 0.5 / std::sqrt( trace );
247 array[0] = M( 2, 1 ) - M( 1, 2 );
250 array[1] = M( 0, 2 ) - M( 2, 0 );
253 array[2] = M( 1, 0 ) - M( 0, 1 );
261 size_t largest = diag.find_max_index();
266 T s = 0.5 / std::sqrt( 1.0 + M( 0, 0 ) - M( 1, 1 ) - M( 2, 2 ) );
269 array[1] = M( 0,1 ) + M( 1,0 );
272 array[2] = M( 0,2 ) + M( 2,0 );
275 array[3] = M( 1,2 ) - M( 2,1 );
278 else if ( largest == 1 )
280 T s = 0.5 / std::sqrt( 1.0 + M( 1,1 ) - M( 0,0 ) - M( 2,2 ) );
281 array[0] = M( 0,1 ) + M( 1,0 );
286 array[2] = M( 1,2 ) + M( 2,1 );
289 array[3] = M( 0,2 ) - M( 2,0 );
293 else if ( largest == 2 )
295 T s = 0.5 / std::sqrt( 1.0 + M( 2,2 ) - M( 0,0 ) - M( 1,1 ) );
296 array[0] = M( 0,2 ) + M( 2,0 );
299 array[1] = M( 1,2 ) + M( 2,1 );
304 array[3] = M( 0,1 ) - M( 1,0 );
309 throw std::runtime_error(
"no clue why, but should not get here" );
316 template <
typename T >
317 void quaternion< T >::zero()
319 ::memset( array, 0,
sizeof( array ));
324 template <
typename T >
325 void quaternion< T >::identity()
330 template <
typename T >
331 bool quaternion< T >::operator==(
const quaternion& rhs )
const
334 array[3] == rhs.array[3] &&
335 array[0] == rhs.array[0] &&
336 array[1] == rhs.array[1] &&
337 array[2] == rhs.array[2]
343 template <
typename T >
345 quaternion< T >::operator!=(
const quaternion& a )
const
347 return ! this->operator==( a );
350 template <
typename T >
351 void quaternion< T >::conjugate()
353 array[0] = -array[0];
354 array[1] = -array[1];
355 array[2] = -array[2];
360 template <
typename T >
361 quaternion< T > quaternion< T >::get_conjugate()
const
363 return quaternion< T > ( -array[0], -array[1], -array[2], array[3] );
368 template <
typename T >
370 quaternion< T >::abs()
const
372 return std::sqrt( squared_abs() );
377 template <
typename T >
378 T quaternion< T >::squared_abs()
const
380 return array[0] * array[0] + array[1] * array[1] + array[2] * array[2] + array[3] * array[3];
385 template <
typename T >
386 quaternion< T > quaternion< T >::inverse()
388 quaternion< T > q( *
this );
391 T tmp = squared_abs();
392 tmp =
static_cast< T
>( 1.0 ) / tmp;
398 template <
typename T >
399 T quaternion< T >::normalize()
405 this->operator*=( len );
411 template <
typename T >
413 quaternion< T >::get_normalized()
const
415 quaternion< T > q( *
this );
426 template <
typename T >
428 quaternion< T >::operator+(
const quaternion< T >& rhs )
const
430 return quaternion( array[0] + rhs.array[0], array[1] + rhs.array[1], array[2] + rhs.array[2], array[3] + rhs.array[3] );
435 template <
typename T >
437 quaternion< T >::operator-(
const quaternion< T >& rhs )
const
439 return quaternion( array[0] - rhs.array[0], array[1] - rhs.array[1], array[2] - rhs.array[2], array[3] - rhs.array[3] );
445 template <
typename T >
446 quaternion< T > quaternion< T >::operator*(
const quaternion< T >& rhs )
const
448 quaternion< T > ret( *
this );
456 template <
typename T >
457 void quaternion< T >::operator*=(
const quaternion< T >& q )
460 quaternion< T > orig( *
this );
461 array[0] = orig.array[3] * a.array[0] + orig.array[0] * a.array[3] + orig.array[1] * a.array[2] - orig.array[2] * a.array[1];
462 array[1] = orig.array[3] * a.array[1] + orig.array[1] * a.array[3] + orig.array[2] * a.array[0] - orig.array[0] * a.array[2];
463 array[2] = orig.array[3] * a.array[2] + orig.array[2] * a.array[3] + orig.array[0] * a.array[1] - orig.array[1] * a.array[0];
464 array[3] = orig.array[3] * a.array[3] - orig.array[0] * a.array[0] - orig.array[1] * a.array[1] - orig.array[2] * a.array[2];
470 const T& a_ = array[ 3 ];
471 const T& b_ = array[ 0 ];
472 const T& c = array[ 1 ];
473 const T& d = array[ 2 ];
474 const T& _x = q.array[ 3 ];
475 const T& _y = q.array[ 0 ];
476 const T& _z = q.array[ 1 ];
477 const T& _w = q.array[ 2 ];
479 const T tmp_00 = (d - c) * (_z - _w);
480 const T tmp_01 = (a_ + b_) * (_x + _y);
481 const T tmp_02 = (a_ - b_) * (_z + _w);
482 const T tmp_03 = (c + d) * (_x - _y);
483 const T tmp_04 = (d - b_) * (_y - _z);
484 const T tmp_05 = (d + b_) * (_y + _z);
485 const T tmp_06 = (a_ + c) * (_x - _w);
486 const T tmp_07 = (a_ - c) * (_x + _w);
487 const T tmp_08 = tmp_05 + tmp_06 + tmp_07;
488 const T tmp_09 = 0.5 * (tmp_04 + tmp_08);
490 array[ 3 ] = tmp_00 + tmp_09 - tmp_05;
491 array[ 0 ] = tmp_01 + tmp_09 - tmp_08;
492 array[ 1 ] = tmp_02 + tmp_09 - tmp_07;
493 array[ 2 ] = tmp_03 + tmp_09 - tmp_06;
502 template <
typename T >
504 quaternion< T >::operator-()
const
506 return quaternion( -array[0], -array[1], -array[2], -array[3] );
511 template <
typename T >
512 void quaternion< T >::operator+=(
const quaternion< T >& q )
514 array[ 0 ] += q.array[ 0 ];
515 array[ 1 ] += q.array[ 1 ];
516 array[ 2 ] += q.array[ 2 ];
517 array[ 3 ] += q.array[ 3 ];
522 template <
typename T >
523 void quaternion< T >::operator-=(
const quaternion< T >& q )
525 array[ 0 ] -= q.array[ 0 ];
526 array[ 1 ] -= q.array[ 1 ];
527 array[ 2 ] -= q.array[ 2 ];
528 array[ 3 ] -= q.array[ 3 ];
537 template <
typename T >
539 quaternion< T >::operator*(
const T a_ )
const
541 return quaternion( array[0] * a_, array[1] * a_, array[2] * a_, array[3] * a_ );
546 template <
typename T >
548 quaternion< T >::operator/( T a_ )
const
551 throw std::runtime_error(
"Division by zero." );
554 return quaternion( array[0] * a_, array[1] * a_, array[2] * a_, array[3] * a_ );
559 template <
typename T >
560 void quaternion< T >::operator*=( T q )
570 template <
typename T >
571 void quaternion< T >::operator/=( T q )
574 throw std::runtime_error(
"Division by zero" );
577 this->operator*=( q );
581 template <
typename T >
582 vector< 3, T > quaternion< T >::cross(
const quaternion< T >& bb )
const
586 result.
array[ 0 ] = array[1] * bb.array[2] - array[2] * bb.array[1];
587 result.
array[ 1 ] = array[2] * bb.array[0] - array[0] * bb.array[2];
588 result.
array[ 2 ] = array[0] * bb.array[1] - array[1] * bb.array[0];
595 template <
typename T >
596 T quaternion< T >::dot(
const quaternion< T >& q )
const
598 return array[3] * q.
array[3] + array[0] * q.array[0] + array[1] * q.array[1] + array[2] * q.array[2];
603 template <
typename T >
605 dot(
const quaternion< T >& p,
const quaternion< T >& q )
607 return p.array[3] * q.array[3] + p.array[0] * q.array[0] + p.array[1] * q.array[1] + p.array[2] * q.array[2];
612 template <
typename T >
613 void quaternion< T >::normal(
const quaternion< T >& aa,
614 const quaternion< T >& bb,
615 const quaternion< T >& cc,
616 const quaternion< T >& dd )
619 const quaternion< T > quat_t = bb - aa;
620 const quaternion< T > quat_u = cc - aa;
621 const quaternion< T > quat_v = dd - aa;
630 template <
typename T >
631 quaternion< T > quaternion< T >::normal(
const quaternion< T >& aa,
632 const quaternion< T >& bb,
633 const quaternion< T >& cc )
636 tmp.normal( *
this, aa, bb, cc );
640 template <
typename T >
642 quaternion< T >::get_rotation_matrix()
const
644 matrix< 3, 3, T > result;
645 get_rotation_matrix< 3 >( result );
651 template <
typename T >
template<
size_t D >
652 void quaternion< T >::get_rotation_matrix( matrix< D, D, T >& M )
const
654 T w2 = array[3] * array[3];
655 T x2 = array[0] * array[0];
656 T y2 = array[1] * array[1];
657 T z2 = array[2] * array[2];
658 T wx = array[3] * array[0];
659 T wy = array[3] * array[1];
660 T wz = array[3] * array[2];
661 T xy = array[0] * array[1];
662 T xz = array[0] * array[2];
663 T yz = array[1] * array[2];
665 M( 0, 0 ) = w2 + x2 - y2 - z2;
666 M( 0, 1 ) = 2. * (xy - wz);
667 M( 0, 2 ) = 2. * (xz + wy);
668 M( 1, 0 ) = 2. * (xy + wz);
669 M( 1, 1 ) = w2 - x2 + y2 - z2;
670 M( 1, 2 ) = 2. * (yz - wx);
671 M( 2, 0 ) = 2. * (xz - wy);
672 M( 2, 1 ) = 2. * (yz + wx);
673 M( 2, 2 ) = w2 - x2 - y2 + z2;
677 template<
typename T >
678 quaternion< T > quaternion< T >::
679 slerp( T a,
const quaternion< T >& p,
const quaternion< T >& q,
const T epsilon )
681 quaternion< T > px = p.get_normalized();
682 quaternion< T > qx = q.get_normalized();
684 T cosine = px.dot( qx );
693 const T abs_cos =
static_cast< T
>( fabs(cosine) );
694 const T one_x =
static_cast< T
>( 1. - epsilon );
695 if( abs_cos < one_x )
698 T sine = std::sqrt( 1. - ( cosine * cosine ) );
699 T angle = atan2( sine, cosine );
700 T coeff1 = std::sin( ( 1.0 - a ) * angle) / sine;
701 T coeff2 = std::sin( a * angle ) / sine;
721 template <
typename T >
722 quaternion< T >& quaternion< T >::operator=(
const quaternion& other)
724 memcpy( array, other.array, 4 *
sizeof( T ) );
bool equals(const quaternion &other, T tolerance=std::numeric_limits< T >::epsilon()) const
quaternion()
Construct an identity quaternion.
heavily inspired by boost::enable_if http://www.boost.org, file: boost/utility/enable_if.hpp, Copyright 2003 Jaakko Järvi, Jeremiah Willcock, Andrew Lumsdaine