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";
33 const int MGRS::mineasting_[] =
34 { minupsSind_, minupsNind_, minutmcol_, minutmcol_ };
35 const int MGRS::maxeasting_[] =
36 { maxupsSind_, maxupsNind_, maxutmcol_, maxutmcol_ };
37 const int MGRS::minnorthing_[] =
38 { minupsSind_, minupsNind_,
39 minutmSrow_, minutmSrow_ - (maxutmSrow_ - minutmNrow_) };
40 const int MGRS::maxnorthing_[] =
41 { maxupsSind_, maxupsNind_,
42 maxutmNrow_ + (maxutmSrow_ - minutmNrow_), maxutmNrow_ };
45 int prec, std::string& mgrs) {
51 isnan(x) || isnan(y) || isnan(lat)) {
55 bool utmp = zone != 0;
56 CheckCoords(utmp, northp, x, y);
59 if (!(prec >= -1 && prec <= maxprec_))
65 char mgrs1[2 + 3 + 2 * maxprec_];
69 mlen = z + 3 + 2 * prec;
71 mgrs1[0] = digits_[ zone / base_ ];
72 mgrs1[1] = digits_[ zone % base_ ];
78 static_assert(numeric_limits<long long>::digits >= 44,
79 "long long not wide enough to store 10e12");
88 ix = (
long long)(floor(xx)),
89 iy = (
long long)(floor(yy)),
90 m = (
long long)(mult_) * (
long long)(tile_);
91 int xh = int(ix / m), yh = int(iy / m);
95 iband = fabs(lat) < angeps ? (northp ? 0 : -1) : LatitudeBand(lat),
96 icol = xh - minutmcol_,
97 irow = UTMRow(iband, icol, yh % utmrowperiod_);
98 if (irow != yh - (northp ? minutmNrow_ : maxutmSrow_))
100 +
" is inconsistent with UTM coordinates");
101 mgrs1[z++] = latband_[10 + iband];
102 mgrs1[z++] = utmcols_[zone1 % 3][icol];
103 mgrs1[z++] = utmrow_[(yh + (zone1 & 1 ? utmevenrowshift_ : 0))
106 bool eastp = xh >= upseasting_;
107 int iband = (northp ? 2 : 0) + (eastp ? 1 : 0);
108 mgrs1[z++] = upsband_[iband];
109 mgrs1[z++] = upscols_[iband][xh - (eastp ? upseasting_ :
110 (northp ? minupsNind_ :
112 mgrs1[z++] = upsrows_[northp][yh - (northp ? minupsNind_ : minupsSind_)];
115 ix -= m * xh; iy -= m * yh;
116 long long d = (
long long)(pow(
real(base_), maxprec_ - prec));
118 for (
int c = prec; c--;) {
119 mgrs1[z + c ] = digits_[ix % base_]; ix /= base_;
120 mgrs1[z + c + prec] = digits_[iy % base_]; iy /= base_;
124 copy(mgrs1, mgrs1 + mlen, mgrs.begin());
128 int prec, std::string& mgrs) {
132 real ys = northp ? y : y - utmNshift_;
141 lat =
real(0.9) * ys;
146 latp =
real(0.901) * ys + (ys > 0 ? 1 : -1) *
real(0.135),
149 late =
real(0.902) * ys * (1 -
real(1.85e-6) * ys * ys);
150 if (LatitudeBand(latp) == LatitudeBand(late))
159 Forward(zone, northp, x, y, lat, prec, mgrs);
163 int& zone,
bool& northp, real& x, real& y,
164 int& prec,
bool centerp) {
167 len = int(mgrs.length());
169 toupper(mgrs[0]) ==
'I' &&
170 toupper(mgrs[1]) ==
'N' &&
171 toupper(mgrs[2]) ==
'V') {
183 zone1 = 10 * zone1 + i;
190 + mgrs.substr(0, p));
194 int zonem1 = zone1 - 1;
195 const char* band = utmp ? latband_ : upsband_;
199 + (utmp ?
"UTM" :
"UPS") +
" set " + band);
200 bool northp1 = iband >= (utmp ? 10 : 2);
208 x = ((zone == 31 && iband == 17) ? 4 : 5) * tile_;
210 y = floor(8 * (iband -
real(9.5)) * deg +
real(0.5)) * tile_
211 + (northp ? 0 : utmNshift_);
214 x = ((iband & 1 ? 1 : -1) * floor(4 * deg +
real(0.5))
215 + upseasting_) * tile_;
217 y = upseasting_ * tile_;
221 }
else if (len - p < 2)
223 const char* col = utmp ? utmcols_[zonem1 % 3] : upscols_[iband];
224 const char* row = utmp ? utmrow_ : upsrows_[northp1];
229 + (utmp ?
"zone " + mgrs.substr(0, p-2) :
240 irow = (irow + utmrowperiod_ - utmevenrowshift_) % utmrowperiod_;
242 irow = UTMRow(iband, icol, irow);
243 if (irow == maxutmSrow_)
245 +
" not in zone/band " + mgrs.substr(0, p-2));
247 irow = northp1 ? irow : irow + 100;
248 icol = icol + minutmcol_;
250 bool eastp = iband & 1;
251 icol += eastp ? upseasting_ : (northp1 ? minupsNind_ : minupsSind_);
252 irow += northp1 ? minupsNind_ : minupsSind_;
254 int prec1 = (len - p)/2;
259 for (
int i = 0; i < prec1; ++i) {
264 if (ix < 0 || iy < 0)
265 throw GeographicErr(
"Encountered a non-digit in " + mgrs.substr(p));
266 x1 = base_ * x1 + ix;
267 y1 = base_ * y1 + iy;
271 throw GeographicErr(
"Encountered a non-digit in " + mgrs.substr(p));
276 if (prec1 > maxprec_)
278 +
" digits in " + mgrs.substr(p));
280 unit *= 2; x1 = 2 * x1 + 1; y1 = 2 * y1 + 1;
284 x = (tile_ * x1) / unit;
285 y = (tile_ * y1) / unit;
289 void MGRS::CheckCoords(
bool utmp,
bool& northp,
real& x,
real& y) {
301 ix = int(floor(x / tile_)),
302 iy = int(floor(y / tile_)),
303 ind = (utmp ? 2 : 0) + (northp ? 1 : 0);
304 if (! (ix >= mineasting_[ind] && ix < maxeasting_[ind]) ) {
305 if (ix == maxeasting_[ind] && x == maxeasting_[ind] * tile_)
310 + (utmp ?
"UTM" :
"UPS") +
" range for "
311 + (northp ?
"N" :
"S" ) +
" hemisphere ["
317 if (! (iy >= minnorthing_[ind] && iy < maxnorthing_[ind]) ) {
318 if (iy == maxnorthing_[ind] && y == maxnorthing_[ind] * tile_)
321 throw GeographicErr(
"Northing " +
Utility::str(
int(floor(y/1000)))
323 + (utmp ?
"UTM" :
"UPS") +
" range for "
324 + (northp ?
"N" :
"S" ) +
" hemisphere ["
333 if (northp && iy < minutmNrow_) {
336 }
else if (!northp && iy >= maxutmSrow_) {
337 if (y == maxutmSrow_ * tile_)
348 int MGRS::UTMRow(
int iband,
int icol,
int irow) {
358 bool northp = iband >= 0;
382 minrow = iband > -10 ?
383 int(floor(c -
real(4.3) -
real(0.1) * northp)) : -90,
385 int(floor(c +
real(4.4) -
real(0.1) * northp)) : 94,
386 baserow = (minrow + maxrow) / 2 - utmrowperiod_ / 2;
390 irow = (irow - baserow + maxutmSrow_) % utmrowperiod_ + baserow;
391 if (!( irow >= minrow && irow <= maxrow )) {
400 sband = iband >= 0 ? iband : -iband - 1,
402 srow = irow >= 0 ? irow : -irow - 1,
404 scol = icol < 4 ? icol : -icol + 7;
407 if ( ! ( (srow == 70 && sband == 8 && scol >= 2) ||
408 (srow == 71 && sband == 7 && scol <= 2) ||
409 (srow == 79 && sband == 9 && scol >= 1) ||
410 (srow == 80 && sband == 8 && scol <= 1) ) )
417 real lat, lon, x, y, t = tile_;
int zone;
bool northp;
420 throw GeographicErr(
"MGRS::Check: equator coverage failure");
423 throw GeographicErr(
"MGRS::Check: UTM doesn't reach latitude = 84");
426 throw GeographicErr(
"MGRS::Check: UTM doesn't reach latitude = -80");
429 throw GeographicErr(
"MGRS::Check: Norway exception creates a gap");
432 throw GeographicErr(
"MGRS::Check: Svalbard exception creates a gap");
436 GeographicErr(
"MGRS::Check: North UPS doesn't reach latitude = 84");
440 GeographicErr(
"MGRS::Check: South UPS doesn't reach latitude = -80");
443 const short tab[] = {
459 7, 5, 70, 7, 7, 70, 7, 7, 71, 7, 9, 71,
460 8, 5, 71, 8, 6, 71, 8, 6, 72, 8, 9, 72,
461 8, 5, 79, 8, 8, 79, 8, 8, 80, 8, 9, 80,
462 9, 5, 80, 9, 7, 80, 9, 7, 81, 9, 9, 81,
465 const int bandchecks =
sizeof(tab) / (3 *
sizeof(
short));
466 for (
int i = 0; i < bandchecks; ++i) {
468 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)
@ 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.