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 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
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::SetEllipse(double semimajor, double semiminor)
185 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
186 // Compute the ECEF to ECI transformation matrix using Stevens and Lewis "Aircraft
187 // Control and Simulation", second edition, eqn. 1.4-12, pg. 39
189 const FGMatrix33& FGLocation::GetTec2i(double epa)
191 double mu = epa - initial_longitude;
192 mTec2i = FGMatrix33( cos(mu), -sin(mu), 0.0,
193 sin(mu), cos(mu), 0.0,
198 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
200 const FGMatrix33& FGLocation::GetTi2ec(double epa)
202 double mu = epa - initial_longitude;
203 mTi2ec = FGMatrix33( cos(mu), sin(mu), 0.0,
204 -sin(mu), cos(mu), 0.0,
209 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
211 void FGLocation::ComputeDerivedUnconditional(void) const
213 // The radius is just the Euclidean norm of the vector.
214 mRadius = mECLoc.Magnitude();
216 // The distance of the location to the Z-axis, which is the axis
217 // through the poles.
218 double rxy = sqrt(mECLoc(eX)*mECLoc(eX) + mECLoc(eY)*mECLoc(eY));
220 // Compute the sin/cos values of the longitude
221 double sinLon, cosLon;
226 sinLon = mECLoc(eY)/rxy;
227 cosLon = mECLoc(eX)/rxy;
230 // Compute the sin/cos values of the latitude
231 double sinLat, cosLat;
232 if (mRadius == 0.0) {
236 sinLat = mECLoc(eZ)/mRadius;
237 cosLat = rxy/mRadius;
240 // Compute the longitude and latitude itself
241 if ( mECLoc( eX ) == 0.0 && mECLoc( eY ) == 0.0 )
244 mLon = atan2( mECLoc( eY ), mECLoc( eX ) );
246 if ( rxy == 0.0 && mECLoc( eZ ) == 0.0 )
249 mLat = atan2( mECLoc(eZ), rxy );
251 // Compute the transform matrices from and to the earth centered frame.
252 // See Stevens and Lewis, "Aircraft Control and Simulation", Second Edition,
253 // Eqn. 1.4-13, page 40.
254 mTec2l = FGMatrix33( -cosLon*sinLat, -sinLon*sinLat, cosLat,
255 -sinLon , cosLon , 0.0 ,
256 -cosLon*cosLat, -sinLon*cosLat, -sinLat );
258 mTl2ec = mTec2l.Transposed();
260 // Calculate the geodetic latitude base on AIAA Journal of Guidance and Control paper,
261 // "Improved Method for Calculating Exact Geodetic Latitude and Altitude", and
262 // "Improved Method for Calculating Exact Geodetic Latitude and Altitude, Revisited",
265 if (a != 0.0 && b != 0.0) {
266 double c, p, q, s, t, u, v, w, z, p2, u2, r02, r0;
267 double Ne, P, Q0, Q, signz0, sqrt_q;
268 p = fabs(mECLoc(eZ))/eps2;
269 r02 = mECLoc(eX)*mECLoc(eX) + mECLoc(eY)*mECLoc(eY);
280 Q0 = sqrt(P+1) + sqrt(P);
281 Q = pow(Q0, 0.66666666667);
282 t = (1.0 + Q + 1.0/Q)/6.0;
283 c = sqrt(u2 - 1 + 2.0*t);
285 signz0 = mECLoc(eZ)>=0?1.0:-1.0;
286 z = signz0*sqrt_q*(w+sqrt(sqrt(t*t+v)-u*w-0.5*t-0.25));
287 Ne = a*sqrt(1+eps2*z*z/b2);
288 mGeodLat = asin((eps2+1.0)*(z/Ne));
290 GeodeticAltitude = r0*cos(mGeodLat) + mECLoc(eZ)*sin(mGeodLat) - a2/Ne;
294 // Mark the cached values as valid
298 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
300 } // namespace JSBSim