iPhoneDev
iPhoneDev

Reputation: 303

How to calculate distance from lat/long in php?

What I am trying to do is I have entries in the database which have a lat/long stored with them. I want to calculate the distance between users lat/long and entries lat/long (in DB). After that, I want to echo the ones with distance less than 500 meters. So far I am able to do this using foreach.

<?php
mysql_connect("localhost", "beepbee_kunwarh", "kunwar") or die('MySQL Error.');
mysql_select_db("beepbee_demotest") or die('MySQL Error.');

$Lat = $_REQUEST['Lat'];
$long = $_REQUEST['long'];

$query = mysql_query("SELECT a.*, 3956 * 2 * ASIN(SQRT( POWER(SIN(($Lat - Lat) * pi()/180 / 2), 2) + COS($Lat * pi()/180) * COS(Lat * pi()/180) *POWER(SIN(($long - long) * pi()/180 / 2), 2) )) as distance FROM userResponse GROUP BY beepid HAVING distance <= 500 ORDER by distance ASC;");
$data = array();
while ($row = mysql_fetch_array($query)) {
    $data[] = $row;
}
echo json_encode($data);
?>

Upvotes: 11

Views: 53840

Answers (9)

ahinkle
ahinkle

Reputation: 2261

For those trying to stay away from Google (and others) APIs, I've been using this one for a while.

Because the earth is round, it will have some weird results for large scale radius submissions. It will work fine for locations within ~500 miles of each other.

/**
 * The max Latitude and Longitude coordinates within a specified milage radius.
 * 
 * @param int $miles
 * @param float $longitude
 * @param float $latitude
 *
 * @return array
 */
public function getMaxCoordinates($miles = 50, $longitude, $latitude) {
    $oneDegree = 69; // 69 Miles = 1 degree

    // Calculate the minimum/maximum possible coordinates.
    $lng_min = $longitude - $miles / abs(cos(deg2rad($latitude)) * $oneDegree);
    $lng_max = $longitude + $miles / abs(cos(deg2rad($latitude)) * $oneDegree);
    $lat_min = $latitude  - ($miles / $oneDegree);
    $lat_max = $latitude  + ($miles / $oneDegree);

    return ([
        'lat_max' => $lat_max,
        'lat_min' => $lat_min,
        'lng_max' => $lng_max,
        'lng_min' => $lng_min,
        'miles'   => $miles,
    ]);
}

Upvotes: 0

sabin
sabin

Reputation: 901

Use distance-matrix google api to calculate distance between latitude and longitude.

$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, 
    'https://maps.googleapis.com/maps/api/distancematrix/json?origins='.$prev_add.'&destinations='.$curr_add.'&key=keyyouhavetogenerate'
);
$content = curl_exec($ch);
$array = json_decode($content);
$obj = json_decode($content, TRUE);

$distance = $obj['rows'][0]['elements'][0]['distance']['text'];

to use this api you will need key,to know more about how to generate key visit https://developers.google.com/maps/documentation/distance-matrix/intro

Upvotes: 0

Riajul Islam
Riajul Islam

Reputation: 1483

Simple and easiest way

<?php
    $lat1 = Yourstart_latitude;
    $lon1 = Yourstart_longitude;
    $lat2 = Yourend_latitude;
    $lon2 = Yourend_longitude;
    $theta = $lon1 - $lon2;
    $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
                              $dist = acos($dist);
                              $dist = rad2deg($dist);
                              $miles= $dist * 60 * 1.1515;
                              $unit = 'K';
                                $km   = $miles*1.609344;
                              echo number_format($km,1);
                            ?>

Upvotes: 0

Roman Losev
Roman Losev

Reputation: 1941

Tested like 3 functions and 3 queries and only one showed good distance:

In meters:

SELECT *,
(
    (((acos(sin((".$latitude."*pi()/180)) * sin((`latitude`*pi()/180))+cos((".$latitude."*pi()/180))    * cos((`latitude`*pi()/180)) * cos(((".$longitude."- `longitude`)*pi()/180))))*180/pi())*60*1.1515*1.609344) 
    * 1000
) as `distance`
FROM `table`
ORDER BY `distance` ASC

In kilometers:

SELECT *,
(
    (((acos(sin((".$latitude."*pi()/180)) * sin((`latitude`*pi()/180))+cos((".$latitude."*pi()/180))    * cos((`latitude`*pi()/180)) * cos(((".$longitude."- `longitude`)*pi()/180))))*180/pi())*60*1.1515*1.609344) 
) as `distance`
FROM `table`
ORDER BY `distance` ASC

Upvotes: 1

andrewchan2022
andrewchan2022

Reputation: 5310

http://www.geodatasource.com/developers/php

<?php

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::                                                                         :*/
/*::  This routine calculates the distance between two points (given the     :*/
/*::  latitude/longitude of those points). It is being used to calculate     :*/
/*::  the distance between two locations using GeoDataSource(TM) Products    :*/
/*::                                                                         :*/
/*::  Definitions:                                                           :*/
/*::    South latitudes are negative, east longitudes are positive           :*/
/*::                                                                         :*/
/*::  Passed to function:                                                    :*/
/*::    lat1, lon1 = Latitude and Longitude of point 1 (in decimal degrees)  :*/
/*::    lat2, lon2 = Latitude and Longitude of point 2 (in decimal degrees)  :*/
/*::    unit = the unit you desire for results                               :*/
/*::           where: 'M' is statute miles                                   :*/
/*::                  'K' is kilometers (default)                            :*/
/*::                  'N' is nautical miles                                  :*/
/*::  Worldwide cities and other features databases with latitude longitude  :*/
/*::  are available at http://www.geodatasource.com                          :*/
/*::                                                                         :*/
/*::  For enquiries, please contact [email protected]                  :*/
/*::                                                                         :*/
/*::  Official Web site: http://www.geodatasource.com                        :*/
/*::                                                                         :*/
/*::         GeoDataSource.com (C) All Rights Reserved 2014                  :*/
/*::                                                                         :*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
function distance($lat1, $lon1, $lat2, $lon2, $unit) {

  $theta = $lon1 - $lon2;
  $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
  $dist = acos($dist);
  $dist = rad2deg($dist);
  $miles = $dist * 60 * 1.1515;
  $unit = strtoupper($unit);

  if ($unit == "K") {
    return ($miles * 1.609344);
  } else if ($unit == "N") {
      return ($miles * 0.8684);
    } else {
        return $miles;
      }
}

echo distance(32.9697, -96.80322, 29.46786, -98.53506, "M") . " Miles<br>";
echo distance(32.9697, -96.80322, 29.46786, -98.53506, "K") . " Kilometers<br>";
echo distance(32.9697, -96.80322, 29.46786, -98.53506, "N") . " Nautical Miles<br>";

?>

Upvotes: 5

Ragnar
Ragnar

Reputation: 4578

This query was perfect for me:

$latitude = "23.139422";  //your current lat
$longitude = "-82.382617"; //your current long

SELECT ( 3959 * acos( cos( radians( '.$latitude.' ) ) * cos( radians( latitude ) ) * 
 cos( radians( longitude ) - radians( '.$longitude.' ) ) + sin( radians( '.$latitude.' )
 ) * sin( radians( latitude ) ) ) ) AS distance from TABLE 
 HAVING distance <= 100 ORDER BY distance ASC

Upvotes: 0

tony gil
tony gil

Reputation: 9574

i would not recommend dumping distance calculations in your sql statement, even though i admit that the solution presented by 'denil' is ingenious.

there are 3 downsides: code maintenance, sql server overload AND (above all) the earth is not symmetrical (it is like an old dented baseball that was run over by a truck). this means that you might want to change the code in the future (there are some VERY sophisticated algorithms out there - http://en.wikipedia.org/wiki/Geographical_distance).

i recommend using a separate function that calculates distance with a simple common algorithm (similar if not identical to denil's). i submit this code which is pure php (no need to use googlemaps api):

<?php

function distanceGeoPoints ($lat1, $lng1, $lat2, $lng2) {

    $earthRadius = 3958.75;

    $dLat = deg2rad($lat2-$lat1);
    $dLng = deg2rad($lng2-$lng1);


    $a = sin($dLat/2) * sin($dLat/2) +
       cos(deg2rad($lat1)) * cos(deg2rad($lat2)) *
       sin($dLng/2) * sin($dLng/2);
    $c = 2 * atan2(sqrt($a), sqrt(1-$a));
    $dist = $earthRadius * $c;

    // from miles
    $meterConversion = 1609;
    $geopointDistance = $dist * $meterConversion;

    return $geopointDistance;
}

// YOUR CODE HERE
echo distanceGeoPoints(22,50,22.1,50.1);

?>

there are a number of free softwares (try gps trackmaker) that will allow you to check the margin of error for your part of the globe (if you need precision). for the above lat/long pair, the error is within +/- 0.1% (according to local topographers).

ATTENTION: this formula gives you CARTOGRAPHIC distance (distance at sea level), not TOPOGRAPHIC distance (disconsiders topography).

Upvotes: 17

Latox
Latox

Reputation: 4705

I did this a few weeks ago.

This link is your best bet:

http://code.google.com/apis/maps/articles/phpsqlsearch.html

Even if you don't use their API, their PHP and SQL query helped really well.

Upvotes: 15

denil
denil

Reputation: 690

Try this query. I found this one when googling but forgot who created it

SELECT a.*,
            3956 * 2 * ASIN(SQRT( POWER(SIN(($lat - lat) * pi()/180 / 2), 2) + COS($lat * pi()/180) * COS(lat * pi()/180) *
            POWER(SIN(($long - longi) * pi()/180 / 2), 2) )) as
            distance FROM table
            GROUP BY id HAVING distance <= 500 ORDER by distance ASC

$lat and $long variable is the current position of user. lat and longi is the latitude and longitudle of entries

Upvotes: 8

Related Questions