Marble

VectorTileLayer.cpp
1/*
2 SPDX-License-Identifier: LGPL-2.1-or-later
3
4 SPDX-FileCopyrightText: 2008-2009 Patrick Spendrin <ps_ml@gmx.de>
5 SPDX-FileCopyrightText: 2010 Thibaut Gridel <tgridel@free.fr>
6 SPDX-FileCopyrightText: 2012 Ander Pijoan <ander.pijoan@deusto.es>
7 SPDX-FileCopyrightText: 2013 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
8*/
9
10#include "VectorTileLayer.h"
11
12#include <qmath.h>
13#include <QThreadPool>
14
15#include "VectorTileModel.h"
16#include "GeoPainter.h"
17#include "GeoSceneGroup.h"
18#include "GeoSceneTypes.h"
19#include "GeoSceneVectorTileDataset.h"
20#include "GeoSceneAbstractTileProjection.h"
21#include "MarbleDebug.h"
22#include "TileLoader.h"
23#include "ViewportParams.h"
24#include "RenderState.h"
25#include "GeoDataDocument.h"
26#include "GeoDataLatLonAltBox.h"
27#include "HttpDownloadManager.h"
28#include "TileLoaderHelper.h"
29
30namespace Marble
31{
32
33class Q_DECL_HIDDEN VectorTileLayer::Private
34{
35public:
36 Private(HttpDownloadManager *downloadManager,
37 const PluginManager *pluginManager,
38 VectorTileLayer *parent,
39 GeoDataTreeModel *treeModel);
40
41 ~Private();
42
43 void updateTile(const TileId &tileId, GeoDataDocument* document);
44 void updateLayerSettings();
45
46 QVector<const GeoSceneVectorTileDataset *> findRelevantVectorLayers( const TileId &stackedTileId ) const;
47
48public:
49 VectorTileLayer *const m_parent;
50 TileLoader m_loader;
51 QVector<VectorTileModel *> m_tileModels;
52 QVector<VectorTileModel *> m_activeTileModels;
53 const GeoSceneGroup *m_layerSettings;
54
55 // TreeModel for displaying GeoDataDocuments
56 GeoDataTreeModel *const m_treeModel;
57
58 QThreadPool m_threadPool; // a shared thread pool for all layers to keep CPU usage sane
59};
60
61VectorTileLayer::Private::Private(HttpDownloadManager *downloadManager,
62 const PluginManager *pluginManager,
63 VectorTileLayer *parent,
64 GeoDataTreeModel *treeModel) :
65 m_parent(parent),
66 m_loader(downloadManager, pluginManager),
67 m_tileModels(),
68 m_activeTileModels(),
69 m_layerSettings(nullptr),
70 m_treeModel(treeModel)
71{
72 m_threadPool.setMaxThreadCount(1);
73}
74
75VectorTileLayer::Private::~Private()
76{
77 qDeleteAll(m_activeTileModels);
78}
79
80void VectorTileLayer::Private::updateTile(const TileId &tileId, GeoDataDocument* document)
81{
82 for (VectorTileModel *mapper: m_activeTileModels) {
83 mapper->updateTile(tileId, document);
84 }
85}
86
87void VectorTileLayer::Private::updateLayerSettings()
88{
89 m_activeTileModels.clear();
90
91 for (VectorTileModel *candidate: m_tileModels) {
92 bool enabled = true;
93 if (m_layerSettings) {
94 const bool propertyExists = m_layerSettings->propertyValue(candidate->name(), enabled);
95 enabled |= !propertyExists; // if property doesn't exist, enable layer nevertheless
96 }
97 if (enabled) {
98 m_activeTileModels.append(candidate);
99 mDebug() << "enabling vector layer" << candidate->name();
100 } else {
101 candidate->clear();
102 mDebug() << "disabling vector layer" << candidate->name();
103 }
104 }
105}
106
107VectorTileLayer::VectorTileLayer(HttpDownloadManager *downloadManager,
108 const PluginManager *pluginManager,
109 GeoDataTreeModel *treeModel)
110 : TileLayer()
111 , d(new Private(downloadManager, pluginManager, this, treeModel))
112{
113 qRegisterMetaType<TileId>("TileId");
114 qRegisterMetaType<GeoDataDocument*>("GeoDataDocument*");
115
116 connect(&d->m_loader, SIGNAL(tileCompleted(TileId,GeoDataDocument*)), this, SLOT(updateTile(TileId,GeoDataDocument*)));
117}
118
119VectorTileLayer::~VectorTileLayer()
120{
121 delete d;
122}
123
124RenderState VectorTileLayer::renderState() const
125{
126 return RenderState(QStringLiteral("Vector Tiles"));
127}
128
129int VectorTileLayer::tileZoomLevel() const
130{
131 int level = -1;
132 for (const auto *mapper: d->m_activeTileModels) {
133 level = qMax(level, mapper->tileZoomLevel());
134 }
135 return level;
136}
137
138QString VectorTileLayer::runtimeTrace() const
139{
140 int tiles = 0;
141 for (const auto *mapper: d->m_activeTileModels) {
142 tiles += mapper->cachedDocuments();
143 }
144 int const layers = d->m_activeTileModels.size();
145 return QStringLiteral("Vector Tiles: %1 tiles in %2 layers").arg(tiles).arg(layers);
146}
147
148bool VectorTileLayer::render(GeoPainter *painter, ViewportParams *viewport,
149 const QString &renderPos, GeoSceneLayer *layer)
150{
151 Q_UNUSED(painter);
152 Q_UNUSED(renderPos);
153 Q_UNUSED(layer);
154
155 int const oldLevel = tileZoomLevel();
156 int level = 0;
157 for (VectorTileModel *mapper: d->m_activeTileModels) {
158 mapper->setViewport(viewport->viewLatLonAltBox());
159 level = qMax(level, mapper->tileZoomLevel());
160 }
161 if (oldLevel != level && level >= 0) {
162 emit tileLevelChanged(level);
163 }
164
165 return true;
166}
167
168void VectorTileLayer::reload()
169{
170 for (auto mapper : d->m_activeTileModels) {
171 mapper->reload();
172 }
173}
174
175QSize VectorTileLayer::tileSize() const
176{
177 return QSize(256, 256);
178}
179
180const GeoSceneAbstractTileProjection *VectorTileLayer::tileProjection() const
181{
182 if (!d->m_activeTileModels.isEmpty())
183 return d->m_activeTileModels.first()->layer()->tileProjection();
184 return 0;
185}
186
187int VectorTileLayer::tileColumnCount(int level) const
188{
189 // So far we only support Vector tiles with a single level zero tile
190 return TileLoaderHelper::levelToColumn( 1, level );
191}
192
193int VectorTileLayer::tileRowCount(int level) const
194{
195 // So far we only support Vector tiles with a single level zero tile
196 return TileLoaderHelper::levelToRow( 1, level );
197}
198
199int VectorTileLayer::layerCount() const
200{
201 // So far we only support one sublayer of vector tiles
202 return 1;
203}
204
205void VectorTileLayer::downloadTile(const TileId &id)
206{
207 const QVector<const GeoSceneVectorTileDataset *> vectorLayers = d->findRelevantVectorLayers( id );
208
209 for ( const GeoSceneVectorTileDataset *vectorLayer: vectorLayers ) {
210 if (vectorLayer->tileLevels().isEmpty() || vectorLayer->tileLevels().contains(id.zoomLevel())) {
211 if ( TileLoader::tileStatus( vectorLayer, id ) != TileLoader::Available ) {
212 d->m_loader.downloadTile( vectorLayer, id, DownloadBulk );
213 }
214 }
215 }
216}
217
218void VectorTileLayer::reset()
219{
220 for (VectorTileModel *mapper: d->m_tileModels) {
221 mapper->clear();
222 }
223}
224
225void VectorTileLayer::setMapTheme(const QVector<const GeoSceneVectorTileDataset *> &textures, const GeoSceneGroup *textureLayerSettings)
226{
227 qDeleteAll(d->m_tileModels);
228 d->m_tileModels.clear();
229 d->m_activeTileModels.clear();
230
231 for (const GeoSceneVectorTileDataset *layer: textures) {
232 d->m_tileModels << new VectorTileModel(&d->m_loader, layer, d->m_treeModel, &d->m_threadPool);
233 }
234
235 d->m_layerSettings = textureLayerSettings;
236
237 if (d->m_layerSettings) {
238 connect(d->m_layerSettings, SIGNAL(valueChanged(QString,bool)),
239 this, SLOT(updateLayerSettings()));
240 }
241
242 d->updateLayerSettings();
243 auto const level = tileZoomLevel();
244 if (level >= 0) {
245 emit tileLevelChanged(level);
246 }
247}
248
249QVector<const GeoSceneVectorTileDataset *> VectorTileLayer::Private::findRelevantVectorLayers( const TileId &tileId ) const
250{
252
253 for (VectorTileModel * candidate: m_activeTileModels) {
254 Q_ASSERT( candidate );
255 const GeoSceneVectorTileDataset * vectorTileDataset = candidate->layer();
256 // check, if layer provides tiles for the current level
257 if ( !vectorTileDataset->hasMaximumTileLevel() ||
258 vectorTileDataset->maximumTileLevel() >= tileId.zoomLevel() ) {
259 //check if the tile intersects with texture bounds
260 if (vectorTileDataset->latLonBox().isNull()) {
261 result.append(vectorTileDataset);
262 }
263 else {
264 const GeoDataLatLonBox bbox = vectorTileDataset->tileProjection()->geoCoordinates(tileId);
265
266 if (vectorTileDataset->latLonBox().intersects(bbox)) {
267 result.append( vectorTileDataset );
268 }
269 }
270 }
271 }
272
273 return result;
274}
275
276
277}
278
279#include "moc_VectorTileLayer.cpp"
This file contains the headers for ViewportParams.
QStringView level(QStringView ifopt)
Binds a QML item to a specific geodetic location in screen coordinates.
void append(QList< T > &&value)
void clear()
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:57:57 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.