Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django - how can I find the distance between two locations?

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.

like image 427
JPC Avatar asked Jan 17 '11 17:01

JPC


People also ask

How do you find the distance between two places in Python?

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.


1 Answers

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

like image 73
John Machin Avatar answered Sep 19 '22 22:09

John Machin