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 if ( contentUri.endsWith( QLatin1String(
".json" ), Qt::CaseInsensitive ) )
584 const thread_local QRegularExpression antiCandidateRx( QStringLiteral(
".*\\.(gltf|glb|b3dm|i3dm|pnts|cmpt|bin|glbin|glbuf|png|jpeg|jpg)$" ), QRegularExpression::PatternOption::CaseInsensitiveOption );
585 if ( antiCandidateRx.match( contentUri ).hasMatch() )
593bool QgsCesiumTiledSceneIndex::fetchHierarchy(
long long id,
QgsFeedback *feedback )
595 QMutexLocker locker( &mLock );
596 auto it = mNodeMap.constFind(
id );
597 if ( it == mNodeMap.constEnd() )
603 auto it = mTileContentFormats.constFind(
id );
604 if ( it != mTileContentFormats.constEnd() )
606 switch ( it.value() )
608 case TileContentFormat::NotJson:
610 case TileContentFormat::Json:
616 const QString contentUri = it.value()->tile()->resources().value( QStringLiteral(
"content" ) ).toString();
619 if ( contentUri.isEmpty() )
623 const QByteArray subTile = retrieveContent( contentUri, feedback );
624 if ( !subTile.isEmpty() )
631 const auto subTileJson = json::parse( subTile.toStdString() );
632 QMutexLocker locker( &mLock );
633 refineNodeFromJson( it.value(), QUrl( contentUri ), subTileJson );
634 mTileContentFormats.insert(
id, TileContentFormat::Json );
637 catch ( json::parse_error & )
639 QMutexLocker locker( &mLock );
640 mTileContentFormats.insert(
id, TileContentFormat::NotJson );
648 mTileContentFormats.insert(
id, TileContentFormat::NotJson );
653QByteArray QgsCesiumTiledSceneIndex::fetchContent(
const QString &uri,
QgsFeedback *feedback )
657 if ( uri.startsWith(
"http" ) )
659 QNetworkRequest networkRequest = QNetworkRequest( url );
661 networkRequest.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
662 networkRequest.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
664 mHeaders.updateNetworkRequest( networkRequest );
666 if ( QThread::currentThread() == QApplication::instance()->thread() )
670 networkRequest, mAuthCfg,
false, feedback );
690 return reply->data();
693 else if ( url.isLocalFile() && QFile::exists( url.toLocalFile() ) )
695 QFile file( url.toLocalFile() );
696 if ( file.open( QIODevice::ReadOnly ) )
698 return file.readAll();
709QgsCesiumTilesDataProviderSharedData::QgsCesiumTilesDataProviderSharedData()
717 mTileset = json::parse( tileset.toStdString() );
718 if ( !mTileset.contains(
"root" ) )
720 mError = QObject::tr(
"JSON is not a valid Cesium 3D Tiles source (does not contain \"root\" value)" );
724 mLayerMetadata.setType( QStringLiteral(
"dataset" ) );
726 if ( mTileset.contains(
"asset" ) )
728 const auto &asset = mTileset[
"asset" ];
729 if ( asset.contains(
"tilesetVersion" ) )
731 const QString tilesetVersion = QString::fromStdString( asset[
"tilesetVersion"].get<std::string>() );
732 mLayerMetadata.setIdentifier( tilesetVersion );
737 new QgsCesiumTiledSceneIndex(
748 const auto &root = mTileset[
"root" ];
760 const auto &rootBoundingVolume = root[
"boundingVolume" ];
763 if ( root.contains(
"transform" ) && !root[
"transform"].is_null() )
765 const auto &transformJson = root[
"transform"];
766 double *ptr = rootTransform.
data();
767 for (
int i = 0; i < 16; ++i )
768 ptr[i] = transformJson[i].get<double>();
771 if ( rootBoundingVolume.contains(
"region" ) )
774 if ( !rootRegion.
isNull() )
779 if ( !mIndex.rootTile().boundingVolume().box().isNull() )
786 mLayerMetadata.setCrs( mSceneCrs );
789 spatialExtent.
bounds = rootRegion;
792 else if ( rootBoundingVolume.contains(
"box" ) )
803 mLayerMetadata.setCrs( mSceneCrs );
806 mBoundingVolume.transform( rootTransform );
810 ct.setBallparkTransformsAreAppropriate(
true );
811 const QgsBox3D rootRegion = mBoundingVolume.bounds( ct );
813 if ( !mIndex.rootTile().boundingVolume().box().isNull() )
818 std::unique_ptr< QgsAbstractGeometry > extent2D( mBoundingVolume.as2DGeometry( ct ) );
819 mExtent = extent2D->boundingBox();
823 QgsDebugError( QStringLiteral(
"Caught transform exception when transforming boundingVolume" ) );
827 spatialExtent.
bounds = mBoundingVolume.bounds();
830 else if ( rootBoundingVolume.contains(
"sphere" ) )
841 mLayerMetadata.setCrs( mSceneCrs );
849 ct.setBallparkTransformsAreAppropriate(
true );
850 const QgsBox3D rootRegion = mBoundingVolume.bounds( ct );
852 if ( !mIndex.rootTile().boundingVolume().box().isNull() )
857 std::unique_ptr< QgsAbstractGeometry > extent2D( mBoundingVolume.as2DGeometry( ct ) );
858 mExtent = extent2D->boundingBox();
862 QgsDebugError( QStringLiteral(
"Caught transform exception when transforming boundingVolume" ) );
866 spatialExtent.
bounds = mBoundingVolume.bounds();
871 mError = QObject::tr(
"JSON is not a valid Cesium 3D Tiles source (unsupported boundingVolume format)" );
877 mLayerMetadata.setExtent( layerExtent );
887QgsCesiumTilesDataProvider::QgsCesiumTilesDataProvider(
const QString &uri,
const ProviderOptions &providerOptions, ReadFlags flags )
889 , mShared( std::make_shared< QgsCesiumTilesDataProviderSharedData >() )
899QgsCesiumTilesDataProvider::QgsCesiumTilesDataProvider(
const QgsCesiumTilesDataProvider &other )
901 , mIsValid( other.mIsValid )
902 , mAuthCfg( other.mAuthCfg )
903 , mHeaders( other.mHeaders )
906 mShared = other.mShared;
909Qgis::TiledSceneProviderCapabilities QgsCesiumTilesDataProvider::capabilities()
const
914QgsCesiumTilesDataProvider::~QgsCesiumTilesDataProvider() =
default;
916QgsCesiumTilesDataProvider *QgsCesiumTilesDataProvider::clone()
const
919 return new QgsCesiumTilesDataProvider( *
this );
922bool QgsCesiumTilesDataProvider::init()
927 const QString uri = dataSourceUri();
929 if ( uri.startsWith( QLatin1String(
"ion://" ) ) )
932 const QString assetId = QUrlQuery( url ).queryItemValue( QStringLiteral(
"assetId" ) );
933 const QString accessToken = QUrlQuery( url ).queryItemValue( QStringLiteral(
"accessToken" ) );
935 const QString CESIUM_ION_URL = QStringLiteral(
"https://api.cesium.com/" );
939 const QString assetInfoEndpoint = CESIUM_ION_URL + QStringLiteral(
"v1/assets/%1" ).arg( assetId );
940 QNetworkRequest request = QNetworkRequest( assetInfoEndpoint );
942 mHeaders.updateNetworkRequest( request );
943 if ( !accessToken.isEmpty() )
944 request.setRawHeader( "Authorization", QStringLiteral( "Bearer %1" ).arg( accessToken ).toLocal8Bit() );
947 if ( accessToken.isEmpty() )
948 networkRequest.setAuthCfg( mAuthCfg );
950 switch ( networkRequest.get( request ) )
963 const json assetInfoJson = json::parse( content.
content().toStdString() );
964 if ( assetInfoJson[
"type"] !=
"3DTILES" )
966 appendError(
QgsErrorMessage( tr(
"Only ion 3D Tiles content can be accessed, not %1" ).arg( QString::fromStdString( assetInfoJson[
"type"].get<std::string>() ) ) ) );
970 mShared->mLayerMetadata.setTitle( QString::fromStdString( assetInfoJson[
"name"].get<std::string>() ) );
971 mShared->mLayerMetadata.setAbstract( QString::fromStdString( assetInfoJson[
"description"].get<std::string>() ) );
972 const QString attribution = QString::fromStdString( assetInfoJson[
"attribution"].get<std::string>() );
973 if ( !attribution.isEmpty() )
974 mShared->mLayerMetadata.setRights( { attribution } );
976 mShared->mLayerMetadata.setDateTime(
Qgis::MetadataDateType::Created, QDateTime::fromString( QString::fromStdString( assetInfoJson[
"dateAdded"].get<std::string>() ), Qt::DateFormat::ISODate ) );
981 const QString tileAccessEndpoint = CESIUM_ION_URL + QStringLiteral(
"v1/assets/%1/endpoint" ).arg( assetId );
982 QNetworkRequest request = QNetworkRequest( tileAccessEndpoint );
984 mHeaders.updateNetworkRequest( request );
985 if ( !accessToken.isEmpty() )
986 request.setRawHeader( "Authorization", QStringLiteral( "Bearer %1" ).arg( accessToken ).toLocal8Bit() );
989 if ( accessToken.isEmpty() )
990 networkRequest.setAuthCfg( mAuthCfg );
992 switch ( networkRequest.get( request ) )
1005 const json tileAccessJson = json::parse( content.
content().toStdString() );
1007 if ( tileAccessJson.contains(
"url" ) )
1009 tileSetUri = QString::fromStdString( tileAccessJson[
"url"].get<std::string>() );
1011 else if ( tileAccessJson.contains(
"options" ) )
1013 const auto &optionsJson = tileAccessJson[
"options"];
1014 if ( optionsJson.contains(
"url" ) )
1016 tileSetUri = QString::fromStdString( optionsJson[
"url"].get<std::string>() );
1020 if ( tileAccessJson.contains(
"accessToken" ) )
1024 mHeaders.insert( QStringLiteral(
"Authorization" ),
1025 QStringLiteral(
"Bearer %1" ).arg( QString::fromStdString( tileAccessJson[
"accessToken"].get<std::string>() ) ) );
1034 tileSetUri = dsUri.
param( QStringLiteral(
"url" ) );
1037 if ( !tileSetUri.isEmpty() )
1039 const QUrl url( tileSetUri );
1041 QNetworkRequest request = QNetworkRequest( url );
1043 mHeaders.updateNetworkRequest( request );
1046 networkRequest.setAuthCfg( mAuthCfg );
1048 switch ( networkRequest.get( request ) )
1062 mShared->initialize( content.
content(), tileSetUri, transformContext(), mAuthCfg, mHeaders );
1069 const QFileInfo fi( dataSourceUri() );
1072 QFile file( dataSourceUri( ) );
1073 if ( file.open( QIODevice::ReadOnly | QIODevice::Text ) )
1075 const QByteArray raw = file.readAll();
1076 mShared->initialize( raw, QUrl::fromLocalFile( dataSourceUri() ), transformContext(), mAuthCfg, mHeaders );
1089 if ( !mShared->mIndex.isValid() )
1091 appendError( mShared->mError );
1102 return mShared->mLayerCrs;
1110 return mShared->mExtent;
1113bool QgsCesiumTilesDataProvider::isValid()
const
1120QString QgsCesiumTilesDataProvider::name()
const
1124 return PROVIDER_KEY;
1127QString QgsCesiumTilesDataProvider::description()
const
1131 return QObject::tr(
"Cesium 3D Tiles" );
1134QString QgsCesiumTilesDataProvider::htmlMetadata()
const
1141 if ( mShared->mTileset.contains(
"asset" ) )
1143 const auto &asset = mShared->mTileset[
"asset" ];
1144 if ( asset.contains(
"version" ) )
1146 const QString version = QString::fromStdString( asset[
"version"].get<std::string>() );
1147 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"3D Tiles Version" ) % QStringLiteral(
"</td><td>%1</a>" ).arg( version ) % QStringLiteral(
"</td></tr>\n" );
1150 if ( asset.contains(
"tilesetVersion" ) )
1152 const QString tilesetVersion = QString::fromStdString( asset[
"tilesetVersion"].get<std::string>() );
1153 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"Tileset Version" ) % QStringLiteral(
"</td><td>%1</a>" ).arg( tilesetVersion ) % QStringLiteral(
"</td></tr>\n" );
1156 if ( asset.contains(
"generator" ) )
1158 const QString generator = QString::fromStdString( asset[
"generator"].get<std::string>() );
1159 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"Tileset Generator" ) % QStringLiteral(
"</td><td>%1</a>" ).arg( generator ) % QStringLiteral(
"</td></tr>\n" );
1162 if ( mShared->mTileset.contains(
"extensionsRequired" ) )
1164 QStringList extensions;
1165 for (
const auto &item : mShared->mTileset[
"extensionsRequired"] )
1167 extensions << QString::fromStdString( item.get<std::string>() );
1169 if ( !extensions.isEmpty() )
1171 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" );
1174 if ( mShared->mTileset.contains(
"extensionsUsed" ) )
1176 QStringList extensions;
1177 for (
const auto &item : mShared->mTileset[
"extensionsUsed"] )
1179 extensions << QString::fromStdString( item.get<std::string>() );
1181 if ( !extensions.isEmpty() )
1183 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" );
1187 if ( !mShared->mZRange.isInfinite() )
1189 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" );
1202 return mShared->mLayerMetadata;
1212 return mShared->mSceneCrs ;
1223 return mShared ? mShared->mBoundingVolume : nullVolume;
1233 return mShared->mIndex;
1243 return mShared->mZRange;
1251QgsCesiumTilesProviderMetadata::QgsCesiumTilesProviderMetadata():
1256QIcon QgsCesiumTilesProviderMetadata::icon()
const
1261QgsCesiumTilesDataProvider *QgsCesiumTilesProviderMetadata::createProvider(
const QString &uri,
const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
1263 return new QgsCesiumTilesDataProvider( uri, options, flags );
1266QList<QgsProviderSublayerDetails> QgsCesiumTilesProviderMetadata::querySublayers(
const QString &uri, Qgis::SublayerQueryFlags,
QgsFeedback * )
const
1268 const QVariantMap parts = decodeUri( uri );
1269 if ( parts.value( QStringLiteral(
"file-name" ) ).toString().compare( QLatin1String(
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
1284int QgsCesiumTilesProviderMetadata::priorityForUri(
const QString &uri )
const
1286 const QVariantMap parts = decodeUri( uri );
1287 if ( parts.value( QStringLiteral(
"file-name" ) ).toString().compare( QLatin1String(
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
1293QList<Qgis::LayerType> QgsCesiumTilesProviderMetadata::validLayerTypesForUri(
const QString &uri )
const
1295 const QVariantMap parts = decodeUri( uri );
1296 if ( parts.value( QStringLiteral(
"file-name" ) ).toString().compare( QLatin1String(
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
1299 return QList< Qgis::LayerType>();
1302QVariantMap QgsCesiumTilesProviderMetadata::decodeUri(
const QString &uri )
const
1304 QVariantMap uriComponents;
1305 QUrl url = QUrl::fromUserInput( uri );
1306 uriComponents.insert( QStringLiteral(
"file-name" ), url.fileName() );
1307 uriComponents.insert( QStringLiteral(
"path" ), uri );
1308 return uriComponents;
1324 return QObject::tr(
"Cesium 3D Tiles" ) + QStringLiteral(
" (tileset.json TILESET.JSON)" );
1329QgsProviderMetadata::ProviderCapabilities QgsCesiumTilesProviderMetadata::providerCapabilities()
const
1331 return FileBasedUris;
1334QList<Qgis::LayerType> QgsCesiumTilesProviderMetadata::supportedLayerTypes()
const
1339QString QgsCesiumTilesProviderMetadata::encodeUri(
const QVariantMap &parts )
const
1341 const QString path = parts.value( QStringLiteral(
"path" ) ).toString();
1345QgsProviderMetadata::ProviderMetadataCapabilities QgsCesiumTilesProviderMetadata::capabilities()
const
1347 return ProviderMetadataCapability::LayerTypesForUri
1348 | ProviderMetadataCapability::PriorityForUri
1349 | 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.