{"id":221,"date":"2019-01-28T12:40:20","date_gmt":"2019-01-28T04:40:20","guid":{"rendered":"https:\/\/www.intelliwolf.com\/?p=221"},"modified":"2021-03-09T12:28:43","modified_gmt":"2021-03-09T04:28:43","slug":"find-nearest-location-from-array-of-coordinates-php","status":"publish","type":"post","link":"https:\/\/wordpress-757293-2559390.cloudwaysapps.com\/find-nearest-location-from-array-of-coordinates-php\/","title":{"rendered":"Find The Nearest Location From An Array of Coordinates In PHP"},"content":{"rendered":"\n

As I discussed in previous tutorials, we have the visitor's latitude and longitude<\/a>, and an array of locations<\/a>. Now we can combine the two to figure out which location in that array is closest to our starting coordinates.<\/p>\n\n\n\n

What is the fastest way to find the nearest location out of an array of coordinates?<\/strong><\/p>\n\n\n\n

  1. Import the array of coordinates<\/li>
  2. Based on the array of coordinates, create another array of the respective distances from the initial location<\/li>
  3. Sort the second array from smallest to largest<\/li>
  4. Use the key of the first array element from the second array to get the details of the closest location from the first array<\/li><\/ol>\n\n\n\n

    Phew that list sounds a bit daunting! Let's see the code first:<\/p>\n\n\n\n

    $locations = array (\n array (\n  \"postcode\" => \"2850\",\n  \"name\" => \"Aarons Pass\",\n  \"state_code\" => \"NSW\",\n  \"lat\" => \"-32.86328\",\n  \"lng\" => \"149.80375\"\n ),\n array (\n  \"postcode\" => \"6280\",\n  \"name\" => \"Abba River\",\n  \"state_code\" => \"WA\",\n  \"lat\" => \"-33.68488\",\n  \"lng\" => \"115.46334\"\n ),\n array (\n  \"postcode\" => \"6280\",\n  \"name\" => \"Abbey\",\n  \"state_code\" => \"WA\",\n  \"lat\" => \"-33.66077\",\n  \"lng\" => \"115.25863\"\n )\n ...\n);\n\n$base_location = array(\n  'lat' => \"-31.959138\",\n  'lng' => \"115.858072\"\n);\n\n$distances = array();\n\nforeach ($locations as $key => $location)\n{\n  $a = $base_location['lat'] - $location['lat'];\n  $b = $base_location['lng'] - $location['lng'];\n  $distance = sqrt(($a**2) + ($b**2));\n  $distances[$key] = $distance;\n}\n\nasort($distances);\n\n$closest = $locations[key($distances)];\n\necho \"Closest foreach suburb is: \" . $closest['name'];<\/code><\/pre>\n\n\n\n

    Not so daunting after all. Let's explore what's happening in the code.<\/p>\n\n\n\n

    Import the array of coordinates<\/h2>\n\n\n\n

    In my earlier post on importing a CSV file into an array<\/a>, I covered a quick way to import a lot of data to an array.<\/p>\n\n\n\n

    I've written the code as above for this tutorial simply for clarity. Because there are so many suburbs in the $locations<\/em> array, I actually put it in a file called locations.php<\/em> and called it using:<\/p>\n\n\n\n

    require('locations.php');<\/code><\/pre>\n\n\n\n

    That does the same thing. It just makes it easier to manage.<\/p>\n\n\n\n

    Based on the array of coordinates, create another array of the respective distances from the initial location<\/h2>\n\n\n\n

    The guts of this code is turning $locations<\/em> into an array of distances from the base coordinates. I've called that array $distances<\/em>.<\/p>\n\n\n\n

    The key<\/em> of each element in $distances<\/em> will be the same as the key for that same element in $locations<\/em>. This is essential<\/strong> for this code to function later.<\/p>\n\n\n\n

    We start with our initial location:<\/p>\n\n\n\n

    $base_location = array(\n  'lat' => \"-31.959138\",\n  'lng' => \"115.858072\"\n);<\/code><\/pre>\n\n\n\n

    You might pull this in dynamically using $_GET<\/em>.<\/p>\n\n\n\n

    You might also use it on the fly with an AJAX<\/em> call from jQuery based on the visitor's location. I wrote about how to get that here<\/a>.<\/p>\n\n\n\n

    Next comes the algorithm for calculating the distance from the base location.<\/p>\n\n\n\n

    I've tested this quite extensively in preparation for this tutorial. Pythagorean Theorem<\/strong> was the fastest and best suited to this project.<\/p>\n\n\n\n

    See the end of this tutorial for how the tests performed and the code for the other formulae.<\/p>\n\n\n\n

    The code for looping over each $locations<\/em> location and calculating how far it is from $base_location<\/em> is:<\/p>\n\n\n\n

    $distances = array();\n\nforeach ($locations as $key => $location)\n{\n  $a = $base_location['lat'] - $location['lat'];\n  $b = $base_location['lng'] - $location['lng'];\n  $distance = sqrt(($a**2) + ($b**2));\n  $distances[$key] = $distance;\n}<\/code><\/pre>\n\n\n\n

    You could make it smaller by putting $a<\/em> and $b<\/em> into the one line, but I broke it apart to make it clear how the algorithm works.<\/p>\n\n\n\n

    If you want to use a different algorithm, swap out the first three lines inside of the foreach loop.<\/p><\/blockquote>\n\n\n\n

    Normally I'd use more descriptive variables, but years of schooling has me automatically remembering that<\/p>\n\n\n\n

    a2<\/sup> + b2<\/sup> = c2<\/sup><\/p>\n\n\n\n

    I'm sure you probably do too.<\/p>\n\n\n\n

    In case you weren't familiar with the format, $a**2<\/em> is PHP for a<\/em>2<\/em><\/sup>. This change came in with PHP 5.6, which if you're reading this, you absolutely should be using that or later.<\/p>\n\n\n\n

    If you're stuck using an earlier version of PHP, swap $a**2<\/em> for<\/p>\n\n\n\n

    pow($a, 2)<\/code><\/pre>\n\n\n\n

    After this foreach<\/em> loop has finished running, we now have an array of distances from the base location in $distances<\/em>. It will look something like this:<\/p>\n\n\n\n

    Array\n(\n  [0] => 33.957716761229\n  [1] => 1.7703103689433\n  [2] => 1.8041292012459\n  [3] => 31.298059163015\n  [4] => 36.246295056854\n  [5] => 35.0622192721\n)<\/code><\/pre>\n\n\n\n

    Note:<\/strong> these aren't actual distances in kilometres or miles. These are relative distances. They also don't take into account the curvature of the Earth. If you need actual distances, you're best to use the Haversine Formula discussed at the bottom<\/p><\/blockquote>\n\n\n\n

    Sort the second array from smallest to largest<\/h2>\n\n\n\n

    Sorting the $distances<\/em> array from smallest to largest is as simple as:<\/p>\n\n\n\n

    asort($distances);<\/code><\/pre>\n\n\n\n

    Now the array looks like this:<\/p>\n\n\n\n

    Array\n(\n  [10712] => 0.0037737207103849\n  [10026] => 0.012187097603613\n  [4258] => 0.013816152431116\n  [14330] => 0.016617217215894\n  [12192] => 0.022168618991717\n  [6076] => 0.02274286806891\n)<\/code><\/pre>\n\n\n\n

    If we were to look up $locations[10712]<\/em>, we'd find it was actually the closest location to our initial coordinates. So let's do that.<\/p>\n\n\n\n

    Use the key of the first array element from the second array to get the details of the closest location from the first array<\/h2>\n\n\n\n

    To pull the key of the first element of $distances<\/em>, we'd use the code:<\/p>\n\n\n\n

    $key = key($distances);<\/code><\/pre>\n\n\n\n

    So to use that key to find the corresponding location in $locations<\/em>, we can simply use:<\/p>\n\n\n\n

    $closest = $locations[key($distances)];<\/code><\/pre>\n\n\n\n

    In our example, our base location was -31.959138, 115.858072<\/em>, which if you check on a map is the Belltower in Perth<\/a>.<\/p>\n\n\n\n

    In my $locations<\/em> array, $locations[10712]<\/em> is Perth, or more specifically:<\/p>\n\n\n\n

    array (\n  \"postcode\" => \"6000\",\n  \"name\" => \"Perth\",\n  \"state_code\" => \"WA\",\n  \"lat\" => \"-31.9554\",\n  \"lng\" => \"115.85859\"\n)<\/code><\/pre>\n\n\n\n

    So to display the name, I just use $closest['name']<\/em>.<\/p>\n\n\n\n

    I hope you found this tutorial on how to find the nearest location from an array of coordinates useful. Read on for a discussion of the algorithms.<\/p>\n\n\n\n

    How do the distance calculation algorithms compare?<\/h2>\n\n\n\n

    The main algorithms I considered were:<\/p>\n\n\n\n