QGIS API Documentation  3.25.0-Master (6b426f5f8a)
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"
21 #include "qgsvtpktiles.h"
24 #include "qgsvectortilelabeling.h"
25 #include "qgsvectortileloader.h"
26 #include "qgsvectortileutils.h"
28 
29 #include "qgsdatasourceuri.h"
33 #include "qgsjsonutils.h"
34 #include "qgspainting.h"
35 #include "qgsmaplayerfactory.h"
36 #include "qgsarcgisrestutils.h"
37 
38 #include <QUrl>
39 #include <QUrlQuery>
40 
41 QgsVectorTileLayer::QgsVectorTileLayer( const QString &uri, const QString &baseName, const LayerOptions &options )
43  , mTransformContext( options.transformContext )
44 {
46 
47  mDataSource = uri;
48 
49  setValid( loadDataSource() );
50 
51  // set a default renderer
55 }
56 
57 void QgsVectorTileLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &, const QgsDataProvider::ProviderOptions &, QgsDataProvider::ReadFlags )
58 {
59  mDataSource = dataSource;
60  mLayerName = baseName;
61  mDataProvider.reset();
62 
63  setValid( loadDataSource() );
64 }
65 
66 bool QgsVectorTileLayer::loadDataSource()
67 {
68  QgsDataSourceUri dsUri;
69  dsUri.setEncodedUri( mDataSource );
70 
71  setCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ) );
72 
73  mSourceType = dsUri.param( QStringLiteral( "type" ) );
74  mSourcePath = dsUri.param( QStringLiteral( "url" ) );
75  if ( mSourceType == QLatin1String( "xyz" ) && dsUri.param( QStringLiteral( "serviceType" ) ) == QLatin1String( "arcgis" ) )
76  {
77  if ( !setupArcgisVectorTileServiceConnection( mSourcePath, dsUri ) )
78  return false;
79  }
80  else if ( mSourceType == QLatin1String( "xyz" ) )
81  {
82  if ( !QgsVectorTileUtils::checkXYZUrlTemplate( mSourcePath ) )
83  {
84  QgsDebugMsg( QStringLiteral( "Invalid format of URL for XYZ source: " ) + mSourcePath );
85  return false;
86  }
87 
88  // online tiles
89  int zMin = 0;
90  if ( dsUri.hasParam( QStringLiteral( "zmin" ) ) )
91  zMin = dsUri.param( QStringLiteral( "zmin" ) ).toInt();
92 
93  int zMax = 14;
94  if ( dsUri.hasParam( QStringLiteral( "zmax" ) ) )
95  zMax = dsUri.param( QStringLiteral( "zmax" ) ).toInt();
96 
97  mMatrixSet = QgsVectorTileMatrixSet::fromWebMercator( zMin, zMax );
98  setExtent( QgsRectangle( -20037508.3427892, -20037508.3427892, 20037508.3427892, 20037508.3427892 ) );
99  }
100  else if ( mSourceType == QLatin1String( "mbtiles" ) )
101  {
102  QgsMbTiles reader( mSourcePath );
103  if ( !reader.open() )
104  {
105  QgsDebugMsg( QStringLiteral( "failed to open MBTiles file: " ) + mSourcePath );
106  return false;
107  }
108 
109  const QString format = reader.metadataValue( QStringLiteral( "format" ) );
110  if ( format != QLatin1String( "pbf" ) )
111  {
112  QgsDebugMsg( QStringLiteral( "Cannot open MBTiles for vector tiles. Format = " ) + format );
113  return false;
114  }
115 
116  QgsDebugMsgLevel( QStringLiteral( "name: " ) + reader.metadataValue( QStringLiteral( "name" ) ), 2 );
117  bool minZoomOk, maxZoomOk;
118  const int minZoom = reader.metadataValue( QStringLiteral( "minzoom" ) ).toInt( &minZoomOk );
119  const int maxZoom = reader.metadataValue( QStringLiteral( "maxzoom" ) ).toInt( &maxZoomOk );
120  if ( minZoomOk )
121  mMatrixSet.dropMatricesOutsideZoomRange( minZoom, 99 );
122  if ( maxZoomOk )
123  mMatrixSet.dropMatricesOutsideZoomRange( 0, maxZoom );
124  QgsDebugMsgLevel( QStringLiteral( "zoom range: %1 - %2" ).arg( mMatrixSet.minimumZoom() ).arg( mMatrixSet.maximumZoom() ), 2 );
125 
126  QgsRectangle r = reader.extent();
127  QgsCoordinateTransform ct( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ),
128  QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ), transformContext() );
129  ct.setBallparkTransformsAreAppropriate( true );
130  r = ct.transformBoundingBox( r );
131  setExtent( r );
132  }
133  else if ( mSourceType == QLatin1String( "vtpk" ) )
134  {
135  QgsVtpkTiles reader( mSourcePath );
136  if ( !reader.open() )
137  {
138  QgsDebugMsg( QStringLiteral( "failed to open VTPK file: " ) + mSourcePath );
139  return false;
140  }
141 
142  const QVariantMap metadata = reader.metadata();
143  const QString format = metadata.value( QStringLiteral( "tileInfo" ) ).toMap().value( QStringLiteral( "format" ) ).toString();
144  if ( format != QLatin1String( "pbf" ) )
145  {
146  QgsDebugMsg( QStringLiteral( "Cannot open VTPK for vector tiles. Format = " ) + format );
147  return false;
148  }
149 
150  mMatrixSet = reader.matrixSet();
151  setCrs( mMatrixSet.crs() );
152  setExtent( reader.extent( transformContext() ) );
153  }
154  else
155  {
156  QgsDebugMsg( QStringLiteral( "Unknown source type: " ) + mSourceType );
157  return false;
158  }
159 
160  const QgsDataProvider::ProviderOptions providerOptions { mTransformContext };
161  const QgsDataProvider::ReadFlags flags;
162  mDataProvider.reset( new QgsVectorTileDataProvider( providerOptions, flags ) );
163  mProviderKey = mDataProvider->name();
164 
165  return true;
166 }
167 
168 bool QgsVectorTileLayer::setupArcgisVectorTileServiceConnection( const QString &uri, const QgsDataSourceUri &dataSourceUri )
169 {
170  QUrl url( uri );
171  // some services don't default to json format, while others do... so let's explicitly request it!
172  // (refs https://github.com/qgis/QGIS/issues/4231)
173  QUrlQuery query;
174  query.addQueryItem( QStringLiteral( "f" ), QStringLiteral( "pjson" ) );
175  url.setQuery( query );
176 
177  QNetworkRequest request = QNetworkRequest( url );
178 
179  QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsVectorTileLayer" ) )
180 
181  QgsBlockingNetworkRequest networkRequest;
182  switch ( networkRequest.get( request ) )
183  {
185  break;
186 
190  return false;
191  }
192 
193  const QgsNetworkReplyContent content = networkRequest.reply();
194  const QByteArray raw = content.content();
195 
196  // Parse data
197  QJsonParseError err;
198  const QJsonDocument doc = QJsonDocument::fromJson( raw, &err );
199  if ( doc.isNull() )
200  {
201  return false;
202  }
203  mArcgisLayerConfiguration = doc.object().toVariantMap();
204  if ( mArcgisLayerConfiguration.contains( QStringLiteral( "error" ) ) )
205  {
206  return false;
207  }
208 
209  mArcgisLayerConfiguration.insert( QStringLiteral( "serviceUri" ), uri );
210  mSourcePath = uri + '/' + mArcgisLayerConfiguration.value( QStringLiteral( "tiles" ) ).toList().value( 0 ).toString();
211  if ( !QgsVectorTileUtils::checkXYZUrlTemplate( mSourcePath ) )
212  {
213  QgsDebugMsg( QStringLiteral( "Invalid format of URL for XYZ source: " ) + mSourcePath );
214  return false;
215  }
216 
217  mMatrixSet.fromEsriJson( mArcgisLayerConfiguration );
218  setCrs( mMatrixSet.crs() );
219 
220  // if hardcoded zoom limits aren't specified, take them from the server
221  if ( dataSourceUri.hasParam( QStringLiteral( "zmin" ) ) )
222  mMatrixSet.dropMatricesOutsideZoomRange( dataSourceUri.param( QStringLiteral( "zmin" ) ).toInt(), 99 );
223 
224  if ( dataSourceUri.hasParam( QStringLiteral( "zmax" ) ) )
225  mMatrixSet.dropMatricesOutsideZoomRange( 0, dataSourceUri.param( QStringLiteral( "zmax" ) ).toInt() );
226 
227  const QVariantMap fullExtent = mArcgisLayerConfiguration.value( QStringLiteral( "fullExtent" ) ).toMap();
228  if ( !fullExtent.isEmpty() )
229  {
230  const QgsRectangle fullExtentRect(
231  fullExtent.value( QStringLiteral( "xmin" ) ).toDouble(),
232  fullExtent.value( QStringLiteral( "ymin" ) ).toDouble(),
233  fullExtent.value( QStringLiteral( "xmax" ) ).toDouble(),
234  fullExtent.value( QStringLiteral( "ymax" ) ).toDouble()
235  );
236 
237  const QgsCoordinateReferenceSystem fullExtentCrs = QgsArcGisRestUtils::convertSpatialReference( fullExtent.value( QStringLiteral( "spatialReference" ) ).toMap() );
238  const QgsCoordinateTransform extentTransform( fullExtentCrs, crs(), transformContext() );
239  try
240  {
241  setExtent( extentTransform.transformBoundingBox( fullExtentRect ) );
242  }
243  catch ( QgsCsException & )
244  {
245  QgsDebugMsg( QStringLiteral( "Could not transform layer fullExtent to layer CRS" ) );
246  }
247  }
248  else
249  {
250  // if no fullExtent specified in JSON, default to web mercator specs full extent
251  const QgsCoordinateTransform extentTransform( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ), crs(), transformContext() );
252  try
253  {
254  setExtent( extentTransform.transformBoundingBox( QgsRectangle( -20037508.3427892, -20037508.3427892, 20037508.3427892, 20037508.3427892 ) ) );
255  }
256  catch ( QgsCsException & )
257  {
258  QgsDebugMsg( QStringLiteral( "Could not transform layer extent to layer CRS" ) );
259  }
260  }
261 
262  return true;
263 }
264 
266 
267 
269 {
270  const QgsVectorTileLayer::LayerOptions options( mTransformContext );
271  QgsVectorTileLayer *layer = new QgsVectorTileLayer( source(), name(), options );
272  layer->setRenderer( renderer() ? renderer()->clone() : nullptr );
273  return layer;
274 }
275 
277 {
278  return mDataProvider.get();
279 }
280 
282 {
283  return mDataProvider.get();
284 }
285 
287 {
288  return new QgsVectorTileLayerRenderer( this, rendererContext );
289 }
290 
291 bool QgsVectorTileLayer::readXml( const QDomNode &layerNode, QgsReadWriteContext &context )
292 {
293  setValid( loadDataSource() );
294 
295  const QDomElement matrixSetElement = layerNode.firstChildElement( QStringLiteral( "matrixSet" ) );
296  if ( !matrixSetElement.isNull() )
297  {
298  mMatrixSet.readXml( matrixSetElement, context );
299  setCrs( mMatrixSet.crs() );
300  }
301 
302  QString errorMsg;
303  if ( !readSymbology( layerNode, errorMsg, context ) )
304  return false;
305 
306  readStyleManager( layerNode );
307  return true;
308 }
309 
310 bool QgsVectorTileLayer::writeXml( QDomNode &layerNode, QDomDocument &doc, const QgsReadWriteContext &context ) const
311 {
312  QDomElement mapLayerNode = layerNode.toElement();
313  mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( QgsMapLayerType::VectorTileLayer ) );
314 
315  mapLayerNode.appendChild( mMatrixSet.writeXml( doc, context ) );
316 
317  // add provider node
318  if ( mDataProvider )
319  {
320  QDomElement provider = doc.createElement( QStringLiteral( "provider" ) );
321  const QDomText providerText = doc.createTextNode( providerType() );
322  provider.appendChild( providerText );
323  mapLayerNode.appendChild( provider );
324  }
325 
326  writeStyleManager( layerNode, doc );
327 
328  QString errorMsg;
329  return writeSymbology( layerNode, doc, errorMsg, context );
330 }
331 
332 bool QgsVectorTileLayer::readSymbology( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
333 {
334  const QDomElement elem = node.toElement();
335 
336  readCommonStyle( elem, context, categories );
337 
338  const QDomElement elemRenderer = elem.firstChildElement( QStringLiteral( "renderer" ) );
339  if ( elemRenderer.isNull() )
340  {
341  errorMessage = tr( "Missing <renderer> tag" );
342  return false;
343  }
344  const QString rendererType = elemRenderer.attribute( QStringLiteral( "type" ) );
345 
346  if ( categories.testFlag( Symbology ) )
347  {
348  QgsVectorTileRenderer *r = nullptr;
349  if ( rendererType == QLatin1String( "basic" ) )
351  else
352  {
353  errorMessage = tr( "Unknown renderer type: " ) + rendererType;
354  return false;
355  }
356 
357  r->readXml( elemRenderer, context );
358  setRenderer( r );
359  }
360 
361  if ( categories.testFlag( Labeling ) )
362  {
363  setLabeling( nullptr );
364  const QDomElement elemLabeling = elem.firstChildElement( QStringLiteral( "labeling" ) );
365  if ( !elemLabeling.isNull() )
366  {
367  const QString labelingType = elemLabeling.attribute( QStringLiteral( "type" ) );
368  QgsVectorTileLabeling *labeling = nullptr;
369  if ( labelingType == QLatin1String( "basic" ) )
371  else
372  {
373  errorMessage = tr( "Unknown labeling type: " ) + rendererType;
374  }
375 
376  if ( labeling )
377  {
378  labeling->readXml( elemLabeling, context );
380  }
381  }
382  }
383 
384  if ( categories.testFlag( Symbology ) )
385  {
386  // get and set the blend mode if it exists
387  const QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
388  if ( !blendModeNode.isNull() )
389  {
390  const QDomElement e = blendModeNode.toElement();
391  setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( e.text().toInt() ) ) );
392  }
393  }
394 
395  // get and set the layer transparency
396  if ( categories.testFlag( Rendering ) )
397  {
398  const QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
399  if ( !layerOpacityNode.isNull() )
400  {
401  const QDomElement e = layerOpacityNode.toElement();
402  setOpacity( e.text().toDouble() );
403  }
404  }
405 
406  return true;
407 }
408 
409 bool QgsVectorTileLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
410 {
411  Q_UNUSED( errorMessage )
412  QDomElement elem = node.toElement();
413 
414  writeCommonStyle( elem, doc, context, categories );
415 
416  if ( mRenderer )
417  {
418  QDomElement elemRenderer = doc.createElement( QStringLiteral( "renderer" ) );
419  elemRenderer.setAttribute( QStringLiteral( "type" ), mRenderer->type() );
420  if ( categories.testFlag( Symbology ) )
421  {
422  mRenderer->writeXml( elemRenderer, context );
423  }
424  elem.appendChild( elemRenderer );
425  }
426 
427  if ( mLabeling && categories.testFlag( Labeling ) )
428  {
429  QDomElement elemLabeling = doc.createElement( QStringLiteral( "labeling" ) );
430  elemLabeling.setAttribute( QStringLiteral( "type" ), mLabeling->type() );
431  mLabeling->writeXml( elemLabeling, context );
432  elem.appendChild( elemLabeling );
433  }
434 
435  if ( categories.testFlag( Symbology ) )
436  {
437  // add the blend mode field
438  QDomElement blendModeElem = doc.createElement( QStringLiteral( "blendMode" ) );
439  const QDomText blendModeText = doc.createTextNode( QString::number( QgsPainting::getBlendModeEnum( blendMode() ) ) );
440  blendModeElem.appendChild( blendModeText );
441  node.appendChild( blendModeElem );
442  }
443 
444  // add the layer opacity
445  if ( categories.testFlag( Rendering ) )
446  {
447  QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
448  const QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
449  layerOpacityElem.appendChild( layerOpacityText );
450  node.appendChild( layerOpacityElem );
451  }
452 
453  return true;
454 }
455 
457 {
458  if ( mDataProvider )
459  mDataProvider->setTransformContext( transformContext );
460 
461  mTransformContext = transformContext;
463 }
464 
465 QString QgsVectorTileLayer::loadDefaultStyle( bool &resultFlag )
466 {
467  QString error;
468  QStringList warnings;
469  resultFlag = loadDefaultStyle( error, warnings );
470  return error;
471 }
472 
473 Qgis::MapLayerProperties QgsVectorTileLayer::properties() const
474 {
475  Qgis::MapLayerProperties res;
476  if ( mSourceType == QLatin1String( "xyz" ) )
477  {
478  // always consider xyz vector tiles as basemap layers
480  }
481  else
482  {
483  // TODO when should we consider mbtiles layers as basemap layers? potentially if their extent is "large"?
484  }
485 
486  return res;
487 }
488 
489 bool QgsVectorTileLayer::loadDefaultStyle( QString &error, QStringList &warnings )
490 {
491  QgsDataSourceUri dsUri;
492  dsUri.setEncodedUri( mDataSource );
493 
494  QVariantMap styleDefinition;
496  QString styleUrl;
497  if ( !dsUri.param( QStringLiteral( "styleUrl" ) ).isEmpty() )
498  {
499  styleUrl = dsUri.param( QStringLiteral( "styleUrl" ) );
500  }
501  else if ( mSourceType == QLatin1String( "xyz" ) && dsUri.param( QStringLiteral( "serviceType" ) ) == QLatin1String( "arcgis" ) )
502  {
503  // for ArcMap VectorTileServices we default to the defaultStyles URL from the layer configuration
504  styleUrl = mArcgisLayerConfiguration.value( QStringLiteral( "serviceUri" ) ).toString()
505  + '/' + mArcgisLayerConfiguration.value( QStringLiteral( "defaultStyles" ) ).toString();
506  }
507 
508  if ( mSourceType == QLatin1String( "vtpk" ) )
509  {
510  QgsVtpkTiles reader( mSourcePath );
511  if ( !reader.open() )
512  {
513  QgsDebugMsg( QStringLiteral( "failed to open VTPK file: " ) + mSourcePath );
514  return false;
515  }
516 
517  styleDefinition = reader.styleDefinition();
518 
519  const QVariantMap spriteDefinition = reader.spriteDefinition();
520  if ( !spriteDefinition.isEmpty() )
521  {
522  const QImage spriteImage = reader.spriteImage();
523  context.setSprites( spriteImage, spriteDefinition );
524  }
525  }
526  else if ( !styleUrl.isEmpty() )
527  {
528  QNetworkRequest request = QNetworkRequest( QUrl( styleUrl ) );
529 
530  QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsVectorTileLayer" ) );
531 
532  QgsBlockingNetworkRequest networkRequest;
533  switch ( networkRequest.get( request ) )
534  {
536  break;
537 
541  error = QObject::tr( "Error retrieving default style" );
542  return false;
543  }
544 
545  const QgsNetworkReplyContent content = networkRequest.reply();
546  styleDefinition = QgsJsonUtils::parseJson( content.content() ).toMap();
547 
548  if ( styleDefinition.contains( QStringLiteral( "sprite" ) ) )
549  {
550  // retrieve sprite definition
551  QString spriteUriBase;
552  if ( styleDefinition.value( QStringLiteral( "sprite" ) ).toString().startsWith( QLatin1String( "http" ) ) )
553  {
554  spriteUriBase = styleDefinition.value( QStringLiteral( "sprite" ) ).toString();
555  }
556  else
557  {
558  spriteUriBase = styleUrl + '/' + styleDefinition.value( QStringLiteral( "sprite" ) ).toString();
559  }
560 
561  for ( int resolution = 2; resolution > 0; resolution-- )
562  {
563  QUrl spriteUrl = QUrl( spriteUriBase );
564  spriteUrl.setPath( spriteUrl.path() + QStringLiteral( "%1.json" ).arg( resolution > 1 ? QStringLiteral( "@%1x" ).arg( resolution ) : QString() ) );
565  QNetworkRequest request = QNetworkRequest( spriteUrl );
566  QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsVectorTileLayer" ) )
567  QgsBlockingNetworkRequest networkRequest;
568  switch ( networkRequest.get( request ) )
569  {
571  {
572  const QgsNetworkReplyContent content = networkRequest.reply();
573  const QVariantMap spriteDefinition = QgsJsonUtils::parseJson( content.content() ).toMap();
574 
575  // retrieve sprite images
576  QUrl spriteUrl = QUrl( spriteUriBase );
577  spriteUrl.setPath( spriteUrl.path() + QStringLiteral( "%1.png" ).arg( resolution > 1 ? QStringLiteral( "@%1x" ).arg( resolution ) : QString() ) );
578  QNetworkRequest request = QNetworkRequest( spriteUrl );
579  QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsVectorTileLayer" ) )
580  QgsBlockingNetworkRequest networkRequest;
581  switch ( networkRequest.get( request ) )
582  {
584  {
585  const QgsNetworkReplyContent imageContent = networkRequest.reply();
586  const QImage spriteImage( QImage::fromData( imageContent.content() ) );
587  context.setSprites( spriteImage, spriteDefinition );
588  break;
589  }
590 
594  break;
595  }
596 
597  break;
598  }
599 
603  break;
604  }
605 
606  if ( !context.spriteDefinitions().isEmpty() )
607  break;
608  }
609  }
610  }
611 
612  if ( !styleDefinition.isEmpty() )
613  {
614  // convert automatically from pixel sizes to millimeters, because pixel sizes
615  // are a VERY edge case in QGIS and don't play nice with hidpi map renders or print layouts
617  //assume source uses 96 dpi
618  context.setPixelSizeConversionFactor( 25.4 / 96.0 );
619 
620  QgsMapBoxGlStyleConverter converter;
621  if ( converter.convert( styleDefinition, &context ) != QgsMapBoxGlStyleConverter::Success )
622  {
623  warnings = converter.warnings();
624  error = converter.errorMessage();
625  return false;
626  }
627 
628  setRenderer( converter.renderer() );
629  setLabeling( converter.labeling() );
630  warnings = converter.warnings();
631  return true;
632  }
633  else
634  {
635  bool resultFlag = false;
636  error = QgsMapLayer::loadDefaultStyle( resultFlag );
637  return resultFlag;
638  }
639 }
640 
641 QString QgsVectorTileLayer::loadDefaultMetadata( bool &resultFlag )
642 {
643  QgsDataSourceUri dsUri;
644  dsUri.setEncodedUri( mDataSource );
645  if ( mSourceType == QLatin1String( "xyz" ) && dsUri.param( QStringLiteral( "serviceType" ) ) == QLatin1String( "arcgis" ) )
646  {
647  // populate default metadata
649  metadata.setIdentifier( mArcgisLayerConfiguration.value( QStringLiteral( "serviceUri" ) ).toString() );
650  const QString parentIdentifier = mArcgisLayerConfiguration.value( QStringLiteral( "serviceItemId" ) ).toString();
651  if ( !parentIdentifier.isEmpty() )
652  {
653  metadata.setParentIdentifier( parentIdentifier );
654  }
655  metadata.setType( QStringLiteral( "dataset" ) );
656  metadata.setTitle( mArcgisLayerConfiguration.value( QStringLiteral( "name" ) ).toString() );
657  const QString copyright = mArcgisLayerConfiguration.value( QStringLiteral( "copyrightText" ) ).toString();
658  if ( !copyright.isEmpty() )
659  metadata.setRights( QStringList() << copyright );
660  metadata.addLink( QgsAbstractMetadataBase::Link( tr( "Source" ), QStringLiteral( "WWW:LINK" ), mArcgisLayerConfiguration.value( QStringLiteral( "serviceUri" ) ).toString() ) );
661 
663 
664  resultFlag = true;
665  return QString();
666  }
667  else if ( mSourceType == QLatin1String( "vtpk" ) )
668  {
669  QgsVtpkTiles reader( mSourcePath );
670  if ( !reader.open() )
671  {
672  QgsDebugMsg( QStringLiteral( "failed to open VTPK file: " ) + mSourcePath );
673  resultFlag = false;
674  }
675  else
676  {
677  setMetadata( reader.layerMetadata() );
678  resultFlag = true;
679  }
680  return QString();
681  }
682  else
683  {
684  QgsMapLayer::loadDefaultMetadata( resultFlag );
685  resultFlag = true;
686  return QString();
687  }
688 }
689 
690 QString QgsVectorTileLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
691 {
692  QgsDataSourceUri dsUri;
693  dsUri.setEncodedUri( source );
694 
695  const QString sourceType = dsUri.param( QStringLiteral( "type" ) );
696  QString sourcePath = dsUri.param( QStringLiteral( "url" ) );
697  if ( sourceType == QLatin1String( "xyz" ) )
698  {
699  const QUrl sourceUrl( sourcePath );
700  if ( sourceUrl.isLocalFile() )
701  {
702  // relative path will become "file:./x.txt"
703  const QString relSrcUrl = context.pathResolver().writePath( sourceUrl.toLocalFile() );
704  dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
705  dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( relSrcUrl ).toString() );
706  return dsUri.encodedUri();
707  }
708  }
709  else if ( sourceType == QLatin1String( "mbtiles" ) )
710  {
712  dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
713  dsUri.setParam( QStringLiteral( "url" ), sourcePath );
714  return dsUri.encodedUri();
715  }
716 
717  return source;
718 }
719 
720 QString QgsVectorTileLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
721 {
722  Q_UNUSED( provider )
723 
724  QgsDataSourceUri dsUri;
725  dsUri.setEncodedUri( source );
726 
727  const QString sourceType = dsUri.param( QStringLiteral( "type" ) );
728  QString sourcePath = dsUri.param( QStringLiteral( "url" ) );
729  if ( sourceType == QLatin1String( "xyz" ) )
730  {
731  const QUrl sourceUrl( sourcePath );
732  if ( sourceUrl.isLocalFile() ) // file-based URL? convert to relative path
733  {
734  const QString absSrcUrl = context.pathResolver().readPath( sourceUrl.toLocalFile() );
735  dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
736  dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( absSrcUrl ).toString() );
737  return dsUri.encodedUri();
738  }
739  }
740  else if ( sourceType == QLatin1String( "mbtiles" ) )
741  {
743  dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
744  dsUri.setParam( QStringLiteral( "url" ), sourcePath );
745  return dsUri.encodedUri();
746  }
747 
748  return source;
749 }
750 
752 {
753  const QgsLayerMetadataFormatter htmlFormatter( metadata() );
754 
755  QString info = QStringLiteral( "<html><head></head>\n<body>\n" );
756 
757  info += generalHtmlMetadata();
758 
759  info += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" ) %
760  QStringLiteral( "<table class=\"list-view\">\n" );
761 
762  info += QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Source type" ) % QStringLiteral( "</td><td>" ) % sourceType() % QStringLiteral( "</td></tr>\n" );
763 
764  info += QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Zoom levels" ) % QStringLiteral( "</td><td>" ) % QStringLiteral( "%1 - %2" ).arg( sourceMinZoom() ).arg( sourceMaxZoom() ) % QStringLiteral( "</td></tr>\n" );
765 
766  info += QLatin1String( "</table>\n<br>" );
767 
768  // CRS
769  info += crsHtmlMetadata();
770 
771  // Identification section
772  info += QStringLiteral( "<h1>" ) % tr( "Identification" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
773  htmlFormatter.identificationSectionHtml() %
774  QStringLiteral( "<br>\n" ) %
775 
776  // extent section
777  QStringLiteral( "<h1>" ) % tr( "Extent" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
778  htmlFormatter.extentSectionHtml( ) %
779  QStringLiteral( "<br>\n" ) %
780 
781  // Start the Access section
782  QStringLiteral( "<h1>" ) % tr( "Access" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
783  htmlFormatter.accessSectionHtml( ) %
784  QStringLiteral( "<br>\n" ) %
785 
786 
787  // Start the contacts section
788  QStringLiteral( "<h1>" ) % tr( "Contacts" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
789  htmlFormatter.contactsSectionHtml( ) %
790  QStringLiteral( "<br><br>\n" ) %
791 
792  // Start the links section
793  QStringLiteral( "<h1>" ) % tr( "References" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
794  htmlFormatter.linksSectionHtml( ) %
795  QStringLiteral( "<br>\n" ) %
796 
797  // Start the history section
798  QStringLiteral( "<h1>" ) % tr( "History" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
799  htmlFormatter.historySectionHtml( ) %
800  QStringLiteral( "<br>\n" ) %
801 
802  QStringLiteral( "\n</body>\n</html>\n" );
803 
804  return info;
805 }
806 
808 {
809  const QgsTileMatrix tileMatrix = mMatrixSet.tileMatrix( tileID.zoomLevel() );
810  const QgsTileRange tileRange( tileID.column(), tileID.column(), tileID.row(), tileID.row() );
811 
812  QgsDataSourceUri dsUri;
813  dsUri.setEncodedUri( mDataSource );
814  const QString authcfg = dsUri.authConfigId();
815  QgsHttpHeaders headers;
816  headers [QStringLiteral( "referer" ) ] = dsUri.param( QStringLiteral( "referer" ) );
817 
818  QList<QgsVectorTileRawData> rawTiles = QgsVectorTileLoader::blockingFetchTileRawData( mSourceType, mSourcePath, tileMatrix, QPointF(), tileRange, authcfg, headers );
819  if ( rawTiles.isEmpty() )
820  return QByteArray();
821  return rawTiles.first().data;
822 }
823 
825 {
826  mRenderer.reset( r );
827  triggerRepaint();
828 }
829 
831 {
832  return mRenderer.get();
833 }
834 
836 {
837  mLabeling.reset( labeling );
838  triggerRepaint();
839 }
840 
842 {
843  return mLabeling.get();
844 }
845 
846 
847 
848 //
849 // QgsVectorTileDataProvider
850 //
852 QgsVectorTileDataProvider::QgsVectorTileDataProvider(
853  const ProviderOptions &options,
854  QgsDataProvider::ReadFlags flags )
855  : QgsDataProvider( QString(), options, flags )
856 {}
857 
859 {
860  return QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) );
861 }
862 
863 QString QgsVectorTileDataProvider::name() const
864 {
865  return QStringLiteral( "vectortile" );
866 }
867 
868 QString QgsVectorTileDataProvider::description() const
869 {
870  return QString();
871 }
872 
873 QgsRectangle QgsVectorTileDataProvider::extent() const
874 {
875  return QgsRectangle();
876 }
877 
878 bool QgsVectorTileDataProvider::isValid() const
879 {
880  return true;
881 }
882 
883 bool QgsVectorTileDataProvider::renderInPreview( const PreviewContext &context )
884 {
885  // Vector tiles by design are very CPU light to render, so we are much more permissive here compared
886  // with other layer types. (Generally if a vector tile layer has taken more than a few milliseconds to render it's
887  // a result of network requests, and the tile manager class handles these gracefully for us)
888  return context.lastRenderingTimeMs <= 1000;
889 }
890 
@ IsBasemapLayer
Layer is considered a 'basemap' layer, and certain properties of the layer should be ignored when cal...
void setType(const QString &type)
Sets the type (nature) of the resource.
void setParentIdentifier(const QString &parentIdentifier)
Sets a reference, URI, URL or some other mechanism to identify the parent resource that this resource...
void setTitle(const QString &title)
Sets the human readable title (name) of the resource, typically displayed in search results.
void setIdentifier(const QString &identifier)
Sets the reference, URI, URL or some other mechanism to identify the resource.
void addLink(const QgsAbstractMetadataBase::Link &link)
Adds an individual link to the existing links.
static QgsCoordinateReferenceSystem convertSpatialReference(const QVariantMap &spatialReferenceMap)
Converts a spatial reference JSON definition to a QgsCoordinateReferenceSystem value.
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Performs a "get" operation on the specified request.
@ NetworkError
A network error occurred.
@ ServerExceptionError
An exception was raised by the server.
@ NoError
No error was encountered.
@ TimeoutError
Timeout was reached before a reply was received.
QgsNetworkReplyContent reply() const
Returns the content of the network reply, after a get() or post() request has been made.
This class represents a coordinate reference system (CRS).
Contains information about the context in which a coordinate transform is executed.
Class for doing transforms between two map coordinate systems.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
Abstract base class for spatial data provider implementations.
Class for storing the component parts of a RDBMS data source URI (e.g.
QByteArray encodedUri() const
Returns the complete encoded URI as a byte array.
bool hasParam(const QString &key) const
Returns true if a parameter with the specified key exists.
int removeParam(const QString &key)
Removes a generic parameter by key.
void setEncodedUri(const QByteArray &uri)
Sets the complete encoded uri.
QString param(const QString &key) const
Returns a generic parameter value corresponding to the specified key.
void setParam(const QString &key, const QString &value)
Sets a generic parameter value on the URI.
QString authConfigId() const
Returns any associated authentication configuration ID stored in the URI.
This class implements simple http header management.
static QVariant parseJson(const std::string &jsonString)
Converts JSON jsonString to a QVariant, in case of parsing error an invalid QVariant is returned and ...
Class for metadata formatter.
QString linksSectionHtml() const
Formats the "Links" section according to a metadata object.
QString extentSectionHtml(const bool showSpatialExtent=true) const
Formats the "Extents" section according to a metadata object (extent and temporal).
QString contactsSectionHtml() const
Formats the "Contacts" section according to a metadata object.
QString identificationSectionHtml() const
Formats the "Identification" section according to a metadata object.
QString historySectionHtml() const
Formats the "History" section according to a metadata object.
QString accessSectionHtml() const
Formats the "Access" section according to a metadata object.
A structured metadata store for a map layer.
void setRights(const QStringList &rights)
Sets a list of rights (attribution or copyright strings) associated with the resource.
Context for a MapBox GL style conversion operation.
void setPixelSizeConversionFactor(double sizeConversionFactor)
Sets the pixel size conversion factor, used to scale the original pixel sizes when converting styles.
void setSprites(const QImage &image, const QVariantMap &definitions)
Sets the sprite image and definitions JSON to use during conversion.
void setTargetUnit(QgsUnitTypes::RenderUnit targetUnit)
Sets the target unit type.
QVariantMap spriteDefinitions() const
Returns the sprite definitions to use during conversion.
Handles conversion of MapBox GL styles to QGIS vector tile renderers and labeling settings.
QgsVectorTileRenderer * renderer() const
Returns a new instance of a vector tile renderer representing the converted style,...
QgsVectorTileLabeling * labeling() const
Returns a new instance of a vector tile labeling representing the converted style,...
Result convert(const QVariantMap &style, QgsMapBoxGlStyleConversionContext *context=nullptr)
Converts a JSON style map, and returns the resultant status of the conversion.
@ Success
Conversion was successful.
QString errorMessage() const
Returns a descriptive error message if an error was encountered during the style conversion,...
QStringList warnings() const
Returns a list of user-friendly warnings generated during the conversion, e.g.
static QString typeToString(QgsMapLayerType type)
Converts a map layer type to a string value.
Base class for utility classes that encapsulate information necessary for rendering of map layers.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
QString name
Definition: qgsmaplayer.h:76
void readStyleManager(const QDomNode &layerNode)
Read style manager's configuration (if any). To be called by subclasses.
void writeStyleManager(QDomNode &layerNode, QDomDocument &doc) const
Write style manager's configuration (if exists). To be called by subclasses.
QString source() const
Returns the source for the layer.
QString providerType() const
Returns the provider type (provider key) for this layer.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
QgsMapLayer::LayerFlags flags() const
Returns the flags for this layer.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
virtual QString loadDefaultStyle(bool &resultFlag)
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
QString mLayerName
Name of the layer - used for display.
Definition: qgsmaplayer.h:1931
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
QString crsHtmlMetadata() const
Returns a HTML fragment containing the layer's CRS metadata, for use in the htmlMetadata() method.
QgsLayerMetadata metadata
Definition: qgsmaplayer.h:78
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
virtual void setOpacity(double opacity)
Sets the opacity for the layer, where opacity is a value between 0 (totally transparent) and 1....
virtual void setMetadata(const QgsLayerMetadata &metadata)
Sets the layer's metadata store.
QString mProviderKey
Data provider key (name of the data provider)
Definition: qgsmaplayer.h:1969
QgsCoordinateTransformContext transformContext() const
Returns the layer data provider coordinate transform context or a default transform context if the la...
virtual QgsError error() const
Gets current status error.
virtual void setExtent(const QgsRectangle &rect)
Sets the extent.
QString mDataSource
Data source description string, varies by layer type.
Definition: qgsmaplayer.h:1928
virtual QString loadDefaultMetadata(bool &resultFlag)
Retrieve the default metadata for this layer if one exists (either as a .qmd file on disk or as a rec...
void setValid(bool valid)
Sets whether layer is valid or not.
void readCommonStyle(const QDomElement &layerElement, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories)
Read style data common to all layer types.
double opacity
Definition: qgsmaplayer.h:82
@ Symbology
Symbology.
Definition: qgsmaplayer.h:161
@ Rendering
Rendering: scale visibility, simplify method, opacity.
Definition: qgsmaplayer.h:170
@ Labeling
Labeling.
Definition: qgsmaplayer.h:163
QString generalHtmlMetadata() const
Returns an HTML fragment containing general metadata information, for use in the htmlMetadata() metho...
void writeCommonStyle(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const
Write style data common to all layer types.
void invalidateWgs84Extent()
Invalidates the WGS84 extent.
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
Utility class for reading and writing MBTiles files (which are SQLite3 databases).
Definition: qgsmbtiles.h:39
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
QByteArray content() const
Returns the reply content.
static QgsPainting::BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode.
Definition: qgspainting.cpp:80
static QPainter::CompositionMode getCompositionMode(QgsPainting::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
Definition: qgspainting.cpp:20
BlendMode
Blending modes enum defining the available composition modes that can be used when rendering a layer.
Definition: qgspainting.h:37
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
The class is used as a container of context for various read/write operations on other objects.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
Contains information about the context of a rendering operation.
virtual QDomElement writeXml(QDomDocument &document, const QgsReadWriteContext &context) const
Writes the set to an XML element.
Definition: qgstiles.cpp:334
QgsCoordinateReferenceSystem crs() const
Returns the coordinate reference system associated with the tiles.
Definition: qgstiles.cpp:195
int minimumZoom() const
Returns the minimum zoom level for tiles present in the set.
Definition: qgstiles.cpp:158
int maximumZoom() const
Returns the maximum zoom level for tiles present in the set.
Definition: qgstiles.cpp:169
QgsTileMatrix tileMatrix(int zoom) const
Returns the tile matrix corresponding to the specified zoom.
Definition: qgstiles.cpp:148
virtual bool readXml(const QDomElement &element, QgsReadWriteContext &context)
Reads the set from an XML element.
Definition: qgstiles.cpp:303
void dropMatricesOutsideZoomRange(int minimumZoom, int maximumZoom)
Deletes any existing matrices which fall outside the zoom range specified by minimumZoom to maximumZo...
Definition: qgstiles.cpp:180
Defines a matrix of tiles for a single zoom level: it is defined by its size (width *.
Definition: qgstiles.h:108
Range of tiles in a tile matrix to be rendered.
Definition: qgstiles.h:71
Stores coordinates of a tile in a tile matrix set.
Definition: qgstiles.h:38
int zoomLevel() const
Returns tile's zoom level (Z)
Definition: qgstiles.h:51
int column() const
Returns tile's column index (X)
Definition: qgstiles.h:47
int row() const
Returns tile's row index (Y)
Definition: qgstiles.h:49
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:169
Basic labeling configuration for vector tile layers.
The default vector tile renderer implementation.
static QList< QgsVectorTileBasicRendererStyle > simpleStyleWithRandomColors()
Returns a list of styles to render all layers, using random colors.
Base class for labeling configuration classes for vector tile layers.
virtual void readXml(const QDomElement &elem, const QgsReadWriteContext &context)=0
Reads labeling properties from given XML element.
This class provides map rendering functionality for vector tile layers.
Implements a map layer that is dedicated to rendering of vector tiles.
QgsVectorTileLayer(const QString &path=QString(), const QString &baseName=QString(), const QgsVectorTileLayer::LayerOptions &options=QgsVectorTileLayer::LayerOptions())
Constructs a new vector tile layer.
QByteArray getRawTile(QgsTileXYZ tileID)
Fetches raw tile data for the give tile coordinates.
bool readXml(const QDomNode &layerNode, QgsReadWriteContext &context) override
Called by readLayerXML(), used by children to read state specific to them from project files.
bool writeSymbology(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const override
Write the style for the layer into the document provided.
void setRenderer(QgsVectorTileRenderer *r)
Sets renderer for the map layer.
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...
QString sourceType() const
Returns type of the data source.
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.
void setLabeling(QgsVectorTileLabeling *labeling)
Sets labeling for the map layer.
QgsVectorTileLabeling * labeling() const
Returns currently assigned labeling.
~QgsVectorTileLayer() override
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.
int sourceMinZoom() const
Returns minimum zoom level at which source has any valid tiles (negative = unconstrained)
QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext) override
Returns new instance of QgsMapLayerRenderer that will be used for rendering of given context.
QString loadDefaultStyle(bool &resultFlag) override
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
Qgis::MapLayerProperties properties() const override
Returns the map layer properties of this layer.
QString htmlMetadata() const override
Obtain a formatted HTML string containing assorted metadata for this layer.
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...
int sourceMaxZoom() const
Returns maximum zoom level at which source has any valid tiles (negative = unconstrained)
QgsVectorTileRenderer * renderer() const
Returns currently assigned renderer.
QgsDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
QString loadDefaultMetadata(bool &resultFlag) override
Retrieve the default metadata for this layer if one exists (either as a .qmd file on disk or as a rec...
QString sourcePath() const
Returns URL/path of the data source (syntax different to each data source type)
void setTransformContext(const QgsCoordinateTransformContext &transformContext) override
Sets the coordinate transform context to transformContext.
QgsVectorTileLayer * clone() const override
Returns a new instance equivalent to this one except for the id which is still unique.
static QList< QgsVectorTileRawData > blockingFetchTileRawData(const QString &sourceType, const QString &sourcePath, const QgsTileMatrix &tileMatrix, const QPointF &viewCenter, const QgsTileRange &range, const QString &authid, const QgsHttpHeaders &headers, QgsFeedback *feedback=nullptr)
Returns raw tile data for the specified range of tiles. Blocks the caller until all tiles are fetched...
bool fromEsriJson(const QVariantMap &json)
Initializes the tile structure settings from an ESRI REST VectorTileService json map.
static QgsVectorTileMatrixSet fromWebMercator(int minimumZoom=0, int maximumZoom=14)
Returns a vector tile structure corresponding to the standard web mercator/GoogleCRS84Quad setup.
Abstract base class for all vector tile renderer implementations.
virtual void readXml(const QDomElement &elem, const QgsReadWriteContext &context)=0
Reads renderer's properties from given XML element.
static bool checkXYZUrlTemplate(const QString &url)
Checks whether the URL template string is correct (contains {x}, {y} / {-y}, {z} placeholders)
Utility class for reading and writing ESRI VTPK files.
Definition: qgsvtpktiles.h:38
QVariantMap spriteDefinition() const
Returns the VTPK sprites definitions.
QgsLayerMetadata layerMetadata() const
Reads layer metadata from the VTPK file.
bool open()
Tries to open the file, returns true on success.
QVariantMap styleDefinition() const
Returns the VTPK style definition.
QImage spriteImage() const
Returns the VTPK sprite image, if it exists.
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgis.h:47
@ VectorTileLayer
Vector tile layer. Added in QGIS 3.14.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
#define QgsSetRequestInitiatorClass(request, _class)
const QgsCoordinateReferenceSystem & crs
Setting options for creating vector data providers.
Setting options for loading vector tile layers.