File indexing completed on 2025-01-05 03:59:19

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