00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <GeographicLib/Geohash.hpp>
00011 #include <GeographicLib/Utility.hpp>
00012
00013 namespace GeographicLib {
00014
00015 using namespace std;
00016
00017 const int Geohash::decprec_[] = {-2, -1, 0, 0, 1, 2, 3, 3, 4, 5,
00018 6, 6, 7, 8, 9, 9, 10, 11, 12};
00019 const string Geohash::lcdigits_ = "0123456789bcdefghjkmnpqrstuvwxyz";
00020 const string Geohash::ucdigits_ = "0123456789BCDEFGHJKMNPQRSTUVWXYZ";
00021
00022 void Geohash::Forward(real lat, real lon, int len, std::string& geohash) {
00023 if (abs(lat) > 90)
00024 throw GeographicErr("Latitude " + Utility::str(lat)
00025 + "d not in [-90d, 90d]");
00026 if (lon < -540 || lon >= 540)
00027 throw GeographicErr("Longitude " + Utility::str(lon)
00028 + "d not in [-540d, 540d)");
00029 if (Math::isnan(lat) || Math::isnan(lon)) {
00030 geohash = "nan";
00031 return;
00032 }
00033 if (lat == 90) lat -= lateps() / 2;
00034 lon = Math::AngNormalize(lon);
00035
00036
00037 len = max(0, min(int(maxlen_), len));
00038 unsigned long long
00039 ulon = (unsigned long long)(floor(lon/loneps()) + shift()),
00040 ulat = (unsigned long long)(floor(lat/lateps()) + shift());
00041 char geohash1[maxlen_];
00042 unsigned byte = 0;
00043 for (unsigned i = 0; i < 5 * unsigned(len);) {
00044 if ((i & 1) == 0) {
00045 byte = (byte << 1) + unsigned((ulon & mask_) != 0);
00046 ulon <<= 1;
00047 } else {
00048 byte = (byte << 1) + unsigned((ulat & mask_) != 0);
00049 ulat <<= 1;
00050 }
00051 ++i;
00052 if (i % 5 == 0) {
00053 geohash1[(i/5)-1] = lcdigits_[byte];
00054 byte = 0;
00055 }
00056 }
00057 geohash.resize(len);
00058 copy(geohash1, geohash1 + len, geohash.begin());
00059 }
00060
00061 void Geohash::Reverse(const std::string& geohash, real& lat, real& lon,
00062 int& len, bool centerp) {
00063 len = min(int(maxlen_), int(geohash.length()));
00064 if (len >= 3 &&
00065 toupper(geohash[0]) == 'N' &&
00066 toupper(geohash[1]) == 'A' &&
00067 toupper(geohash[2]) == 'N') {
00068 lat = lon = Math::NaN();
00069 return;
00070 }
00071 unsigned long long ulon = 0, ulat = 0;
00072 for (unsigned k = 0, j = 0; k < unsigned(len); ++k) {
00073 int byte = Utility::lookup(ucdigits_, geohash[k]);
00074 if (byte < 0)
00075 throw GeographicErr("Illegal character in geohash " + geohash);
00076 for (unsigned i = 0, m = 16; i < 5; ++i, m >>= 1) {
00077 if (j == 0)
00078 ulon = (ulon << 1) + unsigned((byte & m) != 0);
00079 else
00080 ulat = (ulat << 1) + unsigned((byte & m) != 0);
00081 j ^= 1;
00082 }
00083 }
00084 ulon <<= 1; ulat <<= 1;
00085 if (centerp) {
00086 ulon += 1;
00087 ulat += 1;
00088 }
00089 int s = 5 * (maxlen_ - len);
00090 ulon <<= (s / 2);
00091 ulat <<= s - (s / 2);
00092 lon = (unsigned long)(ulon) * loneps() - 180;
00093 lat = (unsigned long)(ulat) * lateps() - 90;
00094 }
00095
00096 }