QGIS API Documentation 3.39.0-Master (8f1a6e30482)
Loading...
Searching...
No Matches
qgsquantizedmeshdataprovider.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsquantizedmeshdataprovider.cpp
3 --------------------
4 begin : June 2024
5 copyright : (C) 2024 by David Koňařík
6 email : dvdkon at konarici dot cz
7 ******************************************************************
8 ***************************************************************************/
9
10/***************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 ***************************************************************************/
18
20#include "qgsapplication.h"
21#include "qgsauthmanager.h"
26#include "qgslogger.h"
27#include "qgsmatrix4x4.h"
28#include "qgsorientedbox3d.h"
29#include "qgsprovidermetadata.h"
33#include "qgstiledsceneindex.h"
35#include "qgstiledscenetile.h"
36#include "qgstiles.h"
37#include "qgsvectortileutils.h"
38#include <limits>
39#include <nlohmann/json.hpp>
40#include <qglobal.h>
41#include <qnetworkrequest.h>
42#include <qobject.h>
43#include <qstringliteral.h>
44#include <qvector.h>
45#include <QUrlQuery>
46
48
49class MissingFieldException : public std::exception
50{
51 public:
52 MissingFieldException( const char *field ) : mField( field ) { }
53 const char *what() const noexcept
54 {
55 return QString( "Missing field: %1" ).arg( mField ).toLocal8Bit().data();
56 }
57 private:
58 const char *mField;
59};
60
61template <typename T>
62static T jsonGet( nlohmann::json &json, const char *idx )
63{
64 auto &obj = json[idx];
65 if ( obj.is_null() )
66 {
67 throw MissingFieldException( idx );
68 }
69 return obj.get<T>();
70}
71
72
73QgsQuantizedMeshMetadata::QgsQuantizedMeshMetadata(
74 const QString &uri,
75 const QgsCoordinateTransformContext &transformContext,
76 QgsError &error )
77{
78 QgsDataSourceUri dsUri;
79 dsUri.setEncodedUri( uri );
80 mAuthCfg = dsUri.authConfigId();
81 mHeaders = dsUri.httpHeaders();
82
83 // The provided URL should be the metadata JSON's location
84 QUrl metadataUrl = dsUri.param( "url" );
85 QNetworkRequest requestData( metadataUrl );
86 mHeaders.updateNetworkRequest( requestData );
87 QgsSetRequestInitiatorClass( requestData,
88 QStringLiteral( "QgsQuantizedMeshDataProvider" ) );
90 if ( !mAuthCfg.isEmpty() )
91 request.setAuthCfg( mAuthCfg );
92 auto respCode = request.get( requestData );
94 {
95 error.append(
96 QObject::tr( "Failed to retrieve quantized mesh tiles metadata: %1" )
97 .arg( request.errorMessage().data() ) );
98 return;
99 }
100 auto reply = request.reply().content();
101
102 try
103 {
104 auto replyJson = nlohmann::json::parse( reply.data() );
105
106 // The metadata is an (undocumented) variant of TileJSON
107 if ( jsonGet<std::string>( replyJson, "format" ) != "quantized-mesh-1.0" )
108 {
109 error.append( QObject::tr( "Unexpected tile format: %1" )
110 .arg( replyJson["format"].dump().c_str() ) );
111 return;
112 }
113
114 auto crsString = QString::fromStdString( jsonGet<std::string>( replyJson, "projection" ) );
115 mCrs = QgsCoordinateReferenceSystem( crsString );
116 if ( !mCrs.isValid() )
117 {
118 error.append( QObject::tr( "Invalid CRS '%1'!" ).arg( crsString ) );
119 return;
120 }
121
122 try
123 {
124 std::vector<double> bounds = jsonGet<std::vector<double>>( replyJson, "bounds" );
125 if ( bounds.size() != 4 )
126 {
127 error.append( QObject::tr( "Bounds array doesn't have 4 items" ) );
128 return;
129 }
130 mExtent = QgsRectangle( bounds[0], bounds[1], bounds[2], bounds[3] );
131 }
132 catch ( MissingFieldException & )
133 {
134 mExtent = mCrs.bounds();
135 }
136
137 auto zRange = dummyZRange;
138 mBoundingVolume =
140 QgsBox3D(
141 mExtent.xMinimum(), mExtent.yMinimum(), zRange.lower(),
142 mExtent.xMaximum(), mExtent.yMaximum(), zRange.upper() ) );
143
144 // The TileJSON spec uses "scheme", but some real-world datasets use "schema"
145 if ( replyJson.find( "scheme" ) != replyJson.end() )
146 mTileScheme = QString::fromStdString( jsonGet<std::string>( replyJson, "scheme" ) );
147 else if ( replyJson.find( "schema" ) != replyJson.end() )
148 mTileScheme = QString::fromStdString( jsonGet<std::string>( replyJson, "schema" ) );
149 else throw MissingFieldException( "scheme/schema" );
150
151 for ( auto &aabbs : replyJson.at( "available" ) )
152 {
153 QVector<QgsTileRange> tileRanges;
154 for ( auto &aabb : aabbs )
155 {
156 tileRanges.push_back(
158 jsonGet<int>( aabb, "startX" ), jsonGet<int>( aabb, "endX" ),
159 jsonGet<int>( aabb, "startY" ), jsonGet<int>( aabb, "endY" ) ) );
160 }
161 mAvailableTiles.push_back( tileRanges );
162 }
163
164 try
165 {
166 mMinZoom = jsonGet<uint8_t>( replyJson, "minzoom" );
167 mMaxZoom = jsonGet<uint8_t>( replyJson, "maxzoom" );
168 }
169 catch ( MissingFieldException & )
170 {
171 mMinZoom = 0;
172 mMaxZoom = mAvailableTiles.size() - 1;
173 }
174
175 QString versionStr =
176 QString::fromStdString( jsonGet<std::string>( replyJson, "version" ) );
177 for ( auto &urlStr : jsonGet<std::vector<std::string>>( replyJson, "tiles" ) )
178 {
179 QUrl url = metadataUrl.resolved( QString::fromStdString( urlStr ) );
180 mTileUrls.push_back(
181 url.toString( QUrl::DecodeReserved ).replace( "{version}", versionStr ) );
182 }
183
184 int rootTileCount = 1;
185 if ( crsString == QLatin1String( "EPSG:4326" ) )
186 rootTileCount = 2;
187 else if ( crsString != QLatin1String( "EPSG:3857" ) )
188 error.append( QObject::tr( "Unhandled CRS: %1" ).arg( crsString ) );
189
190 QgsCoordinateReferenceSystem wgs84( QStringLiteral( "EPSG:4326" ) );
191 // Bounds of tile schema in projected coordinates
192 auto crsBounds =
193 QgsCoordinateTransform( wgs84, mCrs, transformContext )
194 .transform( mCrs.bounds() );
195 QgsPointXY topLeft( crsBounds.xMinimum(), crsBounds.yMaximum() );
196 double z0TileSize = crsBounds.height();
197
198 mTileMatrix = QgsTileMatrix::fromCustomDef( 0, mCrs, topLeft, z0TileSize, rootTileCount, 1 );
199 }
200 catch ( nlohmann::json::exception &ex )
201 {
202 error.append( QObject::tr( "Error parsing JSON metadata: %1" ).arg( ex.what() ) );
203 }
204 catch ( MissingFieldException &ex )
205 {
206 error.append( QObject::tr( "Error parsing JSON metadata: %1" ).arg( ex.what() ) );
207 }
208}
209
210const QgsDoubleRange QgsQuantizedMeshMetadata::dummyZRange = {-10000, 10000};
211
212static QgsTileXYZ tileToTms( QgsTileXYZ &xyzTile )
213{
214 // Flip Y axis for TMS schema
215 Q_ASSERT( xyzTile.zoomLevel() >= 0 );
216 return {xyzTile.column(),
217 ( 1 << xyzTile.zoomLevel() ) - xyzTile.row() - 1,
218 xyzTile.zoomLevel()};
219}
220
221bool QgsQuantizedMeshMetadata::containsTile( QgsTileXYZ tile ) const
222{
223 if ( tile.zoomLevel() < mMinZoom || tile.zoomLevel() > mMaxZoom ||
224 tile.zoomLevel() >= mAvailableTiles.size() )
225 return false;
226 // We operate with XYZ-style tile coordinates, but the availability array may
227 // be given in TMS-style
228 if ( mTileScheme == QLatin1String( "tms" ) )
229 tile = tileToTms( tile );
230 for ( auto &range : mAvailableTiles[tile.zoomLevel()] )
231 {
232 if ( range.startColumn() <= tile.column() && range.endColumn() >= tile.column() &&
233 range.startRow() <= tile.row() && range.endRow() >= tile.row() )
234 return true;
235 }
236 return false;
237}
238
239double QgsQuantizedMeshMetadata::geometricErrorAtZoom( int zoom ) const
240{
241 // The specification doesn't mandate any precision, we can only make a guess
242 // based on each tile's maximum possible numerical precision and some
243 // reasonable-looking constant.
244 return 400000 / pow( 2, zoom );
245}
246
247long long QgsQuantizedMeshIndex::encodeTileId( QgsTileXYZ tile )
248{
249 if ( tile.zoomLevel() == -1 )
250 {
251 Q_ASSERT( tile.column() == 0 && tile.row() == 0 );
252 return ROOT_TILE_ID;
253 }
254 Q_ASSERT( tile.zoomLevel() < ( 2 << 4 ) && ( tile.column() < ( 2 << 27 ) ) &&
255 ( tile.row() < ( 2 << 27 ) ) );
256 return tile.row() | ( ( long long )tile.column() << 28 ) |
257 ( ( long long )tile.zoomLevel() << 56 ) | ( ( long long ) 1 << 61 );
258}
259
260QgsTileXYZ QgsQuantizedMeshIndex::decodeTileId( long long id )
261{
262 if ( id == ROOT_TILE_ID )
263 return QgsTileXYZ( 0, 0, -1 );
264
265 Q_ASSERT( id >> 61 == 1 ); // Check reserved bits
266 return QgsTileXYZ(
267 ( int )( ( id >> 28 ) & ( ( 2 << 27 ) - 1 ) ),
268 ( int )( id & ( ( 2 << 27 ) - 1 ) ),
269 ( int )( ( id >> 56 ) & ( ( 2 << 4 ) - 1 ) ) );
270}
271
272QgsTiledSceneTile QgsQuantizedMeshIndex::rootTile() const
273{
274 // Returns virtual tile to paper over tiling schemes which have >1 tile at zoom 0
275 auto tile = QgsTiledSceneTile( ROOT_TILE_ID );
276 auto bounds = mWgs84ToCrs.transform( mMetadata.mCrs.bounds() );
277 tile.setBoundingVolume(
279 QgsBox3D( bounds, mMetadata.dummyZRange.lower(), mMetadata.dummyZRange.upper() ) ) );
280 tile.setGeometricError( std::numeric_limits<double>::max() );
281 return tile;
282}
283long long QgsQuantizedMeshIndex::parentTileId( long long id ) const
284{
285 if ( id == ROOT_TILE_ID )
286 return -1;
287 auto tile = decodeTileId( id );
288 if ( tile.zoomLevel() == 0 )
289 return ROOT_TILE_ID;
290 return encodeTileId( {tile.zoomLevel() - 1, tile.column() / 2, tile.row() / 2} );
291}
292QVector<long long> QgsQuantizedMeshIndex::childTileIds( long long id ) const
293{
294 auto tile = decodeTileId( id );
295 QVector<long long> children;
296 auto x = tile.column(), y = tile.row(), zoom = tile.zoomLevel();
297
298 if ( mMetadata.containsTile( {x * 2, y * 2, zoom + 1} ) )
299 children.push_back( encodeTileId( {x * 2, y * 2, zoom + 1} ) );
300 if ( mMetadata.containsTile( {x * 2 + 1, y * 2, zoom + 1} ) )
301 children.push_back( encodeTileId( {x * 2 + 1, y * 2, zoom + 1} ) );
302 if ( mMetadata.containsTile( {x * 2, y * 2 + 1, zoom + 1} ) )
303 children.push_back( encodeTileId( {x * 2, y * 2 + 1, zoom + 1} ) );
304 if ( mMetadata.containsTile( {x * 2 + 1, y * 2 + 1, zoom + 1} ) )
305 children.push_back( encodeTileId( {x * 2 + 1, y * 2 + 1, zoom + 1} ) );
306
307 return children;
308}
309QgsTiledSceneTile QgsQuantizedMeshIndex::getTile( long long id )
310{
311 auto xyzTile = decodeTileId( id );
312 QgsTiledSceneTile sceneTile( id );
313
314 auto zoomedMatrix = QgsTileMatrix::fromTileMatrix( xyzTile.zoomLevel(), mMetadata.mTileMatrix );
315 auto tileExtent = zoomedMatrix.tileExtent( xyzTile );
316
317 sceneTile.setBoundingVolume(
319 QgsBox3D( tileExtent, mMetadata.dummyZRange.lower(), mMetadata.dummyZRange.upper() ) ) );
320 sceneTile.setGeometricError( mMetadata.geometricErrorAtZoom( xyzTile.zoomLevel() ) );
321
322 if ( id == ROOT_TILE_ID )
323 // The root tile is fictitious and has no content, don't bother pointing to any.
324 return sceneTile;
325
326 if ( mMetadata.mTileScheme == QLatin1String( "tms" ) )
327 xyzTile = tileToTms( xyzTile );
328
329 if ( mMetadata.mTileUrls.size() == 0 )
330 {
331 QgsDebugError( "Quantized Mesh metadata has no URLs for tiles" );
332 }
333 else
334 {
335 // TODO: Intelligently choose from alternatives. Round robin?
337 mMetadata.mTileUrls[0], xyzTile, zoomedMatrix );
338 sceneTile.setResources( {{"content", tileUri}} );
339 sceneTile.setMetadata(
340 {
341 {QStringLiteral( "gltfUpAxis" ), static_cast<int>( Qgis::Axis::Z )},
342 {QStringLiteral( "contentFormat" ), QStringLiteral( "quantizedmesh" )},
343 } );
344 }
345
346 // Tile meshes have 0.0 -- 1.0 coordinates. Rescale them to the tile's real
347 // width and height in our CRS and move the tile to its position.
348 QgsMatrix4x4 transform(
349 tileExtent.width(), 0, 0, tileExtent.xMinimum(),
350 0, tileExtent.height(), 0, tileExtent.yMinimum(),
351 0, 0, 1, 0,
352 0, 0, 0, 1 );
353 sceneTile.setTransform( transform );
354
355 return sceneTile;
356}
357QVector<long long>
358QgsQuantizedMeshIndex::getTiles( const QgsTiledSceneRequest &request )
359{
360 uint8_t zoomLevel = mMetadata.mMinZoom;
361 if ( request.requiredGeometricError() != 0 )
362 {
363 while ( zoomLevel < mMetadata.mMaxZoom &&
364 mMetadata.geometricErrorAtZoom( zoomLevel ) > request.requiredGeometricError() )
365 zoomLevel++;
366 }
367 auto tileMatrix = QgsTileMatrix::fromTileMatrix( zoomLevel, mMetadata.mTileMatrix );
368
369 QVector<long long> ids;
370 // We can only filter on X and Y
371 auto extent = request.filterBox().extent().toRectangle();
372 if ( request.parentTileId() != -1 )
373 {
374 auto parentTile = decodeTileId( request.parentTileId() );
375 extent.intersect( tileMatrix.tileExtent( parentTile ) );
376 }
377
378 auto tileRange = tileMatrix.tileRangeFromExtent( extent );
379 if ( !tileRange.isValid() )
380 return {};
381
382 for ( int col = tileRange.startColumn(); col <= tileRange.endColumn(); col++ )
383 for ( int row = tileRange.startRow(); row <= tileRange.endRow(); row++ )
384 {
385 auto xyzTile = QgsTileXYZ( col, row, zoomLevel );
386 if ( mMetadata.containsTile( xyzTile ) )
387 ids.push_back( encodeTileId( xyzTile ) );
388 }
389
390 return ids;
391}
393QgsQuantizedMeshIndex::childAvailability( long long id ) const
394{
395 auto childIds = childTileIds( id );
396 if ( childIds.count() == 0 )
399}
400bool QgsQuantizedMeshIndex::fetchHierarchy( long long id, QgsFeedback *feedback )
401{
402 // The API was built for Cesium 3D tiles, which have tiles (actual files with
403 // metadata) as nodes of a hierarchy tree, with the actual data in children
404 // of those tiles. For us, tiles are represented by int IDs, so they don't
405 // need to be fetched.
406 Q_UNUSED( id );
407 Q_UNUSED( feedback );
408 return true;
409}
410
411QByteArray QgsQuantizedMeshIndex::fetchContent( const QString &uri,
412 QgsFeedback *feedback )
413{
414 QNetworkRequest requestData( uri );
415 requestData.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
416 requestData.setRawHeader( "Accept", "application/vnd.quantized-mesh,application/octet-stream;q=0.9" );
417 mMetadata.mHeaders.updateNetworkRequest( requestData );
418 if ( !mMetadata.mAuthCfg.isEmpty() )
419 QgsApplication::authManager()->updateNetworkRequest( requestData, mMetadata.mAuthCfg );
420 QgsSetRequestInitiatorClass( requestData,
421 QStringLiteral( "QgsQuantizedMeshIndex" ) );
422
423 std::unique_ptr<QgsTileDownloadManagerReply> reply( QgsApplication::tileDownloadManager()->get( requestData ) );
424
425 QEventLoop loop;
426 if ( feedback )
427 QObject::connect( feedback, &QgsFeedback::canceled, &loop, &QEventLoop::quit );
428 QObject::connect( reply.get(), &QgsTileDownloadManagerReply::finished, &loop, &QEventLoop::quit );
429 loop.exec();
430
431 if ( reply->error() != QNetworkReply::NoError )
432 {
433 QgsDebugError( QStringLiteral( "Request failed (%1): %2" ).arg( uri ).arg( reply->errorString() ) );
434 return {};
435 }
436 return reply->data();
437}
438
439QgsQuantizedMeshDataProvider::QgsQuantizedMeshDataProvider(
440 const QString &uri, const QgsDataProvider::ProviderOptions &providerOptions,
442 : QgsTiledSceneDataProvider( uri, providerOptions, flags ), mUri( uri ),
443 mProviderOptions( providerOptions )
444{
445 if ( uri.startsWith( QLatin1String( "ion://" ) ) )
446 {
447 QString updatedUri = uriFromIon( uri );
448 mMetadata = QgsQuantizedMeshMetadata( updatedUri, transformContext(), mError );
449 }
450 else
451 {
452 mMetadata = QgsQuantizedMeshMetadata( uri, transformContext(), mError );
453 }
454
455 if ( mError.isEmpty() )
456 {
457 QgsCoordinateReferenceSystem wgs84( QStringLiteral( "EPSG:4326" ) );
458 QgsCoordinateTransform wgs84ToCrs( wgs84, mMetadata->mCrs, transformContext() );
459 mIndex.emplace( new QgsQuantizedMeshIndex( *mMetadata, wgs84ToCrs ) );
460 mIsValid = true;
461 }
462}
463
464QString QgsQuantizedMeshDataProvider::uriFromIon( const QString &uri )
465{
466 // we expect one of the two options:
467 // ion://?assetId=123&accessToken=xyz
468 // ion://?assetId=123&authcfg=abc
469
470 QUrl url( uri );
471 const QString assetId = QUrlQuery( url ).queryItemValue( QStringLiteral( "assetId" ) );
472 const QString accessToken = QUrlQuery( url ).queryItemValue( QStringLiteral( "accessToken" ) );
473
474 const QString CESIUM_ION_URL = QStringLiteral( "https://api.cesium.com/" );
475
476 QgsDataSourceUri dsUri;
477 dsUri.setEncodedUri( uri );
478 QString authCfg = dsUri.authConfigId();
479 QgsHttpHeaders headers = dsUri.httpHeaders();
480
481 // get asset info
482 {
483 const QString assetInfoEndpoint = CESIUM_ION_URL + QStringLiteral( "v1/assets/%1" ).arg( assetId );
484 QNetworkRequest request = QNetworkRequest( assetInfoEndpoint );
485 QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsQuantizedMeshDataProvider" ) )
486 headers.updateNetworkRequest( request );
487 if ( !accessToken.isEmpty() )
488 request.setRawHeader( "Authorization", QStringLiteral( "Bearer %1" ).arg( accessToken ).toLocal8Bit() );
489
490 QgsBlockingNetworkRequest networkRequest;
491 if ( accessToken.isEmpty() )
492 networkRequest.setAuthCfg( authCfg );
493
494 switch ( networkRequest.get( request ) )
495 {
497 break;
498
502 // TODO -- error reporting
503 return QString();
504 }
505
506 const QgsNetworkReplyContent content = networkRequest.reply();
507 const json assetInfoJson = json::parse( content.content().toStdString() );
508 if ( assetInfoJson["type"] != "TERRAIN" )
509 {
510 appendError( QgsErrorMessage( tr( "Only ion TERRAIN content can be accessed, not %1" ).arg( QString::fromStdString( assetInfoJson["type"].get<std::string>() ) ) ) );
511 return QString();
512 }
513 }
514
515 // get tileset access details
516 QString tileSetUri;
517 {
518 const QString tileAccessEndpoint = CESIUM_ION_URL + QStringLiteral( "v1/assets/%1/endpoint" ).arg( assetId );
519 QNetworkRequest request = QNetworkRequest( tileAccessEndpoint );
520 QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsQuantizedMeshDataProvider" ) )
521 headers.updateNetworkRequest( request );
522 if ( !accessToken.isEmpty() )
523 request.setRawHeader( "Authorization", QStringLiteral( "Bearer %1" ).arg( accessToken ).toLocal8Bit() );
524
525 QgsBlockingNetworkRequest networkRequest;
526 if ( accessToken.isEmpty() )
527 networkRequest.setAuthCfg( authCfg );
528
529 switch ( networkRequest.get( request ) )
530 {
532 break;
533
537 // TODO -- error reporting
538 return QString();
539 }
540
541 const QgsNetworkReplyContent content = networkRequest.reply();
542 const json tileAccessJson = json::parse( content.content().toStdString() );
543
544 if ( tileAccessJson.contains( "url" ) )
545 {
546 tileSetUri = QString::fromStdString( tileAccessJson["url"].get<std::string>() );
547 }
548 else if ( tileAccessJson.contains( "options" ) )
549 {
550 const auto &optionsJson = tileAccessJson["options"];
551 if ( optionsJson.contains( "url" ) )
552 {
553 tileSetUri = QString::fromStdString( optionsJson["url"].get<std::string>() );
554 }
555 }
556
557 if ( tileAccessJson.contains( "accessToken" ) )
558 {
559 // The tileset accessToken is NOT the same as the token we use to access the asset details -- ie we can't
560 // use the same authentication as we got from the providers auth cfg!
561 headers.insert( QStringLiteral( "Authorization" ),
562 QStringLiteral( "Bearer %1" ).arg( QString::fromStdString( tileAccessJson["accessToken"].get<std::string>() ) ) );
563 }
564 }
565
566 QgsDataSourceUri finalUri;
567 finalUri.setParam( "url", tileSetUri + "layer.json" );
568 finalUri.setHttpHeaders( headers );
569 return finalUri.encodedUri();
570}
571
573QgsQuantizedMeshDataProvider::capabilities() const
574{
576}
577QgsTiledSceneDataProvider *QgsQuantizedMeshDataProvider::clone() const
578{
579 return new QgsQuantizedMeshDataProvider( mUri, mProviderOptions );
580}
582QgsQuantizedMeshDataProvider::sceneCrs() const
583{
584 return mMetadata->mCrs;
585}
587QgsQuantizedMeshDataProvider::boundingVolume() const
588{
589 return mMetadata->mBoundingVolume;
590}
591
592QgsTiledSceneIndex QgsQuantizedMeshDataProvider::index() const
593{
594 if ( !mIndex )
595 // Return dummy index, this provider is likely not valid
596 return QgsTiledSceneIndex( nullptr );
597 return *mIndex;
598}
599
600QgsDoubleRange QgsQuantizedMeshDataProvider::zRange() const
601{
602 return mMetadata->dummyZRange;
603}
604QgsCoordinateReferenceSystem QgsQuantizedMeshDataProvider::crs() const
605{
606 return mMetadata->mCrs;
607}
608QgsRectangle QgsQuantizedMeshDataProvider::extent() const
609{
610 return mMetadata->mExtent;
611}
612bool QgsQuantizedMeshDataProvider::isValid() const { return mIsValid; }
613QString QgsQuantizedMeshDataProvider::name() const { return providerName; }
614QString QgsQuantizedMeshDataProvider::description() const { return providerDescription; }
615
616const QgsQuantizedMeshMetadata &QgsQuantizedMeshDataProvider::quantizedMeshMetadata() const
617{
618 return *mMetadata;
619}
620
621QgsQuantizedMeshProviderMetadata::QgsQuantizedMeshProviderMetadata()
622 : QgsProviderMetadata( QgsQuantizedMeshDataProvider::providerName,
623 QgsQuantizedMeshDataProvider::providerDescription ) {}
624
625QgsDataProvider *QgsQuantizedMeshProviderMetadata::createProvider(
626 const QString &uri, const QgsDataProvider::ProviderOptions &providerOptions,
628{
629 return new QgsQuantizedMeshDataProvider( uri, providerOptions, flags );
630}
631
QFlags< TiledSceneProviderCapability > TiledSceneProviderCapabilities
Tiled scene data provider capabilities.
Definition qgis.h:5221
QFlags< DataProviderReadFlag > DataProviderReadFlags
Flags which control data provider construction.
Definition qgis.h:450
TileChildrenAvailability
Possible availability states for a tile's children.
Definition qgis.h:5258
@ Available
Tile children are already available.
@ NoChildren
Tile is known to have no children.
@ Z
Z-axis.
static QgsTileDownloadManager * tileDownloadManager()
Returns the application's tile download manager, used for download of map tiles when rendering.
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.
QString errorMessage() const
Returns the error message string, after a get(), post(), head() or put() request has been made.
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr, RequestFlags requestFlags=QgsBlockingNetworkRequest::RequestFlags())
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(), post(), head() or put() request has been mad...
A 3-dimensional box composed of x, y, z coordinates.
Definition qgsbox3d.h:43
QgsRectangle toRectangle() const
Converts the box to a 2D rectangle.
Definition qgsbox3d.h:361
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.
QgsPointXY transform(const QgsPointXY &point, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const
Transform the point from the source CRS to the destination CRS.
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.
void setEncodedUri(const QByteArray &uri)
Sets the complete encoded 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.
void setHttpHeaders(const QgsHttpHeaders &headers)
Sets headers to headers.
QgsRange which stores a range of double values.
Definition qgsrange.h:231
QgsErrorMessage represents single error message.
Definition qgserror.h:33
A container for error messages.
Definition qgserror.h:81
void append(const QString &message, const QString &tag)
Append new error message.
Definition qgserror.cpp:39
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
void canceled()
Internal routines can connect to this signal if they use event loop.
This class implements simple http header management.
void insert(const QString &key, const QVariant &value)
insert a key with the specific value
A simple 4x4 matrix implementation useful for transformation in 3D space.
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
QByteArray content() const
Returns the reply content.
QgsBox3D extent() const
Returns the overall bounding box of the object.
static QgsOrientedBox3D fromBox3D(const QgsBox3D &box)
Constructs an oriented box from an axis-aligned bounding box.
A class to represent a 2D point.
Definition qgspointxy.h:60
Holds data provider key, description, and associated shared library file or function pointer informat...
A rectangle specified with double values.
void finished()
Emitted when the reply has finished (either with a success or with a failure)
static QgsTileMatrix fromTileMatrix(int zoomLevel, const QgsTileMatrix &tileMatrix)
Returns a tile matrix based on another one.
Definition qgstiles.cpp:61
static QgsTileMatrix fromCustomDef(int zoomLevel, const QgsCoordinateReferenceSystem &crs, const QgsPointXY &z0TopLeftPoint, double z0Dimension, int z0MatrixWidth=1, int z0MatrixHeight=1)
Returns a tile matrix for a specific CRS, top left point, zoom level 0 dimension in CRS units.
Definition qgstiles.cpp:31
Range of tiles in a tile matrix to be rendered.
Definition qgstiles.h:99
Stores coordinates of a tile in a tile matrix set.
Definition qgstiles.h:40
int zoomLevel() const
Returns tile's zoom level (Z)
Definition qgstiles.h:53
int column() const
Returns tile's column index (X)
Definition qgstiles.h:49
int row() const
Returns tile's row index (Y)
Definition qgstiles.h:51
Represents a bounding volume for a tiled scene.
Base class for data providers for QgsTiledSceneLayer.
An index for tiled scene data providers.
Tiled scene data request.
QgsOrientedBox3D filterBox() const
Returns the box from which data will be taken.
long long parentTileId() const
Returns the parent tile ID, if filtering is limited to children of a specific tile.
double requiredGeometricError() const
Returns the required geometric error threshold for the returned tiles, in meters.
Represents an individual tile from a tiled scene data source.
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...
#define QgsDebugError(str)
Definition qgslogger.h:38
#define QgsSetRequestInitiatorClass(request, _class)
Setting options for creating vector data providers.