# Geohash

GeoHash是目前比较主流实现位置服务的技术，Geohash算法将经纬度二维数据编码为一个字符串，本质是一个降维的过程，

### 原理

• 将纬度(-90, 90)平均分成两个区间(-90, 0)、(0, 90)，如果坐标位置的纬度值在第一区间，则编码是0，否则编码为1。我们用 39.918118 举例，由于39.918118 属于 (0, 90)，所以编码为1，然后我们继续将(0, 90)分成(0, 45)、(45, 90)两个区间，而39.918118 位于(0, 45)，所以编码是0，依次类推，我们进行20次拆分，最后计算39.918118 的编码是 10111000110001011011；经度的处理也是类似，只是经度的范围是(-180, 180)，116.40382的编码是11010010110001101010
• 经纬度的编码合并，从0开始，奇数为是纬度，偶数为是经度，得到的编码是1110011101001000111100000011100111001101
• 对经纬度合并后的编码，进行base32编码，最终得到wx4g0ffe

### 代码实现

``````    private void convert(double min, double max, double value, List<Character> list) {
if (list.size() > (length - 1)) {
return;
}
double mid = (max + min) / 2;
if (value < mid) {
convert(min, mid, value, list);
} else {
convert(mid, max, value, list);
}
}
``````

``````        List<Character> latList = new ArrayList<Character>();
List<Character> lngList = new ArrayList<Character>();
convert(Min_Lat, Max_Lat, lat, latList);
convert(Min_Lng, Max_Lng, lng, lngList);
StringBuilder sb = new StringBuilder();
for (int index = 0; index < latList.size(); index++) {
sb.append(lngList.get(index)).append(latList.get(index));
}
``````

base32编码

``````    private final String[] base32Lookup =
{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "b", "c", "d", "e", "f", "g", "h",
"j", "k", "m", "n", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"};
private String base32Encode(final String str) {
String unit = "";
StringBuilder sb = new StringBuilder();
for (int start = 0; start < str.length(); start = start + 5) {
unit = str.substring(start, start + 5);
sb.append(base32Lookup[convertToIndex(unit.split(""))]);
}
return sb.toString();
}
private int convertToIndex(String str) {
int length = str.length();
int result = 0;
for (int index = 0; index < length; index++) {
result += str.charAt(index) == '0' ? 0 : 1 << (length - 1 - index);
}
return result;
}
``````

### 边界问题

y84b08j2, wxfzbxvq, wxfzbxvx, wxfzbxvp, y84b08j8, y84b08j0, wxfzbxvw, wxfzbxvn

[116.3967,45.0009] 周围8块区域的Geohash

y84b08j3, wxfzbxvr, y84b08j8, y84b08j0, y84b08j9, y84b08j1, wxfzbxvx, wxfzbxvp

[116.3967,44.9999]和[116.3967,45.0009]分别出现在各自附近的区域中，周围8个区域的Geohash怎么计算得到呢？很简单，当Geohash长度是8时，对应的每个最小单元

``````    double latUnit = (Max_Lat - Min_Lat) / (1 << 20);
double lngUnit = (Max_Lng - Min_Lng) / (1 << 20);
``````

``````[lat + latUnit, lng]
[lat - latUnit, lng]
[lat, lng + lngUnit]
[lat, lng - lngUnit]
[lat + latUnit, lng + lngUnit]
[lat + latUnit, lng - lngUnit]
[lat - latUnit, lng + lngUnit]
[lat - latUnit, lng - lngUnit]
``````

### 距离还是距离

``````    public static double distance(double lat1, double lng1, double lat2, double lng2) {
double x1 = Math.cos(lat1) * Math.cos(lng1);
double y1 = Math.cos(lat1) * Math.sin(lng1);
double z1 = Math.sin(lat1);
double x2 = Math.cos(lat2) * Math.cos(lng2);
double y2 = Math.cos(lat2) * Math.sin(lng2);
double z2 = Math.sin(lat2);
double lineDistance =
Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2));
double realDistance = EARTH_RADIUS * Math.PI * 2 * Math.asin(0.5 * lineDistance) / 180;
return realDistance;
}
``````

# Geohash

## GeoHash是目前比较主流实现位置服务的技术，用最简洁的Java实现GeoHash算法

### Geohash Info

⭐ Stars224
🔗 Source Codegithub.com
🕒 Last Update10 months ago
🕒 Created6 years ago
🐞 Open Issues4
➗ Star-Issue Ratio56
😎 AuthorGongDexing