19#include "moc_qgscesiumtilesdataprovider.cpp"
44#include <QNetworkRequest>
45#include <QJsonDocument>
48#include <QRegularExpression>
49#include <QRecursiveMutex>
51#include <QApplication>
52#include <nlohmann/json.hpp>
53#include <qstringliteral.h>
57#define PROVIDER_KEY QStringLiteral( "cesiumtiles" )
58#define PROVIDER_DESCRIPTION QStringLiteral( "Cesium 3D Tiles data provider" )
69static QString appendQueryFromBaseUrl(
const QString &contentUri,
const QUrl &baseUrl )
71 QUrlQuery contentQuery( QUrl( contentUri ).query() );
72 const QList<QPair<QString, QString>> baseUrlQueryItems = QUrlQuery( baseUrl.query() ).queryItems();
73 for (
const QPair<QString, QString> &kv : baseUrlQueryItems )
75 contentQuery.addQueryItem( kv.first, kv.second );
77 QUrl newContentUrl( contentUri );
78 newContentUrl.setQuery( contentQuery );
79 return newContentUrl.toString();
87 QgsCesiumTiledSceneIndex(
90 const QString &authCfg,
94 std::unique_ptr< QgsTiledSceneTile > tileFromJson(
const json &node,
const QUrl &baseUrl,
const QgsTiledSceneTile *parent,
Qgis::Axis gltfUpAxis );
96 void refineNodeFromJson(
QgsTiledSceneNode *node,
const QUrl &baseUrl,
const json &json );
100 long long parentTileId(
long long id ) const final;
101 QVector<
long long > childTileIds(
long long id ) const final;
103 Qgis::TileChildrenAvailability childAvailability(
long long id ) const final;
104 bool fetchHierarchy(
long long id,
QgsFeedback *feedback =
nullptr ) final;
108 QByteArray fetchContent( const QString &uri,
QgsFeedback *feedback =
nullptr ) final;
112 enum class TileContentFormat
118 mutable QRecursiveMutex mLock;
120 std::unique_ptr< QgsTiledSceneNode > mRootNode;
121 QMap< long long, QgsTiledSceneNode * > mNodeMap;
122 QMap< long long, TileContentFormat > mTileContentFormats;
125 long long mNextTileId = 0;
129class QgsCesiumTilesDataProviderSharedData
132 QgsCesiumTilesDataProviderSharedData();
133 void initialize(
const QString &tileset,
136 const QString &authCfg,
144 nlohmann::json mTileset;
151 QReadWriteLock mReadWriteLock;
162 const std::string gltfUpAxisString = json.get<std::string>();
163 if ( gltfUpAxisString ==
"z" || gltfUpAxisString ==
"Z" )
167 else if ( gltfUpAxisString ==
"y" || gltfUpAxisString ==
"Y" )
171 else if ( gltfUpAxisString ==
"x" || gltfUpAxisString ==
"X" )
175 QgsDebugError( QStringLiteral(
"Unsupported gltfUpAxis value: %1" ).arg( QString::fromStdString( gltfUpAxisString ) ) );
180 : mTransformContext( transformContext )
181 , mAuthCfg( authCfg )
182 , mHeaders( headers )
185 if ( tileset.contains(
"asset" ) )
187 const auto &assetJson = tileset[
"asset"];
188 if ( assetJson.contains(
"gltfUpAxis" ) )
190 gltfUpAxis = axisFromJson( assetJson[
"gltfUpAxis"] );
194 mRootNode.reset( nodeFromJson( tileset[
"root" ], rootUrl,
nullptr, gltfUpAxis ) );
197std::unique_ptr< QgsTiledSceneTile > QgsCesiumTiledSceneIndex::tileFromJson(
const json &json,
const QUrl &baseUrl,
const QgsTiledSceneTile *parent,
Qgis::Axis gltfUpAxis )
199 auto tile = std::make_unique< QgsTiledSceneTile >( mNextTileId++ );
201 tile->setBaseUrl( baseUrl );
204 { QStringLiteral(
"gltfUpAxis" ),
static_cast< int >( gltfUpAxis ) },
205 { QStringLiteral(
"contentFormat" ), QStringLiteral(
"cesiumtiles" ) },
209 if ( json.contains(
"transform" ) && !json[
"transform"].is_null() )
211 const auto &transformJson = json[
"transform"];
212 double *ptr = transform.
data();
213 for (
int i = 0; i < 16; ++i )
214 ptr[i] = transformJson[i].get<double>();
218 transform = *parent->
transform() * transform;
221 else if ( parent && parent->
transform() )
226 tile->setTransform( transform );
228 const auto &boundingVolume = json[
"boundingVolume" ];
230 if ( boundingVolume.contains(
"region" ) )
233 if ( !rootRegion.
isNull() )
235 if ( rootRegion.
width() > 20 || rootRegion.
height() > 20 )
242 QVector< QgsVector3D > corners = rootRegion.
corners();
250 for (
int i = 0; i < 8; ++i )
253 x.append( corner.
x() );
254 y.append( corner.
y() );
255 z.append( corner.
z() );
258 ct.setBallparkTransformsAreAppropriate(
true );
261 ct.transformInPlace( x, y, z );
265 QgsDebugError( QStringLiteral(
"Cannot transform region bounding volume" ) );
268 const auto minMaxX = std::minmax_element( x.constBegin(), x.constEnd() );
269 const auto minMaxY = std::minmax_element( y.constBegin(), y.constEnd() );
270 const auto minMaxZ = std::minmax_element( z.constBegin(), z.constEnd() );
277 else if ( boundingVolume.contains(
"box" ) )
287 else if ( boundingVolume.contains(
"sphere" ) )
298 QgsDebugError( QStringLiteral(
"unsupported boundingVolume format" ) );
301 tile->setBoundingVolume( volume );
303 if ( json.contains(
"geometricError" ) )
304 tile->setGeometricError( json[
"geometricError"].get< double >() );
305 if ( json.contains(
"refine" ) )
307 if ( json[
"refine"] ==
"ADD" )
309 else if ( json[
"refine"] ==
"REPLACE" )
318 if ( json.contains(
"content" ) && !json[
"content"].is_null() )
320 const auto &contentJson = json[
"content"];
324 if ( contentJson.contains(
"uri" ) && !contentJson[
"uri"].is_null() )
326 QString relativeUri = QString::fromStdString( contentJson[
"uri"].get<std::string>() );
327 contentUri = baseUrl.resolved( QUrl( relativeUri ) ).toString();
329 if ( baseUrl.hasQuery() && QUrl( relativeUri ).isRelative() )
330 contentUri = appendQueryFromBaseUrl( contentUri, baseUrl );
332 else if ( contentJson.contains(
"url" ) && !contentJson[
"url"].is_null() )
334 QString relativeUri = QString::fromStdString( contentJson[
"url"].get<std::string>() );
335 contentUri = baseUrl.resolved( QUrl( relativeUri ) ).toString();
337 if ( baseUrl.hasQuery() && QUrl( relativeUri ).isRelative() )
338 contentUri = appendQueryFromBaseUrl( contentUri, baseUrl );
340 if ( !contentUri.isEmpty() )
342 tile->setResources( {{ QStringLiteral(
"content" ), contentUri } } );
351 std::unique_ptr< QgsTiledSceneTile > tile = tileFromJson( json, baseUrl, parent ? parent->
tile() : nullptr, gltfUpAxis );
352 auto newNode = std::make_unique< QgsTiledSceneNode >( tile.release() );
353 mNodeMap.insert( newNode->tile()->id(), newNode.get() );
358 if ( json.contains(
"children" ) )
360 for (
const auto &childJson : json[
"children"] )
362 nodeFromJson( childJson, baseUrl, newNode.get(), gltfUpAxis );
366 return newNode.release();
369void QgsCesiumTiledSceneIndex::refineNodeFromJson(
QgsTiledSceneNode *node,
const QUrl &baseUrl,
const json &json )
371 const auto &rootTileJson = json[
"root"];
374 if ( json.contains(
"asset" ) )
376 const auto &assetJson = json[
"asset"];
377 if ( assetJson.contains(
"gltfUpAxis" ) )
379 gltfUpAxis = axisFromJson( assetJson[
"gltfUpAxis"] );
383 std::unique_ptr< QgsTiledSceneTile > newTile = tileFromJson( rootTileJson, baseUrl, node->
tile(), gltfUpAxis );
393 if ( newTile->transform() )
396 if ( rootTileJson.contains(
"children" ) )
398 for (
const auto &childJson : rootTileJson[
"children"] )
400 nodeFromJson( childJson, baseUrl, node, gltfUpAxis );
407 QMutexLocker locker( &mLock );
413 QMutexLocker locker( &mLock );
414 auto it = mNodeMap.constFind(
id );
415 if ( it != mNodeMap.constEnd() )
417 return *( it.value()->tile() );
423long long QgsCesiumTiledSceneIndex::parentTileId(
long long id )
const
425 QMutexLocker locker( &mLock );
426 auto it = mNodeMap.constFind(
id );
427 if ( it != mNodeMap.constEnd() )
431 return parent->
tile()->
id();
438QVector< long long > QgsCesiumTiledSceneIndex::childTileIds(
long long id )
const
440 QMutexLocker locker( &mLock );
441 auto it = mNodeMap.constFind(
id );
442 if ( it != mNodeMap.constEnd() )
444 QVector< long long > childIds;
445 const QList< QgsTiledSceneNode * > children = it.value()->children();
446 childIds.reserve( children.size() );
449 childIds << child->tile()->id();
459 QVector< long long > results;
462 traverseNode = [&request, &traverseNode, &results,
this](
QgsTiledSceneNode * node )
478 QList< QgsTiledSceneNode * > children = node->
children();
479 if ( children.empty() )
481 switch ( childAvailability( tile->
id() ) )
491 if ( fetchHierarchy( tile->
id() ), request.
feedback() )
506 traverseNode( child );
513 results << tile->
id();
518 if ( children.empty() )
519 results << tile->
id();
525 results << tile->
id();
530 QMutexLocker locker( &mLock );
534 traverseNode( mRootNode.get() );
539 if ( it != mNodeMap.constEnd() )
541 traverseNode( it.value() );
551 QMutexLocker locker( &mLock );
553 auto it = mNodeMap.constFind(
id );
554 if ( it == mNodeMap.constEnd() )
557 if ( !it.value()->children().isEmpty() )
560 contentUri = it.value()->tile()->resources().value( QStringLiteral(
"content" ) ).toString();
564 auto it = mTileContentFormats.constFind(
id );
565 if ( it != mTileContentFormats.constEnd() )
567 switch ( it.value() )
569 case TileContentFormat::NotJson:
571 case TileContentFormat::Json:
578 if ( contentUri.isEmpty() )
588 const thread_local QRegularExpression isJsonRx( QStringLiteral(
".*\\.json(?:\\?.*)?$" ), QRegularExpression::PatternOption::CaseInsensitiveOption );
589 if ( isJsonRx.match( contentUri ).hasMatch() )
593 const thread_local QRegularExpression antiCandidateRx( QStringLiteral(
".*\\.(gltf|glb|b3dm|i3dm|pnts|cmpt|bin|glbin|glbuf|png|jpeg|jpg)(?:\\?.*)?$" ), QRegularExpression::PatternOption::CaseInsensitiveOption );
594 if ( antiCandidateRx.match( contentUri ).hasMatch() )
602bool QgsCesiumTiledSceneIndex::fetchHierarchy(
long long id,
QgsFeedback *feedback )
604 QMutexLocker locker( &mLock );
605 auto it = mNodeMap.constFind(
id );
606 if ( it == mNodeMap.constEnd() )
612 auto it = mTileContentFormats.constFind(
id );
613 if ( it != mTileContentFormats.constEnd() )
615 switch ( it.value() )
617 case TileContentFormat::NotJson:
619 case TileContentFormat::Json:
625 const QString contentUri = it.value()->tile()->resources().value( QStringLiteral(
"content" ) ).toString();
628 if ( contentUri.isEmpty() )
632 const QByteArray subTile = retrieveContent( contentUri, feedback );
633 if ( !subTile.isEmpty() )
640 const auto subTileJson = json::parse( subTile.toStdString() );
641 QMutexLocker locker( &mLock );
642 refineNodeFromJson( it.value(), QUrl( contentUri ), subTileJson );
643 mTileContentFormats.insert(
id, TileContentFormat::Json );
646 catch ( json::parse_error & )
648 QMutexLocker locker( &mLock );
649 mTileContentFormats.insert(
id, TileContentFormat::NotJson );
657 mTileContentFormats.insert(
id, TileContentFormat::NotJson );
662QByteArray QgsCesiumTiledSceneIndex::fetchContent(
const QString &uri,
QgsFeedback *feedback )
666 if ( uri.startsWith(
"http" ) )
668 QNetworkRequest networkRequest = QNetworkRequest( url );
670 networkRequest.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
671 networkRequest.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
true );
673 mHeaders.updateNetworkRequest( networkRequest );
675 if ( QThread::currentThread() == QApplication::instance()->thread() )
679 networkRequest, mAuthCfg,
false, feedback );
699 return reply->data();
702 else if ( url.isLocalFile() && QFile::exists( url.toLocalFile() ) )
704 QFile file( url.toLocalFile() );
705 if ( file.open( QIODevice::ReadOnly ) )
707 return file.readAll();
718QgsCesiumTilesDataProviderSharedData::QgsCesiumTilesDataProviderSharedData()
726 mTileset = json::parse( tileset.toStdString() );
727 if ( !mTileset.contains(
"root" ) )
729 mError = QObject::tr(
"JSON is not a valid Cesium 3D Tiles source (does not contain \"root\" value)" );
733 mLayerMetadata.setType( QStringLiteral(
"dataset" ) );
735 if ( mTileset.contains(
"asset" ) )
737 const auto &asset = mTileset[
"asset" ];
738 if ( asset.contains(
"tilesetVersion" ) )
742 const QString tilesetVersion = QString::fromStdString( asset[
"tilesetVersion"].get<std::string>() );
743 mLayerMetadata.setIdentifier( tilesetVersion );
745 catch ( json::type_error & )
747 QgsDebugError( QStringLiteral(
"Error when parsing tilesetVersion value" ) );
753 new QgsCesiumTiledSceneIndex(
764 const auto &root = mTileset[
"root" ];
776 const auto &rootBoundingVolume = root[
"boundingVolume" ];
779 if ( root.contains(
"transform" ) && !root[
"transform"].is_null() )
781 const auto &transformJson = root[
"transform"];
782 double *ptr = rootTransform.
data();
783 for (
int i = 0; i < 16; ++i )
784 ptr[i] = transformJson[i].get<double>();
787 if ( rootBoundingVolume.contains(
"region" ) )
790 if ( !rootRegion.
isNull() )
795 if ( !mIndex.rootTile().boundingVolume().box().isNull() )
802 mLayerMetadata.setCrs( mSceneCrs );
805 spatialExtent.
bounds = rootRegion;
808 else if ( rootBoundingVolume.contains(
"box" ) )
819 mLayerMetadata.setCrs( mSceneCrs );
822 mBoundingVolume.transform( rootTransform );
826 ct.setBallparkTransformsAreAppropriate(
true );
827 const QgsBox3D rootRegion = mBoundingVolume.bounds( ct );
829 if ( !mIndex.rootTile().boundingVolume().box().isNull() )
834 std::unique_ptr< QgsAbstractGeometry > extent2D( mBoundingVolume.as2DGeometry( ct ) );
835 mExtent = extent2D->boundingBox();
839 QgsDebugError( QStringLiteral(
"Caught transform exception when transforming boundingVolume" ) );
843 spatialExtent.
bounds = mBoundingVolume.bounds();
846 else if ( rootBoundingVolume.contains(
"sphere" ) )
857 mLayerMetadata.setCrs( mSceneCrs );
865 ct.setBallparkTransformsAreAppropriate(
true );
866 const QgsBox3D rootRegion = mBoundingVolume.bounds( ct );
868 if ( !mIndex.rootTile().boundingVolume().box().isNull() )
873 std::unique_ptr< QgsAbstractGeometry > extent2D( mBoundingVolume.as2DGeometry( ct ) );
874 mExtent = extent2D->boundingBox();
878 QgsDebugError( QStringLiteral(
"Caught transform exception when transforming boundingVolume" ) );
882 spatialExtent.
bounds = mBoundingVolume.bounds();
887 mError = QObject::tr(
"JSON is not a valid Cesium 3D Tiles source (unsupported boundingVolume format)" );
893 mLayerMetadata.setExtent( layerExtent );
903QgsCesiumTilesDataProvider::QgsCesiumTilesDataProvider(
const QString &uri,
const ProviderOptions &providerOptions,
Qgis::DataProviderReadFlags flags )
905 , mShared( std::make_shared< QgsCesiumTilesDataProviderSharedData >() )
915QgsCesiumTilesDataProvider::QgsCesiumTilesDataProvider(
const QgsCesiumTilesDataProvider &other )
917 , mIsValid( other.mIsValid )
918 , mAuthCfg( other.mAuthCfg )
919 , mHeaders( other.mHeaders )
922 mShared = other.mShared;
927 return mProviderFlags;
935QgsCesiumTilesDataProvider::~QgsCesiumTilesDataProvider() =
default;
937QgsCesiumTilesDataProvider *QgsCesiumTilesDataProvider::clone()
const
940 return new QgsCesiumTilesDataProvider( *
this );
943bool QgsCesiumTilesDataProvider::init()
948 const QString uri = dataSourceUri();
950 if ( uri.startsWith( QLatin1String(
"ion://" ) ) )
953 const QString assetId = QUrlQuery( url ).queryItemValue( QStringLiteral(
"assetId" ) );
954 const QString accessToken = QUrlQuery( url ).queryItemValue( QStringLiteral(
"accessToken" ) );
956 const QString CESIUM_ION_URL = QStringLiteral(
"https://api.cesium.com/" );
960 const QString assetInfoEndpoint = CESIUM_ION_URL + QStringLiteral(
"v1/assets/%1" ).arg( assetId );
961 QNetworkRequest request = QNetworkRequest( assetInfoEndpoint );
963 mHeaders.updateNetworkRequest( request );
964 if ( !accessToken.isEmpty() )
965 request.setRawHeader( "Authorization", QStringLiteral( "Bearer %1" ).arg( accessToken ).toLocal8Bit() );
968 if ( accessToken.isEmpty() )
969 networkRequest.setAuthCfg( mAuthCfg );
971 switch ( networkRequest.get( request ) )
984 const json assetInfoJson = json::parse( content.
content().toStdString() );
985 if ( assetInfoJson[
"type"] !=
"3DTILES" )
987 appendError(
QgsErrorMessage( tr(
"Only ion 3D Tiles content can be accessed, not %1" ).arg( QString::fromStdString( assetInfoJson[
"type"].get<std::string>() ) ) ) );
991 const QString name = QString::fromStdString( assetInfoJson[
"name"].get<std::string>() );
992 if ( name.compare( QLatin1String(
"Google Photorealistic 3D Tiles" ), Qt::CaseInsensitive ) == 0 )
1000 mShared->mLayerMetadata.setTitle( name );
1001 mShared->mLayerMetadata.setAbstract( QString::fromStdString( assetInfoJson[
"description"].get<std::string>() ) );
1002 const QString attribution = QString::fromStdString( assetInfoJson[
"attribution"].get<std::string>() );
1003 if ( !attribution.isEmpty() )
1004 mShared->mLayerMetadata.setRights( { attribution } );
1006 mShared->mLayerMetadata.setDateTime(
Qgis::MetadataDateType::Created, QDateTime::fromString( QString::fromStdString( assetInfoJson[
"dateAdded"].get<std::string>() ), Qt::DateFormat::ISODate ) );
1011 const QString tileAccessEndpoint = CESIUM_ION_URL + QStringLiteral(
"v1/assets/%1/endpoint" ).arg( assetId );
1012 QNetworkRequest request = QNetworkRequest( tileAccessEndpoint );
1014 mHeaders.updateNetworkRequest( request );
1015 if ( !accessToken.isEmpty() )
1016 request.setRawHeader( "Authorization", QStringLiteral( "Bearer %1" ).arg( accessToken ).toLocal8Bit() );
1019 if ( accessToken.isEmpty() )
1020 networkRequest.setAuthCfg( mAuthCfg );
1022 switch ( networkRequest.get( request ) )
1035 const json tileAccessJson = json::parse( content.
content().toStdString() );
1037 if ( tileAccessJson.contains(
"url" ) )
1039 tileSetUri = QString::fromStdString( tileAccessJson[
"url"].get<std::string>() );
1041 else if ( tileAccessJson.contains(
"options" ) )
1043 const auto &optionsJson = tileAccessJson[
"options"];
1044 if ( optionsJson.contains(
"url" ) )
1046 tileSetUri = QString::fromStdString( optionsJson[
"url"].get<std::string>() );
1050 if ( tileAccessJson.contains(
"accessToken" ) )
1054 mHeaders.insert( QStringLiteral(
"Authorization" ),
1055 QStringLiteral(
"Bearer %1" ).arg( QString::fromStdString( tileAccessJson[
"accessToken"].get<std::string>() ) ) );
1064 tileSetUri = dsUri.
param( QStringLiteral(
"url" ) );
1067 if ( !tileSetUri.isEmpty() )
1069 const QUrl url( tileSetUri );
1071 QNetworkRequest request = QNetworkRequest( url );
1073 mHeaders.updateNetworkRequest( request );
1076 networkRequest.setAuthCfg( mAuthCfg );
1078 switch ( networkRequest.get( request ) )
1092 mShared->initialize( content.
content(), tileSetUri, transformContext(), mAuthCfg, mHeaders );
1099 const QFileInfo fi( dataSourceUri() );
1102 QFile file( dataSourceUri( ) );
1103 if ( file.open( QIODevice::ReadOnly | QIODevice::Text ) )
1105 const QByteArray raw = file.readAll();
1106 mShared->initialize( raw, QUrl::fromLocalFile( dataSourceUri() ), transformContext(), mAuthCfg, mHeaders );
1119 if ( !mShared->mIndex.isValid() )
1121 appendError( mShared->mError );
1132 return mShared->mLayerCrs;
1140 return mShared->mExtent;
1143bool QgsCesiumTilesDataProvider::isValid()
const
1150QString QgsCesiumTilesDataProvider::name()
const
1154 return PROVIDER_KEY;
1157QString QgsCesiumTilesDataProvider::description()
const
1161 return QObject::tr(
"Cesium 3D Tiles" );
1164QString QgsCesiumTilesDataProvider::htmlMetadata()
const
1171 if ( mShared->mTileset.contains(
"asset" ) )
1173 const auto &asset = mShared->mTileset[
"asset" ];
1174 if ( asset.contains(
"version" ) )
1176 const QString version = QString::fromStdString( asset[
"version"].get<std::string>() );
1177 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"3D Tiles Version" ) % QStringLiteral(
"</td><td>%1</a>" ).arg( version ) % QStringLiteral(
"</td></tr>\n" );
1180 if ( asset.contains(
"tilesetVersion" ) )
1184 const QString tilesetVersion = QString::fromStdString( asset[
"tilesetVersion"].get<std::string>() );
1185 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"Tileset Version" ) % QStringLiteral(
"</td><td>%1</a>" ).arg( tilesetVersion ) % QStringLiteral(
"</td></tr>\n" );
1187 catch ( json::type_error & )
1189 QgsDebugError( QStringLiteral(
"Error when parsing tilesetVersion value" ) );
1193 if ( asset.contains(
"generator" ) )
1195 const QString generator = QString::fromStdString( asset[
"generator"].get<std::string>() );
1196 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"Tileset Generator" ) % QStringLiteral(
"</td><td>%1</a>" ).arg( generator ) % QStringLiteral(
"</td></tr>\n" );
1199 if ( mShared->mTileset.contains(
"extensionsRequired" ) )
1201 QStringList extensions;
1202 for (
const auto &item : mShared->mTileset[
"extensionsRequired"] )
1204 extensions << QString::fromStdString( item.get<std::string>() );
1206 if ( !extensions.isEmpty() )
1208 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" );
1211 if ( mShared->mTileset.contains(
"extensionsUsed" ) )
1213 QStringList extensions;
1214 for (
const auto &item : mShared->mTileset[
"extensionsUsed"] )
1216 extensions << QString::fromStdString( item.get<std::string>() );
1218 if ( !extensions.isEmpty() )
1220 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" );
1224 if ( !mShared->mZRange.isInfinite() )
1226 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" );
1239 return mShared->mLayerMetadata;
1249 return mShared->mSceneCrs ;
1260 return mShared ? mShared->mBoundingVolume : nullVolume;
1270 return mShared->mIndex;
1280 return mShared->mZRange;
1288QgsCesiumTilesProviderMetadata::QgsCesiumTilesProviderMetadata():
1293QIcon QgsCesiumTilesProviderMetadata::icon()
const
1300 return new QgsCesiumTilesDataProvider( uri, options, flags );
1305 const QVariantMap parts = decodeUri( uri );
1306 if ( parts.value( QStringLiteral(
"file-name" ) ).toString().compare( QLatin1String(
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
1321int QgsCesiumTilesProviderMetadata::priorityForUri(
const QString &uri )
const
1323 const QVariantMap parts = decodeUri( uri );
1324 if ( parts.value( QStringLiteral(
"file-name" ) ).toString().compare( QLatin1String(
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
1330QList<Qgis::LayerType> QgsCesiumTilesProviderMetadata::validLayerTypesForUri(
const QString &uri )
const
1332 const QVariantMap parts = decodeUri( uri );
1333 if ( parts.value( QStringLiteral(
"file-name" ) ).toString().compare( QLatin1String(
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
1336 return QList< Qgis::LayerType>();
1339QVariantMap QgsCesiumTilesProviderMetadata::decodeUri(
const QString &uri )
const
1341 QVariantMap uriComponents;
1342 QUrl url = QUrl::fromUserInput( uri );
1343 uriComponents.insert( QStringLiteral(
"file-name" ), url.fileName() );
1344 uriComponents.insert( QStringLiteral(
"path" ), uri );
1345 return uriComponents;
1361 return QObject::tr(
"Cesium 3D Tiles" ) + QStringLiteral(
" (tileset.json TILESET.JSON)" );
1368 return FileBasedUris;
1371QList<Qgis::LayerType> QgsCesiumTilesProviderMetadata::supportedLayerTypes()
const
1376QString QgsCesiumTilesProviderMetadata::encodeUri(
const QVariantMap &parts )
const
1378 const QString path = parts.value( QStringLiteral(
"path" ) ).toString();
1384 return ProviderMetadataCapability::LayerTypesForUri
1385 | ProviderMetadataCapability::PriorityForUri
1386 | ProviderMetadataCapability::QuerySublayers;
Provides global constants and enumerations 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.
@ Is3DBasemapSource
Associated source should be considered a '3D basemap' layer. See Qgis::MapLayerProperty::Is3DBasemapL...
@ IsBasemapSource
Associated source should be considered a 'basemap' layer. See Qgis::MapLayerProperty::IsBasemapLayer.
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.
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.
Stores the component parts of a 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.
Represents a 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.
A convenience class that simplifies locking and unlocking QReadWriteLocks.
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...
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
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.