17 const char*
const MGRS::hemispheres_ =
"SN";
18 const char*
const MGRS::utmcols_[] = {
"ABCDEFGH",
"JKLMNPQR",
"STUVWXYZ" };
19 const char*
const MGRS::utmrow_ =
"ABCDEFGHJKLMNPQRSTUV";
20 const char*
const MGRS::upscols_[] =
21 {
"JKLPQRSTUXYZ",
"ABCFGHJKLPQR",
"RSTUXYZ",
"ABCFGHJ" };
22 const char*
const MGRS::upsrows_[] =
23 {
"ABCDEFGHJKLMNPQRSTUVWXYZ",
"ABCDEFGHJKLMNP" };
24 const char*
const MGRS::latband_ =
"CDEFGHJKLMNPQRSTUVWX";
25 const char*
const MGRS::upsband_ =
"ABYZ";
26 const char*
const MGRS::digits_ =
"0123456789";
27 const char*
const MGRS::alpha_ =
28 "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjklmnpqrstuvwxyz";
30 const int MGRS::mineasting_[] =
31 { minupsSind_, minupsNind_, minutmcol_, minutmcol_ };
32 const int MGRS::maxeasting_[] =
33 { maxupsSind_, maxupsNind_, maxutmcol_, maxutmcol_ };
34 const int MGRS::minnorthing_[] =
35 { minupsSind_, minupsNind_,
36 minutmSrow_, minutmSrow_ - (maxutmSrow_ - minutmNrow_) };
37 const int MGRS::maxnorthing_[] =
38 { maxupsSind_, maxupsNind_,
39 maxutmNrow_ + (maxutmSrow_ - minutmNrow_), maxutmNrow_ };
42 int prec, std::string& mgrs) {
47 isnan(x) || isnan(y) || isnan(lat)) {
51 bool utmp = zone != 0;
52 CheckCoords(utmp, northp, x, y);
55 if (!(prec >= -1 && prec <= maxprec_))
61 char mgrs1[2 + 3 + 2 * maxprec_];
65 mlen = z + 3 + 2 * prec;
67 mgrs1[0] = digits_[ zone / base_ ];
68 mgrs1[1] = digits_[ zone % base_ ];
74 static_assert(numeric_limits<long long>::digits >= 44,
75 "long long not wide enough to store 10e12");
84 ix = (
long long)(floor(xx)),
85 iy = (
long long)(floor(yy)),
86 m = (
long long)(mult_) * (
long long)(tile_);
87 int xh = int(ix / m), yh = int(iy / m);
91 iband = fabs(lat) < angeps ? (northp ? 0 : -1) : LatitudeBand(lat),
92 icol = xh - minutmcol_,
93 irow = UTMRow(iband, icol, yh % utmrowperiod_);
94 if (irow != yh - (northp ? minutmNrow_ : maxutmSrow_))
96 +
" is inconsistent with UTM coordinates");
97 mgrs1[z++] = latband_[10 + iband];
98 mgrs1[z++] = utmcols_[zone1 % 3][icol];
99 mgrs1[z++] = utmrow_[(yh + (zone1 & 1 ? utmevenrowshift_ : 0))
102 bool eastp = xh >= upseasting_;
103 int iband = (northp ? 2 : 0) + (eastp ? 1 : 0);
104 mgrs1[z++] = upsband_[iband];
105 mgrs1[z++] = upscols_[iband][xh - (eastp ? upseasting_ :
106 (northp ? minupsNind_ :
108 mgrs1[z++] = upsrows_[northp][yh - (northp ? minupsNind_ : minupsSind_)];
111 ix -= m * xh; iy -= m * yh;
112 long long d = (
long long)(pow(
real(base_), maxprec_ - prec));
114 for (
int c = prec; c--;) {
115 mgrs1[z + c ] = digits_[ix % base_]; ix /= base_;
116 mgrs1[z + c + prec] = digits_[iy % base_]; iy /= base_;
120 copy(mgrs1, mgrs1 + mlen, mgrs.begin());
124 int prec, std::string& mgrs) {
128 real ys = northp ? y : y - utmNshift_;
137 lat =
real(0.9) * ys;
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.length());
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 char* band = utmp ? latband_ : upsband_;
195 + (utmp ?
"UTM" :
"UPS") +
" set " + band);
196 bool northp1 = iband >= (utmp ? 10 : 2);
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 char* col = utmp ? utmcols_[zonem1 % 3] : upscols_[iband];
220 const char* 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));
262 x1 = base_ * x1 + ix;
263 y1 = base_ * y1 + iy;
267 throw GeographicErr(
"Encountered a non-digit in " + mgrs.substr(p));
272 if (prec1 > maxprec_)
274 +
" digits in " + mgrs.substr(p));
276 unit *= 2; x1 = 2 * x1 + 1; y1 = 2 * y1 + 1;
280 x = (tile_ * x1) / unit;
281 y = (tile_ * y1) / unit;
285 void MGRS::CheckCoords(
bool utmp,
bool& northp,
real& x,
real& y) {
297 ix = int(floor(x / tile_)),
298 iy = int(floor(y / tile_)),
299 ind = (utmp ? 2 : 0) + (northp ? 1 : 0);
300 if (! (ix >= mineasting_[ind] && ix < maxeasting_[ind]) ) {
301 if (ix == maxeasting_[ind] && x == maxeasting_[ind] * tile_)
306 + (utmp ?
"UTM" :
"UPS") +
" range for "
307 + (northp ?
"N" :
"S" ) +
" hemisphere ["
313 if (! (iy >= minnorthing_[ind] && iy < maxnorthing_[ind]) ) {
314 if (iy == maxnorthing_[ind] && y == maxnorthing_[ind] * tile_)
317 throw GeographicErr(
"Northing " +
Utility::str(
int(floor(y/1000)))
319 + (utmp ?
"UTM" :
"UPS") +
" range for "
320 + (northp ?
"N" :
"S" ) +
" hemisphere ["
329 if (northp && iy < minutmNrow_) {
332 }
else if (!northp && iy >= maxutmSrow_) {
333 if (y == maxutmSrow_ * tile_)
344 int MGRS::UTMRow(
int iband,
int icol,
int irow) {
354 bool northp = iband >= 0;
378 minrow = iband > -10 ?
379 int(floor(c -
real(4.3) -
real(0.1) * northp)) : -90,
381 int(floor(c + real(4.4) - real(0.1) * northp)) : 94,
382 baserow = (minrow + maxrow) / 2 - utmrowperiod_ / 2;
386 irow = (irow - baserow + maxutmSrow_) % utmrowperiod_ + baserow;
387 if (!( irow >= minrow && irow <= maxrow )) {
396 sband = iband >= 0 ? iband : -iband - 1,
398 srow = irow >= 0 ? irow : -irow - 1,
400 scol = icol < 4 ? icol : -icol + 7;
403 if ( ! ( (srow == 70 && sband == 8 && scol >= 2) ||
404 (srow == 71 && sband == 7 && scol <= 2) ||
405 (srow == 79 && sband == 9 && scol >= 1) ||
406 (srow == 80 && sband == 8 && scol <= 1) ) )
413 string& gridzone,
string& block,
414 string& easting,
string& northing) {
415 string::size_type n = mgrs.length();
417 toupper(mgrs[0]) ==
'I' &&
418 toupper(mgrs[1]) ==
'N' &&
419 toupper(mgrs[2]) ==
'V') {
420 gridzone = mgrs.substr(0, 3);
421 block = easting = northing =
"";
424 string::size_type p0 = mgrs.find_first_not_of(digits_);
425 if (p0 == string::npos)
426 throw GeographicErr(
"MGRS::Decode: ref does not contain alpha chars");
428 throw GeographicErr(
"MGRS::Decode: ref does not start with 0-2 digits");
429 string::size_type p1 = mgrs.find_first_of(alpha_, p0);
431 throw GeographicErr(
"MGRS::Decode: ref contains non alphanumeric chars");
432 p1 = min(mgrs.find_first_not_of(alpha_, p0), n);
433 if (!(p1 == p0 + 1 || p1 == p0 + 3))
434 throw GeographicErr(
"MGRS::Decode: ref must contain 1 or 3 alpha chars");
435 if (p1 == p0 + 1 && p1 < n)
436 throw GeographicErr(
"MGRS::Decode: ref contains junk after 1 alpha char");
437 if (p1 < n && (mgrs.find_first_of(digits_, p1) != p1 ||
438 mgrs.find_first_not_of(digits_, p1) != string::npos))
439 throw GeographicErr(
"MGRS::Decode: ref contains junk at end");
441 throw GeographicErr(
"MGRS::Decode: ref must end with even no of digits");
443 gridzone = mgrs.substr(0, p0+1);
444 block = mgrs.substr(p0+1, p1 - (p0 + 1));
445 easting = mgrs.substr(p1, (n - p1) / 2);
446 northing = mgrs.substr(p1 + (n - p1) / 2);
450 real lat, lon, x, y, t = tile_;
int zone;
bool northp;
453 throw GeographicErr(
"MGRS::Check: equator coverage failure");
456 throw GeographicErr(
"MGRS::Check: UTM doesn't reach latitude = 84");
459 throw GeographicErr(
"MGRS::Check: UTM doesn't reach latitude = -80");
462 throw GeographicErr(
"MGRS::Check: Norway exception creates a gap");
465 throw GeographicErr(
"MGRS::Check: Svalbard exception creates a gap");
469 GeographicErr(
"MGRS::Check: North UPS doesn't reach latitude = 84");
473 GeographicErr(
"MGRS::Check: South UPS doesn't reach latitude = -80");
476 const short tab[] = {
492 7, 5, 70, 7, 7, 70, 7, 7, 71, 7, 9, 71,
493 8, 5, 71, 8, 6, 71, 8, 6, 72, 8, 9, 72,
494 8, 5, 79, 8, 8, 79, 8, 8, 80, 8, 9, 80,
495 9, 5, 80, 9, 7, 80, 9, 7, 81, 9, 9, 81,
498 const int bandchecks =
sizeof(tab) / (3 *
sizeof(
short));
499 for (
int i = 0; i < bandchecks; ++i) {
501 if (!( LatitudeBand(lat) == tab[3*i+0] ))
GeographicLib::Math::real real
Header for GeographicLib::MGRS class.
#define GEOGRAPHICLIB_VOLATILE
Header for GeographicLib::Utility class.
Exception handling for GeographicLib.
static void Reverse(const std::string &mgrs, int &zone, bool &northp, real &x, real &y, int &prec, bool centerp=true)
static void Decode(const std::string &mgrs, std::string &gridzone, std::string &block, std::string &easting, std::string &northing)
static void Forward(int zone, bool northp, real x, real y, int prec, std::string &mgrs)
static constexpr int qd
degrees per quarter turn
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)
static void Reverse(int zone, bool northp, real x, real y, real &lat, real &lon, real &gamma, real &k, bool mgrslimits=false)
static int lookup(const std::string &s, char c)
static std::string str(T x, int p=-1)
Namespace for GeographicLib.