File indexing completed on 2024-05-05 03:49:50

0001 /*
0002     SPDX-License-Identifier: LGPL-2.1-or-later
0003 
0004     SPDX-FileCopyrightText: 2008-2009 Patrick Spendrin <ps_ml@gmx.de>
0005     SPDX-FileCopyrightText: 2010 Thibaut Gridel <tgridel@free.fr>
0006     SPDX-FileCopyrightText: 2012 Ander Pijoan <ander.pijoan@deusto.es>
0007     SPDX-FileCopyrightText: 2013 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
0008 */
0009 
0010 #include "VectorTileLayer.h"
0011 
0012 #include <qmath.h>
0013 #include <QThreadPool>
0014 
0015 #include "VectorTileModel.h"
0016 #include "GeoPainter.h"
0017 #include "GeoSceneGroup.h"
0018 #include "GeoSceneTypes.h"
0019 #include "GeoSceneVectorTileDataset.h"
0020 #include "GeoSceneAbstractTileProjection.h"
0021 #include "MarbleDebug.h"
0022 #include "TileLoader.h"
0023 #include "ViewportParams.h"
0024 #include "RenderState.h"
0025 #include "GeoDataDocument.h"
0026 #include "GeoDataLatLonAltBox.h"
0027 #include "HttpDownloadManager.h"
0028 #include "TileLoaderHelper.h"
0029 
0030 namespace Marble
0031 {
0032 
0033 class Q_DECL_HIDDEN VectorTileLayer::Private
0034 {
0035 public:
0036     Private(HttpDownloadManager *downloadManager,
0037             const PluginManager *pluginManager,
0038             VectorTileLayer *parent,
0039             GeoDataTreeModel *treeModel);
0040 
0041     ~Private();
0042 
0043     void updateTile(const TileId &tileId, GeoDataDocument* document);
0044     void updateLayerSettings();
0045 
0046     QVector<const GeoSceneVectorTileDataset *> findRelevantVectorLayers( const TileId &stackedTileId ) const;
0047 
0048 public:
0049     VectorTileLayer  *const m_parent;
0050     TileLoader m_loader;
0051     QVector<VectorTileModel *> m_tileModels;
0052     QVector<VectorTileModel *> m_activeTileModels;
0053     const GeoSceneGroup *m_layerSettings;
0054 
0055     // TreeModel for displaying GeoDataDocuments
0056     GeoDataTreeModel *const m_treeModel;
0057 
0058     QThreadPool m_threadPool; // a shared thread pool for all layers to keep CPU usage sane
0059 };
0060 
0061 VectorTileLayer::Private::Private(HttpDownloadManager *downloadManager,
0062                                   const PluginManager *pluginManager,
0063                                   VectorTileLayer *parent,
0064                                   GeoDataTreeModel *treeModel) :
0065     m_parent(parent),
0066     m_loader(downloadManager, pluginManager),
0067     m_tileModels(),
0068     m_activeTileModels(),
0069     m_layerSettings(nullptr),
0070     m_treeModel(treeModel)
0071 {
0072     m_threadPool.setMaxThreadCount(1);
0073 }
0074 
0075 VectorTileLayer::Private::~Private()
0076 {
0077     qDeleteAll(m_activeTileModels);
0078 }
0079 
0080 void VectorTileLayer::Private::updateTile(const TileId &tileId, GeoDataDocument* document)
0081 {
0082     for (VectorTileModel *mapper: m_activeTileModels) {
0083         mapper->updateTile(tileId, document);
0084     }
0085 }
0086 
0087 void VectorTileLayer::Private::updateLayerSettings()
0088 {
0089     m_activeTileModels.clear();
0090 
0091     for (VectorTileModel *candidate: m_tileModels) {
0092         bool enabled = true;
0093         if (m_layerSettings) {
0094             const bool propertyExists = m_layerSettings->propertyValue(candidate->name(), enabled);
0095             enabled |= !propertyExists; // if property doesn't exist, enable layer nevertheless
0096         }
0097         if (enabled) {
0098             m_activeTileModels.append(candidate);
0099             mDebug() << "enabling vector layer" << candidate->name();
0100         } else {
0101             candidate->clear();
0102             mDebug() << "disabling vector layer" << candidate->name();
0103         }
0104     }
0105 }
0106 
0107 VectorTileLayer::VectorTileLayer(HttpDownloadManager *downloadManager,
0108                                  const PluginManager *pluginManager,
0109                                  GeoDataTreeModel *treeModel)
0110     : TileLayer()
0111     , d(new Private(downloadManager, pluginManager, this, treeModel))
0112 {
0113     qRegisterMetaType<TileId>("TileId");
0114     qRegisterMetaType<GeoDataDocument*>("GeoDataDocument*");
0115 
0116     connect(&d->m_loader, SIGNAL(tileCompleted(TileId,GeoDataDocument*)), this, SLOT(updateTile(TileId,GeoDataDocument*)));
0117 }
0118 
0119 VectorTileLayer::~VectorTileLayer()
0120 {
0121     delete d;
0122 }
0123 
0124 RenderState VectorTileLayer::renderState() const
0125 {
0126     return RenderState(QStringLiteral("Vector Tiles"));
0127 }
0128 
0129 int VectorTileLayer::tileZoomLevel() const
0130 {
0131     int level = -1;
0132     for (const auto *mapper: d->m_activeTileModels) {
0133         level = qMax(level, mapper->tileZoomLevel());
0134     }
0135     return level;
0136 }
0137 
0138 QString VectorTileLayer::runtimeTrace() const
0139 {
0140     int tiles = 0;
0141     for (const auto *mapper: d->m_activeTileModels) {
0142         tiles += mapper->cachedDocuments();
0143     }
0144     int const layers = d->m_activeTileModels.size();
0145     return QStringLiteral("Vector Tiles: %1 tiles in %2 layers").arg(tiles).arg(layers);
0146 }
0147 
0148 bool VectorTileLayer::render(GeoPainter *painter, ViewportParams *viewport,
0149                              const QString &renderPos, GeoSceneLayer *layer)
0150 {
0151     Q_UNUSED(painter);
0152     Q_UNUSED(renderPos);
0153     Q_UNUSED(layer);
0154 
0155     int const oldLevel = tileZoomLevel();
0156     int level = 0;
0157     for (VectorTileModel *mapper: d->m_activeTileModels) {
0158         mapper->setViewport(viewport->viewLatLonAltBox());
0159         level = qMax(level, mapper->tileZoomLevel());
0160     }
0161     if (oldLevel != level && level >= 0) {
0162         emit tileLevelChanged(level);
0163     }
0164 
0165     return true;
0166 }
0167 
0168 void VectorTileLayer::reload()
0169 {
0170     for (auto mapper : d->m_activeTileModels) {
0171         mapper->reload();
0172     }
0173 }
0174 
0175 QSize VectorTileLayer::tileSize() const
0176 {
0177     return QSize(256, 256);
0178 }
0179 
0180 const GeoSceneAbstractTileProjection *VectorTileLayer::tileProjection() const
0181 {
0182     if (!d->m_activeTileModels.isEmpty())
0183         return d->m_activeTileModels.first()->layer()->tileProjection();
0184     return 0;
0185 }
0186 
0187 int VectorTileLayer::tileColumnCount(int level) const
0188 {
0189     // So far we only support Vector tiles with a single level zero tile
0190     return TileLoaderHelper::levelToColumn( 1, level );
0191 }
0192 
0193 int VectorTileLayer::tileRowCount(int level) const
0194 {
0195     // So far we only support Vector tiles with a single level zero tile
0196     return TileLoaderHelper::levelToRow( 1, level );
0197 }
0198 
0199 int VectorTileLayer::layerCount() const
0200 {
0201     // So far we only support one sublayer of vector tiles
0202     return 1;
0203 }
0204 
0205 void VectorTileLayer::downloadTile(const TileId &id)
0206 {
0207     const QVector<const GeoSceneVectorTileDataset *> vectorLayers = d->findRelevantVectorLayers( id );
0208 
0209     for ( const GeoSceneVectorTileDataset *vectorLayer: vectorLayers ) {
0210         if (vectorLayer->tileLevels().isEmpty() || vectorLayer->tileLevels().contains(id.zoomLevel())) {
0211             if ( TileLoader::tileStatus( vectorLayer, id ) != TileLoader::Available ) {
0212                 d->m_loader.downloadTile( vectorLayer, id, DownloadBulk );
0213             }
0214         }
0215     }
0216 }
0217 
0218 void VectorTileLayer::reset()
0219 {
0220     for (VectorTileModel *mapper: d->m_tileModels) {
0221         mapper->clear();
0222     }
0223 }
0224 
0225 void VectorTileLayer::setMapTheme(const QVector<const GeoSceneVectorTileDataset *> &textures, const GeoSceneGroup *textureLayerSettings)
0226 {
0227     qDeleteAll(d->m_tileModels);
0228     d->m_tileModels.clear();
0229     d->m_activeTileModels.clear();
0230 
0231     for (const GeoSceneVectorTileDataset *layer: textures) {
0232         d->m_tileModels << new VectorTileModel(&d->m_loader, layer, d->m_treeModel, &d->m_threadPool);
0233     }
0234 
0235     d->m_layerSettings = textureLayerSettings;
0236 
0237     if (d->m_layerSettings) {
0238         connect(d->m_layerSettings, SIGNAL(valueChanged(QString,bool)),
0239                 this,                      SLOT(updateLayerSettings()));
0240     }
0241 
0242     d->updateLayerSettings();
0243     auto const level = tileZoomLevel();
0244     if (level >= 0) {
0245         emit tileLevelChanged(level);
0246     }
0247 }
0248 
0249 QVector<const GeoSceneVectorTileDataset *> VectorTileLayer::Private::findRelevantVectorLayers( const TileId &tileId ) const
0250 {
0251     QVector<const GeoSceneVectorTileDataset *> result;
0252 
0253     for (VectorTileModel * candidate: m_activeTileModels) {
0254         Q_ASSERT( candidate );
0255         const GeoSceneVectorTileDataset * vectorTileDataset = candidate->layer();
0256         // check, if layer provides tiles for the current level
0257         if ( !vectorTileDataset->hasMaximumTileLevel() ||
0258              vectorTileDataset->maximumTileLevel() >= tileId.zoomLevel() ) {
0259             //check if the tile intersects with texture bounds
0260             if (vectorTileDataset->latLonBox().isNull()) {
0261                 result.append(vectorTileDataset);
0262             }
0263             else {
0264                 const GeoDataLatLonBox bbox = vectorTileDataset->tileProjection()->geoCoordinates(tileId);
0265 
0266                 if (vectorTileDataset->latLonBox().intersects(bbox)) {
0267                     result.append( vectorTileDataset );
0268                 }
0269             }
0270         }
0271     }
0272 
0273     return result;
0274 }
0275 
0276 
0277 }
0278 
0279 #include "moc_VectorTileLayer.cpp"