FlightGear next
FGQuaternion.cpp
Go to the documentation of this file.
1/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3 Module: FGQuaternion.cpp
4 Author: Jon Berndt, Mathias 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 Mathias Froehlich implemented a quaternion class from many places
31 in JSBSim.
32
33%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
34SENTRY
35%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
36
37/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38 INCLUDES
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
40
41#include <string>
42#include <iostream>
43#include <sstream>
44#include <iomanip>
45#include <cmath>
46using std::cerr;
47using std::cout;
48using std::endl;
49
50#include "FGMatrix33.h"
51#include "FGColumnVector3.h"
52
53#include "FGQuaternion.h"
54
55/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
56 DEFINITIONS
57 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
58
59namespace JSBSim {
60
61//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
62
63// Initialize from q
64FGQuaternion::FGQuaternion(const FGQuaternion& q) : mCacheValid(q.mCacheValid)
65{
66 data[0] = q(1);
67 data[1] = q(2);
68 data[2] = q(3);
69 data[3] = q(4);
70 if (mCacheValid) {
71 mT = q.mT;
72 mTInv = q.mTInv;
73 mEulerAngles = q.mEulerAngles;
74 mEulerSines = q.mEulerSines;
75 mEulerCosines = q.mEulerCosines;
76 }
77}
78
79//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80
81// Initialize with the three euler angles
82FGQuaternion::FGQuaternion(double phi, double tht, double psi): mCacheValid(false)
83{
84 InitializeFromEulerAngles(phi, tht, psi);
85}
86
87//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
88
89FGQuaternion::FGQuaternion(FGColumnVector3 vOrient): mCacheValid(false)
90{
91 double phi = vOrient(ePhi);
92 double tht = vOrient(eTht);
93 double psi = vOrient(ePsi);
94
95 InitializeFromEulerAngles(phi, tht, psi);
96}
97
98//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
99//
100// This function computes the quaternion that describes the relationship of the
101// body frame with respect to another frame, such as the ECI or ECEF frames. The
102// Euler angles used represent a 3-2-1 (psi, theta, phi) rotation sequence from
103// the reference frame to the body frame. See "Quaternions and Rotation
104// Sequences", Jack B. Kuipers, sections 9.2 and 7.6.
105
106void FGQuaternion::InitializeFromEulerAngles(double phi, double tht, double psi)
107{
108 mEulerAngles(ePhi) = phi;
109 mEulerAngles(eTht) = tht;
110 mEulerAngles(ePsi) = psi;
111
112 double thtd2 = 0.5*tht;
113 double psid2 = 0.5*psi;
114 double phid2 = 0.5*phi;
115
116 double Sthtd2 = sin(thtd2);
117 double Spsid2 = sin(psid2);
118 double Sphid2 = sin(phid2);
119
120 double Cthtd2 = cos(thtd2);
121 double Cpsid2 = cos(psid2);
122 double Cphid2 = cos(phid2);
123
124 double Cphid2Cthtd2 = Cphid2*Cthtd2;
125 double Cphid2Sthtd2 = Cphid2*Sthtd2;
126 double Sphid2Sthtd2 = Sphid2*Sthtd2;
127 double Sphid2Cthtd2 = Sphid2*Cthtd2;
128
129 data[0] = Cphid2Cthtd2*Cpsid2 + Sphid2Sthtd2*Spsid2;
130 data[1] = Sphid2Cthtd2*Cpsid2 - Cphid2Sthtd2*Spsid2;
131 data[2] = Cphid2Sthtd2*Cpsid2 + Sphid2Cthtd2*Spsid2;
132 data[3] = Cphid2Cthtd2*Spsid2 - Sphid2Sthtd2*Cpsid2;
133
134 Normalize();
135}
136//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
137// Initialize with a direction cosine (rotation) matrix
138
139FGQuaternion::FGQuaternion(const FGMatrix33& m) : mCacheValid(false)
140{
141 data[0] = 0.50*sqrt(1.0 + m(1,1) + m(2,2) + m(3,3));
142 double t = 0.25/data[0];
143 data[1] = t*(m(2,3) - m(3,2));
144 data[2] = t*(m(3,1) - m(1,3));
145 data[3] = t*(m(1,2) - m(2,1));
146
147 Normalize();
148}
149
150//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
151
159{
160 return FGQuaternion(
161 -0.5*( data[1]*PQR(eP) + data[2]*PQR(eQ) + data[3]*PQR(eR)),
162 0.5*( data[0]*PQR(eP) - data[3]*PQR(eQ) + data[2]*PQR(eR)),
163 0.5*( data[3]*PQR(eP) + data[0]*PQR(eQ) - data[1]*PQR(eR)),
164 0.5*(-data[2]*PQR(eP) + data[1]*PQR(eQ) + data[0]*PQR(eR))
165 );
166}
167
168//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169
171{
172 // Note: this does not touch the cache since it does not change the orientation
173 double norm = Magnitude();
174 if (norm == 0.0 || fabs(norm - 1.000) < 1e-10) return;
175
176 double rnorm = 1.0/norm;
177
178 data[0] *= rnorm;
179 data[1] *= rnorm;
180 data[2] *= rnorm;
181 data[3] *= rnorm;
182}
183
184//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
185
186// Compute the derived values if required ...
187void FGQuaternion::ComputeDerivedUnconditional(void) const
188{
189 mCacheValid = true;
190
191 double q0 = data[0]; // use some aliases/shorthand for the quat elements.
192 double q1 = data[1];
193 double q2 = data[2];
194 double q3 = data[3];
195
196 // Now compute the transformation matrix.
197 double q0q0 = q0*q0;
198 double q1q1 = q1*q1;
199 double q2q2 = q2*q2;
200 double q3q3 = q3*q3;
201 double q0q1 = q0*q1;
202 double q0q2 = q0*q2;
203 double q0q3 = q0*q3;
204 double q1q2 = q1*q2;
205 double q1q3 = q1*q3;
206 double q2q3 = q2*q3;
207
208 mT(1,1) = q0q0 + q1q1 - q2q2 - q3q3; // This is found from Eqn. 1.3-32 in
209 mT(1,2) = 2.0*(q1q2 + q0q3); // Stevens and Lewis
210 mT(1,3) = 2.0*(q1q3 - q0q2);
211 mT(2,1) = 2.0*(q1q2 - q0q3);
212 mT(2,2) = q0q0 - q1q1 + q2q2 - q3q3;
213 mT(2,3) = 2.0*(q2q3 + q0q1);
214 mT(3,1) = 2.0*(q1q3 + q0q2);
215 mT(3,2) = 2.0*(q2q3 - q0q1);
216 mT(3,3) = q0q0 - q1q1 - q2q2 + q3q3;
217
218 // Since this is an orthogonal matrix, the inverse is simply the transpose.
219
220 mTInv = mT;
221 mTInv.T();
222
223 // Compute the Euler-angles
224
225 mEulerAngles = mT.GetEuler();
226
227 // FIXME: may be one can compute those values easier ???
228 mEulerSines(ePhi) = sin(mEulerAngles(ePhi));
229 // mEulerSines(eTht) = sin(mEulerAngles(eTht));
230 mEulerSines(eTht) = -mT(1,3);
231 mEulerSines(ePsi) = sin(mEulerAngles(ePsi));
232 mEulerCosines(ePhi) = cos(mEulerAngles(ePhi));
233 mEulerCosines(eTht) = cos(mEulerAngles(eTht));
234 mEulerCosines(ePsi) = cos(mEulerAngles(ePsi));
235}
236
237//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238
239std::string FGQuaternion::Dump(const std::string& delimiter) const
240{
241 std::ostringstream buffer;
242 buffer << std::setprecision(16) << data[0] << delimiter;
243 buffer << std::setprecision(16) << data[1] << delimiter;
244 buffer << std::setprecision(16) << data[2] << delimiter;
245 buffer << std::setprecision(16) << data[3];
246 return buffer.str();
247}
248
249//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
250
251std::ostream& operator<<(std::ostream& os, const FGQuaternion& q)
252{
253 os << q(1) << " , " << q(2) << " , " << q(3) << " , " << q(4);
254 return os;
255}
256
257} // namespace JSBSim
This class implements a 3 element column vector.
Handles matrix math operations.
Definition FGMatrix33.h:70
FGColumnVector3 GetEuler() const
Returns the Euler angle column vector associated with this matrix.
void T(void)
Transposes this matrix.
Models the Quaternion representation of rotations.
FGQuaternion GetQDot(const FGColumnVector3 &PQR) const
Quaternion derivative for given angular rates.
double Magnitude(void) const
Length of the vector.
FGQuaternion()
Default initializer.
void Normalize(void)
Normalize.
std::string Dump(const std::string &delimiter) const
ostream & operator<<(ostream &os, const FGColumnVector3 &col)
Write vector to a stream.