]> git.mxchange.org Git - simgear.git/blob - simgear/math/SGQuat.hxx
1ac86fe58310bd6857b2f7aa59935de2e15ada7f
[simgear.git] / simgear / math / SGQuat.hxx
1 // Copyright (C) 2006  Mathias Froehlich - Mathias.Froehlich@web.de
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Library General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16 //
17
18 #ifndef SGQuat_H
19 #define SGQuat_H
20
21 /// 3D Vector Class
22 template<typename T>
23 class SGQuat {
24 public:
25   typedef T value_type;
26
27   /// Default constructor. Does not initialize at all.
28   /// If you need them zero initialized, SGQuat::zeros()
29   SGQuat(void)
30   {
31     /// Initialize with nans in the debug build, that will guarantee to have
32     /// a fast uninitialized default constructor in the release but shows up
33     /// uninitialized values in the debug build very fast ...
34 #ifndef NDEBUG
35     for (unsigned i = 0; i < 4; ++i)
36       _data[i] = SGLimits<T>::quiet_NaN();
37 #endif
38   }
39   /// Constructor. Initialize by the given values
40   SGQuat(T _x, T _y, T _z, T _w)
41   { x() = _x; y() = _y; z() = _z; w() = _w; }
42   /// Constructor. Initialize by the content of a plain array,
43   /// make sure it has at least 4 elements
44   explicit SGQuat(const T* d)
45   { _data[0] = d[0]; _data[1] = d[1]; _data[2] = d[2]; _data[3] = d[3]; }
46
47   /// Return a unit quaternion
48   static SGQuat unit(void)
49   { return fromRealImag(1, SGVec3<T>(0)); }
50
51   /// Return a quaternion from euler angles
52   static SGQuat fromEulerRad(T z, T y, T x)
53   {
54     SGQuat q;
55     T zd2 = T(0.5)*z; T yd2 = T(0.5)*y; T xd2 = T(0.5)*x;
56     T Szd2 = sin(zd2); T Syd2 = sin(yd2); T Sxd2 = sin(xd2);
57     T Czd2 = cos(zd2); T Cyd2 = cos(yd2); T Cxd2 = cos(xd2);
58     T Cxd2Czd2 = Cxd2*Czd2; T Cxd2Szd2 = Cxd2*Szd2;
59     T Sxd2Szd2 = Sxd2*Szd2; T Sxd2Czd2 = Sxd2*Czd2;
60     q.w() = Cxd2Czd2*Cyd2 + Sxd2Szd2*Syd2;
61     q.x() = Sxd2Czd2*Cyd2 - Cxd2Szd2*Syd2;
62     q.y() = Cxd2Czd2*Syd2 + Sxd2Szd2*Cyd2;
63     q.z() = Cxd2Szd2*Cyd2 - Sxd2Czd2*Syd2;
64     return q;
65   }
66
67   /// Return a quaternion from euler angles in degrees
68   static SGQuat fromEulerDeg(T z, T y, T x)
69   {
70     return fromEulerRad(SGMisc<T>::deg2rad(z), SGMisc<T>::deg2rad(y),
71                         SGMisc<T>::deg2rad(x));
72   }
73
74   /// Return a quaternion from euler angles
75   static SGQuat fromYawPitchRoll(T y, T p, T r)
76   { return fromEulerRad(y, p, r); }
77
78   /// Return a quaternion from euler angles
79   static SGQuat fromYawPitchRollDeg(T y, T p, T r)
80   { return fromEulerDeg(y, p, r); }
81
82   /// Return a quaternion from euler angles
83   static SGQuat fromHeadAttBank(T h, T a, T b)
84   { return fromEulerRad(h, a, b); }
85
86   /// Return a quaternion from euler angles
87   static SGQuat fromHeadAttBankDeg(T h, T a, T b)
88   { return fromEulerDeg(h, a, b); }
89
90   /// Return a quaternion rotation the the horizontal local frame from given
91   /// longitude and latitude
92   static SGQuat fromLonLatRad(T lon, T lat)
93   {
94     SGQuat q;
95     T zd2 = T(0.5)*lon;
96     T yd2 = T(-0.25)*SGMisc<value_type>::pi() - T(0.5)*lat;
97     T Szd2 = sin(zd2);
98     T Syd2 = sin(yd2);
99     T Czd2 = cos(zd2);
100     T Cyd2 = cos(yd2);
101     q.w() = Czd2*Cyd2;
102     q.x() = -Szd2*Syd2;
103     q.y() = Czd2*Syd2;
104     q.z() = Szd2*Cyd2;
105     return q;
106   }
107
108   /// Return a quaternion rotation the the horizontal local frame from given
109   /// longitude and latitude
110   static SGQuat fromLonLatDeg(T lon, T lat)
111   { return fromLonLatRad(SGMisc<T>::deg2rad(lon), SGMisc<T>::deg2rad(lat)); }
112
113   /// Return a quaternion rotation the the horizontal local frame from given
114   /// longitude and latitude
115   static SGQuat fromLonLat(const SGGeod& geod)
116   { return fromLonLatRad(geod.getLongitudeRad(), geod.getLatitudeRad()); }
117
118   /// Create a quaternion from the angle axis representation
119   static SGQuat fromAngleAxis(T angle, const SGVec3<T>& axis)
120   {
121     T angle2 = 0.5*angle;
122     return fromRealImag(cos(angle2), T(sin(angle2))*axis);
123   }
124
125   /// Create a quaternion from the angle axis representation
126   static SGQuat fromAngleAxisDeg(T angle, const SGVec3<T>& axis)
127   { return fromAngleAxis(SGMisc<T>::deg2rad(angle), axis); }
128
129   /// Create a quaternion from the angle axis representation where the angle
130   /// is stored in the axis' length
131   static SGQuat fromAngleAxis(const SGVec3<T>& axis)
132   {
133     T nAxis = norm(axis);
134     if (nAxis <= SGLimits<T>::min())
135       return SGQuat(1, 0, 0, 0);
136     T angle2 = 0.5*nAxis;
137     return fromRealImag(cos(angle2), T(sin(angle2)/nAxis)*axis);
138   }
139
140   /// Return a quaternion from real and imaginary part
141   static SGQuat fromRealImag(T r, const SGVec3<T>& i)
142   {
143     SGQuat q;
144     q.w() = r;
145     q.x() = i(0);
146     q.y() = i(1);
147     q.z() = i(2);
148     return q;
149   }
150
151   /// Return an all zero vector
152   static SGQuat zeros(void)
153   { return SGQuat(0, 0, 0, 0); }
154
155   /// write the euler angles into the references
156   void getEulerRad(T& zRad, T& yRad, T& xRad) const
157   {
158     value_type sqrQW = w()*w();
159     value_type sqrQX = x()*x();
160     value_type sqrQY = y()*y();
161     value_type sqrQZ = z()*z();
162
163     value_type num = 2*(y()*z() + w()*x());
164     value_type den = sqrQW - sqrQX - sqrQY + sqrQZ;
165     if (fabs(den) < SGLimits<value_type>::min() &&
166         fabs(num) < SGLimits<value_type>::min())
167       xRad = 0;
168     else
169       xRad = atan2(num, den);
170     
171     value_type tmp = 2*(x()*z() - w()*y());
172     if (tmp < -1)
173       yRad = 0.5*SGMisc<value_type>::pi();
174     else if (1 < tmp)
175       yRad = -0.5*SGMisc<value_type>::pi();
176     else
177       yRad = -asin(tmp);
178    
179     num = 2*(x()*y() + w()*z()); 
180     den = sqrQW + sqrQX - sqrQY - sqrQZ;
181     if (fabs(den) < SGLimits<value_type>::min() &&
182         fabs(num) < SGLimits<value_type>::min())
183       zRad = 0;
184     else {
185       value_type psi = atan2(num, den);
186       if (psi < 0)
187         psi += 2*SGMisc<value_type>::pi();
188       zRad = psi;
189     }
190   }
191
192   /// write the euler angles in degrees into the references
193   void getEulerDeg(T& zDeg, T& yDeg, T& xDeg) const
194   {
195     getEulerRad(zDeg, yDeg, xDeg);
196     zDeg = SGMisc<T>::rad2deg(zDeg);
197     yDeg = SGMisc<T>::rad2deg(yDeg);
198     xDeg = SGMisc<T>::rad2deg(xDeg);
199   }
200
201   /// write the angle axis representation into the references
202   void getAngleAxis(T& angle, SGVec3<T>& axis) const
203   {
204     T nrm = norm(*this);
205     if (nrm < SGLimits<T>::min()) {
206       angle = 0;
207       axis = SGVec3<T>(0, 0, 0);
208     } else {
209       T rNrm = 1/nrm;
210       angle = acos(SGMisc<T>::max(-1, SGMisc<T>::min(1, rNrm*w())));
211       T sAng = sin(angle);
212       if (fabs(sAng) < SGLimits<T>::min())
213         axis = SGVec3<T>(1, 0, 0);
214       else 
215         axis = (rNrm/sAng)*imag(*this);
216       angle *= 2;
217     }
218   }
219
220   /// write the angle axis representation into the references
221   void getAngleAxis(SGVec3<T>& axis) const
222   {
223     T angle;
224     getAngleAxis(angle, axis);
225     axis *= angle;
226   }
227
228   /// Access by index, the index is unchecked
229   const T& operator()(unsigned i) const
230   { return _data[i]; }
231   /// Access by index, the index is unchecked
232   T& operator()(unsigned i)
233   { return _data[i]; }
234
235   /// Access raw data by index, the index is unchecked
236   const T& operator[](unsigned i) const
237   { return _data[i]; }
238   /// Access raw data by index, the index is unchecked
239   T& operator[](unsigned i)
240   { return _data[i]; }
241
242   /// Access the x component
243   const T& x(void) const
244   { return _data[0]; }
245   /// Access the x component
246   T& x(void)
247   { return _data[0]; }
248   /// Access the y component
249   const T& y(void) const
250   { return _data[1]; }
251   /// Access the y component
252   T& y(void)
253   { return _data[1]; }
254   /// Access the z component
255   const T& z(void) const
256   { return _data[2]; }
257   /// Access the z component
258   T& z(void)
259   { return _data[2]; }
260   /// Access the w component
261   const T& w(void) const
262   { return _data[3]; }
263   /// Access the w component
264   T& w(void)
265   { return _data[3]; }
266
267   /// Get the data pointer, usefull for interfacing with plib's sg*Vec
268   const T* data(void) const
269   { return _data; }
270   /// Get the data pointer, usefull for interfacing with plib's sg*Vec
271   T* data(void)
272   { return _data; }
273
274   /// Readonly interface function to ssg's sgQuat/sgdQuat
275   const T (&sg(void) const)[4]
276   { return _data; }
277   /// Interface function to ssg's sgQuat/sgdQuat
278   T (&sg(void))[4]
279   { return _data; }
280
281   /// Inplace addition
282   SGQuat& operator+=(const SGQuat& v)
283   { _data[0]+=v(0);_data[1]+=v(1);_data[2]+=v(2);_data[3]+=v(3);return *this; }
284   /// Inplace subtraction
285   SGQuat& operator-=(const SGQuat& v)
286   { _data[0]-=v(0);_data[1]-=v(1);_data[2]-=v(2);_data[3]-=v(3);return *this; }
287   /// Inplace scalar multiplication
288   template<typename S>
289   SGQuat& operator*=(S s)
290   { _data[0] *= s; _data[1] *= s; _data[2] *= s; _data[3] *= s; return *this; }
291   /// Inplace scalar multiplication by 1/s
292   template<typename S>
293   SGQuat& operator/=(S s)
294   { return operator*=(1/T(s)); }
295   /// Inplace quaternion multiplication
296   SGQuat& operator*=(const SGQuat& v);
297
298   /// Transform a vector from the current coordinate frame to a coordinate
299   /// frame rotated with the quaternion
300   SGVec3<T> transform(const SGVec3<T>& v) const
301   {
302     value_type r = 2/dot(*this, *this);
303     SGVec3<T> qimag = imag(*this);
304     value_type qr = real(*this);
305     return (r*qr*qr - 1)*v + (r*dot(qimag, v))*qimag - (r*qr)*cross(qimag, v);
306   }
307   /// Transform a vector from the coordinate frame rotated with the quaternion
308   /// to the current coordinate frame
309   SGVec3<T> backTransform(const SGVec3<T>& v) const
310   {
311     value_type r = 2/dot(*this, *this);
312     SGVec3<T> qimag = imag(*this);
313     value_type qr = real(*this);
314     return (r*qr*qr - 1)*v + (r*dot(qimag, v))*qimag + (r*qr)*cross(qimag, v);
315   }
316
317   /// Rotate a given vector with the quaternion
318   SGVec3<T> rotate(const SGVec3<T>& v) const
319   { return backTransform(v); }
320   /// Rotate a given vector with the inverse quaternion
321   SGVec3<T> rotateBack(const SGVec3<T>& v) const
322   { return transform(v); }
323
324   /// Return the time derivative of the quaternion given the angular velocity
325   SGQuat
326   derivative(const SGVec3<T>& angVel)
327   {
328     SGQuat deriv;
329
330     deriv.w() = 0.5*(-x()*angVel(0) - y()*angVel(1) - z()*angVel(2));
331     deriv.x() = 0.5*( w()*angVel(0) - z()*angVel(1) + y()*angVel(2));
332     deriv.y() = 0.5*( z()*angVel(0) + w()*angVel(1) - x()*angVel(2));
333     deriv.z() = 0.5*(-y()*angVel(0) + x()*angVel(1) + w()*angVel(2));
334     
335     return deriv;
336   }
337
338 private:
339   /// The actual data
340   T _data[4];
341 };
342
343 /// Unary +, do nothing ...
344 template<typename T>
345 inline
346 const SGQuat<T>&
347 operator+(const SGQuat<T>& v)
348 { return v; }
349
350 /// Unary -, do nearly nothing
351 template<typename T>
352 inline
353 SGQuat<T>
354 operator-(const SGQuat<T>& v)
355 { return SGQuat<T>(-v(0), -v(1), -v(2), -v(3)); }
356
357 /// Binary +
358 template<typename T>
359 inline
360 SGQuat<T>
361 operator+(const SGQuat<T>& v1, const SGQuat<T>& v2)
362 { return SGQuat<T>(v1(0)+v2(0), v1(1)+v2(1), v1(2)+v2(2), v1(3)+v2(3)); }
363
364 /// Binary -
365 template<typename T>
366 inline
367 SGQuat<T>
368 operator-(const SGQuat<T>& v1, const SGQuat<T>& v2)
369 { return SGQuat<T>(v1(0)-v2(0), v1(1)-v2(1), v1(2)-v2(2), v1(3)-v2(3)); }
370
371 /// Scalar multiplication
372 template<typename S, typename T>
373 inline
374 SGQuat<T>
375 operator*(S s, const SGQuat<T>& v)
376 { return SGQuat<T>(s*v(0), s*v(1), s*v(2), s*v(3)); }
377
378 /// Scalar multiplication
379 template<typename S, typename T>
380 inline
381 SGQuat<T>
382 operator*(const SGQuat<T>& v, S s)
383 { return SGQuat<T>(s*v(0), s*v(1), s*v(2), s*v(3)); }
384
385 /// Quaterion multiplication
386 template<typename T>
387 inline
388 SGQuat<T>
389 operator*(const SGQuat<T>& v1, const SGQuat<T>& v2)
390 {
391   SGQuat<T> v;
392   v.x() = v1.w()*v2.x() + v1.x()*v2.w() + v1.y()*v2.z() - v1.z()*v2.y();
393   v.y() = v1.w()*v2.y() - v1.x()*v2.z() + v1.y()*v2.w() + v1.z()*v2.x();
394   v.z() = v1.w()*v2.z() + v1.x()*v2.y() - v1.y()*v2.x() + v1.z()*v2.w();
395   v.w() = v1.w()*v2.w() - v1.x()*v2.x() - v1.y()*v2.y() - v1.z()*v2.z();
396   return v;
397 }
398
399 /// Now define the inplace multiplication
400 template<typename T>
401 inline
402 SGQuat<T>&
403 SGQuat<T>::operator*=(const SGQuat& v)
404 { (*this) = (*this)*v; return *this; }
405
406 /// The conjugate of the quaternion, this is also the
407 /// inverse for normalized quaternions
408 template<typename T>
409 inline
410 SGQuat<T>
411 conj(const SGQuat<T>& v)
412 { return SGQuat<T>(-v(0), -v(1), -v(2), v(3)); }
413
414 /// The conjugate of the quaternion, this is also the
415 /// inverse for normalized quaternions
416 template<typename T>
417 inline
418 SGQuat<T>
419 inverse(const SGQuat<T>& v)
420 { return (1/dot(v, v))*SGQuat<T>(-v(0), -v(1), -v(2), v(3)); }
421
422 /// The imagniary part of the quaternion
423 template<typename T>
424 inline
425 T
426 real(const SGQuat<T>& v)
427 { return v.w(); }
428
429 /// The imagniary part of the quaternion
430 template<typename T>
431 inline
432 SGVec3<T>
433 imag(const SGQuat<T>& v)
434 { return SGVec3<T>(v.x(), v.y(), v.z()); }
435
436 /// Scalar dot product
437 template<typename T>
438 inline
439 T
440 dot(const SGQuat<T>& v1, const SGQuat<T>& v2)
441 { return v1(0)*v2(0) + v1(1)*v2(1) + v1(2)*v2(2) + v1(3)*v2(3); }
442
443 /// The euclidean norm of the vector, that is what most people call length
444 template<typename T>
445 inline
446 T
447 norm(const SGQuat<T>& v)
448 { return sqrt(dot(v, v)); }
449
450 /// The euclidean norm of the vector, that is what most people call length
451 template<typename T>
452 inline
453 T
454 length(const SGQuat<T>& v)
455 { return sqrt(dot(v, v)); }
456
457 /// The 1-norm of the vector, this one is the fastest length function we
458 /// can implement on modern cpu's
459 template<typename T>
460 inline
461 T
462 norm1(const SGQuat<T>& v)
463 { return fabs(v(0)) + fabs(v(1)) + fabs(v(2)) + fabs(v(3)); }
464
465 /// The euclidean norm of the vector, that is what most people call length
466 template<typename T>
467 inline
468 SGQuat<T>
469 normalize(const SGQuat<T>& q)
470 { return (1/norm(q))*q; }
471
472 /// Return true if exactly the same
473 template<typename T>
474 inline
475 bool
476 operator==(const SGQuat<T>& v1, const SGQuat<T>& v2)
477 { return v1(0)==v2(0) && v1(1)==v2(1) && v1(2)==v2(2) && v1(3)==v2(3); }
478
479 /// Return true if not exactly the same
480 template<typename T>
481 inline
482 bool
483 operator!=(const SGQuat<T>& v1, const SGQuat<T>& v2)
484 { return ! (v1 == v2); }
485
486 /// Return true if equal to the relative tolerance tol
487 /// Note that this is not the same than comparing quaternions to represent
488 /// the same rotation
489 template<typename T>
490 inline
491 bool
492 equivalent(const SGQuat<T>& v1, const SGQuat<T>& v2, T tol)
493 { return norm1(v1 - v2) < tol*(norm1(v1) + norm1(v2)); }
494
495 /// Return true if about equal to roundoff of the underlying type
496 /// Note that this is not the same than comparing quaternions to represent
497 /// the same rotation
498 template<typename T>
499 inline
500 bool
501 equivalent(const SGQuat<T>& v1, const SGQuat<T>& v2)
502 { return equivalent(v1, v2, 100*SGLimits<T>::epsilon()); }
503
504 #ifndef NDEBUG
505 template<typename T>
506 inline
507 bool
508 isNaN(const SGQuat<T>& v)
509 {
510   return SGMisc<T>::isNaN(v(0)) || SGMisc<T>::isNaN(v(1))
511     || SGMisc<T>::isNaN(v(2)) || SGMisc<T>::isNaN(v(3));
512 }
513 #endif
514
515 /// quaternion interpolation for t in [0,1] interpolate between src (=0)
516 /// and dst (=1)
517 template<typename T>
518 inline
519 SGQuat<T>
520 interpolate(T t, const SGQuat<T>& src, const SGQuat<T>& dst)
521 {
522   T cosPhi = dot(src, dst);
523   // need to take the shorter way ...
524   int signCosPhi = SGMisc<T>::sign(cosPhi);
525   // cosPhi must be corrected for that sign
526   cosPhi = fabs(cosPhi);
527
528   // first opportunity to fail - make sure acos will succeed later -
529   // result is correct
530   if (1 <= cosPhi)
531     return dst;
532
533   // now the half angle between the orientations
534   T o = acos(cosPhi);
535
536   // need the scales now, if the angle is very small, do linear interpolation
537   // to avoid instabilities
538   T scale0, scale1;
539   if (fabs(o) < SGLimits<T>::epsilon()) {
540     scale0 = 1 - t;
541     scale1 = t;
542   } else {
543     // note that we can give a positive lower bound for sin(o) here
544     T sino = sin(o);
545     T so = 1/sino;
546     scale0 = sin((1 - t)*o)*so;
547     scale1 = sin(t*o)*so;
548   }
549
550   return scale0*src + signCosPhi*scale1*dst;
551 }
552
553 /// Output to an ostream
554 template<typename char_type, typename traits_type, typename T>
555 inline
556 std::basic_ostream<char_type, traits_type>&
557 operator<<(std::basic_ostream<char_type, traits_type>& s, const SGQuat<T>& v)
558 { return s << "[ " << v(0) << ", " << v(1) << ", " << v(2) << ", " << v(3) << " ]"; }
559
560 inline
561 SGQuatf
562 toQuatf(const SGQuatd& v)
563 { return SGQuatf((float)v(0), (float)v(1), (float)v(2), (float)v(3)); }
564
565 inline
566 SGQuatd
567 toQuatd(const SGQuatf& v)
568 { return SGQuatd(v(0), v(1), v(2), v(3)); }
569
570 #endif