GeographicLib  2.1.1
Geohash.cpp
Go to the documentation of this file.
1 /**
2  * \file Geohash.cpp
3  * \brief Implementation for GeographicLib::Geohash class
4  *
5  * Copyright (c) Charles Karney (2012-2022) <charles@karney.com> and licensed
6  * under the MIT/X11 License. For more information, see
7  * https://geographiclib.sourceforge.io/
8  **********************************************************************/
9 
12 
13 #if defined(_MSC_VER)
14 // Squelch warnings about enum-float expressions
15 # pragma warning (disable: 5055)
16 #endif
17 
18 namespace GeographicLib {
19 
20  using namespace std;
21 
22  const char* const Geohash::lcdigits_ = "0123456789bcdefghjkmnpqrstuvwxyz";
23  const char* const Geohash::ucdigits_ = "0123456789BCDEFGHJKMNPQRSTUVWXYZ";
24 
25  void Geohash::Forward(real lat, real lon, int len, string& geohash) {
26  using std::isnan; // Needed for Centos 7, ubuntu 14
27  static const real shift = ldexp(real(1), 45);
28  static const real loneps = Math::hd / shift;
29  static const real lateps = Math::qd / shift;
30  if (fabs(lat) > Math::qd)
31  throw GeographicErr("Latitude " + Utility::str(lat)
32  + "d not in [-" + to_string(Math::qd)
33  + "d, " + to_string(Math::qd) + "d]");
34  if (isnan(lat) || isnan(lon)) {
35  geohash = "invalid";
36  return;
37  }
38  if (lat == Math::qd) lat -= lateps / 2;
39  lon = Math::AngNormalize(lon);
40  if (lon == Math::hd) lon = -Math::hd; // lon now in [-180,180)
41  // lon/loneps in [-2^45,2^45); lon/loneps + shift in [0,2^46)
42  // similarly for lat
43  len = max(0, min(int(maxlen_), len));
44  unsigned long long
45  ulon = (unsigned long long)(floor(lon/loneps) + shift),
46  ulat = (unsigned long long)(floor(lat/lateps) + shift);
47  char geohash1[maxlen_];
48  unsigned byte = 0;
49  for (unsigned i = 0; i < 5 * unsigned(len);) {
50  if ((i & 1) == 0) {
51  byte = (byte << 1) + unsigned((ulon & mask_) != 0);
52  ulon <<= 1;
53  } else {
54  byte = (byte << 1) + unsigned((ulat & mask_) != 0);
55  ulat <<= 1;
56  }
57  ++i;
58  if (i % 5 == 0) {
59  geohash1[(i/5)-1] = lcdigits_[byte];
60  byte = 0;
61  }
62  }
63  geohash.resize(len);
64  copy(geohash1, geohash1 + len, geohash.begin());
65  }
66 
67  void Geohash::Reverse(const string& geohash, real& lat, real& lon,
68  int& len, bool centerp) {
69  static const real shift = ldexp(real(1), 45);
70  static const real loneps = Math::hd / shift;
71  static const real lateps = Math::qd / shift;
72  int len1 = min(int(maxlen_), int(geohash.length()));
73  if (len1 >= 3 &&
74  ((toupper(geohash[0]) == 'I' &&
75  toupper(geohash[1]) == 'N' &&
76  toupper(geohash[2]) == 'V') ||
77  // Check A first because it is not in a standard geohash
78  (toupper(geohash[1]) == 'A' &&
79  toupper(geohash[0]) == 'N' &&
80  toupper(geohash[2]) == 'N'))) {
81  lat = lon = Math::NaN();
82  return;
83  }
84  unsigned long long ulon = 0, ulat = 0;
85  for (unsigned k = 0, j = 0; k < unsigned(len1); ++k) {
86  int byte = Utility::lookup(ucdigits_, geohash[k]);
87  if (byte < 0)
88  throw GeographicErr("Illegal character in geohash " + geohash);
89  for (unsigned m = 16; m; m >>= 1) {
90  if (j == 0)
91  ulon = (ulon << 1) + unsigned((byte & m) != 0);
92  else
93  ulat = (ulat << 1) + unsigned((byte & m) != 0);
94  j ^= 1;
95  }
96  }
97  ulon <<= 1; ulat <<= 1;
98  if (centerp) {
99  ulon += 1;
100  ulat += 1;
101  }
102  int s = 5 * (maxlen_ - len1);
103  ulon <<= (s / 2);
104  ulat <<= s - (s / 2);
105  lon = ulon * loneps - Math::hd;
106  lat = ulat * lateps - Math::qd;
107  len = len1;
108  }
109 
110 } // namespace GeographicLib
GeographicLib::Math::real real
Definition: GeodSolve.cpp:31
Header for GeographicLib::Geohash class.
Header for GeographicLib::Utility class.
Exception handling for GeographicLib.
Definition: Constants.hpp:316
static void Forward(real lat, real lon, int len, std::string &geohash)
Definition: Geohash.cpp:25
static void Reverse(const std::string &geohash, real &lat, real &lon, int &len, bool centerp=true)
Definition: Geohash.cpp:67
static T AngNormalize(T x)
Definition: Math.cpp:71
static T NaN()
Definition: Math.cpp:250
@ hd
degrees per half turn
Definition: Math.hpp:144
@ qd
degrees per quarter turn
Definition: Math.hpp:141
static int lookup(const std::string &s, char c)
Definition: Utility.cpp:160
static std::string str(T x, int p=-1)
Definition: Utility.hpp:161
Namespace for GeographicLib.
Definition: Accumulator.cpp:12