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