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$";
49 static const char *IdHdr = ID_LOCATION;
51 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
53 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
55 FGLocation::FGLocation(void)
58 initial_longitude = 0.0;
69 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71 FGLocation::FGLocation(double lon, double lat, double radius)
75 double sinLat = sin(lat);
76 double cosLat = cos(lat);
77 double sinLon = sin(lon);
78 double cosLon = cos(lon);
79 initial_longitude = lon;
88 mECLoc = FGColumnVector3( radius*cosLat*cosLon,
93 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
95 void FGLocation::SetLongitude(double longitude)
97 double rtmp = mECLoc.Magnitude(eX, eY);
98 // Check if we have zero radius.
99 // If so set it to 1, so that we can set a position
100 if (0.0 == mECLoc.Magnitude())
103 // Fast return if we are on the north or south pole ...
109 // Need to figure out how to set the initial_longitude here
111 mECLoc(eX) = rtmp*cos(longitude);
112 mECLoc(eY) = rtmp*sin(longitude);
115 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
117 void FGLocation::SetLatitude(double latitude)
121 double r = mECLoc.Magnitude();
127 double rtmp = mECLoc.Magnitude(eX, eY);
129 double fac = r/rtmp*cos(latitude);
133 mECLoc(eX) = r*cos(latitude);
136 mECLoc(eZ) = r*sin(latitude);
139 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
141 void FGLocation::SetRadius(double radius)
145 double rold = mECLoc.Magnitude();
149 mECLoc *= radius/rold;
152 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154 void FGLocation::SetPosition(double lon, double lat, double radius)
158 double sinLat = sin(lat);
159 double cosLat = cos(lat);
160 double sinLon = sin(lon);
161 double cosLon = cos(lon);
162 initial_longitude = lon;
163 mECLoc = FGColumnVector3( radius*cosLat*cosLon,
164 radius*cosLat*sinLon,
169 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171 void FGLocation::SetPositionGeodetic(double lon, double lat, double height)
177 GeodeticAltitude = height;
179 initial_longitude = mLon;
181 double RN = a / sqrt(1.0 - e2*sin(mGeodLat)*sin(mGeodLat));
183 mECLoc(eX) = (RN + GeodeticAltitude)*cos(mGeodLat)*cos(mLon);
184 mECLoc(eY) = (RN + GeodeticAltitude)*cos(mGeodLat)*sin(mLon);
185 mECLoc(eZ) = ((1 - e2)*RN + GeodeticAltitude)*sin(mGeodLat);
189 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
191 void FGLocation::SetEllipse(double semimajor, double semiminor)
205 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
206 // Compute the ECEF to ECI transformation matrix using Stevens and Lewis "Aircraft
207 // Control and Simulation", second edition, eqn. 1.4-12, pg. 39
209 const FGMatrix33& FGLocation::GetTec2i(double epa)
211 double mu = epa - initial_longitude;
212 mTec2i = FGMatrix33( cos(mu), -sin(mu), 0.0,
213 sin(mu), cos(mu), 0.0,
218 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
220 const FGMatrix33& FGLocation::GetTi2ec(double epa)
222 double mu = epa - initial_longitude;
223 mTi2ec = FGMatrix33( cos(mu), sin(mu), 0.0,
224 -sin(mu), cos(mu), 0.0,
229 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
231 void FGLocation::ComputeDerivedUnconditional(void) const
233 // The radius is just the Euclidean norm of the vector.
234 mRadius = mECLoc.Magnitude();
236 // The distance of the location to the Z-axis, which is the axis
237 // through the poles.
238 double rxy = sqrt(mECLoc(eX)*mECLoc(eX) + mECLoc(eY)*mECLoc(eY));
240 // Compute the sin/cos values of the longitude
241 double sinLon, cosLon;
246 sinLon = mECLoc(eY)/rxy;
247 cosLon = mECLoc(eX)/rxy;
250 // Compute the sin/cos values of the latitude
251 double sinLat, cosLat;
252 if (mRadius == 0.0) {
256 sinLat = mECLoc(eZ)/mRadius;
257 cosLat = rxy/mRadius;
260 // Compute the longitude and latitude itself
261 if ( mECLoc( eX ) == 0.0 && mECLoc( eY ) == 0.0 )
264 mLon = atan2( mECLoc( eY ), mECLoc( eX ) );
266 if ( rxy == 0.0 && mECLoc( eZ ) == 0.0 )
269 mLat = atan2( mECLoc(eZ), rxy );
271 // Compute the transform matrices from and to the earth centered frame.
272 // See Stevens and Lewis, "Aircraft Control and Simulation", Second Edition,
273 // Eqn. 1.4-13, page 40.
274 mTec2l = FGMatrix33( -cosLon*sinLat, -sinLon*sinLat, cosLat,
275 -sinLon , cosLon , 0.0 ,
276 -cosLon*cosLat, -sinLon*cosLat, -sinLat );
278 mTl2ec = mTec2l.Transposed();
280 // Calculate the geodetic latitude base on AIAA Journal of Guidance and Control paper,
281 // "Improved Method for Calculating Exact Geodetic Latitude and Altitude", and
282 // "Improved Method for Calculating Exact Geodetic Latitude and Altitude, Revisited",
285 if (a != 0.0 && b != 0.0) {
286 double c, p, q, s, t, u, v, w, z, p2, u2, r02, r0;
287 double Ne, P, Q0, Q, signz0, sqrt_q;
288 p = fabs(mECLoc(eZ))/eps2;
289 r02 = mECLoc(eX)*mECLoc(eX) + mECLoc(eY)*mECLoc(eY);
300 Q0 = sqrt(P+1) + sqrt(P);
301 Q = pow(Q0, 0.66666666667);
302 t = (1.0 + Q + 1.0/Q)/6.0;
303 c = sqrt(u2 - 1 + 2.0*t);
305 signz0 = mECLoc(eZ)>=0?1.0:-1.0;
306 z = signz0*sqrt_q*(w+sqrt(sqrt(t*t+v)-u*w-0.5*t-0.25));
307 Ne = a*sqrt(1+eps2*z*z/b2);
308 mGeodLat = asin((eps2+1.0)*(z/Ne));
310 GeodeticAltitude = r0*cos(mGeodLat) + mECLoc(eZ)*sin(mGeodLat) - a2/Ne;
314 // Mark the cached values as valid
318 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
320 } // namespace JSBSim