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) {
44 static const real angeps = ldexp(real(1), -(
Math::digits() - 7));
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");
83 ix = (
long long)(floor(xx)),
84 iy = (
long long)(floor(yy)),
85 m = (
long long)(mult_) * (
long long)(tile_);
86 int xh = int(ix / m), yh = int(iy / m);
90 iband = abs(lat) > angeps ? LatitudeBand(lat) : (northp ? 0 : -1),
91 icol = xh - minutmcol_,
92 irow = UTMRow(iband, icol, yh % utmrowperiod_);
93 if (irow != yh - (northp ? minutmNrow_ : maxutmSrow_))
95 +
" is inconsistent with UTM coordinates");
96 mgrs1[z++] = latband_[10 + iband];
97 mgrs1[z++] = utmcols_[zone1 % 3][icol];
98 mgrs1[z++] = utmrow_[(yh + (zone1 & 1 ? utmevenrowshift_ : 0))
101 bool eastp = xh >= upseasting_;
102 int iband = (northp ? 2 : 0) + (eastp ? 1 : 0);
103 mgrs1[z++] = upsband_[iband];
104 mgrs1[z++] = upscols_[iband][xh - (eastp ? upseasting_ :
105 (northp ? minupsNind_ :
107 mgrs1[z++] = upsrows_[northp][yh - (northp ? minupsNind_ : minupsSind_)];
110 ix -= m * xh; iy -= m * yh;
111 long long d = (
long long)(pow(real(base_), maxprec_ - prec));
113 for (
int c = prec; c--;) {
114 mgrs1[z + c ] = digits_[ix % base_]; ix /= base_;
115 mgrs1[z + c + prec] = digits_[iy % base_]; iy /= base_;
119 copy(mgrs1, mgrs1 + mlen, mgrs.begin());
123 int prec, std::string& mgrs) {
127 real ys = northp ? y : y - utmNshift_;
136 lat = real(0.9) * ys;
141 latp = real(0.901) * ys + (ys > 0 ? 1 : -1) * real(0.135),
144 late = real(0.902) * ys * (1 - real(1.85e-6) * ys * ys);
145 if (LatitudeBand(latp) == LatitudeBand(late))
154 Forward(zone, northp, x, y, lat, prec, mgrs);
158 int& zone,
bool& northp, real& x, real& y,
159 int& prec,
bool centerp) {
162 len = int(mgrs.length());
164 toupper(mgrs[0]) ==
'I' &&
165 toupper(mgrs[1]) ==
'N' &&
166 toupper(mgrs[2]) ==
'V') {
178 zone1 = 10 * zone1 + i;
185 + mgrs.substr(0, p));
189 int zonem1 = zone1 - 1;
190 const char* band = utmp ? latband_ : upsband_;
194 + (utmp ?
"UTM" :
"UPS") +
" set " + band);
195 bool northp1 = iband >= (utmp ? 10 : 2);
198 real deg = real(utmNshift_) / (90 * tile_);
203 x = ((zone == 31 && iband == 17) ? 4 : 5) * tile_;
205 y = floor(8 * (iband - real(9.5)) * deg + real(0.5)) * tile_
206 + (northp ? 0 : utmNshift_);
209 x = ((iband & 1 ? 1 : -1) * floor(4 * deg + real(0.5))
210 + upseasting_) * tile_;
212 y = upseasting_ * tile_;
216 }
else if (len - p < 2)
218 const char* col = utmp ? utmcols_[zonem1 % 3] : upscols_[iband];
219 const char* row = utmp ? utmrow_ : upsrows_[northp1];
224 + (utmp ?
"zone " + mgrs.substr(0, p-2) :
235 irow = (irow + utmrowperiod_ - utmevenrowshift_) % utmrowperiod_;
237 irow = UTMRow(iband, icol, irow);
238 if (irow == maxutmSrow_)
240 +
" not in zone/band " + mgrs.substr(0, p-2));
242 irow = northp1 ? irow : irow + 100;
243 icol = icol + minutmcol_;
245 bool eastp = iband & 1;
246 icol += eastp ? upseasting_ : (northp1 ? minupsNind_ : minupsSind_);
247 irow += northp1 ? minupsNind_ : minupsSind_;
249 int prec1 = (len - p)/2;
254 for (
int i = 0; i < prec1; ++i) {
259 if (ix < 0 || iy < 0)
260 throw GeographicErr(
"Encountered a non-digit in " + mgrs.substr(p));
261 x1 = base_ * x1 + ix;
262 y1 = base_ * y1 + iy;
266 throw GeographicErr(
"Encountered a non-digit in " + mgrs.substr(p));
271 if (prec1 > maxprec_)
273 +
" digits in " + mgrs.substr(p));
275 unit *= 2; x1 = 2 * x1 + 1; y1 = 2 * y1 + 1;
279 x = (tile_ * x1) / unit;
280 y = (tile_ * y1) / unit;
284 void MGRS::CheckCoords(
bool utmp,
bool& northp,
real& x,
real& y) {
296 ix = int(floor(x / tile_)),
297 iy = int(floor(y / tile_)),
298 ind = (utmp ? 2 : 0) + (northp ? 1 : 0);
299 if (! (ix >= mineasting_[ind] && ix < maxeasting_[ind]) ) {
300 if (ix == maxeasting_[ind] && x == maxeasting_[ind] * tile_)
305 + (utmp ?
"UTM" :
"UPS") +
" range for "
306 + (northp ?
"N" :
"S" ) +
" hemisphere ["
312 if (! (iy >= minnorthing_[ind] && iy < maxnorthing_[ind]) ) {
313 if (iy == maxnorthing_[ind] && y == maxnorthing_[ind] * tile_)
316 throw GeographicErr(
"Northing " +
Utility::str(
int(floor(y/1000)))
318 + (utmp ?
"UTM" :
"UPS") +
" range for "
319 + (northp ?
"N" :
"S" ) +
" hemisphere ["
328 if (northp && iy < minutmNrow_) {
331 }
else if (!northp && iy >= maxutmSrow_) {
332 if (y == maxutmSrow_ * tile_)
343 int MGRS::UTMRow(
int iband,
int icol,
int irow) {
352 real c = 100 * (8 * iband + 4)/
real(90);
353 bool northp = iband >= 0;
377 minrow = iband > -10 ?
378 int(floor(c -
real(4.3) -
real(0.1) * northp)) : -90,
380 int(floor(c +
real(4.4) -
real(0.1) * northp)) : 94,
381 baserow = (minrow + maxrow) / 2 - utmrowperiod_ / 2;
385 irow = (irow - baserow + maxutmSrow_) % utmrowperiod_ + baserow;
386 if (!( irow >= minrow && irow <= maxrow )) {
395 sband = iband >= 0 ? iband : -iband - 1,
397 srow = irow >= 0 ? irow : -irow - 1,
399 scol = icol < 4 ? icol : -icol + 7;
402 if ( ! ( (srow == 70 && sband == 8 && scol >= 2) ||
403 (srow == 71 && sband == 7 && scol <= 2) ||
404 (srow == 79 && sband == 9 && scol >= 1) ||
405 (srow == 80 && sband == 8 && scol <= 1) ) )
412 real lat, lon, x, y, t = tile_;
int zone;
bool northp;
415 throw GeographicErr(
"MGRS::Check: equator coverage failure");
418 throw GeographicErr(
"MGRS::Check: UTM doesn't reach latitude = 84");
421 throw GeographicErr(
"MGRS::Check: UTM doesn't reach latitude = -80");
424 throw GeographicErr(
"MGRS::Check: Norway exception creates a gap");
427 throw GeographicErr(
"MGRS::Check: Svalbard exception creates a gap");
431 GeographicErr(
"MGRS::Check: North UPS doesn't reach latitude = 84");
435 GeographicErr(
"MGRS::Check: South UPS doesn't reach latitude = -80");
438 const short tab[] = {
454 7, 5, 70, 7, 7, 70, 7, 7, 71, 7, 9, 71,
455 8, 5, 71, 8, 6, 71, 8, 6, 72, 8, 9, 72,
456 8, 5, 79, 8, 8, 79, 8, 8, 80, 8, 9, 80,
457 9, 5, 80, 9, 7, 80, 9, 7, 81, 9, 9, 81,
460 const int bandchecks =
sizeof(tab) / (3 *
sizeof(
short));
461 for (
int i = 0; i < bandchecks; ++i) {
463 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 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.