问题
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.
回答1:
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.
回答2:
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
回答3:
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.
回答4:
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
来源:https://stackoverflow.com/questions/4716017/django-how-can-i-find-the-distance-between-two-locations