1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 
3  Header:       FGLocation.h
4  Author:       Jon S. Berndt, Mathias Froehlich
5  Date started: 04/04/2004
6 
7  ------- Copyright (C) 1999  Jon S. Berndt (jon@jsbsim.org) ------------------
8  -------           (C) 2004  Mathias Froehlich (Mathias.Froehlich@web.de) ----
9  -------           (C) 2011  Ola Røer Thorsen (ola@silentwings.no) -----------
10 
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
13  Software Foundation; either version 2 of the License, or (at your option) any
14  later version.
15 
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
19  details.
20 
21  You should have received a copy of the GNU Lesser General Public License along
22  with this program; if not, write to the Free Software Foundation, Inc., 59
23  Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 
25  Further information about the GNU Lesser General Public License can also be
26  found on the world wide web at http://www.gnu.org.
27 
28 HISTORY
29 -------------------------------------------------------------------------------
30 04/04/2004   MF   Created from code previously in the old positions class.
31 11/01/2011   ORT  Encapsulated ground callback code in FGLocation and removed
32                   it from FGFDMExec.
33 
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 SENTRY
36 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
37 
38 #ifndef FGLOCATION_H
39 #define FGLOCATION_H
40 
41 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 INCLUDES
43 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
44 
45 #include "FGJSBBase.h"
46 #include "FGColumnVector3.h"
47 #include "FGMatrix33.h"
48 #include "input_output/FGGroundCallback.h"
49 
50 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
51 FORWARD DECLARATIONS
52 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
53 
54 namespace JSBSim {
55 
56 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
57 CLASS DOCUMENTATION
58 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
59 
60 /** FGLocation holds an arbitrary location in the Earth centered Earth fixed
61     reference frame (ECEF). The coordinate frame ECEF has its center in the middle
62     of the earth. The X-axis points from the center of the Earth towards a
63     location with zero latitude and longitude on the Earth surface. The Y-axis
64     points from the center of the Earth towards a location with zero latitude
65     and 90 deg East longitude on the Earth surface. The Z-axis points from the
66     Earth center to the geographic north pole.
67 
68     This class provides access functions to set and get the location as either
69     the simple X, Y and Z values in ft or longitude/latitude and the radial
70     distance of the location from the Earth center.
71 
72     It is common to associate a parent frame with a location. This frame is
73     usually called the local horizontal frame or simply the local frame. It is
74     also called the NED frame (North, East, Down), as well as the Navigation
75     frame. This frame has its X/Y plane parallel to the surface of the Earth
76     (with the assumption of a spherical Earth). The X-axis points towards north,
77     the Y-axis points east and the Z-axis points to the center of the Earth.
78 
79     Since the local frame is determined by the location (and NOT by the
80     orientation of the  vehicle IN any frame), this class also provides the
81     rotation matrices required to transform from the Earth centered (ECEF) frame
82     to the local horizontal frame and back. This class also "owns" the
83     transformations that go from the inertial frame (Earth-centered Inertial, or
84     ECI) to and from the ECEF frame, as well as to and from the local frame.
85     Again, this is because the ECI, ECEF, and local frames do not involve the
86     actual orientation of the vehicle - only the location on the Earth surface,
87     and the angular difference between the ECI and ECEF frames. There are
88     conversion functions for conversion of position vectors given in the one
89     frame to positions in the other frame.
90 
91     To keep the transformation matrices between the ECI and ECEF frames up to
92     date, the Earth angular position must be updated by calling
93     SetEarthPositionAngle() or IncrementEarthPositionAngle(). This must be done
94     prior to any conversion from and to the ECI frame.
95 
96     The Earth centered reference frame is NOT an inertial frame since it rotates
97     with the Earth.
98 
99     The cartesian coordinates (X,Y,Z) in the Earth centered frame are the master values. All other
100     values are computed from these master values and are cached as long as the
101     location is changed by access through a non-const member function. Values
102     are cached to improve performance. It is best practice to work with a
103     natural set of master values. Other parameters that are derived from these
104     master values are calculated only when needed, and IF they are needed and
105     calculated, then they are cached (stored and remembered) so they do not need
106     to be re-calculated until the master values they are derived from are
107     themselves changed (and become stale).
108 
109     Accuracy and round off
110 
111     Given,
112 
113     - that we model a vehicle near the Earth
114     - that the Earth surface radius is about 2*10^7, ft
115     - that we use double values for the representation of the location
116 
117     we have an accuracy of about
118 
119     1e-16*2e7ft/1 = 2e-9 ft
120 
121     left. This should be sufficient for our needs. Note that this is the same
122     relative accuracy we would have when we compute directly with
123     lon/lat/radius. For the radius value this is clear. For the lon/lat pair
124     this is easy to see. Take for example KSFO located at about 37.61 deg north
125     122.35 deg west, which corresponds to 0.65642 rad north and 2.13541 rad
126     west. Both values are of magnitude of about 1. But 1 ft corresponds to about
127     1/(2e7*2*pi) = 7.9577e-09 rad. So the left accuracy with this representation
128     is also about 1*1e-16/7.9577e-09 = 1.2566e-08 which is of the same magnitude
129     as the representation chosen here.
130 
131     The advantage of this representation is that it is a linear space without
132     singularities. The singularities are the north and south pole and most
133     notably the non-steady jump at -pi to pi. It is harder to track this jump
134     correctly especially when we need to work with error norms and derivatives
135     of the equations of motion within the time-stepping code. Also, the rate of
136     change is of the same magnitude for all components in this representation
137     which is an advantage for numerical stability in implicit time-stepping.
138 
139     Note: The latitude is a GEOCENTRIC value. FlightGear converts latitude to a
140     geodetic value and uses that. In order to get best matching relative to a
141     map, geocentric latitude must be converted to geodetic.
142 
143     @see Stevens and Lewis, "Aircraft Control and Simulation", Second edition
144     @see W. C. Durham "Aircraft Dynamics & Control", section 2.2
145 
146     @author Mathias Froehlich
147   */
148 
149 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
150 CLASS DECLARATION
151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
152 
153 class FGLocation : public FGJSBBase
154 {
155 public:
156   /** Default constructor. */
157   FGLocation(void);
158 
159   /** Constructor to set the longitude, latitude and the distance
160       from the center of the earth.
161       @param lon longitude
162       @param lat GEOCENTRIC latitude
163       @param radius distance from center of earth to vehicle in feet*/
164   FGLocation(double lon, double lat, double radius);
165 
166   /** Constructor to initialize the location with the cartesian coordinates
167       (X,Y,Z) contained in the input FGColumnVector3. Distances are in feet,
168       the position is expressed in the ECEF frame.
169       @param lv vector that contain the cartesian coordinates*/
170   FGLocation(const FGColumnVector3& lv);
171 
172   /** Copy constructor. */
173   FGLocation(const FGLocation& l);
174 
175   /** Set the longitude.
176       @param longitude Longitude in rad to set.
177       Sets the longitude of the location represented with this class
178       instance to the value of the given argument. The value is meant
179       to be in rad. The latitude and the radius value are preserved
180       with this call with the exception of radius being equal to
181       zero. If the radius is previously set to zero it is changed to be
182       equal to 1.0 past this call. Longitude is positive east and negative west. */
183   void SetLongitude(double longitude);
184 
185   /** Set the latitude.
186       @param latitude Latitude in rad to set.
187       Sets the latitude of the location represented with this class
188       instance to the value of the given argument. The value is meant
189       to be in rad. The longitude and the radius value are preserved
190       with this call with the exception of radius being equal to
191       zero. If the radius is previously set to zero it is changed to be
192       equal to 1.0 past this call.
193       Latitude is positive north and negative south.
194       The arguments should be within the bounds of -pi/2 <= lat <= pi/2.
195       The behavior of this function with arguments outside this range is
196       left as an exercise to the gentle reader ... */
197   void SetLatitude(double latitude);
198 
199   /** Set the distance from the center of the earth.
200       @param radius Radius in ft to set.
201       Sets the radius of the location represented with this class
202       instance to the value of the given argument. The value is meant
203       to be in ft. The latitude and longitude values are preserved
204       with this call with the exception of radius being equal to
205       zero. If the radius is previously set to zero, latitude and
206       longitude is set equal to zero past this call.
207       The argument should be positive.
208       The behavior of this function called with a negative argument is
209       left as an exercise to the gentle reader ... */
210   void SetRadius(double radius);
211 
212   /** Sets the longitude, latitude and the distance from the center of the earth.
213       @param lon longitude in radians
214       @param lat GEOCENTRIC latitude in radians
215       @param radius distance from center of earth to vehicle in feet*/
216   void SetPosition(double lon, double lat, double radius);
217 
218   /** Sets the longitude, latitude and the distance above the reference ellipsoid.
219       @param lon longitude in radians
220       @param lat GEODETIC latitude in radians
221       @param height distance above the reference ellipsoid to vehicle in feet*/
222   void SetPositionGeodetic(double lon, double lat, double height);
223 
224   /** Sets the semimajor and semiminor axis lengths for this planet.
225       The eccentricity and flattening are calculated from the semimajor
226       and semiminor axis lengths */
227   void SetEllipse(double semimajor, double semiminor);
228 
229   /** Get the longitude.
230       @return the longitude in rad of the location represented with this
231       class instance. The returned values are in the range between
232       -pi <= lon <= pi. Longitude is positive east and negative west. */
GetLongitude()233   double GetLongitude() const { ComputeDerived(); return mLon; }
234 
235   /** Get the longitude.
236       @return the longitude in deg of the location represented with this
237       class instance. The returned values are in the range between
238       -180 <= lon <= 180.  Longitude is positive east and negative west. */
GetLongitudeDeg()239   double GetLongitudeDeg() const { ComputeDerived(); return radtodeg*mLon; }
240 
241   /** Get the sine of Longitude. */
GetSinLongitude()242   double GetSinLongitude() const { ComputeDerived(); return -mTec2l(2,1); }
243 
244   /** Get the cosine of Longitude. */
GetCosLongitude()245   double GetCosLongitude() const { ComputeDerived(); return mTec2l(2,2); }
246 
247   /** Get the latitude.
248       @return the latitude in rad of the location represented with this
249       class instance. The returned values are in the range between
250       -pi/2 <= lon <= pi/2. Latitude is positive north and negative south. */
GetLatitude()251   double GetLatitude() const { ComputeDerived(); return mLat; }
252 
253   /** Get the geodetic latitude.
254       @return the geodetic latitude in rad of the location represented with this
255       class instance. The returned values are in the range between
256       -pi/2 <= lon <= pi/2. Latitude is positive north and negative south. */
GetGeodLatitudeRad(void)257   double GetGeodLatitudeRad(void) const { ComputeDerived(); return mGeodLat; }
258 
259   /** Get the latitude.
260       @return the latitude in deg of the location represented with this
261       class instance. The returned value is in the range between
262       -90 <= lon <= 90. Latitude is positive north and negative south. */
GetLatitudeDeg()263   double GetLatitudeDeg() const { ComputeDerived(); return radtodeg*mLat; }
264 
265   /** Get the geodetic latitude in degrees.
266       @return the geodetic latitude in degrees of the location represented by
267       this class instance. The returned value is in the range between
268       -90 <= lon <= 90. Latitude is positive north and negative south. */
GetGeodLatitudeDeg(void)269   double GetGeodLatitudeDeg(void) const { ComputeDerived(); return radtodeg*mGeodLat; }
270 
271   /** Gets the geodetic altitude in feet. */
GetGeodAltitude(void)272   double GetGeodAltitude(void) const {ComputeDerived(); return GeodeticAltitude;}
273 
274   /** Get the sine of Latitude. */
GetSinLatitude()275   double GetSinLatitude() const { ComputeDerived(); return -mTec2l(3,3); }
276 
277   /** Get the cosine of Latitude. */
GetCosLatitude()278   double GetCosLatitude() const { ComputeDerived(); return mTec2l(1,3); }
279 
280   /** Get the cosine of Latitude. */
GetTanLatitude()281   double GetTanLatitude() const {
282     ComputeDerived();
283     double cLat = mTec2l(1,3);
284     if (cLat == 0.0)
285       return 0.0;
286     else
287       return -mTec2l(3,3)/cLat;
288   }
289 
290   /** Get the distance from the center of the earth.
291       @return the distance of the location represented with this class
292       instance to the center of the earth in ft. The radius value is
293       always positive. */
294   //double GetRadius() const { return mECLoc.Magnitude(); } // may not work with FlightGear
GetRadius()295   double GetRadius() const { ComputeDerived(); return mRadius; }
296 
297   /** @name Functions that rely on the ground callback
298       The following functions allow to set and get the vehicle position above
299       the sea or the ground. The sea and the ground levels are obtained by
300       interrogating an FGGroundCallback instance. A ground callback must
301       therefore be set with SetGroundCallback() before calling any of these
302       functions. */
303   ///@{
304   /** Set the altitude above sea level.
305       @param altitudeASL altitude above Sea Level in feet.
306       @see SetGroundCallback */
SetAltitudeASL(double altitudeASL)307   void SetAltitudeASL(double altitudeASL)
308   { SetRadius(GetSeaLevelRadius() + altitudeASL); }
309 
310   /** Set the altitude above ground level.
311       @param altitudeAGL altitude above Ground Level in feet.
312       @see SetGroundCallback */
SetAltitudeAGL(double altitudeAGL)313   void SetAltitudeAGL(double altitudeAGL)
314   { SetRadius(GetTerrainRadius() + altitudeAGL); }
315 
316   /** Get the local sea level radius
317       @return the sea level radius at the location in feet.
318       @see SetGroundCallback */
GetSeaLevelRadius(void)319   double GetSeaLevelRadius(void) const
320   { ComputeDerived(); return GroundCallback->GetSeaLevelRadius(*this); }
321 
322   /** Get the local terrain radius
323       @return the terrain level radius at the location in feet.
324       @see SetGroundCallback */
GetTerrainRadius(void)325   double GetTerrainRadius(void) const
326   { ComputeDerived(); return GroundCallback->GetTerrainGeoCentRadius(*this); }
327 
328   /** Get the altitude above sea level.
329       @return the altitude ASL in feet.
330       @see SetGroundCallback */
GetAltitudeASL(void)331   double GetAltitudeASL(void) const
332   { return GetRadius() - GetSeaLevelRadius(); }
333 
334   /** Get the altitude above ground level.
335       @return the altitude AGL in feet.
336       @see SetGroundCallback */
GetAltitudeAGL(void)337   double GetAltitudeAGL(void) const {
338     FGLocation c;
339     FGColumnVector3 n,v,w;
340     return GetContactPoint(c,n,v,w);
341   }
342 
343   /** Get terrain contact point information below the current location.
344       @param contact Contact point location
345       @param normal  Terrain normal vector in contact point    (ECEF frame)
346       @param v       Terrain linear velocity in contact point  (ECEF frame)
347       @param w       Terrain angular velocity in contact point (ECEF frame)
348       @return Location altitude above contact point (AGL) in feet.
349       @see SetGroundCallback */
GetContactPoint(FGLocation & contact,FGColumnVector3 & normal,FGColumnVector3 & v,FGColumnVector3 & w)350   double GetContactPoint(FGLocation& contact, FGColumnVector3& normal,
351                          FGColumnVector3& v, FGColumnVector3& w) const
352   { ComputeDerived(); return GroundCallback->GetAGLevel(*this, contact, normal, v, w); }
353   ///@}
354 
355   /** Sets the ground callback pointer. The FGGroundCallback instance will be
356       interrogated by FGLocation each time some terrain informations are needed.
357       This will mainly occur when altitudes above the sea level or above the
358       ground level are needed. A 'smart pointer' is used internally to prevent
359       the FGGroundCallback instance against accidental deletion. This can only
360       work if the calling application also make use of FGGroundCallback_ptr
361       'smart pointers' to manage their copy of the ground callback.
362       @param gc A pointer to a ground callback object
363       @see FGGroundCallback
364    */
SetGroundCallback(FGGroundCallback * gc)365   static void SetGroundCallback(FGGroundCallback* gc) { GroundCallback = gc; }
366 
367   /** Get a pointer to the ground callback currently used. Since the
368       FGGroundcallback instance might have been created outside JSBSim, it is
369       recommanded to store the returned pointer in a 'smart pointer'
370       FGGroundCallback_ptr. This pointer maintains a reference counter and
371       protects the returned pointer against an accidental deletion of the object
372       it is pointing to.
373       @return A pointer to the current ground callback object.
374       @see FGGroundCallback
375    */
GetGroundCallback(void)376   static FGGroundCallback* GetGroundCallback(void) { return GroundCallback; }
377 
378   /** Transform matrix from local horizontal to earth centered frame.
379       @return a const reference to the rotation matrix of the transform from
380       the local horizontal frame to the earth centered frame. */
GetTl2ec(void)381   const FGMatrix33& GetTl2ec(void) const { ComputeDerived(); return mTl2ec; }
382 
383   /** Transform matrix from the earth centered to local horizontal frame.
384       @return a const reference to the rotation matrix of the transform from
385       the earth centered frame to the local horizontal frame. */
GetTec2l(void)386   const FGMatrix33& GetTec2l(void) const { ComputeDerived(); return mTec2l; }
387 
388   /** Get the geodetic distance between the current location and a given
389       location. This corresponds to the shortest distance between the two
390       locations. Earth curvature is taken into account.
391       @param target_longitude the target longitude
392       @param target_latitude the target latitude
393       @return The geodetic distance between the two locations */
394   double GetDistanceTo(double target_longitude, double target_latitude) const;
395 
396   /** Get the heading that should be followed from the current location to
397       a given location along the shortest path. Earth curvature is
398       taken into account.
399       @param target_longitude the target longitude
400       @param target_latitude the target latitude
401       @return The heading that should be followed to reach the targeted
402               location along the shortest path */
403   double GetHeadingTo(double target_longitude, double target_latitude) const;
404 
405   /** Conversion from Local frame coordinates to a location in the
406       earth centered and fixed frame.
407       This function calculates the FGLocation of an object which position
408       relative to the vehicle is given as in input.
409       @param lvec Vector in the local horizontal coordinate frame
410       @return The location in the earth centered and fixed frame */
LocalToLocation(const FGColumnVector3 & lvec)411   FGLocation LocalToLocation(const FGColumnVector3& lvec) const {
412     ComputeDerived(); return mTl2ec*lvec + mECLoc;
413   }
414 
415   /** Conversion from a location in the earth centered and fixed frame
416       to local horizontal frame coordinates.
417       This function calculates the relative position between the vehicle and
418       the input vector and returns the result expressed in the local frame.
419       @param ecvec Vector in the earth centered and fixed frame
420       @return The vector in the local horizontal coordinate frame */
LocationToLocal(const FGColumnVector3 & ecvec)421   FGColumnVector3 LocationToLocal(const FGColumnVector3& ecvec) const {
422     ComputeDerived(); return mTec2l*(ecvec - mECLoc);
423   }
424 
425   // For time-stepping, locations have vector properties...
426 
427   /** Read access the entries of the vector.
428       @param idx the component index.
429       Return the value of the matrix entry at the given index.
430       Indices are counted starting with 1.
431       Note that the index given in the argument is unchecked. */
operator()432   double operator()(unsigned int idx) const { return mECLoc.Entry(idx); }
433 
434   /** Write access the entries of the vector.
435       @param idx the component index.
436       @return a reference to the vector entry at the given index.
437       Indices are counted starting with 1.
438       Note that the index given in the argument is unchecked. */
operator()439   double& operator()(unsigned int idx) { mCacheValid = false; return mECLoc.Entry(idx); }
440 
441   /** Read access the entries of the vector.
442       @param idx the component index.
443       @return the value of the matrix entry at the given index.
444       Indices are counted starting with 1.
445       This function is just a shortcut for the <tt>double
446       operator()(unsigned int idx) const</tt> function. It is
447       used internally to access the elements in a more convenient way.
448       Note that the index given in the argument is unchecked. */
Entry(unsigned int idx)449   double Entry(unsigned int idx) const { return mECLoc.Entry(idx); }
450 
451   /** Write access the entries of the vector.
452       @param idx the component index.
453       @return a reference to the vector entry at the given index.
454       Indices are counted starting with 1.
455       This function is just a shortcut for the double&
456       operator()(unsigned int idx) function. It is
457       used internally to access the elements in a more convenient way.
458       Note that the index given in the argument is unchecked. */
Entry(unsigned int idx)459   double& Entry(unsigned int idx) {
460     mCacheValid = false; return mECLoc.Entry(idx);
461   }
462 
463   /** Sets this location via the supplied vector.
464       The location can be set by an Earth-centered, Earth-fixed (ECEF) frame
465       position vector. The cache is marked as invalid, so any future requests
466       for selected important data will cause the parameters to be calculated.
467       @param v the ECEF column vector in feet.
468       @return a reference to the FGLocation object. */
469   const FGLocation& operator=(const FGColumnVector3& v)
470   {
471     mECLoc(eX) = v(eX);
472     mECLoc(eY) = v(eY);
473     mECLoc(eZ) = v(eZ);
474     mCacheValid = false;
475     //ComputeDerived();
476     return *this;
477   }
478 
479   /** Sets this location via the supplied location object.
480       @param v A location object reference.
481       @return a reference to the FGLocation object. */
482   const FGLocation& operator=(const FGLocation& l);
483 
484   /** This operator returns true if the ECEF location vectors for the two
485       location objects are equal. */
486   bool operator==(const FGLocation& l) const {
487     return mECLoc == l.mECLoc;
488   }
489 
490   /** This operator returns true if the ECEF location vectors for the two
491       location objects are not equal. */
492   bool operator!=(const FGLocation& l) const { return ! operator==(l); }
493 
494   /** This operator adds the ECEF position vectors.
495       The cartesian coordinates of the supplied vector (right side) are added to
496       the ECEF position vector on the left side of the equality, and a reference
497       to this object is returned. */
498   const FGLocation& operator+=(const FGLocation &l) {
499     mCacheValid = false;
500     mECLoc += l.mECLoc;
501     return *this;
502   }
503 
504   /** This operator substracts the ECEF position vectors.
505       The cartesian coordinates of the supplied vector (right side) are
506       substracted from the ECEF position vector on the left side of the
507       equality, and a reference to this object is returned. */
508   const FGLocation& operator-=(const FGLocation &l) {
509     mCacheValid = false;
510     mECLoc -= l.mECLoc;
511     return *this;
512   }
513 
514   /** This operator scales the ECEF position vector.
515       The cartesian coordinates of the ECEF position vector on the left side of
516       the equality are scaled by the supplied value (right side), and a
517       reference to this object is returned. */
518   const FGLocation& operator*=(double scalar) {
519     mCacheValid = false;
520     mECLoc *= scalar;
521     return *this;
522   }
523 
524   /** This operator scales the ECEF position vector.
525       The cartesian coordinates of the ECEF position vector on the left side of
526       the equality are scaled by the inverse of the supplied value (right side),
527       and a reference to this object is returned. */
528   const FGLocation& operator/=(double scalar) {
529     return operator*=(1.0/scalar);
530   }
531 
532   /** This operator adds two ECEF position vectors.
533       A new object is returned that defines a position which is the sum of the
534       cartesian coordinates of the two positions provided. */
535   FGLocation operator+(const FGLocation& l) const {
536     return FGLocation(mECLoc + l.mECLoc);
537   }
538 
539   /** This operator substracts two ECEF position vectors.
540       A new object is returned that defines a position which is the difference
541       of the cartesian coordinates of the two positions provided. */
542   FGLocation operator-(const FGLocation& l) const {
543     return FGLocation(mECLoc - l.mECLoc);
544   }
545 
546   /** This operator scales an ECEF position vector.
547       A new object is returned that defines a position made of the cartesian
548       coordinates of the provided ECEF position scaled by the supplied scalar
549       value. */
550   FGLocation operator*(double scalar) const {
551     return FGLocation(scalar*mECLoc);
552   }
553 
554   /** Cast to a simple 3d vector */
555   operator const FGColumnVector3&() const {
556     return mECLoc;
557   }
558 
559 private:
560   /** Computation of derived values.
561       This function re-computes the derived values like lat/lon and
562       transformation matrices. It does this unconditionally. */
563   void ComputeDerivedUnconditional(void) const;
564 
565   /** Computation of derived values.
566       This function checks if the derived values like lat/lon and
567       transformation matrices are already computed. If so, it
568       returns. If they need to be computed this is done here. */
ComputeDerived(void)569   void ComputeDerived(void) const {
570     if (!mCacheValid)
571       ComputeDerivedUnconditional();
572   }
573 
574   /** The coordinates in the earth centered frame. This is the master copy.
575       The coordinate frame has its center in the middle of the earth.
576       Its x-axis points from the center of the earth towards a
577       location with zero latitude and longitude on the earths
578       surface. The y-axis points from the center of the earth towards a
579       location with zero latitude and 90deg longitude on the earths
580       surface. The z-axis points from the earths center to the
581       geographic north pole.
582       @see W. C. Durham "Aircraft Dynamics & Control", section 2.2 */
583   FGColumnVector3 mECLoc;
584 
585   /** The cached lon/lat/radius values. */
586   mutable double mLon;
587   mutable double mLat;
588   mutable double mRadius;
589   mutable double mGeodLat;
590   mutable double GeodeticAltitude;
591 
592   /** The cached rotation matrices from and to the associated frames. */
593   mutable FGMatrix33 mTl2ec;
594   mutable FGMatrix33 mTec2l;
595 
596   /* Terms for geodetic latitude calculation. Values are from WGS84 model */
597   double a;    // Earth semimajor axis in feet
598   double e2;   // Earth eccentricity squared
599   double c;
600   double ec;
601   double ec2;
602 
603   /** A data validity flag.
604       This class implements caching of the derived values like the
605       orthogonal rotation matrices or the lon/lat/radius values. For caching we
606       carry a flag which signals if the values are valid or not.
607       The C++ keyword "mutable" tells the compiler that the data member is
608       allowed to change during a const member function. */
609   mutable bool mCacheValid;
610 
611   /** The ground callback object pointer */
612   static FGGroundCallback_ptr GroundCallback;
613 };
614 
615 /** Scalar multiplication.
616 
617     @param scalar scalar value to multiply with.
618     @param l Vector to multiply.
619 
620     Multiply the Vector with a scalar value. */
621 inline FGLocation operator*(double scalar, const FGLocation& l)
622 {
623   return l.operator*(scalar);
624 }
625 
626 } // namespace JSBSim
627 
628 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
629 #endif
630