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.