An elegant way to find shortest and fastest route

2019-01-11 14:43发布

问题:

I am making a taxi fare calculator. One of the business requirements is that, the company wants the shortest and fastest route options. I know Google directionService by default searched for the fastest route. I set the "avoidhighways" option in request parameter to true in order to get the shortest route, but I am not quite happy with the result.

Anyone have a better solution than that??

回答1:

To obtain the shortest route from A to B I would suggest to make different queries with the “alternatives=true” parameter, playing with the “avoid” parameter between avoid=toll, avoid=highways, and then I would compare all results to pick the shortest route.

 directionsService = new google.maps.DirectionsService;
//avoiding tolls
            directionsService.route({
                origin: {
                    'placeId': originId
                },
                destination: {
                    'placeId': destinationId
                },
                provideRouteAlternatives: true,
                avoidTolls: true,
                travelMode: google.maps.TravelMode.DRIVING
            }, function(response, status) {
                if (status === google.maps.DirectionsStatus.OK) {
                    routesResponses.push(response);
                }
                else {
                    window.alert('Directions request failed due to ' + status);
                }
            });
            //avoiding highways
            directionsService.route({
                origin: {
                    'placeId': originId
                },
                destination: {
                    'placeId': destinationId
                },
                provideRouteAlternatives: true,
                avoidHighways: true,
                travelMode: google.maps.TravelMode.DRIVING
            }, function(response, status) {
                if (status === google.maps.DirectionsStatus.OK) {
                    routesResponses.push(response);
                }
                else {
                    window.alert('Directions request failed due to ' + status);
                }

                //Results analysis and drawing of routes
                var fastest = Number.MAX_VALUE,
                    shortest = Number.MAX_VALUE;

                routesResponses.forEach(function(res) {
                    res.routes.forEach(function(rou, index) {
                        console.log("distance of route " +index+": " , rou.legs[0].distance.value);
                        console.log("duration of route " +index+": " , rou.legs[0].duration.value);
                        if (rou.legs[0].distance.value < shortest) shortest = rou.legs[0].distance.value  ;
                        if (rou.legs[0].duration.value < fastest) fastest = rou.legs[0].duration.value  ;

                    })
                })
                console.log("shortest: ", shortest);
                console.log("fastest: ", fastest);
//painting the routes in green blue and red
                 routesResponses.forEach(function(res) {
                    res.routes.forEach(function(rou, index) {
                        new google.maps.DirectionsRenderer({
                            map:map,
                            directions:res,
                            routeIndex:index,
                            polylineOptions:{
                                strokeColor: rou.legs[0].duration.value == fastest? "red":rou.legs[0].distance.value == shortest?"darkgreen":"blue",
                                strokeOpacity: rou.legs[0].duration.value == fastest? 0.8:rou.legs[0].distance.value == shortest? 0.9: 0.5,
                                strokeWeight: rou.legs[0].duration.value == fastest? 9:rou.legs[0].distance.value == shortest? 8: 3,
                            }
                        })
                    })
                })   
            });
        }

    }


回答2:

You get three options with the alternatives=true option set. You can then search through those for both the shortest and fastest of the routes returned.



回答3:

See http://codepen.io/jasonmayes/pen/DupCH.

var shortestDistance = function() {  
    var directionsDisplay;
    var directionsService = new google.maps.DirectionsService();
    var map;
    var size = 0;
    var currentPosition;

    // An array of interesting places we want to potentially visit.
    var interestingPlaces = [
    {'title': 'Regents Park', 'latLng': new google.maps.LatLng(51.530686, -0.154753)},
    {'title': 'Hyde Park', 'latLng': new google.maps.LatLng(51.507293, -0.164022)},
    {'title': 'Green Park', 'latLng': new google.maps.LatLng(51.504088, -0.141706)},
    {'title': 'Regents Park', 'latLng': new google.maps.LatLng(51.479185, -0.159903)}
    ];

    // An array to store results from Google routing API.
    var routeResults = [];


    // Call this upon page load to set everything in motion!
    function initialize(currentLat, currentLng) {
    currentPosition = new google.maps.LatLng(currentLat, currentLng);
    directionsDisplay = new google.maps.DirectionsRenderer();
    var mapOptions = {
        zoom: 13,
        center: currentPosition
    };
    map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
    directionsDisplay.setMap(map);

    var marker = new google.maps.Marker({
            position: currentPosition,
            map: map,
            title: 'Currrently location.'
    });

    var i = interestingPlaces.length;
        while (i--) {
        interestingPlaces[i].marker = new google.maps.Marker({
        position: interestingPlaces[i].latLng,
        map: map,
        title: interestingPlaces[i].title,
        icon: 'http://maps.google.com/mapfiles/ms/icons/green.png'
        });
    }

    findNearestPlace();
    }


    // Loops through all inteesting places to calculate route between our current position
    // and that place.
    function findNearestPlace() {
    var i = interestingPlaces.length;
    size = interestingPlaces.length;
    routeResults = [];
    while (i--) {
        calcRoute(interestingPlaces[i].latLng, storeResult);
    }
    }


    // A function to calculate the route between our current position and some desired end point.
    function calcRoute(end, callback) {
    var request = {
        origin: currentPosition,
        destination: end,
        travelMode: google.maps.TravelMode.DRIVING
    };
    directionsService.route(request, function(response, status) {
        if (status == google.maps.DirectionsStatus.OK) {
        callback(response);
        } else {
        size--;
        }
    });
    }


    // Stores a routing result from the API in our global array for routes.
    function storeResult(data) {
    routeResults.push(data);
    if (routeResults.length === size) {
        findShortest();
    }
    }


    // Goes through all routes stored and finds which one is the shortest. It then
    // sets the shortest route on the map for the user to see.
    function findShortest() {
    var i = routeResults.length;
    var shortestIndex = 0;
    var shortestLength = routeResults[0].routes[0].legs[0].distance.value;

    while (i--) {
        if (routeResults[i].routes[0].legs[0].distance.value < shortestLength) {
        shortestIndex = i;
        shortestLength = routeResults[i].routes[0].legs[0].distance.value;
        }
    }
    directionsDisplay.setDirections(routeResults[shortestIndex]);
    }

    // Expose the initialize function publicly as "init".
    return {
    init: initialize
    };
}();

// Upon page load, lets start the process!
google.maps.event.addDomListener(window, 'load', shortestDistance.init(51.489554, -0.12969));

DISCLAIMER

THIS IS NOT MY PEN!!! I AM JUST REFERRING TO A USEFUL RESOURCE THAT MIGHT HELP



回答4:

First of all, sorry for my solution being in TS, you can easily convert it to JS.

The "avoidhighways" attribute is not there to get the fastest or shortest route, it's there for what the name suggests, avoiding highways.

I've made my own solution by always getting multiple routs with this attribute:

directionsService.route({
            [...]
            provideRouteAlternatives: true
            [...]
         }, (response, status) => {
            if (status === google.maps.DirectionsStatus.OK) {
                var shortest: google.maps.DirectionsResult = this.shortestRoute(response);
                this.directionsDisplay.setDirections(shortest);
                [...]

And I made this function that returns the DirectionsResult with just the one route. In this case it's the shortest, but you can tweek it so it returns what ever route suits your needs.

    shortestRoute = (routeResults: google.maps.DirectionsResult): google.maps.DirectionsResult => {
        var shortestRoute: google.maps.DirectionsRoute = routeResults.routes[0];
        var shortestLength = shortestRoute.legs[0].distance.value;
        for (var i = 1; i < routeResults.routes.length; i++) {
            if (routeResults.routes[i].legs[0].distance.value < shortestLength) {
                shortestRoute = routeResults.routes[i];
                shortestLength = routeResults.routes[i].legs[0].distance.value;
            }
        }
        routeResults.routes = [shortestRoute];
        return routeResults;
    }


回答5:

I took code from Soldeplata Saketos answer and edited it since it wasn't working. Added params so you can just call it with it like.

shortestRoute(origin, destination, map); 

Works for me all though I'm not sure how correct it is.

Here:

function shortestRoute(origin, destination, map) {

  directionsService = new google.maps.DirectionsService();
  var routesResponses = [];
  //avoiding tolls
  directionsService.route({
    origin: origin,
    destination: destination,
    provideRouteAlternatives: true,
    avoidTolls: true,
    travelMode: google.maps.TravelMode.DRIVING
  }, function (response, status) {
    if (status === google.maps.DirectionsStatus.OK) {
      routesResponses.push(response);
    } else {
      window.alert('Directions request failed due to ' + status);
    }
  });
  //avoiding highways
  directionsService.route({
    origin: origin,
    destination: destination,
    provideRouteAlternatives: true,
    avoidHighways: true,
    travelMode: google.maps.TravelMode.DRIVING
  }, function (response, status) {
    if (status === google.maps.DirectionsStatus.OK) {
      routesResponses.push(response);
    } else {
      window.alert('Directions request failed due to ' + status);
    }

    //Results analysis and drawing of routes
    var fastest = Number.MAX_VALUE,
      shortest = Number.MAX_VALUE;

    routesResponses.forEach(function (res) {
      res.routes.forEach(function (rou, index) {
        console.log("distance of route " + index + ": ", rou.legs[0].distance.value);
        console.log("duration of route " + index + ": ", rou.legs[0].duration.value);
        if (rou.legs[0].distance.value < shortest) shortest = rou.legs[0].distance.value;
        if (rou.legs[0].duration.value < fastest) fastest = rou.legs[0].duration.value;

      })
    })
    console.log("shortest: ", shortest);
    console.log("fastest: ", fastest);
    //painting the routes in green blue and red
    routesResponses.forEach(function (res) {
      res.routes.forEach(function (rou, index) {
        new google.maps.DirectionsRenderer({
          map: map,
          directions: res,
          routeIndex: index,
          polylineOptions: {
            strokeColor: rou.legs[0].duration.value == fastest ? "red" : rou.legs[0].distance.value == shortest ? "darkgreen" : "blue",
            strokeOpacity: rou.legs[0].duration.value == fastest ? 0.8 : rou.legs[0].distance.value == shortest ? 0.9 : 0.5,
            strokeWeight: rou.legs[0].duration.value == fastest ? 9 : rou.legs[0].distance.value == shortest ? 8 : 3,
          }
        });
      });
    });
  });
}


回答6:

Use optimizeWaypoints: true  in Request perameter. See below code snippet

var request ={
                origin: sStartLatLng,
                destination: sStartLatLng,
                waypoints: waypts,
                optimizeWaypoints: true,
                travelMode: google.maps.DirectionsTravelMode.DRIVING
            };