phplatitude-longitudeusort

Sorting PHP array by closest location


I have an array with parcel machines from Paysera:

Array
(
    [0] => Array
        (
            [id] => PMFOzGmlcQ-9GmEt5vj9JTGals_1nI87Lm
            [shipment_gateway_code] => lp
            [code] => 0199
            [address] => Array
                (
                    [country] => LT
                    [city] => Vilnius
                    [street] => Žirmūnų g. 48A
                    [postal_code] => 09226
                )

            [coordinates] => Array
                (
                    [latitude] => 54.70274
                    [longitude] => 25.30368
                )

            [location_name] => Express Market
            [enabled] => 1
        )

    [1] => Array
        (
            [id] => PMBBGl0TsF1vuv8YqeLsn4gyWwGB9-vd98
            [shipment_gateway_code] => lp
            [code] => 0198
            [address] => Array
                (
                    [country] => LT
                    [city] => Vilnius
                    [street] => Lazdynėlių g. 23
                    [postal_code] => 04126
                )

            [coordinates] => Array
                (
                    [latitude] => 54.66283
                    [longitude] => 25.19253
                )

            [location_name] => Maxima
            [enabled] => 1
        )
)

Also I have user's coordinates in array:

Array
    (
        [latitude] => 54.70274
        [longitude] => 25.30368
    )

I have to sort my first array by the nearest location to my user but I don't really understand how to do it.

I tried the following solution but it seems like it does nothing at all:

$cities = <your array>;

$point = array(
    'latitude' => 50.6000,
    'longitude' => -74.15000
);

function distance($a, $b) {
    return sqrt(
        pow($a['latitude'] - $b['latitude'], 2)
        + pow($a['longitude'] - $b['longitude'], 2));
}

usort($cities, function($p, $q) {
    global $point;
    return distance($p, $point) - distance($q, $point);
});

Please help me to achieve my goal. Thanks!


Solution

  • As far as I understood from the comments above and from the Wikipedia the Vincenty's formula is the most accurate formula for calculating a distance.

    So I came up with the following code:

    $arParcelMachines = Array(); // $arParcelMachines is an array of parcell machines from Paysera
    
    if ($latitude && $longitude) { // $latitude && $longitude are user's coordinates
        foreach ($arParcelMachines as &$arParcelMachine) {
            $arParcelMachine["distance"] = getDistance($latitude, $longitude, $arParcelMachine["coordinates"]["latitude"], $arParcelMachine["coordinates"]["longitude"]);
        }
    
        usort($arParcelMachines, function($a, $b) {
            return $a["distance"] - $b["distance"];
        });
    }
    
    function getDistance($fromLatitude, $fromLongitude, $toLatitude, $toLongitude, $radius = 6371000) { // Vincenty's formula
        $fromLatitude = deg2rad($fromLatitude);
        $fromLongitude = deg2rad($fromLongitude);
        $toLatitude = deg2rad($toLatitude);
        $toLongitude = deg2rad($toLongitude);
      
        $deltaLongitude = abs($fromLongitude - $toLongitude);
      
        $centralAngle = atan2(sqrt(pow(cos($toLatitude) * sin($deltaLongitude), 2) + pow(cos($fromLatitude) * sin($toLatitude) - sin($fromLatitude) * cos($toLatitude) * cos($deltaLongitude), 2)), sin($fromLatitude) * sin($toLatitude) + cos($fromLatitude) * cos($toLatitude) * cos($deltaLongitude));
        
        return $radius * $centralAngle;
    }