1 #ifndef INCLUDE_AL_QUAT_HPP
2 #define INCLUDE_AL_QUAT_HPP
47 #include "al/math/al_Constants.hpp"
48 #include "al/math/al_Mat.hpp"
49 #include "al/math/al_Vec.hpp"
62 template <
typename T =
double>
76 Quat(
const T&
w = T(1),
const T&
x = T(0),
const T&
y = T(0),
97 :
w(
w),
x(xyz[0]),
y(xyz[1]),
z(xyz[2]) {}
161 return (
w == v.
w) && (
x == v.
x) && (
y == v.
y) && (
z == v.
z);
168 Quat operator+(
const Quat& v)
const {
return Quat(*
this) += v; }
169 Quat operator+(
const T& v)
const {
return Quat(*
this) += v; }
170 Quat operator-(
const Quat& v)
const {
return Quat(*
this) -= v; }
171 Quat operator-(
const T& v)
const {
return Quat(*
this) -= v; }
172 Quat operator/(
const Quat& v)
const {
return Quat(*
this) /= v; }
173 Quat operator/(
const T& v)
const {
return Quat(*
this) /= v; }
174 Quat operator*(
const Quat& v)
const {
return Quat(*
this) *= v; }
175 Quat operator*(
const T& v)
const {
return Quat(*
this) *= v; }
178 Quat& operator=(
const Quat<U>& v) {
181 Quat& operator=(
const T& v) {
return set(v); }
189 Quat& operator+=(
const T& v) {
203 Quat& operator-=(
const T& v) {
210 Quat& operator*=(
const Quat& v) {
return set(multiply(v)); }
211 Quat& operator*=(
const T& v) {
218 Quat& operator/=(
const Quat& v) {
return (*
this) *= v.recip(); }
219 Quat& operator/=(
const T& v) {
252 Quat multiply(
const Quat& q2)
const;
253 Quat reverseMultiply(
const Quat& q2)
const;
270 return set(q.
w, q.
x, q.
y, q.
z);
285 return set(cos(t2), sin(t2), T(0), T(0));
291 return set(cos(t2), T(0), sin(t2), T(0));
297 return set(cos(t2), T(0), T(0), sin(t2));
302 return fromEuler(aeb[0], aeb[1], aeb[2]);
328 template <
typename T2>
332 template <
typename T2>
352 template <
typename T2>
354 template <
typename T2>
356 toVectorX(v[0], v[1], v[2]);
358 template <
typename T2 = T>
366 template <
typename T2>
368 template <
typename T2>
370 toVectorY(v[0], v[1], v[2]);
372 template <
typename T2 = T>
380 template <
typename T2>
382 template <
typename T2>
384 toVectorZ(v[0], v[1], v[2]);
386 template <
typename T2 = T>
402 return slerp(*
this, target, amt);
413 void print(std::ostream& stream)
const;
415 static T accuracyMax() {
return 1.000001; }
416 static T accuracyMin() {
return 0.999999; }
417 static T eps() {
return 0.0000001; }
420 static T abs(T v) {
return v > T(0) ? v : -v; }
424 Quat<T> operator+(T r,
const Quat<T>& q) {
428 Quat<T> operator-(T r,
const Quat<T>& q) {
432 Quat<T> operator*(T r,
const Quat<T>& q) {
436 Quat<T> operator/(T r,
const Quat<T>& q) {
437 return q.conjugate() * (r / q.magSqr());
442 template <
typename T>
445 if (unit * unit < eps()) {
448 }
else if (unit > accuracyMax() || unit < accuracyMin()) {
449 (*this) *= 1. / sqrt(unit);
455 template <
typename T>
457 return Quat(w * q.
w - x * q.
x - y * q.
y - z * q.
z,
458 w * q.
x + x * q.
w + y * q.
z - z * q.
y,
459 w * q.
y + y * q.
w + z * q.
x - x * q.
z,
460 w * q.
z + z * q.
w + x * q.
y - y * q.
x);
463 template <
typename T>
464 inline Quat<T> Quat<T>::reverseMultiply(
const Quat<T>& q)
const {
472 inline T justUnder1();
474 float inline justUnder1() {
478 double inline justUnder1() {
479 return 0.999999999999999;
483 template <
typename T>
490 if (w_m > justUnder1<T>() || w_m < -justUnder1<T>()) {
491 return Quat<T>((w >= T(0) ? T(1) : T(-1)) * ::pow(m, expo), 0, 0, 0);
494 T theta = ::acos(w_m);
496 imag *= ::sin(expo * theta);
497 return Quat(::cos(expo * theta), imag) * ::pow(m, expo);
500 template <
typename T>
502 return fromAxisAngle(
angle, axis[0], axis[1], axis[2]);
505 template <
typename T>
508 T t2 =
angle * T(0.5);
517 template <
typename T>
536 T c1 = cos(az * T(0.5));
537 T c2 = cos(el * T(0.5));
538 T c3 = cos(ba * T(0.5));
539 T s1 = sin(az * T(0.5));
540 T s2 = sin(el * T(0.5));
541 T s3 = sin(ba * T(0.5));
569 w = tw * c3 - tz * s3;
570 x = tx * c3 + ty * s3;
571 y = ty * c3 - tx * s3;
572 z = tw * s3 + tz * c3;
578 template <
typename T>
580 T trace = m[0] + m[5] + m[10];
581 w = sqrt(1. + trace) * 0.5;
584 x = (m[9] - m[6]) / (4. * w);
585 y = (m[2] - m[8]) / (4. * w);
586 z = (m[4] - m[1]) / (4. * w);
588 if (m[0] > m[5] && m[0] > m[10]) {
590 x = sqrt(1. + m[0] - m[5] - m[10]) * 0.5;
591 w = (m[9] - m[6]) / (4. * x);
592 y = (m[4] + m[1]) / (4. * x);
593 z = (m[8] + m[2]) / (4. * x);
594 }
else if (m[5] > m[0] && m[5] > m[10]) {
596 y = sqrt(1. + m[5] - m[0] - m[10]) * 0.5;
597 w = (m[2] - m[8]) / (4. * y);
598 x = (m[4] + m[1]) / (4. * y);
599 z = (m[9] + m[6]) / (4. * y);
602 z = sqrt(1. + m[10] - m[0] - m[5]) * 0.5;
603 w = (m[4] - m[1]) / (4. * z);
604 x = (m[8] + m[2]) / (4. * z);
605 y = (m[9] + m[6]) / (4. * z);
611 template <
typename T>
613 T trace = m[0] + m[5] + m[10];
614 w = sqrt(1. + trace) * 0.5;
617 x = (m[6] - m[9]) / (4. * w);
618 y = (m[8] - m[2]) / (4. * w);
619 z = (m[1] - m[4]) / (4. * w);
621 if (m[0] > m[5] && m[0] > m[10]) {
623 x = sqrt(1. + m[0] - m[5] - m[10]) * 0.5;
624 w = (m[6] - m[9]) / (4. * x);
625 y = (m[1] + m[4]) / (4. * x);
626 z = (m[2] + m[8]) / (4. * x);
627 }
else if (m[5] > m[0] && m[5] > m[10]) {
629 y = sqrt(1. + m[5] - m[0] - m[10]) * 0.5;
630 w = (m[8] - m[2]) / (4. * y);
631 x = (m[1] + m[4]) / (4. * y);
632 z = (m[6] + m[9]) / (4. * y);
635 z = sqrt(1. + m[10] - m[0] - m[5]) * 0.5;
636 w = (m[1] - m[4]) / (4. * z);
637 x = (m[2] + m[8]) / (4. * z);
638 y = (m[6] + m[9]) / (4. * z);
644 template <
typename T>
649 T invSinAngle = 1. / sqrt(1. - unit);
651 aa = ::acos(w) * T(2);
652 ax = x * invSinAngle;
653 ay = y * invSinAngle;
654 az = z * invSinAngle;
657 if (x == T(0) && y == T(0) && z == T(0)) {
674 template <
typename T>
683 T a = w, b = y, c = x, d = z, e = -1;
688 T test = a * c + e * b * d;
689 if (test > 0.49999) {
695 if (test < -0.49999) {
706 az = ::atan2(2 * (a * b - e * c * d), 1 - 2 * (bsq + csq));
707 el = ::asin(2 * test);
708 ba = ::atan2(2 * (a * d - e * b * c), 1 - 2 * (csq + dsq));
723 template <
typename T>
726 static const T _2 = T(2);
727 static const T _1 = T(1);
728 T _2w = _2 * w, _2x = _2 * x, _2y = _2 * y;
729 T wx = _2w * x, wy = _2w * y, wz = _2w * z, xx = _2x * x, xy = _2x * y,
730 xz = _2x * z, yy = _2y * y, yz = _2y * z, zz = _2 * z * z;
732 ux[0] = -zz - yy + _1;
737 uy[1] = -zz - xx + _1;
742 uz[2] = -yy - xx + _1;
762 template <
typename T>
763 template <
typename T2>
766 toCoordinateFrame(ux, uy, uz);
787 template <
typename T>
788 template <
typename T2>
791 toCoordinateFrame(ux, uy, uz);
811 template <
typename T>
812 template <
typename T2>
814 ax = 1.0 - 2.0 * y * y - 2.0 * z * z;
815 ay = 2.0 * x * y + 2.0 * z * w;
816 az = 2.0 * x * z - 2.0 * y * w;
819 template <
typename T>
820 template <
typename T2>
822 ax = 2.0 * x * y - 2.0 * z * w;
823 ay = 1.0 - 2.0 * x * x - 2.0 * z * z;
824 az = 2.0 * y * z + 2.0 * x * w;
827 template <
typename T>
828 template <
typename T2>
830 ax = 2.0 * x * z + 2.0 * y * w;
831 ay = 2.0 * y * z - 2.0 * x * w;
832 az = 1.0 - 2.0 * x * x - 2.0 * y * y;
840 template <
typename T>
845 Quat p(-x * v.x - y * v.y - z * v.z, w * v.x + y * v.z - z * v.y,
846 w * v.y - x * v.z + z * v.x, w * v.z + x * v.y - y * v.x);
851 p.
y * w - p.
w * y + p.
x * z - p.
z * x,
852 p.
z * w - p.
w * z + p.
y * x - p.
x * y);
857 template <
typename T>
862 template <
typename T>
868 }
else if (amt == T(1)) {
873 T dot_prod = input.
dot(target);
877 dot_prod = (dot_prod < -1) ? -1 : ((dot_prod > 1) ? 1 : dot_prod);
880 if (dot_prod < 0.0) {
881 dot_prod = -dot_prod;
885 T cos_angle = acos(dot_prod);
886 if (Quat::abs(cos_angle) > eps()) {
887 T sine = sin(cos_angle);
888 T inv_sine = 1. / sine;
890 a = sin(cos_angle * (1. - amt)) * inv_sine;
891 b = sin(cos_angle * amt) * inv_sine;
903 result.
w = a * input.
w + b * target.
w;
904 result.
x = a * input.
x + b * target.
x;
905 result.
y = a * input.
y + b * target.
y;
906 result.
z = a * input.
z + b * target.
z;
912 template <
typename T>
914 Quat<T>* buffer,
int numFrames) {
918 RSin(
const T& frq = T(0),
const T& phs = T(0),
const T& amp = T(1))
921 mul = (T)2 * (T)cos(f);
922 val2 = (T)sin(p - f * T(2)) * amp;
923 val = (T)sin(p - f) * amp;
927 T operator()()
const {
928 T v0 = mul * val - val2;
939 T dot_prod = input.
dot(target);
942 dot_prod = (dot_prod < -1) ? -1 : ((dot_prod > 1) ? 1 : dot_prod);
945 if (dot_prod < 0.0) {
946 dot_prod = -dot_prod;
950 const T cos_angle = acos(dot_prod);
951 const T inv_frames = 1. / ((T)numFrames);
953 if (Quat::abs(cos_angle) > eps()) {
954 const T sine = sin(cos_angle);
955 const T inv_sine = 1. / sine;
956 RSin sinA(-cos_angle * inv_frames, cos_angle, inv_sine);
957 RSin sinB(cos_angle * inv_frames, 0, inv_sine * bflip);
959 for (
int i = 0; i < numFrames; i++) {
964 buffer[i].
w = a * input.
w + b * target.
w;
965 buffer[i].
x = a * input.
x + b * target.
x;
966 buffer[i].
y = a * input.
y + b * target.
y;
967 buffer[i].
z = a * input.
z + b * target.
z;
971 for (
int i = 0; i < numFrames; i++) {
972 T a = i * inv_frames;
975 buffer[i].
w = a * input.
w + b * target.
w;
976 buffer[i].
x = a * input.
x + b * target.
x;
977 buffer[i].
y = a * input.
y + b * target.
y;
978 buffer[i].
z = a * input.
z + b * target.
z;
984 template <
typename T>
999 if (d < -0.999999999) {
1003 if (axis.
magSqr() < 0.00000000001) {
1019 T s = sqrt((d + 1.) * 2);
1030 template <
typename T>
1046 T num8 = (m00 + m11) + m22;
1049 T num = sqrt(num8 + 1);
1052 q.
x = (m12 - m21) * num;
1053 q.
y = (m20 - m02) * num;
1054 q.
z = (m01 - m10) * num;
1057 if ((m00 >= m11) && (m00 >= m22)) {
1058 T num7 = sqrt(((1 + m00) - m11) - m22);
1059 T num4 = 0.5 / num7;
1061 q.
y = (m01 + m10) * num4;
1062 q.
z = (m02 + m20) * num4;
1063 q.
w = (m12 - m21) * num4;
1067 T num6 = sqrt(((1 + m11) - m00) - m22);
1068 T num3 = 0.5 / num6;
1069 q.
x = (m10 + m01) * num3;
1071 q.
z = (m21 + m12) * num3;
1072 q.
w = (m20 - m02) * num3;
1075 T num5 = sqrt(((1 + m22) - m00) - m11);
1076 T num2 = 0.5 / num5;
1077 q.
x = (m20 + m02) * num2;
1078 q.
y = (m21 + m12) * num2;
1080 q.
w = (m01 - m10) * num2;
1087 template <
typename T>
1101 cross(axis, zaxis, diff);
1105 float axis_mag_sqr = axis.
dot(axis);
1106 float along = zaxis.
dot(diff);
1108 if (axis_mag_sqr < 0.001 && along < 0) {
1113 if (axis_mag_sqr < 0.001) {
1119 axis_mag_sqr = axis.
dot(axis);
1122 if (along < 0.9995 && axis_mag_sqr > 0.001) {
1123 float theta = Quat::abs(amt) * acos(along);
1125 fromAxisAngle(theta, axis[0], axis[1], axis[2]);
1133 template <
typename T>
1143 T dotmag = v1.
dot(v2);
1144 T theta = acos(dotmag) * 0.5;
1148 Quat<T> q(cos(theta), bivec[0], bivec[1], bivec[2]);
1153 template <
typename T>
1155 stream <<
"Quat(" << w <<
", " << x <<
", " << y <<
", " << z <<
")"
Fixed-size n-by-n square matrix.
Quat & set(const T &w, const T &x, const T &y, const T &z)
Set components.
T magSqr() const
Get magnitude squared.
static Quat getBillboardRotation(const Vec< 3, T > &forward, const Vec< 3, T > &up)
Quat slerp(const Quat &target, T amt) const
Spherical interpolation.
Quat & fromAxisAngle(const T &angle, const Vec< 3, T > &axis)
Set as versor rotated by angle, in radians, around unit vector.
bool operator==(const Quat &v) const
Returns true if all components are equal.
Quat & setIdentity()
Set to identity.
static Quat rotor(const Vec< 3, T > &v1, const Vec< 3, T > &v2)
Get rotor from two unit vectors.
Quat & fromMatrix(const Mat< 4, T > &v)
Quat & set(const Quat< U > &q)
Set from other quaternion.
void slerpTo(const Quat &target, T amt)
In-place spherical interpolation.
void toEuler(T &az, T &el, T &ba) const
Convert to YXZ Euler angles (azimuth, elevation, bank), in radians.
Quat & fromMatrixTransposed(const Mat< 4, T > &v)
Set as versor from row-major 4-by-4 projective space transformation matrix.
Vec< 3, T > rotate(const Vec< 3, T > &v) const
Quat & fromAxisZ(const T &angle)
Set as versor rotated by angle, in radians, around z-axis.
Quat & fromMatrix(const T *matrix)
Quat pow(T v) const
Return quaternion raised to a power.
void print(std::ostream &stream) const
utility for debug printing:
Quat inverse() const
Returns inverse (same as conjugate if normalized as q^-1 = q_conj/q_mag^2)
Quat sgn() const
Returns signum, q/|q|, the closest point on unit 3-sphere.
Quat(const Vec< 3, U > &xyz)
Construct 'pure imaginary' quaternion.
Quat conj() const
Returns the conjugate.
void toMatrix(T2 *matrix) const
Convert to column-major 4-by-4 projective space transformation matrix.
void toEuler(Vec< 3, T > &aeb) const
Convert to YXZ Euler angle vector (azimuth, elevation, bank), in radians.
Quat(const T &w, const Vec< 3, U > &xyz)
Construct quaternion from real and imaginary parts.
void toCoordinateFrame(Vec< 3, T > &ux, Vec< 3, T > &uy, Vec< 3, T > &uz) const
Convert to coordinate frame unit vectors.
void toMatrixTransposed(T2 *matrix) const
Convert to row-major 4-by-4 projective space transformation matrix.
Quat & fromMatrixTransposed(const T *matrix)
Set as versor from row-major 4-by-4 projective space transformation matrix.
void towardPoint(const Vec< 3, T > &pos, const Quat< T > &q, const Vec< 3, T > &v, float amt)
Get the quaternion from a given point and quaterion toward another point.
T components[4]
component vector
Quat recip() const
Returns multiplicative inverse.
Quat & fromEuler(const Vec< 3, T > &aeb)
Set as versor rotated by YXZ Euler angles, in radians.
T mag() const
Get magnitude.
void toAxisAngle(T &angle, T &ax, T &ay, T &az) const
Convert to axis-angle form, in radians.
Quat & fromAxisY(const T &angle)
Set as versor rotated by angle, in radians, around y-axis.
Vec< 3, T > rotateTransposed(const Vec< 3, T > &v) const
This is rotation by the quaternion's conjugate.
static Quat getRotationTo(const Vec< 3, T > &usrc, const Vec< 3, T > &udst)
void toEuler(T *aeb) const
Convert to YXZ Euler angle vector (azimuth, elevation, bank), in radians.
T & operator[](int i)
Set component with index.
Quat & normalize()
Normalize magnitude to one.
static void slerpBuffer(const Quat &from, const Quat &to, Quat< T > *buffer, int numFrames)
Fill an array of Quats with a full spherical interpolation.
static Quat slerp(const Quat &from, const Quat &to, T amt)
Spherical linear interpolation of a quaternion.
Quat & fromAxisAngle(const T &angle, const T &ux, const T &uy, const T &uz)
Set as versor rotated by angle, in radians, around unit vector (ux,uy,uz)
Quat & fromEuler(const T &az, const T &el, const T &ba)
Set as versor rotated by YXZ Euler angles, in radians.
void toVectorX(T2 &ax, T2 &ay, T2 &az) const
Get local x unit vector (1,0,0) in absolute coordinates.
static Quat identity()
Returns identity.
Quat & fromAxisX(const T &angle)
Set as versor rotated by angle, in radians, around x-axis.
Quat(const T &w=T(1), const T &x=T(0), const T &y=T(0), const T &z=T(0))
Default constructor creates an identity quaternion.
const T & operator[](int i) const
Get component with index.
void toVectorZ(T2 &ax, T2 &ay, T2 &az) const
Get local z unit vector (0,0,1) in absolute coordinates.
bool operator!=(const Quat &v) const
Returns true if any components are not equal.
void toVectorY(T2 &ax, T2 &ay, T2 &az) const
Get local y unit vector (0,1,0) in absolute coordinates.
T dot(const Quat &v) const
Returns dot product with another quaternion.
Vec & normalize(T scale=T(1))
Set magnitude to one without changing direction.
T magSqr() const
Returns magnitude squared.
T dot(const Vec< N, U > &v) const
Returns dot (inner) product between vectors.
T angle(const Vec< N, T > &a, const Vec< N, T > &b)
Returns angle, in interval [0, pi], between two vectors.
Quat< double > Quatd
Double-precision quaternion.
Quat< float > Quatf
Single-precision quaternion.
void cross(Vec< 3, T > &r, const Vec< 3, T > &a, const Vec< 3, T > &b)
Sets r to cross product, a x b.