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

KDE's Doxygen guidelines are available online.