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) {
 
  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.
 
A 3d point representation.
 
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)