QGIS API Documentation  3.14.0-Pi (9f7028fd23)
qgsvectortilelayer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectortilelayer.cpp
3  --------------------------------------
4  Date : March 2020
5  Copyright : (C) 2020 by Martin Dobias
6  Email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsvectortilelayer.h"
17 
18 #include "qgslogger.h"
20 #include "qgsmbtiles.h"
23 #include "qgsvectortilelabeling.h"
24 #include "qgsvectortileloader.h"
25 #include "qgsvectortileutils.h"
26 
27 #include "qgsdatasourceuri.h"
28 
29 
30 QgsVectorTileLayer::QgsVectorTileLayer( const QString &uri, const QString &baseName )
32 {
33  mDataSource = uri;
34 
35  mValid = loadDataSource();
36 
37  // set a default renderer
41 }
42 
43 bool QgsVectorTileLayer::loadDataSource()
44 {
45  QgsDataSourceUri dsUri;
46  dsUri.setEncodedUri( mDataSource );
47 
48  mSourceType = dsUri.param( QStringLiteral( "type" ) );
49  mSourcePath = dsUri.param( QStringLiteral( "url" ) );
50  if ( mSourceType == QStringLiteral( "xyz" ) )
51  {
52  if ( !QgsVectorTileUtils::checkXYZUrlTemplate( mSourcePath ) )
53  {
54  QgsDebugMsg( QStringLiteral( "Invalid format of URL for XYZ source: " ) + mSourcePath );
55  return false;
56  }
57 
58  // online tiles
59  mSourceMinZoom = 0;
60  mSourceMaxZoom = 14;
61 
62  if ( dsUri.hasParam( QStringLiteral( "zmin" ) ) )
63  mSourceMinZoom = dsUri.param( QStringLiteral( "zmin" ) ).toInt();
64  if ( dsUri.hasParam( QStringLiteral( "zmax" ) ) )
65  mSourceMaxZoom = dsUri.param( QStringLiteral( "zmax" ) ).toInt();
66 
67  setExtent( QgsRectangle( -20037508.3427892, -20037508.3427892, 20037508.3427892, 20037508.3427892 ) );
68  }
69  else if ( mSourceType == QStringLiteral( "mbtiles" ) )
70  {
71  QgsMbTiles reader( mSourcePath );
72  if ( !reader.open() )
73  {
74  QgsDebugMsg( QStringLiteral( "failed to open MBTiles file: " ) + mSourcePath );
75  return false;
76  }
77 
78  QString format = reader.metadataValue( QStringLiteral( "format" ) );
79  if ( format != QStringLiteral( "pbf" ) )
80  {
81  QgsDebugMsg( QStringLiteral( "Cannot open MBTiles for vector tiles. Format = " ) + format );
82  return false;
83  }
84 
85  QgsDebugMsgLevel( QStringLiteral( "name: " ) + reader.metadataValue( QStringLiteral( "name" ) ), 2 );
86  bool minZoomOk, maxZoomOk;
87  int minZoom = reader.metadataValue( QStringLiteral( "minzoom" ) ).toInt( &minZoomOk );
88  int maxZoom = reader.metadataValue( QStringLiteral( "maxzoom" ) ).toInt( &maxZoomOk );
89  if ( minZoomOk )
90  mSourceMinZoom = minZoom;
91  if ( maxZoomOk )
92  mSourceMaxZoom = maxZoom;
93  QgsDebugMsgLevel( QStringLiteral( "zoom range: %1 - %2" ).arg( mSourceMinZoom ).arg( mSourceMaxZoom ), 2 );
94 
95  QgsRectangle r = reader.extent();
96  QgsCoordinateTransform ct( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ),
97  QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ), transformContext() );
98  r = ct.transformBoundingBox( r );
99  setExtent( r );
100  }
101  else
102  {
103  QgsDebugMsg( QStringLiteral( "Unknown source type: " ) + mSourceType );
104  return false;
105  }
106 
107  setCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ) );
108  return true;
109 }
110 
112 
113 
115 {
116  QgsVectorTileLayer *layer = new QgsVectorTileLayer( source(), name() );
117  layer->setRenderer( renderer() ? renderer()->clone() : nullptr );
118  return layer;
119 }
120 
122 {
123  return new QgsVectorTileLayerRenderer( this, rendererContext );
124 }
125 
126 bool QgsVectorTileLayer::readXml( const QDomNode &layerNode, QgsReadWriteContext &context )
127 {
128  mValid = loadDataSource();
129 
130  QString errorMsg;
131  if ( !readSymbology( layerNode, errorMsg, context ) )
132  return false;
133 
134  readStyleManager( layerNode );
135  return true;
136 }
137 
138 bool QgsVectorTileLayer::writeXml( QDomNode &layerNode, QDomDocument &doc, const QgsReadWriteContext &context ) const
139 {
140  QDomElement mapLayerNode = layerNode.toElement();
141  mapLayerNode.setAttribute( QStringLiteral( "type" ), QStringLiteral( "vector-tile" ) );
142 
143  writeStyleManager( layerNode, doc );
144 
145  QString errorMsg;
146  return writeSymbology( layerNode, doc, errorMsg, context );
147 }
148 
149 bool QgsVectorTileLayer::readSymbology( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
150 {
151  QDomElement elem = node.toElement();
152 
153  readCommonStyle( elem, context, categories );
154 
155  QDomElement elemRenderer = elem.firstChildElement( QStringLiteral( "renderer" ) );
156  if ( elemRenderer.isNull() )
157  {
158  errorMessage = tr( "Missing <renderer> tag" );
159  return false;
160  }
161  QString rendererType = elemRenderer.attribute( QStringLiteral( "type" ) );
162  QgsVectorTileRenderer *r = nullptr;
163  if ( rendererType == QStringLiteral( "basic" ) )
165  else
166  {
167  errorMessage = tr( "Unknown renderer type: " ) + rendererType;
168  return false;
169  }
170 
171  r->readXml( elemRenderer, context );
172  setRenderer( r );
173 
174  setLabeling( nullptr );
175  QDomElement elemLabeling = elem.firstChildElement( QStringLiteral( "labeling" ) );
176  if ( !elemLabeling.isNull() )
177  {
178  QString labelingType = elemLabeling.attribute( QStringLiteral( "type" ) );
179  QgsVectorTileLabeling *labeling = nullptr;
180  if ( labelingType == QStringLiteral( "basic" ) )
182  else
183  {
184  errorMessage = tr( "Unknown labeling type: " ) + rendererType;
185  }
186 
187  if ( labeling )
188  {
189  labeling->readXml( elemLabeling, context );
191  }
192  }
193 
194  return true;
195 }
196 
197 bool QgsVectorTileLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
198 {
199  Q_UNUSED( errorMessage )
200  QDomElement elem = node.toElement();
201 
202  writeCommonStyle( elem, doc, context, categories );
203 
204  if ( mRenderer )
205  {
206  QDomElement elemRenderer = doc.createElement( QStringLiteral( "renderer" ) );
207  elemRenderer.setAttribute( QStringLiteral( "type" ), mRenderer->type() );
208  mRenderer->writeXml( elemRenderer, context );
209  elem.appendChild( elemRenderer );
210  }
211 
212  if ( mLabeling )
213  {
214  QDomElement elemLabeling = doc.createElement( QStringLiteral( "labeling" ) );
215  elemLabeling.setAttribute( QStringLiteral( "type" ), mLabeling->type() );
216  mLabeling->writeXml( elemLabeling, context );
217  elem.appendChild( elemLabeling );
218  }
219 
220  return true;
221 }
222 
224 {
225  Q_UNUSED( transformContext )
226 }
227 
228 QString QgsVectorTileLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
229 {
230  QgsDataSourceUri dsUri;
231  dsUri.setEncodedUri( source );
232 
233  QString sourceType = dsUri.param( QStringLiteral( "type" ) );
234  QString sourcePath = dsUri.param( QStringLiteral( "url" ) );
235  if ( sourceType == QStringLiteral( "xyz" ) )
236  {
237  QUrl sourceUrl( sourcePath );
238  if ( sourceUrl.isLocalFile() )
239  {
240  // relative path will become "file:./x.txt"
241  QString relSrcUrl = context.pathResolver().writePath( sourceUrl.toLocalFile() );
242  dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
243  dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( relSrcUrl ).toString() );
244  return dsUri.encodedUri();
245  }
246  }
247  else if ( sourceType == QStringLiteral( "mbtiles" ) )
248  {
250  dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
251  dsUri.setParam( QStringLiteral( "url" ), sourcePath );
252  return dsUri.encodedUri();
253  }
254 
255  return source;
256 }
257 
258 QString QgsVectorTileLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
259 {
260  Q_UNUSED( provider )
261 
262  QgsDataSourceUri dsUri;
263  dsUri.setEncodedUri( source );
264 
265  QString sourceType = dsUri.param( QStringLiteral( "type" ) );
266  QString sourcePath = dsUri.param( QStringLiteral( "url" ) );
267  if ( sourceType == QStringLiteral( "xyz" ) )
268  {
269  QUrl sourceUrl( sourcePath );
270  if ( sourceUrl.isLocalFile() ) // file-based URL? convert to relative path
271  {
272  QString absSrcUrl = context.pathResolver().readPath( sourceUrl.toLocalFile() );
273  dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
274  dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( absSrcUrl ).toString() );
275  return dsUri.encodedUri();
276  }
277  }
278  else if ( sourceType == QStringLiteral( "mbtiles" ) )
279  {
281  dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
282  dsUri.setParam( QStringLiteral( "url" ), sourcePath );
283  return dsUri.encodedUri();
284  }
285 
286  return source;
287 }
288 
290 {
291  QgsTileMatrix tileMatrix = QgsTileMatrix::fromWebMercator( tileID.zoomLevel() );
292  QgsTileRange tileRange( tileID.column(), tileID.column(), tileID.row(), tileID.row() );
293  QList<QgsVectorTileRawData> rawTiles = QgsVectorTileLoader::blockingFetchTileRawData( mSourceType, mSourcePath, tileMatrix, QPointF(), tileRange );
294  if ( rawTiles.isEmpty() )
295  return QByteArray();
296  return rawTiles.first().data;
297 }
298 
300 {
301  mRenderer.reset( r );
302  triggerRepaint();
303 }
304 
306 {
307  return mRenderer.get();
308 }
309 
311 {
312  mLabeling.reset( labeling );
313  triggerRepaint();
314 }
315 
317 {
318  return mLabeling.get();
319 }
QgsMapLayer::readCommonStyle
void readCommonStyle(const QDomElement &layerElement, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories)
Read style data common to all layer types.
Definition: qgsmaplayer.cpp:1619
QgsVectorTileLayer::QgsVectorTileLayer
QgsVectorTileLayer(const QString &path=QString(), const QString &baseName=QString())
Constructs a new vector tile layer.
Definition: qgsvectortilelayer.cpp:30
QgsDataSourceUri
Definition: qgsdatasourceuri.h:35
QgsVectorTileLayer
Definition: qgsvectortilelayer.h:83
QgsCoordinateTransformContext
Definition: qgscoordinatetransformcontext.h:57
QgsVectorTileLayer::sourceType
QString sourceType() const
Returns type of the data source.
Definition: qgsvectortilelayer.h:116
QgsTileXYZ
Definition: qgstiles.h:32
QgsReadWriteContext
Definition: qgsreadwritecontext.h:34
QgsTileRange
Definition: qgstiles.h:65
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
qgsvectortilelabeling.h
QgsMapLayerType
QgsMapLayerType
Definition: qgsmaplayer.h:67
QgsVectorTileLayer::setRenderer
void setRenderer(QgsVectorTileRenderer *r)
Sets renderer for the map layer.
Definition: qgsvectortilelayer.cpp:299
QgsVectorTileBasicRenderer
Definition: qgsvectortilebasicrenderer.h:127
QgsRenderContext
Definition: qgsrendercontext.h:57
QgsVectorTileBasicLabeling
Definition: qgsvectortilebasiclabeling.h:107
QgsVectorTileLayer::~QgsVectorTileLayer
~QgsVectorTileLayer() override
QgsVectorTileLayerRenderer
Definition: qgsvectortilelayerrenderer.h:40
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsMapLayer::setCrs
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
Definition: qgsmaplayer.cpp:769
QgsRectangle
Definition: qgsrectangle.h:41
QgsVectorTileLayer::clone
QgsVectorTileLayer * clone() const override
Returns a new instance equivalent to this one except for the id which is still unique.
Definition: qgsvectortilelayer.cpp:114
QgsMapLayerRenderer
Definition: qgsmaplayerrenderer.h:50
qgsmbtiles.h
QgsVectorTileLayer::encodedSource
QString encodedSource(const QString &source, const QgsReadWriteContext &context) const FINAL
Called by writeLayerXML(), used by derived classes to encode provider's specific data source to proje...
Definition: qgsvectortilelayer.cpp:228
qgsvectortilelayer.h
QgsDataSourceUri::param
QString param(const QString &key) const
Returns a generic parameter value corresponding to the specified key.
Definition: qgsdatasourceuri.cpp:823
QgsMapLayer::triggerRepaint
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
Definition: qgsmaplayer.cpp:1817
QgsVectorTileLayer::sourcePath
QString sourcePath() const
Returns URL/path of the data source (syntax different to each data source type)
Definition: qgsvectortilelayer.h:118
QgsPathResolver::writePath
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
Definition: qgspathresolver.cpp:187
QgsTileMatrix
Definition: qgstiles.h:102
QgsMbTiles
Definition: qgsmbtiles.h:38
QgsVectorTileLayer::createMapRenderer
virtual QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext) override
Returns new instance of QgsMapLayerRenderer that will be used for rendering of given context.
Definition: qgsvectortilelayer.cpp:121
QgsVectorTileUtils::checkXYZUrlTemplate
static bool checkXYZUrlTemplate(const QString &url)
Checks whether the URL template string is correct (contains {x}, {y} / {-y}, {z} placeholders)
Definition: qgsvectortileutils.cpp:136
QgsMapLayer::mValid
bool mValid
Indicates if the layer is valid and can be drawn.
Definition: qgsmaplayer.h:1518
QgsMapLayer::setExtent
virtual void setExtent(const QgsRectangle &rect)
Sets the extent.
Definition: qgsmaplayer.cpp:1849
qgsdatasourceuri.h
QgsVectorTileRenderer
Definition: qgsvectortilerenderer.h:88
QgsMapLayer::readStyleManager
void readStyleManager(const QDomNode &layerNode)
Read style manager's configuration (if any). To be called by subclasses.
Definition: qgsmaplayer.cpp:637
QgsMapLayer::writeCommonStyle
void writeCommonStyle(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const
Write style data common to all layer types.
Definition: qgsmaplayer.cpp:540
QgsVectorTileRenderer::readXml
virtual void readXml(const QDomElement &elem, const QgsReadWriteContext &context)=0
Reads renderer's properties from given XML element.
QgsVectorTileLayer::renderer
QgsVectorTileRenderer * renderer() const
Returns currently assigned renderer.
Definition: qgsvectortilelayer.cpp:305
QgsDataSourceUri::setParam
void setParam(const QString &key, const QString &value)
Sets a generic parameter value on the URI.
Definition: qgsdatasourceuri.cpp:778
QgsVectorTileLoader::blockingFetchTileRawData
static QList< QgsVectorTileRawData > blockingFetchTileRawData(const QString &sourceType, const QString &sourcePath, const QgsTileMatrix &tileMatrix, const QPointF &viewCenter, const QgsTileRange &range)
Returns raw tile data for the specified range of tiles. Blocks the caller until all tiles are fetched...
Definition: qgsvectortileloader.cpp:146
QgsVectorTileLayer::setLabeling
void setLabeling(QgsVectorTileLabeling *labeling)
Sets labeling for the map layer.
Definition: qgsvectortilelayer.cpp:310
QgsMapLayer::mDataSource
QString mDataSource
Data source description string, varies by layer type.
Definition: qgsmaplayer.h:1521
QgsDataSourceUri::removeParam
int removeParam(const QString &key)
Removes a generic parameter by key.
Definition: qgsdatasourceuri.cpp:802
QgsVectorTileLayer::writeXml
virtual bool writeXml(QDomNode &layerNode, QDomDocument &doc, const QgsReadWriteContext &context) const override
Called by writeLayerXML(), used by children to write state specific to them to project files.
Definition: qgsvectortilelayer.cpp:138
QgsTileXYZ::zoomLevel
int zoomLevel() const
Returns tile's zoom level (Z)
Definition: qgstiles.h:59
QgsCoordinateReferenceSystem
Definition: qgscoordinatereferencesystem.h:206
qgsvectortileloader.h
QgsDataSourceUri::hasParam
bool hasParam(const QString &key) const
Returns true if a parameter with the specified key exists.
Definition: qgsdatasourceuri.cpp:849
QgsPathResolver::readPath
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
Definition: qgspathresolver.cpp:35
QgsMapLayer::source
QString source() const
Returns the source for the layer.
Definition: qgsmaplayer.cpp:192
QgsMapLayer::writeStyleManager
void writeStyleManager(QDomNode &layerNode, QDomDocument &doc) const
Write style manager's configuration (if exists). To be called by subclasses.
Definition: qgsmaplayer.cpp:646
QgsDataSourceUri::encodedUri
QByteArray encodedUri() const
Returns the complete encoded URI as a byte array.
Definition: qgsdatasourceuri.cpp:610
QgsMapLayer::transformContext
QgsCoordinateTransformContext transformContext() const
Returns the layer data provider coordinate transform context or a default transform context if the la...
Definition: qgsmaplayer.cpp:783
QgsDataSourceUri::setEncodedUri
void setEncodedUri(const QByteArray &uri)
Sets the complete encoded uri.
Definition: qgsdatasourceuri.cpp:630
QgsVectorTileLayer::readSymbology
virtual bool readSymbology(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) override
Read the symbology for the current layer from the DOM node supplied.
Definition: qgsvectortilelayer.cpp:149
QgsVectorTileLayer::labeling
QgsVectorTileLabeling * labeling() const
Returns currently assigned labeling.
Definition: qgsvectortilelayer.cpp:316
QgsTileXYZ::row
int row() const
Returns tile's row index (Y)
Definition: qgstiles.h:57
QgsMapLayer
Definition: qgsmaplayer.h:81
qgsvectortilelayerrenderer.h
QgsMapLayerType::VectorTileLayer
@ VectorTileLayer
Added in 3.14.
QgsMapLayer::name
QString name
Definition: qgsmaplayer.h:85
qgsvectortilebasicrenderer.h
QgsVectorTileLayer::getRawTile
QByteArray getRawTile(QgsTileXYZ tileID)
Fetches raw tile data for the give tile coordinates.
Definition: qgsvectortilelayer.cpp:289
QgsVectorTileLayer::decodedSource
QString decodedSource(const QString &source, const QString &provider, const QgsReadWriteContext &context) const FINAL
Called by readLayerXML(), used by derived classes to decode provider's specific data source from proj...
Definition: qgsvectortilelayer.cpp:258
QgsTileMatrix::fromWebMercator
static QgsTileMatrix fromWebMercator(int mZoomLevel)
Returns a tile matrix for the usual web mercator.
Definition: qgstiles.cpp:20
QgsVectorTileLayer::setTransformContext
virtual void setTransformContext(const QgsCoordinateTransformContext &transformContext) override
Sets the coordinate transform context to transformContext.
Definition: qgsvectortilelayer.cpp:223
QgsVectorTileLabeling
Definition: qgsvectortilelabeling.h:57
QgsVectorTileLayer::readXml
virtual bool readXml(const QDomNode &layerNode, QgsReadWriteContext &context) override
Called by readLayerXML(), used by children to read state specific to them from project files.
Definition: qgsvectortilelayer.cpp:126
QgsVectorTileBasicRenderer::simpleStyleWithRandomColors
static QList< QgsVectorTileBasicRendererStyle > simpleStyleWithRandomColors()
Returns a list of styles to render all layers, using random colors.
Definition: qgsvectortilebasicrenderer.cpp:234
qgslogger.h
qgsvectortileutils.h
QgsCoordinateTransform
Definition: qgscoordinatetransform.h:52
qgsvectortilebasiclabeling.h
QgsVectorTileLabeling::readXml
virtual void readXml(const QDomElement &elem, const QgsReadWriteContext &context)=0
Reads labeling properties from given XML element.
QgsVectorTileLayer::writeSymbology
virtual bool writeSymbology(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const override
Write the style for the layer into the docment provided.
Definition: qgsvectortilelayer.cpp:197
QgsReadWriteContext::pathResolver
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
Definition: qgsreadwritecontext.cpp:47
QgsTileXYZ::column
int column() const
Returns tile's column index (X)
Definition: qgstiles.h:55