GeoCoords.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. /**
  2. * \file GeoCoords.hpp
  3. * \brief Header for GeographicLib::GeoCoords class
  4. *
  5. * Copyright (c) Charles Karney (2008-2020) <charles@karney.com> and licensed
  6. * under the MIT/X11 License. For more information, see
  7. * https://geographiclib.sourceforge.io/
  8. **********************************************************************/
  9. #if !defined(GEOGRAPHICLIB_GEOCOORDS_HPP)
  10. #define GEOGRAPHICLIB_GEOCOORDS_HPP 1
  11. #include <GeographicLib/UTMUPS.hpp>
  12. #include <GeographicLib/Constants.hpp>
  13. namespace GeographicLib {
  14. /**
  15. * \brief Conversion between geographic coordinates
  16. *
  17. * This class stores a geographic position which may be set via the
  18. * constructors or Reset via
  19. * - latitude and longitude
  20. * - UTM or UPS coordinates
  21. * - a string representation of these or an MGRS coordinate string
  22. *
  23. * The state consists of the latitude and longitude and the supplied UTM or
  24. * UPS coordinates (possibly derived from the MGRS coordinates). If latitude
  25. * and longitude were given then the UTM/UPS coordinates follows the standard
  26. * conventions.
  27. *
  28. * The mutable state consists of the UTM or UPS coordinates for a alternate
  29. * zone. A method SetAltZone is provided to set the alternate UPS/UTM zone.
  30. *
  31. * Methods are provided to return the geographic coordinates, the input UTM
  32. * or UPS coordinates (and associated meridian convergence and scale), or
  33. * alternate UTM or UPS coordinates (and their associated meridian
  34. * convergence and scale).
  35. *
  36. * Once the input string has been parsed, you can print the result out in any
  37. * of the formats, decimal degrees, degrees minutes seconds, MGRS, UTM/UPS.
  38. *
  39. * Example of use:
  40. * \include example-GeoCoords.cpp
  41. *
  42. * <a href="GeoConvert.1.html">GeoConvert</a> is a command-line utility
  43. * providing access to the functionality of GeoCoords.
  44. **********************************************************************/
  45. class GEOGRAPHICLIB_EXPORT GeoCoords {
  46. private:
  47. typedef Math::real real;
  48. real _lat, _long, _easting, _northing, _gamma, _k;
  49. bool _northp;
  50. int _zone; // See UTMUPS::zonespec
  51. mutable real _alt_easting, _alt_northing, _alt_gamma, _alt_k;
  52. mutable int _alt_zone;
  53. void CopyToAlt() const {
  54. _alt_easting = _easting;
  55. _alt_northing = _northing;
  56. _alt_gamma = _gamma;
  57. _alt_k = _k;
  58. _alt_zone = _zone;
  59. }
  60. static void UTMUPSString(int zone, bool northp,
  61. real easting, real northing,
  62. int prec, bool abbrev, std::string& utm);
  63. void FixHemisphere();
  64. public:
  65. /** \name Initializing the GeoCoords object
  66. **********************************************************************/
  67. ///@{
  68. /**
  69. * The default constructor sets the coordinate as undefined.
  70. **********************************************************************/
  71. GeoCoords()
  72. : _lat(Math::NaN())
  73. , _long(Math::NaN())
  74. , _easting(Math::NaN())
  75. , _northing(Math::NaN())
  76. , _gamma(Math::NaN())
  77. , _k(Math::NaN())
  78. , _northp(false)
  79. , _zone(UTMUPS::INVALID)
  80. { CopyToAlt(); }
  81. /**
  82. * Construct from a string.
  83. *
  84. * @param[in] s 1-element, 2-element, or 3-element string representation of
  85. * the position.
  86. * @param[in] centerp governs the interpretation of MGRS coordinates (see
  87. * below).
  88. * @param[in] longfirst governs the interpretation of geographic
  89. * coordinates (see below).
  90. * @exception GeographicErr if the \e s is malformed (see below).
  91. *
  92. * Parse as a string and interpret it as a geographic position. The input
  93. * string is broken into space (or comma) separated pieces and Basic
  94. * decision on which format is based on number of components
  95. * -# MGRS
  96. * -# "Lat Long" or "Long Lat"
  97. * -# "Zone Easting Northing" or "Easting Northing Zone"
  98. *
  99. * The following inputs are approximately the same (Ar Ramadi Bridge, Iraq)
  100. * - Latitude and Longitude
  101. * - 33.44 43.27
  102. * - N33d26.4' E43d16.2'
  103. * - 43d16'12&quot;E 33d26'24&quot;N
  104. * - 43:16:12E 33:26:24
  105. * - MGRS
  106. * - 38SLC30
  107. * - 38SLC391014
  108. * - 38SLC3918701405
  109. * - 37SHT9708
  110. * - UTM
  111. * - 38n 339188 3701405
  112. * - 897039 3708229 37n
  113. *
  114. * <b>Latitude and Longitude parsing</b>: Latitude precedes longitude,
  115. * unless a N, S, E, W hemisphere designator is used on one or both
  116. * coordinates. If \e longfirst = true (default is false), then
  117. * longitude precedes latitude in the absence of a hemisphere designator.
  118. * Thus (with \e longfirst = false)
  119. * - 40 -75
  120. * - N40 W75
  121. * - -75 N40
  122. * - 75W 40N
  123. * - E-75 -40S
  124. * .
  125. * are all the same position. The coordinates may be given in
  126. * decimal degrees, degrees and decimal minutes, degrees, minutes,
  127. * seconds, etc. Use d, ', and &quot; to mark off the degrees,
  128. * minutes and seconds. Various alternative symbols for degrees, minutes,
  129. * and seconds are allowed. Alternatively, use : to separate these
  130. * components. A single addition or subtraction is allowed. (See
  131. * DMS::Decode for details.) Thus
  132. * - 40d30'30&quot;
  133. * - 40d30'30
  134. * - 40&deg;30'30
  135. * - 40d30.5'
  136. * - 40d30.5
  137. * - 40:30:30
  138. * - 40:30.5
  139. * - 40.508333333
  140. * - 40:30+0:0:30
  141. * - 40:31-0:0.5
  142. * .
  143. * all specify the same angle. The leading sign applies to the following
  144. * components so -1d30 is -(1+30/60) = &minus;1.5. However, note
  145. * that -1:30-0:0:15 is parsed as (-1:30) + (-0:0:15) = &minus;(1+30/60)
  146. * &minus; (15/3600). Latitudes must be in the range [&minus;90&deg;,
  147. * 90&deg;]. Internally longitudes are reduced to the range
  148. * [&minus;180&deg;, 180&deg;].
  149. *
  150. * <b>UTM/UPS parsing</b>: For UTM zones (&minus;80&deg; &le; Lat <
  151. * 84&deg;), the zone designator is made up of a zone number (for 1 to 60)
  152. * and a hemisphere letter (n or s), e.g., 38n (38north can also be used).
  153. * The latitude band designer ([C--M] in the southern hemisphere and [N--X]
  154. * in the northern) should NOT be used. (This is part of the MGRS
  155. * coordinate.) The zone designator for the poles (where UPS is employed)
  156. * is a hemisphere letter by itself, i.e., n or s (north or south can also
  157. * be used).
  158. *
  159. * <b>MGRS parsing</b> interprets the grid references as square area at the
  160. * specified precision (1m, 10m, 100m, etc.). If \e centerp = true (the
  161. * default), the center of this square is then taken to be the precise
  162. * position; thus:
  163. * - 38SMB = 38n 450000 3650000
  164. * - 38SMB4484 = 38n 444500 3684500
  165. * - 38SMB44148470 = 38n 444145 3684705
  166. * .
  167. * Otherwise, the "south-west" corner of the square is used, i.e.,
  168. * - 38SMB = 38n 400000 3600000
  169. * - 38SMB4484 = 38n 444000 3684000
  170. * - 38SMB44148470 = 38n 444140 3684700
  171. **********************************************************************/
  172. explicit GeoCoords(const std::string& s,
  173. bool centerp = true, bool longfirst = false)
  174. { Reset(s, centerp, longfirst); }
  175. /**
  176. * Construct from geographic coordinates.
  177. *
  178. * @param[in] latitude (degrees).
  179. * @param[in] longitude (degrees).
  180. * @param[in] zone if specified, force the UTM/UPS representation to use a
  181. * specified zone using the rules given in UTMUPS::zonespec.
  182. * @exception GeographicErr if \e latitude is not in [&minus;90&deg;,
  183. * 90&deg;].
  184. * @exception GeographicErr if \e zone cannot be used for this location.
  185. **********************************************************************/
  186. GeoCoords(real latitude, real longitude, int zone = UTMUPS::STANDARD) {
  187. Reset(latitude, longitude, zone);
  188. }
  189. /**
  190. * Construct from UTM/UPS coordinates.
  191. *
  192. * @param[in] zone UTM zone (zero means UPS).
  193. * @param[in] northp hemisphere (true means north, false means south).
  194. * @param[in] easting (meters).
  195. * @param[in] northing (meters).
  196. * @exception GeographicErr if \e zone, \e easting, or \e northing is
  197. * outside its allowed range.
  198. **********************************************************************/
  199. GeoCoords(int zone, bool northp, real easting, real northing) {
  200. Reset(zone, northp, easting, northing);
  201. }
  202. /**
  203. * Reset the location from a string. See
  204. * GeoCoords(const std::string& s, bool centerp, bool longfirst).
  205. *
  206. * @param[in] s 1-element, 2-element, or 3-element string representation of
  207. * the position.
  208. * @param[in] centerp governs the interpretation of MGRS coordinates.
  209. * @param[in] longfirst governs the interpretation of geographic
  210. * coordinates.
  211. * @exception GeographicErr if the \e s is malformed.
  212. **********************************************************************/
  213. void Reset(const std::string& s,
  214. bool centerp = true, bool longfirst = false);
  215. /**
  216. * Reset the location in terms of geographic coordinates. See
  217. * GeoCoords(real latitude, real longitude, int zone).
  218. *
  219. * @param[in] latitude (degrees).
  220. * @param[in] longitude (degrees).
  221. * @param[in] zone if specified, force the UTM/UPS representation to use a
  222. * specified zone using the rules given in UTMUPS::zonespec.
  223. * @exception GeographicErr if \e latitude is not in [&minus;90&deg;,
  224. * 90&deg;].
  225. * @exception GeographicErr if \e zone cannot be used for this location.
  226. **********************************************************************/
  227. void Reset(real latitude, real longitude, int zone = UTMUPS::STANDARD) {
  228. UTMUPS::Forward(latitude, longitude,
  229. _zone, _northp, _easting, _northing, _gamma, _k,
  230. zone);
  231. _lat = latitude;
  232. _long = longitude;
  233. if (_long >= 180) _long -= 360;
  234. else if (_long < -180) _long += 360;
  235. CopyToAlt();
  236. }
  237. /**
  238. * Reset the location in terms of UPS/UPS coordinates. See
  239. * GeoCoords(int zone, bool northp, real easting, real northing).
  240. *
  241. * @param[in] zone UTM zone (zero means UPS).
  242. * @param[in] northp hemisphere (true means north, false means south).
  243. * @param[in] easting (meters).
  244. * @param[in] northing (meters).
  245. * @exception GeographicErr if \e zone, \e easting, or \e northing is
  246. * outside its allowed range.
  247. **********************************************************************/
  248. void Reset(int zone, bool northp, real easting, real northing) {
  249. UTMUPS::Reverse(zone, northp, easting, northing,
  250. _lat, _long, _gamma, _k);
  251. _zone = zone;
  252. _northp = northp;
  253. _easting = easting;
  254. _northing = northing;
  255. FixHemisphere();
  256. CopyToAlt();
  257. }
  258. ///@}
  259. /** \name Querying the GeoCoords object
  260. **********************************************************************/
  261. ///@{
  262. /**
  263. * @return latitude (degrees)
  264. **********************************************************************/
  265. Math::real Latitude() const { return _lat; }
  266. /**
  267. * @return longitude (degrees)
  268. **********************************************************************/
  269. Math::real Longitude() const { return _long; }
  270. /**
  271. * @return easting (meters)
  272. **********************************************************************/
  273. Math::real Easting() const { return _easting; }
  274. /**
  275. * @return northing (meters)
  276. **********************************************************************/
  277. Math::real Northing() const { return _northing; }
  278. /**
  279. * @return meridian convergence (degrees) for the UTM/UPS projection.
  280. **********************************************************************/
  281. Math::real Convergence() const { return _gamma; }
  282. /**
  283. * @return scale for the UTM/UPS projection.
  284. **********************************************************************/
  285. Math::real Scale() const { return _k; }
  286. /**
  287. * @return hemisphere (false means south, true means north).
  288. **********************************************************************/
  289. bool Northp() const { return _northp; }
  290. /**
  291. * @return hemisphere letter n or s.
  292. **********************************************************************/
  293. char Hemisphere() const { return _northp ? 'n' : 's'; }
  294. /**
  295. * @return the zone corresponding to the input (return 0 for UPS).
  296. **********************************************************************/
  297. int Zone() const { return _zone; }
  298. ///@}
  299. /** \name Setting and querying the alternate zone
  300. **********************************************************************/
  301. ///@{
  302. /**
  303. * Specify alternate zone number.
  304. *
  305. * @param[in] zone zone number for the alternate representation.
  306. * @exception GeographicErr if \e zone cannot be used for this location.
  307. *
  308. * See UTMUPS::zonespec for more information on the interpretation of \e
  309. * zone. Note that \e zone == UTMUPS::STANDARD (the default) use the
  310. * standard UPS or UTM zone, UTMUPS::MATCH does nothing retaining the
  311. * existing alternate representation. Before this is called the alternate
  312. * zone is the input zone.
  313. **********************************************************************/
  314. void SetAltZone(int zone = UTMUPS::STANDARD) const {
  315. if (zone == UTMUPS::MATCH)
  316. return;
  317. zone = UTMUPS::StandardZone(_lat, _long, zone);
  318. if (zone == _zone)
  319. CopyToAlt();
  320. else {
  321. bool northp;
  322. UTMUPS::Forward(_lat, _long,
  323. _alt_zone, northp,
  324. _alt_easting, _alt_northing, _alt_gamma, _alt_k,
  325. zone);
  326. }
  327. }
  328. /**
  329. * @return current alternate zone (return 0 for UPS).
  330. **********************************************************************/
  331. int AltZone() const { return _alt_zone; }
  332. /**
  333. * @return easting (meters) for alternate zone.
  334. **********************************************************************/
  335. Math::real AltEasting() const { return _alt_easting; }
  336. /**
  337. * @return northing (meters) for alternate zone.
  338. **********************************************************************/
  339. Math::real AltNorthing() const { return _alt_northing; }
  340. /**
  341. * @return meridian convergence (degrees) for alternate zone.
  342. **********************************************************************/
  343. Math::real AltConvergence() const { return _alt_gamma; }
  344. /**
  345. * @return scale for alternate zone.
  346. **********************************************************************/
  347. Math::real AltScale() const { return _alt_k; }
  348. ///@}
  349. /** \name String representations of the GeoCoords object
  350. **********************************************************************/
  351. ///@{
  352. /**
  353. * String representation with latitude and longitude as signed decimal
  354. * degrees.
  355. *
  356. * @param[in] prec precision (relative to about 1m).
  357. * @param[in] longfirst if true give longitude first (default = false)
  358. * @exception std::bad_alloc if memory for the string can't be allocated.
  359. * @return decimal latitude/longitude string representation.
  360. *
  361. * Precision specifies accuracy of representation as follows:
  362. * - prec = &minus;5 (min), 1&deg;
  363. * - prec = 0, 10<sup>&minus;5</sup>&deg; (about 1m)
  364. * - prec = 3, 10<sup>&minus;8</sup>&deg;
  365. * - prec = 9 (max), 10<sup>&minus;14</sup>&deg;
  366. **********************************************************************/
  367. std::string GeoRepresentation(int prec = 0, bool longfirst = false) const;
  368. /**
  369. * String representation with latitude and longitude as degrees, minutes,
  370. * seconds, and hemisphere.
  371. *
  372. * @param[in] prec precision (relative to about 1m)
  373. * @param[in] longfirst if true give longitude first (default = false)
  374. * @param[in] dmssep if non-null, use as the DMS separator character
  375. * (instead of d, ', &quot; delimiters).
  376. * @exception std::bad_alloc if memory for the string can't be allocated.
  377. * @return DMS latitude/longitude string representation.
  378. *
  379. * Precision specifies accuracy of representation as follows:
  380. * - prec = &minus;5 (min), 1&deg;
  381. * - prec = &minus;4, 0.1&deg;
  382. * - prec = &minus;3, 1'
  383. * - prec = &minus;2, 0.1'
  384. * - prec = &minus;1, 1&quot;
  385. * - prec = 0, 0.1&quot; (about 3m)
  386. * - prec = 1, 0.01&quot;
  387. * - prec = 10 (max), 10<sup>&minus;11</sup>&quot;
  388. **********************************************************************/
  389. std::string DMSRepresentation(int prec = 0, bool longfirst = false,
  390. char dmssep = char(0))
  391. const;
  392. /**
  393. * MGRS string.
  394. *
  395. * @param[in] prec precision (relative to about 1m).
  396. * @exception std::bad_alloc if memory for the string can't be allocated.
  397. * @return MGRS string.
  398. *
  399. * This gives the coordinates of the enclosing grid square with size given
  400. * by the precision. Thus 38n 444180 3684790 converted to a MGRS
  401. * coordinate at precision &minus;2 (100m) is 38SMB441847 and not
  402. * 38SMB442848. \e prec specifies the precision of the MGRS string as
  403. * follows:
  404. * - prec = &minus;6 (min), only the grid zone is returned, e.g., 38S
  405. * - prec = &minus;5, 100km, e.g., 38SMB
  406. * - prec = &minus;4, 10km
  407. * - prec = &minus;3, 1km
  408. * - prec = &minus;2, 100m
  409. * - prec = &minus;1, 10m
  410. * - prec = 0, 1m
  411. * - prec = 1, 0.1m
  412. * - prec = 6 (max), 1&mu;m
  413. **********************************************************************/
  414. std::string MGRSRepresentation(int prec = 0) const;
  415. /**
  416. * UTM/UPS string.
  417. *
  418. * @param[in] prec precision (relative to about 1m)
  419. * @param[in] abbrev if true (the default) use abbreviated (n/s) notation
  420. * for hemisphere; otherwise spell out the hemisphere (north/south)
  421. * @exception std::bad_alloc if memory for the string can't be allocated.
  422. * @return UTM/UPS string representation: zone designator, easting, and
  423. * northing.
  424. *
  425. * Precision specifies accuracy of representation as follows:
  426. * - prec = &minus;5 (min), 100km
  427. * - prec = &minus;3, 1km
  428. * - prec = 0, 1m
  429. * - prec = 3, 1mm
  430. * - prec = 6, 1&mu;m
  431. * - prec = 9 (max), 1nm
  432. **********************************************************************/
  433. std::string UTMUPSRepresentation(int prec = 0, bool abbrev = true) const;
  434. /**
  435. * UTM/UPS string with hemisphere override.
  436. *
  437. * @param[in] northp hemisphere override
  438. * @param[in] prec precision (relative to about 1m)
  439. * @param[in] abbrev if true (the default) use abbreviated (n/s) notation
  440. * for hemisphere; otherwise spell out the hemisphere (north/south)
  441. * @exception GeographicErr if the hemisphere override attempts to change
  442. * UPS N to UPS S or vice versa.
  443. * @exception std::bad_alloc if memory for the string can't be allocated.
  444. * @return UTM/UPS string representation: zone designator, easting, and
  445. * northing.
  446. **********************************************************************/
  447. std::string UTMUPSRepresentation(bool northp, int prec = 0,
  448. bool abbrev = true) const;
  449. /**
  450. * MGRS string for the alternate zone. See GeoCoords::MGRSRepresentation.
  451. *
  452. * @param[in] prec precision (relative to about 1m).
  453. * @exception std::bad_alloc if memory for the string can't be allocated.
  454. * @return MGRS string.
  455. **********************************************************************/
  456. std::string AltMGRSRepresentation(int prec = 0) const;
  457. /**
  458. * UTM/UPS string for the alternate zone. See
  459. * GeoCoords::UTMUPSRepresentation.
  460. *
  461. * @param[in] prec precision (relative to about 1m)
  462. * @param[in] abbrev if true (the default) use abbreviated (n/s) notation
  463. * for hemisphere; otherwise spell out the hemisphere (north/south)
  464. * @exception std::bad_alloc if memory for the string can't be allocated.
  465. * @return UTM/UPS string representation: zone designator, easting, and
  466. * northing.
  467. **********************************************************************/
  468. std::string AltUTMUPSRepresentation(int prec = 0, bool abbrev = true)
  469. const;
  470. /**
  471. * UTM/UPS string for the alternate zone, with hemisphere override.
  472. *
  473. * @param[in] northp hemisphere override
  474. * @param[in] prec precision (relative to about 1m)
  475. * @param[in] abbrev if true (the default) use abbreviated (n/s) notation
  476. * for hemisphere; otherwise spell out the hemisphere (north/south)
  477. * @exception GeographicErr if the hemisphere override attempts to change
  478. * UPS n to UPS s or vice verse.
  479. * @exception std::bad_alloc if memory for the string can't be allocated.
  480. * @return UTM/UPS string representation: zone designator, easting, and
  481. * northing.
  482. **********************************************************************/
  483. std::string AltUTMUPSRepresentation(bool northp, int prec = 0,
  484. bool abbrev = true) const;
  485. ///@}
  486. /** \name Inspector functions
  487. **********************************************************************/
  488. ///@{
  489. /**
  490. * @return \e a the equatorial radius of the WGS84 ellipsoid (meters).
  491. *
  492. * (The WGS84 value is returned because the UTM and UPS projections are
  493. * based on this ellipsoid.)
  494. **********************************************************************/
  495. Math::real EquatorialRadius() const { return UTMUPS::EquatorialRadius(); }
  496. /**
  497. * @return \e f the flattening of the WGS84 ellipsoid.
  498. *
  499. * (The WGS84 value is returned because the UTM and UPS projections are
  500. * based on this ellipsoid.)
  501. **********************************************************************/
  502. Math::real Flattening() const { return UTMUPS::Flattening(); }
  503. /**
  504. * \deprecated An old name for EquatorialRadius().
  505. **********************************************************************/
  506. GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
  507. Math::real MajorRadius() const { return EquatorialRadius(); }
  508. ///@}
  509. };
  510. } // namespace GeographicLib
  511. #endif // GEOGRAPHICLIB_GEOCOORDS_HPP