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函数相关推荐

  1. mysql geohash函数_基于MySQL实现按距离排序、范围查找geoHash

    简介 现在几乎所有的O2O应用中都会存在"按范围搜素.离我最近.显示距离"等等类似的功能,那这样的功能是怎么实现的呢?本文提供了基于MySQL的实现方式,同样适用于其它数据库.本文 ...

  2. 把经纬度转换为Geohash(准确)

    # 现在要做: # 1:把数据库的经纬度读出生成Geohash # 2:取Geohash的前N位 # 3:计算前N未Geohash的demandfrom pygeohash import encode ...

  3. mysql 经纬度距离 自定义函数_mysql 经纬度计算距离 自定义函数

    这些经纬线是怎样定出来的呢? 地球是在不停地绕地轴旋转(地轴是一根通过地球南北两极和地球中心的假想线),在地球中腰画一个与地轴垂直的大圆圈,使圈上的每一点都和南北两极的距离相等,这个圆圈就叫作&quo ...

  4. GPS经纬度算附近有什么 --- GeoHash核心原理解析

    2019独角兽企业重金招聘Python工程师标准>>> 一.感性认识GeoHash 首先来点感性认识,http://openlocation.org/geohash/geohash- ...

  5. 中心经纬度计算周边8宫格GeoHash编码

    获取Geohash当前区域周围8个区域编码 | ini's Blog (jianlei.github.io) 获取Geohash当前区域周围8个区域编码 2019-01-18 技术开发MAP GEOH ...

  6. 空间索引 - GeoHash算法及其实现优化

    转自原文 空间索引 - GeoHash算法及其实现优化 上篇博客中提到了空间索引的用途和多种数据库对空间索引的支持情况,那么在应用层以下,好学的小伙伴应该会考虑空间索引的实现原理了. 目前空间索引的实 ...

  7. Redis GeoHash 核心原理解析,你学废了吗?

    作者 | SoWhat1412 来源 | SoWhat1412(ID:sowhat9094) 头图 |  CSDN 下载自东方IC 引言 小麦同学是个吃货+技术宅,平日里就喜欢拿着手机地图点点按按来查 ...

  8. Day739.GEO经纬度数据结构自定义数据结构 -Redis 核心技术与实战

    GEO经纬度数据结构&自定义数据结构 Hi,我是阿昌,今天学习记录的是关于GEO经纬度数据结构&自定义数据结构的内容,感谢您的关注和观看. Redis 的 5 大基本数据类型:Stri ...

  9. app后端开发四:GeoHash实现查找附近的X

    夜以继日,从7月28,到今天此时此刻,用laravel做的app接口,1.0版本终于做完了.后面等整个项目上线了,可以慢慢的来回顾一下这次开发的过程.今天主要来说下附近的X这个功能. 情景描述 现在附 ...

最新文章

  1. (循环练习题) 五只猴子分桃子
  2. 质数判断及质因数分解 质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。 0和1不是质数 除了0,1,质数以外其他的数叫合数
  3. Fastjson 1.2.66 版本发布,继续加固安全!
  4. BZOJ 2879 美食节(费用流-动态加边)
  5. 蓝桥杯java第六届决赛第一题--分机号
  6. matlab 凹盘,刹车盘凹槽是怎么形成的
  7. DEDECMS全版本gotopage变量XSS ROOTKIT 0DAY
  8. 如何处理Docker错误消息:please add——insecure-registry 1
  9. about semget
  10. 见过一个一个拉新地推没见过这么多一起推
  11. 那些月薪过万的程序员都是从什么时间开始的?
  12. 简书和微博的区别是什么
  13. Java面试:mysql批量更新
  14. delphi IDE插件 cnpack 使用记录
  15. 人生若只如初见,碧海青天夜夜心
  16. vs2019 vs2022番茄助手重新安装失败问题处理
  17. 开源网络准入系统(open source Network Access Control system)
  18. 四川师范大学自然地理(1-地球)90分以上版本
  19. sed搜索某行在行末追加_sed在行首或者行尾添加内容
  20. arduino灯带随音乐_Arduino—超简单音乐制作

热门文章

  1. 重磅消息 |《技术人修炼之道:从程序员到百万高管的72项技能》隆重上市!
  2. 没有工业软件 谈什么智能制造转型
  3. C++标准库(第二版).pdf与STL源码剖析.pdf下载
  4. 【ALIENTEK 战舰STM32开发板例程系列连载+教学】第五十八章 UCOSII实验1-任务调度
  5. 启动2015世界人工智能系统智商排名,检测人工智能是否超越人类
  6. 白领女性光吃不胖的减肥食品
  7. 重庆NKOJ8849-配对碱基链
  8. 拼多多为什么越来越受资本青睐?
  9. 推送本地电子书到kindle上
  10. 腾讯服务器有多少台 微信,腾讯官方写论文:微信的技术架构有多复杂