1 // Copyright (C) 2006  Mathias Froehlich - Mathias.Froehlich@web.de
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Library General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16 //
17 
18 #ifndef SGGeod_H
19 #define SGGeod_H
20 
21 #include <simgear/constants.h>
22 #include <simgear/math/SGVec3.hxx>
23 
24 // #define SG_GEOD_NATIVE_DEGREE
25 
26 /// Class representing a geodetic location
27 class SGGeod {
28 public:
29   /// Default constructor, initializes the instance to lat = lon = elev = 0
30   SGGeod(void);
31 
32   /**
33     return an SGGeod for which isValid() returns false.
34     This is necessaerby becuase for historical reasons, ther defaulrt constructor above initialsies to zero,zero,zero
35     which *is*
36    */
37   static SGGeod invalid();
38 
39   /// Factory from angular values in radians and elevation is 0
40   static SGGeod fromRad(double lon, double lat);
41   /// Factory from angular values in degrees and elevation is 0
42   static SGGeod fromDeg(double lon, double lat);
43   /// Factory from angular values in radians and elevation in ft
44   static SGGeod fromRadFt(double lon, double lat, double elevation);
45   /// Factory from angular values in degrees and elevation in ft
46   static SGGeod fromDegFt(double lon, double lat, double elevation);
47   /// Factory from angular values in radians and elevation in m
48   static SGGeod fromRadM(double lon, double lat, double elevation);
49   /// Factory from angular values in degrees and elevation in m
50   static SGGeod fromDegM(double lon, double lat, double elevation);
51   /// Factory from an other SGGeod and a different elevation in m
52   static SGGeod fromGeodM(const SGGeod& geod, double elevation);
53   /// Factory from an other SGGeod and a different elevation in ft
54   static SGGeod fromGeodFt(const SGGeod& geod, double elevation);
55   /// Factory to convert position from a cartesian position assumed to be
56   /// in wgs84 measured in meters
57   /// Note that this conversion is relatively expensive to compute
58   static SGGeod fromCart(const SGVec3<double>& cart);
59   /// Factory to convert position from a geocentric position
60   /// Note that this conversion is relatively expensive to compute
61   static SGGeod fromGeoc(const SGGeoc& geoc);
62 
63   /// Return the geodetic longitude in radians
64   double getLongitudeRad(void) const;
65   /// Set the geodetic longitude from the argument given in radians
66   void setLongitudeRad(double lon);
67 
68   /// Return the geodetic longitude in degrees
69   double getLongitudeDeg(void) const;
70   /// Set the geodetic longitude from the argument given in degrees
71   void setLongitudeDeg(double lon);
72 
73   /// Return the geodetic latitude in radians
74   double getLatitudeRad(void) const;
75   /// Set the geodetic latitude from the argument given in radians
76   void setLatitudeRad(double lat);
77 
78   /// Return the geodetic latitude in degrees
79   double getLatitudeDeg(void) const;
80   /// Set the geodetic latitude from the argument given in degrees
81   void setLatitudeDeg(double lat);
82 
83   /// Return the geodetic elevation in meters
84   double getElevationM(void) const;
85   /// Set the geodetic elevation from the argument given in meters
86   void setElevationM(double elevation);
87 
88   /// Return the geodetic elevation in feet
89   double getElevationFt(void) const;
90   /// Set the geodetic elevation from the argument given in feet
91   void setElevationFt(double elevation);
92 
93   /// Compare two geodetic positions for equality
94   bool operator == ( const SGGeod & other ) const;
95 
96   /// check the Geod contains sane values (finite, inside appropriate
97   /// ranges for lat/lon)
98   bool isValid() const;
99 private:
100   /// This one is private since construction is not unique if you do
101   /// not know the units of the arguments. Use the factory methods for
102   /// that purpose
103   SGGeod(double lon, double lat, double elevation);
104 
105   //// FIXME: wrong comment!
106   /// The actual data, angles in degrees, elevation in meters
107   /// The rationale for storing the values in degrees is that most code places
108   /// in flightgear/terragear use degrees as a nativ input and output value.
109   /// The places where it makes sense to use radians is when we convert
110   /// to other representations or compute rotation matrices. But both tasks
111   /// are computionally intensive anyway and that additional 'toRadian'
112   /// conversion does not hurt too much
113   double _lon;
114   double _lat;
115   double _elevation;
116 };
117 
118 inline
SGGeod(void)119 SGGeod::SGGeod(void) :
120   _lon(0), _lat(0), _elevation(0)
121 {
122 }
123 
124 inline
SGGeod(double lon,double lat,double elevation)125 SGGeod::SGGeod(double lon, double lat, double elevation) :
126   _lon(lon), _lat(lat), _elevation(elevation)
127 {
128 }
129 
130 inline
131 SGGeod
fromRad(double lon,double lat)132 SGGeod::fromRad(double lon, double lat)
133 {
134 #ifdef SG_GEOD_NATIVE_DEGREE
135   return SGGeod(lon*SGD_RADIANS_TO_DEGREES, lat*SGD_RADIANS_TO_DEGREES, 0);
136 #else
137   return SGGeod(lon, lat, 0);
138 #endif
139 }
140 
141 inline
142 SGGeod
fromDeg(double lon,double lat)143 SGGeod::fromDeg(double lon, double lat)
144 {
145 #ifdef SG_GEOD_NATIVE_DEGREE
146   return SGGeod(lon, lat, 0);
147 #else
148   return SGGeod(lon*SGD_DEGREES_TO_RADIANS, lat*SGD_DEGREES_TO_RADIANS, 0);
149 #endif
150 }
151 
152 inline
153 SGGeod
fromRadFt(double lon,double lat,double elevation)154 SGGeod::fromRadFt(double lon, double lat, double elevation)
155 {
156 #ifdef SG_GEOD_NATIVE_DEGREE
157   return SGGeod(lon*SGD_RADIANS_TO_DEGREES, lat*SGD_RADIANS_TO_DEGREES,
158                 elevation*SG_FEET_TO_METER);
159 #else
160   return SGGeod(lon, lat, elevation*SG_FEET_TO_METER);
161 #endif
162 }
163 
164 inline
165 SGGeod
fromDegFt(double lon,double lat,double elevation)166 SGGeod::fromDegFt(double lon, double lat, double elevation)
167 {
168 #ifdef SG_GEOD_NATIVE_DEGREE
169   return SGGeod(lon, lat, elevation*SG_FEET_TO_METER);
170 #else
171   return SGGeod(lon*SGD_DEGREES_TO_RADIANS, lat*SGD_DEGREES_TO_RADIANS,
172                 elevation*SG_FEET_TO_METER);
173 #endif
174 }
175 
176 inline
177 SGGeod
fromRadM(double lon,double lat,double elevation)178 SGGeod::fromRadM(double lon, double lat, double elevation)
179 {
180 #ifdef SG_GEOD_NATIVE_DEGREE
181   return SGGeod(lon*SGD_RADIANS_TO_DEGREES, lat*SGD_RADIANS_TO_DEGREES,
182                 elevation);
183 #else
184   return SGGeod(lon, lat, elevation);
185 #endif
186 }
187 
188 inline
189 SGGeod
fromDegM(double lon,double lat,double elevation)190 SGGeod::fromDegM(double lon, double lat, double elevation)
191 {
192 #ifdef SG_GEOD_NATIVE_DEGREE
193   return SGGeod(lon, lat, elevation);
194 #else
195   return SGGeod(lon*SGD_DEGREES_TO_RADIANS, lat*SGD_DEGREES_TO_RADIANS,
196                 elevation);
197 #endif
198 }
199 
200 inline
201 SGGeod
fromGeodM(const SGGeod & geod,double elevation)202 SGGeod::fromGeodM(const SGGeod& geod, double elevation)
203 {
204   return SGGeod(geod._lon, geod._lat, elevation);
205 }
206 
207 inline
208 SGGeod
fromGeodFt(const SGGeod & geod,double elevation)209 SGGeod::fromGeodFt(const SGGeod& geod, double elevation)
210 {
211   return SGGeod(geod._lon, geod._lat, elevation*SG_FEET_TO_METER);
212 }
213 
214 inline
215 SGGeod
fromCart(const SGVec3<double> & cart)216 SGGeod::fromCart(const SGVec3<double>& cart)
217 {
218   SGGeod geod;
219   SGGeodesy::SGCartToGeod(cart, geod);
220   return geod;
221 }
222 
223 inline
224 SGGeod
fromGeoc(const SGGeoc & geoc)225 SGGeod::fromGeoc(const SGGeoc& geoc)
226 {
227   SGVec3<double> cart;
228   SGGeodesy::SGGeocToCart(geoc, cart);
229   SGGeod geod;
230   SGGeodesy::SGCartToGeod(cart, geod);
231   return geod;
232 }
233 
234 inline
235 double
getLongitudeRad(void) const236 SGGeod::getLongitudeRad(void) const
237 {
238 #ifdef SG_GEOD_NATIVE_DEGREE
239   return _lon*SGD_DEGREES_TO_RADIANS;
240 #else
241   return _lon;
242 #endif
243 }
244 
245 inline
246 void
setLongitudeRad(double lon)247 SGGeod::setLongitudeRad(double lon)
248 {
249 #ifdef SG_GEOD_NATIVE_DEGREE
250   _lon = lon*SGD_RADIANS_TO_DEGREES;
251 #else
252   _lon = lon;
253 #endif
254 }
255 
256 inline
257 double
getLongitudeDeg(void) const258 SGGeod::getLongitudeDeg(void) const
259 {
260 #ifdef SG_GEOD_NATIVE_DEGREE
261   return _lon;
262 #else
263   return _lon*SGD_RADIANS_TO_DEGREES;
264 #endif
265 }
266 
267 inline
268 void
setLongitudeDeg(double lon)269 SGGeod::setLongitudeDeg(double lon)
270 {
271 #ifdef SG_GEOD_NATIVE_DEGREE
272   _lon = lon;
273 #else
274   _lon = lon*SGD_DEGREES_TO_RADIANS;
275 #endif
276 }
277 
278 inline
279 double
getLatitudeRad(void) const280 SGGeod::getLatitudeRad(void) const
281 {
282 #ifdef SG_GEOD_NATIVE_DEGREE
283   return _lat*SGD_DEGREES_TO_RADIANS;
284 #else
285   return _lat;
286 #endif
287 }
288 
289 inline
290 void
setLatitudeRad(double lat)291 SGGeod::setLatitudeRad(double lat)
292 {
293 #ifdef SG_GEOD_NATIVE_DEGREE
294   _lat = lat*SGD_RADIANS_TO_DEGREES;
295 #else
296   _lat = lat;
297 #endif
298 }
299 
300 inline
301 double
getLatitudeDeg(void) const302 SGGeod::getLatitudeDeg(void) const
303 {
304 #ifdef SG_GEOD_NATIVE_DEGREE
305   return _lat;
306 #else
307   return _lat*SGD_RADIANS_TO_DEGREES;
308 #endif
309 }
310 
311 inline
312 void
setLatitudeDeg(double lat)313 SGGeod::setLatitudeDeg(double lat)
314 {
315 #ifdef SG_GEOD_NATIVE_DEGREE
316   _lat = lat;
317 #else
318   _lat = lat*SGD_DEGREES_TO_RADIANS;
319 #endif
320 }
321 
322 inline
323 double
getElevationM(void) const324 SGGeod::getElevationM(void) const
325 {
326   return _elevation;
327 }
328 
329 inline
330 void
setElevationM(double elevation)331 SGGeod::setElevationM(double elevation)
332 {
333   _elevation = elevation;
334 }
335 
336 inline
337 double
getElevationFt(void) const338 SGGeod::getElevationFt(void) const
339 {
340   return _elevation*SG_METER_TO_FEET;
341 }
342 
343 inline
344 void
setElevationFt(double elevation)345 SGGeod::setElevationFt(double elevation)
346 {
347   _elevation = elevation*SG_FEET_TO_METER;
348 }
349 
350 inline
351 bool
operator ==(const SGGeod & other) const352 SGGeod::operator == ( const SGGeod & other ) const
353 {
354   return _lon == other._lon &&
355          _lat == other._lat &&
356          _elevation == other._elevation;
357 }
358 
359 inline
360 bool
isValid() const361 SGGeod::isValid() const
362 {
363   if (SGMiscd::isNaN(_lon))
364       return false;
365   if (SGMiscd::isNaN(_lat))
366       return false;
367 #ifdef SG_GEOD_NATIVE_DEGREE
368   return (_lon >= -180.0) && (_lon <= 180.0) &&
369   (_lat >= -90.0) && (_lat <= 90.0);
370 #else
371   return (_lon >= -SGD_PI) && (_lon <= SGD_PI) &&
372   (_lat >= -SGD_PI_2) && (_lat <= SGD_PI_2);
373 #endif
374 }
375 
376 /// Output to an ostream
377 template<typename char_type, typename traits_type>
378 inline
379 std::basic_ostream<char_type, traits_type>&
operator <<(std::basic_ostream<char_type,traits_type> & s,const SGGeod & g)380 operator<<(std::basic_ostream<char_type, traits_type>& s, const SGGeod& g)
381 {
382   return s << "lon = " << g.getLongitudeDeg()
383            << "deg, lat = " << g.getLatitudeDeg()
384            << "deg, elev = " << g.getElevationM()
385            << "m";
386 }
387 
388 #endif
389