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