00001 /** 00002 * \file GeoCoords.hpp 00003 * \brief Header for GeographicLib::GeoCoords class 00004 * 00005 * Copyright (c) Charles Karney (2008) <charles@karney.com> 00006 * http://charles.karney.info/geographic 00007 * and licensed under the LGPL. 00008 **********************************************************************/ 00009 00010 #ifndef GEOCOORDS_HPP 00011 #define GEOCOORDS_HPP "$Id: GeoCoords.hpp 6543 2009-02-17 11:36:37Z ckarney $" 00012 00013 #include <cmath> 00014 #include <string> 00015 #include <cstdlib> 00016 #include "GeographicLib/UTMUPS.hpp" 00017 #if defined(_MSC_VER) 00018 #include <float.h> // For _finite 00019 #endif 00020 00021 namespace GeographicLib { 00022 00023 /** 00024 * \brief Conversion between geographic coordinates 00025 * 00026 * This class stores a geographic position which may be set via the 00027 * constructors or Reset via 00028 * - latitude and longitude 00029 * - UTM or UPS coordinates 00030 * - a string represention of these or an MGRS coordinate string 00031 * 00032 * The state consists of the latitude and longitude and the supplied UTM or 00033 * UPS coordinates (possibly derived from the MGRS coordinates). If latitude 00034 * and longitude were given then the UTM/UPS coordinates follows the standard 00035 * conventions. 00036 * 00037 * The mutable state consists of the UTM or UPS coordinates for a alternate 00038 * zone. A method SetAltZone is provided to set the alternate UPS/UTM zone. 00039 * 00040 * Methods are provided to return the geographic coordinates, the input UTM 00041 * or UPS coordinates (and associated meridian convergence and scale), or 00042 * alternate UTM or UPS coordinates (and their associated meridian 00043 * convergence and scale). 00044 * 00045 * Once the input string has been parsed, you can print the result out in any 00046 * of the formats, decimal degrees, degrees minutes seconds, MGRS, UTM/UPS. 00047 **********************************************************************/ 00048 class GeoCoords { 00049 private: 00050 double _lat, _long, _easting, _northing, _gamma, _k; 00051 bool _northp; 00052 int _zone; // 0 = poles, -1 = undefined 00053 mutable double _alt_easting, _alt_northing, _alt_gamma, _alt_k; 00054 mutable int _alt_zone; 00055 00056 void CopyToAlt() const throw() { 00057 _alt_easting = _easting; 00058 _alt_northing = _northing; 00059 _alt_gamma = _gamma; 00060 _alt_k = _k; 00061 _alt_zone = _zone; 00062 } 00063 void UTMUPSString(int zone, double easting, double northing, 00064 int prec, std::string& utm) const; 00065 void FixHemisphere(); 00066 #if defined(_MSC_VER) 00067 static inline int isfinite(double x) throw() { return _finite(x); } 00068 #else 00069 static inline int isfinite(double x) throw() { return std::isfinite(x); } 00070 static inline int isnan(double x) throw() { return std::isnan(x); } 00071 static inline int isinf(double x) throw() { return std::isinf(x); } 00072 #endif 00073 public: 00074 00075 /** 00076 * The default contructor is equivalent to \e latitude = 90<sup>o</sup>, \e 00077 * longitude = 0<sup>o</sup>. 00078 **********************************************************************/ 00079 GeoCoords() throw() 00080 // This is the N pole 00081 : _lat(90.0) 00082 , _long(0.0) 00083 , _easting(2000000.0) 00084 , _northing(2000000.0) 00085 , _northp(true) 00086 , _zone(0) 00087 { CopyToAlt();} 00088 00089 /** 00090 * Parse as a string and interpret it as a geographic position. The input 00091 * string is broken into space (or comma) separated pieces and Basic 00092 * decision on which format is based on number of components 00093 * -# MGRS 00094 * -# "Lat Long" or "Long Lat" 00095 * -# "Zone Easting Northing" or "Easting Northing Zone" 00096 * 00097 * The following inputs are approximately the same (Ar Ramadi Bridge, Iraq) 00098 * - Latitude and Longitude 00099 * - 33.44 43.27 00100 * - N33d26.4' E43d16.2' 00101 * - 43d16'12"E 33d26'24"N 00102 * - MGRS 00103 * - 38SLC301 00104 * - 38SLC391014 00105 * - 38SLC3918701405 00106 * - 37SHT9708 00107 * - UTM 00108 * - 38N 339188 3701405 00109 * - 897039 3708229 37N 00110 * 00111 * Latitude and Longitude parsing. Latitude precedes longitude, unless a 00112 * N, S, E, W hemisphere designator is used on one or both coordinates. 00113 * Thus 00114 * - 40 -75 00115 * - N40 W75 00116 * - -75 N40 00117 * - 75W 40N 00118 * - E-75 -40S 00119 * . 00120 * are all the same position. The coodinates may be given in decimal 00121 * degrees, degrees and decimal minutes, degrees, minutes, seconds, etc. 00122 * Use d, ', and " to make off the degrees, minutes and seconds. Thus 00123 * - 40d30'30" 00124 * - 40d30'30 00125 * - 40d30.5' 00126 * - 40d30.5 00127 * - 40.508333333 00128 * . 00129 * all specify the same angle. The leading sign applies to all components 00130 * so -1d30 is -(1+30/60) = -1.5. Latitudes must be in the range [-90, 90] 00131 * and longitudes in the range [-180, 360]. Internally longitudes are 00132 * reduced to the range [-180, 180). 00133 * 00134 * UTM/UPS parsing. For UTM zones (-80 <= Lat <= 84), the zone designator 00135 * is made up of a zone number (for 1 to 60) and a hemisphere letter (N or 00136 * S), e.g., 38N. The latitude zone designer ([C–M] in the southern 00137 * hemisphere and [N–X] in the northern) should NOT be used. (This 00138 * is part of the MGRS coordinate.) The zone designator for the poles 00139 * (where UPS is employed) is a hemisphere letter by itself, i.e., N or S. 00140 * 00141 * MGRS parsing interprets the grid references as square area at the 00142 * specified precision (1m, 10m, 100m, etc.). The center of this square is 00143 * then taken to be the precise position. Thus: 00144 * - 38SMB = 38N 450000 3650000 00145 * - 38SMB4484 = 38N 444500 3684500 00146 * - 38SMB44148470 = 38N 444145 3684705 00147 **********************************************************************/ 00148 GeoCoords(const std::string& s) { Reset(s); } 00149 00150 /** 00151 * Specify the location in terms of \e latitude (degrees) and \e longitude 00152 * (degrees). Use \e zone to force the UTM/UPS representation to use 00153 * a specified zone (\e zone = 0 means UPS). Omitting the third argument 00154 * causes the standard zone to be used. 00155 **********************************************************************/ 00156 GeoCoords(double latitude, double longitude, int zone = -1) { 00157 Reset(latitude, longitude, zone); 00158 } 00159 00160 /** 00161 * Specify the location in terms of UPS/UPS \e zone (zero means UPS), 00162 * hemisphere \e northp (false means south, true means north), \e easting 00163 * (meters) and \e northing (meters). 00164 **********************************************************************/ 00165 GeoCoords(int zone, bool northp, double easting, double northing) { 00166 Reset(zone, northp, easting, northing); 00167 } 00168 00169 /** 00170 * Reset the location as a 1-element, 2-element, or 3-element string. See 00171 * GeoCoords(const string& s). 00172 **********************************************************************/ 00173 void Reset(const std::string& s); 00174 00175 /** 00176 * Reset the location in terms of \e latitude and \e longitude. See 00177 * GeoCoords(double latitude, double longitude, int zone). 00178 **********************************************************************/ 00179 void Reset(double latitude, double longitude, int zone = -1) { 00180 _lat = latitude; 00181 _long = longitude; 00182 UTMUPS::Forward(_lat, _long, 00183 _zone, _northp, _easting, _northing, _gamma, _k, 00184 zone); 00185 if (_long >= 180) 00186 _long -= 360; 00187 CopyToAlt(); 00188 } 00189 00190 /** 00191 * Reset the location in terms of UPS/UPS \e zone, hemisphere \e northp, \e 00192 * easting, and \e northing. See GeoCoords(int zone, bool northp, double 00193 * easting, double northing). 00194 **********************************************************************/ 00195 void Reset(int zone, bool northp, double easting, double northing) { 00196 _zone = zone; 00197 _northp = northp; 00198 _easting = easting; 00199 _northing = northing; 00200 UTMUPS::Reverse(_zone, _northp, _easting, _northing, 00201 _lat, _long, _gamma, _k); 00202 FixHemisphere(); 00203 CopyToAlt(); 00204 } 00205 00206 /** 00207 * Return latitude (degrees) 00208 **********************************************************************/ 00209 double Latitude() const throw() { return _lat; } 00210 00211 /** 00212 * Return longitude (degrees) 00213 **********************************************************************/ 00214 double Longitude() const throw() { return _long; } 00215 00216 /** 00217 * Return easting (meters) 00218 **********************************************************************/ 00219 double Easting() const throw() { return _easting; } 00220 00221 /** 00222 * Return northing (meters) 00223 **********************************************************************/ 00224 double Northing() const throw() { return _northing; } 00225 00226 /** 00227 * Return meridian convergence (degrees) for the UTM/UPS projection. 00228 **********************************************************************/ 00229 double Convergence() const throw() { return _gamma; } 00230 00231 /** 00232 * Return scale for the UTM/UPS projection. 00233 **********************************************************************/ 00234 double Scale() const throw() { return _k; } 00235 00236 /** 00237 * Return hemisphere (false means south, true means north). 00238 **********************************************************************/ 00239 bool Northp() const throw() { return _northp; } 00240 00241 /** 00242 * Return hemisphere letter N or S. 00243 **********************************************************************/ 00244 char Hemisphere() const throw() { return _northp ? 'N' : 'S'; } 00245 00246 /** 00247 * Return the zone corresponding to the input (return 0 for UPS). 00248 **********************************************************************/ 00249 int Zone() const throw() { return _zone; } 00250 00251 /** 00252 * Set the zone (default, -1, means use the standard zone) for the 00253 * alternate representation. Before this is called the alternate zone is 00254 * the input zone. 00255 **********************************************************************/ 00256 void SetAltZone(int zone = -1) const { 00257 if (zone == _zone || 00258 (zone < 0 && _zone == UTMUPS::StandardZone(_lat, _long))) 00259 CopyToAlt(); 00260 else { 00261 bool northp; 00262 UTMUPS::Forward(_lat, _long, 00263 _alt_zone, northp, 00264 _alt_easting, _alt_northing, _alt_gamma, _alt_k, 00265 zone); 00266 } 00267 } 00268 00269 /** 00270 * Returns the current alternate zone (return 0 for UPS). 00271 **********************************************************************/ 00272 int AltZone() const throw() { return _alt_zone; } 00273 00274 /** 00275 * Return easting (meters) for alternate zone. 00276 **********************************************************************/ 00277 double AltEasting() const throw() { return _alt_easting; } 00278 00279 /** 00280 * Return northing (meters) for alternate zone. 00281 **********************************************************************/ 00282 double AltNorthing() const throw() { return _alt_northing; } 00283 00284 /** 00285 * Return meridian convergence (degrees) for altermate zone. 00286 **********************************************************************/ 00287 double AltConvergence() const throw() { return _alt_gamma; } 00288 00289 /** 00290 * Return scale for altermate zone. 00291 **********************************************************************/ 00292 double AltScale() const throw() { return _alt_k; } 00293 00294 /** 00295 * Return string with latitude and longitude as signed decimal degrees. 00296 * Precision \e prec specifies accuracy of representation as follows: 00297 * - prec = -5 (min), 1d 00298 * - prec = 0, 10<sup>-5</sup>d (about 1m) 00299 * - prec = 3, 10<sup>-8</sup>d 00300 * - prec = 9 (max), 10<sup>-14</sup>d 00301 **********************************************************************/ 00302 std::string GeoRepresentation(int prec = 0) const; 00303 00304 /** 00305 * Return string with latitude and longitude as degrees, minutes, seconds, 00306 * and hemisphere. Precision \e prec specifies accuracy of representation 00307 * as follows: 00308 * - prec = -5 (min), 1d 00309 * - prec = -4, 0.1d 00310 * - prec = -3, 1' 00311 * - prec = -2, 0.1' 00312 * - prec = -1, 1" 00313 * - prec = 0, 0.1" (about 3m) 00314 * - prec = 1, 0.01" 00315 * - prec = 10 (max), 10<sup>-11</sup>" 00316 **********************************************************************/ 00317 std::string DMSRepresentation(int prec = 0) const; 00318 00319 /** 00320 * Return MGRS string. This gives the coordinates of the enclosing grid 00321 * square with size given by the precision \e prec. Thus 38N 444180 00322 * 3684790 converted to a MGRS coordinate at precision -2 (100m) is 00323 * 38SMB441847 and not 38SMB442848. Precision \e prec specifies the 00324 * precision of the MSGRS string as follows: 00325 * - prec = -5 (min), 100km 00326 * - prec = -4, 10km 00327 * - prec = -3, 1km 00328 * - prec = -2, 100m 00329 * - prec = -1, 10m 00330 * - prec = 0, 1m 00331 * - prec = 1, 0.1m 00332 * - prec = 6 (max), 1um 00333 **********************************************************************/ 00334 std::string MGRSRepresentation(int prec = 0) const; 00335 00336 /** 00337 * Return string consisting of UTM/UPS zone designator, easting, and 00338 * northing, Precision \e prec specifies accuracy of representation 00339 * as follows: 00340 * - prec = -5 (min), 100km 00341 * - prec = -3, 1km 00342 * - prec = 0, 1m 00343 * - prec = 3, 1mm 00344 * - prec = 6, 1um 00345 * - prec = 9 (max), 1nm 00346 **********************************************************************/ 00347 std::string UTMUPSRepresentation(int prec = 0) const; 00348 00349 /** 00350 * Return MGRS string using alternative zone. See MGRSRepresentation for 00351 * the interpretation of \e prec. 00352 **********************************************************************/ 00353 std::string AltMGRSRepresentation(int prec = 0) const; 00354 00355 /** 00356 * Return string consisting of alternate UTM/UPS zone designator, easting, 00357 * and northing. See UTMUPSRepresentation for the interpretation of \e 00358 * prec. 00359 **********************************************************************/ 00360 std::string AltUTMUPSRepresentation(int prec = 0) const; 00361 }; 00362 00363 } // namespace GeographicLib 00364 #endif // GEOCOORDS_HPP