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
55{
56 if (_terrainQuery) {
57 disconnect(_terrainQuery, &TerrainQueryInterface::coordinateHeightsReceived, this, &TerrainAtCoordinateBatchManager::_coordinateHeights);
58 delete _terrainQuery;
59 }
60 _terrainQuery = terrainQuery;
61 if (_terrainQuery) {
62 _terrainQuery->setParent(this);
63 (void) connect(_terrainQuery, &TerrainQueryInterface::coordinateHeightsReceived, this, &TerrainAtCoordinateBatchManager::_coordinateHeights);
64 }
65}
66
67void TerrainAtCoordinateBatchManager::_sendNextBatch()
68{
69 qCDebug(TerrainQueryLog) << Q_FUNC_INFO << "_state:_requestQueue.count:_sentRequests.count" << _stateToString(_state) << _requestQueue.count() << _sentRequests.count();
70
71 if (_state != TerrainQuery::State::Idle) {
72 // Waiting for last download the complete, wait some more
73 qCDebug(TerrainQueryLog) << Q_FUNC_INFO << "waiting for current batch, restarting timer";
74 _batchTimer->start();
75 return;
76 }
77
78 if (_requestQueue.isEmpty()) {
79 return;
80 }
81
82 _sentRequests.clear();
83
84 // Convert coordinates to point strings for json query
85 QList<QGeoCoordinate> coords;
86 while (!_requestQueue.isEmpty()) {
87 const QueuedRequestInfo_t requestInfo = _requestQueue.dequeue();
88 const SentRequestInfo_t sentRequestInfo = {
89 requestInfo.terrainAtCoordinateQuery,
90 requestInfo.coordinates.count()
91 };
92 (void) _sentRequests.append(sentRequestInfo);
93 coords += requestInfo.coordinates;
94 if (coords.count() > 50) {
95 break;
96 }
97 }
98
99 qCDebug(TerrainQueryLog) << Q_FUNC_INFO << "requesting next batch _state:_requestQueue.count:_sentRequests.count" << _stateToString(_state) << _requestQueue.count() << _sentRequests.count();
100
102 _terrainQuery->requestCoordinateHeights(coords);
103}
104
105void TerrainAtCoordinateBatchManager::_batchFailed()
106{
107 const QList<double> noHeights;
108
109 for (const SentRequestInfo_t &sentRequestInfo: _sentRequests) {
110 if (!sentRequestInfo.terrainAtCoordinateQuery.isNull()) {
111 sentRequestInfo.terrainAtCoordinateQuery->signalTerrainData(false, noHeights);
112 }
113 }
114
115 _sentRequests.clear();
116}
117
118QString TerrainAtCoordinateBatchManager::_stateToString(TerrainQuery::State state)
119{
120 switch (state) {
122 return QStringLiteral("Idle");
124 return QStringLiteral("Downloading");
125 default:
126 break;
127 }
128
129 return QStringLiteral("State unknown");
130}
131
132void TerrainAtCoordinateBatchManager::_coordinateHeights(bool success, const QList<double> &heights)
133{
135
136 qCDebug(TerrainQueryLog) << Q_FUNC_INFO << "signalled success:count" << success << heights.count();
137
138 if (!success) {
139 _batchFailed();
140 return;
141 }
142
143 int currentIndex = 0;
144 for (const SentRequestInfo_t &sentRequestInfo: _sentRequests) {
145 if (!sentRequestInfo.terrainAtCoordinateQuery.isNull()) {
146 qCDebug(TerrainQueryVerboseLog) << Q_FUNC_INFO << "returned TerrainCoordinateQuery:count" << sentRequestInfo.terrainAtCoordinateQuery << sentRequestInfo.cCoord;
147 const QList<double> requestAltitudes = heights.mid(currentIndex, sentRequestInfo.cCoord);
148 sentRequestInfo.terrainAtCoordinateQuery->signalTerrainData(true, requestAltitudes);
149 }
150 currentIndex += sentRequestInfo.cCoord;
151 }
152 _sentRequests.clear();
153
154 if (!_requestQueue.isEmpty()) {
155 _batchTimer->start();
156 }
157}
158
159/*===========================================================================*/
160
162 : QObject(parent)
163 , _autoDelete(autoDelete)
164{
165 qCDebug(TerrainQueryLog) << this;
166}
167
169{
170 qCDebug(TerrainQueryLog) << this;
171}
172
173void TerrainAtCoordinateQuery::requestData(const QList<QGeoCoordinate> &coordinates)
174{
175 if (coordinates.isEmpty()) {
176 return;
177 }
178
180}
181
182bool TerrainAtCoordinateQuery::getAltitudesForCoordinates(const QList<QGeoCoordinate> &coordinates, QList<double> &altitudes, bool &error)
183{
184 return TerrainTileManager::instance()->getAltitudesForCoordinates(coordinates, altitudes, error);
185}
186
187void TerrainAtCoordinateQuery::signalTerrainData(bool success, const QList<double> &heights)
188{
189 emit terrainDataReceived(success, heights);
190 if (_autoDelete) {
191 deleteLater();
192 }
193}
194
195/*===========================================================================*/
196
197TerrainPathQuery::TerrainPathQuery(bool autoDelete, QObject *parent)
198 : QObject(parent)
199 , _autoDelete(autoDelete)
200 , _terrainQuery(new TerrainOfflineQuery(this))
201{
202 qCDebug(TerrainQueryLog) << this;
203
204 qRegisterMetaType<TerrainPathQuery::PathHeightInfo_t>();
205 (void) connect(_terrainQuery, &TerrainQueryInterface::pathHeightsReceived, this, &TerrainPathQuery::_pathHeights);
206}
207
209{
210 qCDebug(TerrainQueryLog) << this;
211}
212
213void TerrainPathQuery::requestData(const QGeoCoordinate &fromCoord, const QGeoCoordinate &toCoord)
214{
215 _terrainQuery->requestPathHeights(fromCoord, toCoord);
216}
217
218void TerrainPathQuery::_pathHeights(bool success, double distanceBetween, double finalDistanceBetween, const QList<double> &heights)
219{
220 PathHeightInfo_t pathHeightInfo;
221 pathHeightInfo.distanceBetween = distanceBetween;
222 pathHeightInfo.finalDistanceBetween = finalDistanceBetween;
223 pathHeightInfo.heights = heights;
224 emit terrainDataReceived(success, pathHeightInfo);
225 if (_autoDelete) {
226 deleteLater();
227 }
228}
229
230/*===========================================================================*/
231
232TerrainAreaQuery::TerrainAreaQuery(bool autoDelete, QObject *parent)
233 : QObject(parent)
234 , _autoDelete(autoDelete)
235 , _terrainQuery(new TerrainOfflineQuery(this))
236{
237 qCDebug(TerrainQueryLog) << this;
238
239 qRegisterMetaType<TerrainAreaQuery::CarpetHeightInfo_t>();
240 (void) connect(_terrainQuery, &TerrainQueryInterface::carpetHeightsReceived, this, &TerrainAreaQuery::_carpetHeights);
241}
242
244{
245 qCDebug(TerrainQueryLog) << this;
246}
247
248void TerrainAreaQuery::requestData(const QGeoCoordinate &swCoord, const QGeoCoordinate &neCoord)
249{
250 _terrainQuery->requestCarpetHeights(swCoord, neCoord, false /* statsOnly */);
251}
252
253void TerrainAreaQuery::_carpetHeights(bool success, double minHeight, double maxHeight, const QList<QList<double>> &carpet)
254{
255 CarpetHeightInfo_t carpetHeightInfo;
256 carpetHeightInfo.minHeight = minHeight;
257 carpetHeightInfo.maxHeight = maxHeight;
258 carpetHeightInfo.carpet = carpet;
259 emit terrainDataReceived(success, carpetHeightInfo);
260 if (_autoDelete) {
261 deleteLater();
262 }
263}
264
265/*===========================================================================*/
266
267TerrainPolyPathQuery::TerrainPolyPathQuery(bool autoDelete, QObject *parent)
268 : QObject(parent)
269 , _autoDelete(autoDelete)
270 , _pathQuery(new TerrainPathQuery(false, this))
271{
272 qCDebug(TerrainQueryLog) << this;
273
274 qRegisterMetaType<QList<TerrainPathQuery::PathHeightInfo_t>>();
275 (void) connect(_pathQuery, &TerrainPathQuery::terrainDataReceived, this, &TerrainPolyPathQuery::_terrainDataReceived);
276}
277
279{
280 qCDebug(TerrainQueryLog) << this;
281}
282
283void TerrainPolyPathQuery::requestData(const QVariantList &polyPath)
284{
285 QList<QGeoCoordinate> path;
286
287 for (const QVariant &geoVar: polyPath) {
288 (void) path.append(geoVar.value<QGeoCoordinate>());
289 }
290
291 requestData(path);
292}
293
294void TerrainPolyPathQuery::requestData(const QList<QGeoCoordinate> &polyPath)
295{
296 qCDebug(TerrainQueryLog) << Q_FUNC_INFO << "count" << polyPath.count();
297
298 if (polyPath.count() < 2) {
299 qCWarning(TerrainQueryLog) << Q_FUNC_INFO << "polyPath requires at least 2 coordinates";
300 emit terrainDataReceived(false, _rgPathHeightInfo);
301 if (_autoDelete) {
302 deleteLater();
303 }
304 return;
305 }
306
307 _rgCoords = polyPath;
308 _curIndex = 0;
309 _pathQuery->requestData(_rgCoords[0], _rgCoords[1]);
310}
311
312void TerrainPolyPathQuery::_terrainDataReceived(bool success, const TerrainPathQuery::PathHeightInfo_t &pathHeightInfo)
313{
314 qCDebug(TerrainQueryLog) << Q_FUNC_INFO << "success:_curIndex" << success << _curIndex;
315
316 if (!success) {
317 _rgPathHeightInfo.clear();
318 emit terrainDataReceived(false, _rgPathHeightInfo);
319 return;
320 }
321
322 (void) _rgPathHeightInfo.append(pathHeightInfo);
323
324 if (++_curIndex >= (_rgCoords.count() - 1)) {
325 qCDebug(TerrainQueryLog) << Q_FUNC_INFO << "complete";
326 emit terrainDataReceived(true, _rgPathHeightInfo);
327 if (_autoDelete) {
328 deleteLater();
329 }
330 } else {
331 _pathQuery->requestData(_rgCoords[_curIndex], _rgCoords[_curIndex + 1]);
332 }
333}
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()
void setTerrainQueryInterface(TerrainQueryInterface *terrainQuery)
Set custom terrain query interface (for testing). Takes ownership.
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)
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.
Base class for offline/online terrain queries.
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()