Honeycomb  0.1
Component-Model Framework
Quat.h
Go to the documentation of this file.
1 // Honeycomb, Copyright (C) 2015 NewGamePlus Inc. Distributed under the Boost Software License v1.0.
2 #pragma once
3 
6 
7 namespace honey
8 {
9 
10 template<class Real> class Interp_;
11 
13 
18 template<class Real__>
19 class Quat_
20 {
21 public:
22  typedef Real__ Real;
23 private:
24  typedef typename Numeral<Real>::Real_ Real_;
25  typedef Alge_<Real> Alge;
26  typedef Trig_<Real> Trig;
27  typedef Vec<3,Real> Vec3;
28  typedef Vec<4,Real> Vec4;
29  typedef Matrix<4,4,Real> Matrix4;
30  typedef Interp_<Real> Interp;
31 
33  enum
34  {
35  eulAxX = 0,
36  eulAxY = 1,
37  eulAxZ = 2,
38  eulFrmS = 0,
39  eulFrmR = 1,
40  eulRepNo = 0,
41  eulRepYes = 1,
42  eulParEven = 0,
43  eulParOdd = 1
44  };
45 
46 public:
47  static const int dim = 4;
48 
49  // Creates an order value between 0 and 23 from 4-tuple choices
50  /*
51  * There are 24 possible conventions, designated by:
52  * - eulAxI, axis used initially
53  * - eulPar, parity of axis permutation
54  * - eulRep, repetition of initial axis as last
55  * - eulFrm, frame from which axes are taken
56  *
57  * Axes I,J,K will be a permutation of X,Y,Z.
58  * Axis H will be either I or K, depending on eulRep.
59  * Frame S takes axes from initial static frame.
60  * If ord = (AxI=X, Par=Even, Rep=No, Frm=S), then {a,b,c,ord} means Rz(c)Ry(b)Rx(a),
61  * where Rz(c)v rotates v around Z by c radians.
62  *
63  * Ken Shoemake, 1993
64  */
65  #define _ORD(i,p,r,f) (((((((i)<<1)+(p))<<1)+(r))<<1)+(f))
66 
68 
75  enum class EulerOrder
76  {
77  xyz_s = _ORD(eulAxX, eulParEven, eulRepNo, eulFrmS),
78  xyx_s = _ORD(eulAxX, eulParEven, eulRepYes, eulFrmS),
79  xzy_s = _ORD(eulAxX, eulParOdd, eulRepNo, eulFrmS),
80  xzx_s = _ORD(eulAxX, eulParOdd, eulRepYes, eulFrmS),
81  yzx_s = _ORD(eulAxY, eulParEven, eulRepNo, eulFrmS),
82  yzy_s = _ORD(eulAxY, eulParEven, eulRepYes, eulFrmS),
83  yxz_s = _ORD(eulAxY, eulParOdd, eulRepNo, eulFrmS),
84  yxy_s = _ORD(eulAxY, eulParOdd, eulRepYes, eulFrmS),
85  zxy_s = _ORD(eulAxZ, eulParEven, eulRepNo, eulFrmS),
86  zxz_s = _ORD(eulAxZ, eulParEven, eulRepYes, eulFrmS),
87  zyx_s = _ORD(eulAxZ, eulParOdd, eulRepNo, eulFrmS),
88  zyz_s = _ORD(eulAxZ, eulParOdd, eulRepYes, eulFrmS),
89 
90  zyx_r = _ORD(eulAxX, eulParEven, eulRepNo, eulFrmR),
91  xyx_r = _ORD(eulAxX, eulParEven, eulRepYes, eulFrmR),
92  yzx_r = _ORD(eulAxX, eulParOdd, eulRepNo, eulFrmR),
93  xzx_r = _ORD(eulAxX, eulParOdd, eulRepYes, eulFrmR),
94  xzy_r = _ORD(eulAxY, eulParEven, eulRepNo, eulFrmR),
95  yzy_r = _ORD(eulAxY, eulParEven, eulRepYes, eulFrmR),
96  zxy_r = _ORD(eulAxY, eulParOdd, eulRepNo, eulFrmR),
97  yxy_r = _ORD(eulAxY, eulParOdd, eulRepYes, eulFrmR),
98  yxz_r = _ORD(eulAxZ, eulParEven, eulRepNo, eulFrmR),
99  zxz_r = _ORD(eulAxZ, eulParEven, eulRepYes, eulFrmR),
100  xyz_r = _ORD(eulAxZ, eulParOdd, eulRepNo, eulFrmR),
101  zyz_r = _ORD(eulAxZ, eulParOdd, eulRepYes, eulFrmR)
102  };
103 
104  #undef _ORD
105 
107  Quat_() : x(0), y(0), z(0), w(1) {}
109  Quat_(Real x, Real y, Real z, Real w) : x(x), y(y), z(z), w(w) {}
111  Quat_(const Vec3& axis, Real angle) { fromAxisAngle(axis, angle); }
113  Quat_(const Vec3& axisX, const Vec3& axisY, const Vec3& axisZ) { fromAxes(axisX, axisY, axisZ); }
115  Quat_(const Vec3& from, const Vec3& to) { fromAlign(from, to); }
117  explicit Quat_(const Vec3& eulerAngles) { fromEulerAngles(eulerAngles); }
119  Quat_(const Vec3& eulerAngles, EulerOrder order) { fromEulerAngles(eulerAngles, order); }
121  Quat_(const Matrix4& rot) { fromMatrix(rot); }
122 
124  Quat_& fromZero() { x=0; y=0; z=0; w=0; return *this; }
126  Quat_& fromIdentity() { x=0; y=0; z=0; w=1; return *this; }
128  Quat_& fromAxisAngle(const Vec3& axis, Real angle);
130  Quat_& fromEulerAngles(const Vec3& eulerAngles);
132  Quat_& fromEulerAngles(const Vec3& eulerAngles, EulerOrder order);
134  Quat_& fromMatrix(const Matrix4& rot);
136  Quat_& fromAlign(const Vec3& v1, const Vec3& v2);
138  Quat_& fromAxes(const Vec3& axisX, const Vec3& axisY, const Vec3& axisZ);
139 
140  bool operator==(const Quat_& rhs) const { return rhs.x == x && rhs.y == y && rhs.z == z && rhs.w == w; }
141  bool operator!=(const Quat_& rhs) const { return rhs.x != x || rhs.y != y || rhs.z != z || rhs.w != w; }
142 
143  Quat_ operator+() const { return *this; }
144  Quat_ operator+(const Quat_& rhs) const { return Quat_(x+rhs.x, y+rhs.y, z+rhs.z, w+rhs.w); }
145  Quat_& operator+=(const Quat_& rhs) { x += rhs.x; y += rhs.y; z += rhs.z; w += rhs.w; return *this; }
146 
147  Quat_ operator-() const { return Quat_(-x, -y, -z, -w); }
148  Quat_ operator-(const Quat_& rhs) const { return Quat_(x-rhs.x, y-rhs.y, z-rhs.z, w-rhs.w); }
149  Quat_& operator-=(const Quat_& rhs) { x -= rhs.x; y -= rhs.y; z -= rhs.z; w -= rhs.w; return *this; }
150 
151  Quat_ operator*(const Quat_& rhs) const
152  {
153  return Quat_( x*rhs.w + y*rhs.z - z*rhs.y + w*rhs.x,
154  -x*rhs.z + y*rhs.w + z*rhs.x + w*rhs.y,
155  x*rhs.y - y*rhs.x + z*rhs.w + w*rhs.z,
156  -x*rhs.x - y*rhs.y - z*rhs.z + w*rhs.w);
157  }
158 
159  Vec3 operator*(const Vec3& rhs) const
160  {
161  Vec3 qvec(x, y, z);
162  Vec3 uv = qvec.cross(rhs);
163  Vec3 uuv = qvec.cross(uv);
164  uv *= w*2;
165  uuv *= 2;
166  return rhs + uv + uuv;
167  }
168 
169  Quat_ operator*(Real rhs) const { return Quat_(x*rhs, y*rhs, z*rhs, w*rhs); }
170  Quat_& operator*=(const Quat_& rhs) { this->operator=(operator*(rhs)); return *this; }
171  Quat_& operator*=(Real rhs) { this->operator=(operator*(rhs)); return *this; }
172 
173  Quat_ operator/(const Quat_& rhs) const { return operator*(rhs.inverseNonUnit()); }
174  Quat_ operator/(Real rhs) const { return operator*(1/rhs); }
175  Quat_& operator/=(const Quat_& rhs) { this->operator=(operator/(rhs)); return *this; }
176  Quat_& operator/=(Real rhs) { this->operator=(operator/(rhs)); return *this; }
177 
178  friend Quat_ operator*(Real lhs, const Quat_& rhs) { return rhs.operator*(lhs); }
179 
181  const Real& operator[](int i) const { assert(i>=0&&i<dim); return *(&x+i); }
182  Real& operator[](int i) { assert(i>=0&&i<dim); return *(&x+i); }
183 
185  operator Real*() { return &x; }
186  operator const Real*() const { return &x; }
187 
188  Real dot(const Quat_& q) const { return x*q.x + y*q.y + z*q.z + w*q.w; }
189  Quat_ conjugate() const { return Quat_(-x, -y, -z, w); }
191  Quat_ inverse() const { return conjugate(); }
192 
195  {
196  Real l = lengthSqr();
197  if (l > Real_::zeroTol)
198  {
199  Real l_inv = 1/l;
200  return Quat_(-x*l_inv, -y*l_inv, -z*l_inv, w*l_inv);
201  }
202  return zero;
203  }
204 
205  Quat_ exp() const;
206  Quat_ ln() const;
207  Quat_ sqrt() const { Real tmp = w*2; return Quat_(x*tmp, y*tmp, z*tmp, w*w - x*x - y*y - z*z); }
209  Real lengthSqr() const { return x*x + y*y + z*z + w*w; }
210  Real length() const { return Alge::sqrt(lengthSqr()); }
211 
214  {
215  Real l = length();
216  if (l > Real_::zeroTol)
217  {
218  if (len) len = l;
219  return *this / l;
220  }
221  if (len) len = 0;
222  return zero;
223  }
224 
227  {
228  static const Real recurse1 = 0.91521198;
229  static const Real recurse2 = 0.65211970;
230 
231  Real s = x*x + y*y + z*z + w*w;
232  Real k = sqrtInverse_fast(s);
233  if (s <= recurse1)
234  {
235  k = k*sqrtInverse_fast(k*k*s);
236  if (s <= recurse2)
237  k = k*sqrtInverse_fast(k*k*s);
238  }
239  return Quat_(x*k, y*k, z*k, w*k);
240  }
241 
243  void axisAngle(Vec3& axis, Real& angle) const;
244 
246  Vec3 axisX() const;
247  Vec3 axisY() const;
248  Vec3 axisZ() const;
249 
251  void axes(Vec3& axisX, Vec3& axisY, Vec3& axisZ) const;
252 
254  Vec3 eulerAngles() const;
256  Vec3 eulerAngles(EulerOrder order) const;
257 
259  Matrix4& toMatrix(Matrix4& rot, bool b3x3 = false) const;
260 
262  static Quat_ slerp(Real t, const Quat_& q0, const Quat_& q1)
263  {
264  t = Alge::clamp(t, 0, 1);
265  //Make sure we take the short way around the sphere
266  Real dot = q0.dot(q1);
267  return (dot >= 0) ? slerp_fast(t, q0, q1, dot) : slerp_fast(t, q0, -q1, -dot);
268  }
269 
271  static void squadSetup( const Quat_& q0, const Quat_& q1, const Quat_& q2, const Quat_& q3,
272  Quat_& a, Quat_& b, Quat_& c);
273 
275  static Quat_ squad(Real t, const Quat_& q1, const Quat_& a, const Quat_& b, const Quat_& c);
276 
278 
284  static Quat_ baryCentric(Real f, Real g, const Quat_& q0, const Quat_& q1, const Quat_& q2);
285 
286  friend ostream& operator<<(ostream& os, const Quat_& val)
287  {
288  os << "[";
289  for (int i = 0; i < dim; ++i)
290  {
291  if (i != 0)
292  os << ", ";
293  os << val[i];
294  }
295  return os << "]";
296  }
297 
298 private:
300  static void eulGetOrd(EulerOrder ord, int& i, int& j, int& k, int& h, int& n, int& s, int& f)
301  {
302  static const int eulSafe[] = {0,1,2,0};
303  static const int eulNext[] = {1,2,0,1};
304 
305  uint32 o = static_cast<uint32>(ord);
306  f=o&1; o>>=1;
307  s=o&1; o>>=1;
308  n=o&1; o>>=1;
309  i=eulSafe[o&3]; j=eulNext[i+n]; k=eulNext[i+1-n];
310  h=s?k:i;
311  }
312 
314  static Quat_ slerp_fast(Real t, const Quat_& q0, const Quat_& q1, Real cosAlpha);
315 
316  static Real slerpCorrection(Real t, Real cosAlpha)
317  {
318  static const Real tcor = 0.58549219;
319  static const Real tcoratten = 0.82279687;
320 
321  Real factor = 1 - tcoratten*cosAlpha;
322  factor = factor*factor;
323  Real k = tcor*factor;
324  Real b = 2 * k;
325  Real c = -3 * k;
326  Real d = 1 + k;
327  return t*(t*(b*t + c) + d);
328  }
329 
331  static Real sqrtInverse_fast(Real x)
332  {
333  static const Real neighborhood = 0.959066;
334  // static const Real scale = 1.000311;
335  static const Real additive = 1.02143; // scale / sqrt(neighborhood)
336  static const Real factor = -0.53235; // scale * (-0.5 / (neighborhood * sqrt(neighborhood)))
337  return additive + (x - neighborhood)*factor;
338  }
339 
340 public:
345 
346  static const Quat_ zero;
347  static const Quat_ identity;
348 };
349 
350 template<class Real> const Quat_<Real> Quat_<Real>::zero (0, 0, 0, 0);
351 template<class Real> const Quat_<Real> Quat_<Real>::identity (0, 0, 0, 1);
352 
356 
357 extern template class Quat_<Float>;
358 extern template class Quat_<Double>;
359 extern template class Quat_<Quad>;
360 
361 }
362 
363 #define Section_Header
364 #include "Honey/Math/Alge/platform/Quat.h"
365 #undef Section_Header
(m x n)-dimensional matrix
Definition: Matrix.h:24
Algebra.
Definition: Alge.h:13
Quat_ normalize_fast() const
Fast normalization, only accurate when quaternion is close to unit length.
Definition: Quat.h:226
Quat_ & operator-=(const Quat_ &rhs)
Definition: Quat.h:149
const Real & operator[](int i) const
Access quaternion components.
Definition: Quat.h:181
Quat_ & operator*=(const Quat_ &rhs)
Definition: Quat.h:170
static optnull_t optnull
Null optional, use to reset an optional to an uninitialized state or test for initialization.
Definition: Optional.h:12
Quat_ & fromEulerAngles(const Vec3 &eulerAngles)
Construct from euler angles in radians and order xyz_s
Definition: Quat.cpp:27
EulerOrder
Euler angle order.
Definition: Quat.h:75
Quat_ operator-() const
Definition: Quat.h:147
unsigned int uint32
Definition: Core.h:16
Quat_ operator*(const Quat_ &rhs) const
Definition: Quat.h:151
Quat_ operator/(Real rhs) const
Definition: Quat.h:174
Quat_ operator-(const Quat_ &rhs) const
Definition: Quat.h:148
Vec3 axisY() const
Definition: Quat.cpp:284
Matrix4 & toMatrix(Matrix4 &rot, bool b3x3=false) const
Convert quaternion to 4x4 homogeneous rotation matrix. Set b3x3 to true to store the result only in t...
Definition: Quat.cpp:422
Interpolation math.
Definition: Quat.h:10
Quat_(const Vec3 &axis, Real angle)
Construct from axis and angle in radians.
Definition: Quat.h:111
Quat_ ln() const
Definition: Quat.cpp:237
Quat_ operator*(Real rhs) const
Definition: Quat.h:169
Quat_ normalize(optional< Real & > len=optnull) const
Get unit quaternion. The pre-normalized length will be returned in len if specified.
Definition: Quat.h:213
Vec3 eulerAngles() const
Get euler angles in radians and order xyz_s
Definition: Quat.cpp:354
Quat_ & fromMatrix(const Matrix4 &rot)
Construct from 4x4 homogeneous matrix. Rotation is extracted from upper-left 3x3 submatrix.
Definition: Quat.cpp:91
static Real sqrt(Real x)
Square Root.
Definition: Alge.h:63
Quat_(Real x, Real y, Real z, Real w)
Construct with imaginary vector components x,y,z and real scalar component w.
Definition: Quat.h:109
Real & operator[](int i)
Definition: Quat.h:182
Quat_ operator+(const Quat_ &rhs) const
Definition: Quat.h:144
Quat_ & operator/=(Real rhs)
Definition: Quat.h:176
Quat_(const Vec3 &eulerAngles, EulerOrder order)
Construct from euler angles in order.
Definition: Quat.h:119
Real dot(const Quat_ &q) const
Definition: Quat.h:188
Real w
Definition: Quat.h:344
Quat_(const Vec3 &from, const Vec3 &to)
Construct a quaternion that rotates unit vector from towards unit vector to.
Definition: Quat.h:115
static Quat_ squad(Real t, const Quat_ &q1, const Quat_ &a, const Quat_ &b, const Quat_ &c)
Spherical quadratic interpolation between q1 and c. t ranges from [0,1].
Definition: Quat.cpp:487
Real y
Definition: Quat.h:342
Quat_()
Construct with identity.
Definition: Quat.h:107
Vec3 axisX() const
Get quaternion's rotated unit axis.
Definition: Quat.cpp:268
Quat_ & operator*=(Real rhs)
Definition: Quat.h:171
static std::common_type< Num, Num2, Num3 >::type clamp(Num val, Num2 min, Num3 max)
Ensure that a number is within a range.
Definition: Alge.h:99
Quat_(const Vec3 &eulerAngles)
Construct from euler angles in radians and order xyz_s
Definition: Quat.h:117
Quat_ inverse() const
Assumes that quaternion is unit length, same as conjugate()
Definition: Quat.h:191
Quat_ & operator/=(const Quat_ &rhs)
Definition: Quat.h:175
#define assert(...)
Forwards to assert_#args. See assert_1(), assert_2().
Definition: Debug.h:24
Quat_ & fromAxes(const Vec3 &axisX, const Vec3 &axisY, const Vec3 &axisZ)
Construct from 3 unit vectors.
Definition: Quat.cpp:133
bool operator!=(const Quat_ &rhs) const
Definition: Quat.h:141
static const Quat_ identity
Definition: Quat.h:347
Real length() const
Definition: Quat.h:210
Quat_ & fromIdentity()
Set quaternion to identity.
Definition: Quat.h:126
Numeric type information, use numeral() to get instance safely from a static context.
Definition: Numeral.h:17
Vec3 axisZ() const
Definition: Quat.cpp:300
Quat_(const Vec3 &axisX, const Vec3 &axisY, const Vec3 &axisZ)
Construct from 3 unit vectors.
Definition: Quat.h:113
Enables any type to be optional so it can exist in an uninitialized null state.
Definition: Optional.h:52
Quat_ & fromAxisAngle(const Vec3 &axis, Real angle)
Construct from axis and angle in radians.
Definition: Quat.cpp:14
Quat_ conjugate() const
Definition: Quat.h:189
Real x
Definition: Quat.h:341
Quat_ & fromAlign(const Vec3 &v1, const Vec3 &v2)
Construct a quaternion that rotates unit vector v1 towards unit vector v2. The resulting quat's axis ...
Definition: Quat.cpp:143
Quat_< Double > Quat_d
Definition: Quat.h:355
Quat_< Real > Quat
Definition: Quat.h:353
Real__ Real
Definition: Quat.h:22
Quat_ operator/(const Quat_ &rhs) const
Definition: Quat.h:173
Quaternion rotation class. Represents a counter-clockwise rotation of an angle about its axis...
Definition: Matrix4.h:10
Quat_ operator+() const
Definition: Quat.h:143
static const int dim
Definition: Quat.h:47
friend Quat_ operator*(Real lhs, const Quat_ &rhs)
Definition: Quat.h:178
Quat_< Float > Quat_f
Definition: Quat.h:354
void axisAngle(Vec3 &axis, Real &angle) const
Get quaternion axis and angle in radians.
Definition: Quat.cpp:326
Quat_ & fromZero()
Set quaternion to zero.
Definition: Quat.h:124
Real lengthSqr() const
Square of the length.
Definition: Quat.h:209
Real z
Definition: Quat.h:343
#define _ORD(i, p, r, f)
Definition: Quat.h:65
bool operator==(const Quat_ &rhs) const
Definition: Quat.h:140
Quat_(const Matrix4 &rot)
Construct from 4x4 homogeneous matrix. Rotation is extracted from upper-left 3x3 submatrix.
Definition: Quat.h:121
Vec3 operator*(const Vec3 &rhs) const
Definition: Quat.h:159
static const Quat_ zero
Definition: Quat.h:346
Quat_ inverseNonUnit() const
Proper quaternion inverse. Only use if quaternion is expected to be non-unit length.
Definition: Quat.h:194
friend ostream & operator<<(ostream &os, const Quat_ &val)
Definition: Quat.h:286
static void squadSetup(const Quat_ &q0, const Quat_ &q1, const Quat_ &q2, const Quat_ &q3, Quat_ &a, Quat_ &b, Quat_ &c)
Calc intermediate quats required for Squad. Ex. To interpolate between q1 and q2: setup(q0...
Definition: Quat.cpp:472
Global Honeycomb namespace.
Quat_ exp() const
Definition: Quat.cpp:205
Quat_ & operator+=(const Quat_ &rhs)
Definition: Quat.h:145
static Quat_ baryCentric(Real f, Real g, const Quat_ &q0, const Quat_ &q1, const Quat_ &q2)
Triangular bary-centric interpolation.
Definition: Quat.cpp:496
static Quat_ slerp(Real t, const Quat_ &q0, const Quat_ &q1)
Spherical linear interpolation from q0 to q1. t ranges from [0,1].
Definition: Quat.h:262
Trigonometry.
Definition: Trig.h:52
void axes(Vec3 &axisX, Vec3 &axisY, Vec3 &axisZ) const
Get unit axes that represent this quaternion.
Definition: Quat.cpp:316
Quat_ sqrt() const
Definition: Quat.h:207