Django - 如何找到两个位置之间的距离?

发布于 2024-10-12 04:08:31 字数 138 浏览 5 评论 0原文

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

I have some users registered in my Django app and I want to simply be able to figure out the distance, geographically, between two users based on their zip code and then sort a list based on that. I would imagine this functionality isn't built into Django. I was looking at some options and stumbled across geodjango which seems like it might be overkill for what my needs are.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

や莫失莫忘 2024-10-19 04:08:31

这是对 @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:WON'T RUN:需要导入acos

问题2:错误答案:需要转换
倒数第二行中的经度与弧度的差值

问题 3:变量名称“距离”是一个极端的用词不当。
这个量实际上是两条线之间角度的余弦
从地球中心到输入点。改为“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

This is a big fat comment on the code posted in the (currently-accepted) answer by @Sven Marnach.

Original code from zip project website, with indentation edited by me:

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

Code posted by 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

Problem 1: WON'T RUN: needs to import acos

Problem 2: WRONG ANSWERS: needs to convert the
longitude difference to radians in the second last line

Problem 3: The variable name "distance" is an extreme misnomer.
That quantity is actually the cos of the angle between the two lines
from the centre of the earth to the input points. Change to "cos_x"

Problem 4: It is not necessary to convert angle x to degrees. Simply
multiply x by earth's radius in chosen units (km, nm, or "statute miles")

After fixing all that, we get:

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

Note: After fixing problems 1 and 2, this is the "spherical law of cosines" as usually implemented.
It is OK for applications like "distance between two US zipcodes".

Caveat 1: It is not precise for small distances like from your front door to the street, so much so that it can give a non-zero distance or raise an exception (cos_x > 1.0) if the two points are identical; this situation can be special-cased.

Caveat 2: If the two points are antipodal (straight line path passes through the center of the earth), it can raise an exception (cos_x < -1.0). Anyone worried about that can check cos_x before doing acos(cos_x).

Example:

SFO (37.676, -122.433) to NYC (40.733, -73.917)

calcDist -> 2570.7758043869976
calc_dist -> 5038.599866130089
calc_dist_fixed -> 2570.9028268899356

A US government website (http://www.nhc.noaa.gov/gccalc.shtml) -> 2569

This website (http://www.timeanddate.com/worldclock/distanceresult.html?p1=179&p2=224), from which I got the SFO and NYC coordinates, -> 2577

Smile简单爱 2024-10-19 04:08:31

根据 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) 的更正。

Following tcarobruce's suggestion, here is my above comment as an answer:

The Zip Code Database Project has a database of the latitudes and longitudes of the US zip codes, either as SQL or as CSV. They also provide the following code for distance calculation (slighlty edited by me):

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

Note that the result is given in statute miles.

Edit: Corrections due to John Machin.

怎樣才叫好 2024-10-19 04:08:31

http://code.google.com/apis/maps/documentation/directions/

您可以为每个地点提供指示。给出了总距离。 API似乎输出JSON;您可以在服务器端解析答案,也可以通过 JavaScript 计算距离。

http://code.google.com/apis/maps/documentation/directions/

You could do directions for each location. The total distance is given. The API seems to output JSON; you could either parse the answer on the server side or have the distance calculated by JavaScript.

倦话 2024-10-19 04:08:31

另一种简单的方法:

下面的函数在根据邮政编码计算纬度和经度后返回两个位置之间的距离。

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

Another simple way:

Below function returns distance between two location after calculating latitudes and longitudes from zipcode.

lat1, long1 are the latitudes and longitudes of first location.

lat2, long2 are the latitudes and longitudes of second location.

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文