QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
TerrainQuery.cc
Go to the documentation of this file.
1#include "TerrainQuery.h"
5
6#include <QtCore/QTimer>
7
8QGC_LOGGING_CATEGORY(TerrainQueryLog, "Terrain.TerrainQuery")
9QGC_LOGGING_CATEGORY(TerrainQueryVerboseLog, "Terrain.TerrainQuery:verbose")
10
11Q_GLOBAL_STATIC(TerrainAtCoordinateBatchManager, _terrainAtCoordinateBatchManager)
12
14 : QObject(parent)
15 , _batchTimer(new QTimer(this))
16 , _terrainQuery(new TerrainOfflineQuery(this))
17{
18 qCDebug(TerrainQueryLog) << this;
19
20 _batchTimer->setSingleShot(true);
21 _batchTimer->setInterval(_batchTimeout);
22
23 (void) connect(_batchTimer, &QTimer::timeout, this, &TerrainAtCoordinateBatchManager::_sendNextBatch);
24 (void) connect(_terrainQuery, &TerrainQueryInterface::coordinateHeightsReceived, this, &TerrainAtCoordinateBatchManager::_coordinateHeights);
25}
26
28{
29 qCDebug(TerrainQueryLog) << this;
30}
31
33{
34 return _terrainAtCoordinateBatchManager();
35}
36
37void TerrainAtCoordinateBatchManager::addQuery(TerrainAtCoordinateQuery *terrainAtCoordinateQuery, const QList<QGeoCoordinate> &coordinates)
38{
39 if (coordinates.isEmpty()) {
40 return;
41 }
42
43 const QueuedRequestInfo_t queuedRequestInfo = {
44 terrainAtCoordinateQuery,
45 coordinates
46 };
47 _requestQueue.enqueue(queuedRequestInfo);
48
49 if (!_batchTimer->isActive()) {
50 _batchTimer->start();
51 }
52}
53
54void TerrainAtCoordinateBatchManager::_sendNextBatch()
55{
56 qCDebug(TerrainQueryLog) << Q_FUNC_INFO << "_state:_requestQueue.count:_sentRequests.count" << _stateToString(_state) << _requestQueue.count() << _sentRequests.count();
57
58 if (_state != TerrainQuery::State::Idle) {
59 // Waiting for last download the complete, wait some more
60 qCDebug(TerrainQueryLog) << Q_FUNC_INFO << "waiting for current batch, restarting timer";
61 _batchTimer->start();
62 return;
63 }
64
65 if (_requestQueue.isEmpty()) {
66 return;
67 }
68
69 _sentRequests.clear();
70
71 // Convert coordinates to point strings for json query
72 QList<QGeoCoordinate> coords;
73 while (!_requestQueue.isEmpty()) {
74 const QueuedRequestInfo_t requestInfo = _requestQueue.dequeue();
75 const SentRequestInfo_t sentRequestInfo = {
76 requestInfo.terrainAtCoordinateQuery,
77 requestInfo.coordinates.count()
78 };
79 (void) _sentRequests.append(sentRequestInfo);
80 coords += requestInfo.coordinates;
81 if (coords.count() > 50) {
82 break;
83 }
84 }
85
86 qCDebug(TerrainQueryLog) << Q_FUNC_INFO << "requesting next batch _state:_requestQueue.count:_sentRequests.count" << _stateToString(_state) << _requestQueue.count() << _sentRequests.count();
87
89 _terrainQuery->requestCoordinateHeights(coords);
90}
91
92void TerrainAtCoordinateBatchManager::_batchFailed()
93{
94 const QList<double> noHeights;
95
96 for (const SentRequestInfo_t &sentRequestInfo: _sentRequests) {
97 if (!sentRequestInfo.terrainAtCoordinateQuery.isNull()) {
98 sentRequestInfo.terrainAtCoordinateQuery->signalTerrainData(false, noHeights);
99 }
100 }
101
102 _sentRequests.clear();
103}
104
105QString TerrainAtCoordinateBatchManager::_stateToString(TerrainQuery::State state)
106{
107 switch (state) {
109 return QStringLiteral("Idle");
111 return QStringLiteral("Downloading");
112 default:
113 break;
114 }
115
116 return QStringLiteral("State unknown");
117}
118
119void TerrainAtCoordinateBatchManager::_coordinateHeights(bool success, const QList<double> &heights)
120{
122
123 qCDebug(TerrainQueryLog) << Q_FUNC_INFO << "signalled success:count" << success << heights.count();
124
125 if (!success) {
126 _batchFailed();
127 return;
128 }
129
130 int currentIndex = 0;
131 for (const SentRequestInfo_t &sentRequestInfo: _sentRequests) {
132 if (!sentRequestInfo.terrainAtCoordinateQuery.isNull()) {
133 qCDebug(TerrainQueryVerboseLog) << Q_FUNC_INFO << "returned TerrainCoordinateQuery:count" << sentRequestInfo.terrainAtCoordinateQuery << sentRequestInfo.cCoord;
134 const QList<double> requestAltitudes = heights.mid(currentIndex, sentRequestInfo.cCoord);
135 sentRequestInfo.terrainAtCoordinateQuery->signalTerrainData(true, requestAltitudes);
136 }
137 currentIndex += sentRequestInfo.cCoord;
138 }
139 _sentRequests.clear();
140
141 if (!_requestQueue.isEmpty()) {
142 _batchTimer->start();
143 }
144}
145
146/*===========================================================================*/
147
149 : QObject(parent)
150 , _autoDelete(autoDelete)
151{
152 qCDebug(TerrainQueryLog) << this;
153}
154
156{
157 qCDebug(TerrainQueryLog) << this;
158}
159
160void TerrainAtCoordinateQuery::requestData(const QList<QGeoCoordinate> &coordinates)
161{
162 if (coordinates.isEmpty()) {
163 return;
164 }
165
167}
168
169bool TerrainAtCoordinateQuery::getAltitudesForCoordinates(const QList<QGeoCoordinate> &coordinates, QList<double> &altitudes, bool &error)
170{
171 return TerrainTileManager::instance()->getAltitudesForCoordinates(coordinates, altitudes, error);
172}
173
174void TerrainAtCoordinateQuery::signalTerrainData(bool success, const QList<double> &heights)
175{
176 emit terrainDataReceived(success, heights);
177 if (_autoDelete) {
178 deleteLater();
179 }
180}
181
182/*===========================================================================*/
183
184TerrainPathQuery::TerrainPathQuery(bool autoDelete, QObject *parent)
185 : QObject(parent)
186 , _autoDelete(autoDelete)
187 , _terrainQuery(new TerrainOfflineQuery(this))
188{
189 qCDebug(TerrainQueryLog) << this;
190
191 qRegisterMetaType<TerrainPathQuery::PathHeightInfo_t>();
192 (void) connect(_terrainQuery, &TerrainQueryInterface::pathHeightsReceived, this, &TerrainPathQuery::_pathHeights);
193}
194
196{
197 qCDebug(TerrainQueryLog) << this;
198}
199
200void TerrainPathQuery::requestData(const QGeoCoordinate &fromCoord, const QGeoCoordinate &toCoord)
201{
202 _terrainQuery->requestPathHeights(fromCoord, toCoord);
203}
204
205void TerrainPathQuery::_pathHeights(bool success, double distanceBetween, double finalDistanceBetween, const QList<double> &heights)
206{
207 PathHeightInfo_t pathHeightInfo;
208 pathHeightInfo.distanceBetween = distanceBetween;
209 pathHeightInfo.finalDistanceBetween = finalDistanceBetween;
210 pathHeightInfo.heights = heights;
211 emit terrainDataReceived(success, pathHeightInfo);
212 if (_autoDelete) {
213 deleteLater();
214 }
215}
216
217/*===========================================================================*/
218
219TerrainAreaQuery::TerrainAreaQuery(bool autoDelete, QObject *parent)
220 : QObject(parent)
221 , _autoDelete(autoDelete)
222 , _terrainQuery(new TerrainOfflineQuery(this))
223{
224 qCDebug(TerrainQueryLog) << this;
225
226 qRegisterMetaType<TerrainAreaQuery::CarpetHeightInfo_t>();
227 (void) connect(_terrainQuery, &TerrainQueryInterface::carpetHeightsReceived, this, &TerrainAreaQuery::_carpetHeights);
228}
229
231{
232 qCDebug(TerrainQueryLog) << this;
233}
234
235void TerrainAreaQuery::requestData(const QGeoCoordinate &swCoord, const QGeoCoordinate &neCoord)
236{
237 _terrainQuery->requestCarpetHeights(swCoord, neCoord, false /* statsOnly */);
238}
239
240void TerrainAreaQuery::_carpetHeights(bool success, double minHeight, double maxHeight, const QList<QList<double>> &carpet)
241{
242 CarpetHeightInfo_t carpetHeightInfo;
243 carpetHeightInfo.minHeight = minHeight;
244 carpetHeightInfo.maxHeight = maxHeight;
245 carpetHeightInfo.carpet = carpet;
246 emit terrainDataReceived(success, carpetHeightInfo);
247 if (_autoDelete) {
248 deleteLater();
249 }
250}
251
252/*===========================================================================*/
253
254TerrainPolyPathQuery::TerrainPolyPathQuery(bool autoDelete, QObject *parent)
255 : QObject(parent)
256 , _autoDelete(autoDelete)
257 , _pathQuery(new TerrainPathQuery(false, this))
258{
259 qCDebug(TerrainQueryLog) << this;
260
261 qRegisterMetaType<QList<TerrainPathQuery::PathHeightInfo_t>>();
262 (void) connect(_pathQuery, &TerrainPathQuery::terrainDataReceived, this, &TerrainPolyPathQuery::_terrainDataReceived);
263}
264
266{
267 qCDebug(TerrainQueryLog) << this;
268}
269
270void TerrainPolyPathQuery::requestData(const QVariantList &polyPath)
271{
272 QList<QGeoCoordinate> path;
273
274 for (const QVariant &geoVar: polyPath) {
275 (void) path.append(geoVar.value<QGeoCoordinate>());
276 }
277
278 requestData(path);
279}
280
281void TerrainPolyPathQuery::requestData(const QList<QGeoCoordinate> &polyPath)
282{
283 qCDebug(TerrainQueryLog) << Q_FUNC_INFO << "count" << polyPath.count();
284
285 if (polyPath.count() < 2) {
286 qCWarning(TerrainQueryLog) << Q_FUNC_INFO << "polyPath requires at least 2 coordinates";
287 emit terrainDataReceived(false, _rgPathHeightInfo);
288 if (_autoDelete) {
289 deleteLater();
290 }
291 return;
292 }
293
294 _rgCoords = polyPath;
295 _curIndex = 0;
296 _pathQuery->requestData(_rgCoords[0], _rgCoords[1]);
297}
298
299void TerrainPolyPathQuery::_terrainDataReceived(bool success, const TerrainPathQuery::PathHeightInfo_t &pathHeightInfo)
300{
301 qCDebug(TerrainQueryLog) << Q_FUNC_INFO << "success:_curIndex" << success << _curIndex;
302
303 if (!success) {
304 _rgPathHeightInfo.clear();
305 emit terrainDataReceived(false, _rgPathHeightInfo);
306 return;
307 }
308
309 (void) _rgPathHeightInfo.append(pathHeightInfo);
310
311 if (++_curIndex >= (_rgCoords.count() - 1)) {
312 qCDebug(TerrainQueryLog) << Q_FUNC_INFO << "complete";
313 emit terrainDataReceived(true, _rgPathHeightInfo);
314 if (_autoDelete) {
315 deleteLater();
316 }
317 } else {
318 _pathQuery->requestData(_rgCoords[_curIndex], _rgCoords[_curIndex + 1]);
319 }
320}
Q_GLOBAL_STATIC(FirmwarePluginFactoryRegister, _firmwarePluginFactoryRegisterInstance)
Error error
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void requestData(const QGeoCoordinate &swCoord, const QGeoCoordinate &neCoord)
void terrainDataReceived(bool success, const TerrainAreaQuery::CarpetHeightInfo_t &carpetHeightInfo)
TerrainAreaQuery(bool autoDelete, QObject *parent=nullptr)
void addQuery(TerrainAtCoordinateQuery *terrainAtCoordinateQuery, const QList< QGeoCoordinate > &coordinates)
static TerrainAtCoordinateBatchManager * instance()
NOTE: TerrainAtCoordinateQuery is not thread safe. All instances/calls to ElevationProvider must be o...
void terrainDataReceived(bool success, const QList< double > &heights)
void requestData(const QList< QGeoCoordinate > &coordinates)
void signalTerrainData(bool success, const QList< double > &heights)
TerrainAtCoordinateQuery(bool autoDelete, QObject *parent=nullptr)
static bool getAltitudesForCoordinates(const QList< QGeoCoordinate > &coordinates, QList< double > &altitudes, bool &error)
void terrainDataReceived(bool success, const TerrainPathQuery::PathHeightInfo_t &pathHeightInfo)
Signalled when terrain data comes back from server.
TerrainPathQuery(bool autoDelete, QObject *parent=nullptr)
TerrainPathHeightInfo PathHeightInfo_t
void requestData(const QGeoCoordinate &fromCoord, const QGeoCoordinate &toCoord)
TerrainPolyPathQuery(bool autoDelete, QObject *parent=nullptr)
void requestData(const QVariantList &polyPath)
void terrainDataReceived(bool success, const QList< TerrainPathQuery::PathHeightInfo_t > &rgPathHeightInfo)
Signalled when terrain data comes back from server.
void pathHeightsReceived(bool success, double distanceBetween, double finalDistanceBetween, const QList< double > &heights)
void carpetHeightsReceived(bool success, double minHeight, double maxHeight, const QList< QList< double > > &carpet)
virtual void requestPathHeights(const QGeoCoordinate &fromCoord, const QGeoCoordinate &toCoord)
virtual void requestCoordinateHeights(const QList< QGeoCoordinate > &coordinates)
void coordinateHeightsReceived(bool success, const QList< double > &heights)
virtual void requestCarpetHeights(const QGeoCoordinate &swCoord, const QGeoCoordinate &neCoord, bool statsOnly)
bool getAltitudesForCoordinates(const QList< QGeoCoordinate > &coordinates, QList< double > &altitudes, bool &error)
static TerrainTileManager * instance()
double distanceBetween
Distance between each height value.