All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Quaternion.h
Go to the documentation of this file.
1 //=================================================================================================
20 //=================================================================================================
21 
22 #ifndef _BLAZE_MATH_QUATERNION_H_
23 #define _BLAZE_MATH_QUATERNION_H_
24 
25 
26 //*************************************************************************************************
27 // Includes
28 //*************************************************************************************************
29 
30 #include <cmath>
31 #include <istream>
32 #include <ostream>
33 #include <blaze/math/Accuracy.h>
34 #include <blaze/math/Forward.h>
35 #include <blaze/math/shims/Equal.h>
37 #include <blaze/math/shims/IsNaN.h>
40 #include <blaze/system/Precision.h>
41 #include <blaze/util/Assert.h>
45 #include <blaze/util/Types.h>
46 
47 
48 namespace blaze {
49 
50 //=================================================================================================
51 //
52 // CLASS DEFINITION
53 //
54 //=================================================================================================
55 
56 //*************************************************************************************************
89 template< typename Type > // Data type of the quaternion
90 class Quaternion
91 {
92  public:
93  //**Type definitions****************************************************************************
94  typedef Type ElementType;
95  //**********************************************************************************************
96 
97  //**Constructors********************************************************************************
100  explicit inline Quaternion();
101 
102  explicit inline Quaternion( Type r, Type i, Type j, Type k );
103 
104  template< typename Axis >
105  explicit inline Quaternion( StaticVector<Axis,3UL,false> axis, Type angle );
106 
107  explicit inline Quaternion( Type xangle, Type yangle, Type zangle );
108 
109  template< typename Other >
110  explicit inline Quaternion( const StaticVector<Other,3UL,false>& euler );
111 
112  inline Quaternion( const Quaternion& q );
113 
114  template< typename Other >
115  inline Quaternion( const Quaternion<Other>& q );
117  //**********************************************************************************************
118 
119  //**Destructor**********************************************************************************
120  // No explicitly declared destructor.
121  //**********************************************************************************************
122 
123  //**Operators***********************************************************************************
126  inline Quaternion& operator= ( const Quaternion& rhs );
127  template< typename Other > inline Quaternion& operator= ( const Quaternion<Other>& rhs );
128  inline Type operator[]( size_t index ) const;
130  //**********************************************************************************************
131 
132  //**Utility functions***************************************************************************
135  inline Quaternion& set( Type r, Type i, Type j, Type k );
136  inline void reset();
137  inline Type length() const;
138  inline Quaternion& normalize();
139  inline const Quaternion getNormalized() const;
140  inline Quaternion& invert();
141  inline const RotationMatrix<Type> toRotationMatrix() const;
142  inline void rotateX( Type angle );
143  inline void rotateY( Type angle );
144  inline void rotateZ( Type angle );
145  inline void swap( Quaternion& q ) /* throw() */;
147  //**********************************************************************************************
148 
149  //**Math functions******************************************************************************
152  template< typename Other, bool TF >
154  rotate( const StaticVector<Other,3UL,TF>& v ) const;
155 
156  template< typename Other >
157  inline const StaticMatrix<typename MultTrait<Type,Other>::Type,3UL,3UL,false>
158  rotate( const StaticMatrix<Other,3UL,3UL,false>& m ) const;
159 
160  template< typename Other >
161  inline const StaticMatrix<typename MultTrait<Type,Other>::Type,3UL,3UL,false>
163 
164  template< typename Other >
165  inline typename MathTrait<Type,Other>::HighType
166  calcAngle( const StaticVector<Other,3UL,false>& axis ) const;
168  //**********************************************************************************************
169 
170  private:
171  //**Member variables****************************************************************************
174  Type v_[4];
175 
181  //**********************************************************************************************
182 
183  //**Compile time checks*************************************************************************
189  //**********************************************************************************************
190 };
191 //*************************************************************************************************
192 
193 
194 
195 
196 //=================================================================================================
197 //
198 // CONSTRUCTORS
199 //
200 //=================================================================================================
201 
202 //*************************************************************************************************
210 template< typename Type > // Data type of the quaternion
212 {
213  reset();
214 }
215 //*************************************************************************************************
216 
217 
218 //*************************************************************************************************
229 template< typename Type > // Data type of the quaternion
230 inline Quaternion<Type>::Quaternion( Type r, Type i, Type j, Type k )
231 {
232  v_[0] = r; v_[1] = i; v_[2] = j; v_[3] = k;
233  BLAZE_USER_ASSERT( std::fabs( r*r + i*i + j*j + k*k - Type(1) ) < Type(accuracy), "Invalid quaternion parameters" );
234 }
235 //*************************************************************************************************
236 
237 
238 //*************************************************************************************************
251 template< typename Type > // Data type of the quaternion
252 template< typename Axis > // Data type of the rotation axis
254 {
256 
257  if( std::fabs(angle) < real(1E-15) ) {
258  reset();
259  return;
260  }
261 
262  BLAZE_USER_ASSERT( axis.sqrLength() > Axis(0), "Invalid rotation axis" );
263 
264  const Type sina( std::sin( angle*Type(0.5) ) );
265  const Type cosa( std::cos( angle*Type(0.5) ) );
266 
267  axis.normalize();
268 
269  v_[0] = cosa;
270  v_[1] = sina * axis[0];
271  v_[2] = sina * axis[1];
272  v_[3] = sina * axis[2];
273 }
274 //*************************************************************************************************
275 
276 
277 //*************************************************************************************************
287 template< typename Type > // Data type of the quaternion
288 inline Quaternion<Type>::Quaternion( Type xangle, Type yangle, Type zangle )
289 {
290  reset();
291  rotateX( xangle );
292  rotateY( yangle );
293  rotateZ( zangle );
294 }
295 //*************************************************************************************************
296 
297 
298 //*************************************************************************************************
306 template< typename Type > // Data type of the quaternion
307 template< typename Other > // Data type of the Euler angle vector
309 {
310  reset();
311  rotateX( euler[0] );
312  rotateY( euler[1] );
313  rotateZ( euler[2] );
314 }
315 //*************************************************************************************************
316 
317 
318 //*************************************************************************************************
325 template< typename Type > // Data type of the quaternion
327 {
328  v_[0] = q.v_[0];
329  v_[1] = q.v_[1];
330  v_[2] = q.v_[2];
331  v_[3] = q.v_[3];
332 }
333 //*************************************************************************************************
334 
335 
336 //*************************************************************************************************
341 template< typename Type > // Data type of the quaternion
342 template< typename Other > // Data type of the foreign quaternion
344 {
345  v_[0] = q[0];
346  v_[1] = q[1];
347  v_[2] = q[2];
348  v_[3] = q[3];
349 }
350 //*************************************************************************************************
351 
352 
353 
354 
355 //=================================================================================================
356 //
357 // OPERATORS
358 //
359 //=================================================================================================
360 
361 //*************************************************************************************************
369 template< typename Type > // Data type of the quaternion
371 {
372  // This implementation is faster than the synthesized default copy assignment operator and
373  // faster than an implementation with the C library function 'memcpy' in combination with a
374  // protection against self-assignment. Additionally, this version goes without a protection
375  // against self-assignment.
376  v_[0] = rhs.v_[0];
377  v_[1] = rhs.v_[1];
378  v_[2] = rhs.v_[2];
379  v_[3] = rhs.v_[3];
380  return *this;
381 }
382 //*************************************************************************************************
383 
384 
385 //*************************************************************************************************
391 template< typename Type > // Data type of the quaternion
392 template< typename Other > // Data type of the foreign quaternion
394 {
395  // This implementation is faster than the synthesized default copy assignment operator and
396  // faster than an implementation with the C library function 'memcpy' in combination with a
397  // protection against self-assignment. Additionally, this version goes without a protection
398  // against self-assignment.
399  v_[0] = rhs[0];
400  v_[1] = rhs[1];
401  v_[2] = rhs[2];
402  v_[3] = rhs[3];
403  return *this;
404 }
405 //*************************************************************************************************
406 
407 
408 //*************************************************************************************************
416 template< typename Type > // Data type of the quaternion
417 inline Type Quaternion<Type>::operator[]( size_t index ) const
418 {
419  BLAZE_USER_ASSERT( index < 4, "Invalid quaternion access index" );
420  return v_[index];
421 }
422 //*************************************************************************************************
423 
424 
425 
426 
427 //=================================================================================================
428 //
429 // UTILITY FUNCTIONS
430 //
431 //=================================================================================================
432 
433 //*************************************************************************************************
441 template< typename Type > // Data type of the quaternion
442 inline Quaternion<Type>& Quaternion<Type>::set( Type r, Type i, Type j, Type k )
443 {
444  BLAZE_USER_ASSERT( std::fabs( r*r + i*i + j*j + k*k - Type(1) ) < Type(1E-8), "Invalid quaternion parameters" );
445  v_[0] = r;
446  v_[1] = i;
447  v_[2] = j;
448  v_[3] = k;
449  return *this;
450 }
451 //*************************************************************************************************
452 
453 
454 //*************************************************************************************************
466 template< typename Type > // Data type of the quaternion
468 {
469  v_[0] = Type(1);
470  v_[1] = v_[2] = v_[3] = Type(0);
471 }
472 //*************************************************************************************************
473 
474 
475 //*************************************************************************************************
480 template< typename Type > // Data type of the quaternion
481 inline Type Quaternion<Type>::length() const
482 {
483  // Although the length of the quaternion should always be exactly one, the function
484  // calculates the actual length to enable length checks.
485  return std::sqrt( v_[0]*v_[0] + v_[1]*v_[1] + v_[2]*v_[2] + v_[3]*v_[3] );
486 }
487 //*************************************************************************************************
488 
489 
490 //*************************************************************************************************
495 template< typename Type > // Data type of the quaternion
497 {
498  const Type len( std::sqrt( v_[0]*v_[0] + v_[1]*v_[1] + v_[2]*v_[2] + v_[3]*v_[3] ) );
499 
500  if( len == Type(0) )
501  return *this;
502 
503  const Type ilen( Type(1)/len );
504 
505  v_[0] *= ilen;
506  v_[1] *= ilen;
507  v_[2] *= ilen;
508  v_[3] *= ilen;
509 
510  return *this;
511 }
512 //*************************************************************************************************
513 
514 
515 //*************************************************************************************************
520 template< typename Type > // Data type of the quaternion
522 {
523  const Type len( std::sqrt( v_[0]*v_[0] + v_[1]*v_[1] + v_[2]*v_[2] + v_[3]*v_[3] ) );
524 
525  if( len == Type(0) )
526  return *this;
527 
528  const Type ilen( Type(1)/len );
529 
530  return Quaternion( ilen*v_[0], ilen*v_[1], ilen*v_[2], ilen*v_[3] );
531 }
532 //*************************************************************************************************
533 
534 
535 //*************************************************************************************************
540 template< typename Type > // Data type of the quaternion
542 {
543  v_[1] *= -Type(1);
544  v_[2] *= -Type(1);
545  v_[3] *= -Type(1);
546  return *this;
547 }
548 //*************************************************************************************************
549 
550 
551 //*************************************************************************************************
556 template< typename Type > // Data type of the quaternion
558 {
559  return RotationMatrix<Type>( Type(1) - Type(2)*v_[2]*v_[2] - Type(2)*v_[3]*v_[3],
560  Type(2)*( v_[1]*v_[2] - v_[0]*v_[3] ),
561  Type(2)*( v_[1]*v_[3] + v_[0]*v_[2] ),
562  Type(2)*( v_[1]*v_[2] + v_[0]*v_[3] ),
563  Type(1) - Type(2)*v_[1]*v_[1] - Type(2)*v_[3]*v_[3],
564  Type(2)*( v_[2]*v_[3] - v_[0]*v_[1] ),
565  Type(2)*( v_[1]*v_[3] - v_[0]*v_[2] ),
566  Type(2)*( v_[2]*v_[3] + v_[0]*v_[1] ),
567  Type(1) - Type(2)*v_[1]*v_[1] - Type(2)*v_[2]*v_[2] );
568 }
569 //*************************************************************************************************
570 
571 
572 //*************************************************************************************************
578 template< typename Type > // Data type of the quaternion
579 inline void Quaternion<Type>::rotateX( Type angle )
580 {
581  const Type sina( std::sin( angle*Type(0.5) ) );
582  const Type cosa( std::cos( angle*Type(0.5) ) );
583 
584  const Quaternion q( cosa*v_[0] - sina*v_[1],
585  cosa*v_[1] + sina*v_[0],
586  cosa*v_[2] - sina*v_[3],
587  cosa*v_[3] + sina*v_[2] );
588 
589  this->operator=( q );
590 }
591 //*************************************************************************************************
592 
593 
594 //*************************************************************************************************
600 template< typename Type > // Data type of the quaternion
601 inline void Quaternion<Type>::rotateY( Type angle )
602 {
603  const Type sina( std::sin( angle*Type(0.5) ) );
604  const Type cosa( std::cos( angle*Type(0.5) ) );
605 
606  const Quaternion q( cosa*v_[0] - sina*v_[2],
607  cosa*v_[1] + sina*v_[3],
608  cosa*v_[2] + sina*v_[0],
609  cosa*v_[3] - sina*v_[1] );
610 
611  this->operator=( q );
612 }
613 //*************************************************************************************************
614 
615 
616 //*************************************************************************************************
622 template< typename Type > // Data type of the quaternion
623 inline void Quaternion<Type>::rotateZ( Type angle )
624 {
625  const Type sina( std::sin( angle*Type(0.5) ) );
626  const Type cosa( std::cos( angle*Type(0.5) ) );
627 
628  const Quaternion q( cosa*v_[0] - sina*v_[3],
629  cosa*v_[1] - sina*v_[2],
630  cosa*v_[2] + sina*v_[1],
631  cosa*v_[3] + sina*v_[0] );
632 
633  this->operator=( q );
634 }
635 //*************************************************************************************************
636 
637 
638 //*************************************************************************************************
645 template< typename Type > // Data type of the quaternion
646 inline void Quaternion<Type>::swap( Quaternion& q ) /* throw() */
647 {
648  std::swap( v_[0], q.v_[0] );
649  std::swap( v_[1], q.v_[1] );
650  std::swap( v_[2], q.v_[2] );
651  std::swap( v_[3], q.v_[3] );
652 }
653 //*************************************************************************************************
654 
655 
656 
657 
658 //=================================================================================================
659 //
660 // MATH FUNCTIONS
661 //
662 //=================================================================================================
663 
664 //*************************************************************************************************
674 template< typename Type > // Data type of the quaternion
675 template< typename Other // Data type of the vector
676  , bool TF > // Transpose flag
679 {
680  typedef typename MultTrait<Type,Other>::Type MT;
681 
682  // Multiplication in two steps
683  const MT w( v_[1]*v[0] + v_[2]*v[1] + v_[3]*v[2] );
684  const MT x( v_[0]*v[0] - v_[3]*v[1] + v_[2]*v[2] );
685  const MT y( v_[0]*v[1] - v_[1]*v[2] + v_[3]*v[0] );
686  const MT z( v_[0]*v[2] - v_[2]*v[0] + v_[1]*v[1] );
687 
688  return StaticVector<MT,3UL,TF>( v_[0]*x + v_[1]*w + v_[2]*z - v_[3]*y,
689  v_[0]*y + v_[2]*w + v_[3]*x - v_[1]*z,
690  v_[0]*z + v_[3]*w + v_[1]*y - v_[2]*x );
691 
692  // Multiplication in one step
693  /*
694  const MT v0( v_[0] * v_[0] );
695  const MT v1( v_[1] * v_[1] );
696  const MT v2( v_[2] * v_[2] );
697  const MT v3( v_[3] * v_[3] );
698 
699  return StaticVector<MT,3UL,TF>( ( v[0]*( v0 + v1 - v2 - v3 ) + 2.0*v_[0]*( v_[2]*v[2] - v_[3]*v[1] ) + 2.0*v_[1]*( v_[2]*v[1] + v_[3]*v[2] ) ),
700  ( v[1]*( v0 - v1 + v2 - v3 ) + 2.0*v_[0]*( v_[3]*v[0] - v_[1]*v[2] ) + 2.0*v_[2]*( v_[1]*v[0] + v_[3]*v[2] ) ),
701  ( v[2]*( v0 - v1 - v2 + v3 ) + 2.0*v_[0]*( v_[1]*v[1] - v_[2]*v[0] ) + 2.0*v_[3]*( v_[1]*v[0] + v_[2]*v[1] ) ) );
702  */
703 }
704 //*************************************************************************************************
705 
706 
707 //*************************************************************************************************
717 template< typename Type > // Data type of the quaternion
718 template< typename Other > // Data type of the matrix
719 inline const StaticMatrix< typename MultTrait<Type,Other>::Type, 3UL, 3UL, false >
721 {
722  typedef typename MultTrait<Type,Other>::Type MT;
723  const RotationMatrix<MT> R( this->toRotationMatrix() );
724  return R.rotate( m );
725 }
726 //*************************************************************************************************
727 
728 
729 //*************************************************************************************************
741 template< typename Type > // Data type of the quaternion
742 template< typename Other > // Data type of the diagonal matrix
743 inline const StaticMatrix< typename MultTrait<Type,Other>::Type, 3UL, 3UL, false >
745 {
746  typedef typename MultTrait<Type,Other>::Type MT;
747  const RotationMatrix<MT> R( this->toRotationMatrix() );
748  return R.diagRotate( m );
749 }
750 //*************************************************************************************************
751 
752 
753 //*************************************************************************************************
759 template< typename Type > // Data type of the quaternion
760 template< typename Other > // Data type of the axis
761 inline typename MathTrait<Type,Other>::HighType
763 {
764  typedef typename MathTrait<Type,Other>::HighType High;
765 
766  const StaticVector<High,3UL,true> u( v_[1], v_[2], v_[3] );
767  const High y ( u.length() );
768  const High x ( v_[0] );
769  const High dot( u * axis );
770 
771  return High(2) * std::atan2( y, ( dot < real(0) )?( -x ):( x ) );
772 }
773 //*************************************************************************************************
774 
775 
776 
777 
778 //=================================================================================================
779 //
780 // GLOBAL OPERATORS
781 //
782 //=================================================================================================
783 
784 //*************************************************************************************************
787 template< typename T1, typename T2 >
788 inline bool operator==( const Quaternion<T1>& lhs, const Quaternion<T2>& rhs );
789 
790 template< typename T1, typename T2 >
791 inline bool operator!=( const Quaternion<T1>& lhs, const Quaternion<T2>& rhs );
792 
793 template< typename Type >
794 std::ostream& operator<<( std::ostream& os, const Quaternion<Type>& q );
795 
796 template< typename Type >
797 std::istream& operator>>( std::istream& is, Quaternion<Type>& q );
798 
799 template< typename Type >
800 inline bool isnan( const Quaternion<Type>& q );
801 
802 template< typename Type >
803 inline void reset( Quaternion<Type>& q );
804 
805 template< typename Type >
806 inline void clear( Quaternion<Type>& q );
807 
808 template< typename Type >
809 inline bool isDefault( const Quaternion<Type>& q );
810 
811 template< typename Type >
812 inline const Quaternion<Type> inv( const Quaternion<Type>& m );
813 
814 template< typename Type >
815 inline const Quaternion<Type> sq( const Quaternion<Type>& m );
816 
817 template< typename Type >
818 inline void swap( Quaternion<Type>& a, Quaternion<Type>& b ) /* throw() */;
820 //*************************************************************************************************
821 
822 
823 //*************************************************************************************************
831 template< typename T1 // Data type of the left-hand side quaternion
832  , typename T2 > // Data type of the right-hand side quaternion
833 inline bool operator==( const Quaternion<T1>& lhs, const Quaternion<T2>& rhs )
834 {
835  // In order to compare the two quaternions, the data values of the lower-order data
836  // type are converted to the higher-order data type within the equal function.
837  if( !equal( lhs[0], rhs[0] ) ||
838  !equal( lhs[1], rhs[1] ) ||
839  !equal( lhs[2], rhs[2] ) ||
840  !equal( lhs[2], rhs[2] ) )
841  return false;
842  else return true;
843 }
844 //*************************************************************************************************
845 
846 
847 //*************************************************************************************************
855 template< typename T1 // Data type of the left-hand side quaternion
856  , typename T2 > // Data type of the right-hand side quaternion
857 inline bool operator!=( const Quaternion<T1>& lhs, const Quaternion<T2>& rhs )
858 {
859  return !( lhs == rhs );
860 }
861 //*************************************************************************************************
862 
863 
864 //*************************************************************************************************
872 template< typename Type > // Data type of the quaternion
873 std::ostream& operator<<( std::ostream& os, const Quaternion<Type>& q )
874 {
875  return os << "<" << q[0] << "," << q[1] << "," << q[2] << "," << q[3] << ">";
876 }
877 //*************************************************************************************************
878 
879 
880 //*************************************************************************************************
888 template< typename Type > // Data type of the quaternion
889 std::istream& operator>>( std::istream& is, Quaternion<Type>& q )
890 {
891  if( !is ) return is;
892 
893  char bracket1, bracket2, comma1, comma2, comma3;
894  Type r(0), i(0), j(0), k(0);
895  const std::istream::pos_type pos( is.tellg() );
896  const std::istream::fmtflags oldFlags( is.flags() );
897 
898  // Setting the 'skip whitespaces' flag
899  is >> std::skipws;
900 
901  // Extracting the quaternion
902  if( !(is >> bracket1 >> r >> comma1 >> i >> comma2 >> j >> comma3 >> k >> bracket2) ||
903  bracket1 != '<' || comma1 != ',' || comma2 != ',' || comma3 != ',' || bracket2 != '>' ) {
904  is.clear();
905  is.seekg( pos );
906  is.setstate( std::istream::failbit );
907  is.flags( oldFlags );
908  return is;
909  }
910 
911  // Transfering the input to the quaternion values
912  q.set( r, i, j, k );
913 
914  // Resetting the flags
915  is.flags( oldFlags );
916 
917  return is;
918 }
919 //*************************************************************************************************
920 
921 
922 //*************************************************************************************************
929 template< typename Type > // Data type of the quaternion
930 inline bool isnan( const Quaternion<Type>& q )
931 {
932  if( isnan( q[0] ) || isnan( q[1] ) || isnan( q[2] ) || isnan( q[3] ) )
933  return true;
934  else return false;
935 }
936 //*************************************************************************************************
937 
938 
939 //*************************************************************************************************
946 template< typename Type > // Data type of the quaternion
947 inline void reset( Quaternion<Type>& q )
948 {
949  q.reset();
950 }
951 //*************************************************************************************************
952 
953 
954 //*************************************************************************************************
963 template< typename Type > // Data type of the quaternion
964 inline void clear( Quaternion<Type>& q )
965 {
966  q.reset();
967 }
968 //*************************************************************************************************
969 
970 
971 //*************************************************************************************************
985 template< typename Type > // Data type of the quaternion
986 inline bool isDefault( const Quaternion<Type>& q )
987 {
988  return ( q[0] == Type(1) ) && ( q[1] == Type(0) ) && ( q[2] == Type(0) ) && ( q[3] == Type(0) );
989 }
990 //*************************************************************************************************
991 
992 
993 //*************************************************************************************************
1002 template< typename Type > // Data type of the quaternion
1003 inline const Quaternion<Type> inv( const Quaternion<Type>& q )
1004 {
1005  return Quaternion<Type>( q[0], -q[1], -q[2], -q[3] );
1006 }
1007 //*************************************************************************************************
1008 
1009 
1010 //*************************************************************************************************
1020 template< typename Type > // Data type of the quaternion
1021 inline const Quaternion<Type> sq( const Quaternion<Type>& q )
1022 {
1023  return q * q;
1024 }
1025 //*************************************************************************************************
1026 
1027 
1028 //*************************************************************************************************
1037 template< typename Type > // Data type of the quaternions
1038 inline void swap( Quaternion<Type>& a, Quaternion<Type>& b ) /* throw() */
1039 {
1040  a.swap( b );
1041 }
1042 //*************************************************************************************************
1043 
1044 
1045 
1046 
1047 //=================================================================================================
1048 //
1049 // GLOBAL ARITHMETIC OPERATORS
1050 //
1051 //=================================================================================================
1052 
1053 //*************************************************************************************************
1056 template< typename T1, typename T2 >
1057 inline const Quaternion< typename MultTrait<T1,T2>::Type >
1058  operator*( const Quaternion<T1>& lhs, const Quaternion<T2>& rhs );
1060 //*************************************************************************************************
1061 
1062 
1063 //*************************************************************************************************
1072 template< typename T1 // Data type of the left-hand side quaternion
1073  , typename T2 > // Data type of the right-hand side quaternion
1074 inline const Quaternion< typename MultTrait<T1,T2>::Type >
1075  operator*( const Quaternion<T1>& lhs, const Quaternion<T2>& rhs )
1076 {
1077  typedef typename MultTrait<T1,T2>::Type MT;
1078 
1079  const MT r( lhs[0]*rhs[0] - lhs[1]*rhs[1] - lhs[2]*rhs[2] - lhs[3]*rhs[3] );
1080  const MT i( lhs[0]*rhs[1] + lhs[1]*rhs[0] + lhs[2]*rhs[3] - lhs[3]*rhs[2] );
1081  const MT j( lhs[0]*rhs[2] + lhs[2]*rhs[0] + lhs[3]*rhs[1] - lhs[1]*rhs[3] );
1082  const MT k( lhs[0]*rhs[3] + lhs[3]*rhs[0] + lhs[1]*rhs[2] - lhs[2]*rhs[1] );
1083 
1084  const MT len2( r*r + i*i + j*j + k*k );
1085 
1086  if( std::fabs( len2 - MT(1) ) < MT(1E-8) ) {
1087  return Quaternion<MT>( r, i, j, k );
1088  }
1089  else {
1090  const MT ilen( MT(1) / std::sqrt( len2 ) );
1091  return Quaternion<MT>( r*ilen, i*ilen, j*ilen, k*ilen );
1092  }
1093 }
1094 //*************************************************************************************************
1095 
1096 
1097 
1098 
1099 //=================================================================================================
1100 //
1101 // MULTTRAIT SPECIALIZATIONS
1102 //
1103 //=================================================================================================
1104 
1105 //*************************************************************************************************
1107 template< typename T1, typename T2 >
1108 struct MultTrait< Quaternion<T1>, Quaternion<T2> >
1109 {
1110  typedef Quaternion< typename MultTrait<T1,T2>::Type > MultType;
1111 };
1113 //*************************************************************************************************
1114 
1115 
1116 
1117 
1118 //=================================================================================================
1119 //
1120 // MATHTRAIT SPECIALIZATIONS
1121 //
1122 //=================================================================================================
1123 
1124 //*************************************************************************************************
1126 template< typename T1, typename T2 >
1127 struct MathTrait< Quaternion<T1>, Quaternion<T2> >
1128 {
1129  typedef Quaternion< typename MathTrait<T1,T2>::HighType > HighType;
1130  typedef Quaternion< typename MathTrait<T1,T2>::LowType > LowType;
1131 };
1133 //*************************************************************************************************
1134 
1135 
1136 
1137 
1138 //=================================================================================================
1139 //
1140 // TYPE DEFINITIONS
1141 //
1142 //=================================================================================================
1143 
1144 //*************************************************************************************************
1149 //*************************************************************************************************
1150 
1151 } // namespace blaze
1152 
1153 #endif