Marble

VectorTileLayer.cpp
1 /*
2  SPDX-License-Identifier: LGPL-2.1-or-later
3 
4  SPDX-FileCopyrightText: 2008-2009 Patrick Spendrin <[email protected]>
5  SPDX-FileCopyrightText: 2010 Thibaut Gridel <[email protected]>
6  SPDX-FileCopyrightText: 2012 Ander Pijoan <[email protected]>
7  SPDX-FileCopyrightText: 2013 Bernhard Beschow <[email protected]>
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 
30 namespace Marble
31 {
32 
33 class Q_DECL_HIDDEN VectorTileLayer::Private
34 {
35 public:
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 
48 public:
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 
61 VectorTileLayer::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 
75 VectorTileLayer::Private::~Private()
76 {
77  qDeleteAll(m_activeTileModels);
78 }
79 
80 void VectorTileLayer::Private::updateTile(const TileId &tileId, GeoDataDocument* document)
81 {
82  for (VectorTileModel *mapper: m_activeTileModels) {
83  mapper->updateTile(tileId, document);
84  }
85 }
86 
87 void 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 
107 VectorTileLayer::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 
119 VectorTileLayer::~VectorTileLayer()
120 {
121  delete d;
122 }
123 
124 RenderState VectorTileLayer::renderState() const
125 {
126  return RenderState(QStringLiteral("Vector Tiles"));
127 }
128 
129 int 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 
138 QString 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 
148 bool 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 
168 void VectorTileLayer::reload()
169 {
170  for (auto mapper : d->m_activeTileModels) {
171  mapper->reload();
172  }
173 }
174 
175 QSize VectorTileLayer::tileSize() const
176 {
177  return QSize(256, 256);
178 }
179 
180 const GeoSceneAbstractTileProjection *VectorTileLayer::tileProjection() const
181 {
182  if (!d->m_activeTileModels.isEmpty())
183  return d->m_activeTileModels.first()->layer()->tileProjection();
184  return 0;
185 }
186 
187 int 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 
193 int 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 
199 int VectorTileLayer::layerCount() const
200 {
201  // So far we only support one sublayer of vector tiles
202  return 1;
203 }
204 
205 void 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 
218 void VectorTileLayer::reset()
219 {
220  for (VectorTileModel *mapper: d->m_tileModels) {
221  mapper->clear();
222  }
223 }
224 
225 void 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 
249 QVector<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"
int size() const const
void append(const T &value)
QStringView level(QStringView ifopt)
void clear()
Binds a QML item to a specific geodetic location in screen coordinates.
@ DownloadBulk
Bulk download, for example "File/Download region".
Definition: MarbleGlobal.h:154
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:31
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Sep 25 2023 03:50:20 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.