Resposta imprecisa do Serviço de Elevação do Google Maps ao dividir um caminho muito grande

Essa é uma pergunta com algum nível de detalhe; deixe-me primeiro explicar a situação, depois minha implementação e a última, para que você entenda melhor.

A partir de 4 de abril, uma atualização é adicionada e os problemas são reduzidos a um problema pendente. Consulte o final desta pergunta para obter as informações atualizadas.

TLDR;

Tenho uma rota longa retornada da API de rotas do Google Maps e quero um gráfico de elevação para essa rota. Pena que não funciona porque é solicitado via GET e o tamanho máximo da URL é de 2.048 caracteres excedidos. Eu dividi os pedidos; garantiu a ordem de processamento correta usando Promessas; mas os dados de desenvolvimento nem sempre estão completos para a rota completa, nem sempre são exibidos na ordem correta, nem sempre seguem o caminho especificado e o local da inter-elevação se estende por vários quilômetros algumas vezes.

Introdução;

Tentando criar um gráfico de elevação para uma resposta DirectionsService do Google Maps Estou enfrentando um problema com rotas muito longas (isso não parece estar relacionado à distância, e não ao número de LatLngs por overview_path). Isso é causado pelo fato de o ElevationService ser solicitado viaGET e o tamanho máximo de um URL é 2048 caracteres. Esse problema édescrito em SO aqui também.

Implementação;

Imaginei que seria mais esperto que o Google (não realmente, mas pelo menos tentando encontrar uma maneira de contorná-lo), para dividir o caminho retornado pelo DirectionsService (overview_path propriedade) em lotes e concatenar os resultados (elevations retornado pelo método ElevationServicegetElevationsAlongPath)

Para obter o melhor nível de detalhe, consulte o ElevationService com 512 amostras por lote;e como o ElevationService distribui as amostras pelo comprimento do caminho, configurei um número máximo deLatLng por lote e verifique quantos lotes são necessários para processar o caminho completo (totalBatches = overview_path.length / maxBatchSize);e, finalmente, obter uma distribuição uniforme para minhas rotas, resulta em uma tentativa de obter um nível de detalhe igual para a rota completa (batchSize = Math.ceil(overview_path.length / totalBatches))

Enquanto o ElevationService trabalha de forma assíncrona, asseguro-me de que todos os pedidos sejam processados na ordem correta, com a ajuda de outros usuários de SO, primeiro usando setTimout e agora trabalhando com Promises.

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

Também estou enviando em lotes a solicitação do DirectionService para resolver a limitação de 8 pontos de passagem que o serviço possui, mas posso confirmar que esse não é o problema, pois também estou enfrentando o problema com 8 ou menos pontos de passagem.

Problema;

Os problemas que estou enfrentando são:

Os dados de elevação nem sempre seguem o caminho completo da rota, o que significa que o último ponto de elevação no gráfico é (distante) do final da rota;Às vezes, os dados de elevação são exibidos em ordem aleatória, como se parecesse que as promessas ainda não estavam aguardando a execução da próxima tarefa;Os dados de elevação nem sempre seguem o dadoLatLngé dooverview_path fornecido em um determinado lote (veja a captura de tela);Os dados da distância entre elevações são muitos. Às vezes, percorre vários quilômetros, solicitando 512 amostras para um tamanho de lote com a mesma correspondência, com um máximo de 200LatLngs por lote.

Imaginei que o lote do ElevationService usando Promises (e antes de cronometrar com setTimtout) resolveria todos os meus problemas, mas o único problema que resolvi não foi exceder a URL de solicitação de char 2.048 e enfrentar os novos problemas descritos acima.

A ajuda é realmente apreciada

Também gostaria de colocar um 250 rep. recompensa sobre essa questão logo à frente, mas isso é impossível no momento. Portanto, sinta-se à vontade para responder, pois mais tarde posso adicionar a recompensa e concedê-la à resposta que resolve os problemas descritos. A 250 rep. A recompensa foi concedida para mostrar minha gratidão por você me indicar a direção certa.

Obrigado por ler e responder!

Atualizado em 4 de abril, deixando 1 problema pendente (pelo que sei no momento)

Problema com elevações em ordem aleatória abordadas

Consegui resolver alguns dos problemas quando percebi um comportamento inconsistente nos resultados das direções. Isso foi causado por uma razão óbvia: as chamadas assíncronas não foram "Prometidas" para serem agendadas, portanto, algumas vezes o pedido estava correto, na maioria das vezes não. Eu não percebi isso no começo porque os marcadores foram exibidos corretamente (em cache).

Problema com a distância entre elevações abordada

A div que exibia os dados de elevação tinha apenas 300 px de largura e muitos pontos de dados. Por uma largura tão pequena, eu simplesmente não conseguia passar o mouse sobre pontos suficientes, provocando pontos de elevação que se afastam um do outro.

Problema com os dados de elevação não exibidos ao longo da rota

De alguma forma, em algum ponto da linha, também resolvi esse problema, mas não tenho certeza se a largura maior ou "Promissor" da ordem das direções resolveu isso.

Problema pendente: os dados de elevação nem sempre estão completos

O único problema restante é que os dados de elevação nem sempre cobrem o caminho completo. Acredito que isso ocorra porque um erro na lógica da Promessa, ao registrar algumas mensagens no console, informa que o gráfico de elevação é desenhado em um ponto em que nem todas as Promise-thens foram concluídas e acho que isso é causado pela recondução de uma chamada em lote quando um Over O erro Limite de consulta é retornado pela API do Google Maps.

Como posso recuperar a mesma cadeia quando um erro de limite de consulta excedente é retornado? Tentei não resolver a mesma função novamente, mas apenas dispare osetTimeout(...), mas a promessa parece não resolver o lote refinado no momento em que não está mais recebendo um limite de excesso de consultas. Atualmente, é assim que eu o configurei (para direções e elevação):

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

questionAnswers(3)

yourAnswerToTheQuestion