41#include <QNetworkRequest>
42#include <QJsonDocument>
45#include <QRegularExpression>
46#include <QRecursiveMutex>
48#include <QApplication>
49#include <nlohmann/json.hpp>
53#define PROVIDER_KEY QStringLiteral( "cesiumtiles" )
54#define PROVIDER_DESCRIPTION QStringLiteral( "Cesium 3D Tiles data provider" )
65static QString appendQueryFromBaseUrl(
const QString &contentUri,
const QUrl &baseUrl )
67 QUrlQuery contentQuery( QUrl( contentUri ).query() );
68 const QList<QPair<QString, QString>> baseUrlQueryItems = QUrlQuery( baseUrl.query() ).queryItems();
69 for (
const QPair<QString, QString> &kv : baseUrlQueryItems )
71 contentQuery.addQueryItem( kv.first, kv.second );
73 QUrl newContentUrl( contentUri );
74 newContentUrl.setQuery( contentQuery );
75 return newContentUrl.toString();
83 QgsCesiumTiledSceneIndex(
86 const QString &authCfg,
90 std::unique_ptr< QgsTiledSceneTile > tileFromJson(
const json &node,
const QUrl &baseUrl,
const QgsTiledSceneTile *parent,
Qgis::Axis gltfUpAxis );
92 void refineNodeFromJson(
QgsTiledSceneNode *node,
const QUrl &baseUrl,
const json &json );
96 long long parentTileId(
long long id ) const final;
97 QVector<
long long > childTileIds(
long long id ) const final;
99 Qgis::TileChildrenAvailability childAvailability(
long long id ) const final;
100 bool fetchHierarchy(
long long id,
QgsFeedback *feedback =
nullptr ) final;
104 QByteArray fetchContent( const QString &uri,
QgsFeedback *feedback =
nullptr ) final;
108 enum class TileContentFormat
114 mutable QRecursiveMutex mLock;
116 std::unique_ptr< QgsTiledSceneNode > mRootNode;
117 QMap< long long, QgsTiledSceneNode * > mNodeMap;
118 QMap< long long, TileContentFormat > mTileContentFormats;
121 long long mNextTileId = 0;
125class QgsCesiumTilesDataProviderSharedData
128 QgsCesiumTilesDataProviderSharedData();
129 void initialize(
const QString &tileset,
132 const QString &authCfg,
140 nlohmann::json mTileset;
147 QReadWriteLock mReadWriteLock;
158 const std::string gltfUpAxisString = json.get<std::string>();
159 if ( gltfUpAxisString ==
"z" || gltfUpAxisString ==
"Z" )
163 else if ( gltfUpAxisString ==
"y" || gltfUpAxisString ==
"Y" )
167 else if ( gltfUpAxisString ==
"x" || gltfUpAxisString ==
"X" )
171 QgsDebugError( QStringLiteral(
"Unsupported gltfUpAxis value: %1" ).arg( QString::fromStdString( gltfUpAxisString ) ) );
176 : mTransformContext( transformContext )
177 , mAuthCfg( authCfg )
178 , mHeaders( headers )
181 if ( tileset.contains(
"asset" ) )
183 const auto &assetJson = tileset[
"asset"];
184 if ( assetJson.contains(
"gltfUpAxis" ) )
186 gltfUpAxis = axisFromJson( assetJson[
"gltfUpAxis"] );
190 mRootNode.reset( nodeFromJson( tileset[
"root" ], rootUrl,
nullptr, gltfUpAxis ) );
193std::unique_ptr< QgsTiledSceneTile > QgsCesiumTiledSceneIndex::tileFromJson(
const json &json,
const QUrl &baseUrl,
const QgsTiledSceneTile *parent,
Qgis::Axis gltfUpAxis )
195 std::unique_ptr< QgsTiledSceneTile > tile = std::make_unique< QgsTiledSceneTile >( mNextTileId++ );
197 tile->setBaseUrl( baseUrl );
198 tile->setMetadata( {{ QStringLiteral(
"gltfUpAxis" ),
static_cast< int >( gltfUpAxis ) }} );
201 if ( json.contains(
"transform" ) && !json[
"transform"].is_null() )
203 const auto &transformJson = json[
"transform"];
204 double *ptr = transform.
data();
205 for (
int i = 0; i < 16; ++i )
206 ptr[i] = transformJson[i].get<double>();
210 transform = *parent->
transform() * transform;
213 else if ( parent && parent->
transform() )
218 tile->setTransform( transform );
220 const auto &boundingVolume = json[
"boundingVolume" ];
222 if ( boundingVolume.contains(
"region" ) )
225 if ( !rootRegion.
isNull() )
227 if ( rootRegion.
width() > 20 || rootRegion.
height() > 20 )
234 QVector< QgsVector3D > corners = rootRegion.
corners();
242 for (
int i = 0; i < 8; ++i )
245 x.append( corner.
x() );
246 y.append( corner.
y() );
247 z.append( corner.
z() );
250 ct.setBallparkTransformsAreAppropriate(
true );
253 ct.transformInPlace( x, y, z );
257 QgsDebugError( QStringLiteral(
"Cannot transform region bounding volume" ) );
260 const auto minMaxX = std::minmax_element( x.constBegin(), x.constEnd() );
261 const auto minMaxY = std::minmax_element( y.constBegin(), y.constEnd() );
262 const auto minMaxZ = std::minmax_element( z.constBegin(), z.constEnd() );
269 else if ( boundingVolume.contains(
"box" ) )
279 else if ( boundingVolume.contains(
"sphere" ) )
290 QgsDebugError( QStringLiteral(
"unsupported boundingVolume format" ) );
293 tile->setBoundingVolume( volume );
295 if ( json.contains(
"geometricError" ) )
296 tile->setGeometricError( json[
"geometricError"].get< double >() );
297 if ( json.contains(
"refine" ) )
299 if ( json[
"refine"] ==
"ADD" )
301 else if ( json[
"refine"] ==
"REPLACE" )
310 if ( json.contains(
"content" ) && !json[
"content"].is_null() )
312 const auto &contentJson = json[
"content"];
316 if ( contentJson.contains(
"uri" ) && !contentJson[
"uri"].is_null() )
318 QString relativeUri = QString::fromStdString( contentJson[
"uri"].get<std::string>() );
319 contentUri = baseUrl.resolved( QUrl( relativeUri ) ).toString();
321 if ( baseUrl.hasQuery() && QUrl( relativeUri ).isRelative() )
322 contentUri = appendQueryFromBaseUrl( contentUri, baseUrl );
324 else if ( contentJson.contains(
"url" ) && !contentJson[
"url"].is_null() )
326 QString relativeUri = QString::fromStdString( contentJson[
"url"].get<std::string>() );
327 contentUri = baseUrl.resolved( QUrl( relativeUri ) ).toString();
329 if ( baseUrl.hasQuery() && QUrl( relativeUri ).isRelative() )
330 contentUri = appendQueryFromBaseUrl( contentUri, baseUrl );
332 if ( !contentUri.isEmpty() )
334 tile->setResources( {{ QStringLiteral(
"content" ), contentUri } } );
343 std::unique_ptr< QgsTiledSceneTile > tile = tileFromJson( json, baseUrl, parent ? parent->
tile() : nullptr, gltfUpAxis );
344 std::unique_ptr< QgsTiledSceneNode > newNode = std::make_unique< QgsTiledSceneNode >( tile.release() );
345 mNodeMap.insert( newNode->tile()->id(), newNode.get() );
350 if ( json.contains(
"children" ) )
352 for (
const auto &childJson : json[
"children"] )
354 nodeFromJson( childJson, baseUrl, newNode.get(), gltfUpAxis );
358 return newNode.release();
361void QgsCesiumTiledSceneIndex::refineNodeFromJson(
QgsTiledSceneNode *node,
const QUrl &baseUrl,
const json &json )
363 const auto &rootTileJson = json[
"root"];
366 if ( json.contains(
"asset" ) )
368 const auto &assetJson = json[
"asset"];
369 if ( assetJson.contains(
"gltfUpAxis" ) )
371 gltfUpAxis = axisFromJson( assetJson[
"gltfUpAxis"] );
375 std::unique_ptr< QgsTiledSceneTile > newTile = tileFromJson( rootTileJson, baseUrl, node->
tile(), gltfUpAxis );
385 if ( newTile->transform() )
388 if ( rootTileJson.contains(
"children" ) )
390 for (
const auto &childJson : rootTileJson[
"children"] )
392 nodeFromJson( childJson, baseUrl, node, gltfUpAxis );
399 QMutexLocker locker( &mLock );
405 QMutexLocker locker( &mLock );
406 auto it = mNodeMap.constFind(
id );
407 if ( it != mNodeMap.constEnd() )
409 return *( it.value()->tile() );
415long long QgsCesiumTiledSceneIndex::parentTileId(
long long id )
const
417 QMutexLocker locker( &mLock );
418 auto it = mNodeMap.constFind(
id );
419 if ( it != mNodeMap.constEnd() )
423 return parent->
tile()->
id();
430QVector< long long > QgsCesiumTiledSceneIndex::childTileIds(
long long id )
const
432 QMutexLocker locker( &mLock );
433 auto it = mNodeMap.constFind(
id );
434 if ( it != mNodeMap.constEnd() )
436 QVector< long long > childIds;
437 const QList< QgsTiledSceneNode * > children = it.value()->children();
438 childIds.reserve( children.size() );
441 childIds << child->tile()->id();
451 QVector< long long > results;
454 traverseNode = [&request, &traverseNode, &results,
this](
QgsTiledSceneNode * node )
470 QList< QgsTiledSceneNode * > children = node->
children();
471 if ( children.empty() )
473 switch ( childAvailability( tile->
id() ) )
483 if ( fetchHierarchy( tile->
id() ), request.
feedback() )
498 traverseNode( child );
505 results << tile->
id();
510 if ( children.empty() )
511 results << tile->
id();
517 results << tile->
id();
522 QMutexLocker locker( &mLock );
526 traverseNode( mRootNode.get() );
531 if ( it != mNodeMap.constEnd() )
533 traverseNode( it.value() );
543 QMutexLocker locker( &mLock );
545 auto it = mNodeMap.constFind(
id );
546 if ( it == mNodeMap.constEnd() )
549 if ( !it.value()->children().isEmpty() )
552 contentUri = it.value()->tile()->resources().value( QStringLiteral(
"content" ) ).toString();
556 auto it = mTileContentFormats.constFind(
id );
557 if ( it != mTileContentFormats.constEnd() )
559 switch ( it.value() )
561 case TileContentFormat::NotJson:
563 case TileContentFormat::Json:
570 if ( contentUri.isEmpty() )
580 const thread_local QRegularExpression isJsonRx( QStringLiteral(
".*\\.json(?:\\?.*)?$" ), QRegularExpression::PatternOption::CaseInsensitiveOption );
581 if ( isJsonRx.match( contentUri ).hasMatch() )
585 const thread_local QRegularExpression antiCandidateRx( QStringLiteral(
".*\\.(gltf|glb|b3dm|i3dm|pnts|cmpt|bin|glbin|glbuf|png|jpeg|jpg)(?:\\?.*)?$" ), QRegularExpression::PatternOption::CaseInsensitiveOption );
586 if ( antiCandidateRx.match( contentUri ).hasMatch() )
594bool QgsCesiumTiledSceneIndex::fetchHierarchy(
long long id,
QgsFeedback *feedback )
596 QMutexLocker locker( &mLock );
597 auto it = mNodeMap.constFind(
id );
598 if ( it == mNodeMap.constEnd() )
604 auto it = mTileContentFormats.constFind(
id );
605 if ( it != mTileContentFormats.constEnd() )
607 switch ( it.value() )
609 case TileContentFormat::NotJson:
611 case TileContentFormat::Json:
617 const QString contentUri = it.value()->tile()->resources().value( QStringLiteral(
"content" ) ).toString();
620 if ( contentUri.isEmpty() )
624 const QByteArray subTile = retrieveContent( contentUri, feedback );
625 if ( !subTile.isEmpty() )
632 const auto subTileJson = json::parse( subTile.toStdString() );
633 QMutexLocker locker( &mLock );
634 refineNodeFromJson( it.value(), QUrl( contentUri ), subTileJson );
635 mTileContentFormats.insert(
id, TileContentFormat::Json );
638 catch ( json::parse_error & )
640 QMutexLocker locker( &mLock );
641 mTileContentFormats.insert(
id, TileContentFormat::NotJson );
649 mTileContentFormats.insert(
id, TileContentFormat::NotJson );
654QByteArray QgsCesiumTiledSceneIndex::fetchContent(
const QString &uri,
QgsFeedback *feedback )
658 if ( uri.startsWith(
"http" ) )
660 QNetworkRequest networkRequest = QNetworkRequest( url );
662 networkRequest.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
663 networkRequest.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
665 mHeaders.updateNetworkRequest( networkRequest );
667 if ( QThread::currentThread() == QApplication::instance()->thread() )
671 networkRequest, mAuthCfg,
false, feedback );
691 return reply->data();
694 else if ( url.isLocalFile() && QFile::exists( url.toLocalFile() ) )
696 QFile file( url.toLocalFile() );
697 if ( file.open( QIODevice::ReadOnly ) )
699 return file.readAll();
710QgsCesiumTilesDataProviderSharedData::QgsCesiumTilesDataProviderSharedData()
718 mTileset = json::parse( tileset.toStdString() );
719 if ( !mTileset.contains(
"root" ) )
721 mError = QObject::tr(
"JSON is not a valid Cesium 3D Tiles source (does not contain \"root\" value)" );
725 mLayerMetadata.setType( QStringLiteral(
"dataset" ) );
727 if ( mTileset.contains(
"asset" ) )
729 const auto &asset = mTileset[
"asset" ];
730 if ( asset.contains(
"tilesetVersion" ) )
734 const QString tilesetVersion = QString::fromStdString( asset[
"tilesetVersion"].get<std::string>() );
735 mLayerMetadata.setIdentifier( tilesetVersion );
737 catch ( json::type_error & )
739 QgsDebugError( QStringLiteral(
"Error when parsing tilesetVersion value" ) );
745 new QgsCesiumTiledSceneIndex(
756 const auto &root = mTileset[
"root" ];
768 const auto &rootBoundingVolume = root[
"boundingVolume" ];
771 if ( root.contains(
"transform" ) && !root[
"transform"].is_null() )
773 const auto &transformJson = root[
"transform"];
774 double *ptr = rootTransform.
data();
775 for (
int i = 0; i < 16; ++i )
776 ptr[i] = transformJson[i].get<double>();
779 if ( rootBoundingVolume.contains(
"region" ) )
782 if ( !rootRegion.
isNull() )
787 if ( !mIndex.rootTile().boundingVolume().box().isNull() )
794 mLayerMetadata.setCrs( mSceneCrs );
797 spatialExtent.
bounds = rootRegion;
800 else if ( rootBoundingVolume.contains(
"box" ) )
811 mLayerMetadata.setCrs( mSceneCrs );
814 mBoundingVolume.transform( rootTransform );
818 ct.setBallparkTransformsAreAppropriate(
true );
819 const QgsBox3D rootRegion = mBoundingVolume.bounds( ct );
821 if ( !mIndex.rootTile().boundingVolume().box().isNull() )
826 std::unique_ptr< QgsAbstractGeometry > extent2D( mBoundingVolume.as2DGeometry( ct ) );
827 mExtent = extent2D->boundingBox();
831 QgsDebugError( QStringLiteral(
"Caught transform exception when transforming boundingVolume" ) );
835 spatialExtent.
bounds = mBoundingVolume.bounds();
838 else if ( rootBoundingVolume.contains(
"sphere" ) )
849 mLayerMetadata.setCrs( mSceneCrs );
857 ct.setBallparkTransformsAreAppropriate(
true );
858 const QgsBox3D rootRegion = mBoundingVolume.bounds( ct );
860 if ( !mIndex.rootTile().boundingVolume().box().isNull() )
865 std::unique_ptr< QgsAbstractGeometry > extent2D( mBoundingVolume.as2DGeometry( ct ) );
866 mExtent = extent2D->boundingBox();
870 QgsDebugError( QStringLiteral(
"Caught transform exception when transforming boundingVolume" ) );
874 spatialExtent.
bounds = mBoundingVolume.bounds();
879 mError = QObject::tr(
"JSON is not a valid Cesium 3D Tiles source (unsupported boundingVolume format)" );
885 mLayerMetadata.setExtent( layerExtent );
895QgsCesiumTilesDataProvider::QgsCesiumTilesDataProvider(
const QString &uri,
const ProviderOptions &providerOptions, ReadFlags flags )
897 , mShared( std::make_shared< QgsCesiumTilesDataProviderSharedData >() )
907QgsCesiumTilesDataProvider::QgsCesiumTilesDataProvider(
const QgsCesiumTilesDataProvider &other )
909 , mIsValid( other.mIsValid )
910 , mAuthCfg( other.mAuthCfg )
911 , mHeaders( other.mHeaders )
914 mShared = other.mShared;
917Qgis::TiledSceneProviderCapabilities QgsCesiumTilesDataProvider::capabilities()
const
922QgsCesiumTilesDataProvider::~QgsCesiumTilesDataProvider() =
default;
924QgsCesiumTilesDataProvider *QgsCesiumTilesDataProvider::clone()
const
927 return new QgsCesiumTilesDataProvider( *
this );
930bool QgsCesiumTilesDataProvider::init()
935 const QString uri = dataSourceUri();
937 if ( uri.startsWith( QLatin1String(
"ion://" ) ) )
940 const QString assetId = QUrlQuery( url ).queryItemValue( QStringLiteral(
"assetId" ) );
941 const QString accessToken = QUrlQuery( url ).queryItemValue( QStringLiteral(
"accessToken" ) );
943 const QString CESIUM_ION_URL = QStringLiteral(
"https://api.cesium.com/" );
947 const QString assetInfoEndpoint = CESIUM_ION_URL + QStringLiteral(
"v1/assets/%1" ).arg( assetId );
948 QNetworkRequest request = QNetworkRequest( assetInfoEndpoint );
950 mHeaders.updateNetworkRequest( request );
951 if ( !accessToken.isEmpty() )
952 request.setRawHeader( "Authorization", QStringLiteral( "Bearer %1" ).arg( accessToken ).toLocal8Bit() );
955 if ( accessToken.isEmpty() )
956 networkRequest.setAuthCfg( mAuthCfg );
958 switch ( networkRequest.get( request ) )
971 const json assetInfoJson = json::parse( content.
content().toStdString() );
972 if ( assetInfoJson[
"type"] !=
"3DTILES" )
974 appendError(
QgsErrorMessage( tr(
"Only ion 3D Tiles content can be accessed, not %1" ).arg( QString::fromStdString( assetInfoJson[
"type"].get<std::string>() ) ) ) );
978 mShared->mLayerMetadata.setTitle( QString::fromStdString( assetInfoJson[
"name"].get<std::string>() ) );
979 mShared->mLayerMetadata.setAbstract( QString::fromStdString( assetInfoJson[
"description"].get<std::string>() ) );
980 const QString attribution = QString::fromStdString( assetInfoJson[
"attribution"].get<std::string>() );
981 if ( !attribution.isEmpty() )
982 mShared->mLayerMetadata.setRights( { attribution } );
984 mShared->mLayerMetadata.setDateTime(
Qgis::MetadataDateType::Created, QDateTime::fromString( QString::fromStdString( assetInfoJson[
"dateAdded"].get<std::string>() ), Qt::DateFormat::ISODate ) );
989 const QString tileAccessEndpoint = CESIUM_ION_URL + QStringLiteral(
"v1/assets/%1/endpoint" ).arg( assetId );
990 QNetworkRequest request = QNetworkRequest( tileAccessEndpoint );
992 mHeaders.updateNetworkRequest( request );
993 if ( !accessToken.isEmpty() )
994 request.setRawHeader( "Authorization", QStringLiteral( "Bearer %1" ).arg( accessToken ).toLocal8Bit() );
997 if ( accessToken.isEmpty() )
998 networkRequest.setAuthCfg( mAuthCfg );
1000 switch ( networkRequest.get( request ) )
1013 const json tileAccessJson = json::parse( content.
content().toStdString() );
1015 if ( tileAccessJson.contains(
"url" ) )
1017 tileSetUri = QString::fromStdString( tileAccessJson[
"url"].get<std::string>() );
1019 else if ( tileAccessJson.contains(
"options" ) )
1021 const auto &optionsJson = tileAccessJson[
"options"];
1022 if ( optionsJson.contains(
"url" ) )
1024 tileSetUri = QString::fromStdString( optionsJson[
"url"].get<std::string>() );
1028 if ( tileAccessJson.contains(
"accessToken" ) )
1032 mHeaders.insert( QStringLiteral(
"Authorization" ),
1033 QStringLiteral(
"Bearer %1" ).arg( QString::fromStdString( tileAccessJson[
"accessToken"].get<std::string>() ) ) );
1042 tileSetUri = dsUri.
param( QStringLiteral(
"url" ) );
1045 if ( !tileSetUri.isEmpty() )
1047 const QUrl url( tileSetUri );
1049 QNetworkRequest request = QNetworkRequest( url );
1051 mHeaders.updateNetworkRequest( request );
1054 networkRequest.setAuthCfg( mAuthCfg );
1056 switch ( networkRequest.get( request ) )
1070 mShared->initialize( content.
content(), tileSetUri, transformContext(), mAuthCfg, mHeaders );
1077 const QFileInfo fi( dataSourceUri() );
1080 QFile file( dataSourceUri( ) );
1081 if ( file.open( QIODevice::ReadOnly | QIODevice::Text ) )
1083 const QByteArray raw = file.readAll();
1084 mShared->initialize( raw, QUrl::fromLocalFile( dataSourceUri() ), transformContext(), mAuthCfg, mHeaders );
1097 if ( !mShared->mIndex.isValid() )
1099 appendError( mShared->mError );
1110 return mShared->mLayerCrs;
1118 return mShared->mExtent;
1121bool QgsCesiumTilesDataProvider::isValid()
const
1128QString QgsCesiumTilesDataProvider::name()
const
1132 return PROVIDER_KEY;
1135QString QgsCesiumTilesDataProvider::description()
const
1139 return QObject::tr(
"Cesium 3D Tiles" );
1142QString QgsCesiumTilesDataProvider::htmlMetadata()
const
1149 if ( mShared->mTileset.contains(
"asset" ) )
1151 const auto &asset = mShared->mTileset[
"asset" ];
1152 if ( asset.contains(
"version" ) )
1154 const QString version = QString::fromStdString( asset[
"version"].get<std::string>() );
1155 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"3D Tiles Version" ) % QStringLiteral(
"</td><td>%1</a>" ).arg( version ) % QStringLiteral(
"</td></tr>\n" );
1158 if ( asset.contains(
"tilesetVersion" ) )
1162 const QString tilesetVersion = QString::fromStdString( asset[
"tilesetVersion"].get<std::string>() );
1163 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"Tileset Version" ) % QStringLiteral(
"</td><td>%1</a>" ).arg( tilesetVersion ) % QStringLiteral(
"</td></tr>\n" );
1165 catch ( json::type_error & )
1167 QgsDebugError( QStringLiteral(
"Error when parsing tilesetVersion value" ) );
1171 if ( asset.contains(
"generator" ) )
1173 const QString generator = QString::fromStdString( asset[
"generator"].get<std::string>() );
1174 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"Tileset Generator" ) % QStringLiteral(
"</td><td>%1</a>" ).arg( generator ) % QStringLiteral(
"</td></tr>\n" );
1177 if ( mShared->mTileset.contains(
"extensionsRequired" ) )
1179 QStringList extensions;
1180 for (
const auto &item : mShared->mTileset[
"extensionsRequired"] )
1182 extensions << QString::fromStdString( item.get<std::string>() );
1184 if ( !extensions.isEmpty() )
1186 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"Extensions Required" ) % QStringLiteral(
"</td><td><ul><li>%1</li></ul></a>" ).arg( extensions.join( QLatin1String(
"</li><li>" ) ) ) % QStringLiteral(
"</td></tr>\n" );
1189 if ( mShared->mTileset.contains(
"extensionsUsed" ) )
1191 QStringList extensions;
1192 for (
const auto &item : mShared->mTileset[
"extensionsUsed"] )
1194 extensions << QString::fromStdString( item.get<std::string>() );
1196 if ( !extensions.isEmpty() )
1198 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"Extensions Used" ) % QStringLiteral(
"</td><td><ul><li>%1</li></ul></a>" ).arg( extensions.join( QLatin1String(
"</li><li>" ) ) ) % QStringLiteral(
"</td></tr>\n" );
1202 if ( !mShared->mZRange.isInfinite() )
1204 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"Z Range" ) % QStringLiteral(
"</td><td>%1 - %2</a>" ).arg( QLocale().toString( mShared->mZRange.lower() ), QLocale().toString( mShared->mZRange.upper() ) ) % QStringLiteral(
"</td></tr>\n" );
1217 return mShared->mLayerMetadata;
1227 return mShared->mSceneCrs ;
1238 return mShared ? mShared->mBoundingVolume : nullVolume;
1248 return mShared->mIndex;
1258 return mShared->mZRange;
1266QgsCesiumTilesProviderMetadata::QgsCesiumTilesProviderMetadata():
1271QIcon QgsCesiumTilesProviderMetadata::icon()
const
1276QgsCesiumTilesDataProvider *QgsCesiumTilesProviderMetadata::createProvider(
const QString &uri,
const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
1278 return new QgsCesiumTilesDataProvider( uri, options, flags );
1281QList<QgsProviderSublayerDetails> QgsCesiumTilesProviderMetadata::querySublayers(
const QString &uri, Qgis::SublayerQueryFlags,
QgsFeedback * )
const
1283 const QVariantMap parts = decodeUri( uri );
1284 if ( parts.value( QStringLiteral(
"file-name" ) ).toString().compare( QLatin1String(
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
1299int QgsCesiumTilesProviderMetadata::priorityForUri(
const QString &uri )
const
1301 const QVariantMap parts = decodeUri( uri );
1302 if ( parts.value( QStringLiteral(
"file-name" ) ).toString().compare( QLatin1String(
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
1308QList<Qgis::LayerType> QgsCesiumTilesProviderMetadata::validLayerTypesForUri(
const QString &uri )
const
1310 const QVariantMap parts = decodeUri( uri );
1311 if ( parts.value( QStringLiteral(
"file-name" ) ).toString().compare( QLatin1String(
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
1314 return QList< Qgis::LayerType>();
1317QVariantMap QgsCesiumTilesProviderMetadata::decodeUri(
const QString &uri )
const
1319 QVariantMap uriComponents;
1320 QUrl url = QUrl::fromUserInput( uri );
1321 uriComponents.insert( QStringLiteral(
"file-name" ), url.fileName() );
1322 uriComponents.insert( QStringLiteral(
"path" ), uri );
1323 return uriComponents;
1339 return QObject::tr(
"Cesium 3D Tiles" ) + QStringLiteral(
" (tileset.json TILESET.JSON)" );
1344QgsProviderMetadata::ProviderCapabilities QgsCesiumTilesProviderMetadata::providerCapabilities()
const
1346 return FileBasedUris;
1349QList<Qgis::LayerType> QgsCesiumTilesProviderMetadata::supportedLayerTypes()
const
1354QString QgsCesiumTilesProviderMetadata::encodeUri(
const QVariantMap &parts )
const
1356 const QString path = parts.value( QStringLiteral(
"path" ) ).toString();
1360QgsProviderMetadata::ProviderMetadataCapabilities QgsCesiumTilesProviderMetadata::capabilities()
const
1362 return ProviderMetadataCapability::LayerTypesForUri
1363 | ProviderMetadataCapability::PriorityForUri
1364 | ProviderMetadataCapability::QuerySublayers;
The Qgis class provides global constants for use throughout the application.
FileFilterType
Type of file filters.
@ TiledScene
Tiled scene layers (since QGIS 3.34)
@ VectorTile
Vector tile layers (since QGIS 3.32)
@ MeshDataset
Mesh datasets.
@ PointCloud
Point clouds (since QGIS 3.18)
@ ReadLayerMetadata
Provider can read layer metadata from data store. See QgsDataProvider::layerMetadata()
TileChildrenAvailability
Possible availability states for a tile's children.
@ Available
Tile children are already available.
@ NeedFetching
Tile has children, but they are not yet available and must be fetched.
@ NoChildren
Tile is known to have no children.
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
@ NoHierarchyFetch
Do not allow hierarchy fetching when hierarchy is not currently available. Avoids network requests,...
@ Additive
When tile is refined its content should be used alongside its children simultaneously.
@ Replacement
When tile is refined then its children should be used in place of itself.
An abstract base class for tiled scene data provider indices.
virtual QgsTiledSceneTile rootTile() const =0
Returns the root tile for the index.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
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...
@ 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.
A 3-dimensional box composed of x, y, z coordinates.
double zMaximum() const
Returns the maximum z value.
QgsRectangle toRectangle() const
Converts the box to a 2D rectangle.
QVector< QgsVector3D > corners() const
Returns an array of all box corners as 3D vectors.
double width() const
Returns the width of the box.
double zMinimum() const
Returns the minimum z value.
double height() const
Returns the height of the box.
bool isNull() const
Test if the box is null (holding no spatial information).
static QgsSphere parseSphere(const json &sphere)
Parses a sphere object from a Cesium JSON document.
static QgsOrientedBox3D parseBox(const json &box)
Parses a box object from a Cesium JSON document to an oriented bounding box.
static QgsBox3D parseRegion(const json ®ion)
Parses a region object from a Cesium JSON object to a 3D box.
static QgsSphere transformSphere(const QgsSphere &sphere, const QgsMatrix4x4 &transform)
Applies a transform to a sphere.
This class represents a coordinate reference system (CRS).
Contains information about the context in which a coordinate transform is executed.
Custom exception class for Coordinate Reference System related exceptions.
Class for storing the component parts of a RDBMS data source URI (e.g.
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.
QString authConfigId() const
Returns any associated authentication configuration ID stored in the URI.
QgsRange which stores a range of double values.
QgsErrorMessage represents single error message.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const
Tells whether the operation has been canceled already.
void canceled()
Internal routines can connect to this signal if they use event loop.
A simple 4x4 matrix implementation useful for transformation in 3D space.
bool isIdentity() const
Returns whether this matrix is an identity matrix.
double * data()
Returns pointer to the matrix data (stored in column-major order)
static QgsNetworkReplyContent blockingGet(QNetworkRequest &request, const QString &authCfg=QString(), bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Posts a GET request to obtain the contents of the target request and returns a new QgsNetworkReplyCon...
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
QByteArray content() const
Returns the reply content.
Represents a oriented (rotated) box in 3 dimensions.
bool isNull() const
Returns true if the box is a null box.
static QgsOrientedBox3D fromBox3D(const QgsBox3D &box)
Constructs an oriented box from an axis-aligned bounding box.
Contains details about a sub layer available from a dataset.
void setUri(const QString &uri)
Sets the layer's uri.
void setType(Qgis::LayerType type)
Sets the layer type.
void setName(const QString &name)
Sets the layer's name.
void setProviderKey(const QString &key)
Sets the associated data provider key.
static QString suggestLayerNameFromFilePath(const QString &path)
Suggests a suitable layer name given only a file path.
The QgsReadWriteLocker class is a convenience class that simplifies locking and unlocking QReadWriteL...
A rectangle specified with double values.
A spherical geometry object.
bool isNull() const
Returns true if the sphere is a null (default constructed) sphere.
QgsBox3D boundingBox() const
Returns the 3-dimensional bounding box containing the sphere.
void finished()
Emitted when the reply has finished (either with a success or with a failure)
Represents a bounding volume for a tiled scene.
QgsOrientedBox3D box() const
Returns the volume's oriented box.
bool intersects(const QgsOrientedBox3D &box) const
Returns true if this bounds intersects the specified box.
void transform(const QgsMatrix4x4 &transform)
Applies a transform to the bounding volume.
Base class for data providers for QgsTiledSceneLayer.
An index for tiled scene data providers.
Allows representing QgsTiledSceneTiles in a hierarchical tree.
void addChild(QgsTiledSceneNode *child)
Adds a child to this node.
QgsTiledSceneNode * parentNode() const
Returns the parent of this node.
QList< QgsTiledSceneNode * > children() const
Returns this node's children.
QgsTiledSceneTile * tile()
Returns the tile associated with the node.
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 scene CRS units.
QgsFeedback * feedback() const
Returns the feedback object that can be queried regularly by the request to check if it should be can...
Qgis::TiledSceneRequestFlags flags() const
Returns the flags which affect how tiles are fetched.
Represents an individual tile from a tiled scene data source.
void setTransform(const QgsMatrix4x4 &transform)
Sets the tile's transform.
Qgis::TileRefinementProcess refinementProcess() const
Returns the tile's refinement process.
const QgsTiledSceneBoundingVolume & boundingVolume() const
Returns the bounding volume for the tile.
long long id() const
Returns the tile's unique ID.
const QgsMatrix4x4 * transform() const
Returns the tile's transform.
void setResources(const QVariantMap &resources)
Sets the resources attached to the tile.
double geometricError() const
Returns the tile's geometric error, which is the error, in scene CRS units, of the tile's simplified ...
Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precisi...
double y() const
Returns Y coordinate.
double z() const
Returns Z coordinate.
double x() const
Returns X coordinate.
#define QgsDebugError(str)
#define QgsSetRequestInitiatorClass(request, _class)
#define QGIS_PROTECT_QOBJECT_THREAD_ACCESS
Setting options for creating vector data providers.