mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-13 08:08:42 +00:00
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
This commit is contained in:
committed by
GitHub
parent
84eceebd00
commit
3a34f7ce55
@@ -196,7 +196,6 @@
|
||||
#define GC_DPRP_EQUIPWEIGHT "<global-general>dataprocess/fixrunningpower/equipwheight"
|
||||
#define GC_DPDR_DRAFTM "<global-general>dataprocess/fixrunningpower/draftm"
|
||||
#define GC_DPFV_MA "<global-general>dataprocess/fixspeed/ma"
|
||||
#define GC_DPFE_AK "<global-general>dataprocess/fixelevation/ak"
|
||||
#define GC_CAD2SMO2 "<global-general>dataprocess/fixmoxy/cad2smo2"
|
||||
#define GC_SPD2THB "<global-general>dataprocess/fixmoxy/spd2thb"
|
||||
#define GC_DPFLS_PL "<global-general>dataprocess/fixlapswim/pool_length"
|
||||
|
||||
@@ -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 <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QMessageBox>
|
||||
|
||||
// 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 <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
|
||||
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<double> 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<double> elevationPoints;
|
||||
QString latLngCollection = "";
|
||||
int pointCount = 0;
|
||||
try {
|
||||
for (std::vector<elevationGPSPoint>::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<double> smoothArray(elevationPoints.length());
|
||||
double lastGoodElevation = 0;
|
||||
for (int i=0; i<elevationPoints.length(); i++) {
|
||||
double elev = QString(elevationPoints.at(i).mid(elevationPoints.at(i).indexOf("|")+1)).toDouble();
|
||||
double elev = elevationPoints.at(i);
|
||||
if (elev>-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<double>
|
||||
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<double> 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<results.size(); i++) {
|
||||
|
||||
QJsonObject each = results.at(i).toObject();
|
||||
elevationPoints << each["elevation"].toDouble();
|
||||
}
|
||||
} else {
|
||||
|
||||
throw tr("Unexpected response from server: %1").arg(QString(elevationJSON));
|
||||
}
|
||||
} else {
|
||||
|
||||
// parse error
|
||||
throw tr("Parse response error: %1").arg(parseError.errorString());
|
||||
}
|
||||
|
||||
return elevationPoints;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user