简体   繁体   中英

Find closest longitude and latitude in array?

I have a longitude and latitude as a string in PHP like below

49.648881
-103.575312

And I want to take that and look in an array of values to find the closest one. The array looks like

array(
'0'=>array('item1','otheritem1details....','55.645645','-42.5323'),
'1'=>array('item1','otheritem1details....','100.645645','-402.5323')
);

I want to return the array that has the closest long and lad. In this case it would be the first one (and yes I know -400 is not aa possible value).

Is there any quick and easy way to do this? I tried array searching but that didn't work.

Difference code

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;
      }
}

You need to map the distance of each item to the reference point first.

Then you sort the map and then you can tell which has the lowest (or highest if you reverse the search) distance:

$ref = array(49.648881, -103.575312);

$items = array(
    '0' => array('item1','otheritem1details....','55.645645','-42.5323'),
    '1' => array('item1','otheritem1details....','100.645645','-402.5323')
);

$distances = array_map(function($item) use($ref) {
    $a = array_slice($item, -2);
    return distance($a, $ref);
}, $items);

asort($distances);

echo 'Closest item is: ', var_dump($items[key($distances)]);

Output:

Closest item is: array(4) {
  [0]=>
  string(5) "item1"
  [1]=>
  string(21) "otheritem1details...."
  [2]=>
  string(9) "55.645645"
  [3]=>
  string(8) "-42.5323"
}

Take care you have the right order of lat and long.

The distance function (only the header slightly changed and units have been dropped):

function distance($a, $b)
{
    list($lat1, $lon1) = $a;
    list($lat2, $lon2) = $b;

    $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;
    return $miles;
}

Rather using the law of cosines for distance, you can use flat earth approximation. The flat earth equations reduce the number of trig functions in the calculation. The Δlat, Δlon is the difference between your reference point and the test point.

This formula would not be accurate for long distance navigation (thousands of miles) but for this particular problem, you aren't really interested in accurate distance, but who is the closest point to me. This is a simpler formulation that should give you that.

x = Δlon * cos(lat)   // lat/lon are in radians!
y = Δlat
distance = R * sqrt( x² + y² )  // R is radius of the earth; 
                                // typical value is 6371 km

Reference: http://www.movable-type.co.uk/scripts/latlong.html

Distance code

function distanceMeters($lat1, $lon1, $lat2, $lon2) { 
  $x = deg2rad( $lon1 - $lon2 ) * Math.cos( deg2rad( ($lat1+$lat2) /2 ) );
  $y = deg2rad( $lat1 - $lat2 ); 
  $dist = 6371000.0 * Math.sqrt( $x*$x + $y*$y );

  return $dist;
}

function deg2rad(degrees) {
  var pi = Math.PI;
  return degrees * (pi/180);
}

There is no quick and easy way to do that. You have to iterate through all elements and calculate distance between them and starting point, save the result and repeat, saving the result only if it is lower then previous.

Iterate through the array, comparing values to what you have. If the value is smaller than your currently stored value (or if you don't have a currently stored value), store that value instead, otherwise throw it away.

$closest = null;
foreach($array as $key => $value){
    $distance = //compare distance here;
    if ($closest === null || $closest > $distance) {
        $closest = $distance;
    };
};

Of course, this will be made more difficult by the fact that latitude and longitude are on a sphere, and longitudes 179 and -179 are closer than 90 and 179.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM