将一个城市的地图按照每1平方公里进行拆分为若干个区域(地图使用高德)
如图:

核心代码(Python 3.5):
map_zoning.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import json
import math
import os
import time
from amap import Map
class MapZoning:
def __init__(self, city, distance=None, map_service=None):
self.city = city
self.distance = distance if distance else 1 # 单位km,默认0.5km
self.earth_radius = 40075.04 / (2 * math.pi)
self.lat_unit = self.get_lat_unit(self.distance)
self.map_service = map_service if map_service else Map(os.environ.get('MAP_KEY'))
self.location_validated = {} # key:[经度,维度] value: 1验证成功,2超出范围
def get_lat_unit(self, distance):
"""
获取一定距离的维度单位
:param distance:
:return:
"""
return distance * 360 / (2 * math.pi) / self.earth_radius
def get_lng_unit(self, lat, distance):
"""
获取一定距离的经度单位
:param lat:
:param distance:
:return:
"""
return distance * 360 / (2 * math.pi) / math.cos(math.radians(lat)) / self.earth_radius
def _get_area_points(self, quadrant, location):
"""
获取区域的点
:param int quadrant:
:param list location:
:return list : 矩形四个点,顺序:左上、右上、右下、左下
"""
if quadrant == 1:
left_lng = float(location[0]) # 经度
bottom_lat = float(location[1]) # 维度
top_lat = round(bottom_lat + self.lat_unit, 6)
right_lng = round(left_lng + self.get_lng_unit(float(top_lat), self.distance), 6)
elif quadrant == 2:
right_lng = float(location[0])
bottom_lat = float(location[1])
top_lat = round(bottom_lat + self.get_lat_unit(self.distance), 6)
left_lng = round(right_lng - self.get_lng_unit(top_lat, self.distance), 6)
elif quadrant == 3:
right_lng = float(location[0])
top_lat = float(location[1])
left_lng = round(right_lng - self.get_lng_unit(top_lat, self.distance), 6)
bottom_lat = round(top_lat - self.get_lat_unit(self.distance), 6)
elif quadrant == 4:
left_lng = float(location[0])
top_lat = float(location[1])
right_lng = round(left_lng + self.get_lng_unit(float(top_lat), self.distance), 6)
bottom_lat = round(top_lat - self.lat_unit, 6)
else:
return None
return [[left_lng, top_lat], [right_lng, top_lat], [right_lng, bottom_lat], [left_lng, bottom_lat]]
def get_area_points_x(self, quadrant, res_points, points, i_temp):
if i_temp > 60:
return
if quadrant == 1:
location = points[2]
elif quadrant == 2:
location = points[3]
elif quadrant == 3:
location = points[0]
elif quadrant == 4:
location = points[1]
else:
return
tmp_pos = self._get_area_points(quadrant, location)
if self.validate_points(tmp_pos):
res_points.append(tmp_pos)
i_temp += 1
self.get_area_points_x(quadrant, res_points, tmp_pos, i_temp)
def get_area_points_y(self, quadrant, res_points, points, i_temp):
if i_temp > 60:
return
if quadrant == 1:
location = points[0]
elif quadrant == 2:
location = points[1]
elif quadrant == 3:
location = points[2]
elif quadrant == 4:
location = points[3]
else:
return
tmp_pos = self._get_area_points(quadrant, location)
if self.validate_points(tmp_pos):
res_points.append(tmp_pos)
i_temp += 1
self.get_area_points_x(quadrant, res_points, tmp_pos, 1)
self.get_area_points_y(quadrant, res_points, tmp_pos, i_temp)
def get_all_area_points(self, quadrant, res_points, location):
tmp_pos = self._get_area_points(quadrant, location)
res_points.append(tmp_pos)
self.get_area_points_x(quadrant, res_points, tmp_pos, 1)
self.get_area_points_y(quadrant, res_points, tmp_pos, 1)
def validate_points(self, points):
b_result = False
for location in points:
if location[0] < 113.74181 or location[1] < 22.438768 or location[1] > 22.887492 or location[0] > 114.649706:
continue
v_key = ','.join([str(x) for x in location])
v_value = self.location_validated.get(v_key)
if not v_value:
res = self.map_service.get_get_address(location)
address_component = res.get('regeocode').get('addressComponent') if res and res.get('regeocode') else {}
if not address_component or address_component.get('citycode') != '0755' or address_component.get(
'seaArea'):
self.location_validated[v_key] = 2
else:
b_result = True
self.location_validated[v_key] = 1
elif v_value == 1:
b_result = True
return b_result
def zoning(self):
print(time.time())
res_points = []
location = [114.057868, 22.543099] # self.map_service.get_geo_code(self.city).split(',')
self.get_all_area_points(1, res_points, location)
self.get_all_area_points(2, res_points, location)
self.get_all_area_points(3, res_points, location)
self.get_all_area_points(4, res_points, location)
with open('tmp/points.js', 'w', encoding='utf-8') as _file:
_file.write('var points = ' + json.dumps(res_points) + ';')
print(time.time())
# points = [['113.980092', '22.475719'], ['113.984953', '22.475719'], ['113.984953', '22.471227'],
# ['113.980092', '22.471227']]
# print(self.validate_points(points))
# print(self.map_service.get_get_address(['113.980092', '22.475719']))
return res_points
amap.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import logging
import requests
class Map:
def __init__(self, key):
if not key:
raise Exception('初始map服务错误无效Key')
self.key = key
def get_geo_code(self, address):
"""
获取地理位置编码
:param address:
:return:
"""
api_geocode = 'http://restapi.amap.com/v3/geocode/geo'
try:
response = requests.get(api_geocode, {'key': self.key,
'address': address,
'output': 'JSON'})
if response.status_code != 200:
return None
res = response.json()
if not res:
return None
geocodes = res.get('geocodes')
if not geocodes:
return None
location = geocodes[0].get('location')
if not location:
return None
return location
except Exception as ex:
logging.error('获取地址位置编码错误:' + str(ex))
return None
def get_get_address(self, location):
api = 'http://restapi.amap.com/v3/geocode/regeo'
try:
response = requests.get(api, {'key': self.key,
'location': ','.join([str(x) for x in location]),
'output': 'JSON'})
if response.status_code != 200:
return None
res = response.json()
if not res:
return None
return res
except Exception as ex:
logging.error('获取地址位置错误:' + str(ex))
return None
app.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import logging
from os.path import join, dirname
from dotenv import load_dotenv
from map_zoning import MapZoning
dotenv_path = join(dirname(__file__), '.env')
load_dotenv(dotenv_path)
if __name__ == '__main__':
try:
MapZoning('深圳市').zoning()
except Exception as ex:
logging.error(ex)
.env
# application APP_NAME="split_map" APP_RUNTIME="dev" APP_LOG_LEVEL="INFO" APP_LOG_HANDLER="console" # map MAP_KEY="amap_web_api_key"