Skip to content

Instantly share code, notes, and snippets.

@kosmosr
Created April 26, 2018 06:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kosmosr/5d599a6cc7bd55fe34197044af105255 to your computer and use it in GitHub Desktop.
Save kosmosr/5d599a6cc7bd55fe34197044af105255 to your computer and use it in GitHub Desktop.
距离排序
import math
from sqlalchemy import asc, func
from model.device.station import Station
def station_nearby_list(distance, longitude, latitude, page=None, limit=None):
minlat, maxlat, minlng, maxlng = __get_area(latitude, longitude, distance)
# 按距离最近排序
order_by = asc(
func.round(6371 * func.acos(
func.cos(func.radians(Station.latitude))
* func.cos(func.radians(latitude))
* func.cos(func.radians(longitude) - func.radians(Station.longitude))
+ func.sin(func.radians(Station.latitude))
* func.sin(func.radians(latitude))
))
)
station_nearby = Station.query.filter(Station.longitude.between(minlng, maxlng),
Station.latitude.between(minlat, maxlat),
Station.enable == bool(True),
Station.is_deleted == bool(False),
).order_by(order_by)
total = station_nearby.count() if station_nearby else 0
if limit and page:
offset = (int(page) - 1) * int(limit)
station_nearby = station_nearby.offset(offset).limit(int(limit))
result = [item.to_json() for item in station_nearby]
return result, total
def pile_nearby_list(distance, longitude, latitude, page=None, limit=None):
minlat, maxlat, minlng, maxlng = __get_area(latitude, longitude, distance)
# 按距离最近排序
order_by = asc(
func.round(6371 * func.acos(
func.cos(func.radians(Station.latitude))
* func.cos(func.radians(latitude))
* func.cos(func.radians(longitude) - func.radians(Station.longitude))
+ func.sin(func.radians(Station.latitude))
* func.sin(func.radians(latitude))
))
)
station_nearby = Station.query.filter(Station.longitude.between(minlng, maxlng),
Station.latitude.between(minlat, maxlat),
Station.enable == bool(True),
Station.is_deleted == bool(False),
).order_by(order_by)
total = station_nearby.count() if station_nearby else 0
if limit and page:
offset = (int(page) - 1) * int(limit)
station_nearby = station_nearby.offset(offset).limit(int(limit))
result = [item.to_json() for item in station_nearby]
return result, total
def __get_area(latitude, longitude, dis):
"""
确定查询经纬度范围
:param latitude:中心纬度
:param longitude:中心经度
:param dis:半径
:return:(minlat, maxlat, minlng, maxlng)
"""
r = 6371.137
dlng = 2 * math.asin(math.sin(dis / (2 * r)) / math.cos(latitude * math.pi / 180))
dlng = dlng * 180 / math.pi
dlat = dis / r
dlat = dlat * 180 / math.pi
minlat = latitude - dlat
maxlat = latitude + dlat
minlng = longitude - dlng
maxlng = longitude + dlng
return minlat, maxlat, minlng, maxlng
def cal_dis(longitude1: float, latitude1: float, longitude2: float, latitude2: float):
"""
根据经纬度计算距离
:param longitude1: 经度1
:param latitude1: 纬度1
:param longitude2: 经度2
:param latitude2: 纬度2
:return: 返回为km单位 保留两位小数
"""
latitude1 = (math.pi / 180.0) * latitude1
latitude2 = (math.pi / 180.0) * latitude2
longitude1 = (math.pi / 180.0) * longitude1
longitude2 = (math.pi / 180.0) * longitude2
# 因此AB两点的球面距离为:{arccos[sina*sinx+cosb*cosx*cos(b-y)]}*R (a,b,x,y)
# 地球半径
R = 6378.1
temp = math.sin(latitude1) * math.sin(latitude2) + \
math.cos(latitude1) * math.cos(latitude2) * math.cos(longitude2 - longitude1)
if float(repr(temp)) > 1.0:
temp = 1.0
d = math.acos(temp) * R
return round(d, 2);
if __name__ == '__main__':
# result, total = station_nearby_list(distance=4, latitude=28.6712732625, longitude=115.8807849884)
print(cal_dis(longitude1=115.860788, latitude1=28.698319, longitude2=115.859198, latitude2=28.682587))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment