JSBSim Flight Dynamics Model  1.2.1 (08 Aug 2024)
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 namespace JSBSim {
48 
49 class FGMatrix33;
50 
51 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
52  CLASS DOCUMENTATION
53  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
54 
82 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
83  CLASS DECLARATION
84  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
85 
86 class JSBSIM_API FGQuaternion : public FGJSBBase {
87 public:
90  FGQuaternion() : mCacheValid(false) {
91  data[0] = 1.0;
92  data[1] = data[2] = data[3] = 0.0;
93  }
94 
98  FGQuaternion(const FGQuaternion& q);
99 
105  FGQuaternion(double phi, double tht, double psi);
106 
110  FGQuaternion(FGColumnVector3 vOrient);
111 
117  FGQuaternion(int idx, double angle)
118  : mCacheValid(false) {
119 
120  double angle2 = 0.5*angle;
121 
122  double Sangle2 = sin(angle2);
123  double Cangle2 = cos(angle2);
124 
125  if (idx == ePhi) {
126  data[0] = Cangle2;
127  data[1] = Sangle2;
128  data[2] = 0.0;
129  data[3] = 0.0;
130 
131  } else if (idx == eTht) {
132  data[0] = Cangle2;
133  data[1] = 0.0;
134  data[2] = Sangle2;
135  data[3] = 0.0;
136 
137  } else {
138  data[0] = Cangle2;
139  data[1] = 0.0;
140  data[2] = 0.0;
141  data[3] = Sangle2;
142 
143  }
144  }
145 
152  FGQuaternion(double angle, const FGColumnVector3& axis)
153  : mCacheValid(false) {
154 
155  double angle2 = 0.5 * angle;
156 
157  double length = axis.Magnitude();
158  double Sangle2 = sin(angle2) / length;
159  double Cangle2 = cos(angle2);
160 
161  data[0] = Cangle2;
162  data[1] = Sangle2 * axis(1);
163  data[2] = Sangle2 * axis(2);
164  data[3] = Sangle2 * axis(3);
165  }
166 
171  FGQuaternion(const FGMatrix33& m);
172 
175 
183  FGQuaternion GetQDot(const FGColumnVector3& PQR) const;
184 
188  const FGMatrix33& GetT(void) const { ComputeDerived(); return mT; }
189 
193  const FGMatrix33& GetTInv(void) const { ComputeDerived(); return mTInv; }
194 
199  const FGColumnVector3& GetEuler(void) const {
200  ComputeDerived();
201  return mEulerAngles;
202  }
203 
210  double GetEuler(int i) const {
211  ComputeDerived();
212  return mEulerAngles(i);
213  }
214 
220  double GetEulerDeg(int i) const {
221  ComputeDerived();
222  return radtodeg*mEulerAngles(i);
223  }
224 
229  FGColumnVector3 const GetEulerDeg(void) const {
230  ComputeDerived();
231  return radtodeg*mEulerAngles;
232  }
233 
237  double GetSinEuler(int i) const {
238  ComputeDerived();
239  return mEulerSines(i);
240  }
241 
245  double GetCosEuler(int i) const {
246  ComputeDerived();
247  return mEulerCosines(i);
248  }
249 
259  double operator()(unsigned int idx) const { return data[idx-1]; }
260 
270  double& operator()(unsigned int idx) { mCacheValid = false; return data[idx-1]; }
271 
285  double Entry(unsigned int idx) const { return data[idx-1]; }
286 
300  double& Entry(unsigned int idx) {
301  mCacheValid = false;
302  return data[idx-1];
303  }
304 
311  // Copy the master values ...
312  data[0] = q.data[0];
313  data[1] = q.data[1];
314  data[2] = q.data[2];
315  data[3] = q.data[3];
316  ComputeDerived();
317  // .. and copy the derived values if they are valid
318  mCacheValid = q.mCacheValid;
319  if (mCacheValid) {
320  mT = q.mT;
321  mTInv = q.mTInv;
322  mEulerAngles = q.mEulerAngles;
323  mEulerSines = q.mEulerSines;
324  mEulerCosines = q.mEulerCosines;
325  }
326  return *this;
327  }
328 
330  operator FGMatrix33() const { return GetT(); }
331 
335  bool operator==(const FGQuaternion& q) const {
336  return data[0] == q.data[0] && data[1] == q.data[1]
337  && data[2] == q.data[2] && data[3] == q.data[3];
338  }
339 
343  bool operator!=(const FGQuaternion& q) const { return ! operator==(q); }
344  const FGQuaternion& operator+=(const FGQuaternion& q) {
345  // Copy the master values ...
346  data[0] += q.data[0];
347  data[1] += q.data[1];
348  data[2] += q.data[2];
349  data[3] += q.data[3];
350  mCacheValid = false;
351  return *this;
352  }
353 
358  // Copy the master values ...
359  data[0] -= q.data[0];
360  data[1] -= q.data[1];
361  data[2] -= q.data[2];
362  data[3] -= q.data[3];
363  mCacheValid = false;
364  return *this;
365  }
366 
370  const FGQuaternion& operator*=(double scalar) {
371  data[0] *= scalar;
372  data[1] *= scalar;
373  data[2] *= scalar;
374  data[3] *= scalar;
375  mCacheValid = false;
376  return *this;
377  }
378 
382  const FGQuaternion& operator/=(double scalar) {
383  return operator*=(1.0/scalar);
384  }
385 
390  return FGQuaternion(data[0]+q.data[0], data[1]+q.data[1],
391  data[2]+q.data[2], data[3]+q.data[3]);
392  }
393 
398  return FGQuaternion(data[0]-q.data[0], data[1]-q.data[1],
399  data[2]-q.data[2], data[3]-q.data[3]);
400  }
401 
407  return FGQuaternion(data[0]*q.data[0]-data[1]*q.data[1]-data[2]*q.data[2]-data[3]*q.data[3],
408  data[0]*q.data[1]+data[1]*q.data[0]+data[2]*q.data[3]-data[3]*q.data[2],
409  data[0]*q.data[2]-data[1]*q.data[3]+data[2]*q.data[0]+data[3]*q.data[1],
410  data[0]*q.data[3]+data[1]*q.data[2]-data[2]*q.data[1]+data[3]*q.data[0]);
411  }
412 
418  double q0 = data[0]*q.data[0]-data[1]*q.data[1]-data[2]*q.data[2]-data[3]*q.data[3];
419  double q1 = data[0]*q.data[1]+data[1]*q.data[0]+data[2]*q.data[3]-data[3]*q.data[2];
420  double q2 = data[0]*q.data[2]-data[1]*q.data[3]+data[2]*q.data[0]+data[3]*q.data[1];
421  double q3 = data[0]*q.data[3]+data[1]*q.data[2]-data[2]*q.data[1]+data[3]*q.data[0];
422  data[0] = q0;
423  data[1] = q1;
424  data[2] = q2;
425  data[3] = q3;
426  mCacheValid = false;
427  return *this;
428  }
429 
436  FGQuaternion Inverse(void) const {
437  double norm = SqrMagnitude();
438  if (norm == 0.0)
439  return *this;
440  double rNorm = 1.0/norm;
441  return FGQuaternion( data[0]*rNorm, -data[1]*rNorm,
442  -data[2]*rNorm, -data[3]*rNorm );
443  }
444 
450  FGQuaternion Conjugate(void) const {
451  return FGQuaternion( data[0], -data[1], -data[2], -data[3] );
452  }
453 
454  friend FGQuaternion operator*(double, const FGQuaternion&);
455 
460  double Magnitude(void) const { return sqrt(SqrMagnitude()); }
461 
466  double SqrMagnitude(void) const {
467  return data[0]*data[0] + data[1]*data[1]
468  + data[2]*data[2] + data[3]*data[3];
469  }
470 
476  void Normalize(void);
477 
480  static FGQuaternion zero(void) { return FGQuaternion( 0.0, 0.0, 0.0, 0.0 ); }
481 
482  std::string Dump(const std::string& delimiter) const;
483 
484  friend FGQuaternion QExp(const FGColumnVector3& omega);
485 
486 private:
488  FGQuaternion(double q1, double q2, double q3, double q4) : mCacheValid(false)
489  { data[0] = q1; data[1] = q2; data[2] = q3; data[3] = q4; }
490 
494  void ComputeDerivedUnconditional(void) const;
495 
502  void ComputeDerived(void) const {
503  if (!mCacheValid)
504  ComputeDerivedUnconditional();
505  }
506 
508  double data[4];
509 
516  mutable bool mCacheValid;
517 
519  mutable FGMatrix33 mT;
520  mutable FGMatrix33 mTInv;
521 
523  mutable FGColumnVector3 mEulerAngles;
524 
526  mutable FGColumnVector3 mEulerSines;
527  mutable FGColumnVector3 mEulerCosines;
528 
529  void InitializeFromEulerAngles(double phi, double tht, double psi);
530 };
531 
539 inline FGQuaternion operator*(double scalar, const FGQuaternion& q) {
540  return FGQuaternion(scalar*q.data[0], scalar*q.data[1], scalar*q.data[2], scalar*q.data[3]);
541 }
542 
548 inline FGQuaternion QExp(const FGColumnVector3& omega) {
549  FGQuaternion qexp;
550  double angle = omega.Magnitude();
551  double sina_a = angle > 0.0 ? sin(angle)/angle : 1.0;
552 
553  qexp.data[0] = cos(angle);
554  qexp.data[1] = omega(1) * sina_a;
555  qexp.data[2] = omega(2) * sina_a;
556  qexp.data[3] = omega(3) * sina_a;
557 
558  return qexp;
559 }
560 
565 JSBSIM_API std::ostream& operator<<(std::ostream& os, const FGQuaternion& q);
566 
567 } // namespace JSBSim
568 #endif
This class implements a 3 element column vector.
double Magnitude(void) const
Length of the vector.
JSBSim Base class.
Definition: FGJSBBase.h:118
Handles matrix math operations.
Definition: FGMatrix33.h:70
Models the Quaternion representation of rotations.
Definition: FGQuaternion.h:86
const FGColumnVector3 & GetEuler(void) const
Retrieves the Euler angles.
Definition: FGQuaternion.h:199
double GetSinEuler(int i) const
Retrieves sine of the given euler angle.
Definition: FGQuaternion.h:237
FGQuaternion(double angle, const FGColumnVector3 &axis)
Initializer by a rotation axis and an angle.
Definition: FGQuaternion.h:152
const FGQuaternion & operator-=(const FGQuaternion &q)
Arithmetic operator "-=".
Definition: FGQuaternion.h:357
FGQuaternion(int idx, double angle)
Initializer by one euler angle.
Definition: FGQuaternion.h:117
double GetCosEuler(int i) const
Retrieves cosine of the given euler angle.
Definition: FGQuaternion.h:245
double GetEuler(int i) const
Retrieves the Euler angles.
Definition: FGQuaternion.h:210
FGQuaternion Inverse(void) const
Inverse of the quaternion.
Definition: FGQuaternion.h:436
double SqrMagnitude(void) const
Square of the length of the vector.
Definition: FGQuaternion.h:466
double operator()(unsigned int idx) const
Read access the entries of the vector.
Definition: FGQuaternion.h:259
~FGQuaternion()
Destructor.
Definition: FGQuaternion.h:174
const FGQuaternion & operator/=(double scalar)
Arithmetic operator "/=".
Definition: FGQuaternion.h:382
FGQuaternion operator*(const FGQuaternion &q) const
Arithmetic operator "*".
Definition: FGQuaternion.h:406
double Magnitude(void) const
Length of the vector.
Definition: FGQuaternion.h:460
const FGMatrix33 & GetT(void) const
Transformation matrix.
Definition: FGQuaternion.h:188
double GetEulerDeg(int i) const
Retrieves the Euler angles.
Definition: FGQuaternion.h:220
const FGQuaternion & operator*=(double scalar)
Arithmetic operator "*=".
Definition: FGQuaternion.h:370
bool operator!=(const FGQuaternion &q) const
Comparison operator "!=".
Definition: FGQuaternion.h:343
double & Entry(unsigned int idx)
Write access the entries of the vector.
Definition: FGQuaternion.h:300
FGQuaternion Conjugate(void) const
Conjugate of the quaternion.
Definition: FGQuaternion.h:450
bool operator==(const FGQuaternion &q) const
Comparison operator "==".
Definition: FGQuaternion.h:335
const FGQuaternion & operator*=(const FGQuaternion &q)
Arithmetic operator "*=".
Definition: FGQuaternion.h:417
static FGQuaternion zero(void)
Zero quaternion vector.
Definition: FGQuaternion.h:480
FGQuaternion operator+(const FGQuaternion &q) const
Arithmetic operator "+".
Definition: FGQuaternion.h:389
const FGMatrix33 & GetTInv(void) const
Backward transformation matrix.
Definition: FGQuaternion.h:193
FGColumnVector3 const GetEulerDeg(void) const
Retrieves the Euler angle vector.
Definition: FGQuaternion.h:229
FGQuaternion operator-(const FGQuaternion &q) const
Arithmetic operator "-".
Definition: FGQuaternion.h:397
const FGQuaternion & operator=(const FGQuaternion &q)
Assignment operator "=".
Definition: FGQuaternion.h:310
double & operator()(unsigned int idx)
Write access the entries of the vector.
Definition: FGQuaternion.h:270
FGQuaternion()
Default initializer.
Definition: FGQuaternion.h:90
double Entry(unsigned int idx) const
Read access the entries of the vector.
Definition: FGQuaternion.h:285