1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5 Date started: 04/04/2004
6 Purpose: Store an arbitrary location on the globe
8 ------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) ------------------
9 ------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
11 This program is free software; you can redistribute it and/or modify it under
12 the terms of the GNU Lesser General Public License as published by the Free Software
13 Foundation; either version 2 of the License, or (at your option) any later
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
21 You should have received a copy of the GNU Lesser General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
23 Place - Suite 330, Boston, MA 02111-1307, USA.
25 Further information about the GNU Lesser General Public License can also be found on
26 the world wide web at http://www.gnu.org.
28 FUNCTIONAL DESCRIPTION
29 ------------------------------------------------------------------------------
30 This class encapsulates an arbitrary position in the globe with its accessors.
31 It has vector properties, so you can add multiply ....
34 ------------------------------------------------------------------------------
37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
43 #include "FGLocation.h"
44 #include "input_output/FGPropertyManager.h"
48 static const char *IdSrc = "$Id: FGLocation.cpp,v 1.23 2010/09/22 11:34:09 jberndt Exp $";
49 static const char *IdHdr = ID_LOCATION;
52 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
54 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
56 FGLocation::FGLocation(void)
59 initial_longitude = 0.0;
70 mLon = mLat = mRadius = mGeodLat = GeodeticAltitude = 0.0;
72 // initial_longitude = 0.0;
83 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
85 FGLocation::FGLocation(double lon, double lat, double radius)
89 double sinLat = sin(lat);
90 double cosLat = cos(lat);
91 double sinLon = sin(lon);
92 double cosLon = cos(lon);
103 mECLoc = FGColumnVector3( radius*cosLat*cosLon,
104 radius*cosLat*sinLon,
106 mLon = mLat = mRadius = mGeodLat = GeodeticAltitude = 0.0;
109 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
111 void FGLocation::SetLongitude(double longitude)
113 double rtmp = mECLoc.Magnitude(eX, eY);
114 // Check if we have zero radius.
115 // If so set it to 1, so that we can set a position
116 if (0.0 == mECLoc.Magnitude())
119 // Fast return if we are on the north or south pole ...
125 // Need to figure out how to set the initial_longitude here
127 mECLoc(eX) = rtmp*cos(longitude);
128 mECLoc(eY) = rtmp*sin(longitude);
131 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
133 void FGLocation::SetLatitude(double latitude)
137 double r = mECLoc.Magnitude();
143 double rtmp = mECLoc.Magnitude(eX, eY);
145 double fac = r/rtmp*cos(latitude);
149 mECLoc(eX) = r*cos(latitude);
152 mECLoc(eZ) = r*sin(latitude);
155 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157 void FGLocation::SetRadius(double radius)
161 double rold = mECLoc.Magnitude();
165 mECLoc *= radius/rold;
168 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
170 void FGLocation::SetPosition(double lon, double lat, double radius)
174 double sinLat = sin(lat);
175 double cosLat = cos(lat);
176 double sinLon = sin(lon);
177 double cosLon = cos(lon);
178 // initial_longitude = lon;
179 mECLoc = FGColumnVector3( radius*cosLat*cosLon,
180 radius*cosLat*sinLon,
184 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
186 void FGLocation::SetPositionGeodetic(double lon, double lat, double height)
192 GeodeticAltitude = height;
194 // initial_longitude = mLon;
196 double RN = a / sqrt(1.0 - e2*sin(mGeodLat)*sin(mGeodLat));
198 mECLoc(eX) = (RN + GeodeticAltitude)*cos(mGeodLat)*cos(mLon);
199 mECLoc(eY) = (RN + GeodeticAltitude)*cos(mGeodLat)*sin(mLon);
200 mECLoc(eZ) = ((1 - e2)*RN + GeodeticAltitude)*sin(mGeodLat);
203 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
205 void FGLocation::SetEllipse(double semimajor, double semiminor)
219 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
220 // Compute the ECEF to ECI transformation matrix using Stevens and Lewis "Aircraft
221 // Control and Simulation", second edition, eqn. 1.4-12, pg. 39. In Stevens and Lewis
222 // notation, this is C_i/e, a transformation from ECEF to ECI.
224 const FGMatrix33& FGLocation::GetTec2i(void)
230 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
231 // This is given in Stevens and Lewis "Aircraft
232 // Control and Simulation", second edition, eqn. 1.4-12, pg. 39
233 // The notation in Stevens and Lewis is: C_e/i. This represents a transformation
234 // from ECI to ECEF - and the orientation of the ECEF frame relative to the ECI
237 const FGMatrix33& FGLocation::GetTi2ec(void)
243 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245 void FGLocation::ComputeDerivedUnconditional(void) const
247 // The radius is just the Euclidean norm of the vector.
248 mRadius = mECLoc.Magnitude();
250 // The distance of the location to the Z-axis, which is the axis
251 // through the poles.
252 double r02 = mECLoc(eX)*mECLoc(eX) + mECLoc(eY)*mECLoc(eY);
253 double rxy = sqrt(r02);
255 // Compute the sin/cos values of the longitude
256 double sinLon, cosLon;
261 sinLon = mECLoc(eY)/rxy;
262 cosLon = mECLoc(eX)/rxy;
265 // Compute the sin/cos values of the latitude
266 double sinLat, cosLat;
267 if (mRadius == 0.0) {
271 sinLat = mECLoc(eZ)/mRadius;
272 cosLat = rxy/mRadius;
275 // Compute the longitude and latitude itself
276 if ( mECLoc( eX ) == 0.0 && mECLoc( eY ) == 0.0 )
279 mLon = atan2( mECLoc( eY ), mECLoc( eX ) );
281 if ( rxy == 0.0 && mECLoc( eZ ) == 0.0 )
284 mLat = atan2( mECLoc(eZ), rxy );
286 // Compute the transform matrices from and to the earth centered frame.
287 // See Stevens and Lewis, "Aircraft Control and Simulation", Second Edition,
288 // Eqn. 1.4-13, page 40. In Stevens and Lewis notation, this is C_n/e - the
289 // orientation of the navigation (local) frame relative to the ECEF frame,
290 // and a transformation from ECEF to nav (local) frame.
292 mTec2l = FGMatrix33( -cosLon*sinLat, -sinLon*sinLat, cosLat,
293 -sinLon , cosLon , 0.0 ,
294 -cosLon*cosLat, -sinLon*cosLat, -sinLat );
296 // In Stevens and Lewis notation, this is C_e/n - the
297 // orientation of the ECEF frame relative to the nav (local) frame,
298 // and a transformation from nav (local) to ECEF frame.
300 mTl2ec = mTec2l.Transposed();
302 // Calculate the inertial to ECEF and transpose matrices
303 double cos_epa = cos(epa);
304 double sin_epa = sin(epa);
305 mTi2ec = FGMatrix33( cos_epa, sin_epa, 0.0,
306 -sin_epa, cos_epa, 0.0,
308 mTec2i = mTi2ec.Transposed();
310 // Now calculate the local (or nav, or ned) frame to inertial transform matrix,
312 mTl2i = mTec2i * mTl2ec;
313 mTi2l = mTl2i.Transposed();
315 // Calculate the geodetic latitude base on AIAA Journal of Guidance and Control paper,
316 // "Improved Method for Calculating Exact Geodetic Latitude and Altitude", and
317 // "Improved Method for Calculating Exact Geodetic Latitude and Altitude, Revisited",
320 if (a != 0.0 && b != 0.0) {
321 double c, p, q, s, t, u, v, w, z, p2, u2, r0;
322 double Ne, P, Q0, Q, signz0, sqrt_q, z_term;
323 p = fabs(mECLoc(eZ))/eps2;
334 Q0 = sqrt(P+1) + sqrt(P);
335 Q = pow(Q0, 0.66666666667);
336 t = (1.0 + Q + 1.0/Q)/6.0;
337 c = sqrt(u2 - 1 + 2.0*t);
339 signz0 = mECLoc(eZ)>=0?1.0:-1.0;
340 z_term = sqrt(t*t+v)-u*w-0.5*t-0.25;
344 z = signz0*sqrt_q*(w+sqrt(z_term));
346 Ne = a*sqrt(1+eps2*z*z/b2);
347 mGeodLat = asin((eps2+1.0)*(z/Ne));
349 GeodeticAltitude = r0*cos(mGeodLat) + mECLoc(eZ)*sin(mGeodLat) - a2/Ne;
353 // Mark the cached values as valid
357 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
359 } // namespace JSBSim