POI计算

一、调用百度接口获取指定范围POI信息

# -*- coding: utf-8 -*-
# 第一行必须有,否则报中文字符非ascii码错误
import sys
reload(sys)
sys.setdefaultencoding("utf8")
import time
import pymysql
import requests
import json
import math
from AngleUtil import *
#ak需要在百度地图开放平台申请

ak = "C1P8exMvy4T8LKxDZkwQvGE2dP8b2aWh"

#关键词
keywords = ['百货商场', '超市', '便利店', '商铺', '集市', '通讯营业厅', '邮局', '物流公司', '公用事业', '公园', '风景区', '动物园', '植物园', '游乐园', '文物古迹',
            '度假村', '农家院', '休闲广场', '高等院校', '中学', '小学', '幼儿园', '特殊教育学校', '综合医院', '专科医院', '诊所', '药店', '飞机场', '火车站',
            '长途汽车站', '公交车站', '公交线路', '港口', '服务区', '收费站', '银行', '快递', '信用社', '投资理财', '中央机构', '各级政府', '行政单位', '政治教育机构',
            '福利机构', '高速公路出口', '高速公路入口', '机场出口', '机场入口', '车站出口', '车站入口', '岛屿', '山峰', '水系']
page_size=20
page_num=0
scope=1

#范围:
N = 5#km
lat = 39.909548618981134 #纬度 天安门广场中心
lng = 116.3981579682617 #经度  天安门广场中心
#lat = 40.026692 #纬度  奥林匹克森林公园
#lng = 116.397654 #经度
#范围:
#左下坐标 36.0802310397025.35913118187642
#右上坐标 36.22664045129566,120.60576994269596
#中间坐标 39.909548618981134,116.3981579682617

#bounds=[
    #[30.379,114.118,30.541,114.3915],
    #[30.379,114.3915,30.541,114.665],
    #[30.541,114.118,30.703,114.3915],
    #[30.541,114.3915,30.703,114.665]
#]
#根据中间坐标求得相距N千米的左下和右上坐标依次求得bounds
def getBounds(lng,lat,N):
    YS = getLatLng(AngleUtil(lng, lat), N, 45)#右上
    ZX = getLatLng(AngleUtil(lng, lat), N, 225)#左下
    print YS,ZX
    bounds = [];
    bound1 = [ZX[0],ZX[1],lat,lng];
    bound2 = [ZX[0],lng,lat,YS[1]];
    bound3 = [lat,ZX[1],YS[0],lng];
    bound4 = [lat,lng,YS[0],YS[1]];
    bounds.append(bound1);
    bounds.append(bound2);
    bounds.append(bound3);
    bounds.append(bound4);
    return bounds;

bounds = getBounds(lng,lat,N)
new_bounds = []
# col_row 将bounds的每一小块继续细分为3行3列,可以防止区域内的搜索数量上限400
col_row = 3

#打开数据库连接(用户名,密码,数据库名)
db = pymysql.connect("localhost","root","123456","python_test")
cursor = db.cursor()#获取游标

for lst in bounds:
    distance_lat = (lst[2] - lst[0])/col_row
    distance_lon = (lst[3] - lst[1])/col_row
    for i in range(col_row):
        for j in range(col_row):
            lst_temp = []
            lst_temp.append(lst[0]+distance_lat*i)
            lst_temp.append(lst[1]+distance_lon*j)
            lst_temp.append(lst[0]+distance_lat*(i+1))
            lst_temp.append(lst[1]+distance_lon*(j+1))
            new_bounds.append(lst_temp)

for type in keywords:
    count = 0  # 用于统计type关键词查询结果为空的次数  如果超过10次 就跳过 开始查询下一个关键词
    for bound in new_bounds:
              # 使用百度提供的url拼接条件
            url = "http://api.map.baidu.com/place/v2/search?ak=" + str(ak) + "&output=json&query=" + str(
                type) + "&page_size=" + str(page_size) + "&page_num=" + str(page_num) + "&bounds=" + str(
                bound[0]) + "," + str(bound[1]) + "," + str(bound[2]) + "," + str(bound[3])

            # 请求url读取,创建网页对象
            result = requests.get(url).json()
            jsonArr = result.get("results")
            if (jsonArr==[]):
                count = count+1
                if(count>=10):
                    break;
                continue;
            for item in jsonArr:
                    ID = item.get("uid")
                    NAME  = item.get("name")
                    LONGLITUDE  = item.get("location").get("lng")
                    LATITUDE  = item.get("location").get("lat")
                    _3D_X  = math.cos(LATITUDE)*math.cos(LONGLITUDE)
                    _3D_Y  = math.cos(LATITUDE)* math.sin(LONGLITUDE)
                    _3D_Z  = math.sin(LATITUDE)
                    ADDRESS = item.get("address")
                    sql = """insert into location_info (ID,NAME,LONGLITUDE,LATITUDE,3D_X,3D_Y,3D_Z,ADDRESS)VALUES("{0}","{1}",{2},{3},{4},{5},{6},"{7}")"""
                    sql = sql.format(ID,NAME,LONGLITUDE,LATITUDE,_3D_X,_3D_Y,_3D_Z,ADDRESS)
                    print sql
                    try:
                        cursor.execute(sql)  # 提行SQL语句
                    except Exception,e:
                        print e
                    db.commit()
            # 防止并发过高,百度地图要求并发小于120
            time.sleep(1.5)

db.close()#关闭数据库连接


#百度地图为了保护数据,单次请求total最多为400,也就是只能搜出400个结果,如果搜索结果大于400个的时候只显示400条记录;
#百度地图为开发者提供的配额为2000次请求/每天,并发访问的限制为120。
import math
def AngleUtil(lng,lat):
    Rc = 6378137;
    Rj = 6356725;
    m_LoDeg = lng;
    m_LoMin = ((lng - m_LoDeg) * 60);
    m_LoSec = (lng - m_LoDeg - m_LoMin / 60.) * 3600;

    m_LaDeg = lat;
    m_LaMin = ((lat - m_LaDeg) * 60);
    m_LaSec = (lat - m_LaDeg - m_LaMin / 60.) * 3600;

    m_Longitude = lng;
    m_Latitude = lat;
    m_RadLo = lng * math.pi / 180;
    m_RadLa = lat * math.pi / 180;
    Ec = Rj + (Rc - Rj) * (90 - m_Latitude) / 90;
    Ed = Ec * math.cos(m_RadLa);
    arr = [];
    arr.append(m_RadLo);
    arr.append(m_RadLa);
    arr.append(Ec);
    arr.append(Ed);
    return arr;

def getLatLng(arr,distance,angle):
    dx = distance*1000*math.sin(math.radians(angle));

    dy = distance * 1000 * math.cos(math.radians(angle));

    bjd = (dx / arr[3] + arr[0]) * 180 / math.pi;

    bwd = (dy / arr[2] + arr[1]) * 180 / math.pi;

    WdArr = [];
    WdArr.append(bwd);
    WdArr.append(bjd);
    return WdArr;

二、根据数据库中存入的POI信息计算相应条件的点

  数据库中存入了11万条网点信息(包含经纬度坐标,网点名称以及对应的三维坐标)通过给定的观察点的经纬度坐标去查询与观察点相距Nkm的范围内的网点

# -*- coding: utf-8 -*-
#获得符合条件的场所  distanceSimplify

import pymysql
import time
import os
import sys
N = 1#与目标点相距N公里的场所
R = 6371#地球半径
#观察者所处位置 或者目标基点经纬度坐标
lng = 116.403411 #经度
lat = 39.92408   #纬度
#打开数据库连接(用户名,密码,数据库名)
db = pymysql.connect("localhost","root","123456","python_test")
cursor = db.cursor()#获取游标
start_time = time.clock()
#DELIMITER $$
#DROP FUNCTION IF EXISTS getDistance$$
#CREATE FUNCTION getDistance(lng float(30),lat float(30),_lng float(30),_lat float(30)) RETURNS float(50)
#BEGIN
#  DECLARE dx float(30);
#  DECLARE dy float(30);
# DECLARE b float(30);
#  DECLARE Lx float(30);
#  DECLARE Ly float(30);
#  SET dx =  ABS(lng-_lng);
#  SET dy = ABS(lat-_lat);
# # SET b = (lat+_lat)/2;
#  SET Lx = radians(dx)*6371*cos(radians(b));
#  SET Ly = 6371*radians(dy);
#  return sqrt(Lx*Lx+Ly*Ly);
#END $$;
# sql = SELECT NAME FROM location_info WHERE getDistance(LONGLITUDE,LATITUDE,'','')<=3
sql = "SELECT NAME FROM location_info WHERE sqrt(radians(ABS(LONGLITUDE-"+str(lng)+"))*6371*cos(radians((LATITUDE+"+str(lat)+")/2))*radians(ABS(LONGLITUDE-"+str(lng)+"))*6371*cos(radians((LATITUDE+"+str(lat)+")/2))+6371*radians(ABS(LATITUDE-"+str(lat)+"))*6371*radians(ABS(LATITUDE-"+str(lat)+")))<="+str(N)+""
try:
    # 执行SQL语句
    cursor.execute(sql)
    # 获取所有记录列表
    results = cursor.fetchall()
    stage_time1 = time.clock()
    print len(results)
    print "查询数据库所用时间",os.path.basename(sys.argv[0]), (stage_time1-start_time)*1000,"ms"
    for row in results:
        print row[0]
    print "总计",len(results),"家场所在目标位置",N,"公里(",N*1000,"米)范围内"
except:
   print "Error: unable to fecth data"
stop_time = time.clock()
cost = stop_time - start_time
cursor.close()
print("总耗时%s cost %s ms" % (os.path.basename(sys.argv[0]), cost*1000))

在本机测试时,发现使用创建function的方式速度会很慢,直接在SQL中通过各种函数计算。一般的查询速度为200ms

posted @ 2020-09-18 14:48  DreamCatt  阅读(285)  评论(0)    收藏  举报