| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951 |
- //
- // SPDX-License-Identifier: BSD-3-Clause
- // Copyright Contributors to the OpenEXR Project.
- //
- //
- // A quaternion
- //
- // "Quaternions came from Hamilton ... and have been an unmixed
- // evil to those who have touched them in any way. Vector is a
- // useless survival ... and has never been of the slightest use
- // to any creature."
- //
- // - Lord Kelvin
- //
- #ifndef INCLUDED_IMATHQUAT_H
- #define INCLUDED_IMATHQUAT_H
- #include "ImathExport.h"
- #include "ImathNamespace.h"
- #include "ImathMatrix.h"
- #include <iostream>
- IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
- #if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
- // Disable MS VC++ warnings about conversion from double to float
- # pragma warning(push)
- # pragma warning(disable : 4244)
- #endif
- ///
- /// The Quat class implements the quaternion numerical type -- you
- /// will probably want to use this class to represent orientations
- /// in R3 and to convert between various euler angle reps. You
- /// should probably use Imath::Euler<> for that.
- ///
- template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Quat
- {
- public:
- /// @{
- /// @name Direct access to elements
-
- /// The real part
- T r;
- /// The imaginary vector
- Vec3<T> v;
- /// @}
- /// Element access: q[0] is the real part, (q[1],q[2],q[3]) is the
- /// imaginary part.
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T& operator[] (int index) IMATH_NOEXCEPT; // as 4D vector
- /// Element access: q[0] is the real part, (q[1],q[2],q[3]) is the
- /// imaginary part.
- IMATH_HOSTDEVICE constexpr T operator[] (int index) const IMATH_NOEXCEPT;
- /// @{
- /// @name Constructors
- /// Default constructor is the identity quat
- IMATH_HOSTDEVICE constexpr Quat() IMATH_NOEXCEPT;
- /// Copy constructor
- IMATH_HOSTDEVICE constexpr Quat (const Quat& q) IMATH_NOEXCEPT;
- /// Construct from a quaternion of a another base type
- template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat (const Quat<S>& q) IMATH_NOEXCEPT;
- /// Initialize with real part `s` and imaginary vector 1(i,j,k)`
- IMATH_HOSTDEVICE constexpr Quat (T s, T i, T j, T k) IMATH_NOEXCEPT;
- /// Initialize with real part `s` and imaginary vector `d`
- IMATH_HOSTDEVICE constexpr Quat (T s, Vec3<T> d) IMATH_NOEXCEPT;
- /// The identity quaternion
- IMATH_HOSTDEVICE constexpr static Quat<T> identity() IMATH_NOEXCEPT;
- /// Assignment
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Quat<T>& operator= (const Quat<T>& q) IMATH_NOEXCEPT;
- /// Destructor
- ~Quat () IMATH_NOEXCEPT = default;
- /// @}
- /// @{
- /// @name Basic Algebra
- ///
- /// Note that the operator return values are *NOT* normalized
- //
- /// Quaternion multiplication
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Quat<T>& operator*= (const Quat<T>& q) IMATH_NOEXCEPT;
-
- /// Scalar multiplication: multiply both real and imaginary parts
- /// by the given scalar.
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Quat<T>& operator*= (T t) IMATH_NOEXCEPT;
- /// Quaterion division, using the inverse()
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Quat<T>& operator/= (const Quat<T>& q) IMATH_NOEXCEPT;
- /// Scalar division: multiply both real and imaginary parts
- /// by the given scalar.
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Quat<T>& operator/= (T t) IMATH_NOEXCEPT;
- /// Quaternion addition
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Quat<T>& operator+= (const Quat<T>& q) IMATH_NOEXCEPT;
- /// Quaternion subtraction
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Quat<T>& operator-= (const Quat<T>& q) IMATH_NOEXCEPT;
- /// Equality
- template <class S> IMATH_HOSTDEVICE constexpr bool operator== (const Quat<S>& q) const IMATH_NOEXCEPT;
- /// Inequality
- template <class S> IMATH_HOSTDEVICE constexpr bool operator!= (const Quat<S>& q) const IMATH_NOEXCEPT;
- /// @}
- /// @{
- /// @name Query
-
- /// Return the R4 length
- IMATH_HOSTDEVICE constexpr T length() const IMATH_NOEXCEPT; // in R4
- /// Return the angle of the axis/angle representation
- IMATH_HOSTDEVICE constexpr T angle() const IMATH_NOEXCEPT;
- /// Return the axis of the axis/angle representation
- IMATH_HOSTDEVICE constexpr Vec3<T> axis() const IMATH_NOEXCEPT;
- /// Return a 3x3 rotation matrix
- IMATH_HOSTDEVICE constexpr Matrix33<T> toMatrix33() const IMATH_NOEXCEPT;
- /// Return a 4x4 rotation matrix
- IMATH_HOSTDEVICE constexpr Matrix44<T> toMatrix44() const IMATH_NOEXCEPT;
- /// Return the logarithm of the quaterion
- IMATH_HOSTDEVICE Quat<T> log() const IMATH_NOEXCEPT;
- /// Return the exponent of the quaterion
- IMATH_HOSTDEVICE Quat<T> exp() const IMATH_NOEXCEPT;
- /// @}
- /// @{
- /// @name Utility Methods
-
- /// Invert in place: this = 1 / this.
- /// @return const reference to this.
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat<T>& invert() IMATH_NOEXCEPT;
- /// Return 1/this, leaving this unchanged.
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat<T> inverse() const IMATH_NOEXCEPT;
- /// Normalize in place
- /// @return const reference to this.
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat<T>& normalize() IMATH_NOEXCEPT;
-
- /// Return a normalized quaternion, leaving this unmodified.
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat<T> normalized() const IMATH_NOEXCEPT;
- /// Rotate the given point by the quaterion.
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec3<T> rotateVector (const Vec3<T>& original) const IMATH_NOEXCEPT;
- /// Return the Euclidean inner product.
- IMATH_HOSTDEVICE constexpr T euclideanInnerProduct (const Quat<T>& q) const IMATH_NOEXCEPT;
- /// Set the quaterion to be a rotation around the given axis by the
- /// given angle.
- /// @return const reference to this.
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat<T>& setAxisAngle (const Vec3<T>& axis, T radians) IMATH_NOEXCEPT;
- /// Set the quaternion to be a rotation that transforms the
- /// direction vector `fromDirection` to `toDirection`
- /// @return const reference to this.
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat<T>&
- setRotation (const Vec3<T>& fromDirection, const Vec3<T>& toDirection) IMATH_NOEXCEPT;
- /// @}
-
- /// The base type: In templates that accept a parameter `V`, you
- /// can refer to `T` as `V::BaseType`
- typedef T BaseType;
- private:
- IMATH_HOSTDEVICE void setRotationInternal (const Vec3<T>& f0, const Vec3<T>& t0, Quat<T>& q) IMATH_NOEXCEPT;
- };
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat<T> slerp (const Quat<T>& q1, const Quat<T>& q2, T t) IMATH_NOEXCEPT;
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat<T> slerpShortestArc (const Quat<T>& q1, const Quat<T>& q2, T t) IMATH_NOEXCEPT;
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Quat<T>
- squad (const Quat<T>& q1, const Quat<T>& q2, const Quat<T>& qa, const Quat<T>& qb, T t) IMATH_NOEXCEPT;
- ///
- /// From advanced Animation and Rendering Techniques by Watt and Watt,
- /// Page 366:
- ///
- /// computing the inner quadrangle points (qa and qb) to guarantee
- /// tangent continuity.
- template <class T>
- IMATH_HOSTDEVICE void intermediate (const Quat<T>& q0,
- const Quat<T>& q1,
- const Quat<T>& q2,
- const Quat<T>& q3,
- Quat<T>& qa,
- Quat<T>& qb) IMATH_NOEXCEPT;
- template <class T>
- IMATH_HOSTDEVICE constexpr Matrix33<T> operator* (const Matrix33<T>& M, const Quat<T>& q) IMATH_NOEXCEPT;
- template <class T>
- IMATH_HOSTDEVICE constexpr Matrix33<T> operator* (const Quat<T>& q, const Matrix33<T>& M) IMATH_NOEXCEPT;
- template <class T> std::ostream& operator<< (std::ostream& o, const Quat<T>& q);
- template <class T>
- IMATH_HOSTDEVICE constexpr Quat<T> operator* (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT;
- template <class T>
- IMATH_HOSTDEVICE constexpr Quat<T> operator/ (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT;
- template <class T>
- IMATH_HOSTDEVICE constexpr Quat<T> operator/ (const Quat<T>& q, T t) IMATH_NOEXCEPT;
- template <class T>
- IMATH_HOSTDEVICE constexpr Quat<T> operator* (const Quat<T>& q, T t) IMATH_NOEXCEPT;
- template <class T>
- IMATH_HOSTDEVICE constexpr Quat<T> operator* (T t, const Quat<T>& q) IMATH_NOEXCEPT;
- template <class T>
- IMATH_HOSTDEVICE constexpr Quat<T> operator+ (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT;
- template <class T>
- IMATH_HOSTDEVICE constexpr Quat<T> operator- (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT;
- template <class T>
- IMATH_HOSTDEVICE constexpr Quat<T> operator~ (const Quat<T>& q) IMATH_NOEXCEPT;
- template <class T>
- IMATH_HOSTDEVICE constexpr Quat<T> operator- (const Quat<T>& q) IMATH_NOEXCEPT;
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec3<T> operator* (const Vec3<T>& v, const Quat<T>& q) IMATH_NOEXCEPT;
- /// Quaternion of type float
- typedef Quat<float> Quatf;
- /// Quaternion of type double
- typedef Quat<double> Quatd;
- //---------------
- // Implementation
- //---------------
- template <class T>
- IMATH_HOSTDEVICE constexpr inline Quat<T>::Quat() IMATH_NOEXCEPT : r (1), v (0, 0, 0)
- {
- // empty
- }
- template <class T>
- template <class S>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>::Quat (const Quat<S>& q) IMATH_NOEXCEPT : r (q.r), v (q.v)
- {
- // empty
- }
- template <class T>
- IMATH_HOSTDEVICE constexpr inline Quat<T>::Quat (T s, T i, T j, T k) IMATH_NOEXCEPT : r (s), v (i, j, k)
- {
- // empty
- }
- template <class T>
- IMATH_HOSTDEVICE constexpr inline Quat<T>::Quat (T s, Vec3<T> d) IMATH_NOEXCEPT : r (s), v (d)
- {
- // empty
- }
- template <class T>
- IMATH_HOSTDEVICE constexpr inline Quat<T>::Quat (const Quat<T>& q) IMATH_NOEXCEPT : r (q.r), v (q.v)
- {
- // empty
- }
- template <class T>
- IMATH_HOSTDEVICE constexpr inline Quat<T>
- Quat<T>::identity() IMATH_NOEXCEPT
- {
- return Quat<T>();
- }
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Quat<T>&
- Quat<T>::operator= (const Quat<T>& q) IMATH_NOEXCEPT
- {
- r = q.r;
- v = q.v;
- return *this;
- }
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Quat<T>&
- Quat<T>::operator*= (const Quat<T>& q) IMATH_NOEXCEPT
- {
- T rtmp = r * q.r - (v ^ q.v);
- v = r * q.v + v * q.r + v % q.v;
- r = rtmp;
- return *this;
- }
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Quat<T>&
- Quat<T>::operator*= (T t) IMATH_NOEXCEPT
- {
- r *= t;
- v *= t;
- return *this;
- }
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Quat<T>&
- Quat<T>::operator/= (const Quat<T>& q) IMATH_NOEXCEPT
- {
- *this = *this * q.inverse();
- return *this;
- }
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Quat<T>&
- Quat<T>::operator/= (T t) IMATH_NOEXCEPT
- {
- r /= t;
- v /= t;
- return *this;
- }
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Quat<T>&
- Quat<T>::operator+= (const Quat<T>& q) IMATH_NOEXCEPT
- {
- r += q.r;
- v += q.v;
- return *this;
- }
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Quat<T>&
- Quat<T>::operator-= (const Quat<T>& q) IMATH_NOEXCEPT
- {
- r -= q.r;
- v -= q.v;
- return *this;
- }
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T&
- Quat<T>::operator[] (int index) IMATH_NOEXCEPT
- {
- return index ? v[index - 1] : r;
- }
- template <class T>
- IMATH_HOSTDEVICE constexpr inline T
- Quat<T>::operator[] (int index) const IMATH_NOEXCEPT
- {
- return index ? v[index - 1] : r;
- }
- template <class T>
- template <class S>
- IMATH_HOSTDEVICE constexpr inline bool
- Quat<T>::operator== (const Quat<S>& q) const IMATH_NOEXCEPT
- {
- return r == q.r && v == q.v;
- }
- template <class T>
- template <class S>
- IMATH_HOSTDEVICE constexpr inline bool
- Quat<T>::operator!= (const Quat<S>& q) const IMATH_NOEXCEPT
- {
- return r != q.r || v != q.v;
- }
- /// 4D dot product
- template <class T>
- IMATH_HOSTDEVICE constexpr inline T
- operator^ (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT
- {
- return q1.r * q2.r + (q1.v ^ q2.v);
- }
- template <class T>
- IMATH_HOSTDEVICE constexpr inline T
- Quat<T>::length() const IMATH_NOEXCEPT
- {
- return std::sqrt (r * r + (v ^ v));
- }
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>&
- Quat<T>::normalize() IMATH_NOEXCEPT
- {
- if (T l = length())
- {
- r /= l;
- v /= l;
- }
- else
- {
- r = 1;
- v = Vec3<T> (0);
- }
- return *this;
- }
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>
- Quat<T>::normalized() const IMATH_NOEXCEPT
- {
- if (T l = length())
- return Quat (r / l, v / l);
- return Quat();
- }
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>
- Quat<T>::inverse() const IMATH_NOEXCEPT
- {
- //
- // 1 Q*
- // - = ---- where Q* is conjugate (operator~)
- // Q Q* Q and (Q* Q) == Q ^ Q (4D dot)
- //
- T qdot = *this ^ *this;
- return Quat (r / qdot, -v / qdot);
- }
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>&
- Quat<T>::invert() IMATH_NOEXCEPT
- {
- T qdot = (*this) ^ (*this);
- r /= qdot;
- v = -v / qdot;
- return *this;
- }
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Vec3<T>
- Quat<T>::rotateVector (const Vec3<T>& original) const IMATH_NOEXCEPT
- {
- //
- // Given a vector p and a quaternion q (aka this),
- // calculate p' = qpq*
- //
- // Assumes unit quaternions (because non-unit
- // quaternions cannot be used to rotate vectors
- // anyway).
- //
- Quat<T> vec (0, original); // temporarily promote grade of original
- Quat<T> inv (*this);
- inv.v *= -1; // unit multiplicative inverse
- Quat<T> result = *this * vec * inv;
- return result.v;
- }
- template <class T>
- IMATH_HOSTDEVICE constexpr inline T
- Quat<T>::euclideanInnerProduct (const Quat<T>& q) const IMATH_NOEXCEPT
- {
- return r * q.r + v.x * q.v.x + v.y * q.v.y + v.z * q.v.z;
- }
- ///
- /// Compute the angle between two quaternions,
- /// interpreting the quaternions as 4D vectors.
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T
- angle4D (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT
- {
- Quat<T> d = q1 - q2;
- T lengthD = std::sqrt (d ^ d);
- Quat<T> s = q1 + q2;
- T lengthS = std::sqrt (s ^ s);
- return 2 * std::atan2 (lengthD, lengthS);
- }
- ///
- /// Spherical linear interpolation.
- /// Assumes q1 and q2 are normalized and that q1 != -q2.
- ///
- /// This method does *not* interpolate along the shortest
- /// arc between q1 and q2. If you desire interpolation
- /// along the shortest arc, and q1^q2 is negative, then
- /// consider calling slerpShortestArc(), below, or flipping
- /// the second quaternion explicitly.
- ///
- /// The implementation of squad() depends on a slerp()
- /// that interpolates as is, without the automatic
- /// flipping.
- ///
- /// Don Hatch explains the method we use here on his
- /// web page, The Right Way to Calculate Stuff, at
- /// http://www.plunk.org/~hatch/rightway.php
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>
- slerp (const Quat<T>& q1, const Quat<T>& q2, T t) IMATH_NOEXCEPT
- {
- T a = angle4D (q1, q2);
- T s = 1 - t;
- Quat<T> q = sinx_over_x (s * a) / sinx_over_x (a) * s * q1 +
- sinx_over_x (t * a) / sinx_over_x (a) * t * q2;
- return q.normalized();
- }
- ///
- /// Spherical linear interpolation along the shortest
- /// arc from q1 to either q2 or -q2, whichever is closer.
- /// Assumes q1 and q2 are unit quaternions.
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>
- slerpShortestArc (const Quat<T>& q1, const Quat<T>& q2, T t) IMATH_NOEXCEPT
- {
- if ((q1 ^ q2) >= 0)
- return slerp (q1, q2, t);
- else
- return slerp (q1, -q2, t);
- }
- ///
- /// Spherical Cubic Spline Interpolation - from Advanced Animation and
- /// Rendering Techniques by Watt and Watt, Page 366:
- ///
- /// A spherical curve is constructed using three spherical linear
- /// interpolations of a quadrangle of unit quaternions: q1, qa, qb,
- /// q2. Given a set of quaternion keys: q0, q1, q2, q3, this routine
- /// does the interpolation between q1 and q2 by constructing two
- /// intermediate quaternions: qa and qb. The qa and qb are computed by
- /// the intermediate function to guarantee the continuity of tangents
- /// across adjacent cubic segments. The qa represents in-tangent for
- /// q1 and the qb represents the out-tangent for q2.
- ///
- /// The q1 q2 is the cubic segment being interpolated.
- ///
- /// The q0 is from the previous adjacent segment and q3 is from the
- /// next adjacent segment. The q0 and q3 are used in computing qa and
- /// qb.
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>
- spline (const Quat<T>& q0, const Quat<T>& q1, const Quat<T>& q2, const Quat<T>& q3, T t) IMATH_NOEXCEPT
- {
- Quat<T> qa = intermediate (q0, q1, q2);
- Quat<T> qb = intermediate (q1, q2, q3);
- Quat<T> result = squad (q1, qa, qb, q2, t);
- return result;
- }
- ///
- /// Spherical Quadrangle Interpolation - from Advanced Animation and
- /// Rendering Techniques by Watt and Watt, Page 366:
- ///
- /// It constructs a spherical cubic interpolation as a series of three
- /// spherical linear interpolations of a quadrangle of unit
- /// quaternions.
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>
- squad (const Quat<T>& q1, const Quat<T>& qa, const Quat<T>& qb, const Quat<T>& q2, T t) IMATH_NOEXCEPT
- {
- Quat<T> r1 = slerp (q1, q2, t);
- Quat<T> r2 = slerp (qa, qb, t);
- Quat<T> result = slerp (r1, r2, 2 * t * (1 - t));
- return result;
- }
- /// Compute the intermediate point between three quaternions `q0`, `q1`,
- /// and `q2`.
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>
- intermediate (const Quat<T>& q0, const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT
- {
- Quat<T> q1inv = q1.inverse();
- Quat<T> c1 = q1inv * q2;
- Quat<T> c2 = q1inv * q0;
- Quat<T> c3 = (T) (-0.25) * (c2.log() + c1.log());
- Quat<T> qa = q1 * c3.exp();
- qa.normalize();
- return qa;
- }
- template <class T>
- IMATH_HOSTDEVICE inline Quat<T>
- Quat<T>::log() const IMATH_NOEXCEPT
- {
- //
- // For unit quaternion, from Advanced Animation and
- // Rendering Techniques by Watt and Watt, Page 366:
- //
- T theta = std::acos (std::min (r, (T) 1.0));
- if (theta == 0)
- return Quat<T> (0, v);
- T sintheta = std::sin (theta);
- T k;
- if (std::abs(sintheta) < 1 && std::abs(theta) >= std::numeric_limits<T>::max() * std::abs(sintheta))
- k = 1;
- else
- k = theta / sintheta;
- return Quat<T> ((T) 0, v.x * k, v.y * k, v.z * k);
- }
- template <class T>
- IMATH_HOSTDEVICE inline Quat<T>
- Quat<T>::exp() const IMATH_NOEXCEPT
- {
- //
- // For pure quaternion (zero scalar part):
- // from Advanced Animation and Rendering
- // Techniques by Watt and Watt, Page 366:
- //
- T theta = v.length();
- T sintheta = std::sin (theta);
- T k;
- if (abs (theta) < 1 && abs (sintheta) >= std::numeric_limits<T>::max() * abs (theta))
- k = 1;
- else
- k = sintheta / theta;
- T costheta = std::cos (theta);
- return Quat<T> (costheta, v.x * k, v.y * k, v.z * k);
- }
- template <class T>
- IMATH_HOSTDEVICE constexpr inline T
- Quat<T>::angle() const IMATH_NOEXCEPT
- {
- return 2 * std::atan2 (v.length(), r);
- }
- template <class T>
- IMATH_HOSTDEVICE constexpr inline Vec3<T>
- Quat<T>::axis() const IMATH_NOEXCEPT
- {
- return v.normalized();
- }
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>&
- Quat<T>::setAxisAngle (const Vec3<T>& axis, T radians) IMATH_NOEXCEPT
- {
- r = std::cos (radians / 2);
- v = axis.normalized() * std::sin (radians / 2);
- return *this;
- }
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Quat<T>&
- Quat<T>::setRotation (const Vec3<T>& from, const Vec3<T>& to) IMATH_NOEXCEPT
- {
- //
- // Create a quaternion that rotates vector from into vector to,
- // such that the rotation is around an axis that is the cross
- // product of from and to.
- //
- // This function calls function setRotationInternal(), which is
- // numerically accurate only for rotation angles that are not much
- // greater than pi/2. In order to achieve good accuracy for angles
- // greater than pi/2, we split large angles in half, and rotate in
- // two steps.
- //
- //
- // Normalize from and to, yielding f0 and t0.
- //
- Vec3<T> f0 = from.normalized();
- Vec3<T> t0 = to.normalized();
- if ((f0 ^ t0) >= 0)
- {
- //
- // The rotation angle is less than or equal to pi/2.
- //
- setRotationInternal (f0, t0, *this);
- }
- else
- {
- //
- // The angle is greater than pi/2. After computing h0,
- // which is halfway between f0 and t0, we rotate first
- // from f0 to h0, then from h0 to t0.
- //
- Vec3<T> h0 = (f0 + t0).normalized();
- if ((h0 ^ h0) != 0)
- {
- setRotationInternal (f0, h0, *this);
- Quat<T> q;
- setRotationInternal (h0, t0, q);
- *this *= q;
- }
- else
- {
- //
- // f0 and t0 point in exactly opposite directions.
- // Pick an arbitrary axis that is orthogonal to f0,
- // and rotate by pi.
- //
- r = T (0);
- Vec3<T> f02 = f0 * f0;
- if (f02.x <= f02.y && f02.x <= f02.z)
- v = (f0 % Vec3<T> (1, 0, 0)).normalized();
- else if (f02.y <= f02.z)
- v = (f0 % Vec3<T> (0, 1, 0)).normalized();
- else
- v = (f0 % Vec3<T> (0, 0, 1)).normalized();
- }
- }
- return *this;
- }
- template <class T>
- IMATH_HOSTDEVICE inline void
- Quat<T>::setRotationInternal (const Vec3<T>& f0, const Vec3<T>& t0, Quat<T>& q) IMATH_NOEXCEPT
- {
- //
- // The following is equivalent to setAxisAngle(n,2*phi),
- // where the rotation axis, n, is orthogonal to the f0 and
- // t0 vectors, and 2*phi is the angle between f0 and t0.
- //
- // This function is called by setRotation(), above; it assumes
- // that f0 and t0 are normalized and that the angle between
- // them is not much greater than pi/2. This function becomes
- // numerically inaccurate if f0 and t0 point into nearly
- // opposite directions.
- //
- //
- // Find a normalized vector, h0, that is halfway between f0 and t0.
- // The angle between f0 and h0 is phi.
- //
- Vec3<T> h0 = (f0 + t0).normalized();
- //
- // Store the rotation axis and rotation angle.
- //
- q.r = f0 ^ h0; // f0 ^ h0 == cos (phi)
- q.v = f0 % h0; // (f0 % h0).length() == sin (phi)
- }
- template <class T>
- IMATH_HOSTDEVICE constexpr inline Matrix33<T>
- Quat<T>::toMatrix33() const IMATH_NOEXCEPT
- {
- return Matrix33<T> (1 - 2 * (v.y * v.y + v.z * v.z),
- 2 * (v.x * v.y + v.z * r),
- 2 * (v.z * v.x - v.y * r),
- 2 * (v.x * v.y - v.z * r),
- 1 - 2 * (v.z * v.z + v.x * v.x),
- 2 * (v.y * v.z + v.x * r),
- 2 * (v.z * v.x + v.y * r),
- 2 * (v.y * v.z - v.x * r),
- 1 - 2 * (v.y * v.y + v.x * v.x));
- }
- template <class T>
- IMATH_HOSTDEVICE constexpr inline Matrix44<T>
- Quat<T>::toMatrix44() const IMATH_NOEXCEPT
- {
- return Matrix44<T> (1 - 2 * (v.y * v.y + v.z * v.z),
- 2 * (v.x * v.y + v.z * r),
- 2 * (v.z * v.x - v.y * r),
- 0,
- 2 * (v.x * v.y - v.z * r),
- 1 - 2 * (v.z * v.z + v.x * v.x),
- 2 * (v.y * v.z + v.x * r),
- 0,
- 2 * (v.z * v.x + v.y * r),
- 2 * (v.y * v.z - v.x * r),
- 1 - 2 * (v.y * v.y + v.x * v.x),
- 0,
- 0,
- 0,
- 0,
- 1);
- }
- /// Transform the quaternion by the matrix
- /// @return M * q
- template <class T>
- IMATH_HOSTDEVICE constexpr inline Matrix33<T>
- operator* (const Matrix33<T>& M, const Quat<T>& q) IMATH_NOEXCEPT
- {
- return M * q.toMatrix33();
- }
- /// Transform the matrix by the quaterion:
- /// @return q * M
- template <class T>
- IMATH_HOSTDEVICE constexpr inline Matrix33<T>
- operator* (const Quat<T>& q, const Matrix33<T>& M) IMATH_NOEXCEPT
- {
- return q.toMatrix33() * M;
- }
- /// Stream output as "(r x y z)"
- template <class T>
- std::ostream&
- operator<< (std::ostream& o, const Quat<T>& q)
- {
- return o << "(" << q.r << " " << q.v.x << " " << q.v.y << " " << q.v.z << ")";
- }
- /// Quaterion multiplication
- template <class T>
- IMATH_HOSTDEVICE constexpr inline Quat<T>
- operator* (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT
- {
- return Quat<T> (q1.r * q2.r - (q1.v ^ q2.v), q1.r * q2.v + q1.v * q2.r + q1.v % q2.v);
- }
- /// Quaterion division
- template <class T>
- IMATH_HOSTDEVICE constexpr inline Quat<T>
- operator/ (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT
- {
- return q1 * q2.inverse();
- }
- /// Quaterion division
- template <class T>
- IMATH_HOSTDEVICE constexpr inline Quat<T>
- operator/ (const Quat<T>& q, T t) IMATH_NOEXCEPT
- {
- return Quat<T> (q.r / t, q.v / t);
- }
- /// Quaterion*scalar multiplication
- /// @return q * t
- template <class T>
- IMATH_HOSTDEVICE constexpr inline Quat<T>
- operator* (const Quat<T>& q, T t) IMATH_NOEXCEPT
- {
- return Quat<T> (q.r * t, q.v * t);
- }
- /// Quaterion*scalar multiplication
- /// @return q * t
- template <class T>
- IMATH_HOSTDEVICE constexpr inline Quat<T>
- operator* (T t, const Quat<T>& q) IMATH_NOEXCEPT
- {
- return Quat<T> (q.r * t, q.v * t);
- }
- /// Quaterion addition
- template <class T>
- IMATH_HOSTDEVICE constexpr inline Quat<T>
- operator+ (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT
- {
- return Quat<T> (q1.r + q2.r, q1.v + q2.v);
- }
- /// Quaterion subtraction
- template <class T>
- IMATH_HOSTDEVICE constexpr inline Quat<T>
- operator- (const Quat<T>& q1, const Quat<T>& q2) IMATH_NOEXCEPT
- {
- return Quat<T> (q1.r - q2.r, q1.v - q2.v);
- }
- /// Compute the conjugate
- template <class T>
- IMATH_HOSTDEVICE constexpr inline Quat<T>
- operator~ (const Quat<T>& q) IMATH_NOEXCEPT
- {
- return Quat<T> (q.r, -q.v);
- }
- /// Negate the quaterion
- template <class T>
- IMATH_HOSTDEVICE constexpr inline Quat<T>
- operator- (const Quat<T>& q) IMATH_NOEXCEPT
- {
- return Quat<T> (-q.r, -q.v);
- }
- /// Quaterion*vector multiplcation
- /// @return v * q
- template <class T>
- IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Vec3<T>
- operator* (const Vec3<T>& v, const Quat<T>& q) IMATH_NOEXCEPT
- {
- Vec3<T> a = q.v % v;
- Vec3<T> b = q.v % a;
- return v + T (2) * (q.r * a + b);
- }
- #if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
- # pragma warning(pop)
- #endif
- IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
- #endif // INCLUDED_IMATHQUAT_H
|