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.
The math. dist() method returns the Euclidean distance between two points (p and q), where p and q are the coordinates of that point. Note: The two points (p and q) must be of the same dimensions.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With