GeographicLib
1.21
|
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 #ifndef GEOGRAPHICLIB_GEOCOORDS_HPP 00011 #define GEOGRAPHICLIB_GEOCOORDS_HPP \ 00012 "$Id: e706d3a35c3be0e2beaf39041cac29beb468a5aa $" 00013 00014 #include <GeographicLib/UTMUPS.hpp> 00015 #include <GeographicLib/Constants.hpp> 00016 00017 namespace GeographicLib { 00018 00019 /** 00020 * \brief Conversion between geographic coordinates 00021 * 00022 * This class stores a geographic position which may be set via the 00023 * constructors or Reset via 00024 * - latitude and longitude 00025 * - UTM or UPS coordinates 00026 * - a string representation of these or an MGRS coordinate string 00027 * 00028 * The state consists of the latitude and longitude and the supplied UTM or 00029 * UPS coordinates (possibly derived from the MGRS coordinates). If latitude 00030 * and longitude were given then the UTM/UPS coordinates follows the standard 00031 * conventions. 00032 * 00033 * The mutable state consists of the UTM or UPS coordinates for a alternate 00034 * zone. A method SetAltZone is provided to set the alternate UPS/UTM zone. 00035 * 00036 * Methods are provided to return the geographic coordinates, the input UTM 00037 * or UPS coordinates (and associated meridian convergence and scale), or 00038 * alternate UTM or UPS coordinates (and their associated meridian 00039 * convergence and scale). 00040 * 00041 * Once the input string has been parsed, you can print the result out in any 00042 * of the formats, decimal degrees, degrees minutes seconds, MGRS, UTM/UPS. 00043 * 00044 * Example of use: 00045 * \include example-GeoCoords.cpp 00046 * 00047 * <a href="GeoConvert.1.html">GeoConvert</a> is a command-line utility 00048 * providing access to the functionality of GeoCoords. 00049 **********************************************************************/ 00050 class GEOGRAPHIC_EXPORT GeoCoords { 00051 private: 00052 typedef Math::real real; 00053 real _lat, _long, _easting, _northing, _gamma, _k; 00054 bool _northp; 00055 int _zone; // See UTMUPS::zonespec 00056 mutable real _alt_easting, _alt_northing, _alt_gamma, _alt_k; 00057 mutable int _alt_zone; 00058 00059 void CopyToAlt() const throw() { 00060 _alt_easting = _easting; 00061 _alt_northing = _northing; 00062 _alt_gamma = _gamma; 00063 _alt_k = _k; 00064 _alt_zone = _zone; 00065 } 00066 void UTMUPSString(int zone, real easting, real northing, 00067 int prec, std::string& utm) const; 00068 void FixHemisphere(); 00069 public: 00070 00071 /** \name Initializing the GeoCoords object 00072 **********************************************************************/ 00073 ///@{ 00074 /** 00075 * The default constructor is equivalent to \e latitude = 90<sup>o</sup>, 00076 * \e longitude = 0<sup>o</sup>. 00077 **********************************************************************/ 00078 GeoCoords() throw() 00079 // This is the N pole 00080 : _lat(90) 00081 , _long(0) 00082 , _easting(2000000) 00083 , _northing(2000000) 00084 , _northp(true) 00085 , _zone(0) 00086 { CopyToAlt(); } 00087 00088 /** 00089 * Construct from a string. 00090 * 00091 * @param[in] s 1-element, 2-element, or 3-element string representation of 00092 * the position. 00093 * @param[in] centerp governs the interpretation of MGRS coordinates (see 00094 * below). 00095 * @param[in] swaplatlong governs the interpretation of geographic 00096 * coordinates (see below). 00097 * 00098 * Parse as a string and interpret it as a geographic position. The input 00099 * string is broken into space (or comma) separated pieces and Basic 00100 * decision on which format is based on number of components 00101 * -# MGRS 00102 * -# "Lat Long" or "Long Lat" 00103 * -# "Zone Easting Northing" or "Easting Northing Zone" 00104 * 00105 * The following inputs are approximately the same (Ar Ramadi Bridge, Iraq) 00106 * - Latitude and Longitude 00107 * - 33.44 43.27 00108 * - N33d26.4' E43d16.2' 00109 * - 43d16'12"E 33d26'24"N 00110 * - 43:16:12E 33:26:24 00111 * - MGRS 00112 * - 38SLC301 00113 * - 38SLC391014 00114 * - 38SLC3918701405 00115 * - 37SHT9708 00116 * - UTM 00117 * - 38N 339188 3701405 00118 * - 897039 3708229 37N 00119 * 00120 * Latitude and Longitude parsing. Latitude precedes longitude, unless a 00121 * N, S, E, W hemisphere designator is used on one or both coordinates. If 00122 * \e swaplatlong = true (default is false), then longitude precedes 00123 * latitude in the absence of a hemisphere designator. Thus (with \e 00124 * swaplatlong = false) 00125 * - 40 -75 00126 * - N40 W75 00127 * - -75 N40 00128 * - 75W 40N 00129 * - E-75 -40S 00130 * . 00131 * are all the same position. The coordinates may be given in 00132 * decimal degrees, degrees and decimal minutes, degrees, minutes, 00133 * seconds, etc. Use d, ', and " to mark off the degrees, 00134 * minutes and seconds. Alternatively, use : to separate these 00135 * components. Thus 00136 * - 40d30'30" 00137 * - 40d30'30 00138 * - 40d30.5' 00139 * - 40d30.5 00140 * - 40:30:30 00141 * - 40:30.5 00142 * - 40.508333333 00143 * . 00144 * all specify the same angle. The leading sign applies to all components 00145 * so -1d30 is -(1+30/60) = -1.5. Latitudes must be in the range [-90, 90] 00146 * and longitudes in the range [-180, 360]. Internally longitudes are 00147 * reduced to the range [-180, 180). 00148 * 00149 * UTM/UPS parsing. For UTM zones (-80 <= Lat <= 84), the zone designator 00150 * is made up of a zone number (for 1 to 60) and a hemisphere letter (N or 00151 * S), e.g., 38N. The latitude zone designer ([C–M] in the southern 00152 * hemisphere and [N–X] in the northern) should NOT be used. (This 00153 * is part of the MGRS coordinate.) The zone designator for the poles 00154 * (where UPS is employed) is a hemisphere letter by itself, i.e., N or S. 00155 * 00156 * MGRS parsing interprets the grid references as square area at the 00157 * specified precision (1m, 10m, 100m, etc.). If \e centerp = true (the 00158 * default), the center of this square is then taken to be the precise 00159 * position; thus: 00160 * - 38SMB = 38N 450000 3650000 00161 * - 38SMB4484 = 38N 444500 3684500 00162 * - 38SMB44148470 = 38N 444145 3684705 00163 * . 00164 * Otherwise, the "south-west" corner of the square is used, i.e., 00165 * - 38SMB = 38N 400000 3600000 00166 * - 38SMB4484 = 38N 444000 3684000 00167 * - 38SMB44148470 = 38N 444140 3684700 00168 **********************************************************************/ 00169 explicit GeoCoords(const std::string& s, 00170 bool centerp = true, bool swaplatlong = false) 00171 { Reset(s, centerp, swaplatlong); } 00172 00173 /** 00174 * Construct from geographic coordinates. 00175 * 00176 * @param[in] latitude (degrees). 00177 * @param[in] longitude (degrees). 00178 * @param[in] zone if specified, force the UTM/UPS representation to use a 00179 * specified zone using the rules given in UTMUPS::zonespec. 00180 **********************************************************************/ 00181 GeoCoords(real latitude, real longitude, int zone = UTMUPS::STANDARD) { 00182 Reset(latitude, longitude, zone); 00183 } 00184 00185 /** 00186 * Construct from UTM/UPS coordinates. 00187 * 00188 * @param[in] zone UTM zone (zero means UPS). 00189 * @param[in] northp hemisphere (true means north, false means south). 00190 * @param[in] easting (meters). 00191 * @param[in] northing (meters). 00192 **********************************************************************/ 00193 GeoCoords(int zone, bool northp, real easting, real northing) { 00194 Reset(zone, northp, easting, northing); 00195 } 00196 00197 /** 00198 * Reset the location from a string. See 00199 * GeoCoords(const std::string& s, bool centerp, bool swaplatlong). 00200 **********************************************************************/ 00201 void Reset(const std::string& s, 00202 bool centerp = true, bool swaplatlong = false); 00203 00204 /** 00205 * Reset the location in terms of geographic coordinates. See 00206 * GeoCoords(real latitude, real longitude, int zone). 00207 **********************************************************************/ 00208 void Reset(real latitude, real longitude, int zone = UTMUPS::STANDARD) { 00209 UTMUPS::Forward(latitude, longitude, 00210 _zone, _northp, _easting, _northing, _gamma, _k, 00211 zone); 00212 _lat = latitude; 00213 _long = longitude; 00214 if (_long >= 180) 00215 _long -= 360; 00216 CopyToAlt(); 00217 } 00218 00219 /** 00220 * Reset the location in terms of UPS/UPS coordinates. See 00221 * GeoCoords(int zone, bool northp, real easting, real northing). 00222 **********************************************************************/ 00223 void Reset(int zone, bool northp, real easting, real northing) { 00224 UTMUPS::Reverse(zone, northp, easting, northing, 00225 _lat, _long, _gamma, _k); 00226 _zone = zone; 00227 _northp = northp; 00228 _easting = easting; 00229 _northing = northing; 00230 FixHemisphere(); 00231 CopyToAlt(); 00232 } 00233 ///@} 00234 00235 /** \name Querying the GeoCoords object 00236 **********************************************************************/ 00237 ///@{ 00238 /** 00239 * @return latitude (degrees) 00240 **********************************************************************/ 00241 Math::real Latitude() const throw() { return _lat; } 00242 00243 /** 00244 * @return longitude (degrees) 00245 **********************************************************************/ 00246 Math::real Longitude() const throw() { return _long; } 00247 00248 /** 00249 * @return easting (meters) 00250 **********************************************************************/ 00251 Math::real Easting() const throw() { return _easting; } 00252 00253 /** 00254 * @return northing (meters) 00255 **********************************************************************/ 00256 Math::real Northing() const throw() { return _northing; } 00257 00258 /** 00259 * @return meridian convergence (degrees) for the UTM/UPS projection. 00260 **********************************************************************/ 00261 Math::real Convergence() const throw() { return _gamma; } 00262 00263 /** 00264 * @return scale for the UTM/UPS projection. 00265 **********************************************************************/ 00266 Math::real Scale() const throw() { return _k; } 00267 00268 /** 00269 * @return hemisphere (false means south, true means north). 00270 **********************************************************************/ 00271 bool Northp() const throw() { return _northp; } 00272 00273 /** 00274 * @return hemisphere letter N or S. 00275 **********************************************************************/ 00276 char Hemisphere() const throw() { return _northp ? 'N' : 'S'; } 00277 00278 /** 00279 * @return the zone corresponding to the input (return 0 for UPS). 00280 **********************************************************************/ 00281 int Zone() const throw() { return _zone; } 00282 00283 ///@} 00284 00285 /** \name Setting and querying the alternate zone 00286 **********************************************************************/ 00287 ///@{ 00288 /** 00289 * Specify alternate zone number. 00290 * 00291 * @param[in] zone zone number for the alternate representation. 00292 * 00293 * See UTMUPS::zonespec for more information on the interpretation of \e 00294 * zone. Note that \e zone == UTMUPS::STANDARD (the default) use the 00295 * standard UPS or UTM zone, UTMUPS::MATCH does nothing retaining the 00296 * existing alternate representation. Before this is called the alternate 00297 * zone is the input zone. 00298 **********************************************************************/ 00299 void SetAltZone(int zone = UTMUPS::STANDARD) const { 00300 if (zone == UTMUPS::MATCH) 00301 return; 00302 zone = UTMUPS::StandardZone(_lat, _long, zone); 00303 if (zone == _zone) 00304 CopyToAlt(); 00305 else { 00306 bool northp; 00307 UTMUPS::Forward(_lat, _long, 00308 _alt_zone, northp, 00309 _alt_easting, _alt_northing, _alt_gamma, _alt_k, 00310 zone); 00311 } 00312 } 00313 00314 /** 00315 * @return current alternate zone (return 0 for UPS). 00316 **********************************************************************/ 00317 int AltZone() const throw() { return _alt_zone; } 00318 00319 /** 00320 * @return easting (meters) for alternate zone. 00321 **********************************************************************/ 00322 Math::real AltEasting() const throw() { return _alt_easting; } 00323 00324 /** 00325 * @return northing (meters) for alternate zone. 00326 **********************************************************************/ 00327 Math::real AltNorthing() const throw() { return _alt_northing; } 00328 00329 /** 00330 * @return meridian convergence (degrees) for alternate zone. 00331 **********************************************************************/ 00332 Math::real AltConvergence() const throw() { return _alt_gamma; } 00333 00334 /** 00335 * @return scale for alternate zone. 00336 **********************************************************************/ 00337 Math::real AltScale() const throw() { return _alt_k; } 00338 ///@} 00339 00340 /** \name String representations of the GeoCoords object 00341 **********************************************************************/ 00342 ///@{ 00343 /** 00344 * String representation with latitude and longitude as signed decimal 00345 * degrees. 00346 * 00347 * @param[in] prec precision (relative to about 1m). 00348 * @param[in] swaplatlong if true give longitude first (default = false) 00349 * @return decimal latitude/longitude string representation. 00350 * 00351 * Precision specifies accuracy of representation as follows: 00352 * - prec = -5 (min), 1d 00353 * - prec = 0, 10<sup>-5</sup>d (about 1m) 00354 * - prec = 3, 10<sup>-8</sup>d 00355 * - prec = 9 (max), 10<sup>-14</sup>d 00356 **********************************************************************/ 00357 std::string GeoRepresentation(int prec = 0, bool swaplatlong = false) const; 00358 00359 /** 00360 * String representation with latitude and longitude as degrees, minutes, 00361 * seconds, and hemisphere. 00362 * 00363 * @param[in] prec precision (relative to about 1m) 00364 * @param[in] swaplatlong if true give longitude first (default = false) 00365 * @param[in] dmssep if non-null, use as the DMS separator character 00366 * (instead of d, ', " delimiters). 00367 * @return DMS latitude/longitude string representation. 00368 * 00369 * Precision specifies accuracy of representation as follows: 00370 * - prec = -5 (min), 1d 00371 * - prec = -4, 0.1d 00372 * - prec = -3, 1' 00373 * - prec = -2, 0.1' 00374 * - prec = -1, 1" 00375 * - prec = 0, 0.1" (about 3m) 00376 * - prec = 1, 0.01" 00377 * - prec = 10 (max), 10<sup>-11</sup>" 00378 **********************************************************************/ 00379 std::string DMSRepresentation(int prec, bool swaplatlong, char dmssep) 00380 const; 00381 00382 /** 00383 * String representation with latitude and longitude as degrees, minutes, 00384 * seconds, and hemisphere. 00385 * 00386 * @param[in] prec precision (relative to about 1m) 00387 * @param[in] swaplatlong if true give longitude first (default = false) 00388 * @return DMS latitude/longitude string representation. 00389 * 00390 * <b>COMPATIBILITY NOTE:</b> This function calls 00391 * DMSRepresentation(int, bool, char) const with a 3rd argument of 00392 * char(0). At some point, DMSRepresentation(int, bool) const and 00393 * will be withdrawn and the interface to 00394 * DMSRepresentation(int, bool, char) const changed so that its 00395 * arguments have default values. This will preserve source-level 00396 * compatibility. 00397 **********************************************************************/ 00398 std::string DMSRepresentation(int prec = 0, bool swaplatlong = false) const; 00399 00400 /** 00401 * MGRS string. 00402 * 00403 * @param[in] prec precision (relative to about 1m). 00404 * @return MGRS string. 00405 * 00406 * This gives the coordinates of the enclosing grid square with size given 00407 * by the precision. Thus 38N 444180 3684790 converted to a MGRS 00408 * coordinate at precision -2 (100m) is 38SMB441847 and not 38SMB442848. 00409 * \e prec specifies the precision of the MGRS string as follows: 00410 * - prec = -5 (min), 100km 00411 * - prec = -4, 10km 00412 * - prec = -3, 1km 00413 * - prec = -2, 100m 00414 * - prec = -1, 10m 00415 * - prec = 0, 1m 00416 * - prec = 1, 0.1m 00417 * - prec = 6 (max), 1um 00418 **********************************************************************/ 00419 std::string MGRSRepresentation(int prec = 0) const; 00420 00421 /** 00422 * UTM/UPS string. 00423 * 00424 * @param[in] prec precision (relative to about 1m) 00425 * @return UTM/UPS string representation: zone designator, easting, and 00426 * northing. 00427 * 00428 * Precision specifies accuracy of representation as follows: 00429 * - prec = -5 (min), 100km 00430 * - prec = -3, 1km 00431 * - prec = 0, 1m 00432 * - prec = 3, 1mm 00433 * - prec = 6, 1um 00434 * - prec = 9 (max), 1nm 00435 **********************************************************************/ 00436 std::string UTMUPSRepresentation(int prec = 0) const; 00437 00438 /** 00439 * MGRS string for the alternate zone. See GeoCoords::MGRSRepresentation. 00440 **********************************************************************/ 00441 std::string AltMGRSRepresentation(int prec = 0) const; 00442 00443 /** 00444 * UTM/UPS string for the alternate zone. See 00445 * GeoCoords::UTMUPSRepresentation. 00446 **********************************************************************/ 00447 std::string AltUTMUPSRepresentation(int prec = 0) const; 00448 ///@} 00449 00450 /** \name Inspector functions 00451 **********************************************************************/ 00452 ///@{ 00453 /** 00454 * @return \e a the equatorial radius of the WGS84 ellipsoid (meters). 00455 * 00456 * (The WGS84 value is returned because the UTM and UPS projections are 00457 * based on this ellipsoid.) 00458 **********************************************************************/ 00459 Math::real MajorRadius() const throw() { return UTMUPS::MajorRadius(); } 00460 00461 /** 00462 * @return \e f the flattening of the WGS84 ellipsoid. 00463 * 00464 * (The WGS84 value is returned because the UTM and UPS projections are 00465 * based on this ellipsoid.) 00466 **********************************************************************/ 00467 Math::real Flattening() const throw() { return UTMUPS::Flattening(); } 00468 ///@} 00469 00470 /// \cond SKIP 00471 /** 00472 * <b>DEPRECATED</b> 00473 * @return \e r the inverse flattening of the ellipsoid. 00474 **********************************************************************/ 00475 Math::real InverseFlattening() const throw() 00476 { return UTMUPS::InverseFlattening(); } 00477 /// \endcond 00478 }; 00479 00480 } // namespace GeographicLib 00481 00482 #endif // GEOGRAPHICLIB_GEOCOORDS_HPP