0

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!

  • 2
    Ignoring "sort", the first step is actually getting the distance between two points in general. I haven't done this in a long time, but at a quick glance the algorithm you are using seems simpler than I remember, although I could be wrong. – Chris Haas Jul 06 '23 at 19:40
  • For calculating distance from latitude and longitude, use [`levenshtein()`](https://www.php.net/manual/en/function.levenshtein.php) – Barmar Jul 06 '23 at 20:06
  • @Barmar can you be more specific? Maybe some code example? – Viacheslav Ravdin Jul 06 '23 at 20:26
  • 1
    Sorry, that was wrong. Levenshtein is edit distance between strings. I meant Haversine: https://stackoverflow.com/questions/14750275/haversine-formula-with-php – Barmar Jul 06 '23 at 20:30
  • 1
    Or https://stackoverflow.com/questions/10053358/measuring-the-distance-between-two-coordinates-in-php – Barmar Jul 06 '23 at 21:34
  • Also, assuming that `$cities` is the first array you are showing, you'll need to access the `coordinates` index, too. Using the code above (which we don't think is correct) it would be something like `return distance($p['coordinates'], $point) - distance($q['coordinates'], $point)` I think – Chris Haas Jul 06 '23 at 21:38

1 Answers1

1

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