diff --git a/src/FactSystem/FactMetaData.cc b/src/FactSystem/FactMetaData.cc index c5b8202a9b6773a7cb6ab7266ef32dc7bbb5df89..5dc608cf688cb83b7d835591c4f3625701db5ab9 100644 --- a/src/FactSystem/FactMetaData.cc +++ b/src/FactSystem/FactMetaData.cc @@ -45,25 +45,27 @@ const FactMetaData::BuiltInTranslation_s FactMetaData::_rgBuiltInTranslations[] // Translations driven by app settings const FactMetaData::AppSettingsTranslation_s FactMetaData::_rgAppSettingsTranslations[] = { - { "m", "m", false, UnitsSettings::DistanceUnitsMeters, FactMetaData::_defaultTranslator, FactMetaData::_defaultTranslator }, - { "meters", "meters", false, UnitsSettings::DistanceUnitsMeters, FactMetaData::_defaultTranslator, FactMetaData::_defaultTranslator }, - { "cm/px", "cm/px", false, UnitsSettings::DistanceUnitsMeters, FactMetaData::_defaultTranslator, FactMetaData::_defaultTranslator }, - { "m/s", "m/s", true, UnitsSettings::SpeedUnitsMetersPerSecond, FactMetaData::_defaultTranslator, FactMetaData::_defaultTranslator }, - { "C", "C", false, UnitsSettings::TemperatureUnitsCelsius, FactMetaData::_defaultTranslator, FactMetaData::_defaultTranslator }, - { "m^2", "m^2", false, UnitsSettings::AreaUnitsSquareMeters, FactMetaData::_defaultTranslator, FactMetaData::_defaultTranslator }, - { "m", "ft", false, UnitsSettings::DistanceUnitsFeet, FactMetaData::_metersToFeet, FactMetaData::_feetToMeters }, - { "meters", "ft", false, UnitsSettings::DistanceUnitsFeet, FactMetaData::_metersToFeet, FactMetaData::_feetToMeters }, - { "cm/px", "in/px", false, UnitsSettings::DistanceUnitsFeet, FactMetaData::_centimetersToInches, FactMetaData::_inchesToCentimeters }, - { "m^2", "km^2", false, UnitsSettings::AreaUnitsSquareKilometers, FactMetaData::_squareMetersToSquareKilometers, FactMetaData::_squareKilometersToSquareMeters }, - { "m^2", "ha", false, UnitsSettings::AreaUnitsHectares, FactMetaData::_squareMetersToHectares, FactMetaData::_hectaresToSquareMeters }, - { "m^2", "ft^2", false, UnitsSettings::AreaUnitsSquareFeet, FactMetaData::_squareMetersToSquareFeet, FactMetaData::_squareFeetToSquareMeters }, - { "m^2", "ac", false, UnitsSettings::AreaUnitsAcres, FactMetaData::_squareMetersToAcres, FactMetaData::_acresToSquareMeters }, - { "m^2", "mi^2", false, UnitsSettings::AreaUnitsSquareMiles, FactMetaData::_squareMetersToSquareMiles, FactMetaData::_squareMilesToSquareMeters }, - { "m/s", "ft/s", true, UnitsSettings::SpeedUnitsFeetPerSecond, FactMetaData::_metersToFeet, FactMetaData::_feetToMeters }, - { "m/s", "mph", true, UnitsSettings::SpeedUnitsMilesPerHour, FactMetaData::_metersPerSecondToMilesPerHour, FactMetaData::_milesPerHourToMetersPerSecond }, - { "m/s", "km/h", true, UnitsSettings::SpeedUnitsKilometersPerHour, FactMetaData::_metersPerSecondToKilometersPerHour, FactMetaData::_kilometersPerHourToMetersPerSecond }, - { "m/s", "kn", true, UnitsSettings::SpeedUnitsKnots, FactMetaData::_metersPerSecondToKnots, FactMetaData::_knotsToMetersPerSecond }, - { "C", "F", false, UnitsSettings::TemperatureUnitsFarenheit, FactMetaData::_celsiusToFarenheit, FactMetaData::_farenheitToCelsius }, + { "m", "m", FactMetaData::UnitDistance, UnitsSettings::DistanceUnitsMeters, FactMetaData::_defaultTranslator, FactMetaData::_defaultTranslator }, + { "meter", "meter", FactMetaData::UnitDistance, UnitsSettings::DistanceUnitsMeters, FactMetaData::_defaultTranslator, FactMetaData::_defaultTranslator }, + { "meters", "meters", FactMetaData::UnitDistance, UnitsSettings::DistanceUnitsMeters, FactMetaData::_defaultTranslator, FactMetaData::_defaultTranslator }, + { "cm/px", "cm/px", FactMetaData::UnitDistance, UnitsSettings::DistanceUnitsMeters, FactMetaData::_defaultTranslator, FactMetaData::_defaultTranslator }, + { "m/s", "m/s", FactMetaData::UnitSpeed, UnitsSettings::SpeedUnitsMetersPerSecond, FactMetaData::_defaultTranslator, FactMetaData::_defaultTranslator }, + { "C", "C", FactMetaData::UnitTemperature, UnitsSettings::TemperatureUnitsCelsius, FactMetaData::_defaultTranslator, FactMetaData::_defaultTranslator }, + { "m^2", "m^2", FactMetaData::UnitArea, UnitsSettings::AreaUnitsSquareMeters, FactMetaData::_defaultTranslator, FactMetaData::_defaultTranslator }, + { "m", "ft", FactMetaData::UnitDistance, UnitsSettings::DistanceUnitsFeet, FactMetaData::_metersToFeet, FactMetaData::_feetToMeters }, + { "meter", "ft", FactMetaData::UnitDistance, UnitsSettings::DistanceUnitsFeet, FactMetaData::_metersToFeet, FactMetaData::_feetToMeters }, + { "meters", "ft", FactMetaData::UnitDistance, UnitsSettings::DistanceUnitsFeet, FactMetaData::_metersToFeet, FactMetaData::_feetToMeters }, + { "cm/px", "in/px", FactMetaData::UnitDistance, UnitsSettings::DistanceUnitsFeet, FactMetaData::_centimetersToInches, FactMetaData::_inchesToCentimeters }, + { "m^2", "km^2", FactMetaData::UnitArea, UnitsSettings::AreaUnitsSquareKilometers, FactMetaData::_squareMetersToSquareKilometers, FactMetaData::_squareKilometersToSquareMeters }, + { "m^2", "ha", FactMetaData::UnitArea, UnitsSettings::AreaUnitsHectares, FactMetaData::_squareMetersToHectares, FactMetaData::_hectaresToSquareMeters }, + { "m^2", "ft^2", FactMetaData::UnitArea, UnitsSettings::AreaUnitsSquareFeet, FactMetaData::_squareMetersToSquareFeet, FactMetaData::_squareFeetToSquareMeters }, + { "m^2", "ac", FactMetaData::UnitArea, UnitsSettings::AreaUnitsAcres, FactMetaData::_squareMetersToAcres, FactMetaData::_acresToSquareMeters }, + { "m^2", "mi^2", FactMetaData::UnitArea, UnitsSettings::AreaUnitsSquareMiles, FactMetaData::_squareMetersToSquareMiles, FactMetaData::_squareMilesToSquareMeters }, + { "m/s", "ft/s", FactMetaData::UnitSpeed, UnitsSettings::SpeedUnitsFeetPerSecond, FactMetaData::_metersToFeet, FactMetaData::_feetToMeters }, + { "m/s", "mph", FactMetaData::UnitSpeed, UnitsSettings::SpeedUnitsMilesPerHour, FactMetaData::_metersPerSecondToMilesPerHour, FactMetaData::_milesPerHourToMetersPerSecond }, + { "m/s", "km/h", FactMetaData::UnitSpeed, UnitsSettings::SpeedUnitsKilometersPerHour, FactMetaData::_metersPerSecondToKilometersPerHour, FactMetaData::_kilometersPerHourToMetersPerSecond }, + { "m/s", "kn", FactMetaData::UnitSpeed, UnitsSettings::SpeedUnitsKnots, FactMetaData::_metersPerSecondToKnots, FactMetaData::_knotsToMetersPerSecond }, + { "C", "F", FactMetaData::UnitTemperature, UnitsSettings::TemperatureUnitsFarenheit, FactMetaData::_celsiusToFarenheit, FactMetaData::_farenheitToCelsius }, }; const char* FactMetaData::_decimalPlacesJsonKey = "decimalPlaces"; @@ -799,7 +801,6 @@ size_t FactMetaData::typeToSize(ValueType_t type) } } - /// Set translators according to app settings void FactMetaData::_setAppSettingsTranslators(void) { @@ -807,12 +808,12 @@ void FactMetaData::_setAppSettingsTranslators(void) if (!_enumStrings.count() && (type() == valueTypeDouble || type() == valueTypeFloat)) { for (size_t i=0; irawUnits == _rawUnits && // Temperature - (!pAppSettingsTranslation->speed && pAppSettingsTranslation->speedOrDistanceUnits == qgcApp()->toolbox()->settingsManager()->unitsSettings()->temperatureUnits()->rawValue().toUInt())) || - (pAppSettingsTranslation->rawUnits == _rawUnits.toLower() && // Speed and Distance - ((pAppSettingsTranslation->speed && pAppSettingsTranslation->speedOrDistanceUnits == qgcApp()->toolbox()->settingsManager()->unitsSettings()->speedUnits()->rawValue().toUInt()) || - (!pAppSettingsTranslation->speed && pAppSettingsTranslation->speedOrDistanceUnits == qgcApp()->toolbox()->settingsManager()->unitsSettings()->distanceUnits()->rawValue().toUInt())))) { + if (pAppSettingsTranslation->rawUnits == _rawUnits.toLower() && ( + (pAppSettingsTranslation->unitType == UnitTemperature && pAppSettingsTranslation->unitOption == qgcApp()->toolbox()->settingsManager()->unitsSettings()->temperatureUnits()->rawValue().toUInt()) || + (pAppSettingsTranslation->unitType == UnitSpeed && pAppSettingsTranslation->unitOption == qgcApp()->toolbox()->settingsManager()->unitsSettings()->speedUnits()->rawValue().toUInt()) || + (pAppSettingsTranslation->unitType == UnitDistance && pAppSettingsTranslation->unitOption == qgcApp()->toolbox()->settingsManager()->unitsSettings()->distanceUnits()->rawValue().toUInt()) || + (pAppSettingsTranslation->unitType == UnitArea && pAppSettingsTranslation->unitOption == qgcApp()->toolbox()->settingsManager()->unitsSettings()->areaUnits()->rawValue().toUInt()))) + { _cookedUnits = pAppSettingsTranslation->cookedUnits; setTranslators(pAppSettingsTranslation->rawTranslator, pAppSettingsTranslation->cookedTranslator); return; @@ -825,13 +826,11 @@ const FactMetaData::AppSettingsTranslation_s* FactMetaData::_findAppSettingsDist { for (size_t i=0; irawUnits == rawUnits && - (!pAppSettingsTranslation->speed && pAppSettingsTranslation->speedOrDistanceUnits == qgcApp()->toolbox()->settingsManager()->unitsSettings()->distanceUnits()->rawValue().toUInt())) { + if (pAppSettingsTranslation->rawUnits == rawUnits.toLower() && + (pAppSettingsTranslation->unitType == UnitDistance && pAppSettingsTranslation->unitOption == qgcApp()->toolbox()->settingsManager()->unitsSettings()->distanceUnits()->rawValue().toUInt())) { return pAppSettingsTranslation; } } - return NULL; } @@ -839,10 +838,8 @@ const FactMetaData::AppSettingsTranslation_s* FactMetaData::_findAppSettingsArea { for (size_t i=0; irawUnits == rawUnits && - (!pAppSettingsTranslation->speed && pAppSettingsTranslation->speedOrDistanceUnits == qgcApp()->toolbox()->settingsManager()->unitsSettings()->areaUnits()->rawValue().toUInt()) - ) { + if (pAppSettingsTranslation->rawUnits == rawUnits.toLower() && + (pAppSettingsTranslation->unitType == UnitArea && pAppSettingsTranslation->unitOption == qgcApp()->toolbox()->settingsManager()->unitsSettings()->areaUnits()->rawValue().toUInt())) { return pAppSettingsTranslation; } } diff --git a/src/FactSystem/FactMetaData.h b/src/FactSystem/FactMetaData.h index a61a340a02fbeb3545c48845b71ba53ca69fd630..28c924fa0bdc76b01d5956c4470957a32a13672a 100644 --- a/src/FactSystem/FactMetaData.h +++ b/src/FactSystem/FactMetaData.h @@ -205,14 +205,20 @@ private: static QVariant _celsiusToFarenheit(const QVariant& celsius); static QVariant _farenheitToCelsius(const QVariant& farenheit); - struct AppSettingsTranslation_s { - const char* rawUnits; - const char* cookedUnits; - bool speed; - uint32_t speedOrDistanceUnits; - Translator rawTranslator; - Translator cookedTranslator; + enum UnitTypes { + UnitDistance = 0, + UnitArea, + UnitSpeed, + UnitTemperature + }; + struct AppSettingsTranslation_s { + const char* rawUnits; + const char* cookedUnits; + UnitTypes unitType; + uint32_t unitOption; + Translator rawTranslator; + Translator cookedTranslator; }; static const AppSettingsTranslation_s* _findAppSettingsDistanceUnitsTranslation(const QString& rawUnits); diff --git a/src/MissionManager/MissionSettingsItem.cc b/src/MissionManager/MissionSettingsItem.cc index a5baad04d2c1c27346ca0598ebb24a39ca1280c5..abe14a452a8f4e67363b8592349c89a54f3c2161 100644 --- a/src/MissionManager/MissionSettingsItem.cc +++ b/src/MissionManager/MissionSettingsItem.cc @@ -57,7 +57,6 @@ MissionSettingsItem::MissionSettingsItem(Vehicle* vehicle, QObject* parent) connect(this, &MissionSettingsItem::terrainAltitudeChanged, this, &MissionSettingsItem::_setHomeAltFromTerrain); - connect(&_plannedHomePositionAltitudeFact, &Fact::valueChanged, this, &MissionSettingsItem::_setDirty); connect(&_plannedHomePositionAltitudeFact, &Fact::valueChanged, this, &MissionSettingsItem::_updateAltitudeInCoordinate); connect(&_cameraSection, &CameraSection::dirtyChanged, this, &MissionSettingsItem::_sectionDirtyChanged); @@ -297,11 +296,6 @@ void MissionSettingsItem::setMissionEndRTL(bool missionEndRTL) void MissionSettingsItem::_setHomeAltFromTerrain(double terrainAltitude) { if (!_plannedHomePositionFromVehicle) { - // We need to stop this from signalling, Otherwise the dirty but get set on a delay - // which then marks the Plan view as incorrectly dirty - _plannedHomePositionAltitudeFact.setSendValueChangedSignals(false); _plannedHomePositionAltitudeFact.setRawValue(terrainAltitude); - _plannedHomePositionAltitudeFact.clearDeferredValueChangeSignal(); - _plannedHomePositionAltitudeFact.setSendValueChangedSignals(true); } } diff --git a/src/MissionManager/VisualMissionItem.h b/src/MissionManager/VisualMissionItem.h index a5a9d2296e12514df58d5ab86b78f873c9dbfdfe..c473adce121a907ed16a74ead3f4e0fc92a5a8de 100644 --- a/src/MissionManager/VisualMissionItem.h +++ b/src/MissionManager/VisualMissionItem.h @@ -7,9 +7,7 @@ * ****************************************************************************/ - -#ifndef VisualMissionItem_H -#define VisualMissionItem_H +#pragma once #include #include @@ -215,5 +213,3 @@ private: double _lastLatTerrainQuery; double _lastLonTerrainQuery; }; - -#endif diff --git a/src/PlanView/PlanView.qml b/src/PlanView/PlanView.qml index 329949110e6260c411e63709a1b95002da91ade0..e57f6e167b2e4379d2736936edebdab7c58b387d 100644 --- a/src/PlanView/PlanView.qml +++ b/src/PlanView/PlanView.qml @@ -360,6 +360,9 @@ QGCView { // than computing the coordinate offset. anchors.fill: parent onClicked: { + // Take focus to close any previous editing + editorMap.focus = true + //-- Don't pay attention to items beneath the toolbar. var topLimit = parent.height - ScreenTools.availableHeight if(mouse.y < topLimit) { diff --git a/src/Terrain.cc b/src/Terrain.cc index 3486b04cbb5a87f1d763a5d2808a3cb5109df0e6..43367fe32cabbe123d3eebc1a2e4fb78d66265ae 100644 --- a/src/Terrain.cc +++ b/src/Terrain.cc @@ -17,27 +17,63 @@ #include #include #include +#include -ElevationProvider::ElevationProvider(QObject* parent) - : QObject(parent) +QGC_LOGGING_CATEGORY(ElevationProviderLog, "ElevationProviderLog") + +Q_GLOBAL_STATIC(TerrainBatchManager, _terrainBatchManager) + +TerrainBatchManager::TerrainBatchManager(void) { + _batchTimer.setSingleShot(true); + _batchTimer.setInterval(_batchTimeout); + connect(&_batchTimer, &QTimer::timeout, this, &TerrainBatchManager::_sendNextBatch); +} +void TerrainBatchManager::addQuery(ElevationProvider* elevationProvider, const QList& coordinates) +{ + if (coordinates.length() > 0) { + QueuedRequestInfo_t queuedRequestInfo = { elevationProvider, coordinates }; + _requestQueue.append(queuedRequestInfo); + if (!_batchTimer.isActive()) { + _batchTimer.start(); + } + } } -bool ElevationProvider::queryTerrainData(const QList& coordinates) +void TerrainBatchManager::_sendNextBatch(void) { - if (_state != State::Idle || coordinates.length() == 0) { - return false; + qCDebug(ElevationProviderLog) << "_sendNextBatch _state:_requestQueue.count" << (int)_state << _requestQueue.count(); + + if (_state != State::Idle) { + // Waiting for last download the complete, wait some more + _batchTimer.start(); + return; } - QUrlQuery query; - QString points = ""; - for (const auto& coordinate : coordinates) { - points += QString::number(coordinate.latitude(), 'f', 10) + "," - + QString::number(coordinate.longitude(), 'f', 10) + ","; + if (_requestQueue.count() == 0) { + return; } - points = points.mid(0, points.length() - 1); // remove the last ',' + _sentRequests.clear(); + + // Convert coordinates to point strings for json query + QString points; + foreach (const QueuedRequestInfo_t& requestInfo, _requestQueue) { + SentRequestInfo_t sentRequestInfo = { requestInfo.elevationProvider, requestInfo.coordinates.count() }; + qCDebug(ElevationProviderLog) << "Building request: coordinate count" << requestInfo.coordinates.count(); + _sentRequests.append(sentRequestInfo); + + foreach (const QGeoCoordinate& coord, requestInfo.coordinates) { + points += QString::number(coord.latitude(), 'f', 10) + "," + + QString::number(coord.longitude(), 'f', 10) + ","; + } + + } + points = points.mid(0, points.length() - 1); // remove the last ',' from string + _requestQueue.clear(); + + QUrlQuery query; query.addQueryItem(QStringLiteral("points"), points); QUrl url(QStringLiteral("https://api.airmap.com/elevation/stage/srtm1/ele")); url.setQuery(query); @@ -50,28 +86,36 @@ bool ElevationProvider::queryTerrainData(const QList& coordinate QNetworkReply* networkReply = _networkManager.get(request); if (!networkReply) { - return false; + _batchFailed(); + return; } - connect(networkReply, &QNetworkReply::finished, this, &ElevationProvider::_requestFinished); + connect(networkReply, &QNetworkReply::finished, this, &TerrainBatchManager::_requestFinished); _state = State::Downloading; - return true; } -void ElevationProvider::_requestFinished() +void TerrainBatchManager::_batchFailed(void) +{ + QList noAltitudes; + + foreach (const SentRequestInfo_t& sentRequestInfo, _sentRequests) { + sentRequestInfo.elevationProvider->_signalTerrainData(false, noAltitudes); + } + _sentRequests.clear(); +} + +void TerrainBatchManager::_requestFinished() { + qCDebug(ElevationProviderLog) << "_requestFinished"; QNetworkReply* reply = qobject_cast(QObject::sender()); - QList altitudes; + _state = State::Idle; // When an error occurs we still end up here if (reply->error() != QNetworkReply::NoError) { - QByteArray responseBytes = reply->readAll(); - - QJsonParseError parseError; - QJsonDocument responseJson = QJsonDocument::fromJson(responseBytes, &parseError); - emit terrainData(false, altitudes); + _batchFailed(); + reply->deleteLater(); return; } @@ -80,18 +124,52 @@ void ElevationProvider::_requestFinished() QJsonParseError parseError; QJsonDocument responseJson = QJsonDocument::fromJson(responseBytes, &parseError); if (parseError.error != QJsonParseError::NoError) { - emit terrainData(false, altitudes); + _batchFailed(); + reply->deleteLater(); return; } + QJsonObject rootObject = responseJson.object(); QString status = rootObject["status"].toString(); - if (status == "success") { - const QJsonArray& dataArray = rootObject["data"].toArray(); - for (int i = 0; i < dataArray.count(); i++) { - altitudes.push_back(dataArray[i].toDouble()); - } + if (status != "success") { + _batchFailed(); + reply->deleteLater(); + return; + } - emit terrainData(true, altitudes); + QList altitudes; + const QJsonArray& dataArray = rootObject["data"].toArray(); + for (int i = 0; i < dataArray.count(); i++) { + altitudes.push_back(dataArray[i].toDouble()); + } + + int currentIndex = 0; + foreach (const SentRequestInfo_t& sentRequestInfo, _sentRequests) { + QList requestAltitudes = altitudes.mid(currentIndex, sentRequestInfo.cCoord); + sentRequestInfo.elevationProvider->_signalTerrainData(true, requestAltitudes); + currentIndex += sentRequestInfo.cCoord; } - emit terrainData(false, altitudes); + _sentRequests.clear(); + + reply->deleteLater(); +} + +ElevationProvider::ElevationProvider(QObject* parent) + : QObject(parent) +{ + +} +void ElevationProvider::queryTerrainData(const QList& coordinates) +{ + qCDebug(ElevationProviderLog) << "queryTerrainData: coordinate count" << coordinates.count(); + if (coordinates.length() == 0) { + return; + } + + _terrainBatchManager->addQuery(this, coordinates); +} + +void ElevationProvider::_signalTerrainData(bool success, QList& altitudes) +{ + emit terrainData(success, altitudes); } diff --git a/src/Terrain.h b/src/Terrain.h index bfc987f74da16a984d9c201126106606f759b92c..549db64c7b7f22ee3aabcc681e05d559a4d25e3a 100644 --- a/src/Terrain.h +++ b/src/Terrain.h @@ -9,47 +9,72 @@ #pragma once +#include "QGCLoggingCategory.h" + #include #include #include +#include -/* usage example: - ElevationProvider *p = new ElevationProvider(); - QList coordinates; - QGeoCoordinate c(47.379243, 8.548265); - coordinates.push_back(c); - c.setLatitude(c.latitude()+0.01); - coordinates.push_back(c); - p->queryTerrainData(coordinates); - */ +Q_DECLARE_LOGGING_CATEGORY(ElevationProviderLog) +class ElevationProvider; -class ElevationProvider : public QObject -{ +/// Used internally by ElevationProvider to batch requests together +class TerrainBatchManager : public QObject { Q_OBJECT -public: - ElevationProvider(QObject* parent = NULL); - /** - * Async elevation query for a list of lon,lat coordinates. When the query is done, the terrainData() signal - * is emitted. - * @param coordinates - * @return true on success - */ - bool queryTerrainData(const QList& coordinates); +public: + TerrainBatchManager(void); -signals: - void terrainData(bool success, QList altitudes); + void addQuery(ElevationProvider* elevationProvider, const QList& coordinates); private slots: - void _requestFinished(); + void _sendNextBatch (void); + void _requestFinished (void); + private: + typedef struct { + ElevationProvider* elevationProvider; + QList coordinates; + } QueuedRequestInfo_t; + + typedef struct { + ElevationProvider* elevationProvider; + int cCoord; + } SentRequestInfo_t; + enum class State { Idle, Downloading, }; - State _state = State::Idle; - QNetworkAccessManager _networkManager; + void _batchFailed(void); + + QList _requestQueue; + QList _sentRequests; + State _state = State::Idle; + QNetworkAccessManager _networkManager; + const int _batchTimeout = 500; + QTimer _batchTimer; +}; + +/// NOTE: ElevationProvider is not thread safe. All instances/calls to ElevationProvider must be on main thread. +class ElevationProvider : public QObject +{ + Q_OBJECT +public: + ElevationProvider(QObject* parent = NULL); + + /// Async elevation query for a list of lon,lat coordinates. When the query is done, the terrainData() signal + /// is emitted. + /// @param coordinates to query + void queryTerrainData(const QList& coordinates); + + // Internal method + void _signalTerrainData(bool success, QList& altitudes); + +signals: + void terrainData(bool success, QList altitudes); };