]> git.mxchange.org Git - simgear.git/blob - simgear/math/SGQuat.hxx
Merge branch 'maint' into next
[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 #ifdef min
22 #undef min
23 #endif
24
25 #ifdef max
26 #undef max
27 #endif
28
29 #include <osg/Quat>
30
31 template<typename T>
32 struct SGQuatStorage {
33   /// Readonly raw storage interface
34   const T (&data(void) const)[4]
35   { return _data; }
36   /// Readonly raw storage interface
37   T (&data(void))[4]
38   { return _data; }
39
40   void osg() const
41   { }
42
43 private:
44   T _data[4];
45 };
46
47 template<>
48 struct SGQuatStorage<double> : public osg::Quat {
49   /// Access raw data by index, the index is unchecked
50   const double (&data(void) const)[4]
51   { return osg::Quat::_v; }
52   /// Access raw data by index, the index is unchecked
53   double (&data(void))[4]
54   { return osg::Quat::_v; }
55
56   const osg::Quat& osg() const
57   { return *this; }
58   osg::Quat& osg()
59   { return *this; }
60 };
61
62 /// 3D Vector Class
63 template<typename T>
64 class SGQuat : protected SGQuatStorage<T> {
65 public:
66   typedef T value_type;
67
68   /// Default constructor. Does not initialize at all.
69   /// If you need them zero initialized, SGQuat::zeros()
70   SGQuat(void)
71   {
72     /// Initialize with nans in the debug build, that will guarantee to have
73     /// a fast uninitialized default constructor in the release but shows up
74     /// uninitialized values in the debug build very fast ...
75 #ifndef NDEBUG
76     for (unsigned i = 0; i < 4; ++i)
77       data()[i] = SGLimits<T>::quiet_NaN();
78 #endif
79   }
80   /// Constructor. Initialize by the given values
81   SGQuat(T _x, T _y, T _z, T _w)
82   { x() = _x; y() = _y; z() = _z; w() = _w; }
83   /// Constructor. Initialize by the content of a plain array,
84   /// make sure it has at least 4 elements
85   explicit SGQuat(const T* d)
86   { data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; data()[3] = d[3]; }
87   explicit SGQuat(const osg::Quat& d)
88   { data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; data()[3] = d[3]; }
89
90   /// Return a unit quaternion
91   static SGQuat unit(void)
92   { return fromRealImag(1, SGVec3<T>(0, 0, 0)); }
93
94   /// Return a quaternion from euler angles
95   static SGQuat fromEulerRad(T z, T y, T x)
96   {
97     SGQuat q;
98     T zd2 = T(0.5)*z; T yd2 = T(0.5)*y; T xd2 = T(0.5)*x;
99     T Szd2 = sin(zd2); T Syd2 = sin(yd2); T Sxd2 = sin(xd2);
100     T Czd2 = cos(zd2); T Cyd2 = cos(yd2); T Cxd2 = cos(xd2);
101     T Cxd2Czd2 = Cxd2*Czd2; T Cxd2Szd2 = Cxd2*Szd2;
102     T Sxd2Szd2 = Sxd2*Szd2; T Sxd2Czd2 = Sxd2*Czd2;
103     q.w() = Cxd2Czd2*Cyd2 + Sxd2Szd2*Syd2;
104     q.x() = Sxd2Czd2*Cyd2 - Cxd2Szd2*Syd2;
105     q.y() = Cxd2Czd2*Syd2 + Sxd2Szd2*Cyd2;
106     q.z() = Cxd2Szd2*Cyd2 - Sxd2Czd2*Syd2;
107     return q;
108   }
109
110   /// Return a quaternion from euler angles in degrees
111   static SGQuat fromEulerDeg(T z, T y, T x)
112   {
113     return fromEulerRad(SGMisc<T>::deg2rad(z), SGMisc<T>::deg2rad(y),
114                         SGMisc<T>::deg2rad(x));
115   }
116
117   /// Return a quaternion from euler angles
118   static SGQuat fromYawPitchRoll(T y, T p, T r)
119   { return fromEulerRad(y, p, r); }
120
121   /// Return a quaternion from euler angles
122   static SGQuat fromYawPitchRollDeg(T y, T p, T r)
123   { return fromEulerDeg(y, p, r); }
124
125   /// Return a quaternion from euler angles
126   static SGQuat fromHeadAttBank(T h, T a, T b)
127   { return fromEulerRad(h, a, b); }
128
129   /// Return a quaternion from euler angles
130   static SGQuat fromHeadAttBankDeg(T h, T a, T b)
131   { return fromEulerDeg(h, a, b); }
132
133   /// Return a quaternion rotation from the earth centered to the
134   /// simulation usual horizontal local frame from given
135   /// longitude and latitude.
136   /// The horizontal local frame used in simulations is the frame with x-axis
137   /// pointing north, the y-axis pointing eastwards and the z axis
138   /// pointing downwards.
139   static SGQuat fromLonLatRad(T lon, T lat)
140   {
141     SGQuat q;
142     T zd2 = T(0.5)*lon;
143     T yd2 = T(-0.25)*SGMisc<T>::pi() - T(0.5)*lat;
144     T Szd2 = sin(zd2);
145     T Syd2 = sin(yd2);
146     T Czd2 = cos(zd2);
147     T Cyd2 = cos(yd2);
148     q.w() = Czd2*Cyd2;
149     q.x() = -Szd2*Syd2;
150     q.y() = Czd2*Syd2;
151     q.z() = Szd2*Cyd2;
152     return q;
153   }
154   /// Like the above provided for convenience
155   static SGQuat fromLonLatDeg(T lon, T lat)
156   { return fromLonLatRad(SGMisc<T>::deg2rad(lon), SGMisc<T>::deg2rad(lat)); }
157   /// Like the above provided for convenience
158   static SGQuat fromLonLat(const SGGeod& geod)
159   { return fromLonLatRad(geod.getLongitudeRad(), geod.getLatitudeRad()); }
160
161   /// Return a quaternion rotation from the earth centered to the
162   /// OpenGL/viewer horizontal local frame from given longitude and latitude.
163   /// This frame matches the usual OpenGL axis directions. That is the target
164   /// frame has an x-axis pointing eastwards, y-axis pointing up and y z-axis
165   /// pointing south.
166   static SGQuat viewHLRad(T lon, T lat)
167   {
168     // That bails down to a 3-2-1 euler sequence lon+pi/2, 0, -lat-pi
169     // what is here is again the hand optimized version ...
170     SGQuat q;
171     T xd2 = -T(0.5)*lat - T(0.5)*SGMisc<T>::pi();
172     T zd2 = T(0.5)*lon + T(0.25)*SGMisc<T>::pi();
173     T Szd2 = sin(zd2);
174     T Sxd2 = sin(xd2);
175     T Czd2 = cos(zd2);
176     T Cxd2 = cos(xd2);
177     q.w() = Cxd2*Czd2;
178     q.x() = Sxd2*Czd2;
179     q.y() = Sxd2*Szd2;
180     q.z() = Cxd2*Szd2;
181     return q;
182   }
183   /// Like the above provided for convenience
184   static SGQuat viewHLDeg(T lon, T lat)
185   { return viewHLRad(SGMisc<T>::deg2rad(lon), SGMisc<T>::deg2rad(lat)); }
186   /// Like the above provided for convenience
187   static SGQuat viewHL(const SGGeod& geod)
188   { return viewHLRad(geod.getLongitudeRad(), geod.getLatitudeRad()); }
189
190   /// Convert a quaternion rotation from the simulation frame
191   /// to the view (OpenGL) frame. That is it just swaps the axis part of
192   /// this current quaternion.
193   /// That proves useful when you want to use the euler 3-2-1 sequence
194   /// for the usual heading/pitch/roll sequence within the context of
195   /// OpenGL/viewer frames.
196   static SGQuat simToView(const SGQuat& q)
197   { return SGQuat(q.y(), -q.z(), -q.x(), q.w()); }
198
199   /// Create a quaternion from the angle axis representation
200   static SGQuat fromAngleAxis(T angle, const SGVec3<T>& axis)
201   {
202     T angle2 = 0.5*angle;
203     return fromRealImag(cos(angle2), T(sin(angle2))*axis);
204   }
205
206   /// Create a quaternion from the angle axis representation
207   static SGQuat fromAngleAxisDeg(T angle, const SGVec3<T>& axis)
208   { return fromAngleAxis(SGMisc<T>::deg2rad(angle), axis); }
209
210   /// Create a quaternion from the angle axis representation where the angle
211   /// is stored in the axis' length
212   static SGQuat fromAngleAxis(const SGVec3<T>& axis)
213   {
214     T nAxis = norm(axis);
215     if (nAxis <= SGLimits<T>::min())
216       return SGQuat(1, 0, 0, 0);
217     T angle2 = 0.5*nAxis;
218     return fromRealImag(cos(angle2), T(sin(angle2)/nAxis)*axis);
219   }
220
221   static SGQuat fromRotateTo(const SGVec3<T>& from, const SGVec3<T>& to)
222   {
223     T nfrom = norm(from);
224     T nto = norm(to);
225     if (nfrom < SGLimits<T>::min() || nto < SGLimits<T>::min())
226       return SGQuat::unit();
227
228     return SGQuat::fromRotateToNorm((1/nfrom)*from, (1/nto)*to);
229   }
230
231   // FIXME more finegrained error behavour.
232   static SGQuat fromRotateTo(const SGVec3<T>& v1, unsigned i1,
233                              const SGVec3<T>& v2, unsigned i2)
234   {
235     T nrmv1 = norm(v1);
236     T nrmv2 = norm(v2);
237     if (nrmv1 < SGLimits<T>::min() || nrmv2 < SGLimits<T>::min())
238       return SGQuat::unit();
239
240     SGVec3<T> nv1 = (1/nrmv1)*v1;
241     SGVec3<T> nv2 = (1/nrmv2)*v2;
242     T dv1v2 = dot(nv1, nv2);
243     if (fabs(fabs(dv1v2)-1) < SGLimits<T>::epsilon())
244       return SGQuat::unit();
245
246     // The target vector for the first rotation
247     SGVec3<T> nto1 = SGVec3<T>::zeros();
248     SGVec3<T> nto2 = SGVec3<T>::zeros();
249     nto1[i1] = 1;
250     nto2[i2] = 1;
251
252     // The first rotation can be done with the usual routine.
253     SGQuat q = SGQuat::fromRotateToNorm(nv1, nto1);
254
255     // The rotation axis for the second rotation is the
256     // target for the first one, so the rotation axis is nto1
257     // We need to get the angle.
258
259     // Make nv2 exactly orthogonal to nv1.
260     nv2 = normalize(nv2 - dv1v2*nv1);
261
262     SGVec3<T> tnv2 = q.transform(nv2);
263     T cosang = dot(nto2, tnv2);
264     T cos05ang = T(0.5+0.5*cosang);
265     if (cos05ang <= 0)
266       cosang = T(0);
267     cos05ang = sqrt(cos05ang);
268     T sig = dot(nto1, cross(nto2, tnv2));
269     T sin05ang = T(0.5-0.5*cosang);
270     if (sin05ang <= 0)
271       sin05ang = 0;
272     sin05ang = copysign(sqrt(sin05ang), sig);
273     q *= SGQuat::fromRealImag(cos05ang, sin05ang*nto1);
274
275     return q;
276   }
277
278
279   // Return a quaternion which rotates the vector given by v
280   // to the vector -v. Other directions are *not* preserved.
281   static SGQuat fromChangeSign(const SGVec3<T>& v)
282   {
283     // The vector from points to the oposite direction than to.
284     // Find a vector perpendicular to the vector to.
285     T absv1 = fabs(v(0));
286     T absv2 = fabs(v(1));
287     T absv3 = fabs(v(2));
288     
289     SGVec3<T> axis;
290     if (absv2 < absv1 && absv3 < absv1) {
291       T quot = v(1)/v(0);
292       axis = (1/sqrt(1+quot*quot))*SGVec3<T>(quot, -1, 0);
293     } else if (absv1 < absv2 && absv3 < absv2) {
294       T quot = v(2)/v(1);
295       axis = (1/sqrt(1+quot*quot))*SGVec3<T>(0, quot, -1);
296     } else if (absv1 < absv3 && absv2 < absv3) {
297       T quot = v(0)/v(2);
298       axis = (1/sqrt(1+quot*quot))*SGVec3<T>(-1, 0, quot);
299     } else {
300       // The all zero case.
301       return SGQuat::unit();
302     }
303
304     return SGQuat::fromRealImag(0, axis);
305   }
306
307   /// Return a quaternion from real and imaginary part
308   static SGQuat fromRealImag(T r, const SGVec3<T>& i)
309   {
310     SGQuat q;
311     q.w() = r;
312     q.x() = i.x();
313     q.y() = i.y();
314     q.z() = i.z();
315     return q;
316   }
317
318   /// Return an all zero vector
319   static SGQuat zeros(void)
320   { return SGQuat(0, 0, 0, 0); }
321
322   /// write the euler angles into the references
323   void getEulerRad(T& zRad, T& yRad, T& xRad) const
324   {
325     T sqrQW = w()*w();
326     T sqrQX = x()*x();
327     T sqrQY = y()*y();
328     T sqrQZ = z()*z();
329
330     T num = 2*(y()*z() + w()*x());
331     T den = sqrQW - sqrQX - sqrQY + sqrQZ;
332     if (fabs(den) < SGLimits<T>::min() &&
333         fabs(num) < SGLimits<T>::min())
334       xRad = 0;
335     else
336       xRad = atan2(num, den);
337     
338     T tmp = 2*(x()*z() - w()*y());
339     if (tmp < -1)
340       yRad = 0.5*SGMisc<T>::pi();
341     else if (1 < tmp)
342       yRad = -0.5*SGMisc<T>::pi();
343     else
344       yRad = -asin(tmp);
345    
346     num = 2*(x()*y() + w()*z()); 
347     den = sqrQW + sqrQX - sqrQY - sqrQZ;
348     if (fabs(den) < SGLimits<T>::min() &&
349         fabs(num) < SGLimits<T>::min())
350       zRad = 0;
351     else {
352       T psi = atan2(num, den);
353       if (psi < 0)
354         psi += 2*SGMisc<T>::pi();
355       zRad = psi;
356     }
357   }
358
359   /// write the euler angles in degrees into the references
360   void getEulerDeg(T& zDeg, T& yDeg, T& xDeg) const
361   {
362     getEulerRad(zDeg, yDeg, xDeg);
363     zDeg = SGMisc<T>::rad2deg(zDeg);
364     yDeg = SGMisc<T>::rad2deg(yDeg);
365     xDeg = SGMisc<T>::rad2deg(xDeg);
366   }
367
368   /// write the angle axis representation into the references
369   void getAngleAxis(T& angle, SGVec3<T>& axis) const
370   {
371     T nrm = norm(*this);
372     if (nrm < SGLimits<T>::min()) {
373       angle = 0;
374       axis = SGVec3<T>(0, 0, 0);
375     } else {
376       T rNrm = 1/nrm;
377       angle = acos(SGMisc<T>::max(-1, SGMisc<T>::min(1, rNrm*w())));
378       T sAng = sin(angle);
379       if (fabs(sAng) < SGLimits<T>::min())
380         axis = SGVec3<T>(1, 0, 0);
381       else 
382         axis = (rNrm/sAng)*imag(*this);
383       angle *= 2;
384     }
385   }
386
387   /// write the angle axis representation into the references
388   void getAngleAxis(SGVec3<T>& axis) const
389   {
390     T angle;
391     getAngleAxis(angle, axis);
392     axis *= angle;
393   }
394
395   /// Access by index, the index is unchecked
396   const T& operator()(unsigned i) const
397   { return data()[i]; }
398   /// Access by index, the index is unchecked
399   T& operator()(unsigned i)
400   { return data()[i]; }
401
402   /// Access raw data by index, the index is unchecked
403   const T& operator[](unsigned i) const
404   { return data()[i]; }
405   /// Access raw data by index, the index is unchecked
406   T& operator[](unsigned i)
407   { return data()[i]; }
408
409   /// Access the x component
410   const T& x(void) const
411   { return data()[0]; }
412   /// Access the x component
413   T& x(void)
414   { return data()[0]; }
415   /// Access the y component
416   const T& y(void) const
417   { return data()[1]; }
418   /// Access the y component
419   T& y(void)
420   { return data()[1]; }
421   /// Access the z component
422   const T& z(void) const
423   { return data()[2]; }
424   /// Access the z component
425   T& z(void)
426   { return data()[2]; }
427   /// Access the w component
428   const T& w(void) const
429   { return data()[3]; }
430   /// Access the w component
431   T& w(void)
432   { return data()[3]; }
433
434   /// Get the data pointer
435   using SGQuatStorage<T>::data;
436
437   /// Readonly interface function to ssg's sgQuat/sgdQuat
438   const T (&sg(void) const)[4]
439   { return data(); }
440   /// Interface function to ssg's sgQuat/sgdQuat
441   T (&sg(void))[4]
442   { return data(); }
443
444   /// Interface function to osg's Quat*
445   using SGQuatStorage<T>::osg;
446
447   /// Inplace addition
448   SGQuat& operator+=(const SGQuat& v)
449   { data()[0]+=v(0);data()[1]+=v(1);data()[2]+=v(2);data()[3]+=v(3);return *this; }
450   /// Inplace subtraction
451   SGQuat& operator-=(const SGQuat& v)
452   { data()[0]-=v(0);data()[1]-=v(1);data()[2]-=v(2);data()[3]-=v(3);return *this; }
453   /// Inplace scalar multiplication
454   template<typename S>
455   SGQuat& operator*=(S s)
456   { data()[0] *= s; data()[1] *= s; data()[2] *= s; data()[3] *= s; return *this; }
457   /// Inplace scalar multiplication by 1/s
458   template<typename S>
459   SGQuat& operator/=(S s)
460   { return operator*=(1/T(s)); }
461   /// Inplace quaternion multiplication
462   SGQuat& operator*=(const SGQuat& v);
463
464   /// Transform a vector from the current coordinate frame to a coordinate
465   /// frame rotated with the quaternion
466   SGVec3<T> transform(const SGVec3<T>& v) const
467   {
468     T r = 2/dot(*this, *this);
469     SGVec3<T> qimag = imag(*this);
470     T qr = real(*this);
471     return (r*qr*qr - 1)*v + (r*dot(qimag, v))*qimag - (r*qr)*cross(qimag, v);
472   }
473   /// Transform a vector from the coordinate frame rotated with the quaternion
474   /// to the current coordinate frame
475   SGVec3<T> backTransform(const SGVec3<T>& v) const
476   {
477     T r = 2/dot(*this, *this);
478     SGVec3<T> qimag = imag(*this);
479     T qr = real(*this);
480     return (r*qr*qr - 1)*v + (r*dot(qimag, v))*qimag + (r*qr)*cross(qimag, v);
481   }
482
483   /// Rotate a given vector with the quaternion
484   SGVec3<T> rotate(const SGVec3<T>& v) const
485   { return backTransform(v); }
486   /// Rotate a given vector with the inverse quaternion
487   SGVec3<T> rotateBack(const SGVec3<T>& v) const
488   { return transform(v); }
489
490   /// Return the time derivative of the quaternion given the angular velocity
491   SGQuat
492   derivative(const SGVec3<T>& angVel) const
493   {
494     SGQuat deriv;
495
496     deriv.w() = 0.5*(-x()*angVel(0) - y()*angVel(1) - z()*angVel(2));
497     deriv.x() = 0.5*( w()*angVel(0) - z()*angVel(1) + y()*angVel(2));
498     deriv.y() = 0.5*( z()*angVel(0) + w()*angVel(1) - x()*angVel(2));
499     deriv.z() = 0.5*(-y()*angVel(0) + x()*angVel(1) + w()*angVel(2));
500     
501     return deriv;
502   }
503
504 private:
505
506   // Private because it assumes normalized inputs.
507   static SGQuat
508   fromRotateToSmaller90Deg(T cosang,
509                            const SGVec3<T>& from, const SGVec3<T>& to)
510   {
511     // In this function we assume that the angle required to rotate from
512     // the vector from to the vector to is <= 90 deg.
513     // That is done so because of possible instabilities when we rotate more
514     // then 90deg.
515
516     // Note that the next comment does actually cover a *more* *general* case
517     // than we need in this function. That shows that this formula is even
518     // valid for rotations up to 180deg.
519
520     // Because of the signs in the axis, it is sufficient to care for angles
521     // in the interval [-pi,pi]. That means that 0.5*angle is in the interval
522     // [-pi/2,pi/2]. But in that range the cosine is allways >= 0.
523     // So we do not need to care for egative roots in the following equation:
524     T cos05ang = sqrt(0.5+0.5*cosang);
525
526
527     // Now our assumption of angles <= 90 deg comes in play.
528     // For that reason, we know that cos05ang is not zero.
529     // It is even more, we can see from the above formula that 
530     // sqrt(0.5) < cos05ang.
531
532
533     // Compute the rotation axis, that is
534     // sin(angle)*normalized rotation axis
535     SGVec3<T> axis = cross(to, from);
536
537     // We need sin(0.5*angle)*normalized rotation axis.
538     // So rescale with sin(0.5*x)/sin(x).
539     // To do that we use the equation:
540     // sin(x) = 2*sin(0.5*x)*cos(0.5*x)
541     return SGQuat::fromRealImag( cos05ang, (1/(2*cos05ang))*axis);
542   }
543
544   // Private because it assumes normalized inputs.
545   static SGQuat
546   fromRotateToNorm(const SGVec3<T>& from, const SGVec3<T>& to)
547   {
548     // To avoid instabilities with roundoff, we distinguish between rotations
549     // with more then 90deg and rotations with less than 90deg.
550
551     // Compute the cosine of the angle.
552     T cosang = dot(from, to);
553
554     // For the small ones do direct computation
555     if (T(-0.5) < cosang)
556       return SGQuat::fromRotateToSmaller90Deg(cosang, from, to);
557
558     // For larger rotations. first rotate from to -from.
559     // Past that we will have a smaller angle again.
560     SGQuat q1 = SGQuat::fromChangeSign(from);
561     SGQuat q2 = SGQuat::fromRotateToSmaller90Deg(-cosang, -from, to);
562     return q1*q2;
563   }
564 };
565
566 /// Unary +, do nothing ...
567 template<typename T>
568 inline
569 const SGQuat<T>&
570 operator+(const SGQuat<T>& v)
571 { return v; }
572
573 /// Unary -, do nearly nothing
574 template<typename T>
575 inline
576 SGQuat<T>
577 operator-(const SGQuat<T>& v)
578 { return SGQuat<T>(-v(0), -v(1), -v(2), -v(3)); }
579
580 /// Binary +
581 template<typename T>
582 inline
583 SGQuat<T>
584 operator+(const SGQuat<T>& v1, const SGQuat<T>& v2)
585 { return SGQuat<T>(v1(0)+v2(0), v1(1)+v2(1), v1(2)+v2(2), v1(3)+v2(3)); }
586
587 /// Binary -
588 template<typename T>
589 inline
590 SGQuat<T>
591 operator-(const SGQuat<T>& v1, const SGQuat<T>& v2)
592 { return SGQuat<T>(v1(0)-v2(0), v1(1)-v2(1), v1(2)-v2(2), v1(3)-v2(3)); }
593
594 /// Scalar multiplication
595 template<typename S, typename T>
596 inline
597 SGQuat<T>
598 operator*(S s, const SGQuat<T>& v)
599 { return SGQuat<T>(s*v(0), s*v(1), s*v(2), s*v(3)); }
600
601 /// Scalar multiplication
602 template<typename S, typename T>
603 inline
604 SGQuat<T>
605 operator*(const SGQuat<T>& v, S s)
606 { return SGQuat<T>(s*v(0), s*v(1), s*v(2), s*v(3)); }
607
608 /// Quaterion multiplication
609 template<typename T>
610 inline
611 SGQuat<T>
612 operator*(const SGQuat<T>& v1, const SGQuat<T>& v2)
613 {
614   SGQuat<T> v;
615   v.x() = v1.w()*v2.x() + v1.x()*v2.w() + v1.y()*v2.z() - v1.z()*v2.y();
616   v.y() = v1.w()*v2.y() - v1.x()*v2.z() + v1.y()*v2.w() + v1.z()*v2.x();
617   v.z() = v1.w()*v2.z() + v1.x()*v2.y() - v1.y()*v2.x() + v1.z()*v2.w();
618   v.w() = v1.w()*v2.w() - v1.x()*v2.x() - v1.y()*v2.y() - v1.z()*v2.z();
619   return v;
620 }
621
622 /// Now define the inplace multiplication
623 template<typename T>
624 inline
625 SGQuat<T>&
626 SGQuat<T>::operator*=(const SGQuat& v)
627 { (*this) = (*this)*v; return *this; }
628
629 /// The conjugate of the quaternion, this is also the
630 /// inverse for normalized quaternions
631 template<typename T>
632 inline
633 SGQuat<T>
634 conj(const SGQuat<T>& v)
635 { return SGQuat<T>(-v(0), -v(1), -v(2), v(3)); }
636
637 /// The conjugate of the quaternion, this is also the
638 /// inverse for normalized quaternions
639 template<typename T>
640 inline
641 SGQuat<T>
642 inverse(const SGQuat<T>& v)
643 { return (1/dot(v, v))*SGQuat<T>(-v(0), -v(1), -v(2), v(3)); }
644
645 /// The imagniary part of the quaternion
646 template<typename T>
647 inline
648 T
649 real(const SGQuat<T>& v)
650 { return v.w(); }
651
652 /// The imagniary part of the quaternion
653 template<typename T>
654 inline
655 SGVec3<T>
656 imag(const SGQuat<T>& v)
657 { return SGVec3<T>(v.x(), v.y(), v.z()); }
658
659 /// Scalar dot product
660 template<typename T>
661 inline
662 T
663 dot(const SGQuat<T>& v1, const SGQuat<T>& v2)
664 { return v1(0)*v2(0) + v1(1)*v2(1) + v1(2)*v2(2) + v1(3)*v2(3); }
665
666 /// The euclidean norm of the vector, that is what most people call length
667 template<typename T>
668 inline
669 T
670 norm(const SGQuat<T>& v)
671 { return sqrt(dot(v, v)); }
672
673 /// The euclidean norm of the vector, that is what most people call length
674 template<typename T>
675 inline
676 T
677 length(const SGQuat<T>& v)
678 { return sqrt(dot(v, v)); }
679
680 /// The 1-norm of the vector, this one is the fastest length function we
681 /// can implement on modern cpu's
682 template<typename T>
683 inline
684 T
685 norm1(const SGQuat<T>& v)
686 { return fabs(v(0)) + fabs(v(1)) + fabs(v(2)) + fabs(v(3)); }
687
688 /// The euclidean norm of the vector, that is what most people call length
689 template<typename T>
690 inline
691 SGQuat<T>
692 normalize(const SGQuat<T>& q)
693 { return (1/norm(q))*q; }
694
695 /// Return true if exactly the same
696 template<typename T>
697 inline
698 bool
699 operator==(const SGQuat<T>& v1, const SGQuat<T>& v2)
700 { return v1(0)==v2(0) && v1(1)==v2(1) && v1(2)==v2(2) && v1(3)==v2(3); }
701
702 /// Return true if not exactly the same
703 template<typename T>
704 inline
705 bool
706 operator!=(const SGQuat<T>& v1, const SGQuat<T>& v2)
707 { return ! (v1 == v2); }
708
709 /// Return true if equal to the relative tolerance tol
710 /// Note that this is not the same than comparing quaternions to represent
711 /// the same rotation
712 template<typename T>
713 inline
714 bool
715 equivalent(const SGQuat<T>& v1, const SGQuat<T>& v2, T tol)
716 { return norm1(v1 - v2) < tol*(norm1(v1) + norm1(v2)); }
717
718 /// Return true if about equal to roundoff of the underlying type
719 /// Note that this is not the same than comparing quaternions to represent
720 /// the same rotation
721 template<typename T>
722 inline
723 bool
724 equivalent(const SGQuat<T>& v1, const SGQuat<T>& v2)
725 { return equivalent(v1, v2, 100*SGLimits<T>::epsilon()); }
726
727 #ifndef NDEBUG
728 template<typename T>
729 inline
730 bool
731 isNaN(const SGQuat<T>& v)
732 {
733   return SGMisc<T>::isNaN(v(0)) || SGMisc<T>::isNaN(v(1))
734     || SGMisc<T>::isNaN(v(2)) || SGMisc<T>::isNaN(v(3));
735 }
736 #endif
737
738 /// quaternion interpolation for t in [0,1] interpolate between src (=0)
739 /// and dst (=1)
740 template<typename T>
741 inline
742 SGQuat<T>
743 interpolate(T t, const SGQuat<T>& src, const SGQuat<T>& dst)
744 {
745   T cosPhi = dot(src, dst);
746   // need to take the shorter way ...
747   int signCosPhi = SGMisc<T>::sign(cosPhi);
748   // cosPhi must be corrected for that sign
749   cosPhi = fabs(cosPhi);
750
751   // first opportunity to fail - make sure acos will succeed later -
752   // result is correct
753   if (1 <= cosPhi)
754     return dst;
755
756   // now the half angle between the orientations
757   T o = acos(cosPhi);
758
759   // need the scales now, if the angle is very small, do linear interpolation
760   // to avoid instabilities
761   T scale0, scale1;
762   if (fabs(o) < SGLimits<T>::epsilon()) {
763     scale0 = 1 - t;
764     scale1 = t;
765   } else {
766     // note that we can give a positive lower bound for sin(o) here
767     T sino = sin(o);
768     T so = 1/sino;
769     scale0 = sin((1 - t)*o)*so;
770     scale1 = sin(t*o)*so;
771   }
772
773   return scale0*src + signCosPhi*scale1*dst;
774 }
775
776 /// Output to an ostream
777 template<typename char_type, typename traits_type, typename T>
778 inline
779 std::basic_ostream<char_type, traits_type>&
780 operator<<(std::basic_ostream<char_type, traits_type>& s, const SGQuat<T>& v)
781 { return s << "[ " << v(0) << ", " << v(1) << ", " << v(2) << ", " << v(3) << " ]"; }
782
783 inline
784 SGQuatf
785 toQuatf(const SGQuatd& v)
786 { return SGQuatf((float)v(0), (float)v(1), (float)v(2), (float)v(3)); }
787
788 inline
789 SGQuatd
790 toQuatd(const SGQuatf& v)
791 { return SGQuatd(v(0), v(1), v(2), v(3)); }
792
793 #endif