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