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"