GeographicLib  1.43
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
UTMUPS.hpp
Go to the documentation of this file.
1 /**
2  * \file UTMUPS.hpp
3  * \brief Header for GeographicLib::UTMUPS class
4  *
5  * Copyright (c) Charles Karney (2008-2014) <charles@karney.com> and licensed
6  * under the MIT/X11 License. For more information, see
7  * http://geographiclib.sourceforge.net/
8  **********************************************************************/
9 
10 #if !defined(GEOGRAPHICLIB_UTMUPS_HPP)
11 #define GEOGRAPHICLIB_UTMUPS_HPP 1
12 
14 
15 namespace GeographicLib {
16 
17  /**
18  * \brief Convert between geographic coordinates and UTM/UPS
19  *
20  * UTM and UPS are defined
21  * - J. W. Hager, J. F. Behensky, and B. W. Drew,
22  * <a href="http://earth-info.nga.mil/GandG/publications/tm8358.2/TM8358_2.pdf">
23  * The Universal Grids: Universal Transverse Mercator (UTM) and Universal
24  * Polar Stereographic (UPS)</a>, Defense Mapping Agency, Technical Manual
25  * TM8358.2 (1989).
26  * .
27  * Section 2-3 defines UTM and section 3-2.4 defines UPS. This document also
28  * includes approximate algorithms for the computation of the underlying
29  * transverse Mercator and polar stereographic projections. Here we
30  * substitute much more accurate algorithms given by
31  * GeographicLib:TransverseMercator and GeographicLib:PolarStereographic.
32  * These are the algorithms recommended by the NGA document
33  * - <a href="http://earth-info.nga.mil/GandG/publications/NGA_SIG_0012_2_0_0_UTMUPS/NGA.SIG.0012_2.0.0_UTMUPS.pdf">
34  * The Universal Grids and the Transverse Mercator and Polar Stereographic
35  * Map Projections</a>, NGA.SIG.0012_2.0.0_UTMUPS (2014).
36  *
37  * In this implementation, the conversions are closed, i.e., output from
38  * Forward is legal input for Reverse and vice versa. The error is about 5nm
39  * in each direction. However, the conversion from legal UTM/UPS coordinates
40  * to geographic coordinates and back might throw an error if the initial
41  * point is within 5nm of the edge of the allowed range for the UTM/UPS
42  * coordinates.
43  *
44  * The simplest way to guarantee the closed property is to define allowed
45  * ranges for the eastings and northings for UTM and UPS coordinates. The
46  * UTM boundaries are the same for all zones. (The only place the
47  * exceptional nature of the zone boundaries is evident is when converting to
48  * UTM/UPS coordinates requesting the standard zone.) The MGRS lettering
49  * scheme imposes natural limits on UTM/UPS coordinates which may be
50  * converted into MGRS coordinates. For the conversion to/from geographic
51  * coordinates these ranges have been extended by 100km in order to provide a
52  * generous overlap between UTM and UPS and between UTM zones.
53  *
54  * The <a href="http://www.nga.mil">NGA</a> software package
55  * <a href="http://earth-info.nga.mil/GandG/geotrans/index.html">geotrans</a>
56  * also provides conversions to and from UTM and UPS. Version 2.4.2 (and
57  * earlier) suffers from some drawbacks:
58  * - Inconsistent rules are used to determine the whether a particular UTM or
59  * UPS coordinate is legal. A more systematic approach is taken here.
60  * - The underlying projections are not very accurately implemented.
61  *
62  * The GeographicLib::UTMUPS::EncodeZone encodes the UTM zone and hemisphere
63  * to allow UTM/UPS coordinated to be displayed as, for example, "38N 444500
64  * 3688500". According to NGA.SIG.0012_2.0.0_UTMUPS the use of "N" to denote
65  * "north" in the context is not allowed (since a upper case letter in this
66  * context denotes the MGRS latitude band). Consequently, as of version
67  * 1.36, EncodeZone uses the lower case letters "n" and "s" to denote the
68  * hemisphere. In addition EncodeZone accepts an optional final argument \e
69  * abbrev, which, if false, results in the hemisphere being spelled out as in
70  * "38north".
71  *
72  * Example of use:
73  * \include example-UTMUPS.cpp
74  **********************************************************************/
76  private:
77  typedef Math::real real;
78  static const int falseeasting_[4];
79  static const int falsenorthing_[4];
80  static const int mineasting_[4];
81  static const int maxeasting_[4];
82  static const int minnorthing_[4];
83  static const int maxnorthing_[4];
84  static const int epsg01N = 32601; // EPSG code for UTM 01N
85  static const int epsg60N = 32660; // EPSG code for UTM 60N
86  static const int epsgN = 32661; // EPSG code for UPS N
87  static const int epsg01S = 32701; // EPSG code for UTM 01S
88  static const int epsg60S = 32760; // EPSG code for UTM 60S
89  static const int epsgS = 32761; // EPSG code for UPS S
90  static real CentralMeridian(int zone)
91  { return real(6 * zone - 183); }
92  static void CheckLatLon(real lat, real lon);
93  // Throw an error if easting or northing are outside standard ranges. If
94  // throwp = false, return bool instead.
95  static bool CheckCoords(bool utmp, bool northp, real x, real y,
96  bool msgrlimits = false, bool throwp = true);
97  UTMUPS(); // Disable constructor
98 
99  public:
100 
101  /**
102  * In this class we bring together the UTM and UPS coordinates systems.
103  * The UTM divides the earth between latitudes &minus;80&deg; and 84&deg;
104  * into 60 zones numbered 1 thru 60. Zone assign zone number 0 to the UPS
105  * regions, covering the two poles. Within UTMUPS, non-negative zone
106  * numbers refer to one of the "physical" zones, 0 for UPS and [1, 60] for
107  * UTM. Negative "pseudo-zone" numbers are used to select one of the
108  * physical zones.
109  **********************************************************************/
110  enum zonespec {
111  /**
112  * The smallest pseudo-zone number.
113  **********************************************************************/
114  MINPSEUDOZONE = -4,
115  /**
116  * A marker for an undefined or invalid zone. Equivalent to NaN.
117  **********************************************************************/
118  INVALID = -4,
119  /**
120  * If a coordinate already include zone information (e.g., it is an MGRS
121  * coordinate), use that, otherwise apply the UTMUPS::STANDARD rules.
122  **********************************************************************/
123  MATCH = -3,
124  /**
125  * Apply the standard rules for UTM zone assigment extending the UTM zone
126  * to each pole to give a zone number in [1, 60]. For example, use UTM
127  * zone 38 for longitude in [42&deg;, 48&deg;). The rules include the
128  * Norway and Svalbard exceptions.
129  **********************************************************************/
130  UTM = -2,
131  /**
132  * Apply the standard rules for zone assignment to give a zone number in
133  * [0, 60]. If the latitude is not in [&minus;80&deg;, 84&deg;), then
134  * use UTMUPS::UPS = 0, otherwise apply the rules for UTMUPS::UTM. The
135  * tests on latitudes and longitudes are all closed on the lower end open
136  * on the upper. Thus for UTM zone 38, latitude is in [&minus;80&deg;,
137  * 84&deg;) and longitude is in [42&deg;, 48&deg;).
138  **********************************************************************/
139  STANDARD = -1,
140  /**
141  * The largest pseudo-zone number.
142  **********************************************************************/
143  MAXPSEUDOZONE = -1,
144  /**
145  * The smallest physical zone number.
146  **********************************************************************/
147  MINZONE = 0,
148  /**
149  * The zone number used for UPS
150  **********************************************************************/
151  UPS = 0,
152  /**
153  * The smallest UTM zone number.
154  **********************************************************************/
155  MINUTMZONE = 1,
156  /**
157  * The largest UTM zone number.
158  **********************************************************************/
159  MAXUTMZONE = 60,
160  /**
161  * The largest physical zone number.
162  **********************************************************************/
163  MAXZONE = 60,
164  };
165 
166  /**
167  * The standard zone.
168  *
169  * @param[in] lat latitude (degrees).
170  * @param[in] lon longitude (degrees).
171  * @param[in] setzone zone override (optional). If omitted, use the
172  * standard rules for picking the zone. If \e setzone is given then use
173  * that zone if it is non-negative, otherwise apply the rules given in
174  * UTMUPS::zonespec.
175  * @exception GeographicErr if \e setzone is outside the range
176  * [UTMUPS::MINPSEUDOZONE, UTMUPS::MAXZONE] = [&minus;4, 60].
177  *
178  * This is exact.
179  **********************************************************************/
180  static int StandardZone(real lat, real lon, int setzone = STANDARD);
181 
182  /**
183  * Forward projection, from geographic to UTM/UPS.
184  *
185  * @param[in] lat latitude of point (degrees).
186  * @param[in] lon longitude of point (degrees).
187  * @param[out] zone the UTM zone (zero means UPS).
188  * @param[out] northp hemisphere (true means north, false means south).
189  * @param[out] x easting of point (meters).
190  * @param[out] y northing of point (meters).
191  * @param[out] gamma meridian convergence at point (degrees).
192  * @param[out] k scale of projection at point.
193  * @param[in] setzone zone override (optional).
194  * @param[in] mgrslimits if true enforce the stricter MGRS limits on the
195  * coordinates (default = false).
196  * @exception GeographicErr if \e lat is not in [&minus;90&deg;,
197  * 90&deg;].
198  * @exception GeographicErr if \e lon is not in [&minus;540&deg;,
199  * 540&deg;).
200  * @exception GeographicErr if the resulting \e x or \e y is out of allowed
201  * range (see Reverse); in this case, these arguments are unchanged.
202  *
203  * If \e setzone is omitted, use the standard rules for picking the zone.
204  * If \e setzone is given then use that zone if it is non-negative,
205  * otherwise apply the rules given in UTMUPS::zonespec. The accuracy of
206  * the conversion is about 5nm.
207  *
208  * The northing \e y jumps by UTMUPS::UTMShift() when crossing the equator
209  * in the southerly direction. Sometimes it is useful to remove this
210  * discontinuity in \e y by extending the "northern" hemisphere using
211  * UTMUPS::Transfer:
212  * \code
213  double lat = -1, lon = 123;
214  int zone;
215  bool northp;
216  double x, y, gamma, k;
217  GeographicLib::UTMUPS::Forward(lat, lon, zone, northp, x, y, gamma, k);
218  GeographicLib::UTMUPS::Transfer(zone, northp, x, y,
219  zone, true, x, y, zone);
220  northp = true;
221  \endcode
222  **********************************************************************/
223  static void Forward(real lat, real lon,
224  int& zone, bool& northp, real& x, real& y,
225  real& gamma, real& k,
226  int setzone = STANDARD, bool mgrslimits = false);
227 
228  /**
229  * Reverse projection, from UTM/UPS to geographic.
230  *
231  * @param[in] zone the UTM zone (zero means UPS).
232  * @param[in] northp hemisphere (true means north, false means south).
233  * @param[in] x easting of point (meters).
234  * @param[in] y northing of point (meters).
235  * @param[out] lat latitude of point (degrees).
236  * @param[out] lon longitude of point (degrees).
237  * @param[out] gamma meridian convergence at point (degrees).
238  * @param[out] k scale of projection at point.
239  * @param[in] mgrslimits if true enforce the stricter MGRS limits on the
240  * coordinates (default = false).
241  * @exception GeographicErr if \e zone, \e x, or \e y is out of allowed
242  * range; this this case the arguments are unchanged.
243  *
244  * The accuracy of the conversion is about 5nm.
245  *
246  * UTM eastings are allowed to be in the range [0km, 1000km], northings are
247  * allowed to be in in [0km, 9600km] for the northern hemisphere and in
248  * [900km, 10000km] for the southern hemisphere. However UTM northings
249  * can be continued across the equator. So the actual limits on the
250  * northings are [-9100km, 9600km] for the "northern" hemisphere and
251  * [900km, 19600km] for the "southern" hemisphere.
252  *
253  * UPS eastings and northings are allowed to be in the range [1200km,
254  * 2800km] in the northern hemisphere and in [700km, 3300km] in the
255  * southern hemisphere.
256  *
257  * These ranges are 100km larger than allowed for the conversions to MGRS.
258  * (100km is the maximum extra padding consistent with eastings remaining
259  * non-negative.) This allows generous overlaps between zones and UTM and
260  * UPS. If \e mgrslimits = true, then all the ranges are shrunk by 100km
261  * so that they agree with the stricter MGRS ranges. No checks are
262  * performed besides these (e.g., to limit the distance outside the
263  * standard zone boundaries).
264  **********************************************************************/
265  static void Reverse(int zone, bool northp, real x, real y,
266  real& lat, real& lon, real& gamma, real& k,
267  bool mgrslimits = false);
268 
269  /**
270  * UTMUPS::Forward without returning convergence and scale.
271  **********************************************************************/
272  static void Forward(real lat, real lon,
273  int& zone, bool& northp, real& x, real& y,
274  int setzone = STANDARD, bool mgrslimits = false) {
275  real gamma, k;
276  Forward(lat, lon, zone, northp, x, y, gamma, k, setzone, mgrslimits);
277  }
278 
279  /**
280  * UTMUPS::Reverse without returning convergence and scale.
281  **********************************************************************/
282  static void Reverse(int zone, bool northp, real x, real y,
283  real& lat, real& lon, bool mgrslimits = false) {
284  real gamma, k;
285  Reverse(zone, northp, x, y, lat, lon, gamma, k, mgrslimits);
286  }
287 
288  /**
289  * Transfer UTM/UPS coordinated from one zone to another.
290  *
291  * @param[in] zonein the UTM zone for \e xin and \e yin (or zero for UPS).
292  * @param[in] northpin hemisphere for \e xin and \e yin (true means north,
293  * false means south).
294  * @param[in] xin easting of point (meters) in \e zonein.
295  * @param[in] yin northing of point (meters) in \e zonein.
296  * @param[in] zoneout the requested UTM zone for \e xout and \e yout (or
297  * zero for UPS).
298  * @param[in] northpout hemisphere for \e xout output and \e yout.
299  * @param[out] xout easting of point (meters) in \e zoneout.
300  * @param[out] yout northing of point (meters) in \e zoneout.
301  * @param[out] zone the actual UTM zone for \e xout and \e yout (or zero
302  * for UPS); this equals \e zoneout if \e zoneout &ge; 0.
303  * @exception GeographicErr if \e zonein is out of range (see below).
304  * @exception GeographicErr if \e zoneout is out of range (see below).
305  * @exception GeographicErr if \e xin or \e yin fall outside their allowed
306  * ranges (see UTMUPS::Reverse).
307  * @exception GeographicErr if \e xout or \e yout fall outside their
308  * allowed ranges (see UTMUPS::Reverse).
309  *
310  * \e zonein must be in the range [UTMUPS::MINZONE, UTMUPS::MAXZONE] = [0,
311  * 60] with \e zonein = UTMUPS::UPS, 0, indicating UPS. \e zonein may
312  * also be UTMUPS::INVALID.
313  *
314  * \e zoneout must be in the range [UTMUPS::MINPSEUDOZONE, UTMUPS::MAXZONE]
315  * = [-4, 60]. If \e zoneout &lt; UTMUPS::MINZONE then the rules give in
316  * the documentation of UTMUPS::zonespec are applied, and \e zone is set to
317  * the actual zone used for output.
318  *
319  * (\e xout, \e yout) can overlap with (\e xin, \e yin).
320  **********************************************************************/
321  static void Transfer(int zonein, bool northpin, real xin, real yin,
322  int zoneout, bool northpout, real& xout, real& yout,
323  int& zone);
324 
325  /**
326  * Decode a UTM/UPS zone string.
327  *
328  * @param[in] zonestr string representation of zone and hemisphere.
329  * @param[out] zone the UTM zone (zero means UPS).
330  * @param[out] northp hemisphere (true means north, false means south).
331  * @exception GeographicErr if \e zonestr is malformed.
332  *
333  * For UTM, \e zonestr has the form of a zone number in the range
334  * [UTMUPS::MINUTMZONE, UTMUPS::MAXUTMZONE] = [1, 60] followed by a
335  * hemisphere letter, n or s (or "north" or "south" spelled out). For UPS,
336  * it consists just of the hemisphere letter (or the spelled out
337  * hemisphere). The returned value of \e zone is UTMUPS::UPS = 0 for UPS.
338  * Note well that "38s" indicates the southern hemisphere of zone 38 and
339  * not latitude band S, 32&deg; &le; \e lat &lt; 40&deg;. n, 01s, 2n, 38s,
340  * south, 3north are legal. 0n, 001s, +3n, 61n, 38P are illegal. INV is a
341  * special value for which the returned value of \e is UTMUPS::INVALID.
342  **********************************************************************/
343  static void DecodeZone(const std::string& zonestr, int& zone, bool& northp);
344 
345  /**
346  * Encode a UTM/UPS zone string.
347  *
348  * @param[in] zone the UTM zone (zero means UPS).
349  * @param[in] northp hemisphere (true means north, false means south).
350  * @param[in] abbrev if true (the default) use abbreviated (n/s) notation
351  * for hemisphere; otherwise spell out the hemisphere (north/south)
352  * @exception GeographicErr if \e zone is out of range (see below).
353  * @exception std::bad_alloc if memoy for the string can't be allocated.
354  * @return string representation of zone and hemisphere.
355  *
356  * \e zone must be in the range [UTMUPS::MINZONE, UTMUPS::MAXZONE] = [0,
357  * 60] with \e zone = UTMUPS::UPS, 0, indicating UPS (but the resulting
358  * string does not contain "0"). \e zone may also be UTMUPS::INVALID, in
359  * which case the returned string is "inv". This reverses
360  * UTMUPS::DecodeZone.
361  **********************************************************************/
362  static std::string EncodeZone(int zone, bool northp, bool abbrev = true);
363 
364  /**
365  * Decode EPSG.
366  *
367  * @param[in] epsg the EPSG code.
368  * @param[out] zone the UTM zone (zero means UPS).
369  * @param[out] northp hemisphere (true means north, false means south).
370  *
371  * EPSG (European Petroleum Survery Group) codes are a way to refer to many
372  * different projections. DecodeEPSG decodes those refering to UTM or UPS
373  * projections for the WGS84 ellipsoid. If the code does not refer to one
374  * of these projections, \e zone is set to UTMUPS::INVALID. See
375  * http://spatialreference.org/ref/epsg/
376  **********************************************************************/
377  static void DecodeEPSG(int epsg, int& zone, bool& northp);
378 
379  /**
380  * Encode zone as EPSG.
381  *
382  * @param[in] zone the UTM zone (zero means UPS).
383  * @param[in] northp hemisphere (true means north, false means south).
384  * @return EPSG code (or -1 if \e zone is not in the range
385  * [UTMUPS::MINZONE, UTMUPS::MAXZONE] = [0, 60])
386  *
387  * Convert \e zone and \e northp to the corresponding EPSG (European
388  * Petroleum Survery Group) codes
389  **********************************************************************/
390  static int EncodeEPSG(int zone, bool northp);
391 
392  /**
393  * @return shift (meters) necessary to align north and south halves of a
394  * UTM zone (10<sup>7</sup>).
395  **********************************************************************/
396  static Math::real UTMShift();
397 
398  /** \name Inspector functions
399  **********************************************************************/
400  ///@{
401  /**
402  * @return \e a the equatorial radius of the WGS84 ellipsoid (meters).
403  *
404  * (The WGS84 value is returned because the UTM and UPS projections are
405  * based on this ellipsoid.)
406  **********************************************************************/
408  { return Constants::WGS84_a(); }
409 
410  /**
411  * @return \e f the flattening of the WGS84 ellipsoid.
412  *
413  * (The WGS84 value is returned because the UTM and UPS projections are
414  * based on this ellipsoid.)
415  **********************************************************************/
417  { return Constants::WGS84_f(); }
418  ///@}
419 
420  /// \cond SKIP
421  /**
422  * <b>DEPRECATED</b>
423  * @return \e r the inverse flattening of the WGS84 ellipsoid.
424  **********************************************************************/
425  static Math::real InverseFlattening()
426  { return 1/Constants::WGS84_f(); }
427  /// \endcond
428  };
429 
430 } // namespace GeographicLib
431 
432 #endif // GEOGRAPHICLIB_UTMUPS_HPP
#define GEOGRAPHICLIB_EXPORT
Definition: Constants.hpp:90
static Math::real Flattening()
Definition: UTMUPS.hpp:416
GeographicLib::Math::real real
Definition: GeodSolve.cpp:32
static void Forward(real lat, real lon, int &zone, bool &northp, real &x, real &y, int setzone=STANDARD, bool mgrslimits=false)
Definition: UTMUPS.hpp:272
static Math::real MajorRadius()
Definition: UTMUPS.hpp:407
Convert between geographic coordinates and UTM/UPS.
Definition: UTMUPS.hpp:75
Header for GeographicLib::Constants class.
static void Reverse(int zone, bool northp, real x, real y, real &lat, real &lon, bool mgrslimits=false)
Definition: UTMUPS.hpp:282