1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5 Date started: 04/04/2004
6 Purpose: Store an arbitrary location on the globe
8 ------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.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 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
42 # include <simgear/compiler.h>
43 # ifdef SG_HAVE_STD_INCLUDES
49 # if defined(sgi) && !defined(__GNUC__)
56 #include "FGLocation.h"
57 #include <input_output/FGPropertyManager.h>
61 static const char *IdSrc = "$Id$";
62 static const char *IdHdr = ID_LOCATION;
64 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
66 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
68 FGLocation::FGLocation(void)
71 initial_longitude = 0.0;
82 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
84 FGLocation::FGLocation(double lon, double lat, double radius)
88 double sinLat = sin(lat);
89 double cosLat = cos(lat);
90 double sinLon = sin(lon);
91 double cosLon = cos(lon);
92 initial_longitude = lon;
101 mECLoc = FGColumnVector3( radius*cosLat*cosLon,
102 radius*cosLat*sinLon,
106 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
108 void FGLocation::SetLongitude(double longitude)
110 double rtmp = mECLoc.Magnitude(eX, eY);
111 // Check if we have zero radius.
112 // If so set it to 1, so that we can set a position
113 if (0.0 == mECLoc.Magnitude())
116 // Fast return if we are on the north or south pole ...
122 // Need to figure out how to set the initial_longitude here
124 mECLoc(eX) = rtmp*cos(longitude);
125 mECLoc(eY) = rtmp*sin(longitude);
128 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130 void FGLocation::SetLatitude(double latitude)
134 double r = mECLoc.Magnitude();
140 double rtmp = mECLoc.Magnitude(eX, eY);
142 double fac = r/rtmp*cos(latitude);
146 mECLoc(eX) = r*cos(latitude);
149 mECLoc(eZ) = r*sin(latitude);
152 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154 void FGLocation::SetRadius(double radius)
158 double rold = mECLoc.Magnitude();
162 mECLoc *= radius/rold;
165 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
167 void FGLocation::SetPosition(double lon, double lat, double radius)
171 double sinLat = sin(lat);
172 double cosLat = cos(lat);
173 double sinLon = sin(lon);
174 double cosLon = cos(lon);
175 initial_longitude = lon;
176 mECLoc = FGColumnVector3( radius*cosLat*cosLon,
177 radius*cosLat*sinLon,
182 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
184 void FGLocation::SetEllipse(double semimajor, double semiminor)
198 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
199 // Compute the ECEF to ECI transformation matrix using Stevens and Lewis "Aircraft
200 // Control and Simulation", second edition, eqn. 1.4-12, pg. 39
202 const FGMatrix33& FGLocation::GetTec2i(double epa)
204 double mu = epa - initial_longitude;
205 mTec2i = FGMatrix33( cos(mu), -sin(mu), 0.0,
206 sin(mu), cos(mu), 0.0,
211 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
213 const FGMatrix33& FGLocation::GetTi2ec(double epa)
215 double mu = epa - initial_longitude;
216 mTi2ec = FGMatrix33( cos(mu), sin(mu), 0.0,
217 -sin(mu), cos(mu), 0.0,
222 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
224 void FGLocation::ComputeDerivedUnconditional(void) const
226 // The radius is just the Euclidean norm of the vector.
227 mRadius = mECLoc.Magnitude();
229 // The distance of the location to the Z-axis, which is the axis
230 // through the poles.
231 double rxy = sqrt(mECLoc(eX)*mECLoc(eX) + mECLoc(eY)*mECLoc(eY));
233 // Compute the sin/cos values of the longitude
234 double sinLon, cosLon;
239 sinLon = mECLoc(eY)/rxy;
240 cosLon = mECLoc(eX)/rxy;
243 // Compute the sin/cos values of the latitude
244 double sinLat, cosLat;
245 if (mRadius == 0.0) {
249 sinLat = mECLoc(eZ)/mRadius;
250 cosLat = rxy/mRadius;
253 // Compute the longitude and latitude itself
254 if ( mECLoc( eX ) == 0.0 && mECLoc( eY ) == 0.0 )
257 mLon = atan2( mECLoc( eY ), mECLoc( eX ) );
259 if ( rxy == 0.0 && mECLoc( eZ ) == 0.0 )
262 mLat = atan2( mECLoc(eZ), rxy );
264 // Compute the transform matrices from and to the earth centered frame.
265 // See Stevens and Lewis, "Aircraft Control and Simulation", Second Edition,
266 // Eqn. 1.4-13, page 40.
267 mTec2l = FGMatrix33( -cosLon*sinLat, -sinLon*sinLat, cosLat,
268 -sinLon , cosLon , 0.0 ,
269 -cosLon*cosLat, -sinLon*cosLat, -sinLat );
271 mTl2ec = mTec2l.Transposed();
273 // Calculate the geodetic latitude base on AIAA Journal of Guidance and Control paper,
274 // "Improved Method for Calculating Exact Geodetic Latitude and Altitude", and
275 // "Improved Method for Calculating Exact Geodetic Latitude and Altitude, Revisited",
278 if (a != 0.0 && b != 0.0) {
279 double c, p, q, s, t, u, v, w, z, p2, u2, r02, r0;
280 double Ne, P, Q0, Q, signz0, sqrt_q;
281 p = fabs(mECLoc(eZ))/eps2;
282 r02 = mECLoc(eX)*mECLoc(eX) + mECLoc(eY)*mECLoc(eY);
293 Q0 = sqrt(P+1) + sqrt(P);
294 Q = pow(Q0, 0.66666666667);
295 t = (1.0 + Q + 1.0/Q)/6.0;
296 c = sqrt(u2 - 1 + 2.0*t);
298 signz0 = mECLoc(eZ)>=0?1.0:-1.0;
299 z = signz0*sqrt_q*(w+sqrt(sqrt(t*t+v)-u*w-0.5*t-0.25));
300 Ne = a*sqrt(1+eps2*z*z/b2);
301 mGeodLat = asin((eps2+1.0)*(z/Ne));
303 GeodeticAltitude = r0*cos(mGeodLat) + mECLoc(eZ)*sin(mGeodLat) - a2/Ne;
307 // Mark the cached values as valid
311 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
313 } // namespace JSBSim