Respuesta inexacta del Servicio de elevación de Google Maps al dividir una ruta demasiado grande

Esta es una pregunta con cierto nivel de detalle, así que permítanme explicar primero la situación, luego mi implementación y, por último, la pregunta para que entiendan mejor.

A partir del 4 de abril, se agrega una actualización y los problemas se reducen a un problema pendiente. Consulte la parte inferior de esta pregunta para obtener información actualizada.

TLDR;

Tengo una ruta larga devuelta desde la API de indicaciones de Google Maps y quiero un gráfico de elevación para esa ruta. Lástima que no funcione porque se solicitó a través de GET y la longitud máxima de la URL es 2.048 caracteres que se exceden. Dividí las solicitudes; garantizó el orden de procesamiento correcto usando Promesas; pero los datos de Evelation no siempre están completos para la ruta completa, no siempre se muestran en el orden correcto, no siempre siguen la ruta dada y, a veces, la ubicación entre elevaciones abarca varios kilómetros.

Introducción;

Intentando crear un gráfico de elevación para una respuesta de Google Maps DirectionsService Estoy enfrentando un problema con rutas demasiado largas (esto no parece estar relacionado con la distancia, en lugar del número de LatLngs por overview_path). Esto se debe al hecho de que ElevationService se solicita a través deGET y una longitud máxima de una URL es de 2048 caracteres. Este problema esdescrito en SO aquí también.

Implementación;

Pensé que sería más inteligente que Google (no realmente, pero al menos tratando de encontrar una manera de evitarlo), para dividir el camino devuelto por el servicio de direcciones (overview_path propiedad) en lotes y concatenar los resultados (elevations devuelto por el método ElevationServicegetElevationsAlongPath)

Para obtener el mejor nivel de detalle, consulto el ElevationService con 512 muestras por lote;y debido a que ElevationService extiende las muestras a lo largo de la ruta, configuré un número máximo deLatLng por lote y verifique cuántos lotes se requieren para procesar la ruta completa (totalBatches = overview_path.length / maxBatchSize);y, finalmente, obtener una distribución uniforme de mis instrucciones, resulta en un intento de obtener el mismo nivel de detalle para la ruta completa (batchSize = Math.ceil(overview_path.length / totalBatches))

Si bien ElevationService funciona de forma asincrónica, me aseguro de que todas las solicitudes se procesen en el orden correcto con la ayuda de otros usuarios de SO que primero usan setTimout y ahora trabajan con Promises.

Mi código

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);
    });
}

Nota al margen;

También estoy procesando la solicitud del DirectionService para abordar la limitación de 8 puntos de referencia que tiene el servicio, pero puedo confirmar que este no es el problema, ya que también estoy enfrentando el problema con 8 o menos puntos de referencia.

Problema;

Los problemas que enfrento son:

Los datos de elevación no siempre siguen la ruta completa de la ruta, lo que significa que el último punto de elevación en la carta está (lejos) desde el final de la ruta;Los datos de elevación a veces se muestran en orden aleatorio como si pareciera que las promesas todavía no estaban esperando que se ejecutara la siguiente tarea;Los datos de elevación no siempre siguen lo dadoLatLnges deloverview_path proporcionado en un lote determinado (ver captura de pantalla);Los datos de distancia entre elevaciones son muchos. A veces se extiende por varios kilómetros al tiempo que solicita 512 muestras para un tamaño de lote uniformemente igualado con un máximo de 200LatLngs por lote.

Pensé que agrupar el ElevationService usando Promises (y antes de cronometrar con setTimtout) resolvería todos mis problemas, pero el único problema que resolví es no exceder la URL de solicitud de caracteres 2.048 y enfrentar los nuevos problemas descritos anteriormente.

La ayuda es realmente apreciada

También me gustaría poner un 250 rep. recompensa por esta pregunta, pero eso es imposible en este momento. Así que no dude en responder, ya que luego puedo agregar la recompensa y otorgarla a la respuesta que resuelve los problemas descritos. A 250 rep. Se ha otorgado recompensa por mostrar mi agradecimiento por que me hayas señalado en la dirección correcta.

Gracias por leer y responder!

Actualizado el 4 de abril dejando 1 problema pendiente (por lo que puedo decir en este momento)

Problema con elevaciones en orden aleatorio abordado

He podido abordar algunos de los problemas cuando noté un comportamiento inconsistente en los resultados de las instrucciones. Esto fue causado por una razón obvia: las llamadas asincrónicas no fueron "prometidas" para ser programadas, por lo que algunas veces el orden era correcto, la mayoría de las veces no lo era. Al principio no me di cuenta porque los marcadores se mostraban correctamente (en caché).

Problema con la distancia entre elevaciones abordada

El div que muestra los datos de elevación tenía solo 300 px de ancho y contenía muchos puntos de datos. Con un ancho tan pequeño, simplemente no pude pasar sobre suficientes puntos, lo que provocó la activación de puntos de elevación que están más separados entre sí.

Problema con los datos de elevación que no se muestran a lo largo de la ruta

De alguna manera en algún momento, también he resuelto este problema, pero no estoy seguro de si el mayor ancho o "Prometedor" del orden de las direcciones lo ha resuelto.

Problema pendiente: los datos de elevación no siempre están completos

El único problema pendiente es que los datos de elevación no siempre cubren la ruta completa. Creo que esto se debe a un error en la lógica prometedora porque registrar algunos mensajes en la consola me dice que el gráfico de elevación se dibuja en un punto donde no se han completado todas las promesas, y creo que esto se debe al rechazar una llamada por lotes cuando un Over El error de Límite de consulta es devuelto por la API de Google Maps.

¿Cómo puedo rechazar la misma cadena cuando se devuelve un error de Límite de exceso de consulta? Traté de no resolver la misma función nuevamente, pero solo disparesetTimeout(...), pero la Promesa no parece resolver el lote restaurado en el momento en que ya no obtiene un Límite de exceso de consultas. Actualmente así es como lo configuré (para ambas direcciones y elevación):

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();
            }
        });
    });
}

Respuestas a la pregunta(3)

Su respuesta a la pregunta