JSBSim Flight Dynamics Model 1.2.2 (22 Mar 2025)
An Open Source Flight Dynamics and Control Software Library in C++
Loading...
Searching...
No Matches
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
27HISTORY
28-------------------------------------------------------------------------------
2912/02/98 JSB Created
3015/01/04 MF Quaternion class from old FGColumnVector4
31
32%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33SENTRY
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
47namespace JSBSim {
48
49class FGMatrix33;
50
51/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
52 CLASS DOCUMENTATION
53 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
54
82/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
83 CLASS DECLARATION
84 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
85
86class JSBSIM_API FGQuaternion : public FGJSBBase {
87public:
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
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
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
486private:
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
539inline 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
548inline 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
565JSBSIM_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:117
Handles matrix math operations.
Definition FGMatrix33.h:70
Models the Quaternion representation of rotations.
double GetSinEuler(int i) const
Retrieves sine of the given euler angle.
FGQuaternion(double angle, const FGColumnVector3 &axis)
Initializer by a rotation axis and an angle.
FGQuaternion(int idx, double angle)
Initializer by one euler angle.
double GetCosEuler(int i) const
Retrieves cosine of the given euler angle.
double GetEuler(int i) const
Retrieves the Euler angles.
FGQuaternion Inverse(void) const
Inverse of the quaternion.
const FGMatrix33 & GetTInv(void) const
Backward transformation matrix.
double SqrMagnitude(void) const
Square of the length of the vector.
double operator()(unsigned int idx) const
Read access the entries of the vector.
~FGQuaternion()
Destructor.
FGQuaternion operator*(const FGQuaternion &q) const
Arithmetic operator "*".
double Magnitude(void) const
Length of the vector.
double GetEulerDeg(int i) const
Retrieves the Euler angles.
double & operator()(unsigned int idx)
Write access the entries of the vector.
bool operator!=(const FGQuaternion &q) const
Comparison operator "!=".
double & Entry(unsigned int idx)
Write access the entries of the vector.
const FGColumnVector3 & GetEuler(void) const
Retrieves the Euler angles.
FGQuaternion Conjugate(void) const
Conjugate of the quaternion.
bool operator==(const FGQuaternion &q) const
Comparison operator "==".
static FGQuaternion zero(void)
Zero quaternion vector.
FGQuaternion operator+(const FGQuaternion &q) const
Arithmetic operator "+".
const FGQuaternion & operator=(const FGQuaternion &q)
Assignment operator "=".
const FGQuaternion & operator/=(double scalar)
Arithmetic operator "/=".
FGColumnVector3 const GetEulerDeg(void) const
Retrieves the Euler angle vector.
const FGMatrix33 & GetT(void) const
Transformation matrix.
FGQuaternion operator-(const FGQuaternion &q) const
Arithmetic operator "-".
const FGQuaternion & operator*=(const FGQuaternion &q)
Arithmetic operator "*=".
const FGQuaternion & operator-=(const FGQuaternion &q)
Arithmetic operator "-=".
FGQuaternion()
Default initializer.
double Entry(unsigned int idx) const
Read access the entries of the vector.
const FGQuaternion & operator*=(double scalar)
Arithmetic operator "*=".