Thursday, April 7, 2011

MySQL Great Circle Distance (Haversine formula)

Hello All, I've got a PHP script that gets Longitude and Latitude values...then inputs them into a MySQL query. I'd really like to make it solely MySQL.

Live site can be found at http://MotoListr.com

Here's my current PHP Code:

if ($distance != "Any" && $customer_zip != "") { //get the great circle distance

    //get the origin zip code info
    $zip_sql = "SELECT * FROM zip_code WHERE zip_code = '$customer_zip'";
    $result = mysql_query($zip_sql);
    $row = mysql_fetch_array($result);
    $origin_lat = $row['lat'];
    $origin_lon = $row['lon'];

    //get the range
    $lat_range = $distance/69.172;
    $lon_range = abs($distance/(cos($details[0]) * 69.172));
    $min_lat = number_format($origin_lat - $lat_range, "4", ".", "");
    $max_lat = number_format($origin_lat + $lat_range, "4", ".", "");
    $min_lon = number_format($origin_lon - $lon_range, "4", ".", "");
    $max_lon = number_format($origin_lon + $lon_range, "4", ".", "");
    $sql .= "lat BETWEEN '$min_lat' AND '$max_lat' AND lon BETWEEN '$min_lon' AND '$max_lon' AND ";
    }

Does anyone know how to make this entirely MySQL? I've browsed the internet a bit but most of the literature on it is pretty confusing.

Best, Nick

From stackoverflow
  • From Google Code FAQ - Creating a Store Locator with PHP, MySQL & Google Maps:

    Here's the SQL statement that will find the closest 20 locations that are within a radius of 25 miles to the 37, -122 coordinate. It calculates the distance based on the latitude/longitude of that row and the target latitude/longitude, and then asks for only rows where the distance value is less than 25, orders the whole query by distance, and limits it to 20 results. To search by kilometers instead of miles, replace 3959 with 6371.

    SELECT id, ( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * sin( radians( lat ) ) ) ) AS distance 
    FROM markers HAVING distance < 25 ORDER BY distance LIMIT 0 , 20;
    
  • $greatCircleDistance = acos( cos($latitude0) * cos($latitude1) * cos($longitude0 - $longitude1) + sin($latitude0) * sin($latitude1));

    with latitude and longitude in radian.

    so

    SELECT 
      acos( 
          cos(radians( $latitude0 ))
        * cos(radians( $latitude1 ))
        * cos(radians( $longitude0 ) - radians( $longitude1 ))
        + sin(radians( $latitude0 )) 
        * sin(radians( $latitude1 ))
      ) AS greatCircleDistance 
     FROM yourTable;
    

    is your sequel query

    to get your results in Km or miles, multiply the result with the mean radius of Earth (3959 miles, 6371 Km or 3440 nautical miles)

    The thing you are calculating in your example is a bounding box. If you put your coordinate data in a spatial enabled MySQL column, you can use MySQL's build in functionality to query the data.

    SELECT 
      id
    FROM spatialEnabledTable
    WHERE 
      MBRWithin(ogc_point, GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))'))
    
  • Using the above formula I am getting big difference in distance ... The distance using maps.google.com is ~1500 but using this formula its 1240.. Can anybody tell why is this ?

    Thanks

    Pavel Chuchuva : Please ask a separate question. You can put link to your question here, as comment to the answer.

0 comments:

Post a Comment

Note: Only a member of this blog may post a comment.