当前位置:   article > 正文

利用GeoHash实现逆地理编码(经纬度坐标转换行政区划)_离线经纬度转行政代码

离线经纬度转行政代码

前言

GeoHash是很多基于LBS(Location Based Services)服务不可绕过的解决方案之一,网上关于GeoHash的介绍和算法很多,资源也算比较丰富。这篇文章主要是介绍如何利用GeoHash或者进行逆地理编码(经纬度坐标转换行政区划)的实现。

  1. 以中文地址【江苏省南京市玄武区梅园新村街道总统府】为例,省级【江苏省】,市级【南京市】,区县级【玄武区】,街道乡镇级【梅园新村街道】,详细地址【总统府】。由于没有地图服务没有提供街道乡镇级的行政区划polygon数据(行政区划边界的坐标点集合),所以本文利用geoHash进行的逆地理编码的方式,只能到区县级。
  2. 第四级和详细地址信息,变更相对会比较频繁,需要人工接入,维护成本比较大。

理解GeoHash

GeoHash是按照固定的算法,将经纬度信息转换为Base32码表中的一串字符。具体的算法网上资源较多,不进行详细介绍。逻辑并不是非常复杂,大概逻辑如下:

  1. 按照经度范围[-180°,180°],纬度范围[-90°,90°]对目标经纬度进行计算;二分经度和纬度范围区间,分别判断经度和纬度,在右侧集合则为1,在左侧集合则为0;循环进行此计算。
  2. 将所得经纬度1和0结果,经度在偶数位(从0位计算),纬度在奇数位进行拼接,5位二进制结果为一组,转换为十进制数后,再转换为对应Base32码表中数字,即得到对应GeoHash值。

推荐一个github上GeoHash的实现:
GeoHash算法实现

GeoHash精度

GeoHash使用5位计算结果(左右区间)作为一个精度,例如wtw6kf共有6个Base32编码表的字母或数字,代表这个geoHash值的精度为6。

GeoHash特征

  • 以一个坐标点118.797405,32.044227为例,该坐标点实际上是无数个精度更高(小数点后精确位到6位以后)的坐标点集合;将其放大理解,可以看作为一个二维矩形,此二维矩形的4角的坐标值分别应为:
坐标位置经度纬度
西南点118.79740532.044227
西北点118.79740532.044227999999…
东北点118.797405999999…32.044227999999…
东南点118.797405999999…32.044227
  • 通过对坐标点的理解, GeoHash的值可以理解为,是无数个经纬度坐标的集合。通过多个经纬度坐标在不同精度的GeoHash计算后,都可以得到一个相同GeoHash的值的规律;可得知,GeoHash的覆盖面积会比经纬度单点的覆盖面积大,只有当GeoHash计算精度越大时,其覆盖面积越小,越近似于经纬度单点的覆盖面积。同类的思路,在我们高等数学中,使用微分计算不规则曲线图形面积时的方法,最终也是极限接近结果。
  • 以坐标点118.797405,32.044227(实际地理位置为:江苏省南京市总统府)的6位精度geoHash值wtsqr3为例,其二维矩形4角的坐标值分别为:
坐标位置经度纬度
西南点118.79516601562532.0416259765625
西北点118.79516601562532.047119140625
东北点118.8061523437532.047119140625
东南点118.8061523437532.0416259765625

在地图上表现为:
在这里插入图片描述
在线绘制地址围栏

可见该GeoHash块的覆盖面积已经将地理位置江苏省南京市总统府完全覆盖,并且也会覆盖更多其他地区。

GeoHash规律

  • 通过GeoHash的运算规则和全球经纬度范围,可以推导出不同精度的GeoHash块父子级规律:即精度为n的GeoHash会有32个精度为n+1的GeoHash块。例如当GeoHash值精度为1,全世界地图都会被32个GeoHash值覆盖。例如精度为1的GeoHash值w,其会覆盖我国大部分国土。
    在这里插入图片描述
    在线标选GeoHash块

  • 当GeoHash精度为2时,其展示效果如下:
    在这里插入图片描述
    当GeoHash精度为3时,其展示效果如下:
    在这里插入图片描述
    所以如果要遍历GeoHash时,不需要进行经纬度的再次运算,可以根据GeoHash奇偶数的规律,进行GeoHash值的生成。其中奇数位的规律如下表所示:
    在这里插入图片描述
    偶数位的规律如下表所示:
    在这里插入图片描述

逆地理编码

逆地理编码指的是将经纬度坐标转换为具体的标准的行政区划信息,以高德逆地理编码接口为例,坐标点118.797405,32.044227响应的结果如下:

{
	"status": "1",
	"regeocode": {
		"addressComponent": {
			"city": "南京市",
			"province": "江苏省",
			"adcode": "320102",
			"district": "玄武区",
			"towncode": "320102002000",
			"streetNumber": {
				"number": "292号",
				"location": "118.797317,32.044008",
				"direction": "南",
				"distance": "25.7166",
				"street": "长江路"
			},
			"country": "中国",
			"township": "梅园新村街道",
		"citycode": "025"
		},
		"formatted_address": "江苏省南京市玄武区梅园新村街道总统府"
	},
	"info": "OK",
	"infocode": "10000"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

高德逆地理编码接口在线测试

此篇博文只介绍可以模拟到行政区划的省/直辖市二级市区/县/三级市的方式。如果想要详细地址(这个需要GPS终端进行实际定位,再转换火星坐标系进行记录)或者乡/镇/街道级别的地址信息,人工维护成本比较大,以笔者不算太长的地图服务接触时间来看,我们国家因城市化速度较快等原因,第四级的行政区划变更速度比较频繁。

实现逆地理编码的基本思路

1.全国范围内6位精度GeoHash计算
  1. 如果按照GeoHash的算法,需要使用全国的示例点进行计算得到结果,这个计算量和工作量非常巨大,基本上可以考虑放弃。
  2. 按照上述的GeoHash规律,我们可以轻易的通过GeoHash奇偶数表获取全国所有的6位精度GeoHash值。
  3. 首先确定全国2位精度GeoHash块(甚至3位)有多少,此数据可以直接通过画图来获取粗略结果,如下图所示:
    在这里插入图片描述
  4. 可见全国(不包含中国南海三沙市)的2位精度GeoHash块约为29块,那么,计算得出的6位精度和7位精度GeoHash值数量分别应为:

6位精度数量:29 * 25 * 25* 25* 25 = 30408704
7位精度数量:29 * 25 * 25* 25* 25 * 25= 973078528

  1. 6位精度的Geohash值可以麻烦大部分数据需求,7位精度Geohash值主要市为了解决区/县/三级市行政区划边界点与6位精度GeoHash块重合现象,7位精度的GeoHash值并不需要完全计算。
2.获取全国范围内区/县/三级市级别行政区划地址围栏点
  1. 首先感谢高德,行政区划地址围栏坐标点的数据需要从高德开放平台获取(高德开放平台地址围栏点比腾讯地图提供的要精准),申请一个高德的Key,批量拉去数据即可。注意编写脚本时建议写入文本文件或者直接写入数据库,数据量比较大。
  2. 高德在线测试获取行政区划围栏点
    拉取数据时,注意区/县/三级市级别行政区划名称有可能会重复,建议使用adcode字段进行区分。
  3. 拉取得围栏点在地图中示例(江苏省南京市玄武区)如下,比较可靠:
    在这里插入图片描述
3.计算6位精度GeoHash块与区/县/三级市级别行政区划关联关系
  1. 使用java7原生API可以判断GeoHash块(二维矩形)与区/县/三级市级别行政区划是否包含或相交,主要使用如下2个类:
import java.awt.Polygon;
import java.awt.geom.Area;
  • 1
  • 2
  1. 判断是否包含:
    在这里插入图片描述

  2. 判断是否相交:
    在这里插入图片描述

  • 如果包含,则记录该区县级别行政区划信息与对应精度的GeoHash值的关联关系;
  • 如果不包含也不相交,则不保留关系;
  • 如果相交,则遍历当前精度的GeoHash值下一精度GeoHash值,重复2 3步骤,直到包含关系,并存储GeoHash值和对应行政区划信息。
  1. 注意:
    由于数据量和计算量大,在编写脚本遍历时,尽量减少O(n)n的大小,例如GeoHash值tz仅在新疆范围内,遍历tz开头的6位精度GeoHash值时,可以仅将新疆地区行政区划参与计算。建议脚本中计算完毕部分数据就写入本地或者数据库,脚本写的粗糙的话,跑计算时很有可能会OOM。
4.将GeoHash结果值与行政区划关联关系数据存储
  1. 使用散列表存储所有的GeoHash值与行政区划关联关系。
  2. 根据GeoHash的规律,参考坐标118.797405,32.044227各精度GeoHash值:
精度GeoHash值
1w
2wt
3wts
4wtsq
5wtsqr
6wtsqr3
7wtsqr33
8wtsqr33x

为了减少单个散列表中数据量过大问题,可以按照2位精度或者3位精度GeoHash值区分存储,具体策略可以根据具体场景自行调整。

5.跟据坐标点的GeoHash值查询行政区划信息
  1. 将目标坐标点进行7位精度GeoHash值计算
  2. 根据GeoHash值获取对应散列表数据,查询获取结果。

结尾

以上查询过程很简单,复杂度O(1)即可拿到对应行政区划数据,不过1-4步骤的数据初始化过程需要人工介入次数较多;在部分边界点处理上,出现7位精度GeoHash仍然是相交而不是包含时,可以选择人工处理或上升到8位精度,按照大部分业务需求不建议上升至9位精度以上计算;如果采用人工处理,可以根据GeoHash覆盖点大小直接确定行政区划归属。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/677856
推荐阅读
相关标签
  

闽ICP备14008679号