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 6876 2010-10-18 13:47:55Z 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 /** \name Initializing the GeoCoords object 00065 **********************************************************************/ 00066 ///@{ 00067 /** 00068 * The default contructor is equivalent to \e latitude = 90<sup>o</sup>, \e 00069 * longitude = 0<sup>o</sup>. 00070 **********************************************************************/ 00071 GeoCoords() throw() 00072 // This is the N pole 00073 : _lat(90) 00074 , _long(0) 00075 , _easting(2000000) 00076 , _northing(2000000) 00077 , _northp(true) 00078 , _zone(0) 00079 { CopyToAlt(); } 00080 00081 /** 00082 * Construct from a string. 00083 * 00084 * @param[in] s 1-element, 2-element, or 3-element string representation of 00085 * the position. 00086 * @param[in] centerp governs the interpretation of MGRS coordinates (see 00087 * below). 00088 * 00089 * Parse as a string and interpret it as a geographic position. The input 00090 * string is broken into space (or comma) separated pieces and Basic 00091 * decision on which format is based on number of components 00092 * -# MGRS 00093 * -# "Lat Long" or "Long Lat" 00094 * -# "Zone Easting Northing" or "Easting Northing Zone" 00095 * 00096 * The following inputs are approximately the same (Ar Ramadi Bridge, Iraq) 00097 * - Latitude and Longitude 00098 * - 33.44 43.27 00099 * - N33d26.4' E43d16.2' 00100 * - 43d16'12"E 33d26'24"N 00101 * - MGRS 00102 * - 38SLC301 00103 * - 38SLC391014 00104 * - 38SLC3918701405 00105 * - 37SHT9708 00106 * - UTM 00107 * - 38N 339188 3701405 00108 * - 897039 3708229 37N 00109 * 00110 * Latitude and Longitude parsing. Latitude precedes longitude, unless a 00111 * N, S, E, W hemisphere designator is used on one or both coordinates. 00112 * Thus 00113 * - 40 -75 00114 * - N40 W75 00115 * - -75 N40 00116 * - 75W 40N 00117 * - E-75 -40S 00118 * . 00119 * are all the same position. The coodinates may be given in decimal 00120 * degrees, degrees and decimal minutes, degrees, minutes, seconds, etc. 00121 * Use d, ', and " to make off the degrees, minutes and seconds. Thus 00122 * - 40d30'30" 00123 * - 40d30'30 00124 * - 40d30.5' 00125 * - 40d30.5 00126 * - 40.508333333 00127 * . 00128 * all specify the same angle. The leading sign applies to all components 00129 * so -1d30 is -(1+30/60) = -1.5. Latitudes must be in the range [-90, 90] 00130 * and longitudes in the range [-180, 360]. Internally longitudes are 00131 * reduced to the range [-180, 180). 00132 * 00133 * UTM/UPS parsing. For UTM zones (-80 <= Lat <= 84), the zone designator 00134 * is made up of a zone number (for 1 to 60) and a hemisphere letter (N or 00135 * S), e.g., 38N. The latitude zone designer ([C–M] in the southern 00136 * hemisphere and [N–X] in the northern) should NOT be used. (This 00137 * is part of the MGRS coordinate.) The zone designator for the poles 00138 * (where UPS is employed) is a hemisphere letter by itself, i.e., N or S. 00139 * 00140 * MGRS parsing interprets the grid references as square area at the 00141 * specified precision (1m, 10m, 100m, etc.). If \e centerp = true (the 00142 * default), the center of this square is then taken to be the precise 00143 * position; thus: 00144 * - 38SMB = 38N 450000 3650000 00145 * - 38SMB4484 = 38N 444500 3684500 00146 * - 38SMB44148470 = 38N 444145 3684705 00147 * . 00148 * Otherwise, the "south-west" corner of the square is used, i.e., 00149 * - 38SMB = 38N 400000 3600000 00150 * - 38SMB4484 = 38N 444000 3684000 00151 * - 38SMB44148470 = 38N 444140 3684700 00152 **********************************************************************/ 00153 explicit GeoCoords(const std::string& s, bool centerp = true) 00154 { Reset(s, centerp); } 00155 00156 /** 00157 * Construct from geographic coordinates. 00158 * 00159 * @param[in] latitude (degrees). 00160 * @param[in] longitude (degrees). 00161 * @param[in] zone if specified, force the UTM/UPS representation to use a 00162 * specified zone using the rules given in UTMUPS::zonespec. 00163 **********************************************************************/ 00164 GeoCoords(real latitude, real longitude, int zone = UTMUPS::STANDARD) { 00165 Reset(latitude, longitude, zone); 00166 } 00167 00168 /** 00169 * Construct from UTM/UPS coordinates. 00170 * 00171 * @param[in] zone UTM zone (zero means UPS). 00172 * @param[in] northp hemisphere (true means north, false means south). 00173 * @param[in] easting (meters). 00174 * @param[in] northing (meters). 00175 **********************************************************************/ 00176 GeoCoords(int zone, bool northp, real easting, real northing) { 00177 Reset(zone, northp, easting, northing); 00178 } 00179 00180 /** 00181 * Reset the location from a string. See 00182 * GeoCoords(const std::string& s, bool centerp). 00183 **********************************************************************/ 00184 void Reset(const std::string& s, bool centerp = true); 00185 00186 /** 00187 * Reset the location in terms of geographic coordinates. See 00188 * GeoCoords(real latitude, real longitude, int zone). 00189 **********************************************************************/ 00190 void Reset(real latitude, real longitude, int zone = UTMUPS::STANDARD) { 00191 UTMUPS::Forward(latitude, longitude, 00192 _zone, _northp, _easting, _northing, _gamma, _k, 00193 zone); 00194 _lat = latitude; 00195 _long = longitude; 00196 if (_long >= 180) 00197 _long -= 360; 00198 CopyToAlt(); 00199 } 00200 00201 /** 00202 * Reset the location in terms of UPS/UPS coordinates. See 00203 * GeoCoords(int zone, bool northp, real easting, real northing). 00204 **********************************************************************/ 00205 void Reset(int zone, bool northp, real easting, real northing) { 00206 UTMUPS::Reverse(zone, northp, easting, northing, 00207 _lat, _long, _gamma, _k); 00208 _zone = zone; 00209 _northp = northp; 00210 _easting = easting; 00211 _northing = northing; 00212 FixHemisphere(); 00213 CopyToAlt(); 00214 } 00215 ///@} 00216 00217 /** \name Querying the GeoCoords object 00218 **********************************************************************/ 00219 ///@{ 00220 /** 00221 * @return latitude (degrees) 00222 **********************************************************************/ 00223 Math::real Latitude() const throw() { return _lat; } 00224 00225 /** 00226 * @return longitude (degrees) 00227 **********************************************************************/ 00228 Math::real Longitude() const throw() { return _long; } 00229 00230 /** 00231 * @return easting (meters) 00232 **********************************************************************/ 00233 Math::real Easting() const throw() { return _easting; } 00234 00235 /** 00236 * @return northing (meters) 00237 **********************************************************************/ 00238 Math::real Northing() const throw() { return _northing; } 00239 00240 /** 00241 * @return meridian convergence (degrees) for the UTM/UPS projection. 00242 **********************************************************************/ 00243 Math::real Convergence() const throw() { return _gamma; } 00244 00245 /** 00246 * @return scale for the UTM/UPS projection. 00247 **********************************************************************/ 00248 Math::real Scale() const throw() { return _k; } 00249 00250 /** 00251 * @return hemisphere (false means south, true means north). 00252 **********************************************************************/ 00253 bool Northp() const throw() { return _northp; } 00254 00255 /** 00256 * @return hemisphere letter N or S. 00257 **********************************************************************/ 00258 char Hemisphere() const throw() { return _northp ? 'N' : 'S'; } 00259 00260 /** 00261 * @return the zone corresponding to the input (return 0 for UPS). 00262 **********************************************************************/ 00263 int Zone() const throw() { return _zone; } 00264 00265 ///@} 00266 00267 /** \name Setting and querying the alternate zone 00268 **********************************************************************/ 00269 ///@{ 00270 /** 00271 * Specify alternate zone number. 00272 * 00273 * @param[in] zone zone number for the alternate representation. 00274 * 00275 * See UTMUPS::zonespec for more information on the interpretation of \e 00276 * zone. Note that \e zone == UTMUPS::STANDARD (the default) use the 00277 * standard UPS or UTM zone, UTMUPS::MATCH does nothing retaining the 00278 * existing alternate representation. Before this is called the alternate 00279 * zone is the input zone. 00280 **********************************************************************/ 00281 void SetAltZone(int zone = UTMUPS::STANDARD) const { 00282 if (zone == UTMUPS::MATCH) 00283 return; 00284 zone = UTMUPS::StandardZone(_lat, _long, zone); 00285 if (zone == _zone) 00286 CopyToAlt(); 00287 else { 00288 bool northp; 00289 UTMUPS::Forward(_lat, _long, 00290 _alt_zone, northp, 00291 _alt_easting, _alt_northing, _alt_gamma, _alt_k, 00292 zone); 00293 } 00294 } 00295 00296 /** 00297 * @return current alternate zone (return 0 for UPS). 00298 **********************************************************************/ 00299 int AltZone() const throw() { return _alt_zone; } 00300 00301 /** 00302 * @return easting (meters) for alternate zone. 00303 **********************************************************************/ 00304 Math::real AltEasting() const throw() { return _alt_easting; } 00305 00306 /** 00307 * @return northing (meters) for alternate zone. 00308 **********************************************************************/ 00309 Math::real AltNorthing() const throw() { return _alt_northing; } 00310 00311 /** 00312 * @return meridian convergence (degrees) for altermate zone. 00313 **********************************************************************/ 00314 Math::real AltConvergence() const throw() { return _alt_gamma; } 00315 00316 /** 00317 * @return scale for altermate zone. 00318 **********************************************************************/ 00319 Math::real AltScale() const throw() { return _alt_k; } 00320 ///@} 00321 00322 /** \name String representations of the GeoCoords object 00323 **********************************************************************/ 00324 ///@{ 00325 /** 00326 * String representation with latitude and longitude as signed decimal 00327 * degrees. 00328 * 00329 * @param[in] prec precision (relative to about 1m). 00330 * @return decimal latitude/longitude string representation. 00331 * 00332 * Precision specifies accuracy of representation as follows: 00333 * - prec = -5 (min), 1d 00334 * - prec = 0, 10<sup>-5</sup>d (about 1m) 00335 * - prec = 3, 10<sup>-8</sup>d 00336 * - prec = 9 (max), 10<sup>-14</sup>d 00337 **********************************************************************/ 00338 std::string GeoRepresentation(int prec = 0) const; 00339 00340 /** 00341 * String representation with latitude and longitude as degrees, minutes, 00342 * seconds, and hemisphere. 00343 * 00344 * @param[in] prec precision (relative to about 1m) 00345 * @return DMS latitude/longitude string representation. 00346 * 00347 * Precision specifies accuracy of representation as follows: 00348 * - prec = -5 (min), 1d 00349 * - prec = -4, 0.1d 00350 * - prec = -3, 1' 00351 * - prec = -2, 0.1' 00352 * - prec = -1, 1" 00353 * - prec = 0, 0.1" (about 3m) 00354 * - prec = 1, 0.01" 00355 * - prec = 10 (max), 10<sup>-11</sup>" 00356 **********************************************************************/ 00357 std::string DMSRepresentation(int prec = 0) const; 00358 00359 /** 00360 * MGRS string. 00361 * 00362 * @param[in] prec precision (relative to about 1m). 00363 * @return MGRS string. 00364 * 00365 * This gives the coordinates of the enclosing grid square with size given 00366 * by the precision. Thus 38N 444180 3684790 converted to a MGRS 00367 * coordinate at precision -2 (100m) is 38SMB441847 and not 38SMB442848. 00368 * \e prec specifies the precision of the MSGRS string as follows: 00369 * - prec = -5 (min), 100km 00370 * - prec = -4, 10km 00371 * - prec = -3, 1km 00372 * - prec = -2, 100m 00373 * - prec = -1, 10m 00374 * - prec = 0, 1m 00375 * - prec = 1, 0.1m 00376 * - prec = 6 (max), 1um 00377 **********************************************************************/ 00378 std::string MGRSRepresentation(int prec = 0) const; 00379 00380 /** 00381 * UTM/UPS string. 00382 * 00383 * @param[in] prec precision (relative to about 1m) 00384 * @return UTM/UPS string representation: zone designator, easting, and 00385 * northing. 00386 * 00387 * Precision specifies accuracy of representation as follows: 00388 * - prec = -5 (min), 100km 00389 * - prec = -3, 1km 00390 * - prec = 0, 1m 00391 * - prec = 3, 1mm 00392 * - prec = 6, 1um 00393 * - prec = 9 (max), 1nm 00394 **********************************************************************/ 00395 std::string UTMUPSRepresentation(int prec = 0) const; 00396 00397 /** 00398 * MGRS string for the alternate zone. See GeoCoords::MGRSRepresentation. 00399 **********************************************************************/ 00400 std::string AltMGRSRepresentation(int prec = 0) const; 00401 00402 /** 00403 * UTM/UPS string for the alternate zone. See 00404 * GeoCoords::UTMUPSRepresentation. 00405 **********************************************************************/ 00406 std::string AltUTMUPSRepresentation(int prec = 0) const; 00407 ///@} 00408 00409 /** \name Inspector functions 00410 **********************************************************************/ 00411 ///@{ 00412 /** 00413 * @return \e a the equatorial radius of the WGS84 ellipsoid (meters). 00414 * 00415 * (The WGS84 value is returned because the UTM and UPS projections are 00416 * based on this ellipsoid.) 00417 **********************************************************************/ 00418 Math::real MajorRadius() const throw() { return UTMUPS::MajorRadius(); } 00419 00420 /** 00421 * @return \e r the inverse flattening of the WGS84 ellipsoid. 00422 * 00423 * (The WGS84 value is returned because the UTM and UPS projections are 00424 * based on this ellipsoid.) 00425 **********************************************************************/ 00426 Math::real InverseFlattening() const throw() 00427 { return UTMUPS::InverseFlattening(); } 00428 ///@} 00429 }; 00430 00431 } // namespace GeographicLib 00432 #endif // GEOGRAPHICLIB_GEOCOORDS_HPP