00001 /** 00002 * \file GeoCoords.hpp 00003 * \brief Header for GeographicLib::GeoCoords class 00004 * 00005 * Copyright (c) Charles Karney (2008-2011) <charles@karney.com> and licensed 00006 * under the MIT/X11 License. For more information, see 00007 * http://geographiclib.sourceforge.net/ 00008 **********************************************************************/ 00009 00010 #if !defined(GEOGRAPHICLIB_GEOCOORDS_HPP) 00011 #define GEOGRAPHICLIB_GEOCOORDS_HPP 1 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 representation 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 * Example of use: 00044 * \include example-GeoCoords.cpp 00045 * 00046 * <a href="GeoConvert.1.html">GeoConvert</a> is a command-line utility 00047 * providing access to the functionality of GeoCoords. 00048 **********************************************************************/ 00049 class GEOGRAPHICLIB_EXPORT GeoCoords { 00050 private: 00051 typedef Math::real real; 00052 real _lat, _long, _easting, _northing, _gamma, _k; 00053 bool _northp; 00054 int _zone; // See UTMUPS::zonespec 00055 mutable real _alt_easting, _alt_northing, _alt_gamma, _alt_k; 00056 mutable int _alt_zone; 00057 00058 void CopyToAlt() const { 00059 _alt_easting = _easting; 00060 _alt_northing = _northing; 00061 _alt_gamma = _gamma; 00062 _alt_k = _k; 00063 _alt_zone = _zone; 00064 } 00065 static void UTMUPSString(int zone, bool northp, real easting, real northing, 00066 int prec, bool abbrev, std::string& utm); 00067 void FixHemisphere(); 00068 public: 00069 00070 /** \name Initializing the GeoCoords object 00071 **********************************************************************/ 00072 ///@{ 00073 /** 00074 * The default constructor is equivalent to \e latitude = 90°, 00075 * \e longitude = 0°. 00076 **********************************************************************/ 00077 GeoCoords() 00078 // This is the N pole 00079 : _lat(90) 00080 , _long(0) 00081 , _easting(2000000) 00082 , _northing(2000000) 00083 , _gamma(0) 00084 , _k(Constants::UPS_k0()) 00085 , _northp(true) 00086 , _zone(0) 00087 { CopyToAlt(); } 00088 00089 /** 00090 * Construct from a string. 00091 * 00092 * @param[in] s 1-element, 2-element, or 3-element string representation of 00093 * the position. 00094 * @param[in] centerp governs the interpretation of MGRS coordinates (see 00095 * below). 00096 * @param[in] swaplatlong governs the interpretation of geographic 00097 * coordinates (see below). 00098 * @exception GeographicErr if the \e s is malformed (see below). 00099 * 00100 * Parse as a string and interpret it as a geographic position. The input 00101 * string is broken into space (or comma) separated pieces and Basic 00102 * decision on which format is based on number of components 00103 * -# MGRS 00104 * -# "Lat Long" or "Long Lat" 00105 * -# "Zone Easting Northing" or "Easting Northing Zone" 00106 * 00107 * The following inputs are approximately the same (Ar Ramadi Bridge, Iraq) 00108 * - Latitude and Longitude 00109 * - 33.44 43.27 00110 * - N33d26.4' E43d16.2' 00111 * - 43d16'12"E 33d26'24"N 00112 * - 43:16:12E 33:26:24 00113 * - MGRS 00114 * - 38SLC30 00115 * - 38SLC391014 00116 * - 38SLC3918701405 00117 * - 37SHT9708 00118 * - UTM 00119 * - 38n 339188 3701405 00120 * - 897039 3708229 37n 00121 * 00122 * <b>Latitude and Longitude parsing</b>: Latitude precedes longitude, 00123 * unless a N, S, E, W hemisphere designator is used on one or both 00124 * coordinates. If \e swaplatlong = true (default is false), then 00125 * longitude precedes latitude in the absence of a hemisphere designator. 00126 * Thus (with \e swaplatlong = false) 00127 * - 40 -75 00128 * - N40 W75 00129 * - -75 N40 00130 * - 75W 40N 00131 * - E-75 -40S 00132 * . 00133 * are all the same position. The coordinates may be given in 00134 * decimal degrees, degrees and decimal minutes, degrees, minutes, 00135 * seconds, etc. Use d, ', and " to mark off the degrees, 00136 * minutes and seconds. Various alternative symbols for degrees, minutes, 00137 * and seconds are allowed. Alternatively, use : to separate these 00138 * components. (See DMS::Decode for details.) Thus 00139 * - 40d30'30" 00140 * - 40d30'30 00141 * - 40°30'30 00142 * - 40d30.5' 00143 * - 40d30.5 00144 * - 40:30:30 00145 * - 40:30.5 00146 * - 40.508333333 00147 * . 00148 * all specify the same angle. The leading sign applies to all components 00149 * so -1d30 is -(1+30/60) = -1.5. Latitudes must be in the range 00150 * [−90°, 90°] and longitudes in the range 00151 * [−540°, 540°). Internally longitudes are reduced 00152 * to the range [−180°, 180°). 00153 * 00154 * <b>UTM/UPS parsing</b>: For UTM zones (−80° ≤ Lat < 00155 * 84°), the zone designator is made up of a zone number (for 1 to 60) 00156 * and a hemisphere letter (n or s), e.g., 38n (38north can also be used). 00157 * The latitude band designer ([C--M] in the southern hemisphere and [N--X] 00158 * in the northern) should NOT be used. (This is part of the MGRS 00159 * coordinate.) The zone designator for the poles (where UPS is employed) 00160 * is a hemisphere letter by itself, i.e., n or s (north or south can also 00161 * be used). 00162 * 00163 * <b>MGRS parsing</b> interprets the grid references as square area at the 00164 * specified precision (1m, 10m, 100m, etc.). If \e centerp = true (the 00165 * default), the center of this square is then taken to be the precise 00166 * position; thus: 00167 * - 38SMB = 38n 450000 3650000 00168 * - 38SMB4484 = 38n 444500 3684500 00169 * - 38SMB44148470 = 38n 444145 3684705 00170 * . 00171 * Otherwise, the "south-west" corner of the square is used, i.e., 00172 * - 38SMB = 38n 400000 3600000 00173 * - 38SMB4484 = 38n 444000 3684000 00174 * - 38SMB44148470 = 38n 444140 3684700 00175 **********************************************************************/ 00176 explicit GeoCoords(const std::string& s, 00177 bool centerp = true, bool swaplatlong = false) 00178 { Reset(s, centerp, swaplatlong); } 00179 00180 /** 00181 * Construct from geographic coordinates. 00182 * 00183 * @param[in] latitude (degrees). 00184 * @param[in] longitude (degrees). 00185 * @param[in] zone if specified, force the UTM/UPS representation to use a 00186 * specified zone using the rules given in UTMUPS::zonespec. 00187 * @exception GeographicErr if \e latitude is not in [−90°, 00188 * 90°]. 00189 * @exception GeographicErr if \e longitude is not in [−540°, 00190 * 540°). 00191 * @exception GeographicErr if \e zone cannot be used for this location. 00192 **********************************************************************/ 00193 GeoCoords(real latitude, real longitude, int zone = UTMUPS::STANDARD) { 00194 Reset(latitude, longitude, zone); 00195 } 00196 00197 /** 00198 * Construct from UTM/UPS coordinates. 00199 * 00200 * @param[in] zone UTM zone (zero means UPS). 00201 * @param[in] northp hemisphere (true means north, false means south). 00202 * @param[in] easting (meters). 00203 * @param[in] northing (meters). 00204 * @exception GeographicErr if \e zone, \e easting, or \e northing is 00205 * outside its allowed range. 00206 **********************************************************************/ 00207 GeoCoords(int zone, bool northp, real easting, real northing) { 00208 Reset(zone, northp, easting, northing); 00209 } 00210 00211 /** 00212 * Reset the location from a string. See 00213 * GeoCoords(const std::string& s, bool centerp, bool swaplatlong). 00214 * 00215 * @param[in] s 1-element, 2-element, or 3-element string representation of 00216 * the position. 00217 * @param[in] centerp governs the interpretation of MGRS coordinates. 00218 * @param[in] swaplatlong governs the interpretation of geographic 00219 * coordinates. 00220 * @exception GeographicErr if the \e s is malformed. 00221 **********************************************************************/ 00222 void Reset(const std::string& s, 00223 bool centerp = true, bool swaplatlong = false); 00224 00225 /** 00226 * Reset the location in terms of geographic coordinates. See 00227 * GeoCoords(real latitude, real longitude, int zone). 00228 * 00229 * @param[in] latitude (degrees). 00230 * @param[in] longitude (degrees). 00231 * @param[in] zone if specified, force the UTM/UPS representation to use a 00232 * specified zone using the rules given in UTMUPS::zonespec. 00233 * @exception GeographicErr if \e latitude is not in [−90°, 00234 * 90°]. 00235 * @exception GeographicErr if \e longitude is not in [−540°, 00236 * 540°). 00237 * @exception GeographicErr if \e zone cannot be used for this location. 00238 **********************************************************************/ 00239 void Reset(real latitude, real longitude, int zone = UTMUPS::STANDARD) { 00240 UTMUPS::Forward(latitude, longitude, 00241 _zone, _northp, _easting, _northing, _gamma, _k, 00242 zone); 00243 _lat = latitude; 00244 _long = longitude; 00245 if (_long >= 180) _long -= 360; 00246 else if (_long < -180) _long += 360; 00247 CopyToAlt(); 00248 } 00249 00250 /** 00251 * Reset the location in terms of UPS/UPS coordinates. See 00252 * GeoCoords(int zone, bool northp, real easting, real northing). 00253 * 00254 * @param[in] zone UTM zone (zero means UPS). 00255 * @param[in] northp hemisphere (true means north, false means south). 00256 * @param[in] easting (meters). 00257 * @param[in] northing (meters). 00258 * @exception GeographicErr if \e zone, \e easting, or \e northing is 00259 * outside its allowed range. 00260 **********************************************************************/ 00261 void Reset(int zone, bool northp, real easting, real northing) { 00262 UTMUPS::Reverse(zone, northp, easting, northing, 00263 _lat, _long, _gamma, _k); 00264 _zone = zone; 00265 _northp = northp; 00266 _easting = easting; 00267 _northing = northing; 00268 FixHemisphere(); 00269 CopyToAlt(); 00270 } 00271 ///@} 00272 00273 /** \name Querying the GeoCoords object 00274 **********************************************************************/ 00275 ///@{ 00276 /** 00277 * @return latitude (degrees) 00278 **********************************************************************/ 00279 Math::real Latitude() const { return _lat; } 00280 00281 /** 00282 * @return longitude (degrees) 00283 **********************************************************************/ 00284 Math::real Longitude() const { return _long; } 00285 00286 /** 00287 * @return easting (meters) 00288 **********************************************************************/ 00289 Math::real Easting() const { return _easting; } 00290 00291 /** 00292 * @return northing (meters) 00293 **********************************************************************/ 00294 Math::real Northing() const { return _northing; } 00295 00296 /** 00297 * @return meridian convergence (degrees) for the UTM/UPS projection. 00298 **********************************************************************/ 00299 Math::real Convergence() const { return _gamma; } 00300 00301 /** 00302 * @return scale for the UTM/UPS projection. 00303 **********************************************************************/ 00304 Math::real Scale() const { return _k; } 00305 00306 /** 00307 * @return hemisphere (false means south, true means north). 00308 **********************************************************************/ 00309 bool Northp() const { return _northp; } 00310 00311 /** 00312 * @return hemisphere letter n or s. 00313 **********************************************************************/ 00314 char Hemisphere() const { return _northp ? 'n' : 's'; } 00315 00316 /** 00317 * @return the zone corresponding to the input (return 0 for UPS). 00318 **********************************************************************/ 00319 int Zone() const { return _zone; } 00320 00321 ///@} 00322 00323 /** \name Setting and querying the alternate zone 00324 **********************************************************************/ 00325 ///@{ 00326 /** 00327 * Specify alternate zone number. 00328 * 00329 * @param[in] zone zone number for the alternate representation. 00330 * @exception GeographicErr if \e zone cannot be used for this location. 00331 * 00332 * See UTMUPS::zonespec for more information on the interpretation of \e 00333 * zone. Note that \e zone == UTMUPS::STANDARD (the default) use the 00334 * standard UPS or UTM zone, UTMUPS::MATCH does nothing retaining the 00335 * existing alternate representation. Before this is called the alternate 00336 * zone is the input zone. 00337 **********************************************************************/ 00338 void SetAltZone(int zone = UTMUPS::STANDARD) const { 00339 if (zone == UTMUPS::MATCH) 00340 return; 00341 zone = UTMUPS::StandardZone(_lat, _long, zone); 00342 if (zone == _zone) 00343 CopyToAlt(); 00344 else { 00345 bool northp; 00346 UTMUPS::Forward(_lat, _long, 00347 _alt_zone, northp, 00348 _alt_easting, _alt_northing, _alt_gamma, _alt_k, 00349 zone); 00350 } 00351 } 00352 00353 /** 00354 * @return current alternate zone (return 0 for UPS). 00355 **********************************************************************/ 00356 int AltZone() const { return _alt_zone; } 00357 00358 /** 00359 * @return easting (meters) for alternate zone. 00360 **********************************************************************/ 00361 Math::real AltEasting() const { return _alt_easting; } 00362 00363 /** 00364 * @return northing (meters) for alternate zone. 00365 **********************************************************************/ 00366 Math::real AltNorthing() const { return _alt_northing; } 00367 00368 /** 00369 * @return meridian convergence (degrees) for alternate zone. 00370 **********************************************************************/ 00371 Math::real AltConvergence() const { return _alt_gamma; } 00372 00373 /** 00374 * @return scale for alternate zone. 00375 **********************************************************************/ 00376 Math::real AltScale() const { return _alt_k; } 00377 ///@} 00378 00379 /** \name String representations of the GeoCoords object 00380 **********************************************************************/ 00381 ///@{ 00382 /** 00383 * String representation with latitude and longitude as signed decimal 00384 * degrees. 00385 * 00386 * @param[in] prec precision (relative to about 1m). 00387 * @param[in] swaplatlong if true give longitude first (default = false) 00388 * @exception std::bad_alloc if memory for the string can't be allocated. 00389 * @return decimal latitude/longitude string representation. 00390 * 00391 * Precision specifies accuracy of representation as follows: 00392 * - prec = −5 (min), 1° 00393 * - prec = 0, 10<sup>−5</sup>° (about 1m) 00394 * - prec = 3, 10<sup>−8</sup>° 00395 * - prec = 9 (max), 10<sup>−14</sup>° 00396 **********************************************************************/ 00397 std::string GeoRepresentation(int prec = 0, bool swaplatlong = false) const; 00398 00399 /** 00400 * String representation with latitude and longitude as degrees, minutes, 00401 * seconds, and hemisphere. 00402 * 00403 * @param[in] prec precision (relative to about 1m) 00404 * @param[in] swaplatlong if true give longitude first (default = false) 00405 * @param[in] dmssep if non-null, use as the DMS separator character 00406 * (instead of d, ', " delimiters). 00407 * @exception std::bad_alloc if memory for the string can't be allocated. 00408 * @return DMS latitude/longitude string representation. 00409 * 00410 * Precision specifies accuracy of representation as follows: 00411 * - prec = −5 (min), 1° 00412 * - prec = −4, 0.1° 00413 * - prec = −3, 1' 00414 * - prec = −2, 0.1' 00415 * - prec = −1, 1" 00416 * - prec = 0, 0.1" (about 3m) 00417 * - prec = 1, 0.01" 00418 * - prec = 10 (max), 10<sup>−11</sup>" 00419 **********************************************************************/ 00420 std::string DMSRepresentation(int prec = 0, bool swaplatlong = false, 00421 char dmssep = char(0)) 00422 const; 00423 00424 /** 00425 * MGRS string. 00426 * 00427 * @param[in] prec precision (relative to about 1m). 00428 * @exception std::bad_alloc if memory for the string can't be allocated. 00429 * @return MGRS string. 00430 * 00431 * This gives the coordinates of the enclosing grid square with size given 00432 * by the precision. Thus 38n 444180 3684790 converted to a MGRS 00433 * coordinate at precision −2 (100m) is 38SMB441847 and not 00434 * 38SMB442848. \e prec specifies the precision of the MGRS string as 00435 * follows: 00436 * - prec = −5 (min), 100km 00437 * - prec = −4, 10km 00438 * - prec = −3, 1km 00439 * - prec = −2, 100m 00440 * - prec = −1, 10m 00441 * - prec = 0, 1m 00442 * - prec = 1, 0.1m 00443 * - prec = 6 (max), 1μm 00444 **********************************************************************/ 00445 std::string MGRSRepresentation(int prec = 0) const; 00446 00447 /** 00448 * UTM/UPS string. 00449 * 00450 * @param[in] prec precision (relative to about 1m) 00451 * @param[in] abbrev if true (the default) use abbreviated (n/s) notation 00452 * for hemisphere; otherwise spell out the hemisphere (north/south) 00453 * @exception std::bad_alloc if memory for the string can't be allocated. 00454 * @return UTM/UPS string representation: zone designator, easting, and 00455 * northing. 00456 * 00457 * Precision specifies accuracy of representation as follows: 00458 * - prec = −5 (min), 100km 00459 * - prec = −3, 1km 00460 * - prec = 0, 1m 00461 * - prec = 3, 1mm 00462 * - prec = 6, 1μm 00463 * - prec = 9 (max), 1nm 00464 **********************************************************************/ 00465 std::string UTMUPSRepresentation(int prec = 0, bool abbrev = true) const; 00466 00467 /** 00468 * UTM/UPS string with hemisphere override. 00469 * 00470 * @param[in] northp hemisphere override 00471 * @param[in] prec precision (relative to about 1m) 00472 * @param[in] abbrev if true (the default) use abbreviated (n/s) notation 00473 * for hemisphere; otherwise spell out the hemisphere (north/south) 00474 * @exception GeographicErr if the hemisphere override attempts to change 00475 * UPS N to UPS S or vice versa. 00476 * @exception std::bad_alloc if memory for the string can't be allocated. 00477 * @return UTM/UPS string representation: zone designator, easting, and 00478 * northing. 00479 **********************************************************************/ 00480 std::string UTMUPSRepresentation(bool northp, int prec = 0, 00481 bool abbrev = true) const; 00482 00483 /** 00484 * MGRS string for the alternate zone. See GeoCoords::MGRSRepresentation. 00485 * 00486 * @param[in] prec precision (relative to about 1m). 00487 * @exception std::bad_alloc if memory for the string can't be allocated. 00488 * @return MGRS string. 00489 **********************************************************************/ 00490 std::string AltMGRSRepresentation(int prec = 0) const; 00491 00492 /** 00493 * UTM/UPS string for the alternate zone. See 00494 * GeoCoords::UTMUPSRepresentation. 00495 * 00496 * @param[in] prec precision (relative to about 1m) 00497 * @param[in] abbrev if true (the default) use abbreviated (n/s) notation 00498 * for hemisphere; otherwise spell out the hemisphere (north/south) 00499 * @exception std::bad_alloc if memory for the string can't be allocated. 00500 * @return UTM/UPS string representation: zone designator, easting, and 00501 * northing. 00502 **********************************************************************/ 00503 std::string AltUTMUPSRepresentation(int prec = 0, bool abbrev = true) const; 00504 00505 /** 00506 * UTM/UPS string for the alternate zone, with hemisphere override. 00507 * 00508 * @param[in] northp hemisphere override 00509 * @param[in] prec precision (relative to about 1m) 00510 * @param[in] abbrev if true (the default) use abbreviated (n/s) notation 00511 * for hemisphere; otherwise spell out the hemisphere (north/south) 00512 * @exception GeographicErr if the hemisphere override attempts to change 00513 * UPS n to UPS s or vice verse. 00514 * @exception std::bad_alloc if memory for the string can't be allocated. 00515 * @return UTM/UPS string representation: zone designator, easting, and 00516 * northing. 00517 **********************************************************************/ 00518 std::string AltUTMUPSRepresentation(bool northp, int prec = 0, 00519 bool abbrev = true) const; 00520 ///@} 00521 00522 /** \name Inspector functions 00523 **********************************************************************/ 00524 ///@{ 00525 /** 00526 * @return \e a the equatorial radius of the WGS84 ellipsoid (meters). 00527 * 00528 * (The WGS84 value is returned because the UTM and UPS projections are 00529 * based on this ellipsoid.) 00530 **********************************************************************/ 00531 Math::real MajorRadius() const { return UTMUPS::MajorRadius(); } 00532 00533 /** 00534 * @return \e f the flattening of the WGS84 ellipsoid. 00535 * 00536 * (The WGS84 value is returned because the UTM and UPS projections are 00537 * based on this ellipsoid.) 00538 **********************************************************************/ 00539 Math::real Flattening() const { return UTMUPS::Flattening(); } 00540 ///@} 00541 00542 /// \cond SKIP 00543 /** 00544 * <b>DEPRECATED</b> 00545 * @return \e r the inverse flattening of the ellipsoid. 00546 **********************************************************************/ 00547 Math::real InverseFlattening() const 00548 { return UTMUPS::InverseFlattening(); } 00549 /// \endcond 00550 }; 00551 00552 } // namespace GeographicLib 00553 00554 #endif // GEOGRAPHICLIB_GEOCOORDS_HPP