00001 /** 00002 * \file Geohash.hpp 00003 * \brief Header for GeographicLib::Geohash class 00004 * 00005 * Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed under 00006 * the MIT/X11 License. For more information, see 00007 * http://geographiclib.sourceforge.net/ 00008 **********************************************************************/ 00009 00010 #if !defined(GEOGRAPHICLIB_GEOHASH_HPP) 00011 #define GEOGRAPHICLIB_GEOHASH_HPP 1 00012 00013 #include <GeographicLib/Constants.hpp> 00014 00015 #if defined(_MSC_VER) 00016 // Squelch warnings about dll vs string 00017 # pragma warning (push) 00018 # pragma warning (disable: 4251) 00019 #endif 00020 00021 namespace GeographicLib { 00022 00023 /** 00024 * \brief Conversions for geohashes 00025 * 00026 * Geohashes are described in 00027 * - http://en.wikipedia.org/wiki/Geohash 00028 * - http://geohash.org/ 00029 * . 00030 * They provide a compact string representation of a particular geographic 00031 * location (expressed as latitude and longitude), with the property that if 00032 * trailing characters are dropped from the string the geographic location 00033 * remains nearby. 00034 * 00035 * Example of use: 00036 * \include example-Geohash.cpp 00037 **********************************************************************/ 00038 00039 class GEOGRAPHICLIB_EXPORT Geohash { 00040 private: 00041 typedef Math::real real; 00042 static const int maxlen_ = 18; 00043 static const unsigned long long mask_ = 1ULL << 45; 00044 static const int decprec_[]; 00045 static inline real shift() { 00046 using std::pow; static const real shift = pow(real(2), 45); 00047 return shift; 00048 } 00049 static inline real loneps() { 00050 static const real loneps = 180 / shift(); 00051 return loneps; 00052 } 00053 static inline real lateps() { 00054 static const real lateps = 90 / shift(); 00055 return lateps; 00056 } 00057 static const real lateps_; 00058 static const std::string lcdigits_; 00059 static const std::string ucdigits_; 00060 Geohash(); // Disable constructor 00061 00062 public: 00063 00064 /** 00065 * Convert from geographic coordinates to a geohash. 00066 * 00067 * @param[in] lat latitude of point (degrees). 00068 * @param[in] lon longitude of point (degrees). 00069 * @param[in] len the length of the resulting geohash. 00070 * @param[out] geohash the geohash. 00071 * @exception GeographicErr if \e la is not in [−90°, 00072 * 90°]. 00073 * @exception GeographicErr if \e lon is not in [−540°, 00074 * 540°). 00075 * @exception std::bad_alloc if memory for \e geohash can't be allocated. 00076 * 00077 * Internally, \e len is first put in the range [0, 18]. 00078 * 00079 * If \e lat or \e lon is NaN, the returned geohash is "nan". 00080 **********************************************************************/ 00081 static void Forward(real lat, real lon, int len, std::string& geohash); 00082 00083 /** 00084 * Convert from a geohash to geographic coordinates. 00085 * 00086 * @param[in] geohash the geohash. 00087 * @param[out] lat latitude of point (degrees). 00088 * @param[out] lon longitude of point (degrees). 00089 * @param[out] len the length of the geohash. 00090 * @param[in] centerp if true (the default) return the center of the 00091 * geohash location, otherwise return the south-west corner. 00092 * @exception GeographicErr if \e geohash contains illegal characters. 00093 * 00094 * Only the first 18 characters for \e geohash are considered. The case of 00095 * the letters in \e geohash is ignored. 00096 * 00097 * If the first three characters in \e geohash are "nan", then \e lat and 00098 * \e lon are set to NaN. 00099 **********************************************************************/ 00100 static void Reverse(const std::string& geohash, real& lat, real& lon, 00101 int& len, bool centerp = true); 00102 00103 /** 00104 * The latitude resolution of a geohash. 00105 * 00106 * @param[in] len the length of the geohash. 00107 * @return the latitude resolution (degrees). 00108 * 00109 * Internally, \e len is first put in the range [0, 18]. 00110 **********************************************************************/ 00111 static Math::real LatitudeResolution(int len) { 00112 len = (std::max)(0, (std::min)(int(maxlen_), len)); 00113 return 180 * std::pow(0.5, 5 * len / 2); 00114 } 00115 00116 /** 00117 * The longitude resolution of a geohash. 00118 * 00119 * @param[in] len the length of the geohash. 00120 * @return the longitude resolution (degrees). 00121 * 00122 * Internally, \e len is first put in the range [0, 18]. 00123 **********************************************************************/ 00124 static Math::real LongitudeResolution(int len) { 00125 len = (std::max)(0, (std::min)(int(maxlen_), len)); 00126 return 360 * std::pow(0.5, 5 * len - 5 * len / 2); 00127 } 00128 00129 /** 00130 * The geohash length required to meet a given geographic resolution. 00131 * 00132 * @param[in] res the minimum of resolution in latitude and longitude 00133 * (degrees). 00134 * @return geohash length. 00135 * 00136 * The returned length is in the range [0, 18]. 00137 **********************************************************************/ 00138 static int GeohashLength(real res) { 00139 using std::abs; 00140 res = abs(res); 00141 for (int len = 0; len < maxlen_; ++len) 00142 if (LongitudeResolution(len) <= res) 00143 return len; 00144 return maxlen_; 00145 } 00146 00147 /** 00148 * The geohash length required to meet a given geographic resolution. 00149 * 00150 * @param[in] latres the resolution in latitude (degrees). 00151 * @param[in] lonres the resolution in longitude (degrees). 00152 * @return geohash length. 00153 * 00154 * The returned length is in the range [0, 18]. 00155 **********************************************************************/ 00156 static int GeohashLength(real latres, real lonres) { 00157 using std::abs; 00158 latres = abs(latres); 00159 lonres = abs(lonres); 00160 for (int len = 0; len < maxlen_; ++len) 00161 if (LatitudeResolution(len) <= latres && 00162 LongitudeResolution(len) <= lonres) 00163 return len; 00164 return maxlen_; 00165 } 00166 00167 /** 00168 * The decimal geographic precision required to match a given geohash 00169 * length. This is the number of digits needed after decimal point in a 00170 * decimal degrees representation. 00171 * 00172 * @param[in] len the length of the geohash. 00173 * @return the decimal precision (may be negative). 00174 * 00175 * Internally, \e len is first put in the range [0, 18]. The returned 00176 * decimal precision is in the range [−2, 12]. 00177 **********************************************************************/ 00178 static int DecimalPrecision(int len) { 00179 using std::floor; using std::log; 00180 return -int(floor(log(LatitudeResolution(len))/log(Math::real(10)))); 00181 } 00182 00183 }; 00184 00185 } // namespace GeographicLib 00186 00187 #if defined(_MSC_VER) 00188 # pragma warning (pop) 00189 #endif 00190 00191 #endif // GEOGRAPHICLIB_GEOHASH_HPP