From 3a34f7ce5566adf4e1368da59d6a534ba35b917f Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Date: Sat, 20 Aug 2022 12:17:56 -0300 Subject: [PATCH] FixElevation - Change MapQuest to Open-Elevation (#4258) Since MapQuest elevation service reaches end of life on aug-31, it is replaced by Open-Elevation public API with minimum changes. TODO: use Post instead of Get to request more points at a time Fixes #4206 --- src/Core/Settings.h | 1 - src/FileIO/FixElevation.cpp | 138 ++++++++++++++---------------------- 2 files changed, 54 insertions(+), 85 deletions(-) diff --git a/src/Core/Settings.h b/src/Core/Settings.h index dc8a8ff08..5ce554a60 100644 --- a/src/Core/Settings.h +++ b/src/Core/Settings.h @@ -196,7 +196,6 @@ #define GC_DPRP_EQUIPWEIGHT "dataprocess/fixrunningpower/equipwheight" #define GC_DPDR_DRAFTM "dataprocess/fixrunningpower/draftm" #define GC_DPFV_MA "dataprocess/fixspeed/ma" -#define GC_DPFE_AK "dataprocess/fixelevation/ak" #define GC_CAD2SMO2 "dataprocess/fixmoxy/cad2smo2" #define GC_SPD2THB "dataprocess/fixmoxy/spd2thb" #define GC_DPFLS_PL "dataprocess/fixlapswim/pool_length" diff --git a/src/FileIO/FixElevation.cpp b/src/FileIO/FixElevation.cpp index 78c536ff4..cc6591d1b 100644 --- a/src/FileIO/FixElevation.cpp +++ b/src/FileIO/FixElevation.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2014 Jon Beverley (jon@csdl.biz) + * Copyright (c) 2022 Ale Martinez (amtriathlon@gmail.com) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -26,16 +27,10 @@ #include #include #include - -// MapQuest default API key. -// If you have reliability problems with Fix Elevation, caused by too -// many API requests per day using this key, then apply for your own -// Free API key at https://developer.mapquest.com/. -// You can then add it to gcconfig.pri - -#ifndef GC_MAPQUESTAPI_KEY -#define GC_MAPQUESTAPI_KEY "Fmjtd%7Cluur20uznu%2Ca2%3Do5-9ayshw" -#endif +#include +#include +#include +#include struct elevationGPSPoint { int rideFileIndex; @@ -48,49 +43,26 @@ class FixElevation; class FixElevationConfig : public DataProcessorConfig { Q_DECLARE_TR_FUNCTIONS(FixElevationConfig) - friend class ::FixElevation; - protected: - QHBoxLayout *layout; - QLabel *akLabel; - QLineEdit *ak; - public: // there is no config FixElevationConfig(QWidget *parent) : DataProcessorConfig(parent) { HelpWhatsThis *help = new HelpWhatsThis(parent); parent->setWhatsThis(help->getWhatsThisText(HelpWhatsThis::MenuBar_Edit_FixElevationErrors)); - - layout = new QHBoxLayout(this); - - layout->setContentsMargins(0,0,0,0); - setContentsMargins(0,0,0,0); - - akLabel = new QLabel(tr("MapQuest API Key")); - - ak = new QLineEdit(); - layout->addWidget(akLabel); - layout->addWidget(ak); - layout->addStretch(); } QString explain() { - return(QString(tr("Fix or add elevation data. If elevation data is " - "present it will be removed and overwritten." - "\n\nMapQuest API Key is optional, you can get a free one from " - "https::/developer/mapquest.com/ to have your own transaction limits." - "\n\nINTERNET CONNECTION REQUIRED."))); + return tr("Fix or add elevation data. If elevation data is " + "present it will be removed and overwritten." + "\nElevation data is provided by Open-Elevation.com public API," + " consider a donation if you find it useful." + "\n\nINTERNET CONNECTION REQUIRED."); } - void readConfig() { - ak->setText(appsettings->value(NULL, GC_DPFE_AK, "").toString()); - } - - void saveConfig() { - appsettings->setValue(GC_DPFE_AK, ak->text()); - } + void readConfig() {} + void saveConfig() {} }; @@ -117,14 +89,11 @@ class FixElevation : public DataProcessor { // Localized Name QString name() { - return (tr("Fix Elevation errors")); + return tr("Fix Elevation errors"); } private: - QString apiKey; - - QStringList FetchElevationDataFromMapQuest(QString latLngCollection); - + QList FetchElevationData(QString latLngCollection); }; static bool fixElevationAdded = DataProcessorFactory::instance().registerProcessor(QString("Fix Elevation errors"), new FixElevation()); @@ -132,15 +101,9 @@ static bool fixElevationAdded = DataProcessorFactory::instance().registerProcess bool FixElevation::postProcess(RideFile *ride, DataProcessorConfig *config=0, QString op="") { + Q_UNUSED(config) Q_UNUSED(op) - // get settings - if (config == NULL) { // being called automatically - apiKey = appsettings->value(NULL, GC_DPFE_AK, "").toString(); - } else { // being called manually - apiKey = ((FixElevationConfig*)(config))->ak->text(); - } - // Cannot process without without GPS data if (!ride || ride->areDataPresent()->lat == false || ride->areDataPresent()->lon == false) return false; @@ -172,22 +135,22 @@ FixElevation::postProcess(RideFile *ride, DataProcessorConfig *config=0, QString } } - //loop through points and build a string to sent to MapQuest - QStringList elevationPoints; + //loop through points and build a string to sent to Open-Elevation public API + QList elevationPoints; QString latLngCollection = ""; int pointCount = 0; try { for (std::vector::iterator point = elvPoints.begin(); point != elvPoints.end(); ++point) { if (latLngCollection.length() != 0) { - latLngCollection.append(','); + latLngCollection.append('|'); } // these values need extended precision or place marker jumps around. latLngCollection.append(QString::number(point->lat,'g',10)); latLngCollection.append(','); latLngCollection.append(QString::number(point->lon,'g',10)); - if (pointCount == 400) { - elevationPoints = elevationPoints + FetchElevationDataFromMapQuest(latLngCollection); + if (pointCount == 45) { // Open-Elevation has a 1024 bytes limit for Get requests + elevationPoints = elevationPoints + FetchElevationData(latLngCollection); latLngCollection = ""; pointCount = 0; } else { @@ -195,7 +158,7 @@ FixElevation::postProcess(RideFile *ride, DataProcessorConfig *config=0, QString } } if (pointCount > 0) { - elevationPoints = elevationPoints + FetchElevationDataFromMapQuest(latLngCollection); + elevationPoints = elevationPoints + FetchElevationData(latLngCollection); } } catch (QString err) { qDebug() << "Cannot fetch elevation data: " << err; @@ -212,7 +175,7 @@ FixElevation::postProcess(RideFile *ride, DataProcessorConfig *config=0, QString QVector smoothArray(elevationPoints.length()); double lastGoodElevation = 0; for (int i=0; i-1000) { lastGoodElevation = elev; smoothArray[i] = elev; @@ -295,16 +258,14 @@ FixElevation::postProcess(RideFile *ride, DataProcessorConfig *config=0, QString return false; } -QStringList -FixElevation::FetchElevationDataFromMapQuest(QString latLngCollection) +QList +FixElevation::FetchElevationData(QString latLngCollection) { - // http://open.mapquestapi.com/elevation/v1/profile?key=Fmjtd%7Cluur20uznu%2Ca2%3Do5-9ayshw&shapeFormat=raw&latLngCollection=52.677,0.94589,52.6769,0.94565,52.6767,0.94545,52.6765,0.94529,52.6764,0.94511,52.6762,0.94488,52.6761,0.94466,52.6759,0.94453,52.6758,0.9447,52.6756,0.94497,52.6756,0.94527,52.6758,0.94553,52.6759,0.94572,52.6761,0.94594,52.6763,0.94611,52.6765,0.94627,52.6766,0.94635,52.6768,0.94639,52.6771,0.9464,52.6772,0.94639,52.6775,0.94637,52.6777,0.94638,52.6779,0.9464,52.6781,0.94645,52.6783,0.94652,52.6784,0.9466,52.6786,0.94672,52.6788,0.94686,52.679,0.94701,52.6792,0.94713,52.6794,0.94721,52.6796,0.94724 - QStringList elevationPoints; + // https://api.open-elevation.com/api/v1/lookup?locations=10,10|20,20|41.161758,-8.583933 + QList elevationPoints; QNetworkAccessManager *networkMgr = new QNetworkAccessManager(); QNetworkReply *reply = networkMgr->get( QNetworkRequest( - QUrl( QString("http://open.mapquestapi.com/elevation/v1/profile?key=%1" - "&shapeFormat=raw&useFilter=true&latLngCollection=" + latLngCollection ) - .arg(apiKey.isEmpty() ? GC_MAPQUESTAPI_KEY : apiKey) ) ) ); + QUrl( QString("https://api.open-elevation.com/api/v1/lookup?locations=" + latLngCollection ) ) ) ); QEventLoop loop; QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); @@ -313,33 +274,42 @@ FixElevation::FetchElevationDataFromMapQuest(QString latLngCollection) // which in turn will trigger event loop quit. loop.exec(); - QString elevationJSON; + QByteArray elevationJSON; elevationJSON = reply->readAll(); QNetworkReply::NetworkError error = reply->error(); delete networkMgr; - if (elevationJSON.contains("Exceeded developer limit configuration")) - throw QString(QObject::tr("Developer limit exceeded")); - if (elevationJSON.contains("exceeded the number of monthly transactions")) - throw QString(QObject::tr("Monthly free plan limit exceeded")); - if (elevationJSON.contains("Bad Request")) - throw QString(QObject::tr("Bad request")); - if (elevationJSON.contains("Gateway Timeout")) - throw QString(QObject::tr("Gateway Timeout")); if (error == QNetworkReply::TimeoutError) - throw QString(QObject::tr("Connection to remote server timed out")); + throw tr("Connection to remote server timed out"); if (error != QNetworkReply::NoError) - throw QString(QObject::tr("Networkerror: %1")).arg(error); + throw tr("Network error: %1").arg(error); - elevationJSON = elevationJSON.mid(elevationJSON.indexOf("elevationProfile") + 19); - elevationJSON = elevationJSON.mid(0, elevationJSON.indexOf("]")); - elevationJSON.replace("{\"distance\":", ""); - elevationJSON.replace(",\"height\":", "|"); - elevationJSON.replace("}", ""); - //qDebug() << elevationJSON; - elevationPoints = elevationJSON.split(","); + // No error, lets parse the response + QJsonParseError parseError; + QJsonDocument document = QJsonDocument::fromJson(elevationJSON , &parseError); + if (parseError.error == QJsonParseError::NoError) { + + // results ? + QJsonArray results = document["results"].toArray(); + // lets look at that then + if (results.size() > 0) { + + for(int i=0; i