Django - 如何计算两个位置之间的距离?
我在我的Django应用里有一些注册用户,我想简单地根据他们的邮政编码来计算两个用户之间的地理距离,然后根据这个距离来排序一个列表。我想这个功能在Django里可能并没有直接提供。我在寻找一些解决方案时,发现了geodjango,但感觉这个工具可能对我来说有点复杂,超出了我的需求。
4 个回答
http://code.google.com/apis/maps/documentation/directions/
你可以为每个地点获取路线。总的距离会被提供出来。这个接口的输出格式好像是JSON;你可以选择在服务器端解析这个答案,或者用JavaScript来计算距离。
这是对@Sven Marnach在(目前被接受的)答案中发布的代码的详细评论。
以下是来自zip项目网站的原始代码,我对缩进进行了编辑:
from math import *
def calcDist(lat_A, long_A, lat_B, long_B):
distance = (sin(radians(lat_A)) *
sin(radians(lat_B)) +
cos(radians(lat_A)) *
cos(radians(lat_B)) *
cos(radians(long_A - long_B)))
distance = (degrees(acos(distance))) * 69.09
return distance
Sven发布的代码:
from math import sin, cos, radians, degrees
def calc_dist(lat_a, long_a, lat_b, long_b):
lat_a = radians(lat_a)
lat_b = radians(lat_b)
distance = (sin(lat_a) * sin(lat_b) +
cos(lat_a) * cos(lat_b) * cos(long_a - long_b))
return degrees(acos(distance)) * 69.09
问题1:无法运行:需要导入acos
。
问题2:错误的答案:在倒数第二行需要将经度差转换为弧度。
问题3:变量名“distance”用得不太准确。这个量实际上是从地球中心到输入点的两条线之间的角度的余弦值。应该改为“cos_x”。
问题4:不需要将角度x转换为度数。只需将x乘以地球的半径,单位可以是公里、海里或“法定英里”。
修正这些问题后,我们得到:
from math import sin, cos, radians, acos
# http://en.wikipedia.org/wiki/Earth_radius
# """For Earth, the mean radius is 6,371.009 km (˜3,958.761 mi; ˜3,440.069 nmi)"""
EARTH_RADIUS_IN_MILES = 3958.761
def calc_dist_fixed(lat_a, long_a, lat_b, long_b):
"""all angles in degrees, result in miles"""
lat_a = radians(lat_a)
lat_b = radians(lat_b)
delta_long = radians(long_a - long_b)
cos_x = (
sin(lat_a) * sin(lat_b) +
cos(lat_a) * cos(lat_b) * cos(delta_long)
)
return acos(cos_x) * EARTH_RADIUS_IN_MILES
注意:修正了问题1和问题2后,这就是通常实现的“球面余弦定律”。对于像“两个美国邮政编码之间的距离”这样的应用是可以的。
注意事项1:对于像从你家门口到街道这样的小距离,它的精确度不高,甚至可能会给出一个非零的距离,或者在两个点完全相同的情况下抛出异常(cos_x > 1.0);这种情况可以特别处理。
注意事项2:如果两个点是对跖点(直线经过地球中心),可能会抛出异常(cos_x < -1.0)。如果有人对此担心,可以在调用acos(cos_x)之前检查cos_x。
示例:
从SFO(37.676, -122.433)到NYC(40.733, -73.917)
calcDist -> 2570.7758043869976
calc_dist -> 5038.599866130089
calc_dist_fixed -> 2570.9028268899356
一个美国政府网站(http://www.nhc.noaa.gov/gccalc.shtml) -> 2569
这个网站(http://www.timeanddate.com/worldclock/distanceresult.html?p1=179&p2=224),我从中获取了SFO和NYC的坐标, -> 2577
根据tcarobruce的建议,我把之前的评论整理成了一个回答:
邮政编码数据库项目提供了美国邮政编码的经纬度数据,可以以SQL或CSV格式下载。他们还提供了以下用于计算距离的代码(我稍微做了一些修改):
from math import sin, cos, radians, degrees, acos
def calc_dist(lat_a, long_a, lat_b, long_b):
lat_a = radians(lat_a)
lat_b = radians(lat_b)
long_diff = radians(long_a - long_b)
distance = (sin(lat_a) * sin(lat_b) +
cos(lat_a) * cos(lat_b) * cos(long_diff))
return degrees(acos(distance)) * 69.09
请注意,计算结果是以法定英里为单位的。
编辑:感谢John Machin的指正。