Atoms Crowd  7.0.0
ImathEuler.h
1 //
2 // SPDX-License-Identifier: BSD-3-Clause
3 // Copyright Contributors to the OpenEXR Project.
4 //
5 
6 //
7 // Euler angle representation of rotation/orientation
8 //
9 
10 #ifndef INCLUDED_ATOMSMATHEULER_H
11 #define INCLUDED_ATOMSMATHEULER_H
12 
13 #include <AtomsMath/ImathMath.h>
14 #include <AtomsMath/ImathMatrix.h>
15 #include <AtomsMath/ImathNamespace.h>
16 #include <AtomsMath/ImathQuat.h>
17 #include <AtomsMath/ImathVec.h>
18 
19 #include <iostream>
20 
21 ATOMSMATH_INTERNAL_NAMESPACE_HEADER_ENTER
22 
23 #if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
24 // Disable MS VC++ warnings about conversion from double to float
25 # pragma warning(disable : 4244)
26 #endif
27 
116 
117 template <class T> class Euler : public Vec3<T>
118 {
119  public:
120  using Vec3<T>::x;
121  using Vec3<T>::y;
122  using Vec3<T>::z;
123 
124 
128  enum Order
129  {
130  XYZ = 0x0101, // "usual" orderings
131  XZY = 0x0001,
132  YZX = 0x1101,
133  YXZ = 0x1001,
134  ZXY = 0x2101,
135  ZYX = 0x2001,
136 
137  XZX = 0x0011, // first axis repeated
138  XYX = 0x0111,
139  YXY = 0x1011,
140  YZY = 0x1111,
141  ZYZ = 0x2011,
142  ZXZ = 0x2111,
143 
144  XYZr = 0x2000, // relative orderings -- not common
145  XZYr = 0x2100,
146  YZXr = 0x1000,
147  YXZr = 0x1100,
148  ZXYr = 0x0000,
149  ZYXr = 0x0100,
150 
151  XZXr = 0x2110, // relative first axis repeated
152  XYXr = 0x2010,
153  YXYr = 0x1110,
154  YZYr = 0x1010,
155  ZYZr = 0x0110,
156  ZXZr = 0x0010,
157  // ||||
158  // VVVV
159  // ABCD
160  // Legend:
161  // A -> Initial Axis (0==x, 1==y, 2==z)
162  // B -> Parity Even (1==true)
163  // C -> Initial Repeated (1==true)
164  // D -> Frame Static (1==true)
165  //
166 
167  Legal = XYZ | XZY | YZX | YXZ | ZXY | ZYX | XZX | XYX | YXY | YZY | ZYZ | ZXZ | XYZr |
168  XZYr | YZXr | YXZr | ZXYr | ZYXr | XZXr | XYXr | YXYr | YZYr | ZYZr | ZXZr,
169 
170  Min = 0x0000,
171  Max = 0x2111,
172  Default = XYZ
173  };
174 
178  enum Axis
179  {
180  X = 0,
181  Y = 1,
182  Z = 2
183  };
184 
188 
190  {
191  XYZLayout,
192  IJKLayout
193  };
194 
206 
208  ATOMSMATH_HOSTDEVICE constexpr Euler() noexcept;
209 
211  ATOMSMATH_HOSTDEVICE ATOMSMATH_CONSTEXPR14 Euler (const Euler&) noexcept;
212 
214  ATOMSMATH_HOSTDEVICE ATOMSMATH_CONSTEXPR14 Euler (Order p) noexcept;
215 
217  ATOMSMATH_HOSTDEVICE ATOMSMATH_CONSTEXPR14 Euler (const Vec3<T>& v,
218  Order o = Default,
219  InputLayout l = IJKLayout) noexcept;
221  ATOMSMATH_HOSTDEVICE ATOMSMATH_CONSTEXPR14
222  Euler (T i, T j, T k, Order o = Default, InputLayout l = IJKLayout) noexcept;
223 
225  ATOMSMATH_HOSTDEVICE ATOMSMATH_CONSTEXPR14 Euler (const Euler<T>& euler, Order newp) noexcept;
226 
228  ATOMSMATH_HOSTDEVICE ATOMSMATH_CONSTEXPR14 Euler (const Matrix33<T>&, Order o = Default) noexcept;
229 
231  ATOMSMATH_HOSTDEVICE ATOMSMATH_CONSTEXPR14 Euler (const Matrix44<T>&, Order o = Default) noexcept;
232 
234  ~Euler() = default;
235 
237 
240 
242  ATOMSMATH_HOSTDEVICE constexpr static bool legal (Order) noexcept;
243 
245  ATOMSMATH_HOSTDEVICE ATOMSMATH_CONSTEXPR14 Order order() const noexcept;
246 
248  ATOMSMATH_HOSTDEVICE constexpr bool frameStatic() const { return _frameStatic; }
249 
251  ATOMSMATH_HOSTDEVICE constexpr bool initialRepeated() const { return _initialRepeated; }
252 
254  ATOMSMATH_HOSTDEVICE constexpr bool parityEven() const { return _parityEven; }
255 
257  ATOMSMATH_HOSTDEVICE constexpr Axis initialAxis() const { return _initialAxis; }
258 
260  ATOMSMATH_HOSTDEVICE void angleOrder (int& i, int& j, int& k) const noexcept;
261 
263  ATOMSMATH_HOSTDEVICE void angleMapping (int& i, int& j, int& k) const noexcept;
264 
266 
269 
272  ATOMSMATH_HOSTDEVICE void setOrder (Order) noexcept;
273 
276  ATOMSMATH_HOSTDEVICE void setXYZVector (const Vec3<T>&) noexcept;
277 
279  ATOMSMATH_HOSTDEVICE void set (Axis initial, bool relative, bool parityEven, bool firstRepeats) noexcept;
280 
282 
286 
288  ATOMSMATH_HOSTDEVICE ATOMSMATH_CONSTEXPR14 const Euler<T>& operator= (const Euler<T>&) noexcept;
289 
291  ATOMSMATH_HOSTDEVICE ATOMSMATH_CONSTEXPR14 const Euler<T>& operator= (const Vec3<T>&) noexcept;
292 
294  ATOMSMATH_HOSTDEVICE void extract (const Matrix33<T>&) noexcept;
295 
297  ATOMSMATH_HOSTDEVICE void extract (const Matrix44<T>&) noexcept;
298 
300  ATOMSMATH_HOSTDEVICE void extract (const Quat<T>&) noexcept;
301 
303  ATOMSMATH_HOSTDEVICE Matrix33<T> toMatrix33() const noexcept;
304 
306  ATOMSMATH_HOSTDEVICE Matrix44<T> toMatrix44() const noexcept;
307 
309  ATOMSMATH_HOSTDEVICE Quat<T> toQuat() const noexcept;
310 
314  ATOMSMATH_HOSTDEVICE Vec3<T> toXYZVector() const noexcept;
315 
317 
324 
326  ATOMSMATH_HOSTDEVICE ATOMSMATH_CONSTEXPR14 static float angleMod (T angle) noexcept;
327 
329  ATOMSMATH_HOSTDEVICE static void simpleXYZRotation (Vec3<T>& xyzRot, const Vec3<T>& targetXyzRot) noexcept;
330 
333  ATOMSMATH_HOSTDEVICE static void
334  nearestRotation (Vec3<T>& xyzRot, const Vec3<T>& targetXyzRot, Order order = XYZ) noexcept;
335 
340  ATOMSMATH_HOSTDEVICE void makeNear (const Euler<T>& target) noexcept;
341 
343 
344  protected:
345 
347  bool _frameStatic : 1;
348 
350  bool _initialRepeated : 1;
351 
353  bool _parityEven : 1;
354 
355 #if defined _WIN32 || defined _WIN64
358 #else
361 #endif
362 };
363 
364 //
365 // Convenient typedefs
366 //
367 
369 typedef Euler<float> Eulerf;
371 typedef Euler<double> Eulerd;
372 
373 //
374 // Implementation
375 //
376 
378 
379 template <class T>
380 inline void
381 Euler<T>::angleOrder (int& i, int& j, int& k) const noexcept
382 {
383  i = _initialAxis;
384  j = _parityEven ? (i + 1) % 3 : (i > 0 ? i - 1 : 2);
385  k = _parityEven ? (i > 0 ? i - 1 : 2) : (i + 1) % 3;
386 }
387 
388 template <class T>
389 inline void
390 Euler<T>::angleMapping (int& i, int& j, int& k) const noexcept
391 {
392  int m[3];
393 
394  m[_initialAxis] = 0;
395  m[(_initialAxis + 1) % 3] = _parityEven ? 1 : 2;
396  m[(_initialAxis + 2) % 3] = _parityEven ? 2 : 1;
397  i = m[0];
398  j = m[1];
399  k = m[2];
400 }
401 
402 template <class T>
403 inline void
404 Euler<T>::setXYZVector (const Vec3<T>& v) noexcept
405 {
406  int i, j, k;
407  angleMapping (i, j, k);
408  (*this)[i] = v.x;
409  (*this)[j] = v.y;
410  (*this)[k] = v.z;
411 }
412 
413 template <class T>
414 inline Vec3<T>
415 Euler<T>::toXYZVector() const noexcept
416 {
417  int i, j, k;
418  angleMapping (i, j, k);
419  return Vec3<T> ((*this)[i], (*this)[j], (*this)[k]);
420 }
421 
422 template <class T>
423 constexpr inline Euler<T>::Euler() noexcept
424  : Vec3<T> (0, 0, 0),
425  _frameStatic (true),
426  _initialRepeated (false),
427  _parityEven (true),
428  _initialAxis (X)
429 {}
430 
431 template <class T>
432 ATOMSMATH_CONSTEXPR14 inline Euler<T>::Euler (typename Euler<T>::Order p) noexcept
433  : Vec3<T> (0, 0, 0),
434  _frameStatic (true),
435  _initialRepeated (false),
436  _parityEven (true),
437  _initialAxis (X)
438 {
439  setOrder (p);
440 }
441 
442 template <class T>
443 ATOMSMATH_CONSTEXPR14 inline Euler<T>::Euler (const Vec3<T>& v,
444  typename Euler<T>::Order p,
445  typename Euler<T>::InputLayout l) noexcept
446 {
447  setOrder (p);
448  if (l == XYZLayout)
449  setXYZVector (v);
450  else
451  {
452  x = v.x;
453  y = v.y;
454  z = v.z;
455  }
456 }
457 
458 template <class T> ATOMSMATH_CONSTEXPR14 inline Euler<T>::Euler (const Euler<T>& euler) noexcept
459 {
460  operator= (euler);
461 }
462 
463 template <class T> ATOMSMATH_CONSTEXPR14 inline Euler<T>::Euler (const Euler<T>& euler, Order p) noexcept
464 {
465  setOrder (p);
466  Matrix33<T> M = euler.toMatrix33();
467  extract (M);
468 }
469 
470 template <class T>
471 ATOMSMATH_CONSTEXPR14 inline Euler<T>::Euler (T xi,
472  T yi,
473  T zi,
474  typename Euler<T>::Order p,
475  typename Euler<T>::InputLayout l) noexcept
476 {
477  setOrder (p);
478  if (l == XYZLayout)
479  setXYZVector (Vec3<T> (xi, yi, zi));
480  else
481  {
482  x = xi;
483  y = yi;
484  z = zi;
485  }
486 }
487 
488 template <class T>
489 ATOMSMATH_CONSTEXPR14 inline Euler<T>::Euler (const Matrix33<T>& M, typename Euler::Order p) noexcept
490 {
491  setOrder (p);
492  extract (M);
493 }
494 
495 template <class T>
496 ATOMSMATH_CONSTEXPR14 inline Euler<T>::Euler (const Matrix44<T>& M, typename Euler::Order p) noexcept
497 {
498  setOrder (p);
499  extract (M);
500 }
501 
502 template <class T>
503 inline void
504 Euler<T>::extract (const Quat<T>& q) noexcept
505 {
506  extract (q.toMatrix33());
507 }
508 
509 template <class T>
510 void
511 Euler<T>::extract (const Matrix33<T>& M) noexcept
512 {
513  int i, j, k;
514  angleOrder (i, j, k);
515 
516  if (_initialRepeated)
517  {
518  //
519  // Extract the first angle, x.
520  //
521 
522  x = std::atan2 (M[j][i], M[k][i]);
523 
524  //
525  // Remove the x rotation from M, so that the remaining
526  // rotation, N, is only around two axes, and gimbal lock
527  // cannot occur.
528  //
529 
530  Vec3<T> r (0, 0, 0);
531  r[i] = (_parityEven ? -x : x);
532 
533  Matrix44<T> N;
534  N.rotate (r);
535 
536  N = N * Matrix44<T> (M[0][0],
537  M[0][1],
538  M[0][2],
539  0,
540  M[1][0],
541  M[1][1],
542  M[1][2],
543  0,
544  M[2][0],
545  M[2][1],
546  M[2][2],
547  0,
548  0,
549  0,
550  0,
551  1);
552  //
553  // Extract the other two angles, y and z, from N.
554  //
555 
556  T sy = std::sqrt (N[j][i] * N[j][i] + N[k][i] * N[k][i]);
557  y = std::atan2 (sy, N[i][i]);
558  z = std::atan2 (N[j][k], N[j][j]);
559  }
560  else
561  {
562  //
563  // Extract the first angle, x.
564  //
565 
566  x = std::atan2 (M[j][k], M[k][k]);
567 
568  //
569  // Remove the x rotation from M, so that the remaining
570  // rotation, N, is only around two axes, and gimbal lock
571  // cannot occur.
572  //
573 
574  Vec3<T> r (0, 0, 0);
575  r[i] = (_parityEven ? -x : x);
576 
577  Matrix44<T> N;
578  N.rotate (r);
579 
580  N = N * Matrix44<T> (M[0][0],
581  M[0][1],
582  M[0][2],
583  0,
584  M[1][0],
585  M[1][1],
586  M[1][2],
587  0,
588  M[2][0],
589  M[2][1],
590  M[2][2],
591  0,
592  0,
593  0,
594  0,
595  1);
596  //
597  // Extract the other two angles, y and z, from N.
598  //
599 
600  T cy = std::sqrt (N[i][i] * N[i][i] + N[i][j] * N[i][j]);
601  y = std::atan2 (-N[i][k], cy);
602  z = std::atan2 (-N[j][i], N[j][j]);
603  }
604 
605  if (!_parityEven)
606  *this *= -1;
607 
608  if (!_frameStatic)
609  {
610  T t = x;
611  x = z;
612  z = t;
613  }
614 }
615 
616 template <class T>
617 void
618 Euler<T>::extract (const Matrix44<T>& M) noexcept
619 {
620  int i, j, k;
621  angleOrder (i, j, k);
622 
623  if (_initialRepeated)
624  {
625  //
626  // Extract the first angle, x.
627  //
628 
629  x = std::atan2 (M[j][i], M[k][i]);
630 
631  //
632  // Remove the x rotation from M, so that the remaining
633  // rotation, N, is only around two axes, and gimbal lock
634  // cannot occur.
635  //
636 
637  Vec3<T> r (0, 0, 0);
638  r[i] = (_parityEven ? -x : x);
639 
640  Matrix44<T> N;
641  N.rotate (r);
642  N = N * M;
643 
644  //
645  // Extract the other two angles, y and z, from N.
646  //
647 
648  T sy = std::sqrt (N[j][i] * N[j][i] + N[k][i] * N[k][i]);
649  y = std::atan2 (sy, N[i][i]);
650  z = std::atan2 (N[j][k], N[j][j]);
651  }
652  else
653  {
654  //
655  // Extract the first angle, x.
656  //
657 
658  x = std::atan2 (M[j][k], M[k][k]);
659 
660  //
661  // Remove the x rotation from M, so that the remaining
662  // rotation, N, is only around two axes, and gimbal lock
663  // cannot occur.
664  //
665 
666  Vec3<T> r (0, 0, 0);
667  r[i] = (_parityEven ? -x : x);
668 
669  Matrix44<T> N;
670  N.rotate (r);
671  N = N * M;
672 
673  //
674  // Extract the other two angles, y and z, from N.
675  //
676 
677  T cy = std::sqrt (N[i][i] * N[i][i] + N[i][j] * N[i][j]);
678  y = std::atan2 (-N[i][k], cy);
679  z = std::atan2 (-N[j][i], N[j][j]);
680  }
681 
682  if (!_parityEven)
683  *this *= -1;
684 
685  if (!_frameStatic)
686  {
687  T t = x;
688  x = z;
689  z = t;
690  }
691 }
692 
693 template <class T>
695 Euler<T>::toMatrix33() const noexcept
696 {
697  int i, j, k;
698  angleOrder (i, j, k);
699 
700  Vec3<T> angles;
701 
702  if (_frameStatic)
703  angles = (*this);
704  else
705  angles = Vec3<T> (z, y, x);
706 
707  if (!_parityEven)
708  angles *= -1.0;
709 
710  T ci = std::cos (angles.x);
711  T cj = std::cos (angles.y);
712  T ch = std::cos (angles.z);
713  T si = std::sin (angles.x);
714  T sj = std::sin (angles.y);
715  T sh = std::sin (angles.z);
716 
717  T cc = ci * ch;
718  T cs = ci * sh;
719  T sc = si * ch;
720  T ss = si * sh;
721 
722  Matrix33<T> M;
723 
724  if (_initialRepeated)
725  {
726  M[i][i] = cj;
727  M[j][i] = sj * si;
728  M[k][i] = sj * ci;
729  M[i][j] = sj * sh;
730  M[j][j] = -cj * ss + cc;
731  M[k][j] = -cj * cs - sc;
732  M[i][k] = -sj * ch;
733  M[j][k] = cj * sc + cs;
734  M[k][k] = cj * cc - ss;
735  }
736  else
737  {
738  M[i][i] = cj * ch;
739  M[j][i] = sj * sc - cs;
740  M[k][i] = sj * cc + ss;
741  M[i][j] = cj * sh;
742  M[j][j] = sj * ss + cc;
743  M[k][j] = sj * cs - sc;
744  M[i][k] = -sj;
745  M[j][k] = cj * si;
746  M[k][k] = cj * ci;
747  }
748 
749  return M;
750 }
751 
752 template <class T>
754 Euler<T>::toMatrix44() const noexcept
755 {
756  int i, j, k;
757  angleOrder (i, j, k);
758 
759  Vec3<T> angles;
760 
761  if (_frameStatic)
762  angles = (*this);
763  else
764  angles = Vec3<T> (z, y, x);
765 
766  if (!_parityEven)
767  angles *= -1.0;
768 
769  T ci = std::cos (angles.x);
770  T cj = std::cos (angles.y);
771  T ch = std::cos (angles.z);
772  T si = std::sin (angles.x);
773  T sj = std::sin (angles.y);
774  T sh = std::sin (angles.z);
775 
776  T cc = ci * ch;
777  T cs = ci * sh;
778  T sc = si * ch;
779  T ss = si * sh;
780 
781  Matrix44<T> M;
782 
783  if (_initialRepeated)
784  {
785  M[i][i] = cj;
786  M[j][i] = sj * si;
787  M[k][i] = sj * ci;
788  M[i][j] = sj * sh;
789  M[j][j] = -cj * ss + cc;
790  M[k][j] = -cj * cs - sc;
791  M[i][k] = -sj * ch;
792  M[j][k] = cj * sc + cs;
793  M[k][k] = cj * cc - ss;
794  }
795  else
796  {
797  M[i][i] = cj * ch;
798  M[j][i] = sj * sc - cs;
799  M[k][i] = sj * cc + ss;
800  M[i][j] = cj * sh;
801  M[j][j] = sj * ss + cc;
802  M[k][j] = sj * cs - sc;
803  M[i][k] = -sj;
804  M[j][k] = cj * si;
805  M[k][k] = cj * ci;
806  }
807 
808  return M;
809 }
810 
811 template <class T>
812 Quat<T>
813 Euler<T>::toQuat() const noexcept
814 {
815  Vec3<T> angles;
816  int i, j, k;
817  angleOrder (i, j, k);
818 
819  if (_frameStatic)
820  angles = (*this);
821  else
822  angles = Vec3<T> (z, y, x);
823 
824  if (!_parityEven)
825  angles.y = -angles.y;
826 
827  T ti = angles.x * 0.5;
828  T tj = angles.y * 0.5;
829  T th = angles.z * 0.5;
830  T ci = std::cos (ti);
831  T cj = std::cos (tj);
832  T ch = std::cos (th);
833  T si = std::sin (ti);
834  T sj = std::sin (tj);
835  T sh = std::sin (th);
836  T cc = ci * ch;
837  T cs = ci * sh;
838  T sc = si * ch;
839  T ss = si * sh;
840 
841  T parity = _parityEven ? 1.0 : -1.0;
842 
843  Quat<T> q;
844  Vec3<T> a;
845 
846  if (_initialRepeated)
847  {
848  a[i] = cj * (cs + sc);
849  a[j] = sj * (cc + ss) * parity, // NOSONAR - suppress SonarCloud bug report.
850  a[k] = sj * (cs - sc);
851  q.r = cj * (cc - ss);
852  }
853  else
854  {
855  a[i] = cj * sc - sj * cs,
856  a[j] = (cj * ss + sj * cc) * parity, // NOSONAR - suppress SonarCloud bug report.
857  a[k] = cj * cs - sj * sc;
858  q.r = cj * cc + sj * ss;
859  }
860 
861  q.v = a;
862 
863  return q;
864 }
865 
866 template <class T>
867 constexpr inline bool
868 Euler<T>::legal (typename Euler<T>::Order order) noexcept
869 {
870  return (order & ~Legal) ? false : true;
871 }
872 
873 template <class T>
874 ATOMSMATH_CONSTEXPR14 typename Euler<T>::Order
875 Euler<T>::order() const noexcept
876 {
877  int foo = (_initialAxis == Z ? 0x2000 : (_initialAxis == Y ? 0x1000 : 0));
878 
879  if (_parityEven)
880  foo |= 0x0100;
881  if (_initialRepeated)
882  foo |= 0x0010;
883  if (_frameStatic)
884  foo++;
885 
886  return (Order) foo;
887 }
888 
889 template <class T>
890 inline void
891 Euler<T>::setOrder (typename Euler<T>::Order p) noexcept
892 {
893  set (p & 0x2000 ? Z : (p & 0x1000 ? Y : X), // initial axis
894  !(p & 0x1), // static?
895  !!(p & 0x100), // permutation even?
896  !!(p & 0x10)); // initial repeats?
897 }
898 
899 template <class T>
900 inline void
901 Euler<T>::set (typename Euler<T>::Axis axis, bool relative, bool parityEven, bool firstRepeats) noexcept
902 {
903  _initialAxis = axis;
904  _frameStatic = !relative;
905  _parityEven = parityEven;
906  _initialRepeated = firstRepeats;
907 }
908 
909 template <class T>
910 ATOMSMATH_CONSTEXPR14 inline const Euler<T>&
911 Euler<T>::operator= (const Euler<T>& euler) noexcept
912 {
913  x = euler.x;
914  y = euler.y;
915  z = euler.z;
916  _initialAxis = euler._initialAxis;
917  _frameStatic = euler._frameStatic;
918  _parityEven = euler._parityEven;
919  _initialRepeated = euler._initialRepeated;
920  return *this;
921 }
922 
923 template <class T>
924 ATOMSMATH_CONSTEXPR14 inline const Euler<T>&
925 Euler<T>::operator= (const Vec3<T>& v) noexcept
926 {
927  x = v.x;
928  y = v.y;
929  z = v.z;
930  return *this;
931 }
932 
934 template <class T>
935 std::ostream&
936 operator<< (std::ostream& o, const Euler<T>& euler) noexcept
937 {
938  char a[3] = { 'X', 'Y', 'Z' };
939 
940  const char* r = euler.frameStatic() ? "" : "r";
941  int i, j, k;
942  euler.angleOrder (i, j, k);
943 
944  if (euler.initialRepeated())
945  k = i;
946 
947  return o << "(" << euler.x << ", " << euler.y << ", " << euler.z << ", " << a[i] << a[j] << a[k]
948  << r << ")";
949 }
950 
951 template <class T>
952 ATOMSMATH_CONSTEXPR14 inline float
953 Euler<T>::angleMod (T angle) noexcept
954 {
955  const T pi = static_cast<T> (M_PI);
956  angle = fmod (T (angle), T (2 * pi));
957 
958  if (angle < -pi)
959  angle += 2 * pi;
960  if (angle > +pi)
961  angle -= 2 * pi;
962 
963  return angle;
964 }
965 
966 template <class T>
967 inline void
968 Euler<T>::simpleXYZRotation (Vec3<T>& xyzRot, const Vec3<T>& targetXyzRot) noexcept
969 {
970  Vec3<T> d = xyzRot - targetXyzRot;
971  xyzRot[0] = targetXyzRot[0] + angleMod (d[0]);
972  xyzRot[1] = targetXyzRot[1] + angleMod (d[1]);
973  xyzRot[2] = targetXyzRot[2] + angleMod (d[2]);
974 }
975 
976 template <class T>
977 void
978 Euler<T>::nearestRotation (Vec3<T>& xyzRot, const Vec3<T>& targetXyzRot, Order order) noexcept
979 {
980  int i, j, k;
981  Euler<T> e (0, 0, 0, order);
982  e.angleOrder (i, j, k);
983 
984  simpleXYZRotation (xyzRot, targetXyzRot);
985 
986  Vec3<T> otherXyzRot;
987  otherXyzRot[i] = M_PI + xyzRot[i];
988  otherXyzRot[j] = M_PI - xyzRot[j];
989  otherXyzRot[k] = M_PI + xyzRot[k];
990 
991  simpleXYZRotation (otherXyzRot, targetXyzRot);
992 
993  Vec3<T> d = xyzRot - targetXyzRot;
994  Vec3<T> od = otherXyzRot - targetXyzRot;
995  T dMag = d.dot (d);
996  T odMag = od.dot (od);
997 
998  if (odMag < dMag)
999  {
1000  xyzRot = otherXyzRot;
1001  }
1002 }
1003 
1004 template <class T>
1005 void
1006 Euler<T>::makeNear (const Euler<T>& target) noexcept
1007 {
1008  Vec3<T> xyzRot = toXYZVector();
1009  Vec3<T> targetXyz;
1010  if (order() != target.order())
1011  {
1012  Euler<T> targetSameOrder = Euler<T> (target, order());
1013  targetXyz = targetSameOrder.toXYZVector();
1014  }
1015  else
1016  {
1017  targetXyz = target.toXYZVector();
1018  }
1019 
1020  nearestRotation (xyzRot, targetXyz, order());
1021 
1022  setXYZVector (xyzRot);
1023 }
1024 
1025 #if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
1026 # pragma warning(default : 4244)
1027 #endif
1028 
1030 
1031 ATOMSMATH_INTERNAL_NAMESPACE_HEADER_EXIT
1032 
1033 #endif // INCLUDED_ATOMSMATHEULER_H
Definition: ImathEuler.h:118
static ATOMSMATH_HOSTDEVICE void nearestRotation(Vec3< T > &xyzRot, const Vec3< T > &targetXyzRot, Order order=XYZ) noexcept
ATOMSMATH_HOSTDEVICE ATOMSMATH_CONSTEXPR14 Order order() const noexcept
Return the order.
constexpr ATOMSMATH_HOSTDEVICE Euler() noexcept
No initialization by default.
constexpr ATOMSMATH_HOSTDEVICE bool frameStatic() const
Return frameStatic.
Definition: ImathEuler.h:248
ATOMSMATH_HOSTDEVICE ATOMSMATH_CONSTEXPR14 const Euler< T > & operator=(const Euler< T > &) noexcept
Assignment.
Order
Definition: ImathEuler.h:129
InputLayout
Definition: ImathEuler.h:190
Axis _initialAxis
First axis of rotation.
Definition: ImathEuler.h:360
constexpr ATOMSMATH_HOSTDEVICE bool parityEven() const
Return partityEven.
Definition: ImathEuler.h:254
ATOMSMATH_HOSTDEVICE void set(Axis initial, bool relative, bool parityEven, bool firstRepeats) noexcept
Set the value.
ATOMSMATH_HOSTDEVICE void extract(const Quat< T > &) noexcept
Assign from Quaternion.
ATOMSMATH_HOSTDEVICE void setOrder(Order) noexcept
bool _parityEven
"parity of axis permutation"
Definition: ImathEuler.h:353
static ATOMSMATH_HOSTDEVICE void simpleXYZRotation(Vec3< T > &xyzRot, const Vec3< T > &targetXyzRot) noexcept
Adjust xyzRot so that its components differ from targetXyzRot by no more than +/-PI.
constexpr ATOMSMATH_HOSTDEVICE bool initialRepeated() const
Return intialRepeated.
Definition: ImathEuler.h:251
bool _frameStatic
relative or static rotations
Definition: ImathEuler.h:347
ATOMSMATH_HOSTDEVICE void angleOrder(int &i, int &j, int &k) const noexcept
Unpack angles from ijk form.
ATOMSMATH_HOSTDEVICE void makeNear(const Euler< T > &target) noexcept
ATOMSMATH_HOSTDEVICE Vec3< T > toXYZVector() const noexcept
Axis
Definition: ImathEuler.h:179
ATOMSMATH_HOSTDEVICE Quat< T > toQuat() const noexcept
Convert to Quat.
ATOMSMATH_HOSTDEVICE void angleMapping(int &i, int &j, int &k) const noexcept
Determine mapping from xyz to ijk (reshuffle the xyz to match the order)
ATOMSMATH_HOSTDEVICE Matrix44< T > toMatrix44() const noexcept
Convert to Matrix44.
ATOMSMATH_HOSTDEVICE static ATOMSMATH_CONSTEXPR14 float angleMod(T angle) noexcept
Convert an angle to its equivalent in [-PI, PI].
ATOMSMATH_HOSTDEVICE void extract(const Matrix44< T > &) noexcept
Assign from Matrix44, assumed to be affine.
ATOMSMATH_HOSTDEVICE void setXYZVector(const Vec3< T > &) noexcept
ATOMSMATH_HOSTDEVICE Matrix33< T > toMatrix33() const noexcept
Convert to Matrix33.
ATOMSMATH_HOSTDEVICE void extract(const Matrix33< T > &) noexcept
Assign from Matrix33, assumed to be affine.
bool _initialRepeated
init axis repeated as last
Definition: ImathEuler.h:350
constexpr ATOMSMATH_HOSTDEVICE Axis initialAxis() const
Return initialAxis.
Definition: ImathEuler.h:257
constexpr static ATOMSMATH_HOSTDEVICE bool legal(Order) noexcept
Return whether the given value is a legal Order.
Definition: ImathMatrix.h:305
Definition: ImathMatrix.h:631
ATOMSMATH_HOSTDEVICE const Matrix44 & rotate(const Vec3< S > &r) noexcept
Definition: ImathQuat.h:41
Vec3< T > v
The imaginary vector.
Definition: ImathQuat.h:51
T r
The real part.
Definition: ImathQuat.h:48
Definition: ImathVec.h:260
constexpr ATOMSMATH_HOSTDEVICE T dot(const Vec3 &v) const noexcept
Dot product.
Definition: ImathVec.h:1370