42#include <QNetworkRequest>
43#include <QJsonDocument>
46#include <QRegularExpression>
47#include <QRecursiveMutex>
49#include <QApplication>
50#include <nlohmann/json.hpp>
54#define PROVIDER_KEY QStringLiteral( "cesiumtiles" )
55#define PROVIDER_DESCRIPTION QStringLiteral( "Cesium 3D Tiles data provider" )
66static QString appendQueryFromBaseUrl(
const QString &contentUri,
const QUrl &baseUrl )
68 QUrlQuery contentQuery( QUrl( contentUri ).query() );
69 const QList<QPair<QString, QString>> baseUrlQueryItems = QUrlQuery( baseUrl.query() ).queryItems();
70 for (
const QPair<QString, QString> &kv : baseUrlQueryItems )
72 contentQuery.addQueryItem( kv.first, kv.second );
74 QUrl newContentUrl( contentUri );
75 newContentUrl.setQuery( contentQuery );
76 return newContentUrl.toString();
84 QgsCesiumTiledSceneIndex(
87 const QString &authCfg,
91 std::unique_ptr< QgsTiledSceneTile > tileFromJson(
const json &node,
const QUrl &baseUrl,
const QgsTiledSceneTile *parent,
Qgis::Axis gltfUpAxis );
93 void refineNodeFromJson(
QgsTiledSceneNode *node,
const QUrl &baseUrl,
const json &json );
97 long long parentTileId(
long long id ) const final;
98 QVector<
long long > childTileIds(
long long id ) const final;
100 Qgis::TileChildrenAvailability childAvailability(
long long id ) const final;
101 bool fetchHierarchy(
long long id,
QgsFeedback *feedback =
nullptr ) final;
105 QByteArray fetchContent( const QString &uri,
QgsFeedback *feedback =
nullptr ) final;
109 enum class TileContentFormat
115 mutable QRecursiveMutex mLock;
117 std::unique_ptr< QgsTiledSceneNode > mRootNode;
118 QMap< long long, QgsTiledSceneNode * > mNodeMap;
119 QMap< long long, TileContentFormat > mTileContentFormats;
122 long long mNextTileId = 0;
126class QgsCesiumTilesDataProviderSharedData
129 QgsCesiumTilesDataProviderSharedData();
130 void initialize(
const QString &tileset,
133 const QString &authCfg,
141 nlohmann::json mTileset;
148 QReadWriteLock mReadWriteLock;
159 const std::string gltfUpAxisString = json.get<std::string>();
160 if ( gltfUpAxisString ==
"z" || gltfUpAxisString ==
"Z" )
164 else if ( gltfUpAxisString ==
"y" || gltfUpAxisString ==
"Y" )
168 else if ( gltfUpAxisString ==
"x" || gltfUpAxisString ==
"X" )
172 QgsDebugError( QStringLiteral(
"Unsupported gltfUpAxis value: %1" ).arg( QString::fromStdString( gltfUpAxisString ) ) );
177 : mTransformContext( transformContext )
178 , mAuthCfg( authCfg )
179 , mHeaders( headers )
182 if ( tileset.contains(
"asset" ) )
184 const auto &assetJson = tileset[
"asset"];
185 if ( assetJson.contains(
"gltfUpAxis" ) )
187 gltfUpAxis = axisFromJson( assetJson[
"gltfUpAxis"] );
191 mRootNode.reset( nodeFromJson( tileset[
"root" ], rootUrl,
nullptr, gltfUpAxis ) );
194std::unique_ptr< QgsTiledSceneTile > QgsCesiumTiledSceneIndex::tileFromJson(
const json &json,
const QUrl &baseUrl,
const QgsTiledSceneTile *parent,
Qgis::Axis gltfUpAxis )
196 std::unique_ptr< QgsTiledSceneTile > tile = std::make_unique< QgsTiledSceneTile >( mNextTileId++ );
198 tile->setBaseUrl( baseUrl );
199 tile->setMetadata( {{ QStringLiteral(
"gltfUpAxis" ),
static_cast< int >( gltfUpAxis ) }} );
202 if ( json.contains(
"transform" ) && !json[
"transform"].is_null() )
204 const auto &transformJson = json[
"transform"];
205 double *ptr = transform.
data();
206 for (
int i = 0; i < 16; ++i )
207 ptr[i] = transformJson[i].get<double>();
211 transform = *parent->
transform() * transform;
214 else if ( parent && parent->
transform() )
219 tile->setTransform( transform );
221 const auto &boundingVolume = json[
"boundingVolume" ];
223 if ( boundingVolume.contains(
"region" ) )
226 if ( !rootRegion.
isNull() )
228 if ( rootRegion.
width() > 20 || rootRegion.
height() > 20 )
235 QVector< QgsVector3D > corners = rootRegion.
corners();
243 for (
int i = 0; i < 8; ++i )
246 x.append( corner.
x() );
247 y.append( corner.
y() );
248 z.append( corner.
z() );
251 ct.setBallparkTransformsAreAppropriate(
true );
254 ct.transformInPlace( x, y, z );
258 QgsDebugError( QStringLiteral(
"Cannot transform region bounding volume" ) );
261 const auto minMaxX = std::minmax_element( x.constBegin(), x.constEnd() );
262 const auto minMaxY = std::minmax_element( y.constBegin(), y.constEnd() );
263 const auto minMaxZ = std::minmax_element( z.constBegin(), z.constEnd() );
270 else if ( boundingVolume.contains(
"box" ) )
280 else if ( boundingVolume.contains(
"sphere" ) )
291 QgsDebugError( QStringLiteral(
"unsupported boundingVolume format" ) );
294 tile->setBoundingVolume( volume );
296 if ( json.contains(
"geometricError" ) )
297 tile->setGeometricError( json[
"geometricError"].get< double >() );
298 if ( json.contains(
"refine" ) )
300 if ( json[
"refine"] ==
"ADD" )
302 else if ( json[
"refine"] ==
"REPLACE" )
311 if ( json.contains(
"content" ) && !json[
"content"].is_null() )
313 const auto &contentJson = json[
"content"];
317 if ( contentJson.contains(
"uri" ) && !contentJson[
"uri"].is_null() )
319 QString relativeUri = QString::fromStdString( contentJson[
"uri"].get<std::string>() );
320 contentUri = baseUrl.resolved( QUrl( relativeUri ) ).toString();
322 if ( baseUrl.hasQuery() && QUrl( relativeUri ).isRelative() )
323 contentUri = appendQueryFromBaseUrl( contentUri, baseUrl );
325 else if ( contentJson.contains(
"url" ) && !contentJson[
"url"].is_null() )
327 QString relativeUri = QString::fromStdString( contentJson[
"url"].get<std::string>() );
328 contentUri = baseUrl.resolved( QUrl( relativeUri ) ).toString();
330 if ( baseUrl.hasQuery() && QUrl( relativeUri ).isRelative() )
331 contentUri = appendQueryFromBaseUrl( contentUri, baseUrl );
333 if ( !contentUri.isEmpty() )
335 tile->setResources( {{ QStringLiteral(
"content" ), contentUri } } );
344 std::unique_ptr< QgsTiledSceneTile > tile = tileFromJson( json, baseUrl, parent ? parent->
tile() :
nullptr, gltfUpAxis );
345 std::unique_ptr< QgsTiledSceneNode > newNode = std::make_unique< QgsTiledSceneNode >( tile.release() );
346 mNodeMap.insert( newNode->tile()->id(), newNode.get() );
351 if ( json.contains(
"children" ) )
353 for (
const auto &childJson : json[
"children"] )
355 nodeFromJson( childJson, baseUrl, newNode.get(), gltfUpAxis );
359 return newNode.release();
362void QgsCesiumTiledSceneIndex::refineNodeFromJson(
QgsTiledSceneNode *node,
const QUrl &baseUrl,
const json &json )
364 const auto &rootTileJson = json[
"root"];
367 if ( json.contains(
"asset" ) )
369 const auto &assetJson = json[
"asset"];
370 if ( assetJson.contains(
"gltfUpAxis" ) )
372 gltfUpAxis = axisFromJson( assetJson[
"gltfUpAxis"] );
376 std::unique_ptr< QgsTiledSceneTile > newTile = tileFromJson( rootTileJson, baseUrl, node->
tile(), gltfUpAxis );
386 if ( newTile->transform() )
389 if ( rootTileJson.contains(
"children" ) )
391 for (
const auto &childJson : rootTileJson[
"children"] )
393 nodeFromJson( childJson, baseUrl, node, gltfUpAxis );
400 QMutexLocker locker( &mLock );
406 QMutexLocker locker( &mLock );
407 auto it = mNodeMap.constFind(
id );
408 if ( it != mNodeMap.constEnd() )
410 return *( it.value()->tile() );
416long long QgsCesiumTiledSceneIndex::parentTileId(
long long id )
const
418 QMutexLocker locker( &mLock );
419 auto it = mNodeMap.constFind(
id );
420 if ( it != mNodeMap.constEnd() )
424 return parent->
tile()->
id();
431QVector< long long > QgsCesiumTiledSceneIndex::childTileIds(
long long id )
const
433 QMutexLocker locker( &mLock );
434 auto it = mNodeMap.constFind(
id );
435 if ( it != mNodeMap.constEnd() )
437 QVector< long long > childIds;
438 const QList< QgsTiledSceneNode * > children = it.value()->children();
439 childIds.reserve( children.size() );
442 childIds << child->tile()->id();
452 QVector< long long > results;
455 traverseNode = [&request, &traverseNode, &results,
this](
QgsTiledSceneNode * node )
471 QList< QgsTiledSceneNode * > children = node->
children();
472 if ( children.empty() )
474 switch ( childAvailability( tile->
id() ) )
484 if ( fetchHierarchy( tile->
id() ), request.
feedback() )
499 traverseNode( child );
506 results << tile->
id();
511 if ( children.empty() )
512 results << tile->
id();
518 results << tile->
id();
523 QMutexLocker locker( &mLock );
527 traverseNode( mRootNode.get() );
532 if ( it != mNodeMap.constEnd() )
534 traverseNode( it.value() );
544 QMutexLocker locker( &mLock );
546 auto it = mNodeMap.constFind(
id );
547 if ( it == mNodeMap.constEnd() )
550 if ( !it.value()->children().isEmpty() )
553 contentUri = it.value()->tile()->resources().value( QStringLiteral(
"content" ) ).toString();
557 auto it = mTileContentFormats.constFind(
id );
558 if ( it != mTileContentFormats.constEnd() )
560 switch ( it.value() )
562 case TileContentFormat::NotJson:
564 case TileContentFormat::Json:
571 if ( contentUri.isEmpty() )
581 const thread_local QRegularExpression isJsonRx( QStringLiteral(
".*\\.json(?:\\?.*)?$" ), QRegularExpression::PatternOption::CaseInsensitiveOption );
582 if ( isJsonRx.match( contentUri ).hasMatch() )
586 const thread_local QRegularExpression antiCandidateRx( QStringLiteral(
".*\\.(gltf|glb|b3dm|i3dm|pnts|cmpt|bin|glbin|glbuf|png|jpeg|jpg)(?:\\?.*)?$" ), QRegularExpression::PatternOption::CaseInsensitiveOption );
587 if ( antiCandidateRx.match( contentUri ).hasMatch() )
595bool QgsCesiumTiledSceneIndex::fetchHierarchy(
long long id,
QgsFeedback *feedback )
597 QMutexLocker locker( &mLock );
598 auto it = mNodeMap.constFind(
id );
599 if ( it == mNodeMap.constEnd() )
605 auto it = mTileContentFormats.constFind(
id );
606 if ( it != mTileContentFormats.constEnd() )
608 switch ( it.value() )
610 case TileContentFormat::NotJson:
612 case TileContentFormat::Json:
618 const QString contentUri = it.value()->tile()->resources().value( QStringLiteral(
"content" ) ).toString();
621 if ( contentUri.isEmpty() )
625 const QByteArray subTile = retrieveContent( contentUri, feedback );
626 if ( !subTile.isEmpty() )
633 const auto subTileJson =
json::parse( subTile.toStdString() );
634 QMutexLocker locker( &mLock );
635 refineNodeFromJson( it.value(), QUrl( contentUri ), subTileJson );
636 mTileContentFormats.insert(
id, TileContentFormat::Json );
639 catch ( json::parse_error & )
641 QMutexLocker locker( &mLock );
642 mTileContentFormats.insert(
id, TileContentFormat::NotJson );
650 mTileContentFormats.insert(
id, TileContentFormat::NotJson );
655QByteArray QgsCesiumTiledSceneIndex::fetchContent(
const QString &uri,
QgsFeedback *feedback )
659 if ( uri.startsWith(
"http" ) )
661 QNetworkRequest networkRequest = QNetworkRequest( url );
663 networkRequest.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
664 networkRequest.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
666 mHeaders.updateNetworkRequest( networkRequest );
668 if ( QThread::currentThread() == QApplication::instance()->thread() )
672 networkRequest, mAuthCfg,
false, feedback );
692 return reply->data();
695 else if ( url.isLocalFile() && QFile::exists( url.toLocalFile() ) )
697 QFile file( url.toLocalFile() );
698 if ( file.open( QIODevice::ReadOnly ) )
700 return file.readAll();
711QgsCesiumTilesDataProviderSharedData::QgsCesiumTilesDataProviderSharedData()
720 if ( !mTileset.contains(
"root" ) )
722 mError = QObject::tr(
"JSON is not a valid Cesium 3D Tiles source (does not contain \"root\" value)" );
726 mLayerMetadata.setType( QStringLiteral(
"dataset" ) );
728 if ( mTileset.contains(
"asset" ) )
730 const auto &asset = mTileset[
"asset" ];
731 if ( asset.contains(
"tilesetVersion" ) )
735 const QString tilesetVersion = QString::fromStdString( asset[
"tilesetVersion"].get<std::string>() );
736 mLayerMetadata.setIdentifier( tilesetVersion );
738 catch ( json::type_error & )
740 QgsDebugError( QStringLiteral(
"Error when parsing tilesetVersion value" ) );
746 new QgsCesiumTiledSceneIndex(
757 const auto &root = mTileset[
"root" ];
769 const auto &rootBoundingVolume = root[
"boundingVolume" ];
772 if ( root.contains(
"transform" ) && !root[
"transform"].is_null() )
774 const auto &transformJson = root[
"transform"];
775 double *ptr = rootTransform.
data();
776 for (
int i = 0; i < 16; ++i )
777 ptr[i] = transformJson[i].get<double>();
780 if ( rootBoundingVolume.contains(
"region" ) )
783 if ( !rootRegion.
isNull() )
788 if ( !mIndex.rootTile().boundingVolume().box().isNull() )
795 mLayerMetadata.setCrs( mSceneCrs );
798 spatialExtent.
bounds = rootRegion;
801 else if ( rootBoundingVolume.contains(
"box" ) )
812 mLayerMetadata.setCrs( mSceneCrs );
815 mBoundingVolume.transform( rootTransform );
819 ct.setBallparkTransformsAreAppropriate(
true );
820 const QgsBox3D rootRegion = mBoundingVolume.bounds( ct );
822 if ( !mIndex.rootTile().boundingVolume().box().isNull() )
827 std::unique_ptr< QgsAbstractGeometry > extent2D( mBoundingVolume.as2DGeometry( ct ) );
828 mExtent = extent2D->boundingBox();
832 QgsDebugError( QStringLiteral(
"Caught transform exception when transforming boundingVolume" ) );
836 spatialExtent.
bounds = mBoundingVolume.bounds();
839 else if ( rootBoundingVolume.contains(
"sphere" ) )
850 mLayerMetadata.setCrs( mSceneCrs );
858 ct.setBallparkTransformsAreAppropriate(
true );
859 const QgsBox3D rootRegion = mBoundingVolume.bounds( ct );
861 if ( !mIndex.rootTile().boundingVolume().box().isNull() )
866 std::unique_ptr< QgsAbstractGeometry > extent2D( mBoundingVolume.as2DGeometry( ct ) );
867 mExtent = extent2D->boundingBox();
871 QgsDebugError( QStringLiteral(
"Caught transform exception when transforming boundingVolume" ) );
875 spatialExtent.
bounds = mBoundingVolume.bounds();
880 mError = QObject::tr(
"JSON is not a valid Cesium 3D Tiles source (unsupported boundingVolume format)" );
886 mLayerMetadata.setExtent( layerExtent );
896QgsCesiumTilesDataProvider::QgsCesiumTilesDataProvider(
const QString &uri,
const ProviderOptions &providerOptions, ReadFlags flags )
898 , mShared( std::make_shared< QgsCesiumTilesDataProviderSharedData >() )
908QgsCesiumTilesDataProvider::QgsCesiumTilesDataProvider(
const QgsCesiumTilesDataProvider &other )
910 , mIsValid( other.mIsValid )
911 , mAuthCfg( other.mAuthCfg )
912 , mHeaders( other.mHeaders )
915 mShared = other.mShared;
928QgsCesiumTilesDataProvider::~QgsCesiumTilesDataProvider() =
default;
930QgsCesiumTilesDataProvider *QgsCesiumTilesDataProvider::clone()
const
933 return new QgsCesiumTilesDataProvider( *
this );
936bool QgsCesiumTilesDataProvider::init()
941 const QString uri = dataSourceUri();
943 if ( uri.startsWith( QLatin1String(
"ion://" ) ) )
946 const QString assetId = QUrlQuery( url ).queryItemValue( QStringLiteral(
"assetId" ) );
947 const QString accessToken = QUrlQuery( url ).queryItemValue( QStringLiteral(
"accessToken" ) );
949 const QString CESIUM_ION_URL = QStringLiteral(
"https://api.cesium.com/" );
953 const QString assetInfoEndpoint = CESIUM_ION_URL + QStringLiteral(
"v1/assets/%1" ).arg( assetId );
954 QNetworkRequest request = QNetworkRequest( assetInfoEndpoint );
956 mHeaders.updateNetworkRequest( request );
957 if ( !accessToken.isEmpty() )
958 request.setRawHeader( "Authorization", QStringLiteral( "Bearer %1" ).arg( accessToken ).toLocal8Bit() );
961 if ( accessToken.isEmpty() )
962 networkRequest.setAuthCfg( mAuthCfg );
964 switch ( networkRequest.get( request ) )
978 if ( assetInfoJson[
"type"] !=
"3DTILES" )
980 appendError(
QgsErrorMessage( tr(
"Only ion 3D Tiles content can be accessed, not %1" ).arg( QString::fromStdString( assetInfoJson[
"type"].get<std::string>() ) ) ) );
984 mShared->mLayerMetadata.setTitle( QString::fromStdString( assetInfoJson[
"name"].get<std::string>() ) );
985 mShared->mLayerMetadata.setAbstract( QString::fromStdString( assetInfoJson[
"description"].get<std::string>() ) );
986 const QString attribution = QString::fromStdString( assetInfoJson[
"attribution"].get<std::string>() );
987 if ( !attribution.isEmpty() )
988 mShared->mLayerMetadata.setRights( { attribution } );
990 mShared->mLayerMetadata.setDateTime(
Qgis::MetadataDateType::Created, QDateTime::fromString( QString::fromStdString( assetInfoJson[
"dateAdded"].get<std::string>() ), Qt::DateFormat::ISODate ) );
995 const QString tileAccessEndpoint = CESIUM_ION_URL + QStringLiteral(
"v1/assets/%1/endpoint" ).arg( assetId );
996 QNetworkRequest request = QNetworkRequest( tileAccessEndpoint );
998 mHeaders.updateNetworkRequest( request );
999 if ( !accessToken.isEmpty() )
1000 request.setRawHeader( "Authorization", QStringLiteral( "Bearer %1" ).arg( accessToken ).toLocal8Bit() );
1003 if ( accessToken.isEmpty() )
1004 networkRequest.setAuthCfg( mAuthCfg );
1006 switch ( networkRequest.get( request ) )
1021 if ( tileAccessJson.contains(
"url" ) )
1023 tileSetUri = QString::fromStdString( tileAccessJson[
"url"].get<std::string>() );
1025 else if ( tileAccessJson.contains(
"options" ) )
1027 const auto &optionsJson = tileAccessJson[
"options"];
1028 if ( optionsJson.contains(
"url" ) )
1030 tileSetUri = QString::fromStdString( optionsJson[
"url"].get<std::string>() );
1034 if ( tileAccessJson.contains(
"accessToken" ) )
1038 mHeaders.insert( QStringLiteral(
"Authorization" ),
1039 QStringLiteral(
"Bearer %1" ).arg( QString::fromStdString( tileAccessJson[
"accessToken"].get<std::string>() ) ) );
1048 tileSetUri = dsUri.
param( QStringLiteral(
"url" ) );
1051 if ( !tileSetUri.isEmpty() )
1053 const QUrl url( tileSetUri );
1055 QNetworkRequest request = QNetworkRequest( url );
1057 mHeaders.updateNetworkRequest( request );
1060 networkRequest.setAuthCfg( mAuthCfg );
1062 switch ( networkRequest.get( request ) )
1076 mShared->initialize( content.
content(), tileSetUri, transformContext(), mAuthCfg, mHeaders );
1083 const QFileInfo fi( dataSourceUri() );
1086 QFile file( dataSourceUri( ) );
1087 if ( file.open( QIODevice::ReadOnly | QIODevice::Text ) )
1089 const QByteArray raw = file.readAll();
1090 mShared->initialize( raw, QUrl::fromLocalFile( dataSourceUri() ), transformContext(), mAuthCfg, mHeaders );
1103 if ( !mShared->mIndex.isValid() )
1105 appendError( mShared->mError );
1116 return mShared->mLayerCrs;
1124 return mShared->mExtent;
1127bool QgsCesiumTilesDataProvider::isValid()
const
1134QString QgsCesiumTilesDataProvider::name()
const
1138 return PROVIDER_KEY;
1141QString QgsCesiumTilesDataProvider::description()
const
1145 return QObject::tr(
"Cesium 3D Tiles" );
1148QString QgsCesiumTilesDataProvider::htmlMetadata()
const
1155 if ( mShared->mTileset.contains(
"asset" ) )
1157 const auto &asset = mShared->mTileset[
"asset" ];
1158 if ( asset.contains(
"version" ) )
1160 const QString version = QString::fromStdString( asset[
"version"].get<std::string>() );
1161 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"3D Tiles Version" ) % QStringLiteral(
"</td><td>%1</a>" ).arg( version ) % QStringLiteral(
"</td></tr>\n" );
1164 if ( asset.contains(
"tilesetVersion" ) )
1168 const QString tilesetVersion = QString::fromStdString( asset[
"tilesetVersion"].get<std::string>() );
1169 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"Tileset Version" ) % QStringLiteral(
"</td><td>%1</a>" ).arg( tilesetVersion ) % QStringLiteral(
"</td></tr>\n" );
1171 catch ( json::type_error & )
1173 QgsDebugError( QStringLiteral(
"Error when parsing tilesetVersion value" ) );
1177 if ( asset.contains(
"generator" ) )
1179 const QString generator = QString::fromStdString( asset[
"generator"].get<std::string>() );
1180 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"Tileset Generator" ) % QStringLiteral(
"</td><td>%1</a>" ).arg( generator ) % QStringLiteral(
"</td></tr>\n" );
1183 if ( mShared->mTileset.contains(
"extensionsRequired" ) )
1185 QStringList extensions;
1186 for (
const auto &item : mShared->mTileset[
"extensionsRequired"] )
1188 extensions << QString::fromStdString( item.get<std::string>() );
1190 if ( !extensions.isEmpty() )
1192 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" );
1195 if ( mShared->mTileset.contains(
"extensionsUsed" ) )
1197 QStringList extensions;
1198 for (
const auto &item : mShared->mTileset[
"extensionsUsed"] )
1200 extensions << QString::fromStdString( item.get<std::string>() );
1202 if ( !extensions.isEmpty() )
1204 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" );
1208 if ( !mShared->mZRange.isInfinite() )
1210 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" );
1223 return mShared->mLayerMetadata;
1233 return mShared->mSceneCrs ;
1244 return mShared ? mShared->mBoundingVolume : nullVolume;
1254 return mShared->mIndex;
1264 return mShared->mZRange;
1272QgsCesiumTilesProviderMetadata::QgsCesiumTilesProviderMetadata():
1277QIcon QgsCesiumTilesProviderMetadata::icon()
const
1284 return new QgsCesiumTilesDataProvider( uri, options, flags );
1289 const QVariantMap parts = decodeUri( uri );
1290 if ( parts.value( QStringLiteral(
"file-name" ) ).toString().compare( QLatin1String(
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
1305int QgsCesiumTilesProviderMetadata::priorityForUri(
const QString &uri )
const
1307 const QVariantMap parts = decodeUri( uri );
1308 if ( parts.value( QStringLiteral(
"file-name" ) ).toString().compare( QLatin1String(
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
1314QList<Qgis::LayerType> QgsCesiumTilesProviderMetadata::validLayerTypesForUri(
const QString &uri )
const
1316 const QVariantMap parts = decodeUri( uri );
1317 if ( parts.value( QStringLiteral(
"file-name" ) ).toString().compare( QLatin1String(
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
1320 return QList< Qgis::LayerType>();
1323QVariantMap QgsCesiumTilesProviderMetadata::decodeUri(
const QString &uri )
const
1325 QVariantMap uriComponents;
1326 QUrl url = QUrl::fromUserInput( uri );
1327 uriComponents.insert( QStringLiteral(
"file-name" ), url.fileName() );
1328 uriComponents.insert( QStringLiteral(
"path" ), uri );
1329 return uriComponents;
1345 return QObject::tr(
"Cesium 3D Tiles" ) + QStringLiteral(
" (tileset.json TILESET.JSON)" );
1352 return FileBasedUris;
1355QList<Qgis::LayerType> QgsCesiumTilesProviderMetadata::supportedLayerTypes()
const
1360QString QgsCesiumTilesProviderMetadata::encodeUri(
const QVariantMap &parts )
const
1362 const QString path = parts.value( QStringLiteral(
"path" ) ).toString();
1368 return ProviderMetadataCapability::LayerTypesForUri
1369 | ProviderMetadataCapability::PriorityForUri
1370 | 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 (since QGIS 3.34)
@ VectorTile
Vector tile layers (since QGIS 3.32)
@ MeshDataset
Mesh datasets.
@ PointCloud
Point clouds (since QGIS 3.18)
@ FastExtent2D
Provider's 2D extent retrieval via QgsDataProvider::extent() is always guaranteed to be trivial/fast ...
@ 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.
QFlags< ReadFlag > ReadFlags
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)
QgsSQLStatement::Node * parse(const QString &str, QString &parserErrorMsg, bool allowFragments)
#define QGIS_PROTECT_QOBJECT_THREAD_ACCESS
const QgsCoordinateReferenceSystem & crs
Setting options for creating vector data providers.