42#include <QNetworkRequest>
43#include <QJsonDocument>
46#include <QRegularExpression>
47#include <QRecursiveMutex>
49#include <QApplication>
50#include <nlohmann/json.hpp>
51#include <qstringliteral.h>
55#define PROVIDER_KEY QStringLiteral( "cesiumtiles" )
56#define PROVIDER_DESCRIPTION QStringLiteral( "Cesium 3D Tiles data provider" )
67static QString appendQueryFromBaseUrl(
const QString &contentUri,
const QUrl &baseUrl )
69 QUrlQuery contentQuery( QUrl( contentUri ).query() );
70 const QList<QPair<QString, QString>> baseUrlQueryItems = QUrlQuery( baseUrl.query() ).queryItems();
71 for (
const QPair<QString, QString> &kv : baseUrlQueryItems )
73 contentQuery.addQueryItem( kv.first, kv.second );
75 QUrl newContentUrl( contentUri );
76 newContentUrl.setQuery( contentQuery );
77 return newContentUrl.toString();
85 QgsCesiumTiledSceneIndex(
88 const QString &authCfg,
92 std::unique_ptr< QgsTiledSceneTile > tileFromJson(
const json &node,
const QUrl &baseUrl,
const QgsTiledSceneTile *parent,
Qgis::Axis gltfUpAxis );
94 void refineNodeFromJson(
QgsTiledSceneNode *node,
const QUrl &baseUrl,
const json &json );
98 long long parentTileId(
long long id ) const final;
99 QVector<
long long > childTileIds(
long long id ) const final;
101 Qgis::TileChildrenAvailability childAvailability(
long long id ) const final;
102 bool fetchHierarchy(
long long id,
QgsFeedback *feedback =
nullptr ) final;
106 QByteArray fetchContent( const QString &uri,
QgsFeedback *feedback =
nullptr ) final;
110 enum class TileContentFormat
116 mutable QRecursiveMutex mLock;
118 std::unique_ptr< QgsTiledSceneNode > mRootNode;
119 QMap< long long, QgsTiledSceneNode * > mNodeMap;
120 QMap< long long, TileContentFormat > mTileContentFormats;
123 long long mNextTileId = 0;
127class QgsCesiumTilesDataProviderSharedData
130 QgsCesiumTilesDataProviderSharedData();
131 void initialize(
const QString &tileset,
134 const QString &authCfg,
142 nlohmann::json mTileset;
149 QReadWriteLock mReadWriteLock;
160 const std::string gltfUpAxisString = json.get<std::string>();
161 if ( gltfUpAxisString ==
"z" || gltfUpAxisString ==
"Z" )
165 else if ( gltfUpAxisString ==
"y" || gltfUpAxisString ==
"Y" )
169 else if ( gltfUpAxisString ==
"x" || gltfUpAxisString ==
"X" )
173 QgsDebugError( QStringLiteral(
"Unsupported gltfUpAxis value: %1" ).arg( QString::fromStdString( gltfUpAxisString ) ) );
178 : mTransformContext( transformContext )
179 , mAuthCfg( authCfg )
180 , mHeaders( headers )
183 if ( tileset.contains(
"asset" ) )
185 const auto &assetJson = tileset[
"asset"];
186 if ( assetJson.contains(
"gltfUpAxis" ) )
188 gltfUpAxis = axisFromJson( assetJson[
"gltfUpAxis"] );
192 mRootNode.reset( nodeFromJson( tileset[
"root" ], rootUrl,
nullptr, gltfUpAxis ) );
195std::unique_ptr< QgsTiledSceneTile > QgsCesiumTiledSceneIndex::tileFromJson(
const json &json,
const QUrl &baseUrl,
const QgsTiledSceneTile *parent,
Qgis::Axis gltfUpAxis )
197 std::unique_ptr< QgsTiledSceneTile > tile = std::make_unique< QgsTiledSceneTile >( mNextTileId++ );
199 tile->setBaseUrl( baseUrl );
202 { QStringLiteral(
"gltfUpAxis" ),
static_cast< int >( gltfUpAxis ) },
203 { QStringLiteral(
"contentFormat" ), QStringLiteral(
"cesiumtiles" ) },
207 if ( json.contains(
"transform" ) && !json[
"transform"].is_null() )
209 const auto &transformJson = json[
"transform"];
210 double *ptr = transform.
data();
211 for (
int i = 0; i < 16; ++i )
212 ptr[i] = transformJson[i].get<double>();
216 transform = *parent->
transform() * transform;
219 else if ( parent && parent->
transform() )
224 tile->setTransform( transform );
226 const auto &boundingVolume = json[
"boundingVolume" ];
228 if ( boundingVolume.contains(
"region" ) )
231 if ( !rootRegion.
isNull() )
233 if ( rootRegion.
width() > 20 || rootRegion.
height() > 20 )
240 QVector< QgsVector3D > corners = rootRegion.
corners();
248 for (
int i = 0; i < 8; ++i )
251 x.append( corner.
x() );
252 y.append( corner.
y() );
253 z.append( corner.
z() );
256 ct.setBallparkTransformsAreAppropriate(
true );
259 ct.transformInPlace( x, y, z );
263 QgsDebugError( QStringLiteral(
"Cannot transform region bounding volume" ) );
266 const auto minMaxX = std::minmax_element( x.constBegin(), x.constEnd() );
267 const auto minMaxY = std::minmax_element( y.constBegin(), y.constEnd() );
268 const auto minMaxZ = std::minmax_element( z.constBegin(), z.constEnd() );
275 else if ( boundingVolume.contains(
"box" ) )
285 else if ( boundingVolume.contains(
"sphere" ) )
296 QgsDebugError( QStringLiteral(
"unsupported boundingVolume format" ) );
299 tile->setBoundingVolume( volume );
301 if ( json.contains(
"geometricError" ) )
302 tile->setGeometricError( json[
"geometricError"].get< double >() );
303 if ( json.contains(
"refine" ) )
305 if ( json[
"refine"] ==
"ADD" )
307 else if ( json[
"refine"] ==
"REPLACE" )
316 if ( json.contains(
"content" ) && !json[
"content"].is_null() )
318 const auto &contentJson = json[
"content"];
322 if ( contentJson.contains(
"uri" ) && !contentJson[
"uri"].is_null() )
324 QString relativeUri = QString::fromStdString( contentJson[
"uri"].get<std::string>() );
325 contentUri = baseUrl.resolved( QUrl( relativeUri ) ).toString();
327 if ( baseUrl.hasQuery() && QUrl( relativeUri ).isRelative() )
328 contentUri = appendQueryFromBaseUrl( contentUri, baseUrl );
330 else if ( contentJson.contains(
"url" ) && !contentJson[
"url"].is_null() )
332 QString relativeUri = QString::fromStdString( contentJson[
"url"].get<std::string>() );
333 contentUri = baseUrl.resolved( QUrl( relativeUri ) ).toString();
335 if ( baseUrl.hasQuery() && QUrl( relativeUri ).isRelative() )
336 contentUri = appendQueryFromBaseUrl( contentUri, baseUrl );
338 if ( !contentUri.isEmpty() )
340 tile->setResources( {{ QStringLiteral(
"content" ), contentUri } } );
349 std::unique_ptr< QgsTiledSceneTile > tile = tileFromJson( json, baseUrl, parent ? parent->
tile() : nullptr, gltfUpAxis );
350 std::unique_ptr< QgsTiledSceneNode > newNode = std::make_unique< QgsTiledSceneNode >( tile.release() );
351 mNodeMap.insert( newNode->tile()->id(), newNode.get() );
356 if ( json.contains(
"children" ) )
358 for (
const auto &childJson : json[
"children"] )
360 nodeFromJson( childJson, baseUrl, newNode.get(), gltfUpAxis );
364 return newNode.release();
367void QgsCesiumTiledSceneIndex::refineNodeFromJson(
QgsTiledSceneNode *node,
const QUrl &baseUrl,
const json &json )
369 const auto &rootTileJson = json[
"root"];
372 if ( json.contains(
"asset" ) )
374 const auto &assetJson = json[
"asset"];
375 if ( assetJson.contains(
"gltfUpAxis" ) )
377 gltfUpAxis = axisFromJson( assetJson[
"gltfUpAxis"] );
381 std::unique_ptr< QgsTiledSceneTile > newTile = tileFromJson( rootTileJson, baseUrl, node->
tile(), gltfUpAxis );
391 if ( newTile->transform() )
394 if ( rootTileJson.contains(
"children" ) )
396 for (
const auto &childJson : rootTileJson[
"children"] )
398 nodeFromJson( childJson, baseUrl, node, gltfUpAxis );
405 QMutexLocker locker( &mLock );
411 QMutexLocker locker( &mLock );
412 auto it = mNodeMap.constFind(
id );
413 if ( it != mNodeMap.constEnd() )
415 return *( it.value()->tile() );
421long long QgsCesiumTiledSceneIndex::parentTileId(
long long id )
const
423 QMutexLocker locker( &mLock );
424 auto it = mNodeMap.constFind(
id );
425 if ( it != mNodeMap.constEnd() )
429 return parent->
tile()->
id();
436QVector< long long > QgsCesiumTiledSceneIndex::childTileIds(
long long id )
const
438 QMutexLocker locker( &mLock );
439 auto it = mNodeMap.constFind(
id );
440 if ( it != mNodeMap.constEnd() )
442 QVector< long long > childIds;
443 const QList< QgsTiledSceneNode * > children = it.value()->children();
444 childIds.reserve( children.size() );
447 childIds << child->tile()->id();
457 QVector< long long > results;
460 traverseNode = [&request, &traverseNode, &results,
this](
QgsTiledSceneNode * node )
476 QList< QgsTiledSceneNode * > children = node->
children();
477 if ( children.empty() )
479 switch ( childAvailability( tile->
id() ) )
489 if ( fetchHierarchy( tile->
id() ), request.
feedback() )
504 traverseNode( child );
511 results << tile->
id();
516 if ( children.empty() )
517 results << tile->
id();
523 results << tile->
id();
528 QMutexLocker locker( &mLock );
532 traverseNode( mRootNode.get() );
537 if ( it != mNodeMap.constEnd() )
539 traverseNode( it.value() );
549 QMutexLocker locker( &mLock );
551 auto it = mNodeMap.constFind(
id );
552 if ( it == mNodeMap.constEnd() )
555 if ( !it.value()->children().isEmpty() )
558 contentUri = it.value()->tile()->resources().value( QStringLiteral(
"content" ) ).toString();
562 auto it = mTileContentFormats.constFind(
id );
563 if ( it != mTileContentFormats.constEnd() )
565 switch ( it.value() )
567 case TileContentFormat::NotJson:
569 case TileContentFormat::Json:
576 if ( contentUri.isEmpty() )
586 const thread_local QRegularExpression isJsonRx( QStringLiteral(
".*\\.json(?:\\?.*)?$" ), QRegularExpression::PatternOption::CaseInsensitiveOption );
587 if ( isJsonRx.match( contentUri ).hasMatch() )
591 const thread_local QRegularExpression antiCandidateRx( QStringLiteral(
".*\\.(gltf|glb|b3dm|i3dm|pnts|cmpt|bin|glbin|glbuf|png|jpeg|jpg)(?:\\?.*)?$" ), QRegularExpression::PatternOption::CaseInsensitiveOption );
592 if ( antiCandidateRx.match( contentUri ).hasMatch() )
600bool QgsCesiumTiledSceneIndex::fetchHierarchy(
long long id,
QgsFeedback *feedback )
602 QMutexLocker locker( &mLock );
603 auto it = mNodeMap.constFind(
id );
604 if ( it == mNodeMap.constEnd() )
610 auto it = mTileContentFormats.constFind(
id );
611 if ( it != mTileContentFormats.constEnd() )
613 switch ( it.value() )
615 case TileContentFormat::NotJson:
617 case TileContentFormat::Json:
623 const QString contentUri = it.value()->tile()->resources().value( QStringLiteral(
"content" ) ).toString();
626 if ( contentUri.isEmpty() )
630 const QByteArray subTile = retrieveContent( contentUri, feedback );
631 if ( !subTile.isEmpty() )
638 const auto subTileJson = json::parse( subTile.toStdString() );
639 QMutexLocker locker( &mLock );
640 refineNodeFromJson( it.value(), QUrl( contentUri ), subTileJson );
641 mTileContentFormats.insert(
id, TileContentFormat::Json );
644 catch ( json::parse_error & )
646 QMutexLocker locker( &mLock );
647 mTileContentFormats.insert(
id, TileContentFormat::NotJson );
655 mTileContentFormats.insert(
id, TileContentFormat::NotJson );
660QByteArray QgsCesiumTiledSceneIndex::fetchContent(
const QString &uri,
QgsFeedback *feedback )
664 if ( uri.startsWith(
"http" ) )
666 QNetworkRequest networkRequest = QNetworkRequest( url );
668 networkRequest.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
669 networkRequest.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
671 mHeaders.updateNetworkRequest( networkRequest );
673 if ( QThread::currentThread() == QApplication::instance()->thread() )
677 networkRequest, mAuthCfg,
false, feedback );
697 return reply->data();
700 else if ( url.isLocalFile() && QFile::exists( url.toLocalFile() ) )
702 QFile file( url.toLocalFile() );
703 if ( file.open( QIODevice::ReadOnly ) )
705 return file.readAll();
716QgsCesiumTilesDataProviderSharedData::QgsCesiumTilesDataProviderSharedData()
724 mTileset = json::parse( tileset.toStdString() );
725 if ( !mTileset.contains(
"root" ) )
727 mError = QObject::tr(
"JSON is not a valid Cesium 3D Tiles source (does not contain \"root\" value)" );
731 mLayerMetadata.setType( QStringLiteral(
"dataset" ) );
733 if ( mTileset.contains(
"asset" ) )
735 const auto &asset = mTileset[
"asset" ];
736 if ( asset.contains(
"tilesetVersion" ) )
740 const QString tilesetVersion = QString::fromStdString( asset[
"tilesetVersion"].get<std::string>() );
741 mLayerMetadata.setIdentifier( tilesetVersion );
743 catch ( json::type_error & )
745 QgsDebugError( QStringLiteral(
"Error when parsing tilesetVersion value" ) );
751 new QgsCesiumTiledSceneIndex(
762 const auto &root = mTileset[
"root" ];
774 const auto &rootBoundingVolume = root[
"boundingVolume" ];
777 if ( root.contains(
"transform" ) && !root[
"transform"].is_null() )
779 const auto &transformJson = root[
"transform"];
780 double *ptr = rootTransform.
data();
781 for (
int i = 0; i < 16; ++i )
782 ptr[i] = transformJson[i].get<double>();
785 if ( rootBoundingVolume.contains(
"region" ) )
788 if ( !rootRegion.
isNull() )
793 if ( !mIndex.rootTile().boundingVolume().box().isNull() )
800 mLayerMetadata.setCrs( mSceneCrs );
803 spatialExtent.
bounds = rootRegion;
806 else if ( rootBoundingVolume.contains(
"box" ) )
817 mLayerMetadata.setCrs( mSceneCrs );
820 mBoundingVolume.transform( rootTransform );
824 ct.setBallparkTransformsAreAppropriate(
true );
825 const QgsBox3D rootRegion = mBoundingVolume.bounds( ct );
827 if ( !mIndex.rootTile().boundingVolume().box().isNull() )
832 std::unique_ptr< QgsAbstractGeometry > extent2D( mBoundingVolume.as2DGeometry( ct ) );
833 mExtent = extent2D->boundingBox();
837 QgsDebugError( QStringLiteral(
"Caught transform exception when transforming boundingVolume" ) );
841 spatialExtent.
bounds = mBoundingVolume.bounds();
844 else if ( rootBoundingVolume.contains(
"sphere" ) )
855 mLayerMetadata.setCrs( mSceneCrs );
863 ct.setBallparkTransformsAreAppropriate(
true );
864 const QgsBox3D rootRegion = mBoundingVolume.bounds( ct );
866 if ( !mIndex.rootTile().boundingVolume().box().isNull() )
871 std::unique_ptr< QgsAbstractGeometry > extent2D( mBoundingVolume.as2DGeometry( ct ) );
872 mExtent = extent2D->boundingBox();
876 QgsDebugError( QStringLiteral(
"Caught transform exception when transforming boundingVolume" ) );
880 spatialExtent.
bounds = mBoundingVolume.bounds();
885 mError = QObject::tr(
"JSON is not a valid Cesium 3D Tiles source (unsupported boundingVolume format)" );
891 mLayerMetadata.setExtent( layerExtent );
901QgsCesiumTilesDataProvider::QgsCesiumTilesDataProvider(
const QString &uri,
const ProviderOptions &providerOptions,
Qgis::DataProviderReadFlags flags )
903 , mShared( std::make_shared< QgsCesiumTilesDataProviderSharedData >() )
913QgsCesiumTilesDataProvider::QgsCesiumTilesDataProvider(
const QgsCesiumTilesDataProvider &other )
915 , mIsValid( other.mIsValid )
916 , mAuthCfg( other.mAuthCfg )
917 , mHeaders( other.mHeaders )
920 mShared = other.mShared;
933QgsCesiumTilesDataProvider::~QgsCesiumTilesDataProvider() =
default;
935QgsCesiumTilesDataProvider *QgsCesiumTilesDataProvider::clone()
const
938 return new QgsCesiumTilesDataProvider( *
this );
941bool QgsCesiumTilesDataProvider::init()
946 const QString uri = dataSourceUri();
948 if ( uri.startsWith( QLatin1String(
"ion://" ) ) )
951 const QString assetId = QUrlQuery( url ).queryItemValue( QStringLiteral(
"assetId" ) );
952 const QString accessToken = QUrlQuery( url ).queryItemValue( QStringLiteral(
"accessToken" ) );
954 const QString CESIUM_ION_URL = QStringLiteral(
"https://api.cesium.com/" );
958 const QString assetInfoEndpoint = CESIUM_ION_URL + QStringLiteral(
"v1/assets/%1" ).arg( assetId );
959 QNetworkRequest request = QNetworkRequest( assetInfoEndpoint );
961 mHeaders.updateNetworkRequest( request );
962 if ( !accessToken.isEmpty() )
963 request.setRawHeader( "Authorization", QStringLiteral( "Bearer %1" ).arg( accessToken ).toLocal8Bit() );
966 if ( accessToken.isEmpty() )
967 networkRequest.setAuthCfg( mAuthCfg );
969 switch ( networkRequest.get( request ) )
982 const json assetInfoJson = json::parse( content.
content().toStdString() );
983 if ( assetInfoJson[
"type"] !=
"3DTILES" )
985 appendError(
QgsErrorMessage( tr(
"Only ion 3D Tiles content can be accessed, not %1" ).arg( QString::fromStdString( assetInfoJson[
"type"].get<std::string>() ) ) ) );
989 mShared->mLayerMetadata.setTitle( QString::fromStdString( assetInfoJson[
"name"].get<std::string>() ) );
990 mShared->mLayerMetadata.setAbstract( QString::fromStdString( assetInfoJson[
"description"].get<std::string>() ) );
991 const QString attribution = QString::fromStdString( assetInfoJson[
"attribution"].get<std::string>() );
992 if ( !attribution.isEmpty() )
993 mShared->mLayerMetadata.setRights( { attribution } );
995 mShared->mLayerMetadata.setDateTime(
Qgis::MetadataDateType::Created, QDateTime::fromString( QString::fromStdString( assetInfoJson[
"dateAdded"].get<std::string>() ), Qt::DateFormat::ISODate ) );
1000 const QString tileAccessEndpoint = CESIUM_ION_URL + QStringLiteral(
"v1/assets/%1/endpoint" ).arg( assetId );
1001 QNetworkRequest request = QNetworkRequest( tileAccessEndpoint );
1003 mHeaders.updateNetworkRequest( request );
1004 if ( !accessToken.isEmpty() )
1005 request.setRawHeader( "Authorization", QStringLiteral( "Bearer %1" ).arg( accessToken ).toLocal8Bit() );
1008 if ( accessToken.isEmpty() )
1009 networkRequest.setAuthCfg( mAuthCfg );
1011 switch ( networkRequest.get( request ) )
1024 const json tileAccessJson = json::parse( content.
content().toStdString() );
1026 if ( tileAccessJson.contains(
"url" ) )
1028 tileSetUri = QString::fromStdString( tileAccessJson[
"url"].get<std::string>() );
1030 else if ( tileAccessJson.contains(
"options" ) )
1032 const auto &optionsJson = tileAccessJson[
"options"];
1033 if ( optionsJson.contains(
"url" ) )
1035 tileSetUri = QString::fromStdString( optionsJson[
"url"].get<std::string>() );
1039 if ( tileAccessJson.contains(
"accessToken" ) )
1043 mHeaders.insert( QStringLiteral(
"Authorization" ),
1044 QStringLiteral(
"Bearer %1" ).arg( QString::fromStdString( tileAccessJson[
"accessToken"].get<std::string>() ) ) );
1053 tileSetUri = dsUri.
param( QStringLiteral(
"url" ) );
1056 if ( !tileSetUri.isEmpty() )
1058 const QUrl url( tileSetUri );
1060 QNetworkRequest request = QNetworkRequest( url );
1062 mHeaders.updateNetworkRequest( request );
1065 networkRequest.setAuthCfg( mAuthCfg );
1067 switch ( networkRequest.get( request ) )
1081 mShared->initialize( content.
content(), tileSetUri, transformContext(), mAuthCfg, mHeaders );
1088 const QFileInfo fi( dataSourceUri() );
1091 QFile file( dataSourceUri( ) );
1092 if ( file.open( QIODevice::ReadOnly | QIODevice::Text ) )
1094 const QByteArray raw = file.readAll();
1095 mShared->initialize( raw, QUrl::fromLocalFile( dataSourceUri() ), transformContext(), mAuthCfg, mHeaders );
1108 if ( !mShared->mIndex.isValid() )
1110 appendError( mShared->mError );
1121 return mShared->mLayerCrs;
1129 return mShared->mExtent;
1132bool QgsCesiumTilesDataProvider::isValid()
const
1139QString QgsCesiumTilesDataProvider::name()
const
1143 return PROVIDER_KEY;
1146QString QgsCesiumTilesDataProvider::description()
const
1150 return QObject::tr(
"Cesium 3D Tiles" );
1153QString QgsCesiumTilesDataProvider::htmlMetadata()
const
1160 if ( mShared->mTileset.contains(
"asset" ) )
1162 const auto &asset = mShared->mTileset[
"asset" ];
1163 if ( asset.contains(
"version" ) )
1165 const QString version = QString::fromStdString( asset[
"version"].get<std::string>() );
1166 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"3D Tiles Version" ) % QStringLiteral(
"</td><td>%1</a>" ).arg( version ) % QStringLiteral(
"</td></tr>\n" );
1169 if ( asset.contains(
"tilesetVersion" ) )
1173 const QString tilesetVersion = QString::fromStdString( asset[
"tilesetVersion"].get<std::string>() );
1174 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"Tileset Version" ) % QStringLiteral(
"</td><td>%1</a>" ).arg( tilesetVersion ) % QStringLiteral(
"</td></tr>\n" );
1176 catch ( json::type_error & )
1178 QgsDebugError( QStringLiteral(
"Error when parsing tilesetVersion value" ) );
1182 if ( asset.contains(
"generator" ) )
1184 const QString generator = QString::fromStdString( asset[
"generator"].get<std::string>() );
1185 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"Tileset Generator" ) % QStringLiteral(
"</td><td>%1</a>" ).arg( generator ) % QStringLiteral(
"</td></tr>\n" );
1188 if ( mShared->mTileset.contains(
"extensionsRequired" ) )
1190 QStringList extensions;
1191 for (
const auto &item : mShared->mTileset[
"extensionsRequired"] )
1193 extensions << QString::fromStdString( item.get<std::string>() );
1195 if ( !extensions.isEmpty() )
1197 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" );
1200 if ( mShared->mTileset.contains(
"extensionsUsed" ) )
1202 QStringList extensions;
1203 for (
const auto &item : mShared->mTileset[
"extensionsUsed"] )
1205 extensions << QString::fromStdString( item.get<std::string>() );
1207 if ( !extensions.isEmpty() )
1209 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" );
1213 if ( !mShared->mZRange.isInfinite() )
1215 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" );
1228 return mShared->mLayerMetadata;
1238 return mShared->mSceneCrs ;
1249 return mShared ? mShared->mBoundingVolume : nullVolume;
1259 return mShared->mIndex;
1269 return mShared->mZRange;
1277QgsCesiumTilesProviderMetadata::QgsCesiumTilesProviderMetadata():
1282QIcon QgsCesiumTilesProviderMetadata::icon()
const
1289 return new QgsCesiumTilesDataProvider( uri, options, flags );
1294 const QVariantMap parts = decodeUri( uri );
1295 if ( parts.value( QStringLiteral(
"file-name" ) ).toString().compare( QLatin1String(
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
1310int QgsCesiumTilesProviderMetadata::priorityForUri(
const QString &uri )
const
1312 const QVariantMap parts = decodeUri( uri );
1313 if ( parts.value( QStringLiteral(
"file-name" ) ).toString().compare( QLatin1String(
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
1319QList<Qgis::LayerType> QgsCesiumTilesProviderMetadata::validLayerTypesForUri(
const QString &uri )
const
1321 const QVariantMap parts = decodeUri( uri );
1322 if ( parts.value( QStringLiteral(
"file-name" ) ).toString().compare( QLatin1String(
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
1325 return QList< Qgis::LayerType>();
1328QVariantMap QgsCesiumTilesProviderMetadata::decodeUri(
const QString &uri )
const
1330 QVariantMap uriComponents;
1331 QUrl url = QUrl::fromUserInput( uri );
1332 uriComponents.insert( QStringLiteral(
"file-name" ), url.fileName() );
1333 uriComponents.insert( QStringLiteral(
"path" ), uri );
1334 return uriComponents;
1350 return QObject::tr(
"Cesium 3D Tiles" ) + QStringLiteral(
" (tileset.json TILESET.JSON)" );
1357 return FileBasedUris;
1360QList<Qgis::LayerType> QgsCesiumTilesProviderMetadata::supportedLayerTypes()
const
1365QString QgsCesiumTilesProviderMetadata::encodeUri(
const QVariantMap &parts )
const
1367 const QString path = parts.value( QStringLiteral(
"path" ) ).toString();
1373 return ProviderMetadataCapability::LayerTypesForUri
1374 | ProviderMetadataCapability::PriorityForUri
1375 | 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.