日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

geohash java github_GitHub - GongDexing/Geohash: GeoHash是目前比较主流实现位置服务的技术,用最简洁的Java实现GeoHash算法...

發布時間:2023/11/27 生活经验 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 geohash java github_GitHub - GongDexing/Geohash: GeoHash是目前比较主流实现位置服务的技术,用最简洁的Java实现GeoHash算法... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Geohash

GeoHash是目前比較主流實現位置服務的技術,Geohash算法將經緯度二維數據編碼為一個字符串,本質是一個降維的過程,

一個栗子

地點

經緯度

Geohash

鳥巢

116.402843,39.999375

wx4g8c9v

水立方

116.3967,39.99932

wx4g89tk

故宮

116.40382,39.918118

wx4g0ffe

水立方就在鳥巢在附近,距離600米左右,而故宮到鳥巢直線距離9公里左右,體現在Geohash上,鳥巢和水立方的前五位是一樣的,而鳥巢和故宮只有前4位是一樣的,也就是說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 list) {

if (list.size() > (length - 1)) {

return;

}

double mid = (max + min) / 2;

if (value < mid) {

list.add('0');

convert(min, mid, value, list);

} else {

list.add('1');

convert(mid, max, value, list);

}

}

合并經緯度的二進制編碼

List latList = new ArrayList();

List lngList = new ArrayList();

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;

}

邊界問題

兩個位置距離得越近是否意味著Geohash前面相同的越多呢?答案是否定的,兩個很近的地點[116.3967,44.9999]和[116.3967,45.0009]的Geohash分別是wxfzbxvr和y84b08j2,這就是Geohash存在的邊界問題,這兩個地點雖然很近,但是剛好在分界點45兩側,導致Geohash完全不同,單純依靠Geohash匹配前綴的方式并不能解決這種問題

在一維空間解決不了這個問題,回到二維空間中,將當前Geohash這塊區域周圍的八塊區域的Geohash計算出來

[116.3967,44.9999] 周圍8塊區域的Geohash

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);

這樣可以計算出8個分別分布在周圍8個區域的地點,根據地點便可以計算出周圍8個區域的Geohash

[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 github_GitHub - GongDexing/Geohash: GeoHash是目前比较主流实现位置服务的技术,用最简洁的Java实现GeoHash算法...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。