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