dvlyadmin_pro/backend/utils/locationanalysis.py
2025-03-18 08:46:50 +08:00

219 lines
7.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/python
#coding: utf-8
# +-------------------------------------------------------------------
# | system: django-vue-lyadmin
# +-------------------------------------------------------------------
# | Author: lybbn
# +-------------------------------------------------------------------
# | QQ: 1042594286
# +-------------------------------------------------------------------
# ------------------------------
# 经纬度工具类封装
# ------------------------------
from urllib import parse
import hashlib
import json
import math
from urllib.request import urlopen
import requests
from math import radians, cos, sin, asin, sqrt, degrees, atan2
from django.db.models.expressions import RawSQL
# ================================================= #
# ******************** 根据经度纬度匹配最近的点 ******************** #
# ================================================= #
def validate_point(lat,lon):
assert -90 <= lat <= 90, "bad latitude"
assert -180 <= lon <= 180, "bad longitude"
# original formula from http://www.movable-type.co.uk/scripts/latlong.html
def distance_haversine(lat1, lon1, lat2, lon2):
"""
Calculate the great circle distance between two points
on the earth (specified in decimal degrees)
Haversine
formula:
a = sin²(Δφ/2) + cos φ1 ⋅ cos φ2 ⋅ sin²(Δλ/2)
_ ____
c = 2 ⋅ atan2( √a, √(1a) )
d = R ⋅ c
where φ is latitude, λ is longitude, R is earths radius (mean radius = 6,371km);
note that angles need to be in radians to pass to trig functions!
"""
validate_point(lat1, lon1)
validate_point(lat2, lon2)
R = 6371 # km - earths's radius
# convert decimal degrees to radians
lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2])
# haversine formula
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * asin(sqrt(a)) # 2 * atan2(sqrt(a), sqrt(1-a))
d = R * c
return d
#根据经纬度匹配最近的商家按distance距离排序
def get_locations_nearby_queryset(queryset,latitude, longitude, max_distance=None):
"""
Return objects sorted by distance to specified coordinates
which distance is less than max_distance given in kilometers
queryset 要查询的商家的查询集
latitude 纬度
longitude 经度
max_distance 自定义的最大查询距离自带单位km
"""
# Great circle distance formula
gcd_formula = "6371 * acos(least(greatest(\
cos(radians(%s)) * cos(radians(latitude)) \
* cos(radians(longitude) - radians(%s)) + \
sin(radians(%s)) * sin(radians(latitude)) \
, -1), 1))"
distance_raw_sql = RawSQL(
gcd_formula,
(latitude, longitude, latitude)
)
qs = queryset.annotate(distance=distance_raw_sql).order_by('distance')
if max_distance is not None:
qs = qs.filter(distance__lt=max_distance)
return qs
# ================================================= #
# ******************** 百度地图详细地址解析成经纬度 ******************** #
# ================================================= #
ak = 'LYGmcld2pgHXuocf4bqsyHABEfT9lf1B'
sk = 'gAaECvBKFjeuLzlwVKNp5r80MRA7zMMe'
# 百度地图根据详细地址获取经纬度
def getbaidulnglat(address):
# 以get请求为例http://api.map.baidu.com/geocoder/v2/?address=百度大厦&output=json&ak=你的ak
queryStr = '/geocoding/v3/?address=%s&output=json&ak=%s' % (address,ak)
# 对queryStr进行转码safe内的保留字符不转换
encodedStr = parse.quote(queryStr, safe="/:=&?#+!$,;'@()*[]")
# 在最后直接追加上yoursk
rawStr = encodedStr + sk
# 计算sn
sn = (hashlib.md5(parse.quote_plus(rawStr).encode("utf8")).hexdigest())
# 由于URL里面含有中文所以需要用parse.quote进行处理然后返回最终可调用的url
uri = parse.quote("http://api.map.baidu.com" +queryStr +"&sn=" +sn, safe="/:=&?#+!$,;'@()*[]")
# print(uri)
try:
req = urlopen(uri)
res = req.read().decode()
temp = json.loads(res)
# print(temp)
# 纬度
lat = temp['result']['location']['lat']
# 经度
lng = temp['result']['location']['lng']
# 地址查找失败
if math.isclose(lat, 39.910925, rel_tol=1e-5):
lat = None
if math.isclose(lng, 116.413384, rel_tol=1e-5):
lng = None
except Exception as e:
# print(e)
lng = None
lat = None
return {'lng':lng,'lat':lat}
def computeMD5(message):
m = hashlib.md5()
m.update(message.encode(encoding='utf-8'))
return m.hexdigest()
# ================================================================= #
# ******************** 腾讯地图详细地址解析成经纬度 ******************** #
# =================================================================#
#限制 10,000 次/日
#限制 并发 5 次/秒
key = "M4NBZ-STTK5-OARIA-Q7T4R-YO5OQ-MTB7O"
secretkey='uCUAQVJKvx5OgvHuOYK5uFzI0CdisBvm'
def gettecentlnglat(address):
# url = 'https://apis.map.qq.com/ws/geocoder/v1/?address='+address+'&key='+key
queryStr1 = '/ws/geocoder/v1/'
queryStr2 = 'address='+address+'&key='+key
# 计算sig
sig = computeMD5(queryStr1+'?'+queryStr2+secretkey)
url = 'https://apis.map.qq.com'+queryStr1+'?'+queryStr2+'&sig='+sig
try:
response = requests.get(url)
res = response.json()
# print(res)
# 纬度
lat = res['result']['location']['lat']
# 经度
lng = res['result']['location']['lng']
except Exception as e:
lng = None
lat = None
return {'lng': lng, 'lat': lat}
# {
# "status": 0,
# "message": "query ok",
# "result": {
# "title": "海淀西大街74号",
# "location": {
# "lng": 116.307015,
# "lat": 39.982915
# },
# "ad_info": {
# "adcode": "110108"
# },
# "address_components": {
# "province": "北京市",
# "city": "北京市",
# "district": "海淀区",
# "street": "海淀西大街",
# "street_number": "74"
# },
# "similarity": 0.8,
# "deviation": 1000,
# "reliability": 7,
# "level": 9
# }
# }
# ========================================================================= #
# ******************** 腾讯地图逆地址解析-经纬度解析成地址信息 ******************** #
# =========================================================================#
def gettecentaddress(location):
"""
location=lat<纬度>,lng<经度>
例如location= 39.984154,116.307490
"""
# url = 'https://apis.map.qq.com/ws/geocoder/v1/?address='+address+'&key='+key
queryStr1 = '/ws/geocoder/v1/'
queryStr2 = 'key='+key+'&location='+location
# 计算sig
sig = computeMD5(queryStr1+'?'+queryStr2+secretkey)
url = 'https://apis.map.qq.com'+queryStr1+'?'+queryStr2+'&sig='+sig
try:
response = requests.get(url)
res = response.json()
# print(res)
except Exception as e:
res=None
return res