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) {
49 bool utmp = zone != 0;
50 CheckCoords(utmp, northp, x, y);
53 if (!(prec >= -1 && prec <= maxprec_))
59 char mgrs1[2 + 3 + 2 * maxprec_];
63 mlen = z + 3 + 2 * prec;
65 mgrs1[0] = digits_[ zone / base_ ];
66 mgrs1[1] = digits_[ zone % base_ ];
72 GEOGRAPHICLIB_STATIC_ASSERT(numeric_limits<long long>::digits >= 44,
73 "long long not wide enough to store 10e12");
75 ix = (
long long)(floor(x * mult_)),
76 iy = (
long long)(floor(y * mult_)),
77 m = (
long long)(mult_) * (
long long)(tile_);
78 int xh = int(ix / m), yh = int(iy / m);
82 iband = abs(lat) > angeps ? LatitudeBand(lat) : (northp ? 0 : -1),
83 icol = xh - minutmcol_,
84 irow = UTMRow(iband, icol, yh % utmrowperiod_);
85 if (irow != yh - (northp ? minutmNrow_ : maxutmSrow_))
87 +
" is inconsistent with UTM coordinates");
88 mgrs1[z++] = latband_[10 + iband];
89 mgrs1[z++] = utmcols_[zone1 % 3][icol];
90 mgrs1[z++] = utmrow_[(yh + (zone1 & 1 ? utmevenrowshift_ : 0))
93 bool eastp = xh >= upseasting_;
94 int iband = (northp ? 2 : 0) + (eastp ? 1 : 0);
95 mgrs1[z++] = upsband_[iband];
96 mgrs1[z++] = upscols_[iband][xh - (eastp ? upseasting_ :
97 (northp ? minupsNind_ : minupsSind_))];
98 mgrs1[z++] = upsrows_[northp][yh - (northp ? minupsNind_ : minupsSind_)];
101 ix -= m * xh; iy -= m * yh;
102 long long d = (
long long)(pow(
real(base_), maxprec_ - prec));
104 for (
int c = prec; c--;) {
105 mgrs1[z + c ] = digits_[ix % base_]; ix /= base_;
106 mgrs1[z + c + prec] = digits_[iy % base_]; iy /= base_;
110 copy(mgrs1, mgrs1 + mlen, mgrs.begin());
114 int prec, std::string& mgrs) {
118 real ys = northp ? y : y - utmNshift_;
132 latp =
real(0.901) * ys + (ys > 0 ? 1 : -1) *
real(0.135),
135 late =
real(0.902) * ys * (1 -
real(1.85e-6) * ys * ys);
136 if (LatitudeBand(latp) == LatitudeBand(late))
145 Forward(zone, northp, x, y, lat, prec, mgrs);
149 int& zone,
bool& northp, real& x, real& y,
150 int& prec,
bool centerp) {
153 len = int(mgrs.length());
155 toupper(mgrs[0]) ==
'I' &&
156 toupper(mgrs[1]) ==
'N' &&
157 toupper(mgrs[2]) ==
'V') {
169 zone1 = 10 * zone1 + i;
176 + mgrs.substr(0, p));
180 int zonem1 = zone1 - 1;
181 const string& band = utmp ? latband_ : upsband_;
185 + (utmp ?
"UTM" :
"UPS") +
" set " + band);
186 bool northp1 = iband >= (utmp ? 10 : 2);
189 real deg =
real(utmNshift_) / (90 * tile_);
194 x = ((zone == 31 && iband == 17) ? 4 : 5) * tile_;
196 y = floor(8 * (iband -
real(9.5)) * deg +
real(0.5)) * tile_
197 + (northp ? 0 : utmNshift_);
200 x = ((iband & 1 ? 1 : -1) * floor(4 * deg +
real(0.5))
201 + upseasting_) * tile_;
203 y = upseasting_ * tile_;
207 }
else if (len - p < 2)
209 const string& col = utmp ? utmcols_[zonem1 % 3] : upscols_[iband];
210 const string& row = utmp ? utmrow_ : upsrows_[northp1];
215 + (utmp ?
"zone " + mgrs.substr(0, p-2) :
226 irow = (irow + utmrowperiod_ - utmevenrowshift_) % utmrowperiod_;
228 irow = UTMRow(iband, icol, irow);
229 if (irow == maxutmSrow_)
231 +
" not in zone/band " + mgrs.substr(0, p-2));
233 irow = northp1 ? irow : irow + 100;
234 icol = icol + minutmcol_;
236 bool eastp = iband & 1;
237 icol += eastp ? upseasting_ : (northp1 ? minupsNind_ : minupsSind_);
238 irow += northp1 ? minupsNind_ : minupsSind_;
240 int prec1 = (len - p)/2;
245 for (
int i = 0; i < prec1; ++i) {
250 if (ix < 0 || iy < 0)
251 throw GeographicErr(
"Encountered a non-digit in " + mgrs.substr(p));
252 x1 = base_ * x1 + ix;
253 y1 = base_ * y1 + iy;
257 throw GeographicErr(
"Encountered a non-digit in " + mgrs.substr(p));
262 if (prec1 > maxprec_)
264 +
" digits in " + mgrs.substr(p));
266 unit *= 2; x1 = 2 * x1 + 1; y1 = 2 * y1 + 1;
270 x = (tile_ * x1) / unit;
271 y = (tile_ * y1) / unit;
275 void MGRS::CheckCoords(
bool utmp,
bool& northp, real& x, real& y) {
287 ix = int(floor(x / tile_)),
288 iy = int(floor(y / tile_)),
289 ind = (utmp ? 2 : 0) + (northp ? 1 : 0);
290 if (! (ix >= mineasting_[ind] && ix < maxeasting_[ind]) ) {
291 if (ix == maxeasting_[ind] && x == maxeasting_[ind] * tile_)
296 + (utmp ?
"UTM" :
"UPS") +
" range for " 297 + (northp ?
"N" :
"S" ) +
" hemisphere [" 303 if (! (iy >= minnorthing_[ind] && iy < maxnorthing_[ind]) ) {
304 if (iy == maxnorthing_[ind] && y == maxnorthing_[ind] * tile_)
309 + (utmp ?
"UTM" :
"UPS") +
" range for " 310 + (northp ?
"N" :
"S" ) +
" hemisphere [" 319 if (northp && iy < minutmNrow_) {
322 }
else if (!northp && iy >= maxutmSrow_) {
323 if (y == maxutmSrow_ * tile_)
334 int MGRS::UTMRow(
int iband,
int icol,
int irow) {
343 real c = 100 * (8 * iband + 4)/
real(90);
344 bool northp = iband >= 0;
368 minrow = iband > -10 ?
369 int(floor(c -
real(4.3) -
real(0.1) * northp)) : -90,
371 int(floor(c +
real(4.4) -
real(0.1) * northp)) : 94,
372 baserow = (minrow + maxrow) / 2 - utmrowperiod_ / 2;
376 irow = (irow - baserow + maxutmSrow_) % utmrowperiod_ + baserow;
377 if (!( irow >= minrow && irow <= maxrow )) {
386 sband = iband >= 0 ? iband : -iband - 1,
388 srow = irow >= 0 ? irow : -irow - 1,
390 scol = icol < 4 ? icol : -icol + 7;
393 if ( ! ( (srow == 70 && sband == 8 && scol >= 2) ||
394 (srow == 71 && sband == 7 && scol <= 2) ||
395 (srow == 79 && sband == 9 && scol >= 1) ||
396 (srow == 80 && sband == 8 && scol <= 1) ) )
403 real lat, lon, x, y, t = tile_;
int zone;
bool northp;
406 throw GeographicErr(
"MGRS::Check: equator coverage failure");
409 throw GeographicErr(
"MGRS::Check: UTM doesn't reach latitude = 84");
412 throw GeographicErr(
"MGRS::Check: UTM doesn't reach latitude = -80");
415 throw GeographicErr(
"MGRS::Check: Norway exception creates a gap");
418 throw GeographicErr(
"MGRS::Check: Svalbard exception creates a gap");
421 throw GeographicErr(
"MGRS::Check: North UPS doesn't reach latitude = 84");
425 GeographicErr(
"MGRS::Check: South UPS doesn't reach latitude = -80");
428 const short tab[] = {
444 7, 5, 70, 7, 7, 70, 7, 7, 71, 7, 9, 71,
445 8, 5, 71, 8, 6, 71, 8, 6, 72, 8, 9, 72,
446 8, 5, 79, 8, 8, 79, 8, 8, 80, 8, 9, 80,
447 9, 5, 80, 9, 7, 80, 9, 7, 81, 9, 9, 81,
450 const int bandchecks =
sizeof(tab) / (3 *
sizeof(
short));
451 for (
int i = 0; i < bandchecks; ++i) {
453 if (!( LatitudeBand(lat) == tab[3*i+0] ))
GeographicLib::Math::real real
Header for GeographicLib::Utility class.
Header for GeographicLib::MGRS class.
static void Forward(real lat, real lon, int &zone, bool &northp, real &x, real &y, real &gamma, real &k, int setzone=STANDARD, bool mgrslimits=false)
Namespace for GeographicLib.
static std::string str(T x, int p=-1)
static void Reverse(int zone, bool northp, real x, real y, real &lat, real &lon, real &gamma, real &k, bool mgrslimits=false)
static void Reverse(const std::string &mgrs, int &zone, bool &northp, real &x, real &y, int &prec, bool centerp=true)
Exception handling for GeographicLib.
static int lookup(const std::string &s, char c)
static void Forward(int zone, bool northp, real x, real y, int prec, std::string &mgrs)