QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
Viewer3DTileQuery.cc
Go to the documentation of this file.
1#include "Viewer3DTileQuery.h"
2
4#include "MapProvider.h"
5#include "QGCMapUrlEngine.h"
6
7#include <QtGui/QPainter>
8#include <QtGui/QPixmap>
9#include <QtNetwork/QNetworkAccessManager>
10
11#include <cmath>
12
13QGC_LOGGING_CATEGORY(Viewer3DTileQueryLog, "Viewer3d.Viewer3DTileQuery")
14
15static constexpr int kMaxTileCounts = 200;
16static constexpr int kMaxZoomLevel = 23;
17
19 : QObject{parent}
20{
21}
22
23void Viewer3DTileQuery::MapTileContainer_t::init()
24{
25 mapWidth = (tileMaxIndex.x() - tileMinIndex.x() + 1) * tileSize;
26 mapHeight = (tileMaxIndex.y() - tileMinIndex.y() + 1) * tileSize;
27 mapTextureImage = QImage(mapWidth, mapHeight, QImage::Format_RGBA32FPx4);
28 mapTextureImage.fill(Qt::gray);
29}
30
31void Viewer3DTileQuery::MapTileContainer_t::setMapTile()
32{
33 QPixmap tmpPixmap;
34 tmpPixmap.loadFromData(currentTileData);
35 QImage tmpImage = tmpPixmap.toImage().convertToFormat(QImage::Format_RGBA32FPx4);
36
37 QPainter painter(&mapTextureImage);
38 int idxX = (currentTileIndex.x() - tileMinIndex.x()) * tileSize;
39 int idxY = (currentTileIndex.y() - tileMinIndex.y()) * tileSize;
40 painter.drawImage(idxX, idxY, tmpImage);
41}
42
43QByteArray Viewer3DTileQuery::MapTileContainer_t::mapData() const
44{
45 return QByteArray(reinterpret_cast<const char *>(mapTextureImage.constBits()), mapTextureImage.sizeInBytes());
46}
47
48void Viewer3DTileQuery::MapTileContainer_t::clear()
49{
50 tileList.clear();
51}
52
53void Viewer3DTileQuery::_loadMapTiles(int zoomLevel, QPoint tileMinIndex, QPoint tileMaxIndex)
54{
55 _mapToBeLoaded.clear();
56 _mapToBeLoaded.zoomLevel = zoomLevel;
57 _mapToBeLoaded.tileMinIndex = tileMinIndex;
58 _mapToBeLoaded.tileMaxIndex = tileMaxIndex;
59 _mapToBeLoaded.init();
60
61 if (!_networkManager) {
62 _networkManager = new QNetworkAccessManager(this);
63 _networkManager->setTransferTimeout(9000);
64 }
65
66 for (int x = tileMinIndex.x(); x <= tileMaxIndex.x(); x++) {
67 for (int y = tileMinIndex.y(); y <= tileMaxIndex.y(); y++) {
68 _mapToBeLoaded.tileList.append(_tileKey(_mapId, x, y, zoomLevel));
69
70 auto *reply = new Viewer3DTileReply(zoomLevel, x, y, _mapId, _mapType, _networkManager, this);
71 connect(reply, &Viewer3DTileReply::tileDone, this, &Viewer3DTileQuery::_tileDone);
72 connect(reply, &Viewer3DTileReply::tileGiveUp, this, &Viewer3DTileQuery::_tileGiveUp);
73 connect(reply, &Viewer3DTileReply::tileEmpty, this, &Viewer3DTileQuery::_tileEmpty);
74 }
75 }
76
77 _totalTilesCount = _mapToBeLoaded.tileList.size();
78 _downloadedTilesCount = 0;
79 qCDebug(Viewer3DTileQueryLog) << "Requesting" << _totalTilesCount << "tiles at zoom" << zoomLevel
80 << "x:[" << tileMinIndex.x() << ".." << tileMaxIndex.x() << "]"
81 << "y:[" << tileMinIndex.y() << ".." << tileMaxIndex.y() << "]";
82}
83
84Viewer3DTileQuery::TileStatistics_t Viewer3DTileQuery::_findAndLoadMapTiles(int zoomLevel, const QGeoCoordinate &coordinateMin, const QGeoCoordinate &coordinateMax)
85{
87 if (!provider) {
88 return {};
89 }
90
91 const double lat1 = coordinateMin.latitude();
92 const double lon1 = coordinateMin.longitude();
93 const double lat2 = coordinateMax.latitude();
94 const double lon2 = coordinateMax.longitude();
95
96 const int minTileX = provider->long2tileX(std::fmin(lon1, lon2), zoomLevel);
97 const int maxTileX = provider->long2tileX(std::fmax(lon1, lon2), zoomLevel);
98 const int minTileY = provider->lat2tileY(std::fmax(lat1, lat2), zoomLevel);
99 const int maxTileY = provider->lat2tileY(std::fmin(lat1, lat2), zoomLevel);
100
101 const QPoint minTile(minTileX, minTileY);
102 const QPoint maxTile(maxTileX, maxTileY);
103
104 const QGeoCoordinate nwCoord(provider->tileY2lat(minTileY, zoomLevel),
105 provider->tileX2long(minTileX, zoomLevel), 0);
106 const QGeoCoordinate seCoord(provider->tileY2lat(maxTileY + 1, zoomLevel),
107 provider->tileX2long(maxTileX + 1, zoomLevel), 0);
108
109 const QGeoCoordinate finalMin = QGeoCoordinate(seCoord.latitude(), nwCoord.longitude(), 0);
110 const QGeoCoordinate finalMax = QGeoCoordinate(nwCoord.latitude(), seCoord.longitude(), 0);
111
112 _loadMapTiles(zoomLevel, minTile, maxTile);
113
114 TileStatistics_t output;
115 output.coordinateMin = finalMin;
116 output.coordinateMax = finalMax;
117 output.tileCounts = QSize(maxTile.x() - minTile.x() + 1, maxTile.y() - minTile.y() + 1);
118 output.zoomLevel = zoomLevel;
119
120 return output;
121}
122
123void Viewer3DTileQuery::adaptiveMapTilesLoader(const QString &mapType, int mapId, const QGeoCoordinate &coordinateMin, const QGeoCoordinate &coordinateMax)
124{
125 _mapId = mapId;
126 _mapType = mapType;
127
128 for (_zoomLevel = kMaxZoomLevel; _zoomLevel > 0; _zoomLevel--) {
129 if (maxTileCount(_zoomLevel, coordinateMin, coordinateMax) < kMaxTileCounts) {
130 break;
131 }
132 }
133
134 _textureCoordinateMin = coordinateMin;
135 _textureCoordinateMax = coordinateMax;
136 emit textureGeometryReady(_findAndLoadMapTiles(_zoomLevel, coordinateMin, coordinateMax));
137}
138
139int Viewer3DTileQuery::maxTileCount(int zoomLevel, const QGeoCoordinate &coordinateMin, const QGeoCoordinate &coordinateMax)
140{
142 if (!provider) {
143 return 0;
144 }
145
146 const double minLon = std::fmin(coordinateMin.longitude(), coordinateMax.longitude());
147 const double maxLon = std::fmax(coordinateMin.longitude(), coordinateMax.longitude());
148 const double minLat = std::fmin(coordinateMin.latitude(), coordinateMax.latitude());
149 const double maxLat = std::fmax(coordinateMin.latitude(), coordinateMax.latitude());
150
151 const int minTileX = provider->long2tileX(minLon, zoomLevel);
152 const int maxTileX = provider->long2tileX(maxLon, zoomLevel);
153 const int minTileY = provider->lat2tileY(maxLat, zoomLevel);
154 const int maxTileY = provider->lat2tileY(minLat, zoomLevel);
155
156 return (maxTileX - minTileX + 1) * (maxTileY - minTileY + 1);
157}
158
159void Viewer3DTileQuery::_cleanupReply(Viewer3DTileReply *reply)
160{
161 disconnect(reply, &Viewer3DTileReply::tileDone, this, &Viewer3DTileQuery::_tileDone);
162 disconnect(reply, &Viewer3DTileReply::tileGiveUp, this, &Viewer3DTileQuery::_tileGiveUp);
163 disconnect(reply, &Viewer3DTileReply::tileEmpty, this, &Viewer3DTileQuery::_tileEmpty);
164 reply->deleteLater();
165}
166
167void Viewer3DTileQuery::_tileDone(Viewer3DTileReply::TileInfo_t tileData)
168{
169 auto *reply = qobject_cast<Viewer3DTileReply *>(QObject::sender());
170
171 const QString key = _tileKey(tileData.mapId, tileData.x, tileData.y, tileData.zoomLevel);
172 const qsizetype itemRemoved = _mapToBeLoaded.tileList.removeAll(key);
173
174 if (itemRemoved > 0) {
175 _mapToBeLoaded.currentTileIndex = QPoint(tileData.x, tileData.y);
176 _mapToBeLoaded.currentTileData = tileData.data;
177 _mapToBeLoaded.setMapTile();
178 _downloadedTilesCount++;
179 emit mapTileDownloaded(100.0f * (static_cast<float>(_downloadedTilesCount) / static_cast<float>(_totalTilesCount)));
180
181 if (_mapToBeLoaded.tileList.isEmpty()) {
182 qCDebug(Viewer3DTileQueryLog) << "All tiles downloaded";
183 _downloadedTilesCount = _totalTilesCount;
184 emit loadingMapCompleted();
185 }
186 }
187
188 _cleanupReply(reply);
189}
190
191void Viewer3DTileQuery::_tileGiveUp(Viewer3DTileReply::TileInfo_t tileData)
192{
193 auto *reply = qobject_cast<Viewer3DTileReply *>(QObject::sender());
194 _cleanupReply(reply);
195
196 const QString key = _tileKey(tileData.mapId, tileData.x, tileData.y, tileData.zoomLevel);
197 _mapToBeLoaded.tileList.removeAll(key);
198 _downloadedTilesCount++;
199 emit mapTileDownloaded(100.0f * (static_cast<float>(_downloadedTilesCount) / static_cast<float>(_totalTilesCount)));
200
201 if (_mapToBeLoaded.tileList.isEmpty()) {
202 _downloadedTilesCount = _totalTilesCount;
203 emit loadingMapCompleted();
204 }
205}
206
207void Viewer3DTileQuery::_tileEmpty(Viewer3DTileReply::TileInfo_t tileData)
208{
209 auto *reply = qobject_cast<Viewer3DTileReply *>(QObject::sender());
210 _cleanupReply(reply);
211
212 if (tileData.zoomLevel > 0 && tileData.zoomLevel == _zoomLevel) {
213 _zoomLevel -= 1;
214 emit textureGeometryReady(_findAndLoadMapTiles(_zoomLevel, _textureCoordinateMin, _textureCoordinateMax));
215 }
216}
217
218QString Viewer3DTileQuery::_tileKey(int mapId, int x, int y, int zoomLevel)
219{
220 return QString::asprintf("%010d%08d%08d%03d", mapId, x, y, zoomLevel);
221}
#define QGC_LOGGING_CATEGORY(name, categoryStr)
std::shared_ptr< const MapProvider > SharedMapProvider
static constexpr int kMaxZoomLevel
static constexpr int kMaxTileCounts
static std::shared_ptr< const MapProvider > getMapProviderFromQtMapId(int qtMapId)
void textureGeometryReady(TileStatistics_t tileInfo)
void mapTileDownloaded(float progress)
void adaptiveMapTilesLoader(const QString &mapType, int mapId, const QGeoCoordinate &coordinateMin, const QGeoCoordinate &coordinateMax)
int maxTileCount(int zoomLevel, const QGeoCoordinate &coordinateMin, const QGeoCoordinate &coordinateMax)
void loadingMapCompleted()
void tileDone(TileInfo_t)
void tileEmpty(TileInfo_t)
void tileGiveUp(TileInfo_t)