1 ///////////////////////////////////////////////////////////////////////////
3 // Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
6 // All rights reserved.
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions are
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
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.
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.
33 ///////////////////////////////////////////////////////////////////////////
37 #ifndef INCLUDED_IMATHEULER_H
38 #define INCLUDED_IMATHEULER_H
40 //----------------------------------------------------------------------
42 // template class Euler<T>
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.
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.
56 // The representations can be partitioned according to two
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)
64 // 2) Is one of the rotations repeated (ala XYX rotation)
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
75 // Eulerf angles(z_rot, y_rot, x_rot, Eulerf::ZYX);
77 // Eulerf angles( V3f(z_rot,y_rot,z_rot), Eulerf::ZYX );
79 // If instead, the order was YXZ for instance you would have to
86 // Eulerf angles(y_rot, x_rot, z_rot, Eulerf::YXZ);
88 // Eulerf angles( V3f(y_rot,x_rot,z_rot), Eulerf::YXZ );
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.:
98 // // v.x == y_rot, v.y == x_rot, v.z == z_rot
100 // If you just want the x, y, and z angles stored in a vector in
101 // that order, you can do this:
103 // V3f v = angles.toXYZVector()
104 // // v.x == x_rot, v.y == y_rot, v.z == z_rot
106 // If you want to set the Euler with an XYZVector use the
107 // optional layout argument:
109 // Eulerf angles(x_rot, y_rot, z_rot,
111 // Eulerf::XYZLayout);
113 // This is the same as:
115 // Eulerf angles(y_rot, x_rot, z_rot, Eulerf::YXZ);
117 // Note that this won't do anything intelligent if you have a
118 // repeated axis in the euler angles (e.g. XYX)
120 // If you need to use the "relative" versions of these, you will
121 // need to use the "r" enums.
123 // The units of the rotation angles are assumed to be radians.
125 //----------------------------------------------------------------------
128 #include "ImathMath.h"
129 #include "ImathVec.h"
130 #include "ImathQuat.h"
131 #include "ImathMatrix.h"
132 #include "ImathLimits.h"
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)
143 class Euler : public Vec3<T>
154 // All 24 possible orderings
157 XYZ = 0x0101, // "usual" orderings
164 XZX = 0x0011, // first axis repeated
171 XYZr = 0x2000, // relative orderings -- not common
178 XZXr = 0x2110, // relative first axis repeated
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)
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,
203 enum Axis { X = 0, Y = 1, Z = 2 };
205 enum InputLayout { XYZLayout, IJKLayout };
207 //----------------------------------------------------------------
208 // Constructors -- all default to ZYX non-relative ala softimage
209 // (where there is no argument to specify it)
210 //----------------------------------------------------------------
215 Euler(const Vec3<T> &v, Order o = Default, InputLayout l = IJKLayout);
216 Euler(T i, T j, T k, Order o = Default, InputLayout l = IJKLayout);
217 Euler(const Euler<T> &euler, Order newp);
218 Euler(const Matrix33<T> &, Order o = Default);
219 Euler(const Matrix44<T> &, Order o = Default);
221 //---------------------------------
222 // Algebraic functions/ Operators
223 //---------------------------------
225 const Euler<T>& operator= (const Euler<T>&);
226 const Euler<T>& operator= (const Vec3<T>&);
228 //--------------------------------------------------------
229 // Set the euler value
230 // This does NOT convert the angles, but setXYZVector()
231 // does reorder the input vector.
232 //--------------------------------------------------------
234 static bool legal(Order);
236 void setXYZVector(const Vec3<T> &);
239 void setOrder(Order);
241 void set(Axis initial,
246 //---------------------------------------------------------
247 // Conversions, toXYZVector() reorders the angles so that
248 // the X rotation comes first, followed by the Y and Z
249 // in cases like XYX ordering, the repeated angle will be
250 // in the "z" component
251 //---------------------------------------------------------
253 void extract(const Matrix33<T>&);
254 void extract(const Matrix44<T>&);
255 void extract(const Quat<T>&);
257 Matrix33<T> toMatrix33() const;
258 Matrix44<T> toMatrix44() const;
259 Quat<T> toQuat() const;
260 Vec3<T> toXYZVector() const;
262 //---------------------------------------------------
263 // Use this function to unpack angles from ijk form
264 //---------------------------------------------------
266 void angleOrder(int &i, int &j, int &k) const;
268 //---------------------------------------------------
269 // Use this function to determine mapping from xyz to ijk
270 // - reshuffles the xyz to match the order
271 //---------------------------------------------------
273 void angleMapping(int &i, int &j, int &k) const;
275 //----------------------------------------------------------------------
277 // Utility methods for getting continuous rotations. None of these
278 // methods change the orientation given by its inputs (or at least
279 // that is the intent).
281 // angleMod() converts an angle to its equivalent in [-PI, PI]
283 // simpleXYZRotation() adjusts xyzRot so that its components differ
284 // from targetXyzRot by no more than +-PI
286 // nearestRotation() adjusts xyzRot so that its components differ
287 // from targetXyzRot by as little as possible.
288 // Note that xyz here really means ijk, because
289 // the order must be provided.
291 // makeNear() adjusts "this" Euler so that its components differ
292 // from target by as little as possible. This method
293 // might not make sense for Eulers with different order
294 // and it probably doesn't work for repeated axis and
295 // relative orderings (TODO).
297 //-----------------------------------------------------------------------
299 static float angleMod (T angle);
300 static void simpleXYZRotation (Vec3<T> &xyzRot,
301 const Vec3<T> &targetXyzRot);
302 static void nearestRotation (Vec3<T> &xyzRot,
303 const Vec3<T> &targetXyzRot,
306 void makeNear (const Euler<T> &target);
308 bool frameStatic() const { return _frameStatic; }
309 bool initialRepeated() const { return _initialRepeated; }
310 bool parityEven() const { return _parityEven; }
311 Axis initialAxis() const { return _initialAxis; }
315 bool _frameStatic : 1; // relative or static rotations
316 bool _initialRepeated : 1; // init axis repeated as last
317 bool _parityEven : 1; // "parity of axis permutation"
318 #if defined _WIN32 || defined _WIN64
319 Axis _initialAxis ; // First axis of rotation
321 Axis _initialAxis : 2; // First axis of rotation
326 //--------------------
327 // Convenient typedefs
328 //--------------------
330 typedef Euler<float> Eulerf;
331 typedef Euler<double> Eulerd;
340 Euler<T>::angleOrder(int &i, int &j, int &k) const
343 j = _parityEven ? (i+1)%3 : (i > 0 ? i-1 : 2);
344 k = _parityEven ? (i > 0 ? i-1 : 2) : (i+1)%3;
349 Euler<T>::angleMapping(int &i, int &j, int &k) const
354 m[(_initialAxis+1) % 3] = _parityEven ? 1 : 2;
355 m[(_initialAxis+2) % 3] = _parityEven ? 2 : 1;
363 Euler<T>::setXYZVector(const Vec3<T> &v)
374 Euler<T>::toXYZVector() const
378 return Vec3<T>((*this)[i],(*this)[j],(*this)[k]);
386 _initialRepeated(false),
392 Euler<T>::Euler(typename Euler<T>::Order p) :
395 _initialRepeated(false),
403 inline Euler<T>::Euler( const Vec3<T> &v,
404 typename Euler<T>::Order p,
405 typename Euler<T>::InputLayout l )
408 if ( l == XYZLayout ) setXYZVector(v);
409 else { x = v.x; y = v.y; z = v.z; }
413 inline Euler<T>::Euler(const Euler<T> &euler)
419 inline Euler<T>::Euler(const Euler<T> &euler,Order p)
422 Matrix33<T> M = euler.toMatrix33();
427 inline Euler<T>::Euler( T xi, T yi, T zi,
428 typename Euler<T>::Order p,
429 typename Euler<T>::InputLayout l)
432 if ( l == XYZLayout ) setXYZVector(Vec3<T>(xi,yi,zi));
433 else { x = xi; y = yi; z = zi; }
437 inline Euler<T>::Euler( const Matrix33<T> &M, typename Euler::Order p )
444 inline Euler<T>::Euler( const Matrix44<T> &M, typename Euler::Order p )
451 inline void Euler<T>::extract(const Quat<T> &q)
453 extract(q.toMatrix33());
457 void Euler<T>::extract(const Matrix33<T> &M)
462 if (_initialRepeated)
465 // Extract the first angle, x.
468 x = Math<T>::atan2 (M[j][i], M[k][i]);
471 // Remove the x rotation from M, so that the remaining
472 // rotation, N, is only around two axes, and gimbal lock
477 r[i] = (_parityEven? -x: x);
482 N = N * Matrix44<T> (M[0][0], M[0][1], M[0][2], 0,
483 M[1][0], M[1][1], M[1][2], 0,
484 M[2][0], M[2][1], M[2][2], 0,
487 // Extract the other two angles, y and z, from N.
490 T sy = Math<T>::sqrt (N[j][i]*N[j][i] + N[k][i]*N[k][i]);
491 y = Math<T>::atan2 (sy, N[i][i]);
492 z = Math<T>::atan2 (N[j][k], N[j][j]);
497 // Extract the first angle, x.
500 x = Math<T>::atan2 (M[j][k], M[k][k]);
503 // Remove the x rotation from M, so that the remaining
504 // rotation, N, is only around two axes, and gimbal lock
509 r[i] = (_parityEven? -x: x);
514 N = N * Matrix44<T> (M[0][0], M[0][1], M[0][2], 0,
515 M[1][0], M[1][1], M[1][2], 0,
516 M[2][0], M[2][1], M[2][2], 0,
519 // Extract the other two angles, y and z, from N.
522 T cy = Math<T>::sqrt (N[i][i]*N[i][i] + N[i][j]*N[i][j]);
523 y = Math<T>::atan2 (-N[i][k], cy);
524 z = Math<T>::atan2 (-N[j][i], N[j][j]);
539 void Euler<T>::extract(const Matrix44<T> &M)
544 if (_initialRepeated)
547 // Extract the first angle, x.
550 x = Math<T>::atan2 (M[j][i], M[k][i]);
553 // Remove the x rotation from M, so that the remaining
554 // rotation, N, is only around two axes, and gimbal lock
559 r[i] = (_parityEven? -x: x);
566 // Extract the other two angles, y and z, from N.
569 T sy = Math<T>::sqrt (N[j][i]*N[j][i] + N[k][i]*N[k][i]);
570 y = Math<T>::atan2 (sy, N[i][i]);
571 z = Math<T>::atan2 (N[j][k], N[j][j]);
576 // Extract the first angle, x.
579 x = Math<T>::atan2 (M[j][k], M[k][k]);
582 // Remove the x rotation from M, so that the remaining
583 // rotation, N, is only around two axes, and gimbal lock
588 r[i] = (_parityEven? -x: x);
595 // Extract the other two angles, y and z, from N.
598 T cy = Math<T>::sqrt (N[i][i]*N[i][i] + N[i][j]*N[i][j]);
599 y = Math<T>::atan2 (-N[i][k], cy);
600 z = Math<T>::atan2 (-N[j][i], N[j][j]);
615 Matrix33<T> Euler<T>::toMatrix33() const
622 if ( _frameStatic ) angles = (*this);
623 else angles = Vec3<T>(z,y,x);
625 if ( !_parityEven ) angles *= -1.0;
627 T ci = Math<T>::cos(angles.x);
628 T cj = Math<T>::cos(angles.y);
629 T ch = Math<T>::cos(angles.z);
630 T si = Math<T>::sin(angles.x);
631 T sj = Math<T>::sin(angles.y);
632 T sh = Math<T>::sin(angles.z);
641 if ( _initialRepeated )
643 M[i][i] = cj; M[j][i] = sj*si; M[k][i] = sj*ci;
644 M[i][j] = sj*sh; M[j][j] = -cj*ss+cc; M[k][j] = -cj*cs-sc;
645 M[i][k] = -sj*ch; M[j][k] = cj*sc+cs; M[k][k] = cj*cc-ss;
649 M[i][i] = cj*ch; M[j][i] = sj*sc-cs; M[k][i] = sj*cc+ss;
650 M[i][j] = cj*sh; M[j][j] = sj*ss+cc; M[k][j] = sj*cs-sc;
651 M[i][k] = -sj; M[j][k] = cj*si; M[k][k] = cj*ci;
658 Matrix44<T> Euler<T>::toMatrix44() const
665 if ( _frameStatic ) angles = (*this);
666 else angles = Vec3<T>(z,y,x);
668 if ( !_parityEven ) angles *= -1.0;
670 T ci = Math<T>::cos(angles.x);
671 T cj = Math<T>::cos(angles.y);
672 T ch = Math<T>::cos(angles.z);
673 T si = Math<T>::sin(angles.x);
674 T sj = Math<T>::sin(angles.y);
675 T sh = Math<T>::sin(angles.z);
684 if ( _initialRepeated )
686 M[i][i] = cj; M[j][i] = sj*si; M[k][i] = sj*ci;
687 M[i][j] = sj*sh; M[j][j] = -cj*ss+cc; M[k][j] = -cj*cs-sc;
688 M[i][k] = -sj*ch; M[j][k] = cj*sc+cs; M[k][k] = cj*cc-ss;
692 M[i][i] = cj*ch; M[j][i] = sj*sc-cs; M[k][i] = sj*cc+ss;
693 M[i][j] = cj*sh; M[j][j] = sj*ss+cc; M[k][j] = sj*cs-sc;
694 M[i][k] = -sj; M[j][k] = cj*si; M[k][k] = cj*ci;
701 Quat<T> Euler<T>::toQuat() const
707 if ( _frameStatic ) angles = (*this);
708 else angles = Vec3<T>(z,y,x);
710 if ( !_parityEven ) angles.y = -angles.y;
715 T ci = Math<T>::cos(ti);
716 T cj = Math<T>::cos(tj);
717 T ch = Math<T>::cos(th);
718 T si = Math<T>::sin(ti);
719 T sj = Math<T>::sin(tj);
720 T sh = Math<T>::sin(th);
726 T parity = _parityEven ? 1.0 : -1.0;
731 if ( _initialRepeated )
734 a[j] = sj*(cc + ss) * parity,
740 a[i] = cj*sc - sj*cs,
741 a[j] = (cj*ss + sj*cc) * parity,
742 a[k] = cj*cs - sj*sc;
753 Euler<T>::legal(typename Euler<T>::Order order)
755 return (order & ~Legal) ? false : true;
759 typename Euler<T>::Order
760 Euler<T>::order() const
762 int foo = (_initialAxis == Z ? 0x2000 : (_initialAxis == Y ? 0x1000 : 0));
764 if (_parityEven) foo |= 0x0100;
765 if (_initialRepeated) foo |= 0x0010;
766 if (_frameStatic) foo++;
772 inline void Euler<T>::setOrder(typename Euler<T>::Order p)
774 set( p & 0x2000 ? Z : (p & 0x1000 ? Y : X), // initial axis
775 !(p & 0x1), // static?
776 !!(p & 0x100), // permutation even?
777 !!(p & 0x10)); // initial repeats?
781 void Euler<T>::set(typename Euler<T>::Axis axis,
787 _frameStatic = !relative;
788 _parityEven = parityEven;
789 _initialRepeated = firstRepeats;
793 const Euler<T>& Euler<T>::operator= (const Euler<T> &euler)
798 _initialAxis = euler._initialAxis;
799 _frameStatic = euler._frameStatic;
800 _parityEven = euler._parityEven;
801 _initialRepeated = euler._initialRepeated;
806 const Euler<T>& Euler<T>::operator= (const Vec3<T> &v)
815 std::ostream& operator << (std::ostream &o, const Euler<T> &euler)
817 char a[3] = { 'X', 'Y', 'Z' };
819 const char* r = euler.frameStatic() ? "" : "r";
821 euler.angleOrder(i,j,k);
823 if ( euler.initialRepeated() ) k = i;
829 << a[i] << a[j] << a[k] << r << ")";
834 Euler<T>::angleMod (T angle)
836 angle = fmod(T (angle), T (2 * M_PI));
838 if (angle < -M_PI) angle += 2 * M_PI;
839 if (angle > +M_PI) angle -= 2 * M_PI;
846 Euler<T>::simpleXYZRotation (Vec3<T> &xyzRot, const Vec3<T> &targetXyzRot)
848 Vec3<T> d = xyzRot - targetXyzRot;
849 xyzRot[0] = targetXyzRot[0] + angleMod(d[0]);
850 xyzRot[1] = targetXyzRot[1] + angleMod(d[1]);
851 xyzRot[2] = targetXyzRot[2] + angleMod(d[2]);
856 Euler<T>::nearestRotation (Vec3<T> &xyzRot, const Vec3<T> &targetXyzRot,
860 Euler<T> e (0,0,0, order);
863 simpleXYZRotation(xyzRot, targetXyzRot);
866 otherXyzRot[i] = M_PI+xyzRot[i];
867 otherXyzRot[j] = M_PI-xyzRot[j];
868 otherXyzRot[k] = M_PI+xyzRot[k];
870 simpleXYZRotation(otherXyzRot, targetXyzRot);
872 Vec3<T> d = xyzRot - targetXyzRot;
873 Vec3<T> od = otherXyzRot - targetXyzRot;
875 T odMag = od.dot(od);
879 xyzRot = otherXyzRot;
885 Euler<T>::makeNear (const Euler<T> &target)
887 Vec3<T> xyzRot = toXYZVector();
888 Euler<T> targetSameOrder = Euler<T>(target, order());
889 Vec3<T> targetXyz = targetSameOrder.toXYZVector();
891 nearestRotation(xyzRot, targetXyz, order());
893 setXYZVector(xyzRot);
896 #if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
897 #pragma warning(default:4244)