GL Studio C++ Runtime API
gls_quaternion.h
Go to the documentation of this file.
1 /*! \file
2  \brief The disti::GlsQuaternion class.
3 
4  \par Copyright Information
5 
6  Copyright (c) 2017 by The DiSTI Corporation.<br>
7  11301 Corporate Blvd., Suite 100<br>
8  Orlando, Florida 32817<br>
9  USA<br>
10  <br>
11  All rights reserved.<br>
12 
13  This Software contains proprietary trade secrets of DiSTI and may not be
14 reproduced, in whole or part, in any form, or by any means of electronic,
15 mechanical, or otherwise, without the written permission of DiSTI. Said
16 permission may be derived through the purchase of applicable DiSTI product
17 licenses which detail the distribution rights of this content and any
18 Derivative Works based on this or other copyrighted DiSTI Software.
19 
20  NO WARRANTY. THE SOFTWARE IS PROVIDED "AS-IS," WITHOUT WARRANTY OF ANY KIND,
21 AND ANY USE OF THIS SOFTWARE PRODUCT IS AT YOUR OWN RISK. TO THE MAXIMUM EXTENT
22 PERMITTED BY APPLICABLE LAW, DISTI AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES
23 AND CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
24 IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY AND/OR FITNESS FOR A
25 PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT, WITH REGARD TO THE SOFTWARE.
26 
27  LIMITATION OF LIABILITY. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW,
28 IN NO EVENT SHALL DISTI OR ITS SUPPLIERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
29 INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION,
30 DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS
31 INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR
32 INABILITY TO USE THE SOFTWARE, EVEN IF DISTI HAS BEEN ADVISED OF THE POSSIBILITY
33 OF SUCH DAMAGES. DISTI'S ENTIRE LIABILITY AND YOUR EXCLUSIVE REMEDY SHALL NOT
34 EXCEED FIVE DOLLARS (US$5.00).
35 
36  The aforementioned terms and restrictions are governed by the laws of the
37 State of Florida and the United States of America.
38 
39 */
40 
41 #ifndef GLS_QUATERNION_H
42 #define GLS_QUATERNION_H
43 
44 #include "vertex.h"
45 
46 namespace disti
47 {
48 namespace
49 {
50  // Circular dependancies prevent us from using VeryCloseToZero in util.h
51  bool IsVeryCloseToZero( double value ) { return fabs( value ) < 0.0001; }
52 } // namespace
53 
54 template<class Type>
55 class GlsMatrixAffine;
56 
57 /** The GlsQuaternion class */
58 template<class Type>
60 {
61 public:
62  //------------------------------------------------------------------------
63  /**
64  * Default constructor. This will initialize the quaternion to zero.
65  */
66  //------------------------------------------------------------------------
67  inline GlsQuaternion()
68  {
69  _v[ 0 ] = 0;
70  _v[ 1 ] = 0;
71  _v[ 2 ] = 0;
72  _v[ 3 ] = 0;
73  }
74 
75  //------------------------------------------------------------------------
76  /**
77  * Constructor. Sets quaternion from 4 constants.
78  * \param x Initial X value
79  * \param y Initial Y value
80  * \param z Initial Z value
81  * \param w Initial W value
82  */
83  //------------------------------------------------------------------------
84  inline GlsQuaternion( Type x, Type y, Type z, Type w )
85  {
86  _v[ 0 ] = x;
87  _v[ 1 ] = y;
88  _v[ 2 ] = z;
89  _v[ 3 ] = w;
90  }
91 
92  //------------------------------------------------------------------------
93  /**
94  * Constructor. Sets quaternion from angle about an arbitrary axis
95  * \param angle Rotation angle in radians
96  * \param axis Unit vector representing arbitrary axis
97  */
98  //------------------------------------------------------------------------
99  inline GlsQuaternion( Type angle, const Vector& axis )
100  {
101  SetFromAngleAxis( angle, axis );
102  }
103 
104  //------------------------------------------------------------------------
105  /**
106  * Constructor. Sets quaternion from 3 angles about 3 axes
107  * \param angle1 Rotation angle about first axis in radians
108  * \param axis1 Unit vector representing first arbitrary axis
109  * \param angle2 Rotation angle about second axis in radians
110  * \param axis2 Unit vector representing second arbitrary axis
111  * \param angle3 Rotation angle about third axis in radians
112  * \param axis3 Unit vector representing third arbitrary axis
113  */
114  //------------------------------------------------------------------------
115  inline GlsQuaternion( Type angle1, const Vector& axis1,
116  Type angle2, const Vector& axis2,
117  Type angle3, const Vector& axis3 )
118  {
119  SetFromAngleAxis( angle1, axis1, angle2, axis2, angle3, axis3 );
120  }
121 
122  //------------------------------------------------------------------------
123  /**
124  * Constructor. Sets quaternion from 3 angles (Euler Angles)
125  * \param angleX Rotation angle about X axis in radians
126  * \param angleY Rotation angle about Y axis in radians
127  * \param angleZ Rotation angle about Z axis in radians
128  */
129  //------------------------------------------------------------------------
130  inline GlsQuaternion( Type angleX, Type angleY, Type angleZ )
131  {
132  SetFromEulerAngles( angleX, angleY, angleZ );
133  }
134 
135  //------------------------------------------------------------------------
136  /**
137  * Constructor. Sets quaternion from 3 angles (Euler Angles)
138  * \param anglesVec A vector where each component of the vector is an
139  * Euler angle component in radians.
140  */
141  //------------------------------------------------------------------------
142  inline GlsQuaternion( const Vector& anglesVec )
143  {
144  SetFromEulerAngles( anglesVec.x, anglesVec.y, anglesVec.z );
145  }
146 
147  //------------------------------------------------------------------------
148  /**
149  * Constructor. Sets quaternion from a rotation matrix
150  * \param matrix An affine matrix representing a rotation matrix
151  */
152  //------------------------------------------------------------------------
153  inline GlsQuaternion( const GlsMatrixAffine<Type>& matrix )
154  {
155  SetFromRotationMatrix( matrix );
156  }
157 
158  //------------------------------------------------------------------------
159  /**
160  * Accessor method providing access to quaternion data.
161  * \return A pointer to the quaternion data.
162  */
163  //------------------------------------------------------------------------
164  inline Type* Data()
165  {
166  return _v;
167  }
168 
169  //------------------------------------------------------------------------
170  /**
171  * Accessor method providing access to quaternion data.
172  * \return A pointer to the quaternion data.
173  */
174  //------------------------------------------------------------------------
175  inline const Type* Data() const
176  {
177  return _v;
178  }
179 
180  //------------------------------------------------------------------------
181  /**
182  * Boolean equivalence operator
183  * \param q Quaternion to compare against
184  * \return True if the two quaternions are exactly equal
185  */
186  //------------------------------------------------------------------------
187  inline bool operator==( const GlsQuaternion& q ) const
188  {
189  return _v[ 0 ] == q._v[ 0 ] && _v[ 1 ] == q._v[ 1 ] && _v[ 2 ] == q._v[ 2 ] && _v[ 3 ] == q._v[ 3 ];
190  }
191 
192  //------------------------------------------------------------------------
193  /**
194  * Boolean non-equivalence operator
195  * \param q Quaternion to compare against
196  * \return True if the two quaternions are not exactly equal
197  */
198  //------------------------------------------------------------------------
199  inline bool operator!=( const GlsQuaternion& q ) const
200  {
201  return _v[ 0 ] != q._v[ 0 ] || _v[ 1 ] != q._v[ 1 ] || _v[ 2 ] != q._v[ 2 ] || _v[ 3 ] != q._v[ 3 ];
202  }
203 
204  //------------------------------------------------------------------------
205  /**
206  * Boolean less than operator
207  * \param q Quaternion to compare against
208  * \return True if the this quaternion is less than the provided one
209  */
210  //------------------------------------------------------------------------
211  inline bool operator<( const GlsQuaternion& q ) const
212  {
213  if( _v[ 0 ] < q._v[ 0 ] )
214  return true;
215  else if( _v[ 0 ] > q._v[ 0 ] )
216  return false;
217  else if( _v[ 1 ] < q._v[ 1 ] )
218  return true;
219  else if( _v[ 1 ] > q._v[ 1 ] )
220  return false;
221  else if( _v[ 2 ] < q._v[ 2 ] )
222  return true;
223  else if( _v[ 2 ] > q._v[ 2 ] )
224  return false;
225  else
226  return ( _v[ 3 ] < q._v[ 3 ] );
227  }
228 
229  //------------------------------------------------------------------------
230  /**
231  * Scalar multiplication operator
232  * \param s A scalar to multiply against
233  * \return This quaternion multiplied by the scalar
234  */
235  //------------------------------------------------------------------------
236  inline const GlsQuaternion operator*( Type s ) const
237  {
238  return GlsQuaternion( _v[ 0 ] * s, _v[ 1 ] * s, _v[ 2 ] * s, _v[ 3 ] * s );
239  }
240 
241  //------------------------------------------------------------------------
242  /**
243  * Scalar multiplication operator and assignment operator
244  * \param s A scalar to multiply against
245  * \return This quaternion multiplied by the scalar
246  */
247  //------------------------------------------------------------------------
248  inline GlsQuaternion& operator*=( Type s )
249  {
250  _v[ 0 ] *= s;
251  _v[ 1 ] *= s;
252  _v[ 2 ] *= s;
253  _v[ 3 ] *= s;
254  return *this; // enable nesting
255  }
256 
257  //------------------------------------------------------------------------
258  /**
259  * Quaternion multiplication operator
260  * \param q A quaternion to multiply against
261  * \return This quaternion multiplied by the quaternion
262  */
263  //------------------------------------------------------------------------
264  inline const GlsQuaternion operator*( const GlsQuaternion& q ) const
265  {
266  return GlsQuaternion( q._v[ 3 ] * _v[ 0 ] + q._v[ 0 ] * _v[ 3 ] + q._v[ 1 ] * _v[ 2 ] - q._v[ 2 ] * _v[ 1 ],
267  q._v[ 3 ] * _v[ 1 ] - q._v[ 0 ] * _v[ 2 ] + q._v[ 1 ] * _v[ 3 ] + q._v[ 2 ] * _v[ 0 ],
268  q._v[ 3 ] * _v[ 2 ] + q._v[ 0 ] * _v[ 1 ] - q._v[ 1 ] * _v[ 0 ] + q._v[ 2 ] * _v[ 3 ],
269  q._v[ 3 ] * _v[ 3 ] - q._v[ 0 ] * _v[ 0 ] - q._v[ 1 ] * _v[ 1 ] - q._v[ 2 ] * _v[ 2 ] );
270  }
271 
272  //------------------------------------------------------------------------
273  /**
274  * Quaternion multiplication operator
275  * \param q A quaternion to multiply against
276  * \return This quaternion multiplied by the quaternion
277  */
278  //------------------------------------------------------------------------
280  {
281  Type x = q._v[ 3 ] * _v[ 0 ] + q._v[ 0 ] * _v[ 3 ] + q._v[ 1 ] * _v[ 2 ] - q._v[ 2 ] * _v[ 1 ];
282  Type y = q._v[ 3 ] * _v[ 1 ] - q._v[ 0 ] * _v[ 2 ] + q._v[ 1 ] * _v[ 3 ] + q._v[ 2 ] * _v[ 0 ];
283  Type z = q._v[ 3 ] * _v[ 2 ] + q._v[ 0 ] * _v[ 1 ] - q._v[ 1 ] * _v[ 0 ] + q._v[ 2 ] * _v[ 3 ];
284  _v[ 3 ] = q._v[ 3 ] * _v[ 3 ] - q._v[ 0 ] * _v[ 0 ] - q._v[ 1 ] * _v[ 1 ] - q._v[ 2 ] * _v[ 2 ];
285 
286  _v[ 2 ] = z;
287  _v[ 1 ] = y;
288  _v[ 0 ] = x;
289 
290  return ( *this ); // enable nesting
291  }
292 
293  //------------------------------------------------------------------------
294  /**
295  * Scalar division operator
296  * \param s A scalar to divide
297  * \return This quaternion divided by the scalar
298  */
299  //------------------------------------------------------------------------
300  inline GlsQuaternion operator/( Type s ) const
301  {
302  Type div = 1.0 / s;
303  return GlsQuaternion( _v[ 0 ] * div, _v[ 1 ] * div, _v[ 2 ] * div, _v[ 3 ] * div );
304  }
305 
306  //------------------------------------------------------------------------
307  /**
308  * Scalar division and assignment operator
309  * \param s A scalar to divide
310  * \return This quaternion divided by the scalar
311  */
312  //------------------------------------------------------------------------
313  inline GlsQuaternion& operator/=( Type s )
314  {
315  Type div = 1 / s;
316  _v[ 0 ] *= div;
317  _v[ 1 ] *= div;
318  _v[ 2 ] *= div;
319  _v[ 3 ] *= div;
320  return *this;
321  }
322 
323  //------------------------------------------------------------------------
324  /**
325  * Quaternion division operator
326  * \param q A quaternion to division by
327  * \return This quaternion divided by the quaternion
328  */
329  //------------------------------------------------------------------------
330  inline const GlsQuaternion operator/( const GlsQuaternion& q ) const
331  {
332  return ( ( *this ) * q.Inverse() );
333  }
334 
335  //------------------------------------------------------------------------
336  /**
337  * Quaternion division operator
338  * \param q A quaternion to division by
339  * \return This quaternion divided by the quaternion
340  */
341  //------------------------------------------------------------------------
343  {
344  ( *this ) = ( *this ) * q.Inverse();
345  return ( *this ); // enable nesting
346  }
347 
348  //------------------------------------------------------------------------
349  /**
350  * Quaternion addition operator
351  * \param q A quaternion to add
352  * \return This quaternion plus the supplied quaternion
353  */
354  //------------------------------------------------------------------------
355  inline const GlsQuaternion operator+( const GlsQuaternion& q ) const
356  {
357  return GlsQuaternion( _v[ 0 ] + q._v[ 0 ], _v[ 1 ] + q._v[ 1 ],
358  _v[ 2 ] + q._v[ 2 ], _v[ 3 ] + q._v[ 3 ] );
359  }
360 
361  //------------------------------------------------------------------------
362  /**
363  * Quaternion addition and assignment operator
364  * \param q A quaternion to add
365  * \return This quaternion plus the supplied quaternion
366  */
367  //------------------------------------------------------------------------
369  {
370  _v[ 0 ] += q._v[ 0 ];
371  _v[ 1 ] += q._v[ 1 ];
372  _v[ 2 ] += q._v[ 2 ];
373  _v[ 3 ] += q._v[ 3 ];
374  return *this; // enable nesting
375  }
376 
377  //------------------------------------------------------------------------
378  /**
379  * Quaternion subtrtaction operator
380  * \param q A quaternion to subtract
381  * \return This quaternion minus the supplied quaternion
382  */
383  //------------------------------------------------------------------------
384  inline const GlsQuaternion operator-( const GlsQuaternion& q ) const
385  {
386  return GlsQuaternion( _v[ 0 ] - q._v[ 0 ], _v[ 1 ] - q._v[ 1 ],
387  _v[ 2 ] - q._v[ 2 ], _v[ 3 ] - q._v[ 3 ] );
388  }
389 
390  //------------------------------------------------------------------------
391  /**
392  * Quaternion subtraction and assignment operator
393  * \param q A quaternion to subtract
394  * \return This quaternion minus the supplied quaternion
395  */
396  //------------------------------------------------------------------------
398  {
399  _v[ 0 ] -= q._v[ 0 ];
400  _v[ 1 ] -= q._v[ 1 ];
401  _v[ 2 ] -= q._v[ 2 ];
402  _v[ 3 ] -= q._v[ 3 ];
403  return *this; // enable nesting
404  }
405 
406  /** Negation operator - returns the negative of the quaternion.
407  Basically just calls operator - () on the Vec4 */
408  inline const GlsQuaternion operator-() const
409  {
410  return GlsQuaternion( -_v[ 0 ], -_v[ 1 ], -_v[ 2 ], -_v[ 3 ] );
411  }
412 
413  //------------------------------------------------------------------------
414  /**
415  * Returns the magnitude of the quaternion
416  * \return The magnitude of the quaternion
417  */
418  //------------------------------------------------------------------------
419  inline Type Magnitude() const
420  {
421  return sqrt( _v[ 0 ] * _v[ 0 ] + _v[ 1 ] * _v[ 1 ] + _v[ 2 ] * _v[ 2 ] + _v[ 3 ] * _v[ 3 ] );
422  }
423 
424  //------------------------------------------------------------------------
425  /**
426  * Returns the magnitude squared of the quaternion
427  * \return The magnitude squared of the quaternion
428  */
429  //------------------------------------------------------------------------
430  inline Type MagnitudeSquared() const
431  {
432  return _v[ 0 ] * _v[ 0 ] + _v[ 1 ] * _v[ 1 ] + _v[ 2 ] * _v[ 2 ] + _v[ 3 ] * _v[ 3 ];
433  }
434 
435  //------------------------------------------------------------------------
436  /**
437  * Returns the conjugate of the quaternion
438  * \return The conjugate of the quaternion
439  */
440  //------------------------------------------------------------------------
441  inline GlsQuaternion Conjugate() const
442  {
443  return GlsQuaternion( -_v[ 0 ], -_v[ 1 ], -_v[ 2 ], _v[ 3 ] );
444  }
445 
446  //------------------------------------------------------------------------
447  /**
448  * Returns the inverse of the quaternion
449  * \return The inverse of the quaternion
450  */
451  //------------------------------------------------------------------------
452  inline const GlsQuaternion Inverse() const
453  {
454  return Conjugate() / MagnitudeSquared();
455  }
456 
457  //------------------------------------------------------------------------
458  /**
459  * Returns the dot product of the quaternion and a supplied quaternion
460  * \param q A quaternion to multiply against this quaternion
461  * \return The dot product of the quaternion and a supplied quaternion
462  */
463  //------------------------------------------------------------------------
464  inline Type DotProduct( const GlsQuaternion& q ) const
465  {
466  return ( ( _v[ 0 ] * q._v[ 0 ] ) + ( _v[ 1 ] * q._v[ 1 ] ) + ( _v[ 2 ] * q._v[ 2 ] ) + ( _v[ 3 ] * q._v[ 3 ] ) );
467  }
468 
469  //------------------------------------------------------------------------
470  /**
471  * Normalizes this quaternion
472  */
473  //------------------------------------------------------------------------
474  inline void Normalize()
475  {
476  *this /= Magnitude();
477  }
478 
479  //------------------------------------------------------------------------
480  /**
481  * Sets the component values for this quaternion
482  * \param x The X value
483  * \param y The Y value
484  * \param z The Z value
485  * \param w The W value
486  */
487  //------------------------------------------------------------------------
488  inline void Set( Type x, Type y, Type z, Type w )
489  {
490  _v[ 0 ] = x;
491  _v[ 1 ] = y;
492  _v[ 2 ] = z;
493  _v[ 3 ] = w;
494  }
495 
496  //------------------------------------------------------------------------
497  /**
498  * Sets quaternion from angle about an arbitrary axis
499  * \param angle Rotation angle in radians
500  * \param axis Unit vector representing arbitrary axis
501  */
502  //------------------------------------------------------------------------
503  void SetFromAngleAxis( Type angle, const Vector& axis )
504  {
505  Type half_angle = angle * (Type)0.5;
506  Type sin_half_angle = sin( half_angle );
507 
508  _v[ 0 ] = sin_half_angle * axis.x;
509  _v[ 1 ] = sin_half_angle * axis.y;
510  _v[ 2 ] = sin_half_angle * axis.z;
511  _v[ 3 ] = cos( half_angle );
512  }
513 
514  //------------------------------------------------------------------------
515  /**
516  * Sets quaternion from three angle-axis pairs.
517  * \param angle1 Rotation angle in radians
518  * \param axis1 Unit vector representing arbitrary axis
519  * \param angle2 Rotation angle in radians
520  * \param axis2 Unit vector representing arbitrary axis
521  * \param angle3 Rotation angle in radians
522  * \param axis3 Unit vector representing arbitrary axis
523  */
524  //------------------------------------------------------------------------
525  void SetFromAngleAxis( Type angle1, const Vector& axis1,
526  Type angle2, const Vector& axis2,
527  Type angle3, const Vector& axis3 )
528  {
529  GlsQuaternion q1( angle1, axis1 );
530  GlsQuaternion q2( angle2, axis2 );
531  SetFromAngleAxis( angle3, axis3 );
532 
533  *this = q1 * q2 * *this;
534  }
535 
536  //------------------------------------------------------------------------
537  /**
538  * Sets quaternion from the Euler angles.
539  * \param angleX The X Euler angle in radians
540  * \param angleY The Y Euler angle in radians
541  * \param angleZ The Z Euler angle in radians
542  */
543  //------------------------------------------------------------------------
544  void SetFromEulerAngles( Type angleX, Type angleY, Type angleZ )
545  {
546  GlsQuaternion<Type> qx, qy, qz;
547 
548  // precompute half angles
549  Type xOver2 = angleX * (Type)0.5;
550  Type yOver2 = angleY * (Type)0.5;
551  Type zOver2 = angleZ * (Type)0.5;
552 
553  // set the pitch quat
554  qx._v[ 0 ] = sin( xOver2 );
555  qx._v[ 1 ] = (Type)0.0;
556  qx._v[ 2 ] = (Type)0.0;
557  qx._v[ 3 ] = cos( xOver2 );
558 
559  // set the yaw quat
560  qy._v[ 0 ] = (Type)0.0;
561  qy._v[ 1 ] = sin( yOver2 );
562  qy._v[ 2 ] = (Type)0.0;
563  qy._v[ 3 ] = cos( yOver2 );
564 
565  // set the roll quat
566  qz._v[ 0 ] = (Type)0.0;
567  qz._v[ 1 ] = (Type)0.0;
568  qz._v[ 2 ] = sin( zOver2 );
569  qz._v[ 3 ] = cos( zOver2 );
570 
571  // compose the three in x y z order...
572  *this = qx * qy * qz;
573 
574  this->Normalize();
575  }
576 
577  //------------------------------------------------------------------------
578  /**
579  * Sets this quaternion to a rotation that rotates 'to' into 'from'.
580  * \param to The rotation destination
581  * \param from The rotation start point
582  */
583  //------------------------------------------------------------------------
584  void SetFromVectors( const Vector& to, const Vector& from )
585  {
586  // dot product vec1*vec2
587  Type cosangle = from.DotProduct( to ) / ( from.Magnitude() * to.Magnitude() );
588 
589  if( IsVeryCloseToZero( cosangle - 1 ) )
590  {
591  // cosangle is close to 1, so the vectors are close to being coincident
592  // Need to generate an angle of zero with any vector we like
593  // We'll choose (1,0,0)
594  SetFromAngleAxis( 0.0, Vector( 1.0, 0.0, 0.0 ) );
595  }
596  else if( IsVeryCloseToZero( cosangle + 1.0 ) )
597  {
598  // vectors are close to being opposite, so will need to find a
599  // vector orthongonal to from to rotate about.
600  Vector tmp;
601  if( fabs( from.x ) < fabs( from.y ) )
602  if( fabs( from.x ) < fabs( from.z ) )
603  tmp = Vector( 1.0, 0.0, 0.0 ); // use x axis.
604  else
605  tmp = Vector( 0.0, 0.0, 1.0 );
606  else if( fabs( from.y ) < fabs( from.z ) )
607  tmp = Vector( 0.0, 1.0, 0.0 );
608  else
609  tmp = Vector( 0.0, 0.0, 1.0 );
610 
611  // find orthogonal axis.
612  Vector axis( from.CrossProduct( tmp ) );
613  axis.Normalize();
614 
615  _v[ 0 ] = axis.x; // sin of half angle of PI is 1.0.
616  _v[ 1 ] = axis.y; // sin of half angle of PI is 1.0.
617  _v[ 2 ] = axis.z; // sin of half angle of PI is 1.0.
618  _v[ 3 ] = 0; // cos of half angle of PI is zero.
619  }
620  else
621  {
622  // This is the usual situation - take a cross-product of vec1 and vec2
623  // and that is the axis around which to rotate.
624  Vector axis( from.CrossProduct( to ) );
625  axis.Normalize();
626  Type angle = acos( cosangle );
627  SetFromAngleAxis( angle, axis );
628  }
629  }
630 
631  //------------------------------------------------------------------------
632  /**
633  * Sets this quaternion from the specified rotation matrix.
634  * \param matrix The rotation matrix
635  */
636  //------------------------------------------------------------------------
638  {
639  Type tr, s;
640  Type tq[ 4 ];
641  int i, j, k;
642  const Type* mat = const_cast<GlsMatrixAffine<Type>&>( matrix ).Data();
643 
644  int nxt[ 3 ] = { 1, 2, 0 };
645 
646  tr = mat[ 0 * 4 + 0 ] + mat[ 1 * 4 + 1 ] + mat[ 2 * 4 + 2 ];
647 
648  // check the diagonal
649  if( tr > 0.0 )
650  {
651  s = (Type)sqrt( tr + 1.0 );
652  _v[ 3 ] = s / 2.0f;
653  s = 0.5f / s;
654  _v[ 0 ] = ( mat[ 1 * 4 + 2 ] - mat[ 2 * 4 + 1 ] ) * s;
655  _v[ 1 ] = ( mat[ 2 * 4 + 0 ] - mat[ 0 * 4 + 2 ] ) * s;
656  _v[ 2 ] = ( mat[ 0 * 4 + 1 ] - mat[ 1 * 4 + 0 ] ) * s;
657  }
658  else
659  {
660  // diagonal is negative
661  i = 0;
662  if( mat[ 1 * 4 + 1 ] > mat[ 0 * 4 + 0 ] )
663  i = 1;
664  if( mat[ 2 * 4 + 2 ] > mat[ i * 4 + i ] )
665  i = 2;
666  j = nxt[ i ];
667  k = nxt[ j ];
668 
669  s = (Type)sqrt( ( mat[ i * 4 + i ] - ( mat[ j * 4 + j ] + mat[ k * 4 + k ] ) ) + 1.0 );
670 
671  tq[ i ] = s * 0.5f;
672 
673  if( s != 0.0f )
674  s = 0.5f / s;
675 
676  tq[ 3 ] = ( mat[ j * 4 + k ] - mat[ k * 4 + j ] ) * s;
677  tq[ j ] = ( mat[ i * 4 + j ] + mat[ j * 4 + i ] ) * s;
678  tq[ k ] = ( mat[ i * 4 + k ] + mat[ k * 4 + i ] ) * s;
679 
680  _v[ 0 ] = tq[ 0 ];
681  _v[ 1 ] = tq[ 1 ];
682  _v[ 2 ] = tq[ 2 ];
683  _v[ 3 ] = tq[ 3 ];
684  }
685  }
686 
687  /** Returns the rotation about the X axis
688  * \return The rotation about the X axis
689  */
690  Type GetRoll( void ) const
691  {
692  return atan2( 2 * ( _v[ 1 ] * _v[ 2 ] + _v[ 3 ] * _v[ 0 ] ), _v[ 3 ] * _v[ 3 ] - _v[ 0 ] * _v[ 0 ] - _v[ 1 ] * _v[ 1 ] + _v[ 2 ] * _v[ 2 ] );
693  }
694 
695  /** Returns the rotation about the Y axis
696  * \return The rotation about the Y axis
697  */
698  Type GetPitch( void ) const
699  {
700  Type tmp = -2 * ( _v[ 0 ] * _v[ 2 ] - _v[ 3 ] * _v[ 1 ] );
701 
702  if( tmp > 1.0 )
703  {
704  tmp = 1.0;
705  }
706  else if( tmp < -1.0 )
707  {
708  tmp = -1.0;
709  }
710 
711  return asin( tmp );
712  }
713  /** Returns the rotation about the Z axis
714  * \return The rotation about the Z axis
715  */
716  Type GetYaw( void ) const
717  {
718  return atan2( 2 * ( _v[ 0 ] * _v[ 1 ] + _v[ 3 ] * _v[ 2 ] ), _v[ 3 ] * _v[ 3 ] + _v[ 0 ] * _v[ 0 ] - _v[ 1 ] * _v[ 1 ] - _v[ 2 ] * _v[ 2 ] );
719  }
720 
721  /** Returns the Euler Angles as a Vector (Warning: SLOW)
722  * \return The Euler Angles as a Vector
723  */
725  {
726  // This is slow
727  return Vector( float( GetRoll() ), float( GetPitch() ), float( GetYaw() ) );
728  }
729 
730  /** Gets the rotation angle (radians) and the axis about which the angle is rotated.
731  * \param angle Returns the angle of rotation of the quaternion
732  * \param axis Returns the axis of rotation of the quaternion
733  */
734  void GetAngleAxis( Type* angle, Vector* axis )
735  {
736 // set sure we don't get a NaN result from acos...
737 #ifdef _WIN32
738  if( abs( _v[ 3 ] ) > (Type)1.0 )
739 #else
740  if( fabs( (double)_v[ 3 ] ) > 1.0 )
741 #endif
742  {
743  this->Normalize();
744  }
745 
746  // set the angle - aCos is mathematically defined to be between 0 and PI
747  Type rad = acos( _v[ 3 ] ) * (Type)2.0;
748 
749  if( angle )
750  {
751  *angle = rad;
752  }
753 
754  // set the axis: (use sin(rad) instead of asin(w))
755  if( axis )
756  {
757  Type sin_half_angle = sin( rad * (Type)0.5 );
758  if( sin_half_angle >= (Type)0.0001 ) // because (PI >= rad >= 0)
759  {
760  Type sin_half_angle_inv = Type( 1.0 ) / sin_half_angle;
761  axis->x = float( _v[ 0 ] * sin_half_angle_inv );
762  axis->y = float( _v[ 1 ] * sin_half_angle_inv );
763  axis->z = float( _v[ 2 ] * sin_half_angle_inv );
764  axis->Normalize();
765  }
766 
767  // avoid NAN
768  else
769  {
770  // one of the terms should be a 1,
771  // so we can maintain unit-ness
772  // in case w is 0 (which here w is 0)
773  axis->x = (float)1.0;
774  axis->y = (float)0.0;
775  axis->z = (float)0.0;
776  }
777  }
778  }
779 
780  /** Returns a rotation matrix representation of the quaternion.
781  * \return The rotation matrix computed from the quaternion
782  */
784  {
785  Type wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2;
786  Type mat[ 4 ][ 4 ];
787 
788  x2 = _v[ 0 ] + _v[ 0 ];
789  y2 = _v[ 1 ] + _v[ 1 ];
790  z2 = _v[ 2 ] + _v[ 2 ];
791 
792  xx = _v[ 0 ] * x2;
793  xy = _v[ 0 ] * y2;
794  xz = _v[ 0 ] * z2;
795 
796  yy = _v[ 1 ] * y2;
797  yz = _v[ 1 ] * z2;
798  zz = _v[ 2 ] * z2;
799 
800  wx = _v[ 3 ] * x2;
801  wy = _v[ 3 ] * y2;
802  wz = _v[ 3 ] * z2;
803 
804  mat[ 0 ][ 0 ] = 1.0f - ( yy + zz );
805  mat[ 0 ][ 1 ] = xy - wz;
806  mat[ 0 ][ 2 ] = xz + wy;
807  mat[ 0 ][ 3 ] = 0.0f;
808 
809  mat[ 1 ][ 0 ] = xy + wz;
810  mat[ 1 ][ 1 ] = 1.0f - ( xx + zz );
811  mat[ 1 ][ 2 ] = yz - wx;
812  mat[ 1 ][ 3 ] = 0.0f;
813 
814  mat[ 2 ][ 0 ] = xz - wy;
815  mat[ 2 ][ 1 ] = yz + wx;
816  mat[ 2 ][ 2 ] = 1.0f - ( xx + yy );
817  mat[ 2 ][ 3 ] = 0.0f;
818 
819  mat[ 3 ][ 0 ] = 0;
820  mat[ 3 ][ 1 ] = 0;
821  mat[ 3 ][ 2 ] = 0;
822  mat[ 3 ][ 3 ] = 1;
823 
824  return GlsMatrixAffine<Type>( mat );
825  }
826 
827  /** Sets this quaternion to an interpolated rotation between the
828  * from and to vectors using spherical linear interpolation (slerp).
829  * \param t Percent of interpelation (0.0 -> 1.0)
830  * \param from The starting quaternion
831  * \param to The ending quaternion
832  * \param adjustSign Whether or not to negate the sign of the to quaternion
833  */
834  void SetFromSlerp( float t, const GlsQuaternion& from, const GlsQuaternion& to, bool adjustSign = true )
835  {
836  const GlsQuaternion& p = from;
837 
838  // calc cosine theta
839  Type cosom = from.DotProduct( to );
840 
841  // adjust signs (if necessary)
843  if( adjustSign && ( cosom < (Type)0.0 ) )
844  {
845  cosom = -cosom;
846  q._v[ 0 ] = -to._v[ 0 ]; // Reverse all signs
847  q._v[ 1 ] = -to._v[ 1 ];
848  q._v[ 2 ] = -to._v[ 2 ];
849  q._v[ 3 ] = -to._v[ 3 ];
850  }
851  else
852  {
853  q = to;
854  }
855 
856  // Calculate coefficients
857  Type sclp, sclq;
858  if( ( (Type)1.0 - cosom ) > (Type)0.0001 ) // 0.0001 -> some epsillon
859  {
860  // Standard case (slerp)
861  Type omega, sinom;
862  omega = acos( cosom ); // extract theta from dot product's cos theta
863  sinom = sin( omega );
864  sclp = sin( ( (Type)1.0 - t ) * omega ) / sinom;
865  sclq = sin( t * omega ) / sinom;
866  }
867  else
868  {
869  // Very close, do linear interp (because it's faster)
870  sclp = (Type)1.0 - t;
871  sclq = t;
872  }
873 
874  _v[ 0 ] = sclp * p._v[ 0 ] + sclq * q._v[ 0 ];
875  _v[ 1 ] = sclp * p._v[ 1 ] + sclq * q._v[ 1 ];
876  _v[ 2 ] = sclp * p._v[ 2 ] + sclq * q._v[ 2 ];
877  _v[ 3 ] = sclp * p._v[ 3 ] + sclq * q._v[ 3 ];
878  }
879 
880 protected:
881  Type _v[ 4 ];
882 };
883 
884 typedef GlsQuaternion<float> GlsQuaternionF;
885 typedef GlsQuaternion<double> GlsQuaternionD;
886 
887 template<class Type>
888 inline std::ostream& operator<<( std::ostream& outstr, const GlsQuaternion<Type>& quat )
889 {
890  outstr.precision( 10 );
891 
892  outstr.width( 1 );
893  outstr << quat.Data()[ 0 ] << " ";
894  outstr.width( 8 );
895  outstr << quat.Data()[ 1 ] << " ";
896  outstr.width( 8 );
897  outstr << quat.Data()[ 2 ] << " ";
898  outstr.width( 8 );
899  outstr << quat.Data()[ 3 ];
900 
901  return outstr;
902 }
903 
904 template<class Type>
905 inline std::istream& operator>>( std::istream& instr, GlsQuaternion<Type>& quat )
906 {
907  instr >> quat.Data()[ 0 ] >> quat.Data()[ 1 ] >> quat.Data()[ 2 ] >> quat.Data()[ 3 ];
908  return instr;
909 }
910 
911 } // end namespace disti
912 
913 #endif
const Type * Data() const
Definition: gls_quaternion.h:175
GlsQuaternion(Type angle1, const Vector &axis1, Type angle2, const Vector &axis2, Type angle3, const Vector &axis3)
Definition: gls_quaternion.h:115
GlsQuaternion(Type angle, const Vector &axis)
Definition: gls_quaternion.h:99
const GlsQuaternion operator+(const GlsQuaternion &q) const
Definition: gls_quaternion.h:355
const GlsQuaternion operator-() const
Definition: gls_quaternion.h:408
bool operator!=(const GlsQuaternion &q) const
Definition: gls_quaternion.h:199
Vector GetEulerAngles()
Definition: gls_quaternion.h:724
void Normalize(void)
Definition: vertex.h:307
float DotProduct(const VertexNoColor &w) const
Definition: vertex.h:356
GlsQuaternion & operator-=(const GlsQuaternion &q)
Definition: gls_quaternion.h:397
bool operator<(const GlsQuaternion &q) const
Definition: gls_quaternion.h:211
void SetFromVectors(const Vector &to, const Vector &from)
Definition: gls_quaternion.h:584
const GlsQuaternion Inverse() const
Definition: gls_quaternion.h:452
Type GetRoll(void) const
Definition: gls_quaternion.h:690
Type DotProduct(const GlsQuaternion &q) const
Definition: gls_quaternion.h:464
void SetFromAngleAxis(Type angle, const Vector &axis)
Definition: gls_quaternion.h:503
void GetAngleAxis(Type *angle, Vector *axis)
Definition: gls_quaternion.h:734
Type Magnitude() const
Definition: gls_quaternion.h:419
GlsQuaternion(const Vector &anglesVec)
Definition: gls_quaternion.h:142
void SetFromAngleAxis(Type angle1, const Vector &axis1, Type angle2, const Vector &axis2, Type angle3, const Vector &axis3)
Definition: gls_quaternion.h:525
const GlsQuaternion operator-(const GlsQuaternion &q) const
Definition: gls_quaternion.h:384
void SetFromEulerAngles(Type angleX, Type angleY, Type angleZ)
Definition: gls_quaternion.h:544
GlsQuaternion(const GlsMatrixAffine< Type > &matrix)
Definition: gls_quaternion.h:153
VertexNoColor Vector
Definition: gls_font_base.h:66
GlsQuaternion(Type angleX, Type angleY, Type angleZ)
Definition: gls_quaternion.h:130
GlsQuaternion Conjugate() const
Definition: gls_quaternion.h:441
GlsQuaternion & operator+=(const GlsQuaternion &q)
Definition: gls_quaternion.h:368
GlsQuaternion & operator/=(Type s)
Definition: gls_quaternion.h:313
The disti::Vertex class. A class for manipulating 3D vertices.
VertexNoColor CrossProduct(const VertexNoColor &w) const
Definition: vertex.h:345
Type GetPitch(void) const
Definition: gls_quaternion.h:698
GlsQuaternion()
Definition: gls_quaternion.h:67
Type MagnitudeSquared() const
Definition: gls_quaternion.h:430
GlsQuaternion(Type x, Type y, Type z, Type w)
Definition: gls_quaternion.h:84
void Set(Type x, Type y, Type z, Type w)
Definition: gls_quaternion.h:488
const GlsQuaternion operator*(Type s) const
Definition: gls_quaternion.h:236
GlsQuaternion & operator/=(const GlsQuaternion &q)
Definition: gls_quaternion.h:342
Type * Data()
Definition: gls_quaternion.h:164
Type GetYaw(void) const
Definition: gls_quaternion.h:716
Definition: vertex.h:83
GlsQuaternion & operator*=(const GlsQuaternion &q)
Definition: gls_quaternion.h:279
const GlsQuaternion operator*(const GlsQuaternion &q) const
Definition: gls_quaternion.h:264
Definition: gls_quaternion.h:59
const GlsQuaternion operator/(const GlsQuaternion &q) const
Definition: gls_quaternion.h:330
bool operator==(const GlsQuaternion &q) const
Definition: gls_quaternion.h:187
float Magnitude() const
Definition: vertex.h:326
void SetFromSlerp(float t, const GlsQuaternion &from, const GlsQuaternion &to, bool adjustSign=true)
Definition: gls_quaternion.h:834
GlsMatrixAffine< Type > GetRotationMatrix()
Definition: gls_quaternion.h:783
GlsQuaternion & operator*=(Type s)
Definition: gls_quaternion.h:248
void SetFromRotationMatrix(const GlsMatrixAffine< Type > &matrix)
Definition: gls_quaternion.h:637
void Normalize()
Definition: gls_quaternion.h:474
Definition: bmpimage.h:46
GlsQuaternion operator/(Type s) const
Definition: gls_quaternion.h:300
Definition: gls_matrix_affine.h:60