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