0

I have a series of functions used to calculate the closest driving distance from the target address to one of my several locations and for the most part it works well. It first gets my closest location as the crow flies, then uses that address to calculate the actual driving distance to the target address and this is where the problem is. Sometimes the as the crow flies distance is far closer to one location but closer to drive from another so how can I calculate the driving distance from the start and skip the as the crow flies calculation?

// Provides "as the crow flies" distance from my closest location to target address
function closestLocation($Address) {
    $values = locationFromAddress($Address);
    $center_lat = $values[0];
    $center_lng = $values[1];   
    // My locations
    $query = sprintf("SELECT ID, Address, (3959 * acos(cos(radians('%s')) * cos(radians(lat)) * cos(radians(lng) - radians('%s')) + sin(radians('%s')) * sin( radians(lat)))) AS Distance 
    FROM locations 
    WHERE Address > 0 AND lat <> 0 AND lng <> 0 
    ORDER BY Distance ASC
    LIMIT 1",
      $center_lat,
      $center_lng,
      $center_lat);
    $rowCat = DBConnect($query, "Select", "pchome_geoip");

    // Returns array of the location
    return $rowCat;
}

You can see that the query simply uses the latitude and longitude stored in the database to calculate it using the latitude and longitude of the target address provided by locationFromAddress() function:

function locationFromAddress($Address) {
    $Address = urlencode($Address);
    if ($Address) :
        $geocode = file_get_contents("http://maps.google.com/maps/api/geocode/json?address=$Address&sensor=false");
        $output = json_decode($geocode);
        $lat = $output->results[0]->geometry->location->lat;
        $long = $output->results[0]->geometry->location->lng;
        return array($lat,$long);
    else:
        return "";
  endif;
}

And then the details are used to calculate the driving distance using the Google API:

function compareDistance($unit,$inLatitude,$inLongitude,$outLatitude,$outLongitude) {
    $url = "http://maps.googleapis.com/maps/api/directions/json?origin=$inLatitude,$inLongitude&destination=$outLatitude,$outLongitude&sensor=false";

    // Retrieve the URL contents
    $c = curl_init();
    curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($c, CURLOPT_URL, $url);
    $jsonResponse = curl_exec($c);
    curl_close($c);

    $dataset = json_decode($jsonResponse);
    if(!$dataset)
        return 0;
    if(!isset($dataset->routes[0]->legs[0]->distance->value))
        return 0;
    $miles = ($dataset->routes[0]->legs[0]->distance->value * .00062);
    // Google API returns meters, multiplied by .00062 to get miles

    // Round up to nearest unit
    if ($unit == "K") :
        return ceil($miles * 1.609344);
    elseif ($unit == "N") :
        return ceil($miles * 0.8684);
    else :
        return ceil($miles);
    endif;
}

function getDrivingDistance($myAddress, $custAddress, $unit) {
    // 'M' is statute miles
    // 'K' is kilometers
    // 'N' is nautical miles
    // Get accurate latitude and longitude based on actual location
    $myValues = locationFromAddress($myAddress);
    $myLat = $myValues[0];
    $myLng = $myValues[1];  

    $custValues = locationFromAddress($custAddress);
    $custLat = $custValues[0];
    $custLng = $custValues[1];

    // Returns actual driving distance
    return compareDistance($unit,$myLat,$myLng,$custLat,$custLng);
}

Also, is there an API parameter for closest rather than fastest route?

DonP
  • 725
  • 1
  • 8
  • 27
  • related question: [How to find optimal route to one of many markers?](https://stackoverflow.com/questions/11345165/how-to-find-optimal-route-to-one-of-many-markers) – geocodezip Aug 07 '17 at 19:38
  • possible duplicate of [Google Maps API - Getting closest points to zipcode](https://stackoverflow.com/questions/17280787/google-maps-api-getting-closest-points-to-zipcode) – geocodezip Aug 07 '17 at 19:40
  • On the related questions, the answer to one is exactly what I am trying to avoid: the direct line _as the crow flies_ calculation. The other is by ZIP which is not specific enough for my needs. – DonP Aug 07 '17 at 20:01
  • You don't have to use the zip code. They both use the direct line distance to reduce the number of candidates to a small number (which you might not need to do), then use the distance matrix or distance service to get the driving distance for those candidates. – geocodezip Aug 07 '17 at 20:13
  • I'm using the direct line distance now to initially fetch my closest location and that is the problem that I am trying to fix. Some mountainous communities surrounding our valley are much closer by direct line to my home in the valley than they are to my home at the coast as it's necessary to go to the coast in order to get into the mountains, and it is calculating it from my valley home because it determined it to be closer when it is not. – DonP Aug 07 '17 at 21:16
  • That is why you need to use driving distance as the final determination. – geocodezip Aug 07 '17 at 21:25
  • That's what I am doing but it is basing it on an erroneous address that is not the closest. The direct line calculation picks the address that is the closest in direct line but it ends up making the driving distance almost twice what it should be from the other location. – DonP Aug 07 '17 at 21:36
  • None of that is clear from your question. – geocodezip Aug 07 '17 at 21:38
  • Sorry if I wasn't clear enough. My question asks _Sometimes the as the crow flies distance is far closer to one location but closer to drive from another so how can I calculate the driving distance from the start and skip the as the crow flies calculation?_ - isn't that what I just repeated here in the comments? I thought it was clear that direct line _as the crow flies_ does not always work and that that is what I am trying to avoid. – DonP Aug 07 '17 at 21:43

1 Answers1

0

I reworked this function and entirely eliminated closestLocation() and another function so it does simplify things a bit. I'll need to rearranged a few of the other areas of where this is being called but it does seem to be pulling out a valid driving distance although sometimes it's the fastest, not the closest. Is there a switch for the Google API for closest?

function getDrivingDistance($Address,$unit="M") {
    if ($Address) :
        $values = locationFromAddress($Address);
        $inLatitude = $values[0];
        $inLongitude = $values[1];  

        // Fetch all of my locations
        $sqlLocation = "SELECT ID, Address, lat, lng 
                        FROM locations";
        $rowLocation = DBConnect($sqlLocation, "Multiple", "pchome_geoip");

        // Create array of driving distances based on latidude and longitude
        foreach ($rowLocation as $key) :
            $outLatitude = $key['lat'];
            $outLongitude = $key['lng'];
            $output[] = compareDistance($inLatitude,$inLongitude,$outLatitude,$outLongitude,$unit);
        endforeach;

        //sort($output, SORT_NUMERIC);
        if (array_sum($output) > 0) :
            return min(array_diff($output,array(0)));
        else :
            return 0;
        endif;
    endif;
}
DonP
  • 725
  • 1
  • 8
  • 27
  • I updated this a bit with a conditional to prevent it from crashing if no address was supplied. Also realized that it was not necessary to sort the array elements if using min() so instead added code to pull out only the smallest non-0 result. Arrays with all 0 values were causing a crash so it was reworked to detect if the array is all 0s. In this case, there are no negative numbers so array_sum() did the trick. – DonP Aug 09 '17 at 02:31
  • If this answer resolves the question, please award yourself the green tick. – mickmackusa Mar 12 '18 at 04:06