GeographicLib  1.30
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-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_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 
31  * Datums, Ellipsoids, Grids, and Grid Reference Systems</a>,
32  * Defense Mapping Agency, Technical Manual TM8358.1 (1990).
33  *
34  * This implementation has the following properties:
35  * - The conversions are closed, i.e., output from Forward is legal input for
36  * Reverse and vice versa. Conversion in both directions preserve the
37  * UTM/UPS selection and the UTM zone.
38  * - Forward followed by Reverse and vice versa is approximately the
39  * identity. (This is affected in predictable ways by errors in
40  * determining the latitude band and by loss of precision in the MGRS
41  * coordinates.)
42  * - All MGRS coordinates truncate to legal 100 km blocks. All MGRS
43  * coordinates with a legal 100 km block prefix are legal (even though the
44  * latitude band letter may now belong to a neighboring band).
45  * - The range of UTM/UPS coordinates allowed for conversion to MGRS
46  * coordinates is the maximum consistent with staying within the letter
47  * ranges of the MGRS scheme.
48  * - All the transformations are implemented as static methods in the MGRS
49  * class.
50  *
51  * The <a href="http://www.nga.mil">NGA</a> software package
52  * <a href="http://earth-info.nga.mil/GandG/geotrans/index.html">geotrans</a>
53  * also provides conversions to and from MGRS. Version 3.0 (and earlier)
54  * suffers from some drawbacks:
55  * - Inconsistent rules are used to determine the whether a particular MGRS
56  * coordinate is legal. A more systematic approach is taken here.
57  * - The underlying projections are not very accurately implemented.
58  *
59  * Example of use:
60  * \include example-MGRS.cpp
61  **********************************************************************/
63  private:
64  typedef Math::real real;
65  // The smallest length s.t., 1.0e7 - eps_ < 1.0e7 (approx 1.9 nm)
66  static const real eps_;
67  // The smallest angle s.t., 90 - eps_ < 90 (approx 50e-12 arcsec)
68  static const real angeps_;
69  static const std::string hemispheres_;
70  static const std::string utmcols_[3];
71  static const std::string utmrow_;
72  static const std::string upscols_[4];
73  static const std::string upsrows_[2];
74  static const std::string latband_;
75  static const std::string upsband_;
76  static const std::string digits_;
77 
78  static const int mineasting_[4];
79  static const int maxeasting_[4];
80  static const int minnorthing_[4];
81  static const int maxnorthing_[4];
82  enum {
83  base_ = 10,
84  // Top-level tiles are 10^5 m = 100 km on a side
85  tilelevel_ = 5,
86  // Period of UTM row letters
87  utmrowperiod_ = 20,
88  // Row letters are shifted by 5 for even zones
89  utmevenrowshift_ = 5,
90  // Maximum precision is um
91  maxprec_ = 5 + 6,
92  };
93  static void CheckCoords(bool utmp, bool& northp, real& x, real& y);
94  static int UTMRow(int iband, int icol, int irow) throw();
95 
96  friend class UTMUPS; // UTMUPS::StandardZone calls LatitudeBand
97  // Return latitude band number [-10, 10) for the give latitude (degrees).
98  // The bands are reckoned in include their southern edges.
99  static int LatitudeBand(real lat) throw() {
100  int ilat = int(std::floor(lat));
101  return (std::max)(-10, (std::min)(9, (ilat + 80)/8 - 10));
102  }
103  // UTMUPS access these enums
104  enum {
105  tile_ = 100000, // Size MGRS blocks
106  minutmcol_ = 1,
107  maxutmcol_ = 9,
108  minutmSrow_ = 10,
109  maxutmSrow_ = 100, // Also used for UTM S false northing
110  minutmNrow_ = 0, // Also used for UTM N false northing
111  maxutmNrow_ = 95,
112  minupsSind_ = 8, // These 4 ind's apply to easting and northing
113  maxupsSind_ = 32,
114  minupsNind_ = 13,
115  maxupsNind_ = 27,
116  upseasting_ = 20, // Also used for UPS false northing
117  utmeasting_ = 5, // UTM false easting
118  // Difference between S hemisphere northing and N hemisphere northing
119  utmNshift_ = (maxutmSrow_ - minutmNrow_) * tile_
120  };
121  MGRS(); // Disable constructor
122 
123  public:
124 
125  /**
126  * Convert UTM or UPS coordinate to an MGRS coordinate.
127  *
128  * @param[in] zone UTM zone (zero means UPS).
129  * @param[in] northp hemisphere (true means north, false means south).
130  * @param[in] x easting of point (meters).
131  * @param[in] y northing of point (meters).
132  * @param[in] prec precision relative to 100 km.
133  * @param[out] mgrs MGRS string.
134  * @exception GeographicErr if \e zone, \e x, or \e y is outside its
135  * allowed range.
136  * @exception GeographicErr if the memory for the MGRS string can't be
137  * allocated.
138  *
139  * \e prec specifies the precision of the MGRS string as follows:
140  * - prec = 0 (min), 100 km
141  * - prec = 1, 10 km
142  * - prec = 2, 1 km
143  * - prec = 3, 100 m
144  * - prec = 4, 10 m
145  * - prec = 5, 1 m
146  * - prec = 6, 0.1 m
147  * - prec = 11 (max), 1 &mu;m
148  *
149  * UTM eastings are allowed to be in the range [100 km, 900 km], northings
150  * are allowed to be in in [0 km, 9500 km] for the northern hemisphere and
151  * in [1000 km, 10000 km] for the southern hemisphere. (However UTM
152  * northings can be continued across the equator. So the actual limits on
153  * the northings are [&minus;9000 km, 9500 km] for the "northern"
154  * hemisphere and [1000 km, 19500 km] for the "southern" hemisphere.)
155  *
156  * UPS eastings/northings are allowed to be in the range [1300 km, 2700 km]
157  * in the northern hemisphere and in [800 km, 3200 km] in the southern
158  * hemisphere.
159  *
160  * The ranges are 100 km more restrictive that for the conversion between
161  * geographic coordinates and UTM and UPS given by UTMUPS. These
162  * restrictions are dictated by the allowed letters in MGRS coordinates.
163  * The choice of 9500 km for the maximum northing for northern hemisphere
164  * and of 1000 km as the minimum northing for southern hemisphere provide
165  * at least 0.5 degree extension into standard UPS zones. The upper ends
166  * of the ranges for the UPS coordinates is dictated by requiring symmetry
167  * about the meridians 0E and 90E.
168  *
169  * All allowed UTM and UPS coordinates may now be converted to legal MGRS
170  * coordinates with the proviso that eastings and northings on the upper
171  * boundaries are silently reduced by about 4 nm (4 nanometers) to place
172  * them \e within the allowed range. (This includes reducing a southern
173  * hemisphere northing of 10000 km by 4 nm so that it is placed in latitude
174  * band M.) The UTM or UPS coordinates are truncated to requested
175  * precision to determine the MGRS coordinate. Thus in UTM zone 38N, the
176  * square area with easting in [444 km, 445 km) and northing in [3688 km,
177  * 3689 km) maps to MGRS coordinate 38SMB4488 (at \e prec = 2, 1 km),
178  * Khulani Sq., Baghdad.
179  *
180  * The UTM/UPS selection and the UTM zone is preserved in the conversion to
181  * MGRS coordinate. Thus for \e zone > 0, the MGRS coordinate begins with
182  * the zone number followed by one of [C--M] for the southern
183  * hemisphere and [N--X] for the northern hemisphere. For \e zone =
184  * 0, the MGRS coordinates begins with one of [AB] for the southern
185  * hemisphere and [XY] for the northern hemisphere.
186  *
187  * The conversion to the MGRS is exact for prec in [0, 5] except that a
188  * neighboring latitude band letter may be given if the point is within 5nm
189  * of a band boundary. For prec in [6, 11], the conversion is accurate to
190  * roundoff.
191  *
192  * If \e x or \e y is NaN or if \e zone is UTMUPS::INVALID, the returned
193  * MGRS string is "INVALID".
194  *
195  * Return the result via a reference argument to avoid the overhead of
196  * allocating a potentially large number of small strings. If an error is
197  * thrown, then \e mgrs is unchanged.
198  **********************************************************************/
199  static void Forward(int zone, bool northp, real x, real y,
200  int prec, std::string& mgrs);
201 
202  /**
203  * Convert UTM or UPS coordinate to an MGRS coordinate when the latitude is
204  * known.
205  *
206  * @param[in] zone UTM zone (zero means UPS).
207  * @param[in] northp hemisphere (true means north, false means south).
208  * @param[in] x easting of point (meters).
209  * @param[in] y northing of point (meters).
210  * @param[in] lat latitude (degrees).
211  * @param[in] prec precision relative to 100 km.
212  * @param[out] mgrs MGRS string.
213  * @exception GeographicErr if \e zone, \e x, or \e y is outside its
214  * allowed range.
215  * @exception GeographicErr if \e lat is inconsistent with the given UTM
216  * coordinates.
217  * @exception std::bad_alloc if the memory for \e mgrs can't be allocated.
218  *
219  * The latitude is ignored for \e zone = 0 (UPS); otherwise the latitude is
220  * used to determine the latitude band and this is checked for consistency
221  * using the same tests as Reverse.
222  **********************************************************************/
223  static void Forward(int zone, bool northp, real x, real y, real lat,
224  int prec, std::string& mgrs);
225 
226  /**
227  * Convert a MGRS coordinate to UTM or UPS coordinates.
228  *
229  * @param[in] mgrs MGRS string.
230  * @param[out] zone UTM zone (zero means UPS).
231  * @param[out] northp hemisphere (true means north, false means south).
232  * @param[out] x easting of point (meters).
233  * @param[out] y northing of point (meters).
234  * @param[out] prec precision relative to 100 km.
235  * @param[in] centerp if true (default), return center of the MGRS square,
236  * else return SW (lower left) corner.
237  * @exception GeographicErr if \e mgrs is illegal.
238  *
239  * All conversions from MGRS to UTM/UPS are permitted provided the MGRS
240  * coordinate is a possible result of a conversion in the other direction.
241  * (The leading 0 may be dropped from an input MGRS coordinate for UTM
242  * zones 1--9.) In addition, MGRS coordinates with a neighboring
243  * latitude band letter are permitted provided that some portion of the
244  * 100 km block is within the given latitude band. Thus
245  * - 38VLS and 38WLS are allowed (latitude 64N intersects the square
246  * 38[VW]LS); but 38VMS is not permitted (all of 38VMS is north of 64N)
247  * - 38MPE and 38NPF are permitted (they straddle the equator); but 38NPE
248  * and 38MPF are not permitted (the equator does not intersect either
249  * block).
250  * - Similarly ZAB and YZB are permitted (they straddle the prime
251  * meridian); but YAB and ZZB are not (the prime meridian does not
252  * intersect either block).
253  *
254  * The UTM/UPS selection and the UTM zone is preserved in the conversion
255  * from MGRS coordinate. The conversion is exact for prec in [0, 5]. With
256  * centerp = true the conversion from MGRS to geographic and back is
257  * stable. This is not assured if \e centerp = false.
258  *
259  * If the first 3 characters of \e mgrs are "INV", then \e x and \e y are
260  * set to NaN and \e zone is set to UTMUPS::INVALID.
261  *
262  * If an exception is thrown, then the arguments are unchanged.
263  **********************************************************************/
264  static void Reverse(const std::string& mgrs,
265  int& zone, bool& northp, real& x, real& y,
266  int& prec, bool centerp = true);
267 
268  /** \name Inspector functions
269  **********************************************************************/
270  ///@{
271  /**
272  * @return \e a the equatorial radius of the WGS84 ellipsoid (meters).
273  *
274  * (The WGS84 value is returned because the UTM and UPS projections are
275  * based on this ellipsoid.)
276  **********************************************************************/
277  static Math::real MajorRadius() throw() { return UTMUPS::MajorRadius(); }
278 
279  /**
280  * @return \e f the flattening of the WGS84 ellipsoid.
281  *
282  * (The WGS84 value is returned because the UTM and UPS projections are
283  * based on this ellipsoid.)
284  **********************************************************************/
285  static Math::real Flattening() throw() { return UTMUPS::Flattening(); }
286  ///@}
287 
288  /// \cond SKIP
289  /**
290  * <b>DEPRECATED</b>
291  * @return \e r the inverse flattening of the WGS84 ellipsoid.
292  **********************************************************************/
293  static Math::real InverseFlattening() throw()
294  { return UTMUPS::InverseFlattening(); }
295  /// \endcond
296  };
297 
298 } // namespace GeographicLib
299 
300 #if defined(_MSC_VER)
301 # pragma warning (pop)
302 #endif
303 
304 #endif // GEOGRAPHICLIB_MGRS_HPP