JSBSim Flight Dynamics Model  1.0 (02 March 2017)
An Open Source Flight Dynamics and Control Software Library in C++
FGQuaternion.h
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 
3  Header: FGQuaternion.h
4  Author: Jon Berndt, Mathis Froehlich
5  Date started: 12/02/98
6 
7  ------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) ------------------
8  ------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
9 
10  This program is free software; you can redistribute it and/or modify it under
11  the terms of the GNU Lesser General Public License as published by the Free Software
12  Foundation; either version 2 of the License, or (at your option) any later
13  version.
14 
15  This program is distributed in the hope that it will be useful, but WITHOUT
16  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
18  details.
19 
20  You should have received a copy of the GNU Lesser General Public License along with
21  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22  Place - Suite 330, Boston, MA 02111-1307, USA.
23 
24  Further information about the GNU Lesser General Public License can also be found on
25  the world wide web at http://www.gnu.org.
26 
27 HISTORY
28 -------------------------------------------------------------------------------
29 12/02/98 JSB Created
30 15/01/04 MF Quaternion class from old FGColumnVector4
31 
32 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33 SENTRY
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
35 
36 #ifndef FGQUATERNION_H
37 #define FGQUATERNION_H
38 
39 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
40  INCLUDES
41  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
42 
43 #include <string>
44 #include "FGJSBBase.h"
45 #include "FGColumnVector3.h"
46 
47 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
48  DEFINITIONS
49  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
50 
51 #define ID_QUATERNION "$Id: FGQuaternion.h,v 1.26 2013/11/24 16:53:15 bcoconni Exp $"
52 
53 namespace JSBSim {
54 
55 class FGMatrix33;
56 
57 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
58  CLASS DOCUMENTATION
59  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
60 
88 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
89  CLASS DECLARATION
90  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
91 
92 class FGQuaternion : public FGJSBBase {
93 public:
96  FGQuaternion() : mCacheValid(false) {
97  data[0] = 1.0;
98  data[1] = data[2] = data[3] = 0.0;
99  }
100 
104  FGQuaternion(const FGQuaternion& q);
105 
111  FGQuaternion(double phi, double tht, double psi);
112 
116  FGQuaternion(FGColumnVector3 vOrient);
117 
123  FGQuaternion(int idx, double angle)
124  : mCacheValid(false) {
125 
126  double angle2 = 0.5*angle;
127 
128  double Sangle2 = sin(angle2);
129  double Cangle2 = cos(angle2);
130 
131  if (idx == ePhi) {
132  data[0] = Cangle2;
133  data[1] = Sangle2;
134  data[2] = 0.0;
135  data[3] = 0.0;
136 
137  } else if (idx == eTht) {
138  data[0] = Cangle2;
139  data[1] = 0.0;
140  data[2] = Sangle2;
141  data[3] = 0.0;
142 
143  } else {
144  data[0] = Cangle2;
145  data[1] = 0.0;
146  data[2] = 0.0;
147  data[3] = Sangle2;
148 
149  }
150  }
151 
158  FGQuaternion(double angle, const FGColumnVector3& axis)
159  : mCacheValid(false) {
160 
161  double angle2 = 0.5 * angle;
162 
163  double length = axis.Magnitude();
164  double Sangle2 = sin(angle2) / length;
165  double Cangle2 = cos(angle2);
166 
167  data[0] = Cangle2;
168  data[1] = Sangle2 * axis(1);
169  data[2] = Sangle2 * axis(2);
170  data[3] = Sangle2 * axis(3);
171  }
172 
177  FGQuaternion(const FGMatrix33& m);
178 
181 
189  FGQuaternion GetQDot(const FGColumnVector3& PQR) const;
190 
194  const FGMatrix33& GetT(void) const { ComputeDerived(); return mT; }
195 
199  const FGMatrix33& GetTInv(void) const { ComputeDerived(); return mTInv; }
200 
205  const FGColumnVector3& GetEuler(void) const {
206  ComputeDerived();
207  return mEulerAngles;
208  }
209 
216  double GetEuler(int i) const {
217  ComputeDerived();
218  return mEulerAngles(i);
219  }
220 
226  double GetEulerDeg(int i) const {
227  ComputeDerived();
228  return radtodeg*mEulerAngles(i);
229  }
230 
235  FGColumnVector3 const GetEulerDeg(void) const {
236  ComputeDerived();
237  return radtodeg*mEulerAngles;
238  }
239 
243  double GetSinEuler(int i) const {
244  ComputeDerived();
245  return mEulerSines(i);
246  }
247 
251  double GetCosEuler(int i) const {
252  ComputeDerived();
253  return mEulerCosines(i);
254  }
255 
265  double operator()(unsigned int idx) const { return data[idx-1]; }
266 
276  double& operator()(unsigned int idx) { mCacheValid = false; return data[idx-1]; }
277 
291  double Entry(unsigned int idx) const { return data[idx-1]; }
292 
306  double& Entry(unsigned int idx) {
307  mCacheValid = false;
308  return data[idx-1];
309  }
310 
317  // Copy the master values ...
318  data[0] = q.data[0];
319  data[1] = q.data[1];
320  data[2] = q.data[2];
321  data[3] = q.data[3];
322  ComputeDerived();
323  // .. and copy the derived values if they are valid
324  mCacheValid = q.mCacheValid;
325  if (mCacheValid) {
326  mT = q.mT;
327  mTInv = q.mTInv;
328  mEulerAngles = q.mEulerAngles;
329  mEulerSines = q.mEulerSines;
330  mEulerCosines = q.mEulerCosines;
331  }
332  return *this;
333  }
334 
336  operator FGMatrix33() const { return GetT(); }
337 
341  bool operator==(const FGQuaternion& q) const {
342  return data[0] == q.data[0] && data[1] == q.data[1]
343  && data[2] == q.data[2] && data[3] == q.data[3];
344  }
345 
349  bool operator!=(const FGQuaternion& q) const { return ! operator==(q); }
350  const FGQuaternion& operator+=(const FGQuaternion& q) {
351  // Copy the master values ...
352  data[0] += q.data[0];
353  data[1] += q.data[1];
354  data[2] += q.data[2];
355  data[3] += q.data[3];
356  mCacheValid = false;
357  return *this;
358  }
359 
364  // Copy the master values ...
365  data[0] -= q.data[0];
366  data[1] -= q.data[1];
367  data[2] -= q.data[2];
368  data[3] -= q.data[3];
369  mCacheValid = false;
370  return *this;
371  }
372 
376  const FGQuaternion& operator*=(double scalar) {
377  data[0] *= scalar;
378  data[1] *= scalar;
379  data[2] *= scalar;
380  data[3] *= scalar;
381  mCacheValid = false;
382  return *this;
383  }
384 
388  const FGQuaternion& operator/=(double scalar) {
389  return operator*=(1.0/scalar);
390  }
391 
396  return FGQuaternion(data[0]+q.data[0], data[1]+q.data[1],
397  data[2]+q.data[2], data[3]+q.data[3]);
398  }
399 
404  return FGQuaternion(data[0]-q.data[0], data[1]-q.data[1],
405  data[2]-q.data[2], data[3]-q.data[3]);
406  }
407 
413  return FGQuaternion(data[0]*q.data[0]-data[1]*q.data[1]-data[2]*q.data[2]-data[3]*q.data[3],
414  data[0]*q.data[1]+data[1]*q.data[0]+data[2]*q.data[3]-data[3]*q.data[2],
415  data[0]*q.data[2]-data[1]*q.data[3]+data[2]*q.data[0]+data[3]*q.data[1],
416  data[0]*q.data[3]+data[1]*q.data[2]-data[2]*q.data[1]+data[3]*q.data[0]);
417  }
418 
424  double q0 = data[0]*q.data[0]-data[1]*q.data[1]-data[2]*q.data[2]-data[3]*q.data[3];
425  double q1 = data[0]*q.data[1]+data[1]*q.data[0]+data[2]*q.data[3]-data[3]*q.data[2];
426  double q2 = data[0]*q.data[2]-data[1]*q.data[3]+data[2]*q.data[0]+data[3]*q.data[1];
427  double q3 = data[0]*q.data[3]+data[1]*q.data[2]-data[2]*q.data[1]+data[3]*q.data[0];
428  data[0] = q0;
429  data[1] = q1;
430  data[2] = q2;
431  data[3] = q3;
432  mCacheValid = false;
433  return *this;
434  }
435 
442  FGQuaternion Inverse(void) const {
443  double norm = SqrMagnitude();
444  if (norm == 0.0)
445  return *this;
446  double rNorm = 1.0/norm;
447  return FGQuaternion( data[0]*rNorm, -data[1]*rNorm,
448  -data[2]*rNorm, -data[3]*rNorm );
449  }
450 
456  FGQuaternion Conjugate(void) const {
457  return FGQuaternion( data[0], -data[1], -data[2], -data[3] );
458  }
459 
460  friend FGQuaternion operator*(double, const FGQuaternion&);
461 
466  double Magnitude(void) const { return sqrt(SqrMagnitude()); }
467 
472  double SqrMagnitude(void) const {
473  return data[0]*data[0] + data[1]*data[1]
474  + data[2]*data[2] + data[3]*data[3];
475  }
476 
482  void Normalize(void);
483 
486  static FGQuaternion zero(void) { return FGQuaternion( 0.0, 0.0, 0.0, 0.0 ); }
487 
488  std::string Dump(const std::string& delimiter) const;
489 
490  friend FGQuaternion QExp(const FGColumnVector3& omega);
491 
492 private:
494  FGQuaternion(double q1, double q2, double q3, double q4) : mCacheValid(false)
495  { data[0] = q1; data[1] = q2; data[2] = q3; data[3] = q4; }
496 
500  void ComputeDerivedUnconditional(void) const;
501 
508  void ComputeDerived(void) const {
509  if (!mCacheValid)
510  ComputeDerivedUnconditional();
511  }
512 
514  double data[4];
515 
522  mutable bool mCacheValid;
523 
525  mutable FGMatrix33 mT;
526  mutable FGMatrix33 mTInv;
527 
529  mutable FGColumnVector3 mEulerAngles;
530 
532  mutable FGColumnVector3 mEulerSines;
533  mutable FGColumnVector3 mEulerCosines;
534 
535  void InitializeFromEulerAngles(double phi, double tht, double psi);
536 };
537 
545 inline FGQuaternion operator*(double scalar, const FGQuaternion& q) {
546  return FGQuaternion(scalar*q.data[0], scalar*q.data[1], scalar*q.data[2], scalar*q.data[3]);
547 }
548 
554 inline FGQuaternion QExp(const FGColumnVector3& omega) {
555  FGQuaternion qexp;
556  double angle = omega.Magnitude();
557  double sina_a = angle > 0.0 ? sin(angle)/angle : 1.0;
558 
559  qexp.data[0] = cos(angle);
560  qexp.data[1] = omega(1) * sina_a;
561  qexp.data[2] = omega(2) * sina_a;
562  qexp.data[3] = omega(3) * sina_a;
563 
564  return qexp;
565 }
566 
571 std::ostream& operator<<(std::ostream& os, const FGQuaternion& q);
572 
573 } // namespace JSBSim
574 #endif
FGQuaternion(int idx, double angle)
Initializer by one euler angle.
Definition: FGQuaternion.h:123
Models the Quaternion representation of rotations.
Definition: FGQuaternion.h:92
double & operator()(unsigned int idx)
Write access the entries of the vector.
Definition: FGQuaternion.h:276
FGQuaternion GetQDot(const FGColumnVector3 &PQR) const
Quaternion derivative for given angular rates.
double Magnitude(void) const
Length of the vector.
Definition: FGQuaternion.h:466
const FGMatrix33 & GetT(void) const
Transformation matrix.
Definition: FGQuaternion.h:194
const FGQuaternion & operator=(const FGQuaternion &q)
Assignment operator "=".
Definition: FGQuaternion.h:316
double GetEulerDeg(int i) const
Retrieves the Euler angles.
Definition: FGQuaternion.h:226
double GetSinEuler(int i) const
Retrieves sine of the given euler angle.
Definition: FGQuaternion.h:243
FGQuaternion(double angle, const FGColumnVector3 &axis)
Initializer by a rotation axis and an angle.
Definition: FGQuaternion.h:158
const FGQuaternion & operator*=(double scalar)
Arithmetic operator "*=".
Definition: FGQuaternion.h:376
FGQuaternion()
Default initializer.
Definition: FGQuaternion.h:96
double Entry(unsigned int idx) const
Read access the entries of the vector.
Definition: FGQuaternion.h:291
const FGMatrix33 & GetTInv(void) const
Backward transformation matrix.
Definition: FGQuaternion.h:199
~FGQuaternion()
Destructor.
Definition: FGQuaternion.h:180
const FGQuaternion & operator/=(double scalar)
Arithmetic operator "/=".
Definition: FGQuaternion.h:388
friend FGQuaternion QExp(const FGColumnVector3 &omega)
Quaternion exponential.
Definition: FGQuaternion.h:554
const FGQuaternion & operator*=(const FGQuaternion &q)
Arithmetic operator "*=".
Definition: FGQuaternion.h:423
FGQuaternion Conjugate(void) const
Conjugate of the quaternion.
Definition: FGQuaternion.h:456
FGQuaternion operator+(const FGQuaternion &q) const
Arithmetic operator "+".
Definition: FGQuaternion.h:395
double SqrMagnitude(void) const
Square of the length of the vector.
Definition: FGQuaternion.h:472
double GetEuler(int i) const
Retrieves the Euler angles.
Definition: FGQuaternion.h:216
double & Entry(unsigned int idx)
Write access the entries of the vector.
Definition: FGQuaternion.h:306
JSBSim Base class.
Definition: FGJSBBase.h:80
This class implements a 3 element column vector.
FGQuaternion Inverse(void) const
Inverse of the quaternion.
Definition: FGQuaternion.h:442
FGQuaternion operator*(const FGQuaternion &q) const
Arithmetic operator "*".
Definition: FGQuaternion.h:412
bool operator==(const FGQuaternion &q) const
Comparison operator "==".
Definition: FGQuaternion.h:341
double operator()(unsigned int idx) const
Read access the entries of the vector.
Definition: FGQuaternion.h:265
double GetCosEuler(int i) const
Retrieves cosine of the given euler angle.
Definition: FGQuaternion.h:251
Handles matrix math operations.
Definition: FGMatrix33.h:92
FGColumnVector3 const GetEulerDeg(void) const
Retrieves the Euler angle vector.
Definition: FGQuaternion.h:235
double Magnitude(void) const
Length of the vector.
void Normalize(void)
Normalize.
const FGColumnVector3 & GetEuler(void) const
Retrieves the Euler angles.
Definition: FGQuaternion.h:205
static FGQuaternion zero(void)
Zero quaternion vector.
Definition: FGQuaternion.h:486
const FGQuaternion & operator-=(const FGQuaternion &q)
Arithmetic operator "-=".
Definition: FGQuaternion.h:363
FGQuaternion operator-(const FGQuaternion &q) const
Arithmetic operator "-".
Definition: FGQuaternion.h:403
bool operator!=(const FGQuaternion &q) const
Comparison operator "!=".
Definition: FGQuaternion.h:349