13 namespace GeographicLib {
20 pow(
real(0.5), numeric_limits<real>::digits - 25);
23 pow(
real(0.5), numeric_limits<real>::digits - 7);
24 const string MGRS::hemispheres_ =
"SN";
25 const string MGRS::utmcols_[3] = {
"ABCDEFGH",
"JKLMNPQR",
"STUVWXYZ" };
26 const string MGRS::utmrow_ =
"ABCDEFGHJKLMNPQRSTUV";
27 const string MGRS::upscols_[4] =
28 {
"JKLPQRSTUXYZ",
"ABCFGHJKLPQR",
"RSTUXYZ",
"ABCFGHJ" };
29 const string MGRS::upsrows_[2] =
30 {
"ABCDEFGHJKLMNPQRSTUVWXYZ",
"ABCDEFGHJKLMNP" };
31 const string MGRS::latband_ =
"CDEFGHJKLMNPQRSTUVWX";
32 const string MGRS::upsband_ =
"ABYZ";
33 const string MGRS::digits_ =
"0123456789";
35 const int MGRS::mineasting_[4] =
36 { minupsSind_, minupsNind_, minutmcol_, minutmcol_ };
37 const int MGRS::maxeasting_[4] =
38 { maxupsSind_, maxupsNind_, maxutmcol_, maxutmcol_ };
39 const int MGRS::minnorthing_[4] =
40 { minupsSind_, minupsNind_,
41 minutmSrow_, minutmSrow_ - (maxutmSrow_ - minutmNrow_) };
42 const int MGRS::maxnorthing_[4] =
43 { maxupsSind_, maxupsNind_,
44 maxutmNrow_ + (maxutmSrow_ - minutmNrow_), maxutmNrow_ };
47 int prec, std::string& mgrs) {
54 bool utmp = zone != 0;
55 CheckCoords(utmp, northp, x, y);
58 if (!(prec >= 0 && prec <= maxprec_))
64 char mgrs1[2 + 3 + 2 * maxprec_];
68 mlen = z + 3 + 2 * prec;
70 mgrs1[0] = digits_[ zone / base_ ];
71 mgrs1[1] = digits_[ zone % base_ ];
76 xh = int(floor(x)) / tile_,
77 yh = int(floor(y)) / tile_;
84 iband = abs(lat) > angeps_ ? LatitudeBand(lat) : (northp ? 0 : -1),
85 icol = xh - minutmcol_,
86 irow = UTMRow(iband, icol, yh % utmrowperiod_);
87 if (irow != yh - (northp ? minutmNrow_ : maxutmSrow_))
89 +
" is inconsistent with UTM coordinates");
90 mgrs1[z++] = latband_[10 + iband];
91 mgrs1[z++] = utmcols_[zone1 % 3][icol];
92 mgrs1[z++] = utmrow_[(yh + (zone1 & 1 ? utmevenrowshift_ : 0))
95 bool eastp = xh >= upseasting_;
96 int iband = (northp ? 2 : 0) + (eastp ? 1 : 0);
97 mgrs1[z++] = upsband_[iband];
98 mgrs1[z++] = upscols_[iband][xh - (eastp ? upseasting_ :
99 (northp ? minupsNind_ : minupsSind_))];
100 mgrs1[z++] = upsrows_[northp][yh - (northp ? minupsNind_ : minupsSind_)];
102 real mult = pow(
real(base_), max(tilelevel_ - prec, 0));
104 ix = int(floor(xf / mult)),
105 iy = int(floor(yf / mult));
106 for (
int c = min(prec,
int(tilelevel_)); c--;) {
107 mgrs1[z + c] = digits_[ ix % base_ ];
109 mgrs1[z + c + prec] = digits_[ iy % base_ ];
112 if (prec > tilelevel_) {
113 xf -= floor(xf / mult);
114 yf -= floor(yf / mult);
115 mult = pow(
real(base_), prec - tilelevel_);
116 ix = int(floor(xf * mult));
117 iy = int(floor(yf * mult));
118 for (
int c = prec - tilelevel_; c--;) {
119 mgrs1[z + c + tilelevel_] = digits_[ ix % base_ ];
121 mgrs1[z + c + tilelevel_ + prec] = digits_[ iy % base_ ];
126 copy(mgrs1, mgrs1 + mlen, mgrs.begin());
130 int prec, std::string& mgrs) {
137 Forward(zone, northp, x, y, lat, prec, mgrs);
141 int& zone,
bool& northp, real& x, real& y,
142 int& prec,
bool centerp) {
145 len = int(mgrs.size());
147 toupper(mgrs[0]) ==
'I' &&
148 toupper(mgrs[1]) ==
'N' &&
149 toupper(mgrs[2]) ==
'V') {
152 x = y = Math::NaN<real>();
161 zone1 = 10 * zone1 + i;
168 + mgrs.substr(0, p));
172 int zonem1 = zone1 - 1;
173 const string& band = utmp ? latband_ : upsband_;
177 + (utmp ?
"UTM" :
"UPS") +
" set " + band);
178 bool northp1 = iband >= (utmp ? 10 : 2);
179 const string& col = utmp ? utmcols_[zonem1 % 3] : upscols_[iband];
180 const string& row = utmp ? utmrow_ : upsrows_[northp1];
185 + (utmp ?
"zone " + mgrs.substr(0, p-2) :
196 irow = (irow + utmrowperiod_ - utmevenrowshift_) % utmrowperiod_;
198 irow = UTMRow(iband, icol, irow);
199 if (irow == maxutmSrow_)
201 +
" not in zone/band " + mgrs.substr(0, p-2));
203 irow = northp1 ? irow : irow + 100;
204 icol = icol + minutmcol_;
206 bool eastp = iband & 1;
207 icol += eastp ? upseasting_ : (northp1 ? minupsNind_ : minupsSind_);
208 irow += northp1 ? minupsNind_ : minupsSind_;
210 int prec1 = (len - p)/2;
215 for (
int i = 0; i < prec1; ++i) {
220 if (ix < 0 || iy < 0)
221 throw GeographicErr(
"Encountered a non-digit in " + mgrs.substr(p));
227 throw GeographicErr(
"Encountered a non-digit in " + mgrs.substr(p));
232 if (prec1 > maxprec_)
247 void MGRS::CheckCoords(
bool utmp,
bool& northp,
real& x,
real& y) {
254 ix = int(floor(x / tile_)),
255 iy = int(floor(y / tile_)),
256 ind = (utmp ? 2 : 0) + (northp ? 1 : 0);
257 if (! (ix >= mineasting_[ind] && ix < maxeasting_[ind]) ) {
258 if (ix == maxeasting_[ind] && x == maxeasting_[ind] * tile_)
263 + (utmp ?
"UTM" :
"UPS") +
" range for "
264 + (northp ?
"N" :
"S" ) +
" hemisphere ["
270 if (! (iy >= minnorthing_[ind] && iy < maxnorthing_[ind]) ) {
271 if (iy == maxnorthing_[ind] && y == maxnorthing_[ind] * tile_)
274 throw GeographicErr(
"Northing " +
Utility::str(
int(floor(y/1000)))
276 + (utmp ?
"UTM" :
"UPS") +
" range for "
277 + (northp ?
"N" :
"S" ) +
" hemisphere ["
286 if (northp && iy < minutmNrow_) {
289 }
else if (!northp && iy >= maxutmSrow_) {
290 if (y == maxutmSrow_ * tile_)
301 int MGRS::UTMRow(
int iband,
int icol,
int irow)
throw() {
309 real c = 100 * (8 * iband + 4)/
real(90);
310 bool northp = iband >= 0;
312 minrow = iband > -10 ?
313 int(floor(c -
real(4.3) -
real(0.1) * northp)) : -90,
315 int(floor(c +
real(4.4) -
real(0.1) * northp)) : 94,
316 baserow = (minrow + maxrow) / 2 - utmrowperiod_ / 2;
318 irow = (irow - baserow + maxutmSrow_) % utmrowperiod_ + baserow;
319 if (irow < minrow || irow > maxrow) {
324 sband = iband >= 0 ? iband : -iband - 1,
326 srow = irow >= 0 ? irow : -irow - 1,
328 scol = icol < 4 ? icol : -icol + 7;
329 if ( ! ( (srow == 70 && sband == 8 && scol >= 2) ||
330 (srow == 71 && sband == 7 && scol <= 2) ||
331 (srow == 79 && sband == 9 && scol >= 1) ||
332 (srow == 80 && sband == 8 && scol <= 1) ) )