Django, ¿cómo puedo encontrar la distancia entre dos ubicaciones?

Tengo algunos usuarios registrados en mi aplicación Django y quiero simplemente poder calcular la distancia, geográficamente, entre dos usuarios según su código postal y luego ordenar una lista en función de eso. Me imagino que esta funcionalidad no está integrada en Django. Estaba buscando algunas opciones y tropecé con geodjango que parece que podría ser una exageración para lo que son mis necesidades.

Siguiendo la sugerencia de tcarobruce, aquí está mi comentario anterior como respuesta:

El Proyecto de Base de Datos de Código Postal tiene una base de datos de las latitudes y longitudes de los códigos postales de EE. UU., Ya sea como SQL o como CSV. También proporcionan el siguiente código para el cálculo de la distancia (editado ligeramente por mí):

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 

Tenga en cuenta que el resultado se da en millas estatutarias.

Edición: Correcciones debidas a John Machin.

Este es un gran comentario sobre el código publicado en la respuesta (actualmente aceptada) por @Sven Marnach.

Código original del sitio web del proyecto zip, con sangría editada por mí:

 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 

Código publicado por 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 

Problema 1: NO FUNCIONA : necesita importar acos

Problema 2: RESPUESTAS INCORRECTAS : necesita convertir la diferencia de longitud a radianes en la segunda última línea

Problema 3: El nombre de la variable “distancia” es un nombre erróneo extremo. Esa cantidad es en realidad el cos del ángulo entre las dos líneas desde el centro de la tierra hasta los puntos de entrada. Cambiar a “cos_x”

Problema 4: No es necesario convertir el ángulo x en grados. Simplemente multiplica x por el radio de la Tierra en unidades elegidas (km, nm o “millas estatutarias”)

Después de arreglar todo eso, obtenemos:

 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 

Nota: Después de solucionar los problemas 1 y 2, esta es la “ley esférica de los cosenos” como se implementa normalmente. Está bien para aplicaciones como “distancia entre dos códigos postales de EE. UU.”.

Advertencia 1: no es preciso para distancias pequeñas como desde la puerta de entrada a la calle, tanto que puede dar una distancia distinta de cero o generar una excepción (cos_x> 1.0) si los dos puntos son idénticos; Esta situación puede ser especial.

Advertencia 2: si los dos puntos son antípodas (la línea recta pasa por el centro de la tierra), puede generar una excepción (cos_x <-1.0). Cualquier persona preocupada por eso puede verificar cos_x antes de hacer acos (cos_x).

Ejemplo:

OFS (37.676, -122.433) a NYC (40.733, -73.917)

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

Un sitio web del gobierno de EE. UU. (http://www.nhc.noaa.gov/gccalc.shtml) -> 2569

Este sitio web (http://www.timeanddate.com/worldclock/distanceresult.html?p1=179&p2=224), del cual obtuve las coordenadas SFO y NYC, -> 2577

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

Podrías hacer indicaciones para cada ubicación. Se da la distancia total. La API parece generar JSON; puede analizar la respuesta en el lado del servidor o calcular la distancia con JavaScript.

Otra forma sencilla:

La función inferior devuelve la distancia entre dos ubicaciones después de calcular latitudes y longitudes desde el código postal.

lat1 , long1 son las latitudes y longitudes de la primera ubicación.

lat2 , long2 son las latitudes y longitudes de la segunda ubicación.

 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