Джанго - как мне найти расстояние между двумя локациями? - PullRequest
9 голосов
/ 17 января 2011

У меня есть несколько пользователей, зарегистрированных в моем приложении Django, и я хочу просто иметь возможность определять географически расстояние между двумя пользователями на основе их почтового индекса, а затем сортировать список на основе этого.Я полагаю, что эта функциональность не встроена в Django.Я искал некоторые варианты и наткнулся на геоджанго, который, кажется, может быть излишним для моих потребностей.

Ответы [ 4 ]

18 голосов
/ 18 января 2011

Это большой жирный комментарий к коду, опубликованному в (принятом в настоящее время) ответе @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

Код, отправленный Свеном:

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 на радиус Земли в выбранных единицах (км, нм или «статутных милях»)

После исправления всего этого мы получаем:

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). Любой, кто обеспокоен этим, может проверить cos_x перед выполнением acos (cos_x). </p>

Пример: * * тысяча тридцать-один

SFO (37,676, -122,433) в Нью-Йорк (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

6 голосов
/ 17 января 2011

Следуя предложению 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

Обратите внимание, что результат указывается в уставных милях.

Редактировать: Исправления, внесенные Джоном Мачином.

0 голосов
/ 06 апреля 2016

Еще один простой способ:

Функция ниже возвращает расстояние между двумя точками после вычисления широты и долготы по почтовому индексу.

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
0 голосов
/ 17 января 2011

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

Вы можете сделать указания для каждого места. Общее расстояние указано. Кажется, API выводит JSON; Вы можете либо проанализировать ответ на стороне сервера, либо рассчитать расстояние с помощью JavaScript.

...