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

浙公网安备 33010602011771号