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