Google Maps Elevation Response Inaccurate When Splitting Too Long

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

As of April 4, an update is being added, and the problems narrow down to one incomplete problem, see the bottom of this question for current information.

TL; DR;

I have a long route returned from the Google Maps API, and you need an Elevation diagram for that route. Too bad that it does not work, because it is requested via GET, and the maximum URL length is 2.048 characters that exceed. I shared the requests; guaranteed the correct processing order using Promises; but Evelation data is not always complete for the full route, it does not always appear in the correct order, it does not always follow the given path, and intermediate intersections sometimes take several kilometers.

Introduction

Trying to create a height chart to respond to Google Maps DirectionsService. I ran into the problem of routes too long (this does not seem to be related to the distance, and not to the number of LatLngs per view_view). This is because the ElevationService is requested via GET and the maximum URL length is 2048 characters. This issue is described here as well here .

Implementation

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

  • To get the best level of detail, I request an ElevationService with 512 samples per batch;
  • and because the ElevationService distributes samples along the path, I set the maximum number of LatLng per batch and checked how many packets are required to process the full path ( totalBatches = overview_path.length / maxBatchSize );
  • and finally getting even distribution for my directions will result in an attempt to get an even level of detail for the entire route ( batchSize = Math.ceil(overview_path.length / totalBatches) ).

While the ElevationService works asynchronously, I am sure that all requests are processed in the correct order with the help of other SO users, first with setTimout and now work 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 also run a DirectionService request to solve the 8th route problem provided by the service, but I can confirm that this is not a problem, since I also ran into a problem with 8 or less waypoints.

Problem

I ran into problems:

  • Altitude data does not always follow the full path of the route, that is, the last point in the graph (far) from the end of the route;
  • Height data is sometimes displayed in random order, as if it seemed like promises were still not waiting for the next task;
  • Altitude data does not always follow LatLng data from overview_path in this batch (see screenshot);
  • Inter-distance between data is a lot. Sometimes it takes several kilometers, requesting 512 samples for a uniformly matching batch size with a maximum of 200 LatLng per batch.

altitude data not matching overview_path said to follow

I decided to dispense the ElevationService using promises (and before timing using setTimtout) it will solve all my problems, but the only problem I solved does not exceed the request URL 2.048 char and addresses the new problems described above.

Help is really appreciated

Also I would like to put 250 rep. generosity in this matter, but at this moment it is impossible. Therefore, please do not hesitate to answer, as I can add a reward later and give her an answer that solves the problems described. 250 rep. the award was awarded to express your appreciation for pointing me in the right direction.

Thanks for reading and responding!

Updated on April 4, leaving 1 incomplete problem (as far as I can tell at the moment)

Random elevation down issue

I managed to solve some problems when I noticed inconsistent behavior in the route results. This was caused for an obvious reason: asynchronous calls were not “promised” to be scheduled, so some of them were correct, in most cases this is not so. I did not notice this at first, because the markers were correctly displayed (cached).

The problem with the distance between the reliefs is overcome

The div, which displays height data, is only 300 pixels wide and contains many data points. With such a small width, I simply could not hover over a sufficient number of points, forcing me to launch elevation points that lie further apart.

Problem with altitude data not showing along the route

Somewhere somewhere along the line, I also solved this problem, but I'm not sure if this allowed a wider width or a "promise" of the order of directions.

Pending issue: height data not always complete

The only remaining problem is that the altitude data does not always cover the full path. I believe that this is due to the error in the Promising logic, since recording some messages in the console tells me that the height diagram is drawn at the point where not all the Promise is finished after that, and I think this is caused by repeating the batch call when Over Error request restriction is returned by the Google Maps API.

How can I restore the same chain when returning an error with a request exceeding? I tried not to allow the same function again, but just ran setTimeout(...) , but then Promise didn’t seem to be resolving the batch when it no longer gets the Over Over Query Limit. This is currently how I set it (for both directions and heights):

 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(); } }); }); } 
+7
javascript batch-processing google-maps-api-3 google-elevation-api
source share
3 answers

The last remaining issue was also resolved with this SO question: How to re-execute javascript promise on failure? . Therefore, if jfriend00 answers this question, I can award him generosity, as this is a trick that helped me in the end.

To make sure that the function resolves with OK status, repeats in OVER_QUERY_LIMIT and rejects in any other status , I had to put the Promise logic in the function and call this function, for example:

 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); }); } 
0
source share

Concerns regarding implementation, side note, and issues listed are addressed in the Google Maps Heights API . The full documentation provides a simple interface for querying locations on the ground for elevation data and will resolve any issues that arise, such as altitude queries, using parameters, indicating locations, paths, and elevation responses.

For the concern discussed in your Introduction, the Google Maps API Heights API has standard and maximum usage restrictions. These restrictions apply to prevent abuse of the Google Maps Add-in API. API Limitations The Elevation API Google provides you with detailed information about usage limits and quota increases.

Additional notes from the documentation that may solve your problems:

  • Note that elevation data becomes coarser when transmitting multiple points. To get the most accurate height value for a point, you must request it independently.
  • In cases where Google does not have accurate height measurements at the exact location you request, the service will interpolate and return the average value using the four nearest locations.
  • As with positional queries, the path parameter specifies a set of latitude and longitude values. However, unlike a positional query, a path indicates an ordered set of vertices. Instead of returning altitude data at the vertices, path queries are selected along the path length, where each sample is equidistant from each other.
  • The Google Maps Elevation API returns data for single point queries with the highest possible accuracy. Batch queries with multiple locations may return data with less accuracy.
0
source share

Mmmh, how many points should you handle. Can you post this way, so maybe some others can test it in their applications. You tried to reduce waypoints using Douglas-Peuker or comparable methods. You tried other applications, such as the free “Routeconverter” (which works with HGT), to find out if you have better results. Do you need elevation points directly / on the fly? Will use other free elevation services. You may need to read the elevation points to your route points so that you can sort the unnecessary points.

Just some thoughts, in bad English, I'm afraid. Good luck, Reinhard

0
source share

All Articles