Geohash.hpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /**
  2. * \file Geohash.hpp
  3. * \brief Header for GeographicLib::Geohash class
  4. *
  5. * Copyright (c) Charles Karney (2012-2017) <charles@karney.com> and licensed
  6. * under the MIT/X11 License. For more information, see
  7. * https://geographiclib.sourceforge.io/
  8. **********************************************************************/
  9. #if !defined(GEOGRAPHICLIB_GEOHASH_HPP)
  10. #define GEOGRAPHICLIB_GEOHASH_HPP 1
  11. #include <GeographicLib/Constants.hpp>
  12. #if defined(_MSC_VER)
  13. // Squelch warnings about dll vs string
  14. # pragma warning (push)
  15. # pragma warning (disable: 4251)
  16. #endif
  17. namespace GeographicLib {
  18. /**
  19. * \brief Conversions for geohashes
  20. *
  21. * Geohashes are described in
  22. * - https://en.wikipedia.org/wiki/Geohash
  23. * - http://geohash.org/
  24. * .
  25. * They provide a compact string representation of a particular geographic
  26. * location (expressed as latitude and longitude), with the property that if
  27. * trailing characters are dropped from the string the geographic location
  28. * remains nearby. The classes Georef and GARS implement similar compact
  29. * representations.
  30. *
  31. * Example of use:
  32. * \include example-Geohash.cpp
  33. **********************************************************************/
  34. class GEOGRAPHICLIB_EXPORT Geohash {
  35. private:
  36. typedef Math::real real;
  37. static const int maxlen_ = 18;
  38. static const unsigned long long mask_ = 1ULL << 45;
  39. static const char* const lcdigits_;
  40. static const char* const ucdigits_;
  41. Geohash(); // Disable constructor
  42. public:
  43. /**
  44. * Convert from geographic coordinates to a geohash.
  45. *
  46. * @param[in] lat latitude of point (degrees).
  47. * @param[in] lon longitude of point (degrees).
  48. * @param[in] len the length of the resulting geohash.
  49. * @param[out] geohash the geohash.
  50. * @exception GeographicErr if \e lat is not in [&minus;90&deg;,
  51. * 90&deg;].
  52. * @exception std::bad_alloc if memory for \e geohash can't be allocated.
  53. *
  54. * Internally, \e len is first put in the range [0, 18]. (\e len = 18
  55. * provides approximately 1&mu;m precision.)
  56. *
  57. * If \e lat or \e lon is NaN, the returned geohash is "invalid".
  58. **********************************************************************/
  59. static void Forward(real lat, real lon, int len, std::string& geohash);
  60. /**
  61. * Convert from a geohash to geographic coordinates.
  62. *
  63. * @param[in] geohash the geohash.
  64. * @param[out] lat latitude of point (degrees).
  65. * @param[out] lon longitude of point (degrees).
  66. * @param[out] len the length of the geohash.
  67. * @param[in] centerp if true (the default) return the center of the
  68. * geohash location, otherwise return the south-west corner.
  69. * @exception GeographicErr if \e geohash contains illegal characters.
  70. *
  71. * Only the first 18 characters for \e geohash are considered. (18
  72. * characters provides approximately 1&mu;m precision.) The case of the
  73. * letters in \e geohash is ignored.
  74. *
  75. * If the first 3 characters of \e geohash are "inv", then \e lat and \e
  76. * lon are set to NaN and \e len is unchanged. ("nan" is treated
  77. * similarly.)
  78. **********************************************************************/
  79. static void Reverse(const std::string& geohash, real& lat, real& lon,
  80. int& len, bool centerp = true);
  81. /**
  82. * The latitude resolution of a geohash.
  83. *
  84. * @param[in] len the length of the geohash.
  85. * @return the latitude resolution (degrees).
  86. *
  87. * Internally, \e len is first put in the range [0, 18].
  88. **********************************************************************/
  89. static Math::real LatitudeResolution(int len) {
  90. using std::ldexp;
  91. len = (std::max)(0, (std::min)(int(maxlen_), len));
  92. return ldexp(real(180), -(5 * len / 2));
  93. }
  94. /**
  95. * The longitude resolution of a geohash.
  96. *
  97. * @param[in] len the length of the geohash.
  98. * @return the longitude resolution (degrees).
  99. *
  100. * Internally, \e len is first put in the range [0, 18].
  101. **********************************************************************/
  102. static Math::real LongitudeResolution(int len) {
  103. using std::ldexp;
  104. len = (std::max)(0, (std::min)(int(maxlen_), len));
  105. return ldexp(real(360), -(5 * len - 5 * len / 2));
  106. }
  107. /**
  108. * The geohash length required to meet a given geographic resolution.
  109. *
  110. * @param[in] res the minimum of resolution in latitude and longitude
  111. * (degrees).
  112. * @return geohash length.
  113. *
  114. * The returned length is in the range [0, 18].
  115. **********************************************************************/
  116. static int GeohashLength(real res) {
  117. using std::abs; res = abs(res);
  118. for (int len = 0; len < maxlen_; ++len)
  119. if (LongitudeResolution(len) <= res)
  120. return len;
  121. return maxlen_;
  122. }
  123. /**
  124. * The geohash length required to meet a given geographic resolution.
  125. *
  126. * @param[in] latres the resolution in latitude (degrees).
  127. * @param[in] lonres the resolution in longitude (degrees).
  128. * @return geohash length.
  129. *
  130. * The returned length is in the range [0, 18].
  131. **********************************************************************/
  132. static int GeohashLength(real latres, real lonres) {
  133. using std::abs;
  134. latres = abs(latres);
  135. lonres = abs(lonres);
  136. for (int len = 0; len < maxlen_; ++len)
  137. if (LatitudeResolution(len) <= latres &&
  138. LongitudeResolution(len) <= lonres)
  139. return len;
  140. return maxlen_;
  141. }
  142. /**
  143. * The decimal geographic precision required to match a given geohash
  144. * length. This is the number of digits needed after decimal point in a
  145. * decimal degrees representation.
  146. *
  147. * @param[in] len the length of the geohash.
  148. * @return the decimal precision (may be negative).
  149. *
  150. * Internally, \e len is first put in the range [0, 18]. The returned
  151. * decimal precision is in the range [&minus;2, 12].
  152. **********************************************************************/
  153. static int DecimalPrecision(int len) {
  154. using std::floor; using std::log;
  155. return -int(floor(log(LatitudeResolution(len))/log(Math::real(10))));
  156. }
  157. };
  158. } // namespace GeographicLib
  159. #if defined(_MSC_VER)
  160. # pragma warning (pop)
  161. #endif
  162. #endif // GEOGRAPHICLIB_GEOHASH_HPP