6#include "DownloadRegion.h"
8#include "GeoDataLatLonAltBox.h"
9#include "GeoDataLineString.h"
10#include "GeoSceneAbstractTileProjection.h"
11#include "GeoSceneDocument.h"
12#include "GeoSceneLayer.h"
13#include "GeoSceneMap.h"
14#include "GeoSceneTileDataset.h"
15#include "MarbleDebug.h"
17#include "MarbleMath.h"
19#include "TextureLayer.h"
20#include "TileCoordsPyramid.h"
25class DownloadRegionPrivate
28 MarbleModel *m_marbleModel;
30 QPair<int, int> m_tileLevelRange;
32 int m_visibleTileLevel;
34 DownloadRegionPrivate();
36 int rad2PixelX(qreal
const lon,
const TileLayer *tileLayer)
const;
38 int rad2PixelY(qreal
const lat,
const TileLayer *tileLayer)
const;
41DownloadRegionPrivate::DownloadRegionPrivate()
42 : m_marbleModel(nullptr)
43 , m_tileLevelRange(0, 0)
44 , m_visibleTileLevel(0)
50int DownloadRegionPrivate::rad2PixelX(qreal
const lon,
const TileLayer *tileLayer)
const
52 qreal tileWidth = tileLayer && tileLayer->layerCount() > 0 ? tileLayer->tileSize().width() : 256;
53 qreal
const globalWidth = tileWidth * tileLayer->tileColumnCount(m_visibleTileLevel);
54 return static_cast<int>(globalWidth * 0.5 * (1 + lon / M_PI));
58int DownloadRegionPrivate::rad2PixelY(qreal
const lat,
const TileLayer *tileLayer)
const
60 qreal tileHeight = tileLayer && tileLayer->layerCount() > 0 ? tileLayer->tileSize().height() : 256;
61 qreal
const globalHeight = tileHeight * tileLayer->tileRowCount(m_visibleTileLevel);
63 switch (tileLayer->tileProjection()->type()) {
64 case GeoSceneAbstractTileProjection::Equirectangular:
65 return static_cast<int>(globalHeight * (0.5 - lat / M_PI));
66 case GeoSceneAbstractTileProjection::Mercator:
67 if (fabs(lat) < 1.4835)
68 return static_cast<int>(globalHeight * 0.5 * (1 -
gdInv(lat) / M_PI));
70 return static_cast<int>(globalHeight * 0.5 * (1 - 3.1309587 / M_PI));
72 return static_cast<int>(globalHeight * 0.5 * (1 + 3.1309587 / M_PI));
79DownloadRegion::DownloadRegion(
QObject *parent)
81 , d(new DownloadRegionPrivate)
86void DownloadRegion::setMarbleModel(MarbleModel *model)
88 d->m_marbleModel = model;
91DownloadRegion::~DownloadRegion()
96void DownloadRegion::setTileLevelRange(
const int minimumTileLevel,
const int maximumTileLevel)
98 Q_ASSERT(minimumTileLevel >= 0);
99 Q_ASSERT(maximumTileLevel >= 0);
100 Q_ASSERT(minimumTileLevel <= maximumTileLevel);
101 d->m_tileLevelRange.first = minimumTileLevel;
102 d->m_tileLevelRange.second = maximumTileLevel;
105QList<TileCoordsPyramid> DownloadRegion::region(
const TileLayer *tileLayer,
const GeoDataLatLonAltBox &downloadRegion)
const
109 int tileLevelRangeFirst = d->m_tileLevelRange.first;
110 int tileLevelRangeSecond = d->m_tileLevelRange.second;
112 TileType tileType =
dynamic_cast<const TextureLayer *
>(tileLayer) ? TextureTileType :
VectorTileType;
115 validLevels = validTileLevels(tileType);
119 int lastIndex = validLevels.
count() - 1;
120 for (
int i = 0; i < validLevels.
count(); ++i) {
121 if (validLevels.
at(lastIndex - i) <= tileLevelRangeSecond && validLevels.
at(lastIndex - i) >= tileLevelRangeFirst) {
122 tileLevelRangeSecond = validLevels.
at(lastIndex - i);
128 int const westX = d->rad2PixelX(downloadRegion.west(), tileLayer);
129 int const northY = d->rad2PixelY(downloadRegion.north(), tileLayer);
130 int const eastX = d->rad2PixelX(downloadRegion.east(), tileLayer);
131 int const southY = d->rad2PixelY(downloadRegion.south(), tileLayer);
134 mDebug() <<
"DownloadRegionDialog downloadRegion:"
135 <<
"north:" << downloadRegion.north() <<
"south:" << downloadRegion.south() <<
"east:" << downloadRegion.east()
136 <<
"west:" << downloadRegion.west();
137 mDebug() <<
"north/west (x/y):" << westX << northY;
138 mDebug() <<
"south/east (x/y):" << eastX << southY;
140 int const tileWidth = tileLayer->tileSize().width();
141 int const tileHeight = tileLayer->tileSize().height();
142 mDebug() <<
"DownloadRegionDialog downloadRegion: tileSize:" << tileWidth << tileHeight;
144 int const visibleLevelX1 = qMin(westX, eastX);
145 int const visibleLevelY1 = qMin(northY, southY);
146 int const visibleLevelX2 = qMax(westX, eastX);
147 int const visibleLevelY2 = qMax(northY, southY);
149 mDebug() <<
"visible level pixel coords (level/x1/y1/x2/y2):" << d->m_visibleTileLevel << visibleLevelX1 << visibleLevelY1 << visibleLevelX2
152 int bottomLevelX1, bottomLevelY1, bottomLevelX2, bottomLevelY2;
155 if (d->m_visibleTileLevel > tileLevelRangeSecond) {
156 int const deltaLevel = d->m_visibleTileLevel - tileLevelRangeSecond;
157 bottomLevelX1 = visibleLevelX1 >> deltaLevel;
158 bottomLevelY1 = visibleLevelY1 >> deltaLevel;
159 bottomLevelX2 = visibleLevelX2 >> deltaLevel;
160 bottomLevelY2 = visibleLevelY2 >> deltaLevel;
161 }
else if (d->m_visibleTileLevel < tileLevelRangeSecond) {
162 int const deltaLevel = tileLevelRangeSecond - d->m_visibleTileLevel;
163 bottomLevelX1 = visibleLevelX1 << deltaLevel;
164 bottomLevelY1 = visibleLevelY1 << deltaLevel;
165 bottomLevelX2 = visibleLevelX2 << deltaLevel;
166 bottomLevelY2 = visibleLevelY2 << deltaLevel;
168 bottomLevelX1 = visibleLevelX1;
169 bottomLevelY1 = visibleLevelY1;
170 bottomLevelX2 = visibleLevelX2;
171 bottomLevelY2 = visibleLevelY2;
173 mDebug() <<
"bottom level pixel coords (level/x1/y1/x2/y2):" << tileLevelRangeSecond << bottomLevelX1 << bottomLevelY1 << bottomLevelX2 << bottomLevelY2;
175 TileCoordsPyramid coordsPyramid(tileLevelRangeFirst, tileLevelRangeSecond);
176 coordsPyramid.setValidTileLevels(validLevels);
178 QRect bottomLevelTileCoords;
179 bottomLevelTileCoords.
setCoords(bottomLevelX1 / tileWidth,
180 bottomLevelY1 / tileHeight,
181 bottomLevelX2 / tileWidth + (bottomLevelX2 % tileWidth > 0 ? 1 : 0) - 1,
182 bottomLevelY2 / tileHeight + (bottomLevelY2 % tileHeight > 0 ? 1 : 0) - 1);
183 mDebug() <<
"bottom level tile coords: (x1/y1/size):" << bottomLevelTileCoords;
184 coordsPyramid.setBottomLevelCoords(bottomLevelTileCoords);
186 mDebug() <<
"tiles count:" << coordsPyramid.tilesCount();
188 pyramid << coordsPyramid;
192void DownloadRegion::setVisibleTileLevel(
const int tileLevel)
194 d->m_visibleTileLevel = tileLevel;
197QList<TileCoordsPyramid> DownloadRegion::fromPath(
const TileLayer *tileLayer, qreal offset,
const GeoDataLineString &waypoints)
const
199 if (!d->m_marbleModel) {
203 int tileLevelRangeFirst = d->m_tileLevelRange.first;
204 int tileLevelRangeSecond = d->m_tileLevelRange.second;
206 TileType tileType =
dynamic_cast<const TextureLayer *
>(tileLayer) ? TextureTileType :
VectorTileType;
209 validLevels = validTileLevels(tileType);
213 int lastIndex = validLevels.
count() - 1;
214 for (
int i = 0; i < validLevels.
count(); ++i) {
215 if (validLevels.
at(lastIndex - i) <= tileLevelRangeSecond && validLevels.
at(lastIndex - i) >= tileLevelRangeFirst) {
216 tileLevelRangeSecond = validLevels.
at(lastIndex - i);
222 TileCoordsPyramid coordsPyramid(tileLevelRangeFirst, tileLevelRangeSecond);
223 coordsPyramid.setValidTileLevels(validLevels);
225 int const tileWidth = tileLayer->tileSize().width();
226 int const tileHeight = tileLayer->tileSize().height();
228 qreal radius = d->m_marbleModel->planetRadius();
230 qreal radianOffset = offset / radius;
232 for (
int i = 1; i < waypoints.size(); ++i) {
233 GeoDataCoordinates position = waypoints[i];
234 qreal lonCenter = position.longitude();
235 qreal latCenter = position.latitude();
238 qreal latNorth = asin(sin(latCenter) * cos(radianOffset) + cos(latCenter) * sin(radianOffset) * cos(7 * M_PI / 4));
239 qreal dlonWest = atan2(sin(7 * M_PI / 4) * sin(radianOffset) * cos(latCenter), cos(radianOffset) - sin(latCenter) * sin(latNorth));
240 qreal lonWest = fmod(lonCenter - dlonWest + M_PI, 2 * M_PI) - M_PI;
241 qreal latSouth = asin(sin(latCenter) * cos(radianOffset) + cos(latCenter) * sin(radianOffset) * cos(3 * M_PI / 4));
242 qreal dlonEast = atan2(sin(3 * M_PI / 4) * sin(radianOffset) * cos(latCenter), cos(radianOffset) - sin(latCenter) * sin(latSouth));
243 qreal lonEast = fmod(lonCenter - dlonEast + M_PI, 2 * M_PI) - M_PI;
245 int const northY = d->rad2PixelY(latNorth, tileLayer);
246 int const southY = d->rad2PixelY(latSouth, tileLayer);
247 int const eastX = d->rad2PixelX(lonEast, tileLayer);
248 int const westX = d->rad2PixelX(lonWest, tileLayer);
250 int const west = qMin(westX, eastX);
251 int const north = qMin(northY, southY);
252 int const east = qMax(westX, eastX);
253 int const south = qMax(northY, southY);
255 int bottomLevelTileX1 = 0;
256 int bottomLevelTileY1 = 0;
257 int bottomLevelTileX2 = 0;
258 int bottomLevelTileY2 = 0;
260 if (d->m_visibleTileLevel > tileLevelRangeSecond) {
261 int const deltaLevel = d->m_visibleTileLevel - tileLevelRangeSecond;
262 bottomLevelTileX1 = west >> deltaLevel;
263 bottomLevelTileY1 = north >> deltaLevel;
264 bottomLevelTileX2 = east >> deltaLevel;
265 bottomLevelTileY2 = south >> deltaLevel;
266 }
else if (d->m_visibleTileLevel < tileLevelRangeSecond) {
267 int const deltaLevel = tileLevelRangeSecond - d->m_visibleTileLevel;
268 bottomLevelTileX1 = west << deltaLevel;
269 bottomLevelTileY1 = north << deltaLevel;
270 bottomLevelTileX2 = east << deltaLevel;
271 bottomLevelTileY2 = south << deltaLevel;
273 bottomLevelTileX1 = west;
274 bottomLevelTileY1 = north;
275 bottomLevelTileX2 = east;
276 bottomLevelTileY2 = south;
279 QRect waypointRegion;
281 waypointRegion.
setCoords(bottomLevelTileX1 / tileWidth, bottomLevelTileY1 / tileHeight, bottomLevelTileX2 / tileWidth, bottomLevelTileY2 / tileHeight);
282 coordsPyramid.setBottomLevelCoords(waypointRegion);
283 pyramid << coordsPyramid;
289QList<int> DownloadRegion::validTileLevels(
const TileType tileType)
const
293 GeoSceneMap *
map = d->m_marbleModel->mapTheme()->map();
295 for (
auto layer : std::as_const(layers)) {
296 if ((layer->backend() ==
QLatin1StringView(
"vectortile") && tileType == VectorTileType)
297 || (layer->backend() ==
QLatin1StringView(
"texture") && tileType == TextureTileType)) {
298 GeoSceneTileDataset *dataset =
dynamic_cast<GeoSceneTileDataset *
>(layer->datasets().first());
299 validTileLevels = dataset->tileLevels();
304 return validTileLevels;
309#include "moc_DownloadRegion.cpp"
This file contains the headers for MarbleMap.
This file contains the headers for MarbleModel.
Binds a QML item to a specific geodetic location in screen coordinates.
qreal gdInv(qreal x)
This method is a fast Mac Laurin power series approximation of the.
@ VectorTileType
Tiles that consist of vector data.
const_reference at(qsizetype i) const const
qsizetype count() const const
bool isEmpty() const const
void setCoords(int x1, int y1, int x2, int y2)
QFuture< void > map(Iterator begin, Iterator end, MapFunctor &&function)