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) {
 
   46    static const real angeps = ldexp(real(1), -(
Math::digits() - 7));
 
   48        isnan(x) || isnan(y) || isnan(lat)) {
 
   52    bool utmp = zone != 0;
 
   53    CheckCoords(utmp, northp, x, y);
 
   56    if (!(prec >= -1 && prec <= maxprec_))
 
   62    char mgrs1[2 + 3 + 2 * maxprec_];
 
   66      mlen = z + 3 + 2 * prec;
 
   68      mgrs1[0] = digits_[ zone / base_ ];
 
   69      mgrs1[1] = digits_[ zone % base_ ];
 
   75    static_assert(numeric_limits<long long>::digits >= 44,
 
   76                  "long long not wide enough to store 10e12");
 
   85      ix = (
long long)(floor(xx)),
 
   86      iy = (
long long)(floor(yy)),
 
   87      m = (
long long)(mult_) * (
long long)(tile_);
 
   88    int xh = int(ix / m), yh = int(iy / m);
 
   92        iband = fabs(lat) < angeps ? (northp ? 0 : -1) : LatitudeBand(lat),
 
   93        icol = xh - minutmcol_,
 
   94        irow = UTMRow(iband, icol, yh % utmrowperiod_);
 
   95      if (irow != yh - (northp ? minutmNrow_ : maxutmSrow_))
 
   97                            + 
" is inconsistent with UTM coordinates");
 
   98      mgrs1[z++] = latband_[10 + iband];
 
   99      mgrs1[z++] = utmcols_[zone1 % 3][icol];
 
  100      mgrs1[z++] = utmrow_[(yh + (zone1 & 1 ? utmevenrowshift_ : 0))
 
  103      bool eastp = xh >= upseasting_;
 
  104      int iband = (northp ? 2 : 0) + (eastp ? 1 : 0);
 
  105      mgrs1[z++] = upsband_[iband];
 
  106      mgrs1[z++] = upscols_[iband][xh - (eastp ? upseasting_ :
 
  107                                         (northp ? minupsNind_ :
 
  109      mgrs1[z++] = upsrows_[northp][yh - (northp ? minupsNind_ : minupsSind_)];
 
  112      ix -= m * xh; iy -= m * yh;
 
  113      long long d = (
long long)(pow(real(base_), maxprec_ - prec));
 
  115      for (
int c = prec; c--;) {
 
  116        mgrs1[z + c       ] = digits_[ix % base_]; ix /= base_;
 
  117        mgrs1[z + c + prec] = digits_[iy % base_]; iy /= base_;
 
  121    copy(mgrs1, mgrs1 + mlen, mgrs.begin());
 
 
  125                     int prec, std::string& mgrs) {
 
  129      real ys = northp ? y : y - utmNshift_;
 
  138        lat = real(0.9) * ys;         
 
  143          latp = real(0.901) * ys + (ys > 0 ? 1 : -1) * real(0.135),
 
  146          late = real(0.902) * ys * (1 - real(1.85e-6) * ys * ys);
 
  147        if (LatitudeBand(latp) == LatitudeBand(late))
 
  156    Forward(zone, northp, x, y, lat, prec, mgrs);
 
 
  160                     int& zone, 
bool& northp, real& x, real& y,
 
  161                     int& prec, 
bool centerp) {
 
  164      len = int(mgrs.length());
 
  166        toupper(mgrs[0]) == 
'I' &&
 
  167        toupper(mgrs[1]) == 
'N' &&
 
  168        toupper(mgrs[2]) == 
'V') {
 
  180      zone1 = 10 * zone1 + i;
 
  187                          + mgrs.substr(0, p));
 
  191    int zonem1 = zone1 - 1;
 
  192    const char* band = utmp ? latband_ : upsband_;
 
  196                          + (utmp ? 
"UTM" : 
"UPS") + 
" set " + band);
 
  197    bool northp1 = iband >= (utmp ? 10 : 2);
 
  200      real deg = real(utmNshift_) / (
Math::qd * tile_);
 
  205        x = ((zone == 31 && iband == 17) ? 4 : 5) * tile_;
 
  207        y = floor(8 * (iband - real(9.5)) * deg + real(0.5)) * tile_
 
  208          + (northp ? 0 : utmNshift_);
 
  211        x = ((iband & 1 ? 1 : -1) * floor(4 * deg + real(0.5))
 
  212             + upseasting_) * tile_;
 
  214        y = upseasting_ * tile_;
 
  218    } 
else if (len - p < 2)
 
  220    const char* col = utmp ? utmcols_[zonem1 % 3] : upscols_[iband];
 
  221    const char* row = utmp ? utmrow_ : upsrows_[northp1];
 
  226                          + (utmp ? 
"zone " + mgrs.substr(0, p-2) :
 
  237        irow = (irow + utmrowperiod_ - utmevenrowshift_) % utmrowperiod_;
 
  239      irow = UTMRow(iband, icol, irow);
 
  240      if (irow == maxutmSrow_)
 
  242                            + 
" not in zone/band " + mgrs.substr(0, p-2));
 
  244      irow = northp1 ? irow : irow + 100;
 
  245      icol = icol + minutmcol_;
 
  247      bool eastp = iband & 1;
 
  248      icol += eastp ? upseasting_ : (northp1 ? minupsNind_ : minupsSind_);
 
  249      irow += northp1 ? minupsNind_ : minupsSind_;
 
  251    int prec1 = (len - p)/2;
 
  256    for (
int i = 0; i < prec1; ++i) {
 
  261      if (ix < 0 || iy < 0)
 
  262        throw GeographicErr(
"Encountered a non-digit in " + mgrs.substr(p));
 
  263      x1 = base_ * x1 + ix;
 
  264      y1 = base_ * y1 + iy;
 
  268        throw GeographicErr(
"Encountered a non-digit in " + mgrs.substr(p));
 
  273    if (prec1 > maxprec_)
 
  275                          + 
" digits in " + mgrs.substr(p));
 
  277      unit *= 2; x1 = 2 * x1 + 1; y1 = 2 * y1 + 1;
 
  281    x = (tile_ * x1) / unit;
 
  282    y = (tile_ * y1) / unit;
 
 
  286  void MGRS::CheckCoords(
bool utmp, 
bool& northp, 
real& x, 
real& y) {
 
  298      ix = int(floor(x / tile_)),
 
  299      iy = int(floor(y / tile_)),
 
  300      ind = (utmp ? 2 : 0) + (northp ? 1 : 0);
 
  301    if (! (ix >= mineasting_[ind] && ix < maxeasting_[ind]) ) {
 
  302      if (ix == maxeasting_[ind] && x == maxeasting_[ind] * tile_)
 
  307                            + (utmp ? 
"UTM" : 
"UPS") + 
" range for " 
  308                            + (northp ? 
"N" : 
"S" ) + 
" hemisphere [" 
  309                            + 
Utility::str(mineasting_[ind]*tile_/1000)
 
  311                            + 
Utility::str(maxeasting_[ind]*tile_/1000)
 
  314    if (! (iy >= minnorthing_[ind] && iy < maxnorthing_[ind]) ) {
 
  315      if (iy == maxnorthing_[ind] && y == maxnorthing_[ind] * tile_)
 
  318        throw GeographicErr(
"Northing " + 
Utility::str(
int(floor(y/1000)))
 
  320                            + (utmp ? 
"UTM" : 
"UPS") + 
" range for " 
  321                            + (northp ? 
"N" : 
"S" ) + 
" hemisphere [" 
  322                            + Utility::str(minnorthing_[ind]*tile_/1000)
 
  324                            + Utility::str(maxnorthing_[ind]*tile_/1000)
 
  330      if (northp && iy < minutmNrow_) {
 
  333      } 
else if (!northp && iy >= maxutmSrow_) {
 
  334        if (y == maxutmSrow_ * tile_)
 
  345  int MGRS::UTMRow(
int iband, 
int icol, 
int irow) {
 
  355    bool northp = iband >= 0;
 
  379      minrow = iband > -10 ?
 
  380      int(floor(c - 
real(4.3) - 
real(0.1) * northp)) : -90,
 
  382      int(floor(c + 
real(4.4) - 
real(0.1) * northp)) :  94,
 
  383      baserow = (minrow + maxrow) / 2 - utmrowperiod_ / 2;
 
  387    irow = (irow - baserow + maxutmSrow_) % utmrowperiod_ + baserow;
 
  388    if (!( irow >= minrow && irow <= maxrow )) {
 
  397        sband = iband >= 0 ? iband : -iband - 1,
 
  399        srow = irow >= 0 ? irow : -irow - 1,
 
  401        scol = icol < 4 ? icol : -icol + 7;
 
  404      if ( ! ( (srow == 70 && sband == 8 && scol >= 2) ||
 
  405               (srow == 71 && sband == 7 && scol <= 2) ||
 
  406               (srow == 79 && sband == 9 && scol >= 1) ||
 
  407               (srow == 80 && sband == 8 && scol <= 1) ) )
 
  414                    string& gridzone, 
string& block,
 
  415                    string& easting, 
string& northing) {
 
  416    string::size_type n = mgrs.length();
 
  418        toupper(mgrs[0]) == 
'I' &&
 
  419        toupper(mgrs[1]) == 
'N' &&
 
  420        toupper(mgrs[2]) == 
'V') {
 
  421      gridzone = mgrs.substr(0, 3);
 
  422      block = easting = northing = 
"";
 
  425    string::size_type p0 = mgrs.find_first_not_of(digits_);
 
  426    if (p0 == string::npos)
 
  427      throw GeographicErr(
"MGRS::Decode: ref does not contain alpha chars");
 
  429      throw GeographicErr(
"MGRS::Decode: ref does not start with 0-2 digits");
 
  430    string::size_type p1 = mgrs.find_first_of(alpha_, p0);
 
  432      throw GeographicErr(
"MGRS::Decode: ref contains non alphanumeric chars");
 
  433    p1 = min(mgrs.find_first_not_of(alpha_, p0), n);
 
  434    if (!(p1 == p0 + 1 || p1 == p0 + 3))
 
  435      throw GeographicErr(
"MGRS::Decode: ref must contain 1 or 3 alpha chars");
 
  436    if (p1 == p0 + 1 && p1 < n)
 
  437      throw GeographicErr(
"MGRS::Decode: ref contains junk after 1 alpha char");
 
  438    if (p1 < n && (mgrs.find_first_of(digits_, p1) != p1 ||
 
  439                   mgrs.find_first_not_of(digits_, p1) != string::npos))
 
  440      throw GeographicErr(
"MGRS::Decode: ref contains junk at end");
 
  442      throw GeographicErr(
"MGRS::Decode: ref must end with even no of digits");
 
  444    gridzone = mgrs.substr(0, p0+1);
 
  445    block = mgrs.substr(p0+1, p1 - (p0 + 1));
 
  446    easting = mgrs.substr(p1, (n - p1) / 2);
 
  447    northing = mgrs.substr(p1 + (n - p1) / 2);
 
 
  451    real lat, lon, x, y, t = tile_; 
int zone; 
bool northp;
 
  454      throw GeographicErr(
"MGRS::Check: equator coverage failure");
 
  457      throw GeographicErr(
"MGRS::Check: UTM doesn't reach latitude = 84");
 
  460      throw GeographicErr(
"MGRS::Check: UTM doesn't reach latitude = -80");
 
  463      throw GeographicErr(
"MGRS::Check: Norway exception creates a gap");
 
  466      throw GeographicErr(
"MGRS::Check: Svalbard exception creates a gap");
 
  470        GeographicErr(
"MGRS::Check: North UPS doesn't reach latitude = 84");
 
  474        GeographicErr(
"MGRS::Check: South UPS doesn't reach latitude = -80");
 
  477    const short tab[] = {
 
  493      7, 5, 70,   7, 7, 70,   7, 7, 71,   7, 9, 71, 
 
  494      8, 5, 71,   8, 6, 71,   8, 6, 72,   8, 9, 72, 
 
  495      8, 5, 79,   8, 8, 79,   8, 8, 80,   8, 9, 80, 
 
  496      9, 5, 80,   9, 7, 80,   9, 7, 81,   9, 9, 81, 
 
  499    const int bandchecks = 
sizeof(tab) / (3 * 
sizeof(
short));
 
  500    for (
int i = 0; i < bandchecks; ++i) {
 
  502      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)
Some utility routines for GeographicLib.
static int lookup(const std::string &s, char c)
static std::string str(T x, int p=-1)
Namespace for GeographicLib.