GeographicLib  1.44
MGRS.hpp
Go to the documentation of this file.
1 /**
2  * \file MGRS.hpp
3  * \brief Header for GeographicLib::MGRS class
4  *
5  * Copyright (c) Charles Karney (2008-2015) <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_MGRS_HPP)
11 #define GEOGRAPHICLIB_MGRS_HPP 1
12 
14 #include <GeographicLib/UTMUPS.hpp>
15 
16 #if defined(_MSC_VER)
17 // Squelch warnings about dll vs string
18 # pragma warning (push)
19 # pragma warning (disable: 4251)
20 #endif
21 
22 namespace GeographicLib {
23 
24  /**
25  * \brief Convert between UTM/UPS and %MGRS
26  *
27  * MGRS is defined in Chapter 3 of
28  * - J. W. Hager, L. L. Fry, S. S. Jacks, D. R. Hill,
29  * <a href="http://earth-info.nga.mil/GandG/publications/tm8358.1/pdf/TM8358_1.pdf">
30  * Datums, Ellipsoids, Grids, and Grid Reference Systems</a>,
31  * Defense Mapping Agency, Technical Manual TM8358.1 (1990).
32  * .
33  * This document has been updated by the two NGA documents
34  * - <a href="http://earth-info.nga.mil/GandG/publications/NGA_STND_0037_2_0_0_GRIDS/NGA.STND.0037_2.0.0_GRIDS.pdf">
35  * Universal Grids and Grid Reference Systems</a>,
36  * NGA.STND.0037_2.0.0_GRIDS (2014).
37  * - <a href="http://earth-info.nga.mil/GandG/publications/NGA_SIG_0012_2_0_0_UTMUPS/NGA.SIG.0012_2.0.0_UTMUPS.pdf">
38  * The Universal Grids and the Transverse Mercator and Polar Stereographic
39  * Map Projections</a>, NGA.SIG.0012_2.0.0_UTMUPS (2014).
40  *
41  * This implementation has the following properties:
42  * - The conversions are closed, i.e., output from Forward is legal input for
43  * Reverse and vice versa. Conversion in both directions preserve the
44  * UTM/UPS selection and the UTM zone.
45  * - Forward followed by Reverse and vice versa is approximately the
46  * identity. (This is affected in predictable ways by errors in
47  * determining the latitude band and by loss of precision in the MGRS
48  * coordinates.)
49  * - The trailing digits produced by Forward are consistent as the precision
50  * is varied. Specifically, the digits are obtained by operating on the
51  * easting with &lfloor;10<sup>6</sup> <i>x</i>&rfloor; and extracting the
52  * required digits from the resulting number (and similarly for the
53  * northing).
54  * - All MGRS coordinates truncate to legal 100 km blocks. All MGRS
55  * coordinates with a legal 100 km block prefix are legal (even though the
56  * latitude band letter may now belong to a neighboring band).
57  * - The range of UTM/UPS coordinates allowed for conversion to MGRS
58  * coordinates is the maximum consistent with staying within the letter
59  * ranges of the MGRS scheme.
60  * - All the transformations are implemented as static methods in the MGRS
61  * class.
62  *
63  * The <a href="http://www.nga.mil">NGA</a> software package
64  * <a href="http://earth-info.nga.mil/GandG/geotrans/index.html">geotrans</a>
65  * also provides conversions to and from MGRS. Version 3.0 (and earlier)
66  * suffers from some drawbacks:
67  * - Inconsistent rules are used to determine the whether a particular MGRS
68  * coordinate is legal. A more systematic approach is taken here.
69  * - The underlying projections are not very accurately implemented.
70  *
71  * Example of use:
72  * \include example-MGRS.cpp
73  **********************************************************************/
75  private:
76  typedef Math::real real;
77  static const std::string hemispheres_;
78  static const std::string utmcols_[3];
79  static const std::string utmrow_;
80  static const std::string upscols_[4];
81  static const std::string upsrows_[2];
82  static const std::string latband_;
83  static const std::string upsband_;
84  static const std::string digits_;
85 
86  static const int mineasting_[4];
87  static const int maxeasting_[4];
88  static const int minnorthing_[4];
89  static const int maxnorthing_[4];
90  enum {
91  base_ = 10,
92  // Top-level tiles are 10^5 m = 100 km on a side
93  tilelevel_ = 5,
94  // Period of UTM row letters
95  utmrowperiod_ = 20,
96  // Row letters are shifted by 5 for even zones
97  utmevenrowshift_ = 5,
98  // Maximum precision is um
99  maxprec_ = 5 + 6,
100  // For generating digits at maxprec
101  mult_ = 1000000,
102  };
103  static void CheckCoords(bool utmp, bool& northp, real& x, real& y);
104  static int UTMRow(int iband, int icol, int irow);
105 
106  friend class UTMUPS; // UTMUPS::StandardZone calls LatitudeBand
107  // Return latitude band number [-10, 10) for the given latitude (degrees).
108  // The bands are reckoned in include their southern edges.
109  static int LatitudeBand(real lat) {
110  using std::floor;
111  int ilat = int(floor(lat));
112  return (std::max)(-10, (std::min)(9, (ilat + 80)/8 - 10));
113  }
114  // Return approximate latitude band number [-10, 10) for the given northing
115  // (meters). With this rule, each 100km tile would have a unique band
116  // letter corresponding to the latitude at the center of the tile. This
117  // function isn't currently used.
118  static int ApproxLatitudeBand(real y) {
119  // northing at tile center in units of tile = 100km
120  using std::floor; using std::abs;
121  real ya = floor( (std::min)(real(88), abs(y/tile_)) ) +
122  real(0.5);
123  // convert to lat (mult by 90/100) and then to band (divide by 8)
124  // the +1 fine tunes the boundary between bands 3 and 4
125  int b = int(floor( ((ya * 9 + 1) / 10) / 8 ));
126  // For the northern hemisphere we have
127  // band rows num
128  // N 0 0:8 9
129  // P 1 9:17 9
130  // Q 2 18:26 9
131  // R 3 27:34 8
132  // S 4 35:43 9
133  // T 5 44:52 9
134  // U 6 53:61 9
135  // V 7 62:70 9
136  // W 8 71:79 9
137  // X 9 80:94 15
138  return y >= 0 ? b : -(b + 1);
139  }
140  // UTMUPS access these enums
141  enum {
142  tile_ = 100000, // Size MGRS blocks
143  minutmcol_ = 1,
144  maxutmcol_ = 9,
145  minutmSrow_ = 10,
146  maxutmSrow_ = 100, // Also used for UTM S false northing
147  minutmNrow_ = 0, // Also used for UTM N false northing
148  maxutmNrow_ = 95,
149  minupsSind_ = 8, // These 4 ind's apply to easting and northing
150  maxupsSind_ = 32,
151  minupsNind_ = 13,
152  maxupsNind_ = 27,
153  upseasting_ = 20, // Also used for UPS false northing
154  utmeasting_ = 5, // UTM false easting
155  // Difference between S hemisphere northing and N hemisphere northing
156  utmNshift_ = (maxutmSrow_ - minutmNrow_) * tile_
157  };
158  MGRS(); // Disable constructor
159 
160  public:
161 
162  /**
163  * Convert UTM or UPS coordinate to an MGRS coordinate.
164  *
165  * @param[in] zone UTM zone (zero means UPS).
166  * @param[in] northp hemisphere (true means north, false means south).
167  * @param[in] x easting of point (meters).
168  * @param[in] y northing of point (meters).
169  * @param[in] prec precision relative to 100 km.
170  * @param[out] mgrs MGRS string.
171  * @exception GeographicErr if \e zone, \e x, or \e y is outside its
172  * allowed range.
173  * @exception GeographicErr if the memory for the MGRS string can't be
174  * allocated.
175  *
176  * \e prec specifies the precision of the MGRS string as follows:
177  * - \e prec = &minus;1 (min), only the grid zone is returned
178  * - \e prec = 0, 100 km
179  * - \e prec = 1, 10 km
180  * - \e prec = 2, 1 km
181  * - \e prec = 3, 100 m
182  * - \e prec = 4, 10 m
183  * - \e prec = 5, 1 m
184  * - \e prec = 6, 0.1 m
185  * - &hellip;
186  * - \e prec = 11 (max), 1 &mu;m
187  *
188  * UTM eastings are allowed to be in the range [100 km, 900 km], northings
189  * are allowed to be in in [0 km, 9500 km] for the northern hemisphere and
190  * in [1000 km, 10000 km] for the southern hemisphere. (However UTM
191  * northings can be continued across the equator. So the actual limits on
192  * the northings are [&minus;9000 km, 9500 km] for the "northern"
193  * hemisphere and [1000 km, 19500 km] for the "southern" hemisphere.)
194  *
195  * UPS eastings/northings are allowed to be in the range [1300 km, 2700 km]
196  * in the northern hemisphere and in [800 km, 3200 km] in the southern
197  * hemisphere.
198  *
199  * The ranges are 100 km more restrictive than for the conversion between
200  * geographic coordinates and UTM and UPS given by UTMUPS. These
201  * restrictions are dictated by the allowed letters in MGRS coordinates.
202  * The choice of 9500 km for the maximum northing for northern hemisphere
203  * and of 1000 km as the minimum northing for southern hemisphere provide
204  * at least 0.5 degree extension into standard UPS zones. The upper ends
205  * of the ranges for the UPS coordinates is dictated by requiring symmetry
206  * about the meridians 0E and 90E.
207  *
208  * All allowed UTM and UPS coordinates may now be converted to legal MGRS
209  * coordinates with the proviso that eastings and northings on the upper
210  * boundaries are silently reduced by about 4 nm (4 nanometers) to place
211  * them \e within the allowed range. (This includes reducing a southern
212  * hemisphere northing of 10000 km by 4 nm so that it is placed in latitude
213  * band M.) The UTM or UPS coordinates are truncated to requested
214  * precision to determine the MGRS coordinate. Thus in UTM zone 38n, the
215  * square area with easting in [444 km, 445 km) and northing in [3688 km,
216  * 3689 km) maps to MGRS coordinate 38SMB4488 (at \e prec = 2, 1 km),
217  * Khulani Sq., Baghdad.
218  *
219  * The UTM/UPS selection and the UTM zone is preserved in the conversion to
220  * MGRS coordinate. Thus for \e zone > 0, the MGRS coordinate begins with
221  * the zone number followed by one of [C--M] for the southern
222  * hemisphere and [N--X] for the northern hemisphere. For \e zone =
223  * 0, the MGRS coordinates begins with one of [AB] for the southern
224  * hemisphere and [XY] for the northern hemisphere.
225  *
226  * The conversion to the MGRS is exact for prec in [0, 5] except that a
227  * neighboring latitude band letter may be given if the point is within 5nm
228  * of a band boundary. For prec in [6, 11], the conversion is accurate to
229  * roundoff.
230  *
231  * If \e prec = &minus;1, then the "grid zone designation", e.g., 18T, is
232  * returned. This consists of the UTM zone number (absent for UPS) and the
233  * first letter of the MGRS string which labels the latitude band for UTM
234  * and the hemisphere for UPS.
235  *
236  * If \e x or \e y is NaN or if \e zone is UTMUPS::INVALID, the returned
237  * MGRS string is "INVALID".
238  *
239  * Return the result via a reference argument to avoid the overhead of
240  * allocating a potentially large number of small strings. If an error is
241  * thrown, then \e mgrs is unchanged.
242  **********************************************************************/
243  static void Forward(int zone, bool northp, real x, real y,
244  int prec, std::string& mgrs);
245 
246  /**
247  * Convert UTM or UPS coordinate to an MGRS coordinate when the latitude is
248  * known.
249  *
250  * @param[in] zone UTM zone (zero means UPS).
251  * @param[in] northp hemisphere (true means north, false means south).
252  * @param[in] x easting of point (meters).
253  * @param[in] y northing of point (meters).
254  * @param[in] lat latitude (degrees).
255  * @param[in] prec precision relative to 100 km.
256  * @param[out] mgrs MGRS string.
257  * @exception GeographicErr if \e zone, \e x, or \e y is outside its
258  * allowed range.
259  * @exception GeographicErr if \e lat is inconsistent with the given UTM
260  * coordinates.
261  * @exception std::bad_alloc if the memory for \e mgrs can't be allocated.
262  *
263  * The latitude is ignored for \e zone = 0 (UPS); otherwise the latitude is
264  * used to determine the latitude band and this is checked for consistency
265  * using the same tests as Reverse.
266  **********************************************************************/
267  static void Forward(int zone, bool northp, real x, real y, real lat,
268  int prec, std::string& mgrs);
269 
270  /**
271  * Convert a MGRS coordinate to UTM or UPS coordinates.
272  *
273  * @param[in] mgrs MGRS string.
274  * @param[out] zone UTM zone (zero means UPS).
275  * @param[out] northp hemisphere (true means north, false means south).
276  * @param[out] x easting of point (meters).
277  * @param[out] y northing of point (meters).
278  * @param[out] prec precision relative to 100 km.
279  * @param[in] centerp if true (default), return center of the MGRS square,
280  * else return SW (lower left) corner.
281  * @exception GeographicErr if \e mgrs is illegal.
282  *
283  * All conversions from MGRS to UTM/UPS are permitted provided the MGRS
284  * coordinate is a possible result of a conversion in the other direction.
285  * (The leading 0 may be dropped from an input MGRS coordinate for UTM
286  * zones 1--9.) In addition, MGRS coordinates with a neighboring
287  * latitude band letter are permitted provided that some portion of the
288  * 100 km block is within the given latitude band. Thus
289  * - 38VLS and 38WLS are allowed (latitude 64N intersects the square
290  * 38[VW]LS); but 38VMS is not permitted (all of 38WMS is north of 64N)
291  * - 38MPE and 38NPF are permitted (they straddle the equator); but 38NPE
292  * and 38MPF are not permitted (the equator does not intersect either
293  * block).
294  * - Similarly ZAB and YZB are permitted (they straddle the prime
295  * meridian); but YAB and ZZB are not (the prime meridian does not
296  * intersect either block).
297  *
298  * The UTM/UPS selection and the UTM zone is preserved in the conversion
299  * from MGRS coordinate. The conversion is exact for prec in [0, 5]. With
300  * \e centerp = true, the conversion from MGRS to geographic and back is
301  * stable. This is not assured if \e centerp = false.
302  *
303  * If a "grid zone designation" (for example, 18T or A) is given, then some
304  * suitable (but essentially arbitrary) point within that grid zone is
305  * returned. The main utility of the conversion is to allow \e zone and \e
306  * northp to be determined. In this case, the \e centerp parameter is
307  * ignored and \e prec is set to &minus;1.
308  *
309  * If the first 3 characters of \e mgrs are "INV", then \e x and \e y are
310  * set to NaN, \e zone is set to UTMUPS::INVALID, and \e prec is set to
311  * &minus;2.
312  *
313  * If an exception is thrown, then the arguments are unchanged.
314  **********************************************************************/
315  static void Reverse(const std::string& mgrs,
316  int& zone, bool& northp, real& x, real& y,
317  int& prec, bool centerp = true);
318 
319  /** \name Inspector functions
320  **********************************************************************/
321  ///@{
322  /**
323  * @return \e a the equatorial radius of the WGS84 ellipsoid (meters).
324  *
325  * (The WGS84 value is returned because the UTM and UPS projections are
326  * based on this ellipsoid.)
327  **********************************************************************/
329 
330  /**
331  * @return \e f the flattening of the WGS84 ellipsoid.
332  *
333  * (The WGS84 value is returned because the UTM and UPS projections are
334  * based on this ellipsoid.)
335  **********************************************************************/
336  static Math::real Flattening() { return UTMUPS::Flattening(); }
337  ///@}
338 
339  /**
340  * Perform some checks on the UTMUPS coordinates on this ellipsoid. Throw
341  * an error if any of the assumptions made in the MGRS class is not true.
342  * This check needs to be carried out if the ellipsoid parameters (or the
343  * UTM/UPS scales) are ever changed.
344  **********************************************************************/
345  static void Check();
346 
347  /// \cond SKIP
348  /**
349  * <b>DEPRECATED</b>
350  * @return \e r the inverse flattening of the WGS84 ellipsoid.
351  **********************************************************************/
352  static Math::real InverseFlattening()
353  { return UTMUPS::InverseFlattening(); }
354  /// \endcond
355  };
356 
357 } // namespace GeographicLib
358 
359 #if defined(_MSC_VER)
360 # pragma warning (pop)
361 #endif
362 
363 #endif // GEOGRAPHICLIB_MGRS_HPP
#define GEOGRAPHICLIB_EXPORT
Definition: Constants.hpp:90
static Math::real Flattening()
Definition: UTMUPS.hpp:413
static Math::real MajorRadius()
Definition: MGRS.hpp:328
GeographicLib::Math::real real
Definition: GeodSolve.cpp:32
Header for GeographicLib::UTMUPS class.
static Math::real MajorRadius()
Definition: UTMUPS.hpp:404
Convert between geographic coordinates and UTM/UPS.
Definition: UTMUPS.hpp:75
Namespace for GeographicLib.
Definition: Accumulator.cpp:12
Header for GeographicLib::Constants class.
static Math::real Flattening()
Definition: MGRS.hpp:336
Convert between UTM/UPS and MGRS.
Definition: MGRS.hpp:74