QGIS API Documentation 3.39.0-Master (d85f3c2a281)
Loading...
Searching...
No Matches
qgsxyzvectortiledataprovider.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsxyzvectortiledataprovider.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
18#include "qgsthreadingutils.h"
19#include "qgstiles.h"
20#include "qgsvectortileloader.h"
21#include "qgsvectortileutils.h"
24#include "qgsapplication.h"
25#include "qgsauthmanager.h"
26#include "qgsmessagelog.h"
28#include "qgslogger.h"
29#include <QIcon>
30#include <QNetworkRequest>
31
33
34QString QgsXyzVectorTileDataProvider::XYZ_DATA_PROVIDER_KEY = QStringLiteral( "xyzvectortiles" );
35QString QgsXyzVectorTileDataProvider::XYZ_DATA_PROVIDER_DESCRIPTION = QObject::tr( "XYZ Vector Tiles data provider" );
36
37//
38// QgsXyzVectorTileDataProviderBase
39//
40
41QgsXyzVectorTileDataProviderBase::QgsXyzVectorTileDataProviderBase( const QString &uri, const ProviderOptions &providerOptions, Qgis::DataProviderReadFlags flags )
42 : QgsVectorTileDataProvider( uri, providerOptions, flags )
43{
44 QgsDataSourceUri dsUri;
45 dsUri.setEncodedUri( uri );
46 mAuthCfg = dsUri.authConfigId();
47 mHeaders = dsUri.httpHeaders();
48}
49
50QgsXyzVectorTileDataProviderBase::QgsXyzVectorTileDataProviderBase( const QgsXyzVectorTileDataProviderBase &other )
52{
53 mAuthCfg = other.mAuthCfg;
54 mHeaders = other.mHeaders;
55}
56
57bool QgsXyzVectorTileDataProviderBase::supportsAsync() const
58{
59 return true;
60}
61
62QgsVectorTileRawData QgsXyzVectorTileDataProviderBase::readTile( const QgsTileMatrixSet &set, const QgsTileXYZ &id, QgsFeedback *feedback ) const
63{
64 return QgsVectorTileRawData( id, loadFromNetwork( id, set.tileMatrix( id.zoomLevel() ), sourcePath(), mAuthCfg, mHeaders, feedback ) );
65}
66
67QList<QgsVectorTileRawData> QgsXyzVectorTileDataProviderBase::readTiles( const QgsTileMatrixSet &set, const QVector<QgsTileXYZ> &tiles, QgsFeedback *feedback, Qgis::RendererUsage usage ) const
68{
69 QList<QgsVectorTileRawData> rawTiles;
70 rawTiles.reserve( tiles.size() );
71 for ( QgsTileXYZ id : std::as_const( tiles ) )
72 {
73 QMap<QString, QByteArray> data;
74 const QgsStringMap sources = sourcePaths();
75 QgsStringMap::const_iterator it = sources.constBegin();
76 for ( ; it != sources.constEnd(); ++it )
77 {
78 if ( feedback && feedback->isCanceled() )
79 break;
80
81 const QByteArray rawData = loadFromNetwork( id, set.tileMatrix( id.zoomLevel() ), it.value(), mAuthCfg, mHeaders, feedback, usage );
82 if ( !rawData.isEmpty() )
83 {
84 data[it.key()] = rawData;
85 }
86 }
87 rawTiles.append( QgsVectorTileRawData( id, data ) );
88 }
89 return rawTiles;
90}
91
92QList<QNetworkRequest> QgsXyzVectorTileDataProviderBase::tileRequests( const QgsTileMatrixSet &set, const QgsTileXYZ &id, Qgis::RendererUsage usage ) const
93{
94 QList<QNetworkRequest> requests;
95
96 const QgsStringMap sourcesPaths = sourcePaths();
97
98 QgsStringMap::const_iterator it = sourcesPaths.constBegin();
99
100 for ( ; it != sourcesPaths.constEnd(); ++it )
101 {
102 QString urlTemplate = it.value();
103 QString layerName = it.key();
104
105 if ( urlTemplate.contains( QLatin1String( "{usage}" ) ) )
106 {
107 switch ( usage )
108 {
110 urlTemplate.replace( QLatin1String( "{usage}" ), QLatin1String( "view" ) );
111 break;
113 urlTemplate.replace( QLatin1String( "{usage}" ), QLatin1String( "export" ) );
114 break;
116 urlTemplate.replace( QLatin1String( "{usage}" ), QString() );
117 break;
118 }
119 }
120
121 const QString url = QgsVectorTileUtils::formatXYZUrlTemplate( urlTemplate, id, set.tileMatrix( id.zoomLevel() ) );
122
123 QNetworkRequest request( url );
124 QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsXyzVectorTileDataProvider" ) );
125 QgsSetRequestInitiatorId( request, id.toString() );
126
127 request.setAttribute( static_cast<QNetworkRequest::Attribute>( QgsVectorTileDataProvider::DATA_COLUMN ), id.column() );
128 request.setAttribute( static_cast<QNetworkRequest::Attribute>( QgsVectorTileDataProvider::DATA_ROW ), id.row() );
129 request.setAttribute( static_cast<QNetworkRequest::Attribute>( QgsVectorTileDataProvider::DATA_ZOOM ), id.zoomLevel() );
130 request.setAttribute( static_cast<QNetworkRequest::Attribute>( QgsVectorTileDataProvider::DATA_SOURCE_ID ), layerName );
131
132 request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
133 request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
134
135 mHeaders.updateNetworkRequest( request );
136
137 if ( !mAuthCfg.isEmpty() && !QgsApplication::authManager()->updateNetworkRequest( request, mAuthCfg ) )
138 {
139 QgsMessageLog::logMessage( tr( "network request update failed for authentication config" ), tr( "Network" ) );
140 }
141
142 requests << request;
143 }
144
145 return requests;
146}
147
148QByteArray QgsXyzVectorTileDataProviderBase::loadFromNetwork( const QgsTileXYZ &id, const QgsTileMatrix &tileMatrix, const QString &requestUrl, const QString &authid, const QgsHttpHeaders &headers, QgsFeedback *feedback, Qgis::RendererUsage usage )
149{
150 QString url = QgsVectorTileUtils::formatXYZUrlTemplate( requestUrl, id, tileMatrix );
151
152 if ( url.contains( QLatin1String( "{usage}" ) ) )
153 {
154 switch ( usage )
155 {
157 url.replace( QLatin1String( "{usage}" ), QLatin1String( "view" ) );
158 break;
160 url.replace( QLatin1String( "{usage}" ), QLatin1String( "export" ) );
161 break;
163 url.replace( QLatin1String( "{usage}" ), QString() );
164 break;
165 }
166 }
167
168 QNetworkRequest nr;
169 nr.setUrl( QUrl( url ) );
170
171 headers.updateNetworkRequest( nr );
172
174 req.setAuthCfg( authid );
175 QgsDebugMsgLevel( QStringLiteral( "Blocking request: " ) + url, 2 );
176 QgsBlockingNetworkRequest::ErrorCode errCode = req.get( nr, false, feedback );
177 if ( errCode != QgsBlockingNetworkRequest::NoError )
178 {
179 QgsDebugError( QStringLiteral( "Request failed: " ) + url );
180 return QByteArray();
181 }
182 QgsNetworkReplyContent reply = req.reply();
183 QgsDebugMsgLevel( QStringLiteral( "Request successful, content size %1" ).arg( reply.content().size() ), 2 );
184 return reply.content();
185}
186
187
188//
189// QgsXyzVectorTileDataProviderMetadata
190//
191
192
193QgsXyzVectorTileDataProviderMetadata::QgsXyzVectorTileDataProviderMetadata()
194 : QgsProviderMetadata( QgsXyzVectorTileDataProvider::XYZ_DATA_PROVIDER_KEY, QgsXyzVectorTileDataProvider::XYZ_DATA_PROVIDER_DESCRIPTION )
195{
196}
197
198QgsXyzVectorTileDataProvider *QgsXyzVectorTileDataProviderMetadata::createProvider( const QString &uri, const QgsDataProvider::ProviderOptions &options, Qgis::DataProviderReadFlags flags )
199{
200 return new QgsXyzVectorTileDataProvider( uri, options, flags );
201}
202
203QIcon QgsXyzVectorTileDataProviderMetadata::icon() const
204{
205 return QgsApplication::getThemeIcon( QStringLiteral( "mIconVectorTileLayer.svg" ) );
206}
207
208QgsProviderMetadata::ProviderCapabilities QgsXyzVectorTileDataProviderMetadata::providerCapabilities() const
209{
210 return FileBasedUris;
211}
212
213QVariantMap QgsXyzVectorTileDataProviderMetadata::decodeUri( const QString &uri ) const
214{
215 QgsDataSourceUri dsUri;
216 dsUri.setEncodedUri( uri );
217
218 QVariantMap uriComponents;
219 uriComponents.insert( QStringLiteral( "type" ), QStringLiteral( "xyz" ) );
220
221 if ( uriComponents[ QStringLiteral( "type" ) ] == QLatin1String( "mbtiles" ) ||
222 ( uriComponents[ QStringLiteral( "type" ) ] == QLatin1String( "xyz" ) &&
223 !dsUri.param( QStringLiteral( "url" ) ).startsWith( QLatin1String( "http" ) ) ) )
224 {
225 uriComponents.insert( QStringLiteral( "path" ), dsUri.param( QStringLiteral( "url" ) ) );
226 }
227 else
228 {
229 uriComponents.insert( QStringLiteral( "url" ), dsUri.param( QStringLiteral( "url" ) ) );
230 if ( dsUri.hasParam( QStringLiteral( "urlName" ) ) )
231 uriComponents.insert( QStringLiteral( "urlName" ), dsUri.param( QStringLiteral( "urlName" ) ) );
232 }
233 int i = 2;
234 while ( true )
235 {
236 QString url = dsUri.param( QStringLiteral( "url_%2" ).arg( i ) );
237 QString urlName = dsUri.param( QStringLiteral( "urlName_%2" ).arg( i ) );
238 if ( url.isEmpty() || urlName.isEmpty() )
239 break;
240 uriComponents.insert( QStringLiteral( "urlName_%2" ).arg( i ), urlName );
241 uriComponents.insert( QStringLiteral( "url_%2" ).arg( i ), url );
242 i++;
243 }
244
245
246 if ( dsUri.hasParam( QStringLiteral( "zmin" ) ) )
247 uriComponents.insert( QStringLiteral( "zmin" ), dsUri.param( QStringLiteral( "zmin" ) ) );
248 if ( dsUri.hasParam( QStringLiteral( "zmax" ) ) )
249 uriComponents.insert( QStringLiteral( "zmax" ), dsUri.param( QStringLiteral( "zmax" ) ) );
250
251 dsUri.httpHeaders().updateMap( uriComponents );
252
253 if ( dsUri.hasParam( QStringLiteral( "styleUrl" ) ) )
254 uriComponents.insert( QStringLiteral( "styleUrl" ), dsUri.param( QStringLiteral( "styleUrl" ) ) );
255
256 const QString authcfg = dsUri.authConfigId();
257 if ( !authcfg.isEmpty() )
258 uriComponents.insert( QStringLiteral( "authcfg" ), authcfg );
259
260 return uriComponents;
261}
262
263QString QgsXyzVectorTileDataProviderMetadata::encodeUri( const QVariantMap &parts ) const
264{
265 QgsDataSourceUri dsUri;
266 dsUri.setParam( QStringLiteral( "type" ), QStringLiteral( "xyz" ) );
267 dsUri.setParam( QStringLiteral( "url" ), parts.value( parts.contains( QStringLiteral( "path" ) ) ? QStringLiteral( "path" ) : QStringLiteral( "url" ) ).toString() );
268 if ( parts.contains( QStringLiteral( "urlName" ) ) )
269 dsUri.setParam( QStringLiteral( "urlName" ), parts[ QStringLiteral( "urlName" ) ].toString() );
270
271 int i = 2;
272 while ( true )
273 {
274 QString urlNameKey = QStringLiteral( "urlName_%2" ).arg( i );
275 QString urlKey = QStringLiteral( "url_%2" ).arg( i );
276
277 if ( !parts.contains( urlNameKey ) || !parts.contains( urlKey ) )
278 break;
279 QString url = dsUri.param( QStringLiteral( "url_%2" ).arg( i ) );
280 QString urlName = dsUri.param( QStringLiteral( "urlName_%2" ).arg( i ) );
281 if ( url.isEmpty() || urlName.isEmpty() )
282 break;
283
284 dsUri.setParam( urlNameKey, parts[ urlNameKey ].toString() );
285 dsUri.setParam( urlKey, parts[ urlKey ].toString() );
286 i++;
287 }
288
289 if ( parts.contains( QStringLiteral( "zmin" ) ) )
290 dsUri.setParam( QStringLiteral( "zmin" ), parts[ QStringLiteral( "zmin" ) ].toString() );
291 if ( parts.contains( QStringLiteral( "zmax" ) ) )
292 dsUri.setParam( QStringLiteral( "zmax" ), parts[ QStringLiteral( "zmax" ) ].toString() );
293
294 dsUri.httpHeaders().setFromMap( parts );
295
296 if ( parts.contains( QStringLiteral( "styleUrl" ) ) )
297 dsUri.setParam( QStringLiteral( "styleUrl" ), parts[ QStringLiteral( "styleUrl" ) ].toString() );
298
299 if ( parts.contains( QStringLiteral( "authcfg" ) ) )
300 dsUri.setAuthConfigId( parts[ QStringLiteral( "authcfg" ) ].toString() );
301
302 return dsUri.encodedUri();
303}
304
305QString QgsXyzVectorTileDataProviderMetadata::absoluteToRelativeUri( const QString &uri, const QgsReadWriteContext &context ) const
306{
307 QgsDataSourceUri dsUri;
308 dsUri.setEncodedUri( uri );
309
310 QString sourcePath = dsUri.param( QStringLiteral( "url" ) );
311
312 const QUrl sourceUrl( sourcePath );
313 if ( sourceUrl.isLocalFile() )
314 {
315 // relative path will become "file:./x.txt"
316 const QString relSrcUrl = context.pathResolver().writePath( sourceUrl.toLocalFile() );
317 dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
318 dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( relSrcUrl ).toString() );
319 return dsUri.encodedUri();
320 }
321
322 return uri;
323}
324
325QString QgsXyzVectorTileDataProviderMetadata::relativeToAbsoluteUri( const QString &uri, const QgsReadWriteContext &context ) const
326{
327 QgsDataSourceUri dsUri;
328 dsUri.setEncodedUri( uri );
329
330 QString sourcePath = dsUri.param( QStringLiteral( "url" ) );
331
332 const QUrl sourceUrl( sourcePath );
333 if ( sourceUrl.isLocalFile() ) // file-based URL? convert to relative path
334 {
335 const QString absSrcUrl = context.pathResolver().readPath( sourceUrl.toLocalFile() );
336 dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
337 dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( absSrcUrl ).toString() );
338 return dsUri.encodedUri();
339 }
340
341 return uri;
342}
343
344QList<Qgis::LayerType> QgsXyzVectorTileDataProviderMetadata::supportedLayerTypes() const
345{
347}
348
349
350//
351// QgsXyzVectorTileDataProvider
352//
353
354QgsXyzVectorTileDataProvider::QgsXyzVectorTileDataProvider( const QString &uri, const ProviderOptions &providerOptions, Qgis::DataProviderReadFlags flags )
355 : QgsXyzVectorTileDataProviderBase( uri, providerOptions, flags )
356{
357 QgsDataSourceUri dsUri;
358 dsUri.setEncodedUri( uri );
359
360 const QString sourcePath = dsUri.param( QStringLiteral( "url" ) );
361 if ( !QgsVectorTileUtils::checkXYZUrlTemplate( sourcePath ) )
362 {
363 QgsDebugError( QStringLiteral( "Invalid format of URL for XYZ source: " ) + sourcePath );
364 mIsValid = false;
365 return;
366 }
367
368 int zMin = 0;
369 if ( dsUri.hasParam( QStringLiteral( "zmin" ) ) )
370 zMin = dsUri.param( QStringLiteral( "zmin" ) ).toInt();
371
372 int zMax = 14;
373 if ( dsUri.hasParam( QStringLiteral( "zmax" ) ) )
374 zMax = dsUri.param( QStringLiteral( "zmax" ) ).toInt();
375
376 mMatrixSet = QgsVectorTileMatrixSet::fromWebMercator( zMin, zMax );
377 mExtent = QgsRectangle( -20037508.3427892, -20037508.3427892, 20037508.3427892, 20037508.3427892 );
378
379 mIsValid = true;
380}
381
382QgsXyzVectorTileDataProvider::QgsXyzVectorTileDataProvider( const QgsXyzVectorTileDataProvider &other )
383 : QgsXyzVectorTileDataProviderBase( other )
384{
385 mIsValid = other.mIsValid;
386 mExtent = other.mExtent;
387 mMatrixSet = other.mMatrixSet;
388}
389
390Qgis::DataProviderFlags QgsXyzVectorTileDataProvider::flags() const
391{
393}
394
395QString QgsXyzVectorTileDataProvider::name() const
396{
398
399 return XYZ_DATA_PROVIDER_KEY;
400}
401
402QString QgsXyzVectorTileDataProvider::description() const
403{
405
406 return XYZ_DATA_PROVIDER_DESCRIPTION;
407}
408
409QgsVectorTileDataProvider *QgsXyzVectorTileDataProvider::clone() const
410{
412
413 return new QgsXyzVectorTileDataProvider( *this );
414}
415
416bool QgsXyzVectorTileDataProvider::isValid() const
417{
419
420 return mIsValid;
421}
422
423QgsRectangle QgsXyzVectorTileDataProvider::extent() const
424{
426
427 return mExtent;
428}
429
430QgsCoordinateReferenceSystem QgsXyzVectorTileDataProvider::crs() const
431{
433
434 return QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) );
435}
436
437const QgsVectorTileMatrixSet &QgsXyzVectorTileDataProvider::tileMatrixSet() const
438{
440
441 return mMatrixSet;
442}
443
444QString QgsXyzVectorTileDataProvider::sourcePath() const
445{
447
448 QgsDataSourceUri dsUri;
449 dsUri.setEncodedUri( dataSourceUri() );
450 return dsUri.param( QStringLiteral( "url" ) );
451}
452
453QgsStringMap QgsXyzVectorTileDataProvider::sourcePaths() const
454{
456
457 QgsDataSourceUri dsUri;
458 dsUri.setEncodedUri( dataSourceUri() );
459
460 QgsStringMap paths = { { dsUri.param( QStringLiteral( "urlName" ) ), dsUri.param( QStringLiteral( "url" ) ) } };
461
462 int i = 2;
463 while ( true )
464 {
465 QString url = dsUri.param( QStringLiteral( "url_%2" ).arg( i ) );
466 QString urlName = dsUri.param( QStringLiteral( "urlName_%2" ).arg( i ) );
467 if ( url.isEmpty() || urlName.isEmpty() )
468 break;
469
470 paths.insert( urlName, url );
471 i++;
472 }
473
474 return paths;
475}
476
478
479
480
QFlags< DataProviderFlag > DataProviderFlags
Data provider flags.
Definition qgis.h:2147
@ FastExtent2D
Provider's 2D extent retrieval via QgsDataProvider::extent() is always guaranteed to be trivial/fast ...
QFlags< DataProviderReadFlag > DataProviderReadFlags
Flags which control data provider construction.
Definition qgis.h:450
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
RendererUsage
Usage of the renderer.
Definition qgis.h:3186
@ Export
Renderer used for printing or exporting to a file.
@ View
Renderer used for displaying on screen.
@ Unknown
Renderer used for unknown usage.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
bool updateNetworkRequest(QNetworkRequest &request, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkRequest with an authentication config.
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
void setAuthCfg(const QString &authCfg)
Sets the authentication config id which should be used during the request.
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr, RequestFlags requestFlags=QgsBlockingNetworkRequest::RequestFlags())
Performs a "get" operation on the specified request.
@ NoError
No error was encountered.
QgsNetworkReplyContent reply() const
Returns the content of the network reply, after a get(), post(), head() or put() request has been mad...
This class represents a coordinate reference system (CRS).
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.
void setAuthConfigId(const QString &authcfg)
Sets the authentication configuration ID for the URI.
QgsHttpHeaders httpHeaders() const
Returns http headers.
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.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:53
This class implements simple http header management.
bool updateMap(QVariantMap &map) const
Updates a map by adding all the HTTP headers.
bool updateNetworkRequest(QNetworkRequest &request) const
Updates a request by adding all the HTTP headers.
void setFromMap(const QVariantMap &map)
Loads headers from the map.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
QByteArray content() const
Returns the reply content.
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.
Holds data provider key, description, and associated shared library file or function pointer informat...
QFlags< ProviderCapability > ProviderCapabilities
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.
Defines a set of tile matrices for multiple zoom levels.
Definition qgstiles.h:252
QgsTileMatrix tileMatrix(int zoom) const
Returns the tile matrix corresponding to the specified zoom.
Definition qgstiles.cpp:156
Defines a matrix of tiles for a single zoom level: it is defined by its size (width *.
Definition qgstiles.h:136
Stores coordinates of a tile in a tile matrix set.
Definition qgstiles.h:40
Base class for vector tile layer data providers.
static int DATA_ZOOM
Role to set zoom attribute in the request so it can be retrieved later.
static int DATA_ROW
Role to set row attribute in the request so it can be retrieved later.
static int DATA_SOURCE_ID
Role to set source ID attribute in the request so it can be retrieved later.
static int DATA_COLUMN
Role to set column attribute in the request so it can be retrieved later.
Encapsulates properties of a vector tile matrix set, including tile origins and scaling information.
static QgsVectorTileMatrixSet fromWebMercator(int minimumZoom=0, int maximumZoom=14)
Returns a vector tile structure corresponding to the standard web mercator/GoogleCRS84Quad setup.
Keeps track of raw tile data from one or more sources that need to be decoded.
static bool checkXYZUrlTemplate(const QString &url)
Checks whether the URL template string is correct (contains {x}, {y} / {-y}, {z} placeholders)
static QString formatXYZUrlTemplate(const QString &url, QgsTileXYZ tile, const QgsTileMatrix &tileMatrix)
Returns formatted tile URL string replacing {x}, {y}, {z} placeholders (or {-y} instead of {y} for TM...
QMap< QString, QString > QgsStringMap
Definition qgis.h:6395
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39
#define QgsDebugError(str)
Definition qgslogger.h:38
#define QgsSetRequestInitiatorClass(request, _class)
#define QgsSetRequestInitiatorId(request, str)
#define QGIS_PROTECT_QOBJECT_THREAD_ACCESS
Setting options for creating vector data providers.