GeographicLib  1.50.1
GARS.cpp
Go to the documentation of this file.
1 /**
2  * \file GARS.cpp
3  * \brief Implementation for GeographicLib::GARS class
4  *
5  * Copyright (c) Charles Karney (2015-2019) <charles@karney.com> and licensed
6  * under the MIT/X11 License. For more information, see
7  * https://geographiclib.sourceforge.io/
8  **********************************************************************/
9 
10 #include <GeographicLib/GARS.hpp>
12 
13 namespace GeographicLib {
14 
15  using namespace std;
16 
17  const char* const GARS::digits_ = "0123456789";
18  const char* const GARS::letters_ = "ABCDEFGHJKLMNPQRSTUVWXYZ";
19 
20  void GARS::Forward(real lat, real lon, int prec, std::string& gars) {
21  if (abs(lat) > 90)
22  throw GeographicErr("Latitude " + Utility::str(lat)
23  + "d not in [-90d, 90d]");
24  if (Math::isnan(lat) || Math::isnan(lon)) {
25  gars = "INVALID";
26  return;
27  }
28  lon = Math::AngNormalize(lon);
29  if (lon == 180) lon = -180; // lon now in [-180,180)
30  if (lat == 90) lat *= (1 - numeric_limits<real>::epsilon() / 2);
31  prec = max(0, min(int(maxprec_), prec));
32  int
33  x = int(floor(lon * m_)) - lonorig_ * m_,
34  y = int(floor(lat * m_)) - latorig_ * m_,
35  ilon = x * mult1_ / m_,
36  ilat = y * mult1_ / m_;
37  x -= ilon * m_ / mult1_; y -= ilat * m_ / mult1_;
38  char gars1[maxlen_];
39  ++ilon;
40  for (int c = lonlen_; c--;) {
41  gars1[c] = digits_[ ilon % baselon_]; ilon /= baselon_;
42  }
43  for (int c = latlen_; c--;) {
44  gars1[lonlen_ + c] = letters_[ilat % baselat_]; ilat /= baselat_;
45  }
46  if (prec > 0) {
47  ilon = x / mult3_; ilat = y / mult3_;
48  gars1[baselen_] = digits_[mult2_ * (mult2_ - 1 - ilat) + ilon + 1];
49  if (prec > 1) {
50  ilon = x % mult3_; ilat = y % mult3_;
51  gars1[baselen_ + 1] = digits_[mult3_ * (mult3_ - 1 - ilat) + ilon + 1];
52  }
53  }
54  gars.resize(baselen_ + prec);
55  copy(gars1, gars1 + baselen_ + prec, gars.begin());
56  }
57 
58  void GARS::Reverse(const std::string& gars, real& lat, real& lon,
59  int& prec, bool centerp) {
60  int len = int(gars.length());
61  if (len >= 3 &&
62  toupper(gars[0]) == 'I' &&
63  toupper(gars[1]) == 'N' &&
64  toupper(gars[2]) == 'V') {
65  lat = lon = Math::NaN();
66  return;
67  }
68  if (len < baselen_)
69  throw GeographicErr("GARS must have at least 5 characters " + gars);
70  if (len > maxlen_)
71  throw GeographicErr("GARS can have at most 7 characters " + gars);
72  int prec1 = len - baselen_;
73  int ilon = 0;
74  for (int c = 0; c < lonlen_; ++c) {
75  int k = Utility::lookup(digits_, gars[c]);
76  if (k < 0)
77  throw GeographicErr("GARS must start with 3 digits " + gars);
78  ilon = ilon * baselon_ + k;
79  }
80  if (!(ilon >= 1 && ilon <= 720))
81  throw GeographicErr("Initial digits in GARS must lie in [1, 720] " +
82  gars);
83  --ilon;
84  int ilat = 0;
85  for (int c = 0; c < latlen_; ++c) {
86  int k = Utility::lookup(letters_, gars[lonlen_ + c]);
87  if (k < 0)
88  throw GeographicErr("Illegal letters in GARS " + gars.substr(3,2));
89  ilat = ilat * baselat_ + k;
90  }
91  if (!(ilat < 360))
92  throw GeographicErr("GARS letters must lie in [AA, QZ] " + gars);
93  real
94  unit = mult1_,
95  lat1 = ilat + latorig_ * unit,
96  lon1 = ilon + lonorig_ * unit;
97  if (prec1 > 0) {
98  int k = Utility::lookup(digits_, gars[baselen_]);
99  if (!(k >= 1 && k <= mult2_ * mult2_))
100  throw GeographicErr("6th character in GARS must [1, 4] " + gars);
101  --k;
102  unit *= mult2_;
103  lat1 = mult2_ * lat1 + (mult2_ - 1 - k / mult2_);
104  lon1 = mult2_ * lon1 + (k % mult2_);
105  if (prec1 > 1) {
106  k = Utility::lookup(digits_, gars[baselen_ + 1]);
107  if (!(k >= 1 /* && k <= mult3_ * mult3_ */))
108  throw GeographicErr("7th character in GARS must [1, 9] " + gars);
109  --k;
110  unit *= mult3_;
111  lat1 = mult3_ * lat1 + (mult3_ - 1 - k / mult3_);
112  lon1 = mult3_ * lon1 + (k % mult3_);
113  }
114  }
115  if (centerp) {
116  unit *= 2; lat1 = 2 * lat1 + 1; lon1 = 2 * lon1 + 1;
117  }
118  lat = lat1 / unit;
119  lon = lon1 / unit;
120  prec = prec1;
121  }
122 
123 } // namespace GeographicLib
static T AngNormalize(T x)
Definition: Math.hpp:383
Header for GeographicLib::Utility class.
static void Forward(real lat, real lon, int prec, std::string &gars)
Definition: GARS.cpp:20
static void Reverse(const std::string &gars, real &lat, real &lon, int &prec, bool centerp=true)
Definition: GARS.cpp:58
Namespace for GeographicLib.
Definition: Accumulator.cpp:12
static T NaN()
Definition: Math.cpp:389
static bool isnan(T x)
Definition: Math.cpp:401
static std::string str(T x, int p=-1)
Definition: Utility.hpp:276
Exception handling for GeographicLib.
Definition: Constants.hpp:390
static int lookup(const std::string &s, char c)
Definition: Utility.hpp:460
Header for GeographicLib::GARS class.