13 namespace GeographicLib {
17 const string MGRS::hemispheres_ =
"SN";
18 const string MGRS::utmcols_[3] = {
"ABCDEFGH",
"JKLMNPQR",
"STUVWXYZ" };
19 const string MGRS::utmrow_ =
"ABCDEFGHJKLMNPQRSTUV";
20 const string MGRS::upscols_[4] =
21 {
"JKLPQRSTUXYZ",
"ABCFGHJKLPQR",
"RSTUXYZ",
"ABCFGHJ" };
22 const string MGRS::upsrows_[2] =
23 {
"ABCDEFGHJKLMNPQRSTUVWXYZ",
"ABCDEFGHJKLMNP" };
24 const string MGRS::latband_ =
"CDEFGHJKLMNPQRSTUVWX";
25 const string MGRS::upsband_ =
"ABYZ";
26 const string MGRS::digits_ =
"0123456789";
28 const int MGRS::mineasting_[4] =
29 { minupsSind_, minupsNind_, minutmcol_, minutmcol_ };
30 const int MGRS::maxeasting_[4] =
31 { maxupsSind_, maxupsNind_, maxutmcol_, maxutmcol_ };
32 const int MGRS::minnorthing_[4] =
33 { minupsSind_, minupsNind_,
34 minutmSrow_, minutmSrow_ - (maxutmSrow_ - minutmNrow_) };
35 const int MGRS::maxnorthing_[4] =
36 { maxupsSind_, maxupsNind_,
37 maxutmNrow_ + (maxutmSrow_ - minutmNrow_), maxutmNrow_ };
40 int prec, std::string& mgrs) {
46 bool utmp = zone != 0;
47 CheckCoords(utmp, northp, x, y);
50 if (!(prec >= -1 && prec <= maxprec_))
56 char mgrs1[2 + 3 + 2 * maxprec_];
60 mlen = z + 3 + 2 * prec;
62 mgrs1[0] = digits_[ zone / base_ ];
63 mgrs1[1] = digits_[ zone % base_ ];
68 xh = int(floor(x)) / tile_,
69 yh = int(floor(y)) / tile_;
76 iband = abs(lat) > angeps() ? LatitudeBand(lat) : (northp ? 0 : -1),
77 icol = xh - minutmcol_,
78 irow = UTMRow(iband, icol, yh % utmrowperiod_);
79 if (irow != yh - (northp ? minutmNrow_ : maxutmSrow_))
81 +
" is inconsistent with UTM coordinates");
82 mgrs1[z++] = latband_[10 + iband];
83 mgrs1[z++] = utmcols_[zone1 % 3][icol];
84 mgrs1[z++] = utmrow_[(yh + (zone1 & 1 ? utmevenrowshift_ : 0))
87 bool eastp = xh >= upseasting_;
88 int iband = (northp ? 2 : 0) + (eastp ? 1 : 0);
89 mgrs1[z++] = upsband_[iband];
90 mgrs1[z++] = upscols_[iband][xh - (eastp ? upseasting_ :
91 (northp ? minupsNind_ : minupsSind_))];
92 mgrs1[z++] = upsrows_[northp][yh - (northp ? minupsNind_ : minupsSind_)];
95 real mult = pow(
real(base_), max(tilelevel_ - prec, 0));
97 ix = int(floor(xf / mult)),
98 iy = int(floor(yf / mult));
99 for (
int c = min(prec,
int(tilelevel_)); c--;) {
100 mgrs1[z + c] = digits_[ ix % base_ ];
102 mgrs1[z + c + prec] = digits_[ iy % base_ ];
105 if (prec > tilelevel_) {
106 xf -= floor(xf / mult);
107 yf -= floor(yf / mult);
108 mult = pow(
real(base_), prec - tilelevel_);
109 ix = int(floor(xf * mult));
110 iy = int(floor(yf * mult));
111 for (
int c = prec - tilelevel_; c--;) {
112 mgrs1[z + c + tilelevel_] = digits_[ ix % base_ ];
114 mgrs1[z + c + tilelevel_ + prec] = digits_[ iy % base_ ];
120 copy(mgrs1, mgrs1 + mlen, mgrs.begin());
124 int prec, std::string& mgrs) {
128 real ys = northp ? y : y - utmNshift_;
142 latp =
real(0.901) * ys + (ys > 0 ? 1 : -1) *
real(0.135),
145 late =
real(0.902) * ys * (1 -
real(1.85e-6) * ys * ys);
146 if (LatitudeBand(latp) == LatitudeBand(late))
155 Forward(zone, northp, x, y, lat, prec, mgrs);
159 int& zone,
bool& northp, real& x, real& y,
160 int& prec,
bool centerp) {
163 len = int(mgrs.size());
165 toupper(mgrs[0]) ==
'I' &&
166 toupper(mgrs[1]) ==
'N' &&
167 toupper(mgrs[2]) ==
'V') {
179 zone1 = 10 * zone1 + i;
186 + mgrs.substr(0, p));
190 int zonem1 = zone1 - 1;
191 const string& band = utmp ? latband_ : upsband_;
195 + (utmp ?
"UTM" :
"UPS") +
" set " + band);
196 bool northp1 = iband >= (utmp ? 10 : 2);
199 real deg =
real(utmNshift_) / (90 * tile_);
204 x = ((zone == 31 && iband == 17) ? 4 : 5) * tile_;
206 y = floor(8 * (iband -
real(9.5)) * deg +
real(0.5)) * tile_
207 + (northp ? 0 : utmNshift_);
210 x = ((iband & 1 ? 1 : -1) * floor(4 * deg +
real(0.5))
211 + upseasting_) * tile_;
213 y = upseasting_ * tile_;
217 }
else if (len - p < 2)
219 const string& col = utmp ? utmcols_[zonem1 % 3] : upscols_[iband];
220 const string& row = utmp ? utmrow_ : upsrows_[northp1];
225 + (utmp ?
"zone " + mgrs.substr(0, p-2) :
236 irow = (irow + utmrowperiod_ - utmevenrowshift_) % utmrowperiod_;
238 irow = UTMRow(iband, icol, irow);
239 if (irow == maxutmSrow_)
241 +
" not in zone/band " + mgrs.substr(0, p-2));
243 irow = northp1 ? irow : irow + 100;
244 icol = icol + minutmcol_;
246 bool eastp = iband & 1;
247 icol += eastp ? upseasting_ : (northp1 ? minupsNind_ : minupsSind_);
248 irow += northp1 ? minupsNind_ : minupsSind_;
250 int prec1 = (len - p)/2;
255 for (
int i = 0; i < prec1; ++i) {
260 if (ix < 0 || iy < 0)
261 throw GeographicErr(
"Encountered a non-digit in " + mgrs.substr(p));
267 throw GeographicErr(
"Encountered a non-digit in " + mgrs.substr(p));
272 if (prec1 > maxprec_)
287 void MGRS::CheckCoords(
bool utmp,
bool& northp,
real& x,
real& y) {
294 ix = int(floor(x / tile_)),
295 iy = int(floor(y / tile_)),
296 ind = (utmp ? 2 : 0) + (northp ? 1 : 0);
297 if (! (ix >= mineasting_[ind] && ix < maxeasting_[ind]) ) {
298 if (ix == maxeasting_[ind] && x == maxeasting_[ind] * tile_)
303 + (utmp ?
"UTM" :
"UPS") +
" range for "
304 + (northp ?
"N" :
"S" ) +
" hemisphere ["
310 if (! (iy >= minnorthing_[ind] && iy < maxnorthing_[ind]) ) {
311 if (iy == maxnorthing_[ind] && y == maxnorthing_[ind] * tile_)
314 throw GeographicErr(
"Northing " +
Utility::str(
int(floor(y/1000)))
316 + (utmp ?
"UTM" :
"UPS") +
" range for "
317 + (northp ?
"N" :
"S" ) +
" hemisphere ["
326 if (northp && iy < minutmNrow_) {
329 }
else if (!northp && iy >= maxutmSrow_) {
330 if (y == maxutmSrow_ * tile_)
341 int MGRS::UTMRow(
int iband,
int icol,
int irow) {
349 real c = 100 * (8 * iband + 4)/
real(90);
350 bool northp = iband >= 0;
373 minrow = iband > -10 ?
374 int(floor(c -
real(4.3) -
real(0.1) * northp)) : -90,
376 int(floor(c +
real(4.4) -
real(0.1) * northp)) : 94,
377 baserow = (minrow + maxrow) / 2 - utmrowperiod_ / 2;
379 irow = (irow - baserow + maxutmSrow_) % utmrowperiod_ + baserow;
380 if (irow < minrow || irow > maxrow) {
385 sband = iband >= 0 ? iband : -iband - 1,
387 srow = irow >= 0 ? irow : -irow - 1,
389 scol = icol < 4 ? icol : -icol + 7;
390 if ( ! ( (srow == 70 && sband == 8 && scol >= 2) ||
391 (srow == 71 && sband == 7 && scol <= 2) ||
392 (srow == 79 && sband == 9 && scol >= 1) ||
393 (srow == 80 && sband == 8 && scol <= 1) ) )