我有一些用户在我的Django应用程序中注册了,我希望能够根据他们的邮政编码简单地找出两个用户之间的距离,然后根据该列表对列表进行排序。我想这个功能没有内置到Django中。我正在寻找一些选项并偶然发现geodjango,这似乎对我的需求可能有点过分。
答案 0 :(得分:18)
对于@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:变量名称“距离”是一个极端的用词不当。 该数量实际上是两条线之间角度的cos 从地球中心到输入点。更改为“cos_x”
问题4:没有必要将角度x转换为度数。只是 将x乘以所选单位的地球半径(km,nm或“statute miles”)
解决了所有问题后,我们得到:
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)到纽约(40.733,-73.917) calcDist - &gt; 2570.7758043869976
calc_dist - &gt; 5038.599866130089
calc_dist_fixed - &gt; 2570.9028268899356
美国政府网站(http://www.nhc.noaa.gov/gccalc.shtml) - &gt; 2569
本网站(http://www.timeanddate.com/worldclock/distanceresult.html?p1=179&p2=224),我从中获得了SFO和NYC坐标, - &gt; 2577
答案 1 :(得分:6)
根据tcarobruce的建议,以上是我的上述评论作为答案:
Zip Code Database Project有一个美国邮政编码的纬度和经度数据库,可以是SQL也可以是CSV。他们还为距离计算提供了以下代码(由我编辑的slighlty):
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的更正。
答案 2 :(得分:0)
http://code.google.com/apis/maps/documentation/directions/
您可以为每个位置指明路线。总距离给出。 API似乎输出JSON;你可以在服务器端解析答案,也可以用JavaScript计算距离。
答案 3 :(得分:0)
另一种简单的方法:
在从zipcode计算纬度和经度之后,函数返回两个位置之间的距离。
lat1
,long1
是第一个位置的纬度和经度。
lat2
,long2
是第二位置的纬度和经度。
from decimal import Decimal
from math import sin, cos, sqrt, atan2, radians
def distance(lat1, lat2, long1, long2):
r = 6373.0
lat1 = radians(lat1)
lat2 = radians(lat2)
long1 = radians(long1)
long2 = radians(long2)
d_lat = lat2 - lat1
d_long = long2 - long1
a = (sin(d_lat/2))**2 + cos(lat1) * cos(lat2) * (sin(d_long/2))**2
c = 2 * atan2(sqrt(a), sqrt(1-a))
# distance in miles
dis = r * c
# distance in KM
dis /= 1.609344
return dis