Google map direction services waypoints more than 50
Asked Answered
R

5

12

Documentation says that waypoints limit is 8 points. But I have to find best waypoints order list from more than 50 waypoints. How to do that?

I am able to find waypoints order by using Start + Destination + 8 Waypoints But I need help for more than 50 Waypoints

Rimskykorsakov answered 26/2, 2014 at 10:23 Comment(1)
Currently, in 2016, the documentation says that maximum number of waypoints in Directions API web service is 23.Chair
V
16

function initMap() {
    var service = new google.maps.DirectionsService;
    var map = new google.maps.Map(document.getElementById('map'));

    // list of points
    var stations = [
        {lat: 48.9812840, lng: 21.2171920, name: 'Station 1'},
        {lat: 48.9832841, lng: 21.2176398, name: 'Station 2'},
        {lat: 48.9856443, lng: 21.2209088, name: 'Station 3'},
        {lat: 48.9861461, lng: 21.2261563, name: 'Station 4'},
        {lat: 48.9874682, lng: 21.2294855, name: 'Station 5'},
        {lat: 48.9909244, lng: 21.2295512, name: 'Station 6'},
        {lat: 48.9928871, lng: 21.2292352, name: 'Station 7'},
        {lat: 48.9921334, lng: 21.2246742, name: 'Station 8'},
        {lat: 48.9943196, lng: 21.2234792, name: 'Station 9'},
        {lat: 48.9966345, lng: 21.2221262, name: 'Station 10'},
        {lat: 48.9981191, lng: 21.2271386, name: 'Station 11'},
        {lat: 49.0009168, lng: 21.2359527, name: 'Station 12'},
        {lat: 49.0017950, lng: 21.2392890, name: 'Station 13'},
        {lat: 48.9991912, lng: 21.2398272, name: 'Station 14'},
        {lat: 48.9959850, lng: 21.2418410, name: 'Station 15'},
        {lat: 48.9931772, lng: 21.2453901, name: 'Station 16'},
        {lat: 48.9963512, lng: 21.2525850, name: 'Station 17'},
        {lat: 48.9985134, lng: 21.2508423, name: 'Station 18'},
        {lat: 49.0085000, lng: 21.2508000, name: 'Station 19'},
        {lat: 49.0093000, lng: 21.2528000, name: 'Station 20'},
        {lat: 49.0103000, lng: 21.2560000, name: 'Station 21'},
        {lat: 49.0112000, lng: 21.2590000, name: 'Station 22'},
        {lat: 49.0124000, lng: 21.2620000, name: 'Station 23'},
        {lat: 49.0135000, lng: 21.2650000, name: 'Station 24'},
        {lat: 49.0149000, lng: 21.2680000, name: 'Station 25'},
        {lat: 49.0171000, lng: 21.2710000, name: 'Station 26'},
        {lat: 49.0198000, lng: 21.2740000, name: 'Station 27'},
        {lat: 49.0305000, lng: 21.3000000, name: 'Station 28'},
    ];
    
    // Zoom and center map automatically by stations (each station will be in visible map area)
    var lngs = stations.map(function(station) { return station.lng; });
    var lats = stations.map(function(station) { return station.lat; });
    map.fitBounds({
        west: Math.min.apply(null, lngs),
        east: Math.max.apply(null, lngs),
        north: Math.min.apply(null, lats),
        south: Math.max.apply(null, lats),
    });
    
    // Show stations on the map as markers
    for (var i = 0; i < stations.length; i++) {
        if (!stations[i].name)
            continue;
        new google.maps.Marker({
            position: stations[i],
            map: map,
            title: stations[i].name
        });
    }

    // Divide route to several parts because max stations limit is 25 (23 waypoints + 1 origin + 1 destination)
    for (var i = 0, parts = [], max = 8 - 1; i < stations.length; i = i + max)
        parts.push(stations.slice(i, i + max + 1));

    // Callback function to process service results
    var service_callback = function(response, status) {
        if (status != 'OK') {
            console.log('Directions request failed due to ' + status);
            return;
        }
        var renderer = new google.maps.DirectionsRenderer;
        renderer.setMap(map);
        renderer.setOptions({ suppressMarkers: true, preserveViewport: true });
        renderer.setDirections(response);
    };
        
    // Send requests to service to get route (for stations count <= 25 only one request will be sent)
    for (var i = 0; i < parts.length; i++) {
        // Waypoints does not include first station (origin) and last station (destination)
        var waypoints = [];
        for (var j = 1; j < parts[i].length - 1; j++)
            waypoints.push({location: parts[i][j], stopover: false});
        // Service options
        var service_options = {
            origin: parts[i][0],
            destination: parts[i][parts[i].length - 1],
            waypoints: waypoints,
            travelMode: 'WALKING'
        };
        // Send request
        service.route(service_options, service_callback);
    }
  }
html, body {
    height: 100%;
    margin: 0;
    padding: 0;
}
#map {
    height: 100%;     
    width: 100%;
    height: 100%;
}
<div id="map"></div>

<!-- without API KEY set variable "max" to 8 -->
<script async defer src="https://maps.googleapis.com/maps/api/js?callback=initMap"></script>

<!-- with API KEY set variable "max" to 25 -->
<!-- <script async defer src="https://maps.googleapis.com/maps/api/js?callback=initMap&key=YOUR_API_KEY"></script>-->

With following code you can use as many waypoints as you need and you will never get error MAX_WAYPOINTS_EXCEEDED. Do not forget to replace "YOUR_API_KEY" to your API KEY or remove &key=YOUR_API_KEY from google API URL and set variable "max" to 8 (max = 25 when using API KEY, max = 8 when not using API KEY).

<div id="map"></div>
<script>
  function initMap() {
    var service = new google.maps.DirectionsService;
    var map = new google.maps.Map(document.getElementById('map'));

    // list of points
    var stations = [
        {lat: 48.9812840, lng: 21.2171920, name: 'Station 1'},
        {lat: 48.9832841, lng: 21.2176398, name: 'Station 2'},
        {lat: 48.9856443, lng: 21.2209088, name: 'Station 3'},
        {lat: 48.9861461, lng: 21.2261563, name: 'Station 4'},
        {lat: 48.9874682, lng: 21.2294855, name: 'Station 5'},
        {lat: 48.9909244, lng: 21.2295512, name: 'Station 6'},
        {lat: 48.9928871, lng: 21.2292352, name: 'Station 7'},
        {lat: 48.9921334, lng: 21.2246742, name: 'Station 8'},
        {lat: 48.9943196, lng: 21.2234792, name: 'Station 9'},
        {lat: 48.9966345, lng: 21.2221262, name: 'Station 10'},
        {lat: 48.9981191, lng: 21.2271386, name: 'Station 11'},
        {lat: 49.0009168, lng: 21.2359527, name: 'Station 12'},
        {lat: 49.0017950, lng: 21.2392890, name: 'Station 13'},
        {lat: 48.9991912, lng: 21.2398272, name: 'Station 14'},
        {lat: 48.9959850, lng: 21.2418410, name: 'Station 15'},
        {lat: 48.9931772, lng: 21.2453901, name: 'Station 16'},
        {lat: 48.9963512, lng: 21.2525850, name: 'Station 17'},
        {lat: 48.9985134, lng: 21.2508423, name: 'Station 18'},
        {lat: 49.0085000, lng: 21.2508000, name: 'Station 19'},
        {lat: 49.0093000, lng: 21.2528000, name: 'Station 20'},
        {lat: 49.0103000, lng: 21.2560000, name: 'Station 21'},
        {lat: 49.0112000, lng: 21.2590000, name: 'Station 22'},
        {lat: 49.0124000, lng: 21.2620000, name: 'Station 23'},
        {lat: 49.0135000, lng: 21.2650000, name: 'Station 24'},
        {lat: 49.0149000, lng: 21.2680000, name: 'Station 25'},
        {lat: 49.0171000, lng: 21.2710000, name: 'Station 26'},
        {lat: 49.0198000, lng: 21.2740000, name: 'Station 27'},
        {lat: 49.0305000, lng: 21.3000000, name: 'Station 28'},
        // ... as many other stations as you need
    ];

    // Zoom and center map automatically by stations (each station will be in visible map area)
    var lngs = stations.map(function(station) { return station.lng; });
    var lats = stations.map(function(station) { return station.lat; });
    map.fitBounds({
        west: Math.min.apply(null, lngs),
        east: Math.max.apply(null, lngs),
        north: Math.min.apply(null, lats),
        south: Math.max.apply(null, lats),
    });

    // Show stations on the map as markers
    for (var i = 0; i < stations.length; i++) {
        new google.maps.Marker({
            position: stations[i],
            map: map,
            title: stations[i].name
        });
    }

    // Divide route to several parts because max stations limit is 25 (23 waypoints + 1 origin + 1 destination)
    for (var i = 0, parts = [], max = 25 - 1; i < stations.length; i = i + max)
        parts.push(stations.slice(i, i + max + 1));

    // Service callback to process service results
    var service_callback = function(response, status) {
        if (status != 'OK') {
            console.log('Directions request failed due to ' + status);
            return;
        }
        var renderer = new google.maps.DirectionsRenderer;
        renderer.setMap(map);
        renderer.setOptions({ suppressMarkers: true, preserveViewport: true });
        renderer.setDirections(response);
    };

    // Send requests to service to get route (for stations count <= 25 only one request will be sent)
    for (var i = 0; i < parts.length; i++) {
        // Waypoints does not include first station (origin) and last station (destination)
        var waypoints = [];
        for (var j = 1; j < parts[i].length - 1; j++)
            waypoints.push({location: parts[i][j], stopover: false});
        // Service options
        var service_options = {
            origin: parts[i][0],
            destination: parts[i][parts[i].length - 1],
            waypoints: waypoints,
            travelMode: 'WALKING'
        };
        // Send request
        service.route(service_options, service_callback);
    }
  }
</script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"></script>
Verified answered 17/4, 2017 at 19:59 Comment(6)
This doesn't work as you "divide the route to several parts", but those parts are chunks of 25 completely arbitrary points. There's no guarantee that the points you randomly bunched into groups of 25 are even close to eachother. In fact, if you could be sure that point[i] was close to point[i+1] there wouldn't be a need to optimize the route at all.Jujube
Points optimization in my case was not needed. Points in my case are known and I just needed to connect it (points are public transport vehicle stations and they usually goes from one to another in row). It depends on purpose. In many cases it is suitable solution but I agree that not for 100% cases. By upvotes in this answer and this https://mcmap.net/q/388694/-exceed-23-waypoint-per-request-limit-on-google-directions-api-business-work-level including positive comments it helped many users. There is no other better way until google increase limit.Verified
The question asks "to find best waypoints order" which this answer won't do.Jujube
I think there could be a solution. In my case points usually goes one to another in row (because of bus stations points are already optimized) so my solution works well. In case points are random you should sort it by distance first - e.g. using haversine algorithm https://mcmap.net/q/80593/-calculate-distance-between-2-gps-coordinates or there are easier + faster algorithms usable when all points are in radius several kilometers (can assume that earth is flat). When points are sorted by distance (not random) there is a high probability to get correct result when passing points to my solution which splits route to parts.Verified
Sorting by distance to what? To your reference point? Then you sort them by radius in a sphere/circle around you, after just 1km distance sorting, the points will be 0 to 2 radii (2km) away from eachother depending on the direction they are located at from you. If you sort each point by the distance to the previous closest point then you have an O(n^2) algorithm that does a random walk, better just do a random walk then. The travelling salesman problem cannot be solved like this. It's notorious complexity to solve is exactly why the waypoints are so limitedJujube
Sorry, I don't mean to come down on you hard. It was important to me to point out this won't yield optimized routes.Jujube
F
3

I've created a workaround but it is a bit more expensive (in terms of API calls) to use.

Instead of creating a single call with the start, end, and waypoints LatLngs, I split the waypoints into pairs make the calls per pair.

Example:

Problem: Route and get Directions for 100 points

Solution:

  • Call 1: Point 1 and Point 2
  • Call 2: Point 2 and Point 3
  • Call 3: Point 3 and Point 4

    ... and so on.

With this solution you'll never have to worry about the 8 waypoint limitation since you're only making a 2 point query every time. The weakness of this solution is you will be creating a lot of calls and it will eat up your 2500 free calls per day if not used properly.

Fabrizio answered 4/8, 2014 at 7:3 Comment(3)
Yes, You are right. This process will spend all available free calls limit. In my case there is going to have 19K-20K points per day. So this solution is not going to help me.Rimskykorsakov
What about optimizing the route? Anything for that?Melano
HI, Google usually does its own route optimizations on the fly based on your passed parameters.Fabrizio
L
1

Ufortunately it is not possible to do.

I'f you have a business account you can add up to around 25 waypoints. A business account is quite expensive.

You need to look for another vendor if you need to use more than 25 waypoints.

Laevorotation answered 26/2, 2014 at 10:45 Comment(0)
L
1

I have found this workaround.

It seems like it does exactly what you need. take a look: http://lemonharpy.wordpress.com/2011/12/15/working-around-8-waypoint-limit-in-google-maps-directions-api/

Laevorotation answered 26/2, 2014 at 10:53 Comment(1)
This wont help in my situation because this doesn't give accurate waypoints order for best help for driver directionRimskykorsakov
A
1

HERE Maps (https://developer.here.com/blog/delivery-made-easy-with-the-here-waypoint-sequence-api) offers Waypoints Optimization up to 120 waypoints. Check them out, their prices are very reasonable as well

Atomic answered 30/10, 2016 at 1:33 Comment(3)
Your link is broken.Jujube
Fixed to the updated link. Thanks for bringing to my attention Robin. Please upvote my answer as I cannot remove your downvote. :)Atomic
It wasn't me that downvoted it ;) I followed the link to find out why someone would downvote it. You can also improve the quality of your answer by providing a short code example on waypoints with the HERE API. (Then I'll upvote it myself)Jujube

© 2022 - 2024 — McMap. All rights reserved.