GeographicLib  1.35
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) <charles@karney.com> and licensed under
6  * the MIT/X11 License. For more information, see
7  * http://geographiclib.sourceforge.net/
8  **********************************************************************/
9 
12 
13 namespace GeographicLib {
14 
15  using namespace std;
16 
17  const int Geohash::decprec_[] = {-2, -1, 0, 0, 1, 2, 3, 3, 4, 5,
18  6, 6, 7, 8, 9, 9, 10, 11, 12};
19  const Math::real Geohash::loneps_ = 180 * std::pow(0.5, 45);
20  const Math::real Geohash::lateps_ = 90 * std::pow(0.5, 45);
21  const Math::real Geohash::shift_ = std::pow(2.0, 45);
22  const string Geohash::lcdigits_ = "0123456789bcdefghjkmnpqrstuvwxyz";
23  const string Geohash::ucdigits_ = "0123456789BCDEFGHJKMNPQRSTUVWXYZ";
24 
25  void Geohash::Forward(real lat, real lon, int len, std::string& geohash) {
26  if (abs(lat) > 90)
27  throw GeographicErr("Latitude " + Utility::str(lat)
28  + "d not in [-90d, 90d]");
29  if (lon < -540 || lon >= 540)
30  throw GeographicErr("Longitude " + Utility::str(lon)
31  + "d not in [-540d, 540d)");
32  if (Math::isnan(lat) || Math::isnan(lon)) {
33  geohash = "nan";
34  return;
35  }
36  if (lat == 90) lat -= lateps_ / 2;
37  lon = Math::AngNormalize(lon); // lon in [-180,180)
38  // lon/loneps_ in [-2^45,2^45); lon/eps + shift_ in [0,2^46)
39  // similarly for lat
40  len = max(0, min(int(maxlen_), len));
41  unsigned long long
42  ulon = (unsigned long long)(floor(lon/loneps_) + shift_),
43  ulat = (unsigned long long)(floor(lat/lateps_) + shift_);
44  char geohash1[maxlen_];
45  unsigned byte = 0;
46  for (unsigned i = 0; i < 5 * unsigned(len);) {
47  if ((i & 1) == 0) {
48  byte = (byte << 1) + unsigned((ulon & mask_) != 0);
49  ulon <<= 1;
50  } else {
51  byte = (byte << 1) + unsigned((ulat & mask_) != 0);
52  ulat <<= 1;
53  }
54  ++i;
55  if (i % 5 == 0) {
56  geohash1[(i/5)-1] = lcdigits_[byte];
57  byte = 0;
58  }
59  }
60  geohash.resize(len);
61  copy(geohash1, geohash1 + len, geohash.begin());
62  }
63 
64  void Geohash::Reverse(const std::string& geohash, real& lat, real& lon,
65  int& len, bool centerp) {
66  len = min(int(maxlen_), int(geohash.length()));
67  if (len >= 3 &&
68  toupper(geohash[0]) == 'N' &&
69  toupper(geohash[1]) == 'A' &&
70  toupper(geohash[2]) == 'N') {
71  lat = lon = Math::NaN<real>();
72  return;
73  }
74  unsigned long long ulon = 0, ulat = 0;
75  for (unsigned k = 0, j = 0; k < unsigned(len); ++k) {
76  int byte = Utility::lookup(ucdigits_, geohash[k]);
77  if (byte < 0)
78  throw GeographicErr("Illegal character in geohash " + geohash);
79  for (unsigned i = 0, m = 16; i < 5; ++i, m >>= 1) {
80  if (j == 0)
81  ulon = (ulon << 1) + unsigned((byte & m) != 0);
82  else
83  ulat = (ulat << 1) + unsigned((byte & m) != 0);
84  j ^= 1;
85  }
86  }
87  ulon <<= 1; ulat <<= 1;
88  if (centerp) {
89  ulon += 1;
90  ulat += 1;
91  }
92  int s = 5 * (maxlen_ - len);
93  ulon <<= (s / 2);
94  ulat <<= s - (s / 2);
95  lon = ulon * loneps_ - 180;
96  lat = ulat * lateps_ - 90;
97  }
98 
99 } // namespace GeographicLib
static T AngNormalize(T x)
Definition: Math.hpp:388
Header for GeographicLib::Utility class.
static bool isnan(T x)
Definition: Math.hpp:486
static std::string str(T x, int p=-1)
Definition: Utility.hpp:266
static void Forward(real lat, real lon, int len, std::string &geohash)
Definition: Geohash.cpp:25
Exception handling for GeographicLib.
Definition: Constants.hpp:320
static int lookup(const std::string &s, char c)
Definition: Utility.hpp:364
static void Reverse(const std::string &geohash, real &lat, real &lon, int &len, bool centerp=true)
Definition: Geohash.cpp:64
Header for GeographicLib::Geohash class.