19#include "moc_qgscesiumtilesdataprovider.cpp"
43#include <QNetworkRequest>
44#include <QJsonDocument>
47#include <QRegularExpression>
48#include <QRecursiveMutex>
50#include <QApplication>
51#include <nlohmann/json.hpp>
52#include <qstringliteral.h>
56#define PROVIDER_KEY QStringLiteral( "cesiumtiles" )
57#define PROVIDER_DESCRIPTION QStringLiteral( "Cesium 3D Tiles data provider" )
68static QString appendQueryFromBaseUrl(
const QString &contentUri,
const QUrl &baseUrl )
70 QUrlQuery contentQuery( QUrl( contentUri ).query() );
71 const QList<QPair<QString, QString>> baseUrlQueryItems = QUrlQuery( baseUrl.query() ).queryItems();
72 for (
const QPair<QString, QString> &kv : baseUrlQueryItems )
74 contentQuery.addQueryItem( kv.first, kv.second );
76 QUrl newContentUrl( contentUri );
77 newContentUrl.setQuery( contentQuery );
78 return newContentUrl.toString();
86 QgsCesiumTiledSceneIndex(
89 const QString &authCfg,
93 std::unique_ptr< QgsTiledSceneTile > tileFromJson(
const json &node,
const QUrl &baseUrl,
const QgsTiledSceneTile *parent,
Qgis::Axis gltfUpAxis );
95 void refineNodeFromJson(
QgsTiledSceneNode *node,
const QUrl &baseUrl,
const json &json );
99 long long parentTileId(
long long id ) const final;
100 QVector<
long long > childTileIds(
long long id ) const final;
102 Qgis::TileChildrenAvailability childAvailability(
long long id ) const final;
103 bool fetchHierarchy(
long long id,
QgsFeedback *feedback =
nullptr ) final;
107 QByteArray fetchContent( const QString &uri,
QgsFeedback *feedback =
nullptr ) final;
111 enum class TileContentFormat
117 mutable QRecursiveMutex mLock;
119 std::unique_ptr< QgsTiledSceneNode > mRootNode;
120 QMap< long long, QgsTiledSceneNode * > mNodeMap;
121 QMap< long long, TileContentFormat > mTileContentFormats;
124 long long mNextTileId = 0;
128class QgsCesiumTilesDataProviderSharedData
131 QgsCesiumTilesDataProviderSharedData();
132 void initialize(
const QString &tileset,
135 const QString &authCfg,
143 nlohmann::json mTileset;
150 QReadWriteLock mReadWriteLock;
161 const std::string gltfUpAxisString = json.get<std::string>();
162 if ( gltfUpAxisString ==
"z" || gltfUpAxisString ==
"Z" )
166 else if ( gltfUpAxisString ==
"y" || gltfUpAxisString ==
"Y" )
170 else if ( gltfUpAxisString ==
"x" || gltfUpAxisString ==
"X" )
174 QgsDebugError( QStringLiteral(
"Unsupported gltfUpAxis value: %1" ).arg( QString::fromStdString( gltfUpAxisString ) ) );
179 : mTransformContext( transformContext )
180 , mAuthCfg( authCfg )
181 , mHeaders( headers )
184 if ( tileset.contains(
"asset" ) )
186 const auto &assetJson = tileset[
"asset"];
187 if ( assetJson.contains(
"gltfUpAxis" ) )
189 gltfUpAxis = axisFromJson( assetJson[
"gltfUpAxis"] );
193 mRootNode.reset( nodeFromJson( tileset[
"root" ], rootUrl,
nullptr, gltfUpAxis ) );
196std::unique_ptr< QgsTiledSceneTile > QgsCesiumTiledSceneIndex::tileFromJson(
const json &json,
const QUrl &baseUrl,
const QgsTiledSceneTile *parent,
Qgis::Axis gltfUpAxis )
198 std::unique_ptr< QgsTiledSceneTile > tile = std::make_unique< QgsTiledSceneTile >( mNextTileId++ );
200 tile->setBaseUrl( baseUrl );
203 { QStringLiteral(
"gltfUpAxis" ),
static_cast< int >( gltfUpAxis ) },
204 { QStringLiteral(
"contentFormat" ), QStringLiteral(
"cesiumtiles" ) },
208 if ( json.contains(
"transform" ) && !json[
"transform"].is_null() )
210 const auto &transformJson = json[
"transform"];
211 double *ptr = transform.
data();
212 for (
int i = 0; i < 16; ++i )
213 ptr[i] = transformJson[i].get<double>();
217 transform = *parent->
transform() * transform;
220 else if ( parent && parent->
transform() )
225 tile->setTransform( transform );
227 const auto &boundingVolume = json[
"boundingVolume" ];
229 if ( boundingVolume.contains(
"region" ) )
232 if ( !rootRegion.
isNull() )
234 if ( rootRegion.
width() > 20 || rootRegion.
height() > 20 )
241 QVector< QgsVector3D > corners = rootRegion.
corners();
249 for (
int i = 0; i < 8; ++i )
252 x.append( corner.
x() );
253 y.append( corner.
y() );
254 z.append( corner.
z() );
257 ct.setBallparkTransformsAreAppropriate(
true );
260 ct.transformInPlace( x, y, z );
264 QgsDebugError( QStringLiteral(
"Cannot transform region bounding volume" ) );
267 const auto minMaxX = std::minmax_element( x.constBegin(), x.constEnd() );
268 const auto minMaxY = std::minmax_element( y.constBegin(), y.constEnd() );
269 const auto minMaxZ = std::minmax_element( z.constBegin(), z.constEnd() );
276 else if ( boundingVolume.contains(
"box" ) )
286 else if ( boundingVolume.contains(
"sphere" ) )
297 QgsDebugError( QStringLiteral(
"unsupported boundingVolume format" ) );
300 tile->setBoundingVolume( volume );
302 if ( json.contains(
"geometricError" ) )
303 tile->setGeometricError( json[
"geometricError"].get< double >() );
304 if ( json.contains(
"refine" ) )
306 if ( json[
"refine"] ==
"ADD" )
308 else if ( json[
"refine"] ==
"REPLACE" )
317 if ( json.contains(
"content" ) && !json[
"content"].is_null() )
319 const auto &contentJson = json[
"content"];
323 if ( contentJson.contains(
"uri" ) && !contentJson[
"uri"].is_null() )
325 QString relativeUri = QString::fromStdString( contentJson[
"uri"].get<std::string>() );
326 contentUri = baseUrl.resolved( QUrl( relativeUri ) ).toString();
328 if ( baseUrl.hasQuery() && QUrl( relativeUri ).isRelative() )
329 contentUri = appendQueryFromBaseUrl( contentUri, baseUrl );
331 else if ( contentJson.contains(
"url" ) && !contentJson[
"url"].is_null() )
333 QString relativeUri = QString::fromStdString( contentJson[
"url"].get<std::string>() );
334 contentUri = baseUrl.resolved( QUrl( relativeUri ) ).toString();
336 if ( baseUrl.hasQuery() && QUrl( relativeUri ).isRelative() )
337 contentUri = appendQueryFromBaseUrl( contentUri, baseUrl );
339 if ( !contentUri.isEmpty() )
341 tile->setResources( {{ QStringLiteral(
"content" ), contentUri } } );
350 std::unique_ptr< QgsTiledSceneTile > tile = tileFromJson( json, baseUrl, parent ? parent->
tile() : nullptr, gltfUpAxis );
351 std::unique_ptr< QgsTiledSceneNode > newNode = std::make_unique< QgsTiledSceneNode >( tile.release() );
352 mNodeMap.insert( newNode->tile()->id(), newNode.get() );
357 if ( json.contains(
"children" ) )
359 for (
const auto &childJson : json[
"children"] )
361 nodeFromJson( childJson, baseUrl, newNode.get(), gltfUpAxis );
365 return newNode.release();
368void QgsCesiumTiledSceneIndex::refineNodeFromJson(
QgsTiledSceneNode *node,
const QUrl &baseUrl,
const json &json )
370 const auto &rootTileJson = json[
"root"];
373 if ( json.contains(
"asset" ) )
375 const auto &assetJson = json[
"asset"];
376 if ( assetJson.contains(
"gltfUpAxis" ) )
378 gltfUpAxis = axisFromJson( assetJson[
"gltfUpAxis"] );
382 std::unique_ptr< QgsTiledSceneTile > newTile = tileFromJson( rootTileJson, baseUrl, node->
tile(), gltfUpAxis );
392 if ( newTile->transform() )
395 if ( rootTileJson.contains(
"children" ) )
397 for (
const auto &childJson : rootTileJson[
"children"] )
399 nodeFromJson( childJson, baseUrl, node, gltfUpAxis );
406 QMutexLocker locker( &mLock );
412 QMutexLocker locker( &mLock );
413 auto it = mNodeMap.constFind(
id );
414 if ( it != mNodeMap.constEnd() )
416 return *( it.value()->tile() );
422long long QgsCesiumTiledSceneIndex::parentTileId(
long long id )
const
424 QMutexLocker locker( &mLock );
425 auto it = mNodeMap.constFind(
id );
426 if ( it != mNodeMap.constEnd() )
430 return parent->
tile()->
id();
437QVector< long long > QgsCesiumTiledSceneIndex::childTileIds(
long long id )
const
439 QMutexLocker locker( &mLock );
440 auto it = mNodeMap.constFind(
id );
441 if ( it != mNodeMap.constEnd() )
443 QVector< long long > childIds;
444 const QList< QgsTiledSceneNode * > children = it.value()->children();
445 childIds.reserve( children.size() );
448 childIds << child->tile()->id();
458 QVector< long long > results;
461 traverseNode = [&request, &traverseNode, &results,
this](
QgsTiledSceneNode * node )
477 QList< QgsTiledSceneNode * > children = node->
children();
478 if ( children.empty() )
480 switch ( childAvailability( tile->
id() ) )
490 if ( fetchHierarchy( tile->
id() ), request.
feedback() )
505 traverseNode( child );
512 results << tile->
id();
517 if ( children.empty() )
518 results << tile->
id();
524 results << tile->
id();
529 QMutexLocker locker( &mLock );
533 traverseNode( mRootNode.get() );
538 if ( it != mNodeMap.constEnd() )
540 traverseNode( it.value() );
550 QMutexLocker locker( &mLock );
552 auto it = mNodeMap.constFind(
id );
553 if ( it == mNodeMap.constEnd() )
556 if ( !it.value()->children().isEmpty() )
559 contentUri = it.value()->tile()->resources().value( QStringLiteral(
"content" ) ).toString();
563 auto it = mTileContentFormats.constFind(
id );
564 if ( it != mTileContentFormats.constEnd() )
566 switch ( it.value() )
568 case TileContentFormat::NotJson:
570 case TileContentFormat::Json:
577 if ( contentUri.isEmpty() )
587 const thread_local QRegularExpression isJsonRx( QStringLiteral(
".*\\.json(?:\\?.*)?$" ), QRegularExpression::PatternOption::CaseInsensitiveOption );
588 if ( isJsonRx.match( contentUri ).hasMatch() )
592 const thread_local QRegularExpression antiCandidateRx( QStringLiteral(
".*\\.(gltf|glb|b3dm|i3dm|pnts|cmpt|bin|glbin|glbuf|png|jpeg|jpg)(?:\\?.*)?$" ), QRegularExpression::PatternOption::CaseInsensitiveOption );
593 if ( antiCandidateRx.match( contentUri ).hasMatch() )
601bool QgsCesiumTiledSceneIndex::fetchHierarchy(
long long id,
QgsFeedback *feedback )
603 QMutexLocker locker( &mLock );
604 auto it = mNodeMap.constFind(
id );
605 if ( it == mNodeMap.constEnd() )
611 auto it = mTileContentFormats.constFind(
id );
612 if ( it != mTileContentFormats.constEnd() )
614 switch ( it.value() )
616 case TileContentFormat::NotJson:
618 case TileContentFormat::Json:
624 const QString contentUri = it.value()->tile()->resources().value( QStringLiteral(
"content" ) ).toString();
627 if ( contentUri.isEmpty() )
631 const QByteArray subTile = retrieveContent( contentUri, feedback );
632 if ( !subTile.isEmpty() )
639 const auto subTileJson = json::parse( subTile.toStdString() );
640 QMutexLocker locker( &mLock );
641 refineNodeFromJson( it.value(), QUrl( contentUri ), subTileJson );
642 mTileContentFormats.insert(
id, TileContentFormat::Json );
645 catch ( json::parse_error & )
647 QMutexLocker locker( &mLock );
648 mTileContentFormats.insert(
id, TileContentFormat::NotJson );
656 mTileContentFormats.insert(
id, TileContentFormat::NotJson );
661QByteArray QgsCesiumTiledSceneIndex::fetchContent(
const QString &uri,
QgsFeedback *feedback )
665 if ( uri.startsWith(
"http" ) )
667 QNetworkRequest networkRequest = QNetworkRequest( url );
669 networkRequest.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
670 networkRequest.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
672 mHeaders.updateNetworkRequest( networkRequest );
674 if ( QThread::currentThread() == QApplication::instance()->thread() )
678 networkRequest, mAuthCfg,
false, feedback );
698 return reply->data();
701 else if ( url.isLocalFile() && QFile::exists( url.toLocalFile() ) )
703 QFile file( url.toLocalFile() );
704 if ( file.open( QIODevice::ReadOnly ) )
706 return file.readAll();
717QgsCesiumTilesDataProviderSharedData::QgsCesiumTilesDataProviderSharedData()
725 mTileset = json::parse( tileset.toStdString() );
726 if ( !mTileset.contains(
"root" ) )
728 mError = QObject::tr(
"JSON is not a valid Cesium 3D Tiles source (does not contain \"root\" value)" );
732 mLayerMetadata.setType( QStringLiteral(
"dataset" ) );
734 if ( mTileset.contains(
"asset" ) )
736 const auto &asset = mTileset[
"asset" ];
737 if ( asset.contains(
"tilesetVersion" ) )
741 const QString tilesetVersion = QString::fromStdString( asset[
"tilesetVersion"].get<std::string>() );
742 mLayerMetadata.setIdentifier( tilesetVersion );
744 catch ( json::type_error & )
746 QgsDebugError( QStringLiteral(
"Error when parsing tilesetVersion value" ) );
752 new QgsCesiumTiledSceneIndex(
763 const auto &root = mTileset[
"root" ];
775 const auto &rootBoundingVolume = root[
"boundingVolume" ];
778 if ( root.contains(
"transform" ) && !root[
"transform"].is_null() )
780 const auto &transformJson = root[
"transform"];
781 double *ptr = rootTransform.
data();
782 for (
int i = 0; i < 16; ++i )
783 ptr[i] = transformJson[i].get<double>();
786 if ( rootBoundingVolume.contains(
"region" ) )
789 if ( !rootRegion.
isNull() )
794 if ( !mIndex.rootTile().boundingVolume().box().isNull() )
801 mLayerMetadata.setCrs( mSceneCrs );
804 spatialExtent.
bounds = rootRegion;
807 else if ( rootBoundingVolume.contains(
"box" ) )
818 mLayerMetadata.setCrs( mSceneCrs );
821 mBoundingVolume.transform( rootTransform );
825 ct.setBallparkTransformsAreAppropriate(
true );
826 const QgsBox3D rootRegion = mBoundingVolume.bounds( ct );
828 if ( !mIndex.rootTile().boundingVolume().box().isNull() )
833 std::unique_ptr< QgsAbstractGeometry > extent2D( mBoundingVolume.as2DGeometry( ct ) );
834 mExtent = extent2D->boundingBox();
838 QgsDebugError( QStringLiteral(
"Caught transform exception when transforming boundingVolume" ) );
842 spatialExtent.
bounds = mBoundingVolume.bounds();
845 else if ( rootBoundingVolume.contains(
"sphere" ) )
856 mLayerMetadata.setCrs( mSceneCrs );
864 ct.setBallparkTransformsAreAppropriate(
true );
865 const QgsBox3D rootRegion = mBoundingVolume.bounds( ct );
867 if ( !mIndex.rootTile().boundingVolume().box().isNull() )
872 std::unique_ptr< QgsAbstractGeometry > extent2D( mBoundingVolume.as2DGeometry( ct ) );
873 mExtent = extent2D->boundingBox();
877 QgsDebugError( QStringLiteral(
"Caught transform exception when transforming boundingVolume" ) );
881 spatialExtent.
bounds = mBoundingVolume.bounds();
886 mError = QObject::tr(
"JSON is not a valid Cesium 3D Tiles source (unsupported boundingVolume format)" );
892 mLayerMetadata.setExtent( layerExtent );
902QgsCesiumTilesDataProvider::QgsCesiumTilesDataProvider(
const QString &uri,
const ProviderOptions &providerOptions,
Qgis::DataProviderReadFlags flags )
904 , mShared( std::make_shared< QgsCesiumTilesDataProviderSharedData >() )
914QgsCesiumTilesDataProvider::QgsCesiumTilesDataProvider(
const QgsCesiumTilesDataProvider &other )
916 , mIsValid( other.mIsValid )
917 , mAuthCfg( other.mAuthCfg )
918 , mHeaders( other.mHeaders )
921 mShared = other.mShared;
934QgsCesiumTilesDataProvider::~QgsCesiumTilesDataProvider() =
default;
936QgsCesiumTilesDataProvider *QgsCesiumTilesDataProvider::clone()
const
939 return new QgsCesiumTilesDataProvider( *
this );
942bool QgsCesiumTilesDataProvider::init()
947 const QString uri = dataSourceUri();
949 if ( uri.startsWith( QLatin1String(
"ion://" ) ) )
952 const QString assetId = QUrlQuery( url ).queryItemValue( QStringLiteral(
"assetId" ) );
953 const QString accessToken = QUrlQuery( url ).queryItemValue( QStringLiteral(
"accessToken" ) );
955 const QString CESIUM_ION_URL = QStringLiteral(
"https://api.cesium.com/" );
959 const QString assetInfoEndpoint = CESIUM_ION_URL + QStringLiteral(
"v1/assets/%1" ).arg( assetId );
960 QNetworkRequest request = QNetworkRequest( assetInfoEndpoint );
962 mHeaders.updateNetworkRequest( request );
963 if ( !accessToken.isEmpty() )
964 request.setRawHeader( "Authorization", QStringLiteral( "Bearer %1" ).arg( accessToken ).toLocal8Bit() );
967 if ( accessToken.isEmpty() )
968 networkRequest.setAuthCfg( mAuthCfg );
970 switch ( networkRequest.get( request ) )
983 const json assetInfoJson = json::parse( content.
content().toStdString() );
984 if ( assetInfoJson[
"type"] !=
"3DTILES" )
986 appendError(
QgsErrorMessage( tr(
"Only ion 3D Tiles content can be accessed, not %1" ).arg( QString::fromStdString( assetInfoJson[
"type"].get<std::string>() ) ) ) );
990 mShared->mLayerMetadata.setTitle( QString::fromStdString( assetInfoJson[
"name"].get<std::string>() ) );
991 mShared->mLayerMetadata.setAbstract( QString::fromStdString( assetInfoJson[
"description"].get<std::string>() ) );
992 const QString attribution = QString::fromStdString( assetInfoJson[
"attribution"].get<std::string>() );
993 if ( !attribution.isEmpty() )
994 mShared->mLayerMetadata.setRights( { attribution } );
996 mShared->mLayerMetadata.setDateTime(
Qgis::MetadataDateType::Created, QDateTime::fromString( QString::fromStdString( assetInfoJson[
"dateAdded"].get<std::string>() ), Qt::DateFormat::ISODate ) );
1001 const QString tileAccessEndpoint = CESIUM_ION_URL + QStringLiteral(
"v1/assets/%1/endpoint" ).arg( assetId );
1002 QNetworkRequest request = QNetworkRequest( tileAccessEndpoint );
1004 mHeaders.updateNetworkRequest( request );
1005 if ( !accessToken.isEmpty() )
1006 request.setRawHeader( "Authorization", QStringLiteral( "Bearer %1" ).arg( accessToken ).toLocal8Bit() );
1009 if ( accessToken.isEmpty() )
1010 networkRequest.setAuthCfg( mAuthCfg );
1012 switch ( networkRequest.get( request ) )
1025 const json tileAccessJson = json::parse( content.
content().toStdString() );
1027 if ( tileAccessJson.contains(
"url" ) )
1029 tileSetUri = QString::fromStdString( tileAccessJson[
"url"].get<std::string>() );
1031 else if ( tileAccessJson.contains(
"options" ) )
1033 const auto &optionsJson = tileAccessJson[
"options"];
1034 if ( optionsJson.contains(
"url" ) )
1036 tileSetUri = QString::fromStdString( optionsJson[
"url"].get<std::string>() );
1040 if ( tileAccessJson.contains(
"accessToken" ) )
1044 mHeaders.insert( QStringLiteral(
"Authorization" ),
1045 QStringLiteral(
"Bearer %1" ).arg( QString::fromStdString( tileAccessJson[
"accessToken"].get<std::string>() ) ) );
1054 tileSetUri = dsUri.
param( QStringLiteral(
"url" ) );
1057 if ( !tileSetUri.isEmpty() )
1059 const QUrl url( tileSetUri );
1061 QNetworkRequest request = QNetworkRequest( url );
1063 mHeaders.updateNetworkRequest( request );
1066 networkRequest.setAuthCfg( mAuthCfg );
1068 switch ( networkRequest.get( request ) )
1082 mShared->initialize( content.
content(), tileSetUri, transformContext(), mAuthCfg, mHeaders );
1089 const QFileInfo fi( dataSourceUri() );
1092 QFile file( dataSourceUri( ) );
1093 if ( file.open( QIODevice::ReadOnly | QIODevice::Text ) )
1095 const QByteArray raw = file.readAll();
1096 mShared->initialize( raw, QUrl::fromLocalFile( dataSourceUri() ), transformContext(), mAuthCfg, mHeaders );
1109 if ( !mShared->mIndex.isValid() )
1111 appendError( mShared->mError );
1122 return mShared->mLayerCrs;
1130 return mShared->mExtent;
1133bool QgsCesiumTilesDataProvider::isValid()
const
1140QString QgsCesiumTilesDataProvider::name()
const
1144 return PROVIDER_KEY;
1147QString QgsCesiumTilesDataProvider::description()
const
1151 return QObject::tr(
"Cesium 3D Tiles" );
1154QString QgsCesiumTilesDataProvider::htmlMetadata()
const
1161 if ( mShared->mTileset.contains(
"asset" ) )
1163 const auto &asset = mShared->mTileset[
"asset" ];
1164 if ( asset.contains(
"version" ) )
1166 const QString version = QString::fromStdString( asset[
"version"].get<std::string>() );
1167 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"3D Tiles Version" ) % QStringLiteral(
"</td><td>%1</a>" ).arg( version ) % QStringLiteral(
"</td></tr>\n" );
1170 if ( asset.contains(
"tilesetVersion" ) )
1174 const QString tilesetVersion = QString::fromStdString( asset[
"tilesetVersion"].get<std::string>() );
1175 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"Tileset Version" ) % QStringLiteral(
"</td><td>%1</a>" ).arg( tilesetVersion ) % QStringLiteral(
"</td></tr>\n" );
1177 catch ( json::type_error & )
1179 QgsDebugError( QStringLiteral(
"Error when parsing tilesetVersion value" ) );
1183 if ( asset.contains(
"generator" ) )
1185 const QString generator = QString::fromStdString( asset[
"generator"].get<std::string>() );
1186 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"Tileset Generator" ) % QStringLiteral(
"</td><td>%1</a>" ).arg( generator ) % QStringLiteral(
"</td></tr>\n" );
1189 if ( mShared->mTileset.contains(
"extensionsRequired" ) )
1191 QStringList extensions;
1192 for (
const auto &item : mShared->mTileset[
"extensionsRequired"] )
1194 extensions << QString::fromStdString( item.get<std::string>() );
1196 if ( !extensions.isEmpty() )
1198 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" );
1201 if ( mShared->mTileset.contains(
"extensionsUsed" ) )
1203 QStringList extensions;
1204 for (
const auto &item : mShared->mTileset[
"extensionsUsed"] )
1206 extensions << QString::fromStdString( item.get<std::string>() );
1208 if ( !extensions.isEmpty() )
1210 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" );
1214 if ( !mShared->mZRange.isInfinite() )
1216 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" );
1229 return mShared->mLayerMetadata;
1239 return mShared->mSceneCrs ;
1250 return mShared ? mShared->mBoundingVolume : nullVolume;
1260 return mShared->mIndex;
1270 return mShared->mZRange;
1278QgsCesiumTilesProviderMetadata::QgsCesiumTilesProviderMetadata():
1283QIcon QgsCesiumTilesProviderMetadata::icon()
const
1290 return new QgsCesiumTilesDataProvider( uri, options, flags );
1295 const QVariantMap parts = decodeUri( uri );
1296 if ( parts.value( QStringLiteral(
"file-name" ) ).toString().compare( QLatin1String(
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
1311int QgsCesiumTilesProviderMetadata::priorityForUri(
const QString &uri )
const
1313 const QVariantMap parts = decodeUri( uri );
1314 if ( parts.value( QStringLiteral(
"file-name" ) ).toString().compare( QLatin1String(
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
1320QList<Qgis::LayerType> QgsCesiumTilesProviderMetadata::validLayerTypesForUri(
const QString &uri )
const
1322 const QVariantMap parts = decodeUri( uri );
1323 if ( parts.value( QStringLiteral(
"file-name" ) ).toString().compare( QLatin1String(
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
1326 return QList< Qgis::LayerType>();
1329QVariantMap QgsCesiumTilesProviderMetadata::decodeUri(
const QString &uri )
const
1331 QVariantMap uriComponents;
1332 QUrl url = QUrl::fromUserInput( uri );
1333 uriComponents.insert( QStringLiteral(
"file-name" ), url.fileName() );
1334 uriComponents.insert( QStringLiteral(
"path" ), uri );
1335 return uriComponents;
1351 return QObject::tr(
"Cesium 3D Tiles" ) + QStringLiteral(
" (tileset.json TILESET.JSON)" );
1358 return FileBasedUris;
1361QList<Qgis::LayerType> QgsCesiumTilesProviderMetadata::supportedLayerTypes()
const
1366QString QgsCesiumTilesProviderMetadata::encodeUri(
const QVariantMap &parts )
const
1368 const QString path = parts.value( QStringLiteral(
"path" ) ).toString();
1374 return ProviderMetadataCapability::LayerTypesForUri
1375 | ProviderMetadataCapability::PriorityForUri
1376 | ProviderMetadataCapability::QuerySublayers;
The Qgis class provides global constants for use throughout the application.
QFlags< TiledSceneProviderCapability > TiledSceneProviderCapabilities
Tiled scene data provider capabilities.
QFlags< DataProviderFlag > DataProviderFlags
Data provider flags.
FileFilterType
Type of file filters.
@ TiledScene
Tiled scene layers.
@ VectorTile
Vector tile layers.
@ MeshDataset
Mesh datasets.
@ PointCloud
Point clouds.
@ 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.
@ ReadLayerMetadata
Provider can read layer metadata from data store. See QgsDataProvider::layerMetadata()
QFlags< SublayerQueryFlag > SublayerQueryFlags
Sublayer query flags.
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 meters.
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 meters, of the tile's simplified represent...
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.