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