6 #include "DownloadRegion.h"
10 #include "MarbleMath.h"
11 #include "MarbleDebug.h"
12 #include "TextureLayer.h"
13 #include "GeoDataLatLonAltBox.h"
14 #include "GeoDataLineString.h"
15 #include "GeoSceneDocument.h"
16 #include "GeoSceneMap.h"
17 #include "GeoSceneLayer.h"
18 #include "GeoSceneTileDataset.h"
19 #include "GeoSceneAbstractTileProjection.h"
20 #include "TileCoordsPyramid.h"
24 class DownloadRegionPrivate
27 MarbleModel* m_marbleModel;
31 int m_visibleTileLevel;
33 DownloadRegionPrivate();
35 int rad2PixelX( qreal
const lon,
const TileLayer *tileLayer )
const;
37 int rad2PixelY( qreal
const lat,
const TileLayer *tileLayer )
const;
40 DownloadRegionPrivate::DownloadRegionPrivate() : m_marbleModel( nullptr ),
41 m_tileLevelRange( 0, 0 ), m_visibleTileLevel( 0 )
47 int DownloadRegionPrivate::rad2PixelX( qreal
const lon,
const TileLayer *tileLayer )
const
49 qreal tileWidth = tileLayer && tileLayer->layerCount() > 0 ? tileLayer->tileSize().width() : 256;
50 qreal
const globalWidth = tileWidth * tileLayer->tileColumnCount( m_visibleTileLevel );
51 return static_cast<int>(globalWidth * 0.5 * (1 + lon / M_PI));
55 int DownloadRegionPrivate::rad2PixelY( qreal
const lat,
const TileLayer *tileLayer )
const
57 qreal tileHeight = tileLayer && tileLayer->layerCount() > 0 ? tileLayer->tileSize().height() : 256;
58 qreal
const globalHeight = tileHeight * tileLayer->tileRowCount( m_visibleTileLevel );
60 switch (tileLayer->tileProjection()->type()) {
61 case GeoSceneAbstractTileProjection::Equirectangular:
62 return static_cast<int>(globalHeight * (0.5 - lat / M_PI));
63 case GeoSceneAbstractTileProjection::Mercator:
64 if ( fabs( lat ) < 1.4835 )
65 return static_cast<int>(globalHeight * 0.5 * (1 -
gdInv(lat) / M_PI));
67 return static_cast<int>(globalHeight * 0.5 * (1 - 3.1309587 / M_PI));
69 return static_cast<int>(globalHeight * 0.5 * (1 + 3.1309587 / M_PI));
76 DownloadRegion::DownloadRegion(
QObject* parent ) :
QObject( parent ),
77 d( new DownloadRegionPrivate )
82 void DownloadRegion::setMarbleModel( MarbleModel* model )
84 d->m_marbleModel = model;
87 DownloadRegion::~DownloadRegion()
92 void DownloadRegion::setTileLevelRange(
const int minimumTileLevel,
const int maximumTileLevel )
94 Q_ASSERT( minimumTileLevel >= 0 );
95 Q_ASSERT( maximumTileLevel >= 0 );
96 Q_ASSERT( minimumTileLevel <= maximumTileLevel );
97 d->m_tileLevelRange.first = minimumTileLevel;
98 d->m_tileLevelRange.second = maximumTileLevel;
101 QVector<TileCoordsPyramid> DownloadRegion::region(
const TileLayer *tileLayer,
const GeoDataLatLonAltBox &downloadRegion )
const
103 Q_ASSERT( tileLayer );
105 int tileLevelRangeFirst = d->m_tileLevelRange.first;
106 int tileLevelRangeSecond = d->m_tileLevelRange.second;
111 validLevels = validTileLevels(tileType);
115 int lastIndex = validLevels.
count() - 1;
116 for (
int i = 0; i < validLevels.
count(); ++i ) {
117 if (validLevels.
at(lastIndex - i) <= tileLevelRangeSecond
118 && validLevels.
at(lastIndex - i) >= tileLevelRangeFirst) {
119 tileLevelRangeSecond = validLevels.
at(lastIndex - i);
125 int const westX = d->rad2PixelX( downloadRegion.west(), tileLayer );
126 int const northY = d->rad2PixelY( downloadRegion.north(), tileLayer );
127 int const eastX = d->rad2PixelX( downloadRegion.east(), tileLayer );
128 int const southY = d->rad2PixelY( downloadRegion.south(), tileLayer );
131 mDebug() <<
"DownloadRegionDialog downloadRegion:"
132 <<
"north:" << downloadRegion.north()
133 <<
"south:" << downloadRegion.south()
134 <<
"east:" << downloadRegion.east()
135 <<
"west:" << downloadRegion.west();
136 mDebug() <<
"north/west (x/y):" << westX << northY;
137 mDebug() <<
"south/east (x/y):" << eastX << southY;
139 int const tileWidth = tileLayer->tileSize().width();
140 int const tileHeight = tileLayer->tileSize().height();
141 mDebug() <<
"DownloadRegionDialog downloadRegion: tileSize:" << tileWidth << tileHeight;
143 int const visibleLevelX1 = qMin( westX, eastX );
144 int const visibleLevelY1 = qMin( northY, southY );
145 int const visibleLevelX2 = qMax( westX, eastX );
146 int const visibleLevelY2 = qMax( northY, southY );
148 mDebug() <<
"visible level pixel coords (level/x1/y1/x2/y2):" << d->m_visibleTileLevel
149 << visibleLevelX1 << visibleLevelY1 << visibleLevelX2 << visibleLevelY2;
151 int bottomLevelX1, bottomLevelY1, bottomLevelX2, bottomLevelY2;
154 if ( d->m_visibleTileLevel > tileLevelRangeSecond ) {
155 int const deltaLevel = d->m_visibleTileLevel - tileLevelRangeSecond;
156 bottomLevelX1 = visibleLevelX1 >> deltaLevel;
157 bottomLevelY1 = visibleLevelY1 >> deltaLevel;
158 bottomLevelX2 = visibleLevelX2 >> deltaLevel;
159 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;
169 bottomLevelX1 = visibleLevelX1;
170 bottomLevelY1 = visibleLevelY1;
171 bottomLevelX2 = visibleLevelX2;
172 bottomLevelY2 = visibleLevelY2;
174 mDebug() <<
"bottom level pixel coords (level/x1/y1/x2/y2):"
175 << tileLevelRangeSecond
176 << bottomLevelX1 << bottomLevelY1 << bottomLevelX2 << bottomLevelY2;
178 TileCoordsPyramid coordsPyramid( tileLevelRangeFirst, tileLevelRangeSecond );
179 coordsPyramid.setValidTileLevels(validLevels);
181 QRect bottomLevelTileCoords;
183 ( bottomLevelX1 / tileWidth,
184 bottomLevelY1 / tileHeight,
185 bottomLevelX2 / tileWidth + ( bottomLevelX2 % tileWidth > 0 ? 1 : 0 ) - 1,
186 bottomLevelY2 / tileHeight + ( bottomLevelY2 % tileHeight > 0 ? 1 : 0 ) - 1);
187 mDebug() <<
"bottom level tile coords: (x1/y1/size):" << bottomLevelTileCoords;
188 coordsPyramid.setBottomLevelCoords( bottomLevelTileCoords );
190 mDebug() <<
"tiles count:" << coordsPyramid.tilesCount( );
192 pyramid << coordsPyramid;
196 void DownloadRegion::setVisibleTileLevel(
const int tileLevel)
198 d->m_visibleTileLevel = tileLevel;
201 QVector<TileCoordsPyramid> DownloadRegion::fromPath(
const TileLayer *tileLayer, qreal offset,
const GeoDataLineString &waypoints )
const
203 if ( !d->m_marbleModel ) {
207 int tileLevelRangeFirst = d->m_tileLevelRange.first;
208 int tileLevelRangeSecond = d->m_tileLevelRange.second;
213 validLevels = validTileLevels(tileType);
217 int lastIndex = validLevels.
count() - 1;
218 for (
int i = 0; i < validLevels.
count(); ++i ) {
219 if (validLevels.
at(lastIndex - i) <= tileLevelRangeSecond
220 && validLevels.
at(lastIndex - i) >= tileLevelRangeFirst) {
221 tileLevelRangeSecond = validLevels.
at(lastIndex - i);
227 TileCoordsPyramid coordsPyramid( tileLevelRangeFirst, tileLevelRangeSecond );
228 coordsPyramid.setValidTileLevels(validLevels);
230 int const tileWidth = tileLayer->tileSize().width();
231 int const tileHeight = tileLayer->tileSize().height();
233 qreal radius = d->m_marbleModel->planetRadius();
235 qreal radianOffset = offset / radius;
237 for(
int i = 1; i < waypoints.size(); ++i ) {
238 GeoDataCoordinates position = waypoints[i];
239 qreal lonCenter = position.longitude();
240 qreal latCenter = position.latitude();
243 qreal latNorth = asin( sin( latCenter ) * cos( radianOffset ) + cos( latCenter ) * sin( radianOffset ) * cos( 7*M_PI/4 ) );
244 qreal dlonWest = atan2( sin( 7*M_PI/4 ) * sin( radianOffset ) * cos( latCenter ), cos( radianOffset ) - sin( latCenter ) * sin( latNorth ) );
245 qreal lonWest = fmod( lonCenter - dlonWest + M_PI, 2*M_PI ) - M_PI;
246 qreal latSouth = asin( sin( latCenter ) * cos( radianOffset ) + cos( latCenter ) * sin( radianOffset ) * cos( 3*M_PI/4 ) );
247 qreal dlonEast = atan2( sin( 3*M_PI/4 ) * sin( radianOffset ) * cos( latCenter ), cos( radianOffset ) - sin( latCenter ) * sin( latSouth ) );
248 qreal lonEast = fmod( lonCenter - dlonEast+M_PI, 2*M_PI ) - M_PI;
250 int const northY = d->rad2PixelY( latNorth, tileLayer );
251 int const southY = d->rad2PixelY( latSouth, tileLayer );
252 int const eastX = d->rad2PixelX( lonEast, tileLayer );
253 int const westX = d->rad2PixelX( lonWest, tileLayer );
255 int const west = qMin( westX, eastX );
256 int const north = qMin( northY, southY );
257 int const east = qMax( westX, eastX );
258 int const south = qMax( northY, southY );
260 int bottomLevelTileX1 = 0;
261 int bottomLevelTileY1 = 0;
262 int bottomLevelTileX2 = 0;
263 int bottomLevelTileY2 = 0;
265 if ( d->m_visibleTileLevel > tileLevelRangeSecond ) {
266 int const deltaLevel = d->m_visibleTileLevel - tileLevelRangeSecond;
267 bottomLevelTileX1 = west >> deltaLevel;
268 bottomLevelTileY1 = north >> deltaLevel;
269 bottomLevelTileX2 = east >> deltaLevel;
270 bottomLevelTileY2 = south >> deltaLevel;
272 else if ( d->m_visibleTileLevel < tileLevelRangeSecond ) {
273 int const deltaLevel = tileLevelRangeSecond - d->m_visibleTileLevel;
274 bottomLevelTileX1 = west << deltaLevel;
275 bottomLevelTileY1 = north << deltaLevel;
276 bottomLevelTileX2 = east << deltaLevel;
277 bottomLevelTileY2 = south << deltaLevel;
280 bottomLevelTileX1 = west;
281 bottomLevelTileY1 = north;
282 bottomLevelTileX2 = east;
283 bottomLevelTileY2 = south;
286 QRect waypointRegion;
288 waypointRegion.
setCoords( bottomLevelTileX1/tileWidth, bottomLevelTileY1/tileHeight,
289 bottomLevelTileX2/tileWidth, bottomLevelTileY2/tileHeight );
290 coordsPyramid.setBottomLevelCoords( waypointRegion );
291 pyramid << coordsPyramid;
301 GeoSceneMap *
map = d->m_marbleModel->mapTheme()->map();
303 for (
auto layer : layers) {
304 if ((layer->backend() ==
"vectortile" && tileType ==
VectorTileType )
306 GeoSceneTileDataset * dataset =
dynamic_cast<GeoSceneTileDataset*
>(layer->datasets().first());
307 validTileLevels = dataset->tileLevels();
312 return validTileLevels;
317 #include "moc_DownloadRegion.cpp"