逆地理编码-离线版-part1

知识养成了思想,思想同时又在融化知识。这篇文章主要讲述逆地理编码-离线版-part1相关的知识,希望能为你提供帮助。
在数据处理过程中经常遇到经纬度需要解析成地址的问题,即逆地理编码。如果为了获取高精度的数据,可以采用百度or高德的逆地理编码接口,但是个人请求量受限,企业版限额会高一些。
【逆地理编码-离线版-part1】那有没有不限额的逆地理编码方案呢?
本文提供一种离线方案,实现经纬转地址信息的方案,精度为乡镇街道粒度,响应速度单核4ms/每条,能满足一般的逆地理编码需求。
本文分模块提供如下代码。
程序主入口为 getGeoInfo,具体参考如下代码。

from s2sphere import CellId

from s2sphere import LatLng

import GeoUtils
import S2Utils, LineUtils
from geo_obj import *
# pip --trusted-host pypi.tuna.tsinghua.edu.cn install s2sphere
from data_loader import boundaryAdminCell, boundaryIndex, boundaryData, adminData, streetData, cityBusinessArea, \\
cityLevelData

min_level = 12


def init(needBoundary=True, needArea=False, needStreet=True, needCityLevel=False):
"""
按需初始化数据, 离线数据处理可以不加载该方法
:param needBoundary:是否需要加载边界数据,用于经纬度转换省市区县
:param needArea:是否需要加载商圈数据
:param needStreet:是否需要加载街道数据
:param needCityLevel:是否需要加载城市级别数据
:return:
"""

adminData
if needBoundary:
boundaryData
boundaryIndex
boundaryAdminCell

if needStreet:
streetData
if needArea:
cityBusinessArea
if needCityLevel:
cityLevelData


def determineAdminCode(lonIn: float, latIn: float, coordSys: CoordinateSystem = CoordinateSystem.GCJ02):
gcj02LonLat = GeoUtils.toGCJ02(lonIn, latIn, coordSys)
lon = gcj02LonLat[0]
lat = gcj02LonLat[1]
# print(lon, lat)
# lon = 112.989382
# lat = 28.147062

s2LatLng = LatLng.from_degrees(lat, lon)
id1 = CellId.from_lat_lng(s2LatLng).parent(min_level).id()

id2 = CellId.from_lat_lng(s2LatLng).parent(min_level - 2).id()
if GeoUtils.outOfChina(lon, lat):
return -1
elif boundaryAdminCell.get(id1) is not None:
return boundaryAdminCell.get(id1)
elif boundaryAdminCell.get(id2) is not None:
return boundaryAdminCell.get(id2)
else:
keys = []
maxLevel = 2000# 必须大于2000m,否则会出现格子半径过小选择错误问题
# 最远距离 为新疆哈密市80公里
while len(keys) == 0 and maxLevel < 200000:
newKeys = S2Utils.getCellId(s2LatLng, maxLevel, min_level)
# newKeys = []
for key in newKeys:
if boundaryIndex.get(key) is not None:
# print("flatmap", key, maxLevel, boundaryIndex.get(key))
keys.extend(boundaryIndex.get(key))

maxLevel = maxLevel * 2

def fun_(key, s2LatLng):
# 修改成 getutils distance
# return (key, CellId(key).to_lat_lng().get_distance(s2LatLng))
# return key, GeoUtils.get_earth_distance(CellId(key).to_lat_lng(), s2LatLng)
latlng = CellId(key).to_lat_lng()
dis = GeoUtils.get_earth_dist(latlng, s2LatLng)
return key, dis

# print(newKeys, newKeys)
if len(keys) > 0:
# lines1 = map(lambda key: fun_(key, s2LatLng),newKeys)
lines1 = []
for key in keys:
lines1.append(fun_(key, s2LatLng))
lines1.sort(key=lambda x: x[1])
# take 5
lines1_tak5 = lines1[0:5]
# print("lines1_tak5 ", lines1_tak5)
res1 = []
# flatmap
for startPoint in lines1_tak5:
if boundaryData.get(startPoint[0]) is not None:
values = boundaryData.get(startPoint[0])
for value in values:
res1.extend(
[(startPoint[0], value[0], value[1], True), (startPoint[0], value[0], value[2], False)])
lines1 = []
for line in res1:
start = CellId(line[0]).to_lat_lng()
end = CellId(line[1]).to_lat_lng()
dis = LineUtils.pointToLineDis(start.lng().degrees, start.lat().degrees, end.lng().degrees,
end.lat().degrees, lon, lat)
lines1.append((((start.lng().degrees, start.lat().degrees), (end.lng().degrees,

    推荐阅读