将一个城市的地图按照每1平方公里进行拆分为若干个区域

将一个城市的地图按照每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"

  

原文地址:https://www.cnblogs.com/stones/p/6297276.html