Django - 我怎样才能找到两个位置之间的距离?

时间:2011-01-17 17:31:13

标签: python django google-maps geodjango

我有一些用户在我的Django应用程序中注册了,我希望能够根据他们的邮政编码简单地找出两个用户之间的距离,然后根据该列表对列表进行排序。我想这个功能没有内置到Django中。我正在寻找一些选项并偶然发现geodjango,这似乎对我的需求可能有点过分。

4 个答案:

答案 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计算纬度和经度之后,函数返回两个位置之间的距离。

lat1long1是第一个位置的纬度和经度。

lat2long2是第二位置的纬度和经度。

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