Unkorrekte Antwort des Google Maps Elevation Service beim Aufteilen eines zu großen Pfads

Dies ist eine Frage mit einem gewissen Detaillierungsgrad. Lassen Sie mich daher zuerst die Situation erklären, dann meine Implementierung und zuletzt die Frage, damit Sie sie am besten verstehen.

Ab dem 4. April wird ein Update hinzugefügt, und die Probleme werden auf ein ausstehendes Problem eingegrenzt. Die aktuellen Informationen finden Sie am Ende dieser Frage.

TLDR;

Ich habe eine lange Route von der Google Maps Directions API zurückgegeben und möchte eine Höhenkarte für diese Route. Schade, dass es nicht funktioniert, da es über GET angefordert wird und die maximale URL-Länge 2.048 Zeichen beträgt, die überschritten werden. Ich teilte die Anfragen auf; garantierte die korrekte Bearbeitungsreihenfolge mit Promises; Die Evelationsdaten sind jedoch nicht immer für die vollständige Route vollständig, werden nicht immer in der richtigen Reihenfolge angezeigt und folgen manchmal nicht immer dem angegebenen Pfad und dem angegebenen Höhenunterschied, der sich über mehrere Kilometer erstreckt.

Einführung

Versuche, eine Höhenkarte für eine Google Maps-Route zu erstellenRoutenservice-Antwort Es liegt ein Problem mit zu langen Routen vor (dies scheint nicht mit der Entfernung zu tun zu haben, sondern mit der Anzahl der LatLngs pro Übersichtspfad). Dies liegt daran, dass der ElevationService über @ angefordert wirGET und eine maximale Länge einer URL beträgt 2048 Zeichen. Dieses Problem ist hier auch auf SO beschrieben.

Implementierung

Ich dachte, ich wäre schlauer als Google (nicht wirklich, aber ich versuche zumindest, eine Möglichkeit zu finden, das Problem zu umgehen), um den vom DirectionsService (@) zurückgegebenen Pfad zu teileoverview_path property) zu Batches zusammenfassen und die Ergebnisse verketten elevations von der ElevationService-Methode zurückgegebengetElevationsAlongPath).

Um den bestmöglichen Detaillierungsgrad zu erzielen, frage ich den ElevationService mit 512 Stichproben pro Charge ab.und weil der ElevationService die Samples über die Länge des Pfades verteilt, habe ich eine maximale Anzahl von @ eingerichtLatLng pro Charge und überprüfen Sie, wie viele Chargen erforderlich sind, um den vollständigen Pfad zu verarbeiten totalBatches = overview_path.length / maxBatchSize);und endlich eine gleichmäßige Streuung für meine Wegbeschreibung zu erhalten, führt zu dem Versuch, für die gesamte Route den gleichen Detaillierungsgrad zu erzielen batchSize = Math.ceil(overview_path.length / totalBatches)).

Während der ElevationService asynchron arbeitet, stelle ich sicher, dass alle Anforderungen in der richtigen Reihenfolge mit Hilfe anderer SO-Benutzer verarbeitet werden. Verwenden Sie dazu zuerst setTimout und arbeiten Sie jetzt mit Promises.

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

Randnotiz

Ich fasse auch die Anfrage des DirectionService zusammen, um die 8-Wegpunkte-Einschränkung des Dienstes zu beheben, kann aber bestätigen, dass dies nicht der Fall ist, da das Problem auch bei 8 oder weniger Wegpunkten auftritt.

Problem

ie Probleme, mit denen ich konfrontiert bin, sin

Erhöhungsdaten folgen nicht immer dem vollständigen Weg der Route, dh der letzte Höhenpunkt in der Karte ist (weit) vom Ende der Route entfernt.Erhöhungsdaten werden manchmal in zufälliger Reihenfolge angezeigt, als ob die Versprechungen noch nicht auf die Ausführung der nächsten Aufgabe gewartet hätten.Hebedaten folgen nicht immer dem angegebenenLatLng 's vomoverview_path in einem bestimmten Stapel bereitgestellt (siehe Screenshot);Inter Höhendistanzdaten ist eine Menge. Spannt sich manchmal über mehrere Kilometer, während 512 Proben für eine gleichmäßig angepasste Chargengröße mit maximal 200 @ angefordert werdeLatLngs pro Charge.

Ich dachte, dass das Batching des ElevationService mit Promises (und vor dem Timing mit setTimtout) alle meine Probleme lösen würde, aber das einzige Problem, das ich gelöst habe, ist, die URL der 2.048-Zeichenanforderung nicht zu überschreiten und auf die oben beschriebenen neuen Probleme zu stoßen.

Hilfe wird sehr geschätzt

Auch ich möchte eine 250 rep setzen. Kopfgeld auf diese Frage direkt vor, aber das ist in diesem Moment unmöglich. Sie können also gerne antworten, da ich das Kopfgeld später hinzufügen und der Antwort zuweisen kann, die die beschriebenen Probleme behebt. A 250 rep. Die Prämie wurde verliehen, um meine Wertschätzung dafür zu zeigen, dass Sie mich in die richtige Richtung gelenkt haben.

Danke fürs Lesen und Antworten!

Aktualisiert am 4. April, wobei 1 ausstehende Ausgabe übrig bleibt (soweit ich das im Moment beurteilen kann)

Problem mit Erhöhungen in zufälliger Reihenfolge behoben

Ich konnte einige der Probleme angehen, als ich ein inkonsistentes Verhalten in den Richtungsergebnissen bemerkte. Dies wurde aus einem offensichtlichen Grund verursacht: Die asynchronen Anrufe sollten nicht "zugesagt" werden, daher war die Reihenfolge in einigen Fällen korrekt, in den meisten Fällen nicht. Das ist mir zunächst nicht aufgefallen, da die Markierungen korrekt angezeigt (zwischengespeichert) wurden.

Problem mit Höhenunterschied angepackt

Das Div, das die Höhendaten anzeigt, war nur 300 Pixel breit und enthielt viele Datenpunkte. Bei einer so geringen Breite konnte ich einfach nicht über genügend Punkte schweben, um Höhenpunkte auszulösen, die weiter voneinander entfernt liegen.

Problem mit Höhendaten, die nicht auf der Route angezeigt werden

Irgendwie irgendwo auf der ganzen Linie habe ich auch dieses Problem gelöst, aber ich bin mir nicht sicher, ob die größere Breite oder die "vielversprechende" Reihenfolge der Richtungen dies gelöst hat.

Offenes Problem: Höhendaten sind nicht immer vollständig

Das einzige verbleibende Problem ist, dass die Höhendaten nicht immer den vollständigen Pfad abdecken. Ich glaube, das liegt daran, dass ein Fehler in der Versprechenslogik darauf zurückzuführen ist, dass das Protokollieren einiger Nachrichten in der Konsole besagt, dass die Höhentabelle an einem Punkt gezeichnet wurde, an dem nicht alle Versprechensnachweise abgeschlossen wurden Der Abfragebegrenzungsfehler wird von der Google Maps-API zurückgegeben.

Wie kann ich dieselbe Kette erneut aktivieren, wenn ein Over Query Limit-Fehler zurückgegeben wird? Ich habe versucht, nicht die gleiche Funktion wieder aufzulösen, sondern nur dassetTimeout(...), aber dann scheint das Versprechen den gelöschten Stapel nicht mehr zu lösen, da es kein Über-Abfrage-Limit mehr gibt. Im Moment habe ich es so eingerichtet (für beide Richtungen und für die Höhe):

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

Antworten auf die Frage(6)

Ihre Antwort auf die Frage