15# pragma warning (disable: 5055 5054)
22 const char*
const MGRS::hemispheres_ =
"SN";
23 const char*
const MGRS::utmcols_[] = {
"ABCDEFGH",
"JKLMNPQR",
"STUVWXYZ" };
24 const char*
const MGRS::utmrow_ =
"ABCDEFGHJKLMNPQRSTUV";
25 const char*
const MGRS::upscols_[] =
26 {
"JKLPQRSTUXYZ",
"ABCFGHJKLPQR",
"RSTUXYZ",
"ABCFGHJ" };
27 const char*
const MGRS::upsrows_[] =
28 {
"ABCDEFGHJKLMNPQRSTUVWXYZ",
"ABCDEFGHJKLMNP" };
29 const char*
const MGRS::latband_ =
"CDEFGHJKLMNPQRSTUVWX";
30 const char*
const MGRS::upsband_ =
"ABYZ";
31 const char*
const MGRS::digits_ =
"0123456789";
32 const char*
const MGRS::alpha_ =
33 "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjklmnpqrstuvwxyz";
35 const int MGRS::mineasting_[] =
36 { minupsSind_, minupsNind_, minutmcol_, minutmcol_ };
37 const int MGRS::maxeasting_[] =
38 { maxupsSind_, maxupsNind_, maxutmcol_, maxutmcol_ };
39 const int MGRS::minnorthing_[] =
40 { minupsSind_, minupsNind_,
41 minutmSrow_, minutmSrow_ - (maxutmSrow_ - minutmNrow_) };
42 const int MGRS::maxnorthing_[] =
43 { maxupsSind_, maxupsNind_,
44 maxutmNrow_ + (maxutmSrow_ - minutmNrow_), maxutmNrow_ };
47 int prec, std::string& mgrs) {
51 static const real angeps = ldexp(real(1), -(
Math::digits() - 7));
53 isnan(x) || isnan(y) || isnan(lat)) {
57 bool utmp = zone != 0;
58 CheckCoords(utmp, northp, x, y);
61 if (!(prec >= -1 && prec <= maxprec_))
67 char mgrs1[2 + 3 + 2 * maxprec_];
71 mlen = z + 3 + 2 * prec;
73 mgrs1[0] = digits_[ zone / base_ ];
74 mgrs1[1] = digits_[ zone % base_ ];
80 static_assert(numeric_limits<long long>::digits >= 44,
81 "long long not wide enough to store 10e12");
90 ix = (
long long)(floor(xx)),
91 iy = (
long long)(floor(yy)),
92 m = (
long long)(mult_) * (
long long)(tile_);
93 int xh = int(ix / m), yh = int(iy / m);
97 iband = fabs(lat) < angeps ? (northp ? 0 : -1) : LatitudeBand(lat),
98 icol = xh - minutmcol_,
99 irow = UTMRow(iband, icol, yh % utmrowperiod_);
100 if (irow != yh - (northp ? minutmNrow_ : maxutmSrow_))
102 +
" is inconsistent with UTM coordinates");
103 mgrs1[z++] = latband_[10 + iband];
104 mgrs1[z++] = utmcols_[zone1 % 3][icol];
105 mgrs1[z++] = utmrow_[(yh + (zone1 & 1 ? utmevenrowshift_ : 0))
108 bool eastp = xh >= upseasting_;
109 int iband = (northp ? 2 : 0) + (eastp ? 1 : 0);
110 mgrs1[z++] = upsband_[iband];
111 mgrs1[z++] = upscols_[iband][xh - (eastp ? upseasting_ :
112 (northp ? minupsNind_ :
114 mgrs1[z++] = upsrows_[northp][yh - (northp ? minupsNind_ : minupsSind_)];
117 ix -= m * xh; iy -= m * yh;
118 long long d = (
long long)(pow(real(base_), maxprec_ - prec));
120 for (
int c = prec; c--;) {
121 mgrs1[z + c ] = digits_[ix % base_]; ix /= base_;
122 mgrs1[z + c + prec] = digits_[iy % base_]; iy /= base_;
126 copy(mgrs1, mgrs1 + mlen, mgrs.begin());
130 int prec, std::string& mgrs) {
134 real ys = northp ? y : y - utmNshift_;
143 lat = real(0.9) * ys;
148 latp = real(0.901) * ys + (ys > 0 ? 1 : -1) * real(0.135),
151 late = real(0.902) * ys * (1 - real(1.85e-6) * ys * ys);
152 if (LatitudeBand(latp) == LatitudeBand(late))
161 Forward(zone, northp, x, y, lat, prec, mgrs);
165 int& zone,
bool& northp, real& x, real& y,
166 int& prec,
bool centerp) {
169 len = int(mgrs.length());
171 toupper(mgrs[0]) ==
'I' &&
172 toupper(mgrs[1]) ==
'N' &&
173 toupper(mgrs[2]) ==
'V') {
185 zone1 = 10 * zone1 + i;
192 + mgrs.substr(0, p));
196 int zonem1 = zone1 - 1;
197 const char* band = utmp ? latband_ : upsband_;
201 + (utmp ?
"UTM" :
"UPS") +
" set " + band);
202 bool northp1 = iband >= (utmp ? 10 : 2);
205 real deg = real(utmNshift_) / (
Math::qd * tile_);
210 x = ((zone == 31 && iband == 17) ? 4 : 5) * tile_;
212 y = floor(8 * (iband - real(9.5)) * deg + real(0.5)) * tile_
213 + (northp ? 0 : utmNshift_);
216 x = ((iband & 1 ? 1 : -1) * floor(4 * deg + real(0.5))
217 + upseasting_) * tile_;
219 y = upseasting_ * tile_;
223 }
else if (len - p < 2)
225 const char* col = utmp ? utmcols_[zonem1 % 3] : upscols_[iband];
226 const char* row = utmp ? utmrow_ : upsrows_[northp1];
231 + (utmp ?
"zone " + mgrs.substr(0, p-2) :
242 irow = (irow + utmrowperiod_ - utmevenrowshift_) % utmrowperiod_;
244 irow = UTMRow(iband, icol, irow);
245 if (irow == maxutmSrow_)
247 +
" not in zone/band " + mgrs.substr(0, p-2));
249 irow = northp1 ? irow : irow + 100;
250 icol = icol + minutmcol_;
252 bool eastp = iband & 1;
253 icol += eastp ? upseasting_ : (northp1 ? minupsNind_ : minupsSind_);
254 irow += northp1 ? minupsNind_ : minupsSind_;
256 int prec1 = (len - p)/2;
261 for (
int i = 0; i < prec1; ++i) {
266 if (ix < 0 || iy < 0)
267 throw GeographicErr(
"Encountered a non-digit in " + mgrs.substr(p));
268 x1 = base_ * x1 + ix;
269 y1 = base_ * y1 + iy;
273 throw GeographicErr(
"Encountered a non-digit in " + mgrs.substr(p));
278 if (prec1 > maxprec_)
280 +
" digits in " + mgrs.substr(p));
282 unit *= 2; x1 = 2 * x1 + 1; y1 = 2 * y1 + 1;
286 x = (tile_ * x1) / unit;
287 y = (tile_ * y1) / unit;
291 void MGRS::CheckCoords(
bool utmp,
bool& northp,
real& x,
real& y) {
303 ix = int(floor(x / tile_)),
304 iy = int(floor(y / tile_)),
305 ind = (utmp ? 2 : 0) + (northp ? 1 : 0);
306 if (! (ix >= mineasting_[ind] && ix < maxeasting_[ind]) ) {
307 if (ix == maxeasting_[ind] && x == maxeasting_[ind] * tile_)
312 + (utmp ?
"UTM" :
"UPS") +
" range for "
313 + (northp ?
"N" :
"S" ) +
" hemisphere ["
319 if (! (iy >= minnorthing_[ind] && iy < maxnorthing_[ind]) ) {
320 if (iy == maxnorthing_[ind] && y == maxnorthing_[ind] * tile_)
323 throw GeographicErr(
"Northing " +
Utility::str(
int(floor(y/1000)))
325 + (utmp ?
"UTM" :
"UPS") +
" range for "
326 + (northp ?
"N" :
"S" ) +
" hemisphere ["
335 if (northp && iy < minutmNrow_) {
338 }
else if (!northp && iy >= maxutmSrow_) {
339 if (y == maxutmSrow_ * tile_)
350 int MGRS::UTMRow(
int iband,
int icol,
int irow) {
360 bool northp = iband >= 0;
384 minrow = iband > -10 ?
385 int(floor(c -
real(4.3) -
real(0.1) * northp)) : -90,
387 int(floor(c +
real(4.4) -
real(0.1) * northp)) : 94,
388 baserow = (minrow + maxrow) / 2 - utmrowperiod_ / 2;
392 irow = (irow - baserow + maxutmSrow_) % utmrowperiod_ + baserow;
393 if (!( irow >= minrow && irow <= maxrow )) {
402 sband = iband >= 0 ? iband : -iband - 1,
404 srow = irow >= 0 ? irow : -irow - 1,
406 scol = icol < 4 ? icol : -icol + 7;
409 if ( ! ( (srow == 70 && sband == 8 && scol >= 2) ||
410 (srow == 71 && sband == 7 && scol <= 2) ||
411 (srow == 79 && sband == 9 && scol >= 1) ||
412 (srow == 80 && sband == 8 && scol <= 1) ) )
419 string& gridzone,
string& block,
420 string& easting,
string& northing) {
421 string::size_type n = mgrs.length();
423 toupper(mgrs[0]) ==
'I' &&
424 toupper(mgrs[1]) ==
'N' &&
425 toupper(mgrs[2]) ==
'V') {
426 gridzone = mgrs.substr(0, 3);
427 block = easting = northing =
"";
430 string::size_type p0 = mgrs.find_first_not_of(digits_);
431 if (p0 == string::npos)
432 throw GeographicErr(
"MGRS::Decode: ref does not contain alpha chars");
434 throw GeographicErr(
"MGRS::Decode: ref does not start with 0-2 digits");
435 string::size_type p1 = mgrs.find_first_of(alpha_, p0);
437 throw GeographicErr(
"MGRS::Decode: ref contains non alphanumeric chars");
438 p1 = min(mgrs.find_first_not_of(alpha_, p0), n);
439 if (!(p1 == p0 + 1 || p1 == p0 + 3))
440 throw GeographicErr(
"MGRS::Decode: ref must contain 1 or 3 alpha chars");
441 if (p1 == p0 + 1 && p1 < n)
442 throw GeographicErr(
"MGRS::Decode: ref contains junk after 1 alpha char");
443 if (p1 < n && (mgrs.find_first_of(digits_, p1) != p1 ||
444 mgrs.find_first_not_of(digits_, p1) != string::npos))
445 throw GeographicErr(
"MGRS::Decode: ref contains junk at end");
447 throw GeographicErr(
"MGRS::Decode: ref must end with even no of digits");
449 gridzone = mgrs.substr(0, p0+1);
450 block = mgrs.substr(p0+1, p1 - (p0 + 1));
451 easting = mgrs.substr(p1, (n - p1) / 2);
452 northing = mgrs.substr(p1 + (n - p1) / 2);
456 real lat, lon, x, y, t = tile_;
int zone;
bool northp;
459 throw GeographicErr(
"MGRS::Check: equator coverage failure");
462 throw GeographicErr(
"MGRS::Check: UTM doesn't reach latitude = 84");
465 throw GeographicErr(
"MGRS::Check: UTM doesn't reach latitude = -80");
468 throw GeographicErr(
"MGRS::Check: Norway exception creates a gap");
471 throw GeographicErr(
"MGRS::Check: Svalbard exception creates a gap");
475 GeographicErr(
"MGRS::Check: North UPS doesn't reach latitude = 84");
479 GeographicErr(
"MGRS::Check: South UPS doesn't reach latitude = -80");
482 const short tab[] = {
498 7, 5, 70, 7, 7, 70, 7, 7, 71, 7, 9, 71,
499 8, 5, 71, 8, 6, 71, 8, 6, 72, 8, 9, 72,
500 8, 5, 79, 8, 8, 79, 8, 8, 80, 8, 9, 80,
501 9, 5, 80, 9, 7, 80, 9, 7, 81, 9, 9, 81,
504 const int bandchecks =
sizeof(tab) / (3 *
sizeof(
short));
505 for (
int i = 0; i < bandchecks; ++i) {
507 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)
@ 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.