00001 /** 00002 * \file GeoCoords.hpp 00003 * \brief Header for GeographicLib::GeoCoords class 00004 * 00005 * Copyright (c) Charles Karney (2008, 2009, 2010) <charles@karney.com> 00006 * and licensed under the LGPL. For more information, see 00007 * http://geographiclib.sourceforge.net/ 00008 **********************************************************************/ 00009 00010 #ifndef GEOGRAPHICLIB_GEOCOORDS_HPP 00011 #define GEOGRAPHICLIB_GEOCOORDS_HPP "$Id: GeoCoords.hpp 6785 2010-01-05 22:15:42Z karney $" 00012 00013 #include "GeographicLib/UTMUPS.hpp" 00014 #include "GeographicLib/Constants.hpp" 00015 00016 namespace GeographicLib { 00017 00018 /** 00019 * \brief Conversion between geographic coordinates 00020 * 00021 * This class stores a geographic position which may be set via the 00022 * constructors or Reset via 00023 * - latitude and longitude 00024 * - UTM or UPS coordinates 00025 * - a string represention of these or an MGRS coordinate string 00026 * 00027 * The state consists of the latitude and longitude and the supplied UTM or 00028 * UPS coordinates (possibly derived from the MGRS coordinates). If latitude 00029 * and longitude were given then the UTM/UPS coordinates follows the standard 00030 * conventions. 00031 * 00032 * The mutable state consists of the UTM or UPS coordinates for a alternate 00033 * zone. A method SetAltZone is provided to set the alternate UPS/UTM zone. 00034 * 00035 * Methods are provided to return the geographic coordinates, the input UTM 00036 * or UPS coordinates (and associated meridian convergence and scale), or 00037 * alternate UTM or UPS coordinates (and their associated meridian 00038 * convergence and scale). 00039 * 00040 * Once the input string has been parsed, you can print the result out in any 00041 * of the formats, decimal degrees, degrees minutes seconds, MGRS, UTM/UPS. 00042 **********************************************************************/ 00043 class GeoCoords { 00044 private: 00045 typedef Math::real real; 00046 real _lat, _long, _easting, _northing, _gamma, _k; 00047 bool _northp; 00048 int _zone; // See UTMUPS::zonespec 00049 mutable real _alt_easting, _alt_northing, _alt_gamma, _alt_k; 00050 mutable int _alt_zone; 00051 00052 void CopyToAlt() const throw() { 00053 _alt_easting = _easting; 00054 _alt_northing = _northing; 00055 _alt_gamma = _gamma; 00056 _alt_k = _k; 00057 _alt_zone = _zone; 00058 } 00059 void UTMUPSString(int zone, real easting, real northing, 00060 int prec, std::string& utm) const; 00061 void FixHemisphere(); 00062 public: 00063 00064 /** 00065 * The default contructor is equivalent to \e latitude = 90<sup>o</sup>, \e 00066 * longitude = 0<sup>o</sup>. 00067 **********************************************************************/ 00068 GeoCoords() throw() 00069 // This is the N pole 00070 : _lat(90) 00071 , _long(0) 00072 , _easting(2000000) 00073 , _northing(2000000) 00074 , _northp(true) 00075 , _zone(0) 00076 { CopyToAlt(); } 00077 00078 /** 00079 * Parse as a string and interpret it as a geographic position. The input 00080 * string is broken into space (or comma) separated pieces and Basic 00081 * decision on which format is based on number of components 00082 * -# MGRS 00083 * -# "Lat Long" or "Long Lat" 00084 * -# "Zone Easting Northing" or "Easting Northing Zone" 00085 * 00086 * The following inputs are approximately the same (Ar Ramadi Bridge, Iraq) 00087 * - Latitude and Longitude 00088 * - 33.44 43.27 00089 * - N33d26.4' E43d16.2' 00090 * - 43d16'12"E 33d26'24"N 00091 * - MGRS 00092 * - 38SLC301 00093 * - 38SLC391014 00094 * - 38SLC3918701405 00095 * - 37SHT9708 00096 * - UTM 00097 * - 38N 339188 3701405 00098 * - 897039 3708229 37N 00099 * 00100 * Latitude and Longitude parsing. Latitude precedes longitude, unless a 00101 * N, S, E, W hemisphere designator is used on one or both coordinates. 00102 * Thus 00103 * - 40 -75 00104 * - N40 W75 00105 * - -75 N40 00106 * - 75W 40N 00107 * - E-75 -40S 00108 * . 00109 * are all the same position. The coodinates may be given in decimal 00110 * degrees, degrees and decimal minutes, degrees, minutes, seconds, etc. 00111 * Use d, ', and " to make off the degrees, minutes and seconds. Thus 00112 * - 40d30'30" 00113 * - 40d30'30 00114 * - 40d30.5' 00115 * - 40d30.5 00116 * - 40.508333333 00117 * . 00118 * all specify the same angle. The leading sign applies to all components 00119 * so -1d30 is -(1+30/60) = -1.5. Latitudes must be in the range [-90, 90] 00120 * and longitudes in the range [-180, 360]. Internally longitudes are 00121 * reduced to the range [-180, 180). 00122 * 00123 * UTM/UPS parsing. For UTM zones (-80 <= Lat <= 84), the zone designator 00124 * is made up of a zone number (for 1 to 60) and a hemisphere letter (N or 00125 * S), e.g., 38N. The latitude zone designer ([C–M] in the southern 00126 * hemisphere and [N–X] in the northern) should NOT be used. (This 00127 * is part of the MGRS coordinate.) The zone designator for the poles 00128 * (where UPS is employed) is a hemisphere letter by itself, i.e., N or S. 00129 * 00130 * MGRS parsing interprets the grid references as square area at the 00131 * specified precision (1m, 10m, 100m, etc.). If \e centerp = true (the 00132 * default), the center of this square is then taken to be the precise 00133 * position; thus: 00134 * - 38SMB = 38N 450000 3650000 00135 * - 38SMB4484 = 38N 444500 3684500 00136 * - 38SMB44148470 = 38N 444145 3684705 00137 * . 00138 * Otherwise, the "south-west" corner of the square is used, i.e., 00139 * - 38SMB = 38N 400000 3600000 00140 * - 38SMB4484 = 38N 444000 3684000 00141 * - 38SMB44148470 = 38N 444140 3684700 00142 **********************************************************************/ 00143 explicit GeoCoords(const std::string& s, bool centerp = true) 00144 { Reset(s, centerp); } 00145 00146 /** 00147 * Specify the location in terms of \e latitude (degrees) and \e longitude 00148 * (degrees). Use \e zone to force the UTM/UPS representation to use a 00149 * specified zone using the rules given in UTMUPS::zonespec. 00150 **********************************************************************/ 00151 GeoCoords(real latitude, real longitude, int zone = UTMUPS::STANDARD) { 00152 Reset(latitude, longitude, zone); 00153 } 00154 00155 /** 00156 * Specify the location in terms of UPS/UPS \e zone (zero means UPS), 00157 * hemisphere \e northp (false means south, true means north), \e easting 00158 * (meters) and \e northing (meters). 00159 **********************************************************************/ 00160 GeoCoords(int zone, bool northp, real easting, real northing) { 00161 Reset(zone, northp, easting, northing); 00162 } 00163 00164 /** 00165 * Reset the location as a 1-element, 2-element, or 3-element string. See 00166 * GeoCoords(const string& s, bool centerp). 00167 **********************************************************************/ 00168 void Reset(const std::string& s, bool centerp = true); 00169 00170 /** 00171 * Reset the location in terms of \e latitude and \e longitude. See 00172 * GeoCoords(real latitude, real longitude, int zone). 00173 **********************************************************************/ 00174 void Reset(real latitude, real longitude, int zone = UTMUPS::STANDARD) { 00175 UTMUPS::Forward(latitude, longitude, 00176 _zone, _northp, _easting, _northing, _gamma, _k, 00177 zone); 00178 _lat = latitude; 00179 _long = longitude; 00180 if (_long >= 180) 00181 _long -= 360; 00182 CopyToAlt(); 00183 } 00184 00185 /** 00186 * Reset the location in terms of UPS/UPS \e zone, hemisphere \e northp, \e 00187 * easting, and \e northing. See GeoCoords(int zone, bool northp, 00188 * real easting, real northing). 00189 **********************************************************************/ 00190 void Reset(int zone, bool northp, real easting, real northing) { 00191 UTMUPS::Reverse(zone, northp, easting, northing, 00192 _lat, _long, _gamma, _k); 00193 _zone = zone; 00194 _northp = northp; 00195 _easting = easting; 00196 _northing = northing; 00197 FixHemisphere(); 00198 CopyToAlt(); 00199 } 00200 00201 /** 00202 * Return latitude (degrees) 00203 **********************************************************************/ 00204 Math::real Latitude() const throw() { return _lat; } 00205 00206 /** 00207 * Return longitude (degrees) 00208 **********************************************************************/ 00209 Math::real Longitude() const throw() { return _long; } 00210 00211 /** 00212 * Return easting (meters) 00213 **********************************************************************/ 00214 Math::real Easting() const throw() { return _easting; } 00215 00216 /** 00217 * Return northing (meters) 00218 **********************************************************************/ 00219 Math::real Northing() const throw() { return _northing; } 00220 00221 /** 00222 * Return meridian convergence (degrees) for the UTM/UPS projection. 00223 **********************************************************************/ 00224 Math::real Convergence() const throw() { return _gamma; } 00225 00226 /** 00227 * Return scale for the UTM/UPS projection. 00228 **********************************************************************/ 00229 Math::real Scale() const throw() { return _k; } 00230 00231 /** 00232 * Return hemisphere (false means south, true means north). 00233 **********************************************************************/ 00234 bool Northp() const throw() { return _northp; } 00235 00236 /** 00237 * Return hemisphere letter N or S. 00238 **********************************************************************/ 00239 char Hemisphere() const throw() { return _northp ? 'N' : 'S'; } 00240 00241 /** 00242 * Return the zone corresponding to the input (return 0 for UPS). 00243 **********************************************************************/ 00244 int Zone() const throw() { return _zone; } 00245 00246 /** 00247 * Use zone number, \e zone, for the alternate representation. See 00248 * UTMUPS::zonespec for more information on the interpretation of \e zone. 00249 * Note that \e zone == UTMUPS::STANDARD (the default) use the standard UPS 00250 * or UTM zone, UTMUPS::MATCH does nothing retaining the existing alternate 00251 * representation. Before this is called the alternate zone is the input 00252 * zone. 00253 **********************************************************************/ 00254 void SetAltZone(int zone = UTMUPS::STANDARD) const { 00255 if (zone == UTMUPS::MATCH) 00256 return; 00257 zone = UTMUPS::StandardZone(_lat, _long, zone); 00258 if (zone == _zone) 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 Math::real AltEasting() const throw() { return _alt_easting; } 00278 00279 /** 00280 * Return northing (meters) for alternate zone. 00281 **********************************************************************/ 00282 Math::real AltNorthing() const throw() { return _alt_northing; } 00283 00284 /** 00285 * Return meridian convergence (degrees) for altermate zone. 00286 **********************************************************************/ 00287 Math::real AltConvergence() const throw() { return _alt_gamma; } 00288 00289 /** 00290 * Return scale for altermate zone. 00291 **********************************************************************/ 00292 Math::real 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 * The major radius of the ellipsoid (meters). This is the value for the 00364 * WGS84 ellipsoid because the UTM and UPS projections are based on this 00365 * ellipsoid. 00366 **********************************************************************/ 00367 Math::real MajorRadius() const throw() { return UTMUPS::MajorRadius(); } 00368 00369 /** 00370 * The inverse flattening of the ellipsoid. This is the value for the 00371 * WGS84 ellipsoid because the UTM and UPS projections are based on this 00372 * ellipsoid. 00373 **********************************************************************/ 00374 Math::real InverseFlattening() const throw() 00375 { return UTMUPS::InverseFlattening(); } 00376 }; 00377 00378 } // namespace GeographicLib 00379 #endif // GEOGRAPHICLIB_GEOCOORDS_HPP