23

I grabbed a database of the zip codes and their langitudes/latitudes, etc from this This page. It has got the following fields:

ZIP, LATITUDE, LONGITUDE, CITY, STATE, COUNTY, ZIP_CLASS

The data was in a text file but I inserted it into a MySQL table. My question now is, how can i utilise the fields above to calculate the distance between two zip codes that a user can enter on the website? Working code in PHP will be appreciated

Ali
  • 261,656
  • 265
  • 575
  • 769
  • 5
    What is "distance"? Do you want distance "as the crow flies" / great-circle distance? Road distance? Actual 3D distance between the two points in space? – ShreevatsaR Jan 02 '09 at 21:43
  • 3
    @Shreevats: Since he is asking for a calculation using lat/long, it's safe to assume that you're not going to get road distance. Actual distance between two points in space (e.g. through the earth's body) is probably also not useful. Therefore, "as the crow flies"/great circle is most likely. – Adam Bellaire Jan 03 '09 at 00:35

5 Answers5

26

This is mike's answer with some annotations for the magic numbers. It seemed to work fine for me for some test data:

function calc_distance($point1, $point2)
{
    $radius      = 3958;      // Earth's radius (miles)
    $deg_per_rad = 57.29578;  // Number of degrees/radian (for conversion)

    $distance = ($radius * pi() * sqrt(
                ($point1['lat'] - $point2['lat'])
                * ($point1['lat'] - $point2['lat'])
                + cos($point1['lat'] / $deg_per_rad)  // Convert these to
                * cos($point2['lat'] / $deg_per_rad)  // radians for cos()
                * ($point1['long'] - $point2['long'])
                * ($point1['long'] - $point2['long'])
        ) / 180);

    return $distance;  // Returned using the units used for $radius.
}
kba
  • 19,333
  • 5
  • 62
  • 89
Adam Bellaire
  • 108,003
  • 19
  • 148
  • 163
7

It can be done with just maths...

function calc_distance($point1, $point2)
{
    $distance = (3958 * 3.1415926 * sqrt(
            ($point1['lat'] - $point2['lat'])
            * ($point1['lat'] - $point2['lat'])
            + cos($point1['lat'] / 57.29578)
            * cos($point2['lat'] / 57.29578)
            * ($point1['long'] - $point2['long'])
            * ($point1['long'] - $point2['long'])
        ) / 180);

    return $distance;
}
Greg
  • 316,276
  • 54
  • 369
  • 333
Mike Paterson
  • 409
  • 2
  • 5
  • 3
    Can you give a reference to where you took this calculation from? – Eran Galperin Jan 02 '09 at 21:00
  • 2
    Too many magic numbers, and far too much indentation to the right! – Jonathan Leffler Jan 02 '09 at 21:03
  • What unit is this returning the distance in? For a zip code which should give 10 miles, it gave something like 7892.xx (approx). How can this be converted to miles? – Ali Jan 02 '09 at 21:11
  • functions from a util class had around for years. originally found the math online long ago, dont remember where. formating preference is subjective. i do agree with the magic numbers however its not to likely that the earth is going to change sizes and break the code. – Mike Paterson Jan 02 '09 at 21:15
  • 1
    And shouldn't pi be 3.1415927 (with a 7 at the end, not a 6, since the next digit is 5? Or have I misremembered that...) – Ben Jan 02 '09 at 21:55
  • The magic numbers: 57.29578 degrees is one radian. And 3958 seems close to the Earth's radius, which is 3963 miles. [Why is the number different? And why only four significant digits when there are so many digits of π?] – ShreevatsaR Jan 03 '09 at 01:10
  • 1
    3958 is probably the mean radius: 3963 is the equatorial radius. Using a more accurate mean radius is probably meaningless given that the USA is not actually isometric to a subset of the surface of a sphere: what you'd want is a more accurate mean taken over the USA. Or use the GPS spheroid. – Steve Jessop Jan 03 '09 at 01:19
7

Check out the Haversine formula for calculating great circle distances between two points. Some more samples can be found here

Haversine formula:

  • R = earth’s radius (mean radius = 6,371km)
  • Δlat = lat2− lat1
  • Δlong = long2− long1
  • a = sin²(Δlat/2) + cos(lat1).cos(lat2).sin²(Δlong/2)
  • c = 2.atan2(√a, √(1−a))
  • d = R.c

(Note that angles need to be in radians to pass to trig functions).

Paul Dixon
  • 295,876
  • 54
  • 310
  • 348
6

You can also try hitting a web service to calc the distance. Let someone else do the heavy lifting.

https://www.zipcodeapi.com/API#distance

brendan
  • 29,308
  • 20
  • 68
  • 109
  • 3
    that would work for 2 zipcodes, but imagine trying to select the top 100 closest locations to a given zipcode, from thousands of records in the database :) – aryaxt Sep 29 '10 at 04:58
1

In your zip table you need to grab the coordinates (lat,long) for the two points for which you want to get the distance.

You can then either calculate the distance right in the SQL or with PHP. Both methods are outlined in this post:

http://dev.strategystar.net/2011/10/mysql-php-get-distance-between-two-coordinates-in-miles-kilometers/

The calculation in the example is based on the formula already discussed in this thread. It provides the radius for the earth in both miles and kilometers so it will allow you to get the distance between two points in both units.

The link above is great because the method for calculation does not include any magic numbers, just the radius of the earth!

JV-
  • 406
  • 1
  • 4
  • 11