分割太大的路径时,Google Maps Elevation Service响应不准确 [英] Inaccurate Google Maps Elevation Service response when splitting a too large path

查看:173
本文介绍了分割太大的路径时,Google Maps Elevation Service响应不准确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个有点细节的问题,所以让我先解释一下情况,然后解释一下我的实现,然后回答这个问题,这样你就可以最好地理解了。



截至4月4日,新增了一个更新,问题被缩小为一个悬而未决的问题,请参阅本问题的底部日期信息



TLDR;

我从Google Maps Directions API返回的漫长路线,并且需要该路线的海拔图。太糟糕了,它不起作用,因为它是通过GET请求的,URL的最大长度是2.048个字符,超过了。我拆分了请求;使用承诺保证正确的处理订单;但是Evelation数据并不总是完整的完整路线,并不总是以正确的顺序显示,并不总是遵循给定路径,并且海拔高度位置跨越数km。



简介



尝试为Google Maps DirectionsService创建海拔图响应我面临着路线太长的问题(这似乎与距离无关,而不是每个overview_path的LatLng数量)。这是由于通过 GET 请求ElevationService并且URL的最大长度为2048个字符。这个问题也在



我认为使用Promises对ElevationService进行批处理(在使用setTimtout进行计时之前)将解决我所有的问题,但我解决的唯一问题不会超过2.048 char请求URL并面临上述新问题。 p>

非常感谢帮助

另外我想放一个250代表。在这个问题上提前赏金,但这是不可能的。所以请随时回复,因为我以后可以添加赏金并将其奖励给解决所述问题的答案。 250名代表。赏金已被授予表示我感谢您指点我的方向正确。

感谢您的阅读和回复!



于4月4日更新,留下1个悬而未决的问题(就目前我可以看出的情况而言)





当我注意到路线结果中的不一致行为时,我已经能够解决一些问题。这是由于一个显而易见的原因造成的:异步调用不是预定的,因此有些时候订单是正确的,大部分时间不是。我一开始并没有注意到这一点,因为标记显示正确(缓存)。



解决了高程距离问题



显示高程数据的div只有300px宽,并包含许多数据点。通过这么小的宽度,我无法将鼠标悬停在足够多的点上,从而触发彼此距离更远的高程点。



海拔数据不存在问题

不知何故,线我也解决了这个问题,但我不确定是否更大的宽度或有前途的指示顺序已经解决了这个问题。



待定问题:高程数据并不总是完整的

剩下的唯一问题是高程数据并不总是覆盖完整路径。我相信这是因为Promising逻辑中的一个错误,因为在控制台中记录一些消息告诉我高程图是在并非所有的Promise都已经完成的时候绘制的,我认为这是由于在Over查询限制错误是由Google Maps API返回的。



如果返回超过查询限制错误,我该如何重新链接相同的链?我试着不再解析相同的函数,但只是触发 setTimeout(...),但是Promise似乎并没有解析refired批处理当它不再获得超过查询限制时。目前这是我设置它的方式(适用于双向和海拔):

pre $ function getRouteElevationChartDataBatchPromise(batch,batchSize){
return new Promise(function(resolve,reject){
var elevator = new google.maps.ElevationService();
var thisBatchPath = [];

for (var j = batch * batchSize; j< batch * batchSize + batchSize; j ++){
if(j< directions.routes [0] .overview_path.length){
thisBatchPath.push .routes [0] .overview_path [j]);
} else {
break;
}
}

elevator.getElevationAlongPath({
path:thisBatchPath,
samples:512
},function(elevation,status){
if(status!= google.maps.ElevationStatus.OK){
if(状态== google.maps.ElevationStatus.OVER_QUERY_LIMIT){
console.log('ElevationService:超过查询限制,在200ms内重试');

resolve(setTimeout(function(){
getRouteElevationChartDataBatchPromise(batch,batchSize);

},200));
} else {
reject(status);
}
} else {
console.log('Elevations Count:'+ elevations.length);
routeElevations = routeElevations.concat(elevation);
resolve();
}
});
});
}


解决方案

已经解决了这个SO问题的帮助:如何重新编译,在失败时运行javascript promise?。所以如果 jfriend00 回复这个问题,我可以奖励他,因为这是最终帮助我的窍门。



为了确保 重试状态 重试 OVER_QUERY_LIMIT 拒绝> 任何其他状态 在函数中承诺逻辑并调用该函数,如下所示:

  function getRouteElevationChartDataBatchPromise(batch,batchSize){
return new Promise(function(resolve,reject){
function run(batch,batchSize){
var elevator = new google.maps.ElevationService();
var thisBatchPath = []; $ b $ j
for(var j = batch * batchSize; j< batch * batchSize + batchSize; j ++){
if(j< directions.routes [0] .overview_path.length){
thisB atchPath.push(directions.routes [0] .overview_path [J]);
} else {
break;



elevator.getElevationAlongPath({
path:thisBatchPath,
samples:512
},function(elevation,status) {
if(status == google.maps.ElevationStatus.OK){
routeElevations = routeElevations.concat(elevation);
resolve();
} else if(status = = google.maps.ElevationStatus.OVER_QUERY_LIMIT){
setTimeout(function(){
run(batch,batchSize);
},200);
} else {
拒绝(状态);
}
});
}

run(batch,batchSize);
});
}


This is a bit of a question with some level of detail to it, so let me first explain the situation, then my implementation and last the question so you understand best.

As of April 4 an update is added and the issues are narrowed down to one pending issue, see the bottom of this question for the up to date info.

TLDR;

I have a long route returned from Google Maps Directions API and want an Elevation chart for that route. Too bad it doesn't work because it's requested via GET and the URL maximum length is 2.048 chars which get exceeded. I splitted the requests; guaranteed the correct processing order using Promises; but Evelation data isn't always complete for full route, isn't always displayed in the correct order, doesn't always follow the given path and inter elevation location spans over several km's sometimes.

Introduction;

Trying to create an elevation chart for a Google Maps DirectionsService response I'm facing an issue with too long routes (this doesn't seem to be related to distance, rather than number of LatLngs per overview_path). This is caused by the fact the ElevationService is requested via GET and a maximum length of an URL is 2048 chars. This problem is described on SO here as well.

Implementation;

I figured I would be smarter than Google (not really, but at least trying to find a way to work around it), to split the path returned by the DirectionsService (overview_path property) into batches and concatenate the results (elevations returned by the ElevationService method getElevationsAlongPath).

  • To get the best level of detail I query the ElevationService with 512 samples per batch;
  • and because the ElevationService spreads the samples over the length of the path I set up a maximum number of LatLng per batch and check how many batches are required to process the full path (totalBatches = overview_path.length / maxBatchSize);
  • and finally get an even spread for my directions result in an attempt to get an equal level of detail for the complete route (batchSize = Math.ceil(overview_path.length / totalBatches)).

While the ElevationService work asynchronously I make sure the requests are all processed in the correct order with help of other SO-users first using setTimout and now working with Promises.

My code

var maxBatchSize = 200;
var currentBatch = 0;
var promise = Promise.resolve();
var totalElevationBatches = Math.ceil(directions.routes[0].overview_path.length / maxBatchSize);
var batchSize =  Math.ceil(directions.routes[0].overview_path.length / totalElevationBatches);

while(currentBatch < totalElevationBatches) {
    promise = addToChain(promise, currentBatch, batchSize);
    currentBatch++;
}

promise.then(function() {
    drawRouteElevationChart(); // this uses the routeElevations to draw an AreaChart
});

function getRouteElevationChartDataBatchPromise(batch, batchSize) {
    return new Promise(function(resolve, reject) {
        var elevator = new google.maps.ElevationService();
        var thisBatchPath = [];

        for (var j = batch * batchSize; j < batch * batchSize + batchSize; j++) {
            if (j < directions.routes[0].overview_path.length) {
                thisBatchPath.push(directions.routes[0].overview_path[j]);
            } else {
                break;
            }
        }

        elevator.getElevationAlongPath({
            path: thisBatchPath,
            samples: 512
        }, function (elevations, status) {
            if (status != google.maps.ElevationStatus.OK) {
                if(status == google.maps.ElevationStatus.OVER_QUERY_LIMIT) {
                    console.log('Over query limit, retrying in 250ms');

                    resolve(setTimeout(function() {
                        getRouteElevationChartDataBatchPromise(batch, batchSize);

                    }, 250));
                } else {
                    reject(status);
                }
            } else {
                routeElevations = routeElevations.concat(elevations);
                resolve();
            }
        });
    });
}

function addToChain(chain, batch, batchSize){
    return chain.then(function(){
        console.log('Promise add to chain for batch: ' + batch);
        return getRouteElevationChartDataBatchPromise(batch, batchSize);
    });
}

Side note;

I'm also batching the DirectionService's request to address the 8 waypoint limitation the service has but I can confirm this is not the issue since I'm also facing the issue with 8 or fewer waypoints.

Problem;

The problems I'm facing are:

  • Elevation data is not always following the full path of route, meaning the last elevation point in the chart is (far) from the end of the route;
  • Elevation data sometimes gets displayed in random order as if it seems the promises were still not waiting for the next task to execute;
  • Elevation data doensn't always follow the given LatLng's from the overview_path provided in a given batch (see screenshot);
  • Inter elevation distance data is a lot. Sometimes spans multiple km's while requesting for 512 samples for an evenly matched batch size with a maximum of 200 LatLngs per batch.

I figured batching the ElevationService using Promises (and before timing with setTimtout) would solve all my problems but the only problem I solved is not exceeding the 2.048 char request URL and facing the above described new issues.

Help is really appreciated

Also I would like to put a 250 rep. bounty on this question right ahead but that's impossible at this moment. So please feel free to reply as I can later add the bounty and award it to the answer that solves the issues described. A 250 rep. bounty has been awarded to show my appreciation for you to point me in the right direction.

Thanks for reading and replying!

Updated at April 4 leaving 1 pending issue (for as far as I can tell at the moment)

Problem with elevations in random order tackled down

I've been able to tackle some of the problems when I was noticing inconsistent behavior in the directions results. This was caused for an obvious reason: the asynchronous calls weren't "Promised" to be scheduled so some of the times the order was correct, most of the times it wasn't. I didn't noticed this at first because the markers were displayed correctly (cached).

Problem with inter elevation distance tackled down

The div displaying the elevation data was only a 300px wide and containing many datapoints. By such a small width I was simply unable to hover over enough points causing to trigger elevation points which lie further apart from each other.

Problem with elevation data not showing along the route

Somehow somewhere down the line I've also solved this issue but I'm not sure if the bigger width or "Promising" the directions order has solved this.

Pending issue: elevation data is not always complete

The only remaining issue is that elevation data is not always covering the full path. I believe this is because an error in the Promising logic because logging some messages in the console tells me the elevation chart is drawn at a point where not all Promise-then's have completed and I think this is caused by refiring a batched call when an Over Query Limit error is returned by the Google Maps API.

How can I refire the same chain when an Over Query Limit error is returned? I've tried not to resolve the same function again, but just fire the setTimeout(...), but then the Promise doesn't seem to resolve the refired batch at the moment it is no longer getting an Over Query Limit. Currently this is how I've set it up (for both directions and elevation):

function getRouteElevationChartDataBatchPromise(batch, batchSize) {
    return new Promise(function(resolve, reject) {
        var elevator = new google.maps.ElevationService();
        var thisBatchPath = [];

        for (var j = batch * batchSize; j < batch * batchSize + batchSize; j++) {
            if (j < directions.routes[0].overview_path.length) {
                thisBatchPath.push(directions.routes[0].overview_path[j]);
            } else {
                break;
            }
        }

        elevator.getElevationAlongPath({
            path: thisBatchPath,
            samples: 512
        }, function (elevations, status) {
            if (status != google.maps.ElevationStatus.OK) {
                if(status == google.maps.ElevationStatus.OVER_QUERY_LIMIT) {
                    console.log('ElevationService: Over Query Limit, retrying in 200ms');

                    resolve(setTimeout(function() {
                        getRouteElevationChartDataBatchPromise(batch, batchSize);

                    }, 200));
                } else {
                    reject(status);
                }
            } else {
                console.log('Elevations Count: ' + elevations.length);
                routeElevations = routeElevations.concat(elevations);
                resolve();
            }
        });
    });
}

解决方案

The last remaining issue has also been solved with the help of this SO question: How to re-run a javascript promise when failed?. So if jfriend00 replies to this question I can award the bounty to him, since that's the trick that helped me out in the end.

To be sure the function resolves at status OK, retries at OVER_QUERY_LIMIT and reject at any other status I had to put the Promise logic within a function and call that function, like so:

function getRouteElevationChartDataBatchPromise(batch, batchSize) {
    return new Promise(function(resolve, reject) {
        function run(batch, batchSize) {
            var elevator = new google.maps.ElevationService();
            var thisBatchPath = [];

            for (var j = batch * batchSize; j < batch * batchSize + batchSize; j++) {
                if (j < directions.routes[0].overview_path.length) {
                    thisBatchPath.push(directions.routes[0].overview_path[j]);
                } else {
                    break;
                }
            }

            elevator.getElevationAlongPath({
                path: thisBatchPath,
                samples: 512
            }, function (elevations, status) {
                if(status == google.maps.ElevationStatus.OK) {
                    routeElevations = routeElevations.concat(elevations);
                    resolve();
                } else if (status == google.maps.ElevationStatus.OVER_QUERY_LIMIT) {                        
                    setTimeout(function () {
                        run(batch, batchSize);
                    }, 200);
                } else {
                    reject(status);
                }
            });
        }

        run(batch, batchSize);
    });
}

这篇关于分割太大的路径时,Google Maps Elevation Service响应不准确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆