• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
4 // Digital Ltd. LLC
5 //
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions are
10 // met:
11 // *       Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // *       Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 // *       Neither the name of Industrial Light & Magic nor the names of
18 // its contributors may be used to endorse or promote products derived
19 // from this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 ///////////////////////////////////////////////////////////////////////////
34 
35 
36 
37 #ifndef INCLUDED_IMATHEULER_H
38 #define INCLUDED_IMATHEULER_H
39 
40 //----------------------------------------------------------------------
41 //
42 //	template class Euler<T>
43 //
44 //      This class represents euler angle orientations. The class
45 //	inherits from Vec3 to it can be freely cast. The additional
46 //	information is the euler priorities rep. This class is
47 //	essentially a rip off of Ken Shoemake's GemsIV code. It has
48 //	been modified minimally to make it more understandable, but
49 //	hardly enough to make it easy to grok completely.
50 //
51 //	There are 24 possible combonations of Euler angle
52 //	representations of which 12 are common in CG and you will
53 //	probably only use 6 of these which in this scheme are the
54 //	non-relative-non-repeating types.
55 //
56 //	The representations can be partitioned according to two
57 //	criteria:
58 //
59 //	   1) Are the angles measured relative to a set of fixed axis
60 //	      or relative to each other (the latter being what happens
61 //	      when rotation matrices are multiplied together and is
62 //	      almost ubiquitous in the cg community)
63 //
64 //	   2) Is one of the rotations repeated (ala XYX rotation)
65 //
66 //	When you construct a given representation from scratch you
67 //	must order the angles according to their priorities. So, the
68 //	easiest is a softimage or aerospace (yaw/pitch/roll) ordering
69 //	of ZYX.
70 //
71 //	    float x_rot = 1;
72 //	    float y_rot = 2;
73 //	    float z_rot = 3;
74 //
75 //	    Eulerf angles(z_rot, y_rot, x_rot, Eulerf::ZYX);
76 //		-or-
77 //	    Eulerf angles( V3f(z_rot,y_rot,z_rot), Eulerf::ZYX );
78 //
79 //	If instead, the order was YXZ for instance you would have to
80 //	do this:
81 //
82 //	    float x_rot = 1;
83 //	    float y_rot = 2;
84 //	    float z_rot = 3;
85 //
86 //	    Eulerf angles(y_rot, x_rot, z_rot, Eulerf::YXZ);
87 //		-or-
88 //	    Eulerf angles( V3f(y_rot,x_rot,z_rot), Eulerf::YXZ );
89 //
90 //	Notice how the order you put the angles into the three slots
91 //	should correspond to the enum (YXZ) ordering. The input angle
92 //	vector is called the "ijk" vector -- not an "xyz" vector. The
93 //	ijk vector order is the same as the enum. If you treat the
94 //	Euler<> as a Vec<> (which it inherts from) you will find the
95 //	angles are ordered in the same way, i.e.:
96 //
97 //	    V3f v = angles;
98 //	    // v.x == y_rot, v.y == x_rot, v.z == z_rot
99 //
100 //	If you just want the x, y, and z angles stored in a vector in
101 //	that order, you can do this:
102 //
103 //	    V3f v = angles.toXYZVector()
104 //	    // v.x == x_rot, v.y == y_rot, v.z == z_rot
105 //
106 //	If you want to set the Euler with an XYZVector use the
107 //	optional layout argument:
108 //
109 //	    Eulerf angles(x_rot, y_rot, z_rot,
110 //			  Eulerf::YXZ,
111 //		          Eulerf::XYZLayout);
112 //
113 //	This is the same as:
114 //
115 //	    Eulerf angles(y_rot, x_rot, z_rot, Eulerf::YXZ);
116 //
117 //	Note that this won't do anything intelligent if you have a
118 //	repeated axis in the euler angles (e.g. XYX)
119 //
120 //	If you need to use the "relative" versions of these, you will
121 //	need to use the "r" enums.
122 //
123 //      The units of the rotation angles are assumed to be radians.
124 //
125 //----------------------------------------------------------------------
126 
127 
128 #include "ImathMath.h"
129 #include "ImathVec.h"
130 #include "ImathQuat.h"
131 #include "ImathMatrix.h"
132 #include "ImathLimits.h"
133 #include <iostream>
134 
135 namespace Imath {
136 
137 #if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
138 // Disable MS VC++ warnings about conversion from double to float
139 #pragma warning(disable:4244)
140 #endif
141 
142 template <class T>
143 class Euler : public Vec3<T>
144 {
145   public:
146 
147     using Vec3<T>::x;
148     using Vec3<T>::y;
149     using Vec3<T>::z;
150 
151     enum Order
152     {
153     //
154     //  All 24 possible orderings
155     //
156 
157     XYZ	= 0x0101,	// "usual" orderings
158     XZY	= 0x0001,
159     YZX	= 0x1101,
160     YXZ	= 0x1001,
161     ZXY	= 0x2101,
162     ZYX	= 0x2001,
163 
164     XZX	= 0x0011,	// first axis repeated
165     XYX	= 0x0111,
166     YXY	= 0x1011,
167     YZY	= 0x1111,
168     ZYZ	= 0x2011,
169     ZXZ	= 0x2111,
170 
171     XYZr	= 0x2000,	// relative orderings -- not common
172     XZYr	= 0x2100,
173     YZXr	= 0x1000,
174     YXZr	= 0x1100,
175     ZXYr	= 0x0000,
176     ZYXr	= 0x0100,
177 
178     XZXr	= 0x2110,	// relative first axis repeated
179     XYXr	= 0x2010,
180     YXYr	= 0x1110,
181     YZYr	= 0x1010,
182     ZYZr	= 0x0110,
183     ZXZr	= 0x0010,
184     //          ||||
185     //          VVVV
186     //  Legend: ABCD
187     //  A -> Initial Axis (0==x, 1==y, 2==z)
188     //  B -> Parity Even (1==true)
189     //  C -> Initial Repeated (1==true)
190     //  D -> Frame Static (1==true)
191     //
192 
193     Legal	=   XYZ | XZY | YZX | YXZ | ZXY | ZYX |
194             XZX | XYX | YXY | YZY | ZYZ | ZXZ |
195             XYZr| XZYr| YZXr| YXZr| ZXYr| ZYXr|
196             XZXr| XYXr| YXYr| YZYr| ZYZr| ZXZr,
197 
198     Min	= 0x0000,
199     Max	= 0x2111,
200     Default	= XYZ
201     };
202 
203     enum Axis { X = 0, Y = 1, Z = 2 };
204 
205     enum InputLayout { XYZLayout, IJKLayout };
206 
207     //--------------------------------------------------------------------
208     //	Constructors -- all default to ZYX non-relative ala softimage
209     //			(where there is no argument to specify it)
210     //
211     // The Euler-from-matrix constructors assume that the matrix does
212     // not include shear or non-uniform scaling, but the constructors
213     // do not examine the matrix to verify this assumption.  If necessary,
214     // you can adjust the matrix by calling the removeScalingAndShear()
215     // function, defined in ImathMatrixAlgo.h.
216     //--------------------------------------------------------------------
217 
218     Euler();
219     Euler(const Euler&);
220     Euler(Order p);
221     Euler(const Vec3<T> &v, Order o = Default, InputLayout l = IJKLayout);
222     Euler(T i, T j, T k, Order o = Default, InputLayout l = IJKLayout);
223     Euler(const Euler<T> &euler, Order newp);
224     Euler(const Matrix33<T> &, Order o = Default);
225     Euler(const Matrix44<T> &, Order o = Default);
226 
227     //---------------------------------
228     //  Algebraic functions/ Operators
229     //---------------------------------
230 
231     const Euler<T>&	operator=  (const Euler<T>&);
232     const Euler<T>&	operator=  (const Vec3<T>&);
233 
234     //--------------------------------------------------------
235     //	Set the euler value
236     //  This does NOT convert the angles, but setXYZVector()
237     //	does reorder the input vector.
238     //--------------------------------------------------------
239 
240     static bool		legal(Order);
241 
242     void		setXYZVector(const Vec3<T> &);
243 
244     Order		order() const;
245     void		setOrder(Order);
246 
247     void		set(Axis initial,
248                 bool relative,
249                 bool parityEven,
250                 bool firstRepeats);
251 
252     //------------------------------------------------------------
253     //	Conversions, toXYZVector() reorders the angles so that
254     //  the X rotation comes first, followed by the Y and Z
255     //  in cases like XYX ordering, the repeated angle will be
256     //	in the "z" component
257     //
258     // The Euler-from-matrix extract() functions assume that the
259     // matrix does not include shear or non-uniform scaling, but
260     // the extract() functions do not examine the matrix to verify
261     // this assumption.  If necessary, you can adjust the matrix
262     // by calling the removeScalingAndShear() function, defined
263     // in ImathMatrixAlgo.h.
264     //------------------------------------------------------------
265 
266     void		extract(const Matrix33<T>&);
267     void		extract(const Matrix44<T>&);
268     void		extract(const Quat<T>&);
269 
270     Matrix33<T>		toMatrix33() const;
271     Matrix44<T>		toMatrix44() const;
272     Quat<T>		toQuat() const;
273     Vec3<T>		toXYZVector() const;
274 
275     //---------------------------------------------------
276     //	Use this function to unpack angles from ijk form
277     //---------------------------------------------------
278 
279     void		angleOrder(int &i, int &j, int &k) const;
280 
281     //---------------------------------------------------
282     //	Use this function to determine mapping from xyz to ijk
283     // - reshuffles the xyz to match the order
284     //---------------------------------------------------
285 
286     void		angleMapping(int &i, int &j, int &k) const;
287 
288     //----------------------------------------------------------------------
289     //
290     //  Utility methods for getting continuous rotations. None of these
291     //  methods change the orientation given by its inputs (or at least
292     //  that is the intent).
293     //
294     //    angleMod() converts an angle to its equivalent in [-PI, PI]
295     //
296     //    simpleXYZRotation() adjusts xyzRot so that its components differ
297     //                        from targetXyzRot by no more than +-PI
298     //
299     //    nearestRotation() adjusts xyzRot so that its components differ
300     //                      from targetXyzRot by as little as possible.
301     //                      Note that xyz here really means ijk, because
302     //                      the order must be provided.
303     //
304     //    makeNear() adjusts "this" Euler so that its components differ
305     //               from target by as little as possible. This method
306     //               might not make sense for Eulers with different order
307     //               and it probably doesn't work for repeated axis and
308     //               relative orderings (TODO).
309     //
310     //-----------------------------------------------------------------------
311 
312     static float	angleMod (T angle);
313     static void		simpleXYZRotation (Vec3<T> &xyzRot,
314                        const Vec3<T> &targetXyzRot);
315     static void		nearestRotation (Vec3<T> &xyzRot,
316                      const Vec3<T> &targetXyzRot,
317                      Order order = XYZ);
318 
319     void		makeNear (const Euler<T> &target);
320 
frameStatic()321     bool		frameStatic() const { return _frameStatic; }
initialRepeated()322     bool		initialRepeated() const { return _initialRepeated; }
parityEven()323     bool		parityEven() const { return _parityEven; }
initialAxis()324     Axis		initialAxis() const { return _initialAxis; }
325 
326   protected:
327 
328     bool		_frameStatic	 : 1;	// relative or static rotations
329     bool		_initialRepeated : 1;	// init axis repeated as last
330     bool		_parityEven	 : 1;	// "parity of axis permutation"
331 #if defined _WIN32 || defined _WIN64
332     Axis		_initialAxis	 ;	// First axis of rotation
333 #else
334     Axis		_initialAxis	 : 2;	// First axis of rotation
335 #endif
336 };
337 
338 
339 //--------------------
340 // Convenient typedefs
341 //--------------------
342 
343 typedef Euler<float>	Eulerf;
344 typedef Euler<double>	Eulerd;
345 
346 
347 //---------------
348 // Implementation
349 //---------------
350 
351 template<class T>
352 inline void
angleOrder(int & i,int & j,int & k)353  Euler<T>::angleOrder(int &i, int &j, int &k) const
354 {
355     i = _initialAxis;
356     j = _parityEven ? (i+1)%3 : (i > 0 ? i-1 : 2);
357     k = _parityEven ? (i > 0 ? i-1 : 2) : (i+1)%3;
358 }
359 
360 template<class T>
361 inline void
angleMapping(int & i,int & j,int & k)362  Euler<T>::angleMapping(int &i, int &j, int &k) const
363 {
364     int m[3];
365 
366     m[_initialAxis] = 0;
367     m[(_initialAxis+1) % 3] = _parityEven ? 1 : 2;
368     m[(_initialAxis+2) % 3] = _parityEven ? 2 : 1;
369     i = m[0];
370     j = m[1];
371     k = m[2];
372 }
373 
374 template<class T>
375 inline void
setXYZVector(const Vec3<T> & v)376 Euler<T>::setXYZVector(const Vec3<T> &v)
377 {
378     int i,j,k;
379     angleMapping(i,j,k);
380     (*this)[i] = v.x;
381     (*this)[j] = v.y;
382     (*this)[k] = v.z;
383 }
384 
385 template<class T>
386 inline Vec3<T>
toXYZVector()387 Euler<T>::toXYZVector() const
388 {
389     int i,j,k;
390     angleMapping(i,j,k);
391     return Vec3<T>((*this)[i],(*this)[j],(*this)[k]);
392 }
393 
394 
395 template<class T>
Euler()396 Euler<T>::Euler() :
397     Vec3<T>(0,0,0),
398     _frameStatic(true),
399     _initialRepeated(false),
400     _parityEven(true),
401     _initialAxis(X)
402 {}
403 
404 template<class T>
Euler(typename Euler<T>::Order p)405 Euler<T>::Euler(typename Euler<T>::Order p) :
406     Vec3<T>(0,0,0),
407     _frameStatic(true),
408     _initialRepeated(false),
409     _parityEven(true),
410     _initialAxis(X)
411 {
412     setOrder(p);
413 }
414 
415 template<class T>
Euler(const Vec3<T> & v,typename Euler<T>::Order p,typename Euler<T>::InputLayout l)416 inline Euler<T>::Euler( const Vec3<T> &v,
417             typename Euler<T>::Order p,
418             typename Euler<T>::InputLayout l )
419 {
420     setOrder(p);
421     if ( l == XYZLayout ) setXYZVector(v);
422     else { x = v.x; y = v.y; z = v.z; }
423 }
424 
425 template<class T>
Euler(const Euler<T> & euler)426 inline Euler<T>::Euler(const Euler<T> &euler)
427 {
428     operator=(euler);
429 }
430 
431 template<class T>
Euler(const Euler<T> & euler,Order p)432 inline Euler<T>::Euler(const Euler<T> &euler,Order p)
433 {
434     setOrder(p);
435     Matrix33<T> M = euler.toMatrix33();
436     extract(M);
437 }
438 
439 template<class T>
Euler(T xi,T yi,T zi,typename Euler<T>::Order p,typename Euler<T>::InputLayout l)440 inline Euler<T>::Euler( T xi, T yi, T zi,
441             typename Euler<T>::Order p,
442             typename Euler<T>::InputLayout l)
443 {
444     setOrder(p);
445     if ( l == XYZLayout ) setXYZVector(Vec3<T>(xi,yi,zi));
446     else { x = xi; y = yi; z = zi; }
447 }
448 
449 template<class T>
Euler(const Matrix33<T> & M,typename Euler::Order p)450 inline Euler<T>::Euler( const Matrix33<T> &M, typename Euler::Order p )
451 {
452     setOrder(p);
453     extract(M);
454 }
455 
456 template<class T>
Euler(const Matrix44<T> & M,typename Euler::Order p)457 inline Euler<T>::Euler( const Matrix44<T> &M, typename Euler::Order p )
458 {
459     setOrder(p);
460     extract(M);
461 }
462 
463 template<class T>
extract(const Quat<T> & q)464 inline void Euler<T>::extract(const Quat<T> &q)
465 {
466     extract(q.toMatrix33());
467 }
468 
469 template<class T>
extract(const Matrix33<T> & M)470 void Euler<T>::extract(const Matrix33<T> &M)
471 {
472     int i,j,k;
473     angleOrder(i,j,k);
474 
475     if (_initialRepeated)
476     {
477     //
478     // Extract the first angle, x.
479     //
480 
481     x = Math<T>::atan2 (M[j][i], M[k][i]);
482 
483     //
484     // Remove the x rotation from M, so that the remaining
485     // rotation, N, is only around two axes, and gimbal lock
486     // cannot occur.
487     //
488 
489     Vec3<T> r (0, 0, 0);
490     r[i] = (_parityEven? -x: x);
491 
492     Matrix44<T> N;
493     N.rotate (r);
494 
495     N = N * Matrix44<T> (M[0][0], M[0][1], M[0][2], 0,
496                  M[1][0], M[1][1], M[1][2], 0,
497                  M[2][0], M[2][1], M[2][2], 0,
498                  0,       0,       0,       1);
499     //
500     // Extract the other two angles, y and z, from N.
501     //
502 
503     T sy = Math<T>::sqrt (N[j][i]*N[j][i] + N[k][i]*N[k][i]);
504     y = Math<T>::atan2 (sy, N[i][i]);
505     z = Math<T>::atan2 (N[j][k], N[j][j]);
506     }
507     else
508     {
509     //
510     // Extract the first angle, x.
511     //
512 
513     x = Math<T>::atan2 (M[j][k], M[k][k]);
514 
515     //
516     // Remove the x rotation from M, so that the remaining
517     // rotation, N, is only around two axes, and gimbal lock
518     // cannot occur.
519     //
520 
521     Vec3<T> r (0, 0, 0);
522     r[i] = (_parityEven? -x: x);
523 
524     Matrix44<T> N;
525     N.rotate (r);
526 
527     N = N * Matrix44<T> (M[0][0], M[0][1], M[0][2], 0,
528                  M[1][0], M[1][1], M[1][2], 0,
529                  M[2][0], M[2][1], M[2][2], 0,
530                  0,       0,       0,       1);
531     //
532     // Extract the other two angles, y and z, from N.
533     //
534 
535     T cy = Math<T>::sqrt (N[i][i]*N[i][i] + N[i][j]*N[i][j]);
536     y = Math<T>::atan2 (-N[i][k], cy);
537     z = Math<T>::atan2 (-N[j][i], N[j][j]);
538     }
539 
540     if (!_parityEven)
541     *this *= -1;
542 
543     if (!_frameStatic)
544     {
545     T t = x;
546     x = z;
547     z = t;
548     }
549 }
550 
551 template<class T>
extract(const Matrix44<T> & M)552 void Euler<T>::extract(const Matrix44<T> &M)
553 {
554     int i,j,k;
555     angleOrder(i,j,k);
556 
557     if (_initialRepeated)
558     {
559     //
560     // Extract the first angle, x.
561     //
562 
563     x = Math<T>::atan2 (M[j][i], M[k][i]);
564 
565     //
566     // Remove the x rotation from M, so that the remaining
567     // rotation, N, is only around two axes, and gimbal lock
568     // cannot occur.
569     //
570 
571     Vec3<T> r (0, 0, 0);
572     r[i] = (_parityEven? -x: x);
573 
574     Matrix44<T> N;
575     N.rotate (r);
576     N = N * M;
577 
578     //
579     // Extract the other two angles, y and z, from N.
580     //
581 
582     T sy = Math<T>::sqrt (N[j][i]*N[j][i] + N[k][i]*N[k][i]);
583     y = Math<T>::atan2 (sy, N[i][i]);
584     z = Math<T>::atan2 (N[j][k], N[j][j]);
585     }
586     else
587     {
588     //
589     // Extract the first angle, x.
590     //
591 
592     x = Math<T>::atan2 (M[j][k], M[k][k]);
593 
594     //
595     // Remove the x rotation from M, so that the remaining
596     // rotation, N, is only around two axes, and gimbal lock
597     // cannot occur.
598     //
599 
600     Vec3<T> r (0, 0, 0);
601     r[i] = (_parityEven? -x: x);
602 
603     Matrix44<T> N;
604     N.rotate (r);
605     N = N * M;
606 
607     //
608     // Extract the other two angles, y and z, from N.
609     //
610 
611     T cy = Math<T>::sqrt (N[i][i]*N[i][i] + N[i][j]*N[i][j]);
612     y = Math<T>::atan2 (-N[i][k], cy);
613     z = Math<T>::atan2 (-N[j][i], N[j][j]);
614     }
615 
616     if (!_parityEven)
617     *this *= -1;
618 
619     if (!_frameStatic)
620     {
621     T t = x;
622     x = z;
623     z = t;
624     }
625 }
626 
627 template<class T>
toMatrix33()628 Matrix33<T> Euler<T>::toMatrix33() const
629 {
630     int i,j,k;
631     angleOrder(i,j,k);
632 
633     Vec3<T> angles;
634 
635     if ( _frameStatic ) angles = (*this);
636     else angles = Vec3<T>(z,y,x);
637 
638     if ( !_parityEven ) angles *= -1.0;
639 
640     T ci = Math<T>::cos(angles.x);
641     T cj = Math<T>::cos(angles.y);
642     T ch = Math<T>::cos(angles.z);
643     T si = Math<T>::sin(angles.x);
644     T sj = Math<T>::sin(angles.y);
645     T sh = Math<T>::sin(angles.z);
646 
647     T cc = ci*ch;
648     T cs = ci*sh;
649     T sc = si*ch;
650     T ss = si*sh;
651 
652     Matrix33<T> M;
653 
654     if ( _initialRepeated )
655     {
656     M[i][i] = cj;	  M[j][i] =  sj*si;    M[k][i] =  sj*ci;
657     M[i][j] = sj*sh;  M[j][j] = -cj*ss+cc; M[k][j] = -cj*cs-sc;
658     M[i][k] = -sj*ch; M[j][k] =  cj*sc+cs; M[k][k] =  cj*cc-ss;
659     }
660     else
661     {
662     M[i][i] = cj*ch; M[j][i] = sj*sc-cs; M[k][i] = sj*cc+ss;
663     M[i][j] = cj*sh; M[j][j] = sj*ss+cc; M[k][j] = sj*cs-sc;
664     M[i][k] = -sj;	 M[j][k] = cj*si;    M[k][k] = cj*ci;
665     }
666 
667     return M;
668 }
669 
670 template<class T>
toMatrix44()671 Matrix44<T> Euler<T>::toMatrix44() const
672 {
673     int i,j,k;
674     angleOrder(i,j,k);
675 
676     Vec3<T> angles;
677 
678     if ( _frameStatic ) angles = (*this);
679     else angles = Vec3<T>(z,y,x);
680 
681     if ( !_parityEven ) angles *= -1.0;
682 
683     T ci = Math<T>::cos(angles.x);
684     T cj = Math<T>::cos(angles.y);
685     T ch = Math<T>::cos(angles.z);
686     T si = Math<T>::sin(angles.x);
687     T sj = Math<T>::sin(angles.y);
688     T sh = Math<T>::sin(angles.z);
689 
690     T cc = ci*ch;
691     T cs = ci*sh;
692     T sc = si*ch;
693     T ss = si*sh;
694 
695     Matrix44<T> M;
696 
697     if ( _initialRepeated )
698     {
699     M[i][i] = cj;	  M[j][i] =  sj*si;    M[k][i] =  sj*ci;
700     M[i][j] = sj*sh;  M[j][j] = -cj*ss+cc; M[k][j] = -cj*cs-sc;
701     M[i][k] = -sj*ch; M[j][k] =  cj*sc+cs; M[k][k] =  cj*cc-ss;
702     }
703     else
704     {
705     M[i][i] = cj*ch; M[j][i] = sj*sc-cs; M[k][i] = sj*cc+ss;
706     M[i][j] = cj*sh; M[j][j] = sj*ss+cc; M[k][j] = sj*cs-sc;
707     M[i][k] = -sj;	 M[j][k] = cj*si;    M[k][k] = cj*ci;
708     }
709 
710     return M;
711 }
712 
713 template<class T>
toQuat()714 Quat<T> Euler<T>::toQuat() const
715 {
716     Vec3<T> angles;
717     int i,j,k;
718     angleOrder(i,j,k);
719 
720     if ( _frameStatic ) angles = (*this);
721     else angles = Vec3<T>(z,y,x);
722 
723     if ( !_parityEven ) angles.y = -angles.y;
724 
725     T ti = angles.x*0.5;
726     T tj = angles.y*0.5;
727     T th = angles.z*0.5;
728     T ci = Math<T>::cos(ti);
729     T cj = Math<T>::cos(tj);
730     T ch = Math<T>::cos(th);
731     T si = Math<T>::sin(ti);
732     T sj = Math<T>::sin(tj);
733     T sh = Math<T>::sin(th);
734     T cc = ci*ch;
735     T cs = ci*sh;
736     T sc = si*ch;
737     T ss = si*sh;
738 
739     T parity = _parityEven ? 1.0 : -1.0;
740 
741     Quat<T> q;
742     Vec3<T> a;
743 
744     if ( _initialRepeated )
745     {
746     a[i]	= cj*(cs + sc);
747     a[j]	= sj*(cc + ss) * parity,
748     a[k]	= sj*(cs - sc);
749     q.r	= cj*(cc - ss);
750     }
751     else
752     {
753     a[i]	= cj*sc - sj*cs,
754     a[j]	= (cj*ss + sj*cc) * parity,
755     a[k]	= cj*cs - sj*sc;
756     q.r	= cj*cc + sj*ss;
757     }
758 
759     q.v = a;
760 
761     return q;
762 }
763 
764 template<class T>
765 inline bool
legal(typename Euler<T>::Order order)766 Euler<T>::legal(typename Euler<T>::Order order)
767 {
768     return (order & ~Legal) ? false : true;
769 }
770 
771 template<class T>
772 typename Euler<T>::Order
order()773 Euler<T>::order() const
774 {
775     int foo = (_initialAxis == Z ? 0x2000 : (_initialAxis == Y ? 0x1000 : 0));
776 
777     if (_parityEven)	  foo |= 0x0100;
778     if (_initialRepeated) foo |= 0x0010;
779     if (_frameStatic)	  foo++;
780 
781     return (Order)foo;
782 }
783 
784 template<class T>
setOrder(typename Euler<T>::Order p)785 inline void Euler<T>::setOrder(typename Euler<T>::Order p)
786 {
787     set( p & 0x2000 ? Z : (p & 0x1000 ? Y : X),	// initial axis
788      !(p & 0x1),	    			// static?
789      !!(p & 0x100),				// permutation even?
790      !!(p & 0x10));				// initial repeats?
791 }
792 
793 template<class T>
set(typename Euler<T>::Axis axis,bool relative,bool parityEven,bool firstRepeats)794 void Euler<T>::set(typename Euler<T>::Axis axis,
795            bool relative,
796            bool parityEven,
797            bool firstRepeats)
798 {
799     _initialAxis	= axis;
800     _frameStatic	= !relative;
801     _parityEven		= parityEven;
802     _initialRepeated	= firstRepeats;
803 }
804 
805 template<class T>
806 const Euler<T>& Euler<T>::operator= (const Euler<T> &euler)
807 {
808     x = euler.x;
809     y = euler.y;
810     z = euler.z;
811     _initialAxis = euler._initialAxis;
812     _frameStatic = euler._frameStatic;
813     _parityEven	 = euler._parityEven;
814     _initialRepeated = euler._initialRepeated;
815     return *this;
816 }
817 
818 template<class T>
819 const Euler<T>& Euler<T>::operator= (const Vec3<T> &v)
820 {
821     x = v.x;
822     y = v.y;
823     z = v.z;
824     return *this;
825 }
826 
827 template<class T>
828 std::ostream& operator << (std::ostream &o, const Euler<T> &euler)
829 {
830     char a[3] = { 'X', 'Y', 'Z' };
831 
832     const char* r = euler.frameStatic() ? "" : "r";
833     int i,j,k;
834     euler.angleOrder(i,j,k);
835 
836     if ( euler.initialRepeated() ) k = i;
837 
838     return o << "("
839          << euler.x << " "
840          << euler.y << " "
841          << euler.z << " "
842          << a[i] << a[j] << a[k] << r << ")";
843 }
844 
845 template <class T>
846 float
angleMod(T angle)847 Euler<T>::angleMod (T angle)
848 {
849     angle = fmod(T (angle), T (2 * M_PI));
850 
851     if (angle < -M_PI)	angle += 2 * M_PI;
852     if (angle > +M_PI)	angle -= 2 * M_PI;
853 
854     return angle;
855 }
856 
857 template <class T>
858 void
simpleXYZRotation(Vec3<T> & xyzRot,const Vec3<T> & targetXyzRot)859 Euler<T>::simpleXYZRotation (Vec3<T> &xyzRot, const Vec3<T> &targetXyzRot)
860 {
861     Vec3<T> d  = xyzRot - targetXyzRot;
862     xyzRot[0]  = targetXyzRot[0] + angleMod(d[0]);
863     xyzRot[1]  = targetXyzRot[1] + angleMod(d[1]);
864     xyzRot[2]  = targetXyzRot[2] + angleMod(d[2]);
865 }
866 
867 template <class T>
868 void
nearestRotation(Vec3<T> & xyzRot,const Vec3<T> & targetXyzRot,Order order)869 Euler<T>::nearestRotation (Vec3<T> &xyzRot, const Vec3<T> &targetXyzRot,
870                Order order)
871 {
872     int i,j,k;
873     Euler<T> e (0,0,0, order);
874     e.angleOrder(i,j,k);
875 
876     simpleXYZRotation(xyzRot, targetXyzRot);
877 
878     Vec3<T> otherXyzRot;
879     otherXyzRot[i] = M_PI+xyzRot[i];
880     otherXyzRot[j] = M_PI-xyzRot[j];
881     otherXyzRot[k] = M_PI+xyzRot[k];
882 
883     simpleXYZRotation(otherXyzRot, targetXyzRot);
884 
885     Vec3<T> d  = xyzRot - targetXyzRot;
886     Vec3<T> od = otherXyzRot - targetXyzRot;
887     T dMag     = d.dot(d);
888     T odMag    = od.dot(od);
889 
890     if (odMag < dMag)
891     {
892     xyzRot = otherXyzRot;
893     }
894 }
895 
896 template <class T>
897 void
makeNear(const Euler<T> & target)898 Euler<T>::makeNear (const Euler<T> &target)
899 {
900     Vec3<T> xyzRot = toXYZVector();
901     Vec3<T> targetXyz;
902     if (order() != target.order())
903     {
904         Euler<T> targetSameOrder = Euler<T>(target, order());
905         targetXyz = targetSameOrder.toXYZVector();
906     }
907     else
908     {
909         targetXyz = target.toXYZVector();
910     }
911 
912     nearestRotation(xyzRot, targetXyz, order());
913 
914     setXYZVector(xyzRot);
915 }
916 
917 #if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
918 #pragma warning(default:4244)
919 #endif
920 
921 } // namespace Imath
922 
923 
924 #endif
925