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";
28 const int MGRS::mineasting_[] =
29 { minupsSind_, minupsNind_, minutmcol_, minutmcol_ };
30 const int MGRS::maxeasting_[] =
31 { maxupsSind_, maxupsNind_, maxutmcol_, maxutmcol_ };
32 const int MGRS::minnorthing_[] =
33 { minupsSind_, minupsNind_,
34 minutmSrow_, minutmSrow_ - (maxutmSrow_ - minutmNrow_) };
35 const int MGRS::maxnorthing_[] =
36 { maxupsSind_, maxupsNind_,
37 maxutmNrow_ + (maxutmSrow_ - minutmNrow_), maxutmNrow_ };
40 int prec, std::string& mgrs) {
46 isnan(x) || isnan(y) || isnan(lat)) {
50 bool utmp = zone != 0;
51 CheckCoords(utmp, northp, x, y);
54 if (!(prec >= -1 && prec <= maxprec_))
60 char mgrs1[2 + 3 + 2 * maxprec_];
64 mlen = z + 3 + 2 * prec;
66 mgrs1[0] = digits_[ zone / base_ ];
67 mgrs1[1] = digits_[ zone % base_ ];
73 static_assert(numeric_limits<long long>::digits >= 44,
74 "long long not wide enough to store 10e12");
76 ix = (
long long)(floor(x * mult_)),
77 iy = (
long long)(floor(y * mult_)),
78 m = (
long long)(mult_) * (
long long)(tile_);
79 int xh = int(ix / m), yh = int(iy / m);
83 iband = abs(lat) > angeps ? LatitudeBand(lat) : (northp ? 0 : -1),
84 icol = xh - minutmcol_,
85 irow = UTMRow(iband, icol, yh % utmrowperiod_);
86 if (irow != yh - (northp ? minutmNrow_ : maxutmSrow_))
88 +
" is inconsistent with UTM coordinates");
89 mgrs1[z++] = latband_[10 + iband];
90 mgrs1[z++] = utmcols_[zone1 % 3][icol];
91 mgrs1[z++] = utmrow_[(yh + (zone1 & 1 ? utmevenrowshift_ : 0))
94 bool eastp = xh >= upseasting_;
95 int iband = (northp ? 2 : 0) + (eastp ? 1 : 0);
96 mgrs1[z++] = upsband_[iband];
97 mgrs1[z++] = upscols_[iband][xh - (eastp ? upseasting_ :
98 (northp ? minupsNind_ :
100 mgrs1[z++] = upsrows_[northp][yh - (northp ? minupsNind_ : minupsSind_)];
103 ix -= m * xh; iy -= m * yh;
104 long long d = (
long long)(pow(
real(base_), maxprec_ - prec));
106 for (
int c = prec; c--;) {
107 mgrs1[z + c ] = digits_[ix % base_]; ix /= base_;
108 mgrs1[z + c + prec] = digits_[iy % base_]; iy /= base_;
112 copy(mgrs1, mgrs1 + mlen, mgrs.begin());
116 int prec, std::string& mgrs) {
120 real ys = northp ? y : y - utmNshift_;
129 lat =
real(0.9) * ys;
134 latp =
real(0.901) * ys + (ys > 0 ? 1 : -1) *
real(0.135),
137 late =
real(0.902) * ys * (1 -
real(1.85e-6) * ys * ys);
138 if (LatitudeBand(latp) == LatitudeBand(late))
147 Forward(zone, northp, x, y, lat, prec, mgrs);
151 int& zone,
bool& northp, real& x, real& y,
152 int& prec,
bool centerp) {
155 len = int(mgrs.length());
157 toupper(mgrs[0]) ==
'I' &&
158 toupper(mgrs[1]) ==
'N' &&
159 toupper(mgrs[2]) ==
'V') {
171 zone1 = 10 * zone1 + i;
178 + mgrs.substr(0, p));
182 int zonem1 = zone1 - 1;
183 const char* band = utmp ? latband_ : upsband_;
187 + (utmp ?
"UTM" :
"UPS") +
" set " + band);
188 bool northp1 = iband >= (utmp ? 10 : 2);
191 real deg =
real(utmNshift_) / (90 * tile_);
196 x = ((zone == 31 && iband == 17) ? 4 : 5) * tile_;
198 y = floor(8 * (iband -
real(9.5)) * deg +
real(0.5)) * tile_
199 + (northp ? 0 : utmNshift_);
202 x = ((iband & 1 ? 1 : -1) * floor(4 * deg +
real(0.5))
203 + upseasting_) * tile_;
205 y = upseasting_ * tile_;
209 }
else if (len - p < 2)
211 const char* col = utmp ? utmcols_[zonem1 % 3] : upscols_[iband];
212 const char* row = utmp ? utmrow_ : upsrows_[northp1];
217 + (utmp ?
"zone " + mgrs.substr(0, p-2) :
228 irow = (irow + utmrowperiod_ - utmevenrowshift_) % utmrowperiod_;
230 irow = UTMRow(iband, icol, irow);
231 if (irow == maxutmSrow_)
233 +
" not in zone/band " + mgrs.substr(0, p-2));
235 irow = northp1 ? irow : irow + 100;
236 icol = icol + minutmcol_;
238 bool eastp = iband & 1;
239 icol += eastp ? upseasting_ : (northp1 ? minupsNind_ : minupsSind_);
240 irow += northp1 ? minupsNind_ : minupsSind_;
242 int prec1 = (len - p)/2;
247 for (
int i = 0; i < prec1; ++i) {
252 if (ix < 0 || iy < 0)
253 throw GeographicErr(
"Encountered a non-digit in " + mgrs.substr(p));
254 x1 = base_ * x1 + ix;
255 y1 = base_ * y1 + iy;
259 throw GeographicErr(
"Encountered a non-digit in " + mgrs.substr(p));
264 if (prec1 > maxprec_)
266 +
" digits in " + mgrs.substr(p));
268 unit *= 2; x1 = 2 * x1 + 1; y1 = 2 * y1 + 1;
272 x = (tile_ * x1) / unit;
273 y = (tile_ * y1) / unit;
277 void MGRS::CheckCoords(
bool utmp,
bool& northp,
real& x,
real& y) {
289 ix = int(floor(x / tile_)),
290 iy = int(floor(y / tile_)),
291 ind = (utmp ? 2 : 0) + (northp ? 1 : 0);
292 if (! (ix >= mineasting_[ind] && ix < maxeasting_[ind]) ) {
293 if (ix == maxeasting_[ind] && x == maxeasting_[ind] * tile_)
298 + (utmp ?
"UTM" :
"UPS") +
" range for "
299 + (northp ?
"N" :
"S" ) +
" hemisphere ["
305 if (! (iy >= minnorthing_[ind] && iy < maxnorthing_[ind]) ) {
306 if (iy == maxnorthing_[ind] && y == maxnorthing_[ind] * tile_)
309 throw GeographicErr(
"Northing " +
Utility::str(
int(floor(y/1000)))
311 + (utmp ?
"UTM" :
"UPS") +
" range for "
312 + (northp ?
"N" :
"S" ) +
" hemisphere ["
321 if (northp && iy < minutmNrow_) {
324 }
else if (!northp && iy >= maxutmSrow_) {
325 if (y == maxutmSrow_ * tile_)
336 int MGRS::UTMRow(
int iband,
int icol,
int irow) {
345 real c = 100 * (8 * iband + 4)/
real(90);
346 bool northp = iband >= 0;
370 minrow = iband > -10 ?
371 int(floor(c -
real(4.3) -
real(0.1) * northp)) : -90,
373 int(floor(c +
real(4.4) -
real(0.1) * northp)) : 94,
374 baserow = (minrow + maxrow) / 2 - utmrowperiod_ / 2;
378 irow = (irow - baserow + maxutmSrow_) % utmrowperiod_ + baserow;
379 if (!( irow >= minrow && irow <= maxrow )) {
388 sband = iband >= 0 ? iband : -iband - 1,
390 srow = irow >= 0 ? irow : -irow - 1,
392 scol = icol < 4 ? icol : -icol + 7;
395 if ( ! ( (srow == 70 && sband == 8 && scol >= 2) ||
396 (srow == 71 && sband == 7 && scol <= 2) ||
397 (srow == 79 && sband == 9 && scol >= 1) ||
398 (srow == 80 && sband == 8 && scol <= 1) ) )
405 real lat, lon, x, y, t = tile_;
int zone;
bool northp;
408 throw GeographicErr(
"MGRS::Check: equator coverage failure");
411 throw GeographicErr(
"MGRS::Check: UTM doesn't reach latitude = 84");
414 throw GeographicErr(
"MGRS::Check: UTM doesn't reach latitude = -80");
417 throw GeographicErr(
"MGRS::Check: Norway exception creates a gap");
420 throw GeographicErr(
"MGRS::Check: Svalbard exception creates a gap");
424 GeographicErr(
"MGRS::Check: North UPS doesn't reach latitude = 84");
428 GeographicErr(
"MGRS::Check: South UPS doesn't reach latitude = -80");
431 const short tab[] = {
447 7, 5, 70, 7, 7, 70, 7, 7, 71, 7, 9, 71,
448 8, 5, 71, 8, 6, 71, 8, 6, 72, 8, 9, 72,
449 8, 5, 79, 8, 8, 79, 8, 8, 80, 8, 9, 80,
450 9, 5, 80, 9, 7, 80, 9, 7, 81, 9, 9, 81,
453 const int bandchecks =
sizeof(tab) / (3 *
sizeof(
short));
454 for (
int i = 0; i < bandchecks; ++i) {
456 if (!( LatitudeBand(lat) == tab[3*i+0] ))
GeographicLib::Math::real real
Header for GeographicLib::MGRS class.
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 Forward(int zone, bool northp, real x, real y, int prec, std::string &mgrs)
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.