37

我想使用谷歌方向 API 为一家处理冬季扫雪机和夏季景观美化的公司开发路线规划软件。客户要求之一是他能够计算至少有 30 个(最好是更多)航路点的路线。根据文档(引用如下),即使 Google Maps API for Work 客户的每个请求也仅限于 23 个航点。

使用 Google Directions API 的查询限制为每天 2,500 个路线请求。单个路线请求在请求中最多可包含 8 个中间航路点。Google Maps API for Work 客户每天最多可以查询 100,000 个路线请求,每个请求中最多允许 23 个航点。

有没有人知道一种解决方法 - 无论如何 - 来解决这个问题?

另外——是否可以使用免费 API 的解决方法?我听说高级帐户非常昂贵。

谢谢!!马克

4

4 回答 4

25

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

使用以下代码,您可以根据需要使用尽可能多的航点,并且您永远不会收到错误MAX_WAYPOINTS_EXCEEDED。不要忘记将“YOUR_API_KEY”替换为您的 API KEY 或从 google API URL 中删除&key=YOUR_API_KEY并将变量“max”设置为 8(使用 API KEY 时 max = 25,不使用 API KEY 时 max = 8)。

<style>
html, body { height: 100%; margin: 0; padding: 0; }
#map { height: 100%; width: 100%; height: 100%; }
</style>
<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>

你可以在这里看到屏幕。

摆弄显示/隐藏线路按钮

于 2017-04-17T19:16:13.200 回答
22

你是对的,上一次我与谷歌代表通过电话交谈时,首要定价相当昂贵,起价为 10,000 美元。

我找到了一种解决方法,可以绕过 8 个航点的限制。我能够让它工作。

我通过接收我的航路点并将它们分成不同的路线但将它们作为同一条路线绘制在一起来做到这一点。

例如,如果需要 30 个航点,我将绘制 4 条线,但颜色相同等。所以,基本上你将航点切割成不同的路线,每次调用方向渲染器,就好像它是不同的路线一样。关键是在第一条路线之后,下一条路线必须从上一条路线的最后一个航路点开始(这样可以确保路线相互连接)

它可以工作,但与拥有高级帐户相比,您需要编写更多的代码,并且在这种情况下您需要更多的指示。

在没有高级帐户的情况下,我已经搜索并考虑了其他方法来做到这一点并且失败了。

虽然,当我与谷歌交谈时,他们确实表示他们打算为具有不同需求/需求的客户创建一个分层的支付结构。例如,如果客户只需要更多的方式而不是更多的方向请求。

希望这会有所帮助,因为它在实践应用程序中对我有用。

于 2012-01-09T23:43:53.293 回答
0

这个解决方案很容易。

根据距离阈值将航点保留在数组中并继续添加它们。一旦达到数组中 8 个值的限制,将航点数组的第一个位置(原点)分配给新航点数组 .... 将最后一个航点作为第二个元素分配给新航点 ...现在替换旧航路点阵列与这个新航路点阵列并继续。

无论您做什么,航路点都不会超过 8 个值,并且它会跟踪绘制出来的路线(除非旅程太长)

var addWaypoint = function(point) {
    if($scope.waypoints.length > 8){
        var temp = [];
        temp.push($scope.waypoints[0]); //Start Point
        temp.push($scope.waypoints[7]); //Last point
        temp.push(point); //New point
        $scope.waypoints = temp; //Replace the old object with this new one
    }
    else 
        $scope.waypoints.push(point);
}
于 2016-10-04T13:20:55.563 回答
-2

下面的 C# 代码计算您将调用 Google Directions API 的次数以及每次迭代中的航点数。您可以修改 Modmin 以更改上一次迭代所需的最小航路点。

例如,如果您有 totalWaypoints.Count = 97:

97 Mod 23 = 5,在这种情况下,我想要一个大于 5 的 Modmin,所以我将使用较低的 waypointsByIteration 再次计算;

97 Mod 22 = 9, (9 > Modmin) , OK;

迭代次数 = ((97 - (97 % 22)) / (22)) + 1 = 5;

在最后一次迭代中,waypointsByIteration 将是残差。

        var iterations = 1;//Number of iterations
        var waypointsByIteration = 23;//Number of waypoints by iteration
        var modMin = 5;//Minimum of Waypoints in the last iteration
        var residue = 0;//Residue of the division (totalWaypoints % waypointsByIteration)

        if (totalWaypoints.Count <= waypointsByIteration)
        {
            waypointsByIteration = totalWaypoints.Count;
        }
        else
        {
            while (totalWaypoints.Count % waypointsByIteration < modMin)
            {
                waypointsByIteration--;
            }

            //Calculate number of waypoints by iteracoes
            iterations = ((totalWaypoints.Count - (totalWaypoints.Count % waypointsByIteration)) / (waypointsByIteration)) + 1;
        }

        residue = totalWaypoints % waypointsByIteration;

        for(i=0;i<iterations;i++)
        {
            //If it is the last index, the waypointsByIteration will be the residue
            if(i == iteration - 1)
            {
                waypointsByIteration = residue;
            }
        }
于 2017-05-04T14:10:20.923 回答