经纬度转geohash函数
生活随笔
收集整理的這篇文章主要介紹了
经纬度转geohash函数
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1.原理剖析
Geohash原理
關鍵理解
(1)GeoHash將二維的經緯度轉換成字符串,每一個字符串代表了某一矩形區域。
(2)不同的編碼長度,表示不同的范圍區間,字符串越長,表示的范圍越精確
(3)Peano曲線實現更加簡單,在使用的時候配合一定的解決手段,可以很好的滿足大部分需求,因此TD內部Geohash算法采用的是Peano空間填充曲線。
2.JAVA實現代碼
package com.common.udf;import java.util.ArrayList; import java.util.Arrays; import java.util.List;public class GeoHashUdf {private LocationBean location;/*** 1 2500km;2 630km;3 78km;4 30km* 5 2.4km; 6 610m; 7 76m; 8 19m*/private int hashLength = 8; //經緯度轉化為geohash長度private int latLength = 20; //緯度轉化為二進制長度private int lngLength = 20; //經度轉化為二進制長度private double minLat;//每格緯度的單位大小private double minLng;//每個經度的倒下private static final char[] CHARS = {'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'};public GeoHashUdf(double lat, double lng) {location = new LocationBean(lat, lng);setMinLatLng();}public int gethashLength() {return hashLength;}/*** @Author:lulei* @Description: 設置經緯度的最小單位*/private void setMinLatLng() {minLat = LocationBean.MAXLAT - LocationBean.MINLAT;for (int i = 0; i < latLength; i++) {minLat /= 2.0;}minLng = LocationBean.MAXLNG - LocationBean.MINLNG;for (int i = 0; i < lngLength; i++) {minLng /= 2.0;}}/*** @return* @Author:lulei* @Description: 求所在坐標點及周圍點組成的九個*/public List<String> getGeoHashBase32For9() {double leftLat = location.getLat() - minLat;double rightLat = location.getLat() + minLat;double upLng = location.getLng() - minLng;double downLng = location.getLng() + minLng;List<String> base32For9 = new ArrayList<String>();//左側從上到下 3個String leftUp = getGeoHashBase32(leftLat, upLng);if (!(leftUp == null || "".equals(leftUp))) {base32For9.add(leftUp);}String leftMid = getGeoHashBase32(leftLat, location.getLng());if (!(leftMid == null || "".equals(leftMid))) {base32For9.add(leftMid);}String leftDown = getGeoHashBase32(leftLat, downLng);if (!(leftDown == null || "".equals(leftDown))) {base32For9.add(leftDown);}//中間從上到下 3個String midUp = getGeoHashBase32(location.getLat(), upLng);if (!(midUp == null || "".equals(midUp))) {base32For9.add(midUp);}String midMid = getGeoHashBase32(location.getLat(), location.getLng());if (!(midMid == null || "".equals(midMid))) {base32For9.add(midMid);}String midDown = getGeoHashBase32(location.getLat(), downLng);if (!(midDown == null || "".equals(midDown))) {base32For9.add(midDown);}//右側從上到下 3個String rightUp = getGeoHashBase32(rightLat, upLng);if (!(rightUp == null || "".equals(rightUp))) {base32For9.add(rightUp);}String rightMid = getGeoHashBase32(rightLat, location.getLng());if (!(rightMid == null || "".equals(rightMid))) {base32For9.add(rightMid);}String rightDown = getGeoHashBase32(rightLat, downLng);if (!(rightDown == null || "".equals(rightDown))) {base32For9.add(rightDown);}return base32For9;}/*** @param length* @return* @Author:lulei* @Description: 設置經緯度轉化為geohash長度*/public boolean sethashLength(int length) {if (length < 1) {return false;}hashLength = length;latLength = (length * 5) / 2;if (length % 2 == 0) {lngLength = latLength;} else {lngLength = latLength + 1;}setMinLatLng();return true;}/*** @return* @Author:lulei* @Description: 獲取經緯度的base32字符串*/public String getGeoHashBase32() {return getGeoHashBase32(location.getLat(), location.getLng());}/*** @param lat* @param lng* @return* @Author:lulei* @Description: 獲取經緯度的base32字符串*/private String getGeoHashBase32(double lat, double lng) {boolean[] bools = getGeoBinary(lat, lng);if (bools == null) {return null;}StringBuffer sb = new StringBuffer();for (int i = 0; i < bools.length; i = i + 5) {boolean[] base32 = new boolean[5];for (int j = 0; j < 5; j++) {base32[j] = bools[i + j];}char cha = getBase32Char(base32);if (' ' == cha) {return null;}sb.append(cha);}return sb.toString();}/*** @param base32* @return* @Author:lulei* @Description: 將五位二進制轉化為base32*/private char getBase32Char(boolean[] base32) {if (base32 == null || base32.length != 5) {return ' ';}int num = 0;for (boolean bool : base32) {num <<= 1;if (bool) {num += 1;}}return CHARS[num % CHARS.length];}/*** @param lat* @param lng* @return* @Author:lulei* @Description: 獲取坐標的geo二進制字符串*/private boolean[] getGeoBinary(double lat, double lng) {boolean[] latArray = getHashArray(lat, LocationBean.MINLAT, LocationBean.MAXLAT, latLength);boolean[] lngArray = getHashArray(lng, LocationBean.MINLNG, LocationBean.MAXLNG, lngLength);return merge(latArray, lngArray);}/*** @param latArray* @param lngArray* @return* @Author:lulei* @Description: 合并經緯度二進制*/private boolean[] merge(boolean[] latArray, boolean[] lngArray) {if (latArray == null || lngArray == null) {return null;}boolean[] result = new boolean[lngArray.length + latArray.length];Arrays.fill(result, false);for (int i = 0; i < lngArray.length; i++) {result[2 * i] = lngArray[i];}for (int i = 0; i < latArray.length; i++) {result[2 * i + 1] = latArray[i];}return result;}/*** @param value* @param min* @param max* @return* @Author:lulei* @Description: 將數字轉化為geohash二進制字符串*/private boolean[] getHashArray(double value, double min, double max, int length) {if (value < min || value > max) {return null;}if (length < 1) {return null;}boolean[] result = new boolean[length];for (int i = 0; i < length; i++) {double mid = (min + max) / 2.0;if (value > mid) {result[i] = true;min = mid;} else {result[i] = false;max = mid;}}return result;}class LocationBean {public static final double MINLAT = -90;public static final double MAXLAT = 90;public static final double MINLNG = -180;public static final double MAXLNG = 180;private double lat;//緯度[-90,90]private double lng;//經度[-180,180]public LocationBean(double lat, double lng) {this.lat = lat;this.lng = lng;}public double getLat() {return lat;}public void setLat(double lat) {this.lat = lat;}public double getLng() {return lng;}public void setLng(double lng) {this.lng = lng;}}public static void main(String[] args) {// TODO Auto-generated method stubGeoHashUdf g = new GeoHashUdf(36.451113, -102.849854);g.sethashLength(8);System.out.println("當前坐標:"+g.getGeoHashBase32());//for (String str:// g.getGeoHashBase32For9()) {// System.out.println(str);//}} }運行返回值
3.PYTHON實現代碼
class get_geohash_encode():def evaluate(self, longitude,latitude, precision= 12):__base32 = '0123456789bcdefghjkmnpqrstuvwxyz'try:longitude = float(longitude)latitude = float(latitude)except:return Nonelat_interval, lon_interval = (-90.0, 90.0), (-180.0, 180.0)geohash = []bits = [ 16, 8, 4, 2, 1 ]bit = 0ch = 0even = Truewhile len(geohash) < precision:if even:mid = (lon_interval[0] + lon_interval[1]) / 2if longitude > mid:ch |= bits[bit]lon_interval = (mid, lon_interval[1])else:lon_interval = (lon_interval[0], mid)else:mid = (lat_interval[0] + lat_interval[1]) / 2if latitude > mid:ch |= bits[bit]lat_interval = (mid, lat_interval[1])else:lat_interval = (lat_interval[0], mid)even = not evenif bit < 4:bit += 1else:geohash += __base32[ch]bit = 0ch = 0return ''.join(geohash)總結
以上是生活随笔為你收集整理的经纬度转geohash函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Seq2Seq Attention输入输
- 下一篇: plc与plc之间怎么通讯?