42#include <QNetworkRequest> 
   43#include <QJsonDocument> 
   46#include <QRegularExpression> 
   47#include <QRecursiveMutex> 
   49#include <QApplication> 
   50#include <nlohmann/json.hpp> 
   54#define PROVIDER_KEY QStringLiteral( "cesiumtiles" ) 
   55#define PROVIDER_DESCRIPTION QStringLiteral( "Cesium 3D Tiles data provider" ) 
   66static QString appendQueryFromBaseUrl( 
const QString &contentUri, 
const QUrl &baseUrl )
 
   68  QUrlQuery contentQuery( QUrl( contentUri ).query() );
 
   69  const QList<QPair<QString, QString>> baseUrlQueryItems = QUrlQuery( baseUrl.query() ).queryItems();
 
   70  for ( 
const QPair<QString, QString> &kv : baseUrlQueryItems )
 
   72    contentQuery.addQueryItem( kv.first, kv.second );
 
   74  QUrl newContentUrl( contentUri );
 
   75  newContentUrl.setQuery( contentQuery );
 
   76  return newContentUrl.toString();
 
   84    QgsCesiumTiledSceneIndex(
 
   87      const QString &authCfg,
 
   91    std::unique_ptr< QgsTiledSceneTile > tileFromJson( 
const json &node, 
const QUrl &baseUrl, 
const QgsTiledSceneTile *parent, 
Qgis::Axis gltfUpAxis );
 
   93    void refineNodeFromJson( 
QgsTiledSceneNode *node, 
const QUrl &baseUrl, 
const json &json );
 
   97    long long parentTileId( 
long long id ) const final;
 
   98    QVector< 
long long > childTileIds( 
long long id ) const final;
 
  100    Qgis::TileChildrenAvailability childAvailability( 
long long id ) const final;
 
  101    bool fetchHierarchy( 
long long id, 
QgsFeedback *feedback = 
nullptr ) final;
 
  105    QByteArray fetchContent( const QString &uri, 
QgsFeedback *feedback = 
nullptr ) final;
 
  109    enum class TileContentFormat
 
  115    mutable QRecursiveMutex mLock;
 
  117    std::unique_ptr< QgsTiledSceneNode > mRootNode;
 
  118    QMap< long long, QgsTiledSceneNode * > mNodeMap;
 
  119    QMap< long long, TileContentFormat > mTileContentFormats;
 
  122    long long mNextTileId = 0;
 
  126class QgsCesiumTilesDataProviderSharedData
 
  129    QgsCesiumTilesDataProviderSharedData();
 
  130    void initialize( 
const QString &tileset,
 
  133                     const QString &authCfg,
 
  141    nlohmann::json mTileset;
 
  148    QReadWriteLock mReadWriteLock;
 
  159  const std::string gltfUpAxisString = json.get<std::string>();
 
  160  if ( gltfUpAxisString == 
"z" || gltfUpAxisString == 
"Z" )
 
  164  else if ( gltfUpAxisString == 
"y" || gltfUpAxisString == 
"Y" )
 
  168  else if ( gltfUpAxisString == 
"x" || gltfUpAxisString == 
"X" )
 
  172  QgsDebugError( QStringLiteral( 
"Unsupported gltfUpAxis value: %1" ).arg( QString::fromStdString( gltfUpAxisString ) ) );
 
  177  : mTransformContext( transformContext )
 
  178  , mAuthCfg( authCfg )
 
  179  , mHeaders( headers )
 
  182  if ( tileset.contains( 
"asset" ) )
 
  184    const auto &assetJson = tileset[
"asset"];
 
  185    if ( assetJson.contains( 
"gltfUpAxis" ) )
 
  187      gltfUpAxis = axisFromJson( assetJson[
"gltfUpAxis"] );
 
  191  mRootNode.reset( nodeFromJson( tileset[ 
"root" ], rootUrl, 
nullptr, gltfUpAxis ) );
 
  194std::unique_ptr< QgsTiledSceneTile > QgsCesiumTiledSceneIndex::tileFromJson( 
const json &json, 
const QUrl &baseUrl, 
const QgsTiledSceneTile *parent, 
Qgis::Axis gltfUpAxis )
 
  196  std::unique_ptr< QgsTiledSceneTile > tile = std::make_unique< QgsTiledSceneTile >( mNextTileId++ );
 
  198  tile->setBaseUrl( baseUrl );
 
  199  tile->setMetadata( {{ QStringLiteral( 
"gltfUpAxis" ), 
static_cast< int >( gltfUpAxis ) }} );
 
  202  if ( json.contains( 
"transform" ) && !json[
"transform"].is_null() )
 
  204    const auto &transformJson = json[
"transform"];
 
  205    double *ptr = transform.
data();
 
  206    for ( 
int i = 0; i < 16; ++i )
 
  207      ptr[i] = transformJson[i].get<double>();
 
  211      transform = *parent->
transform() * transform;
 
  214  else if ( parent && parent->
transform() )
 
  219    tile->setTransform( transform );
 
  221  const auto &boundingVolume = json[ 
"boundingVolume" ];
 
  223  if ( boundingVolume.contains( 
"region" ) )
 
  226    if ( !rootRegion.
isNull() )
 
  228      if ( rootRegion.
width() > 20 || rootRegion.
height() > 20 )
 
  235        QVector< QgsVector3D > corners = rootRegion.
corners();
 
  243        for ( 
int i = 0; i < 8; ++i )
 
  246          x.append( corner.
x() );
 
  247          y.append( corner.
y() );
 
  248          z.append( corner.
z() );
 
  251        ct.setBallparkTransformsAreAppropriate( 
true );
 
  254          ct.transformInPlace( x, y, z );
 
  258          QgsDebugError( QStringLiteral( 
"Cannot transform region bounding volume" ) );
 
  261        const auto minMaxX = std::minmax_element( x.constBegin(), x.constEnd() );
 
  262        const auto minMaxY = std::minmax_element( y.constBegin(), y.constEnd() );
 
  263        const auto minMaxZ = std::minmax_element( z.constBegin(), z.constEnd() );
 
  270  else if ( boundingVolume.contains( 
"box" ) )
 
  280  else if ( boundingVolume.contains( 
"sphere" ) )
 
  291    QgsDebugError( QStringLiteral( 
"unsupported boundingVolume format" ) );
 
  294  tile->setBoundingVolume( volume );
 
  296  if ( json.contains( 
"geometricError" ) )
 
  297    tile->setGeometricError( json[
"geometricError"].get< double >() );
 
  298  if ( json.contains( 
"refine" ) )
 
  300    if ( json[
"refine"] == 
"ADD" )
 
  302    else if ( json[
"refine"] == 
"REPLACE" )
 
  311  if ( json.contains( 
"content" ) && !json[
"content"].is_null() )
 
  313    const auto &contentJson = json[
"content"];
 
  317    if ( contentJson.contains( 
"uri" ) && !contentJson[
"uri"].is_null() )
 
  319      QString relativeUri = QString::fromStdString( contentJson[
"uri"].get<std::string>() );
 
  320      contentUri = baseUrl.resolved( QUrl( relativeUri ) ).toString();
 
  322      if ( baseUrl.hasQuery() && QUrl( relativeUri ).isRelative() )
 
  323        contentUri = appendQueryFromBaseUrl( contentUri, baseUrl );
 
  325    else if ( contentJson.contains( 
"url" ) && !contentJson[
"url"].is_null() )
 
  327      QString relativeUri = QString::fromStdString( contentJson[
"url"].get<std::string>() );
 
  328      contentUri = baseUrl.resolved( QUrl( relativeUri ) ).toString();
 
  330      if ( baseUrl.hasQuery() && QUrl( relativeUri ).isRelative() )
 
  331        contentUri = appendQueryFromBaseUrl( contentUri, baseUrl );
 
  333    if ( !contentUri.isEmpty() )
 
  335      tile->setResources( {{ QStringLiteral( 
"content" ), contentUri } } );
 
  344  std::unique_ptr< QgsTiledSceneTile > tile = tileFromJson( json, baseUrl, parent ? parent->
tile() : nullptr, gltfUpAxis );
 
  345  std::unique_ptr< QgsTiledSceneNode > newNode = std::make_unique< QgsTiledSceneNode >( tile.release() );
 
  346  mNodeMap.insert( newNode->tile()->id(), newNode.get() );
 
  351  if ( json.contains( 
"children" ) )
 
  353    for ( 
const auto &childJson : json[
"children"] )
 
  355      nodeFromJson( childJson, baseUrl, newNode.get(), gltfUpAxis );
 
  359  return newNode.release();
 
  362void QgsCesiumTiledSceneIndex::refineNodeFromJson( 
QgsTiledSceneNode *node, 
const QUrl &baseUrl, 
const json &json )
 
  364  const auto &rootTileJson = json[
"root"];
 
  367  if ( json.contains( 
"asset" ) )
 
  369    const auto &assetJson = json[
"asset"];
 
  370    if ( assetJson.contains( 
"gltfUpAxis" ) )
 
  372      gltfUpAxis = axisFromJson( assetJson[
"gltfUpAxis"] );
 
  376  std::unique_ptr< QgsTiledSceneTile > newTile = tileFromJson( rootTileJson, baseUrl, node->
tile(), gltfUpAxis );
 
  386  if ( newTile->transform() )
 
  389  if ( rootTileJson.contains( 
"children" ) )
 
  391    for ( 
const auto &childJson : rootTileJson[
"children"] )
 
  393      nodeFromJson( childJson, baseUrl, node, gltfUpAxis );
 
  400  QMutexLocker locker( &mLock );
 
  406  QMutexLocker locker( &mLock );
 
  407  auto it = mNodeMap.constFind( 
id );
 
  408  if ( it != mNodeMap.constEnd() )
 
  410    return *( it.value()->tile() );
 
  416long long QgsCesiumTiledSceneIndex::parentTileId( 
long long id )
 const 
  418  QMutexLocker locker( &mLock );
 
  419  auto it = mNodeMap.constFind( 
id );
 
  420  if ( it != mNodeMap.constEnd() )
 
  424      return parent->
tile()->
id();
 
  431QVector< long long > QgsCesiumTiledSceneIndex::childTileIds( 
long long id )
 const 
  433  QMutexLocker locker( &mLock );
 
  434  auto it = mNodeMap.constFind( 
id );
 
  435  if ( it != mNodeMap.constEnd() )
 
  437    QVector< long long > childIds;
 
  438    const QList< QgsTiledSceneNode * > children = it.value()->children();
 
  439    childIds.reserve( children.size() );
 
  442      childIds << child->tile()->id();
 
  452  QVector< long long > results;
 
  455  traverseNode = [&request, &traverseNode, &results, 
this]( 
QgsTiledSceneNode * node )
 
  471      QList< QgsTiledSceneNode * > children = node->
children();
 
  472      if ( children.empty() )
 
  474        switch ( childAvailability( tile->
id() ) )
 
  484              if ( fetchHierarchy( tile->
id() ), request.
feedback() )
 
  499        traverseNode( child );
 
  506          results << tile->
id();
 
  511          if ( children.empty() )
 
  512            results << tile->
id();
 
  518      results << tile->
id();
 
  523  QMutexLocker locker( &mLock );
 
  527      traverseNode( mRootNode.get() );
 
  532    if ( it != mNodeMap.constEnd() )
 
  534      traverseNode( it.value() );
 
  544  QMutexLocker locker( &mLock );
 
  546    auto it = mNodeMap.constFind( 
id );
 
  547    if ( it == mNodeMap.constEnd() )
 
  550    if ( !it.value()->children().isEmpty() )
 
  553    contentUri = it.value()->tile()->resources().value( QStringLiteral( 
"content" ) ).toString();
 
  557    auto it = mTileContentFormats.constFind( 
id );
 
  558    if ( it != mTileContentFormats.constEnd() )
 
  560      switch ( it.value() )
 
  562        case TileContentFormat::NotJson:
 
  564        case TileContentFormat::Json:
 
  571  if ( contentUri.isEmpty() )
 
  581  const thread_local QRegularExpression isJsonRx( QStringLiteral( 
".*\\.json(?:\\?.*)?$" ), QRegularExpression::PatternOption::CaseInsensitiveOption );
 
  582  if ( isJsonRx.match( contentUri ).hasMatch() )
 
  586  const thread_local QRegularExpression antiCandidateRx( QStringLiteral( 
".*\\.(gltf|glb|b3dm|i3dm|pnts|cmpt|bin|glbin|glbuf|png|jpeg|jpg)(?:\\?.*)?$" ), QRegularExpression::PatternOption::CaseInsensitiveOption );
 
  587  if ( antiCandidateRx.match( contentUri ).hasMatch() )
 
  595bool QgsCesiumTiledSceneIndex::fetchHierarchy( 
long long id, 
QgsFeedback *feedback )
 
  597  QMutexLocker locker( &mLock );
 
  598  auto it = mNodeMap.constFind( 
id );
 
  599  if ( it == mNodeMap.constEnd() )
 
  605    auto it = mTileContentFormats.constFind( 
id );
 
  606    if ( it != mTileContentFormats.constEnd() )
 
  608      switch ( it.value() )
 
  610        case TileContentFormat::NotJson:
 
  612        case TileContentFormat::Json:
 
  618  const QString contentUri = it.value()->tile()->resources().value( QStringLiteral( 
"content" ) ).toString();
 
  621  if ( contentUri.isEmpty() )
 
  625  const QByteArray subTile = retrieveContent( contentUri, feedback );
 
  626  if ( !subTile.isEmpty() )
 
  633      const auto subTileJson = json::parse( subTile.toStdString() );
 
  634      QMutexLocker locker( &mLock );
 
  635      refineNodeFromJson( it.value(), QUrl( contentUri ), subTileJson );
 
  636      mTileContentFormats.insert( 
id, TileContentFormat::Json );
 
  639    catch ( json::parse_error & )
 
  641      QMutexLocker locker( &mLock );
 
  642      mTileContentFormats.insert( 
id, TileContentFormat::NotJson );
 
  650    mTileContentFormats.insert( 
id, TileContentFormat::NotJson );
 
  655QByteArray QgsCesiumTiledSceneIndex::fetchContent( 
const QString &uri, 
QgsFeedback *feedback )
 
  659  if ( uri.startsWith( 
"http" ) )
 
  661    QNetworkRequest networkRequest = QNetworkRequest( url );
 
  663    networkRequest.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
 
  664    networkRequest.setAttribute( QNetworkRequest::CacheSaveControlAttribute, 
true );
 
  666    mHeaders.updateNetworkRequest( networkRequest );
 
  668    if ( QThread::currentThread() == QApplication::instance()->thread() )
 
  672                                             networkRequest, mAuthCfg, 
false, feedback );
 
  692      return reply->data();
 
  695  else if ( url.isLocalFile() && QFile::exists( url.toLocalFile() ) )
 
  697    QFile file( url.toLocalFile() );
 
  698    if ( file.open( QIODevice::ReadOnly ) )
 
  700      return file.readAll();
 
  711QgsCesiumTilesDataProviderSharedData::QgsCesiumTilesDataProviderSharedData()
 
  719  mTileset = json::parse( tileset.toStdString() );
 
  720  if ( !mTileset.contains( 
"root" ) )
 
  722    mError = QObject::tr( 
"JSON is not a valid Cesium 3D Tiles source (does not contain \"root\" value)" );
 
  726  mLayerMetadata.setType( QStringLiteral( 
"dataset" ) );
 
  728  if ( mTileset.contains( 
"asset" ) )
 
  730    const auto &asset = mTileset[ 
"asset" ];
 
  731    if ( asset.contains( 
"tilesetVersion" ) )
 
  735        const QString tilesetVersion = QString::fromStdString( asset[
"tilesetVersion"].get<std::string>() );
 
  736        mLayerMetadata.setIdentifier( tilesetVersion );
 
  738      catch ( json::type_error & )
 
  740        QgsDebugError( QStringLiteral( 
"Error when parsing tilesetVersion value" ) );
 
  746             new QgsCesiumTiledSceneIndex(
 
  757    const auto &root = mTileset[ 
"root" ];
 
  769      const auto &rootBoundingVolume = root[ 
"boundingVolume" ];
 
  772      if ( root.contains( 
"transform" ) && !root[
"transform"].is_null() )
 
  774        const auto &transformJson = root[
"transform"];
 
  775        double *ptr = rootTransform.
data();
 
  776        for ( 
int i = 0; i < 16; ++i )
 
  777          ptr[i] = transformJson[i].get<double>();
 
  780      if ( rootBoundingVolume.contains( 
"region" ) )
 
  783        if ( !rootRegion.
isNull() )
 
  788          if ( !mIndex.rootTile().boundingVolume().box().isNull() )
 
  795          mLayerMetadata.setCrs( mSceneCrs );
 
  798          spatialExtent.
bounds = rootRegion;
 
  801      else if ( rootBoundingVolume.contains( 
"box" ) )
 
  812          mLayerMetadata.setCrs( mSceneCrs );
 
  815          mBoundingVolume.transform( rootTransform );
 
  819            ct.setBallparkTransformsAreAppropriate( 
true );
 
  820            const QgsBox3D rootRegion = mBoundingVolume.bounds( ct );
 
  822            if ( !mIndex.rootTile().boundingVolume().box().isNull() )
 
  827            std::unique_ptr< QgsAbstractGeometry > extent2D( mBoundingVolume.as2DGeometry( ct ) );
 
  828            mExtent = extent2D->boundingBox();
 
  832            QgsDebugError( QStringLiteral( 
"Caught transform exception when transforming boundingVolume" ) );
 
  836          spatialExtent.
bounds = mBoundingVolume.bounds();
 
  839      else if ( rootBoundingVolume.contains( 
"sphere" ) )
 
  850          mLayerMetadata.setCrs( mSceneCrs );
 
  858            ct.setBallparkTransformsAreAppropriate( 
true );
 
  859            const QgsBox3D rootRegion = mBoundingVolume.bounds( ct );
 
  861            if ( !mIndex.rootTile().boundingVolume().box().isNull() )
 
  866            std::unique_ptr< QgsAbstractGeometry > extent2D( mBoundingVolume.as2DGeometry( ct ) );
 
  867            mExtent = extent2D->boundingBox();
 
  871            QgsDebugError( QStringLiteral( 
"Caught transform exception when transforming boundingVolume" ) );
 
  875          spatialExtent.
bounds = mBoundingVolume.bounds();
 
  880        mError = QObject::tr( 
"JSON is not a valid Cesium 3D Tiles source (unsupported boundingVolume format)" );
 
  886      mLayerMetadata.setExtent( layerExtent );
 
  896QgsCesiumTilesDataProvider::QgsCesiumTilesDataProvider( 
const QString &uri, 
const ProviderOptions &providerOptions, ReadFlags flags )
 
  898  , mShared( std::make_shared< QgsCesiumTilesDataProviderSharedData >() )
 
  908QgsCesiumTilesDataProvider::QgsCesiumTilesDataProvider( 
const QgsCesiumTilesDataProvider &other )
 
  910  , mIsValid( other.mIsValid )
 
  911  , mAuthCfg( other.mAuthCfg )
 
  912  , mHeaders( other.mHeaders )
 
  915  mShared = other.mShared;
 
  928QgsCesiumTilesDataProvider::~QgsCesiumTilesDataProvider() = 
default;
 
  930QgsCesiumTilesDataProvider *QgsCesiumTilesDataProvider::clone()
 const 
  933  return new QgsCesiumTilesDataProvider( *
this );
 
  936bool QgsCesiumTilesDataProvider::init()
 
  941  const QString uri = dataSourceUri();
 
  943  if ( uri.startsWith( QLatin1String( 
"ion://" ) ) )
 
  946    const QString assetId = QUrlQuery( url ).queryItemValue( QStringLiteral( 
"assetId" ) );
 
  947    const QString accessToken = QUrlQuery( url ).queryItemValue( QStringLiteral( 
"accessToken" ) );
 
  949    const QString CESIUM_ION_URL = QStringLiteral( 
"https://api.cesium.com/" );
 
  953      const QString assetInfoEndpoint = CESIUM_ION_URL + QStringLiteral( 
"v1/assets/%1" ).arg( assetId );
 
  954      QNetworkRequest request = QNetworkRequest( assetInfoEndpoint );
 
  956      mHeaders.updateNetworkRequest( request );
 
  957      if ( !accessToken.isEmpty() )
 
  958        request.setRawHeader( "Authorization", QStringLiteral( "Bearer %1" ).arg( accessToken ).toLocal8Bit() );
 
  961      if ( accessToken.isEmpty() )
 
  962        networkRequest.setAuthCfg( mAuthCfg );
 
  964      switch ( networkRequest.get( request ) )
 
  977      const json assetInfoJson  = json::parse( content.
content().toStdString() );
 
  978      if ( assetInfoJson[
"type"] != 
"3DTILES" )
 
  980        appendError( 
QgsErrorMessage( tr( 
"Only ion 3D Tiles content can be accessed, not %1" ).arg( QString::fromStdString( assetInfoJson[
"type"].get<std::string>() ) ) ) );
 
  984      mShared->mLayerMetadata.setTitle( QString::fromStdString( assetInfoJson[
"name"].get<std::string>() ) );
 
  985      mShared->mLayerMetadata.setAbstract( QString::fromStdString( assetInfoJson[
"description"].get<std::string>() ) );
 
  986      const QString attribution = QString::fromStdString( assetInfoJson[
"attribution"].get<std::string>() );
 
  987      if ( !attribution.isEmpty() )
 
  988        mShared->mLayerMetadata.setRights( { attribution } );
 
  990      mShared->mLayerMetadata.setDateTime( 
Qgis::MetadataDateType::Created, QDateTime::fromString( QString::fromStdString( assetInfoJson[
"dateAdded"].get<std::string>() ), Qt::DateFormat::ISODate ) );
 
  995      const QString tileAccessEndpoint = CESIUM_ION_URL + QStringLiteral( 
"v1/assets/%1/endpoint" ).arg( assetId );
 
  996      QNetworkRequest request = QNetworkRequest( tileAccessEndpoint );
 
  998      mHeaders.updateNetworkRequest( request );
 
  999      if ( !accessToken.isEmpty() )
 
 1000        request.setRawHeader( "Authorization", QStringLiteral( "Bearer %1" ).arg( accessToken ).toLocal8Bit() );
 
 1003      if ( accessToken.isEmpty() )
 
 1004        networkRequest.setAuthCfg( mAuthCfg );
 
 1006      switch ( networkRequest.get( request ) )
 
 1019      const json tileAccessJson = json::parse( content.
content().toStdString() );
 
 1021      if ( tileAccessJson.contains( 
"url" ) )
 
 1023        tileSetUri = QString::fromStdString( tileAccessJson[
"url"].get<std::string>() );
 
 1025      else if ( tileAccessJson.contains( 
"options" ) )
 
 1027        const auto &optionsJson = tileAccessJson[
"options"];
 
 1028        if ( optionsJson.contains( 
"url" ) )
 
 1030          tileSetUri = QString::fromStdString( optionsJson[
"url"].get<std::string>() );
 
 1034      if ( tileAccessJson.contains( 
"accessToken" ) )
 
 1038        mHeaders.insert( QStringLiteral( 
"Authorization" ),
 
 1039                         QStringLiteral( 
"Bearer %1" ).arg( QString::fromStdString( tileAccessJson[
"accessToken"].get<std::string>() ) ) );
 
 1048    tileSetUri = dsUri.
param( QStringLiteral( 
"url" ) );
 
 1051  if ( !tileSetUri.isEmpty() )
 
 1053    const QUrl url( tileSetUri );
 
 1055    QNetworkRequest request = QNetworkRequest( url );
 
 1057    mHeaders.updateNetworkRequest( request );
 
 1060    networkRequest.setAuthCfg( mAuthCfg );
 
 1062    switch ( networkRequest.get( request ) )
 
 1076    mShared->initialize( content.
content(), tileSetUri, transformContext(), mAuthCfg, mHeaders );
 
 1083    const QFileInfo fi( dataSourceUri() );
 
 1086      QFile file( dataSourceUri( ) );
 
 1087      if ( file.open( QIODevice::ReadOnly | QIODevice::Text ) )
 
 1089        const QByteArray raw = file.readAll();
 
 1090        mShared->initialize( raw, QUrl::fromLocalFile( dataSourceUri() ), transformContext(), mAuthCfg, mHeaders );
 
 1103  if ( !mShared->mIndex.isValid() )
 
 1105    appendError( mShared->mError );
 
 1116  return mShared->mLayerCrs;
 
 1124  return mShared->mExtent;
 
 1127bool QgsCesiumTilesDataProvider::isValid()
 const 
 1134QString QgsCesiumTilesDataProvider::name()
 const 
 1138  return PROVIDER_KEY;
 
 1141QString QgsCesiumTilesDataProvider::description()
 const 
 1145  return QObject::tr( 
"Cesium 3D Tiles" );
 
 1148QString QgsCesiumTilesDataProvider::htmlMetadata()
 const 
 1155  if ( mShared->mTileset.contains( 
"asset" ) )
 
 1157    const auto &asset = mShared->mTileset[ 
"asset" ];
 
 1158    if ( asset.contains( 
"version" ) )
 
 1160      const QString version = QString::fromStdString( asset[
"version"].get<std::string>() );
 
 1161      metadata += QStringLiteral( 
"<tr><td class=\"highlight\">" ) % tr( 
"3D Tiles Version" ) % QStringLiteral( 
"</td><td>%1</a>" ).arg( version ) % QStringLiteral( 
"</td></tr>\n" );
 
 1164    if ( asset.contains( 
"tilesetVersion" ) )
 
 1168        const QString tilesetVersion = QString::fromStdString( asset[
"tilesetVersion"].get<std::string>() );
 
 1169        metadata += QStringLiteral( 
"<tr><td class=\"highlight\">" ) % tr( 
"Tileset Version" ) % QStringLiteral( 
"</td><td>%1</a>" ).arg( tilesetVersion ) % QStringLiteral( 
"</td></tr>\n" );
 
 1171      catch ( json::type_error & )
 
 1173        QgsDebugError( QStringLiteral( 
"Error when parsing tilesetVersion value" ) );
 
 1177    if ( asset.contains( 
"generator" ) )
 
 1179      const QString generator = QString::fromStdString( asset[
"generator"].get<std::string>() );
 
 1180      metadata += QStringLiteral( 
"<tr><td class=\"highlight\">" ) % tr( 
"Tileset Generator" ) % QStringLiteral( 
"</td><td>%1</a>" ).arg( generator ) % QStringLiteral( 
"</td></tr>\n" );
 
 1183  if ( mShared->mTileset.contains( 
"extensionsRequired" ) )
 
 1185    QStringList extensions;
 
 1186    for ( 
const auto &item : mShared->mTileset[
"extensionsRequired"] )
 
 1188      extensions << QString::fromStdString( item.get<std::string>() );
 
 1190    if ( !extensions.isEmpty() )
 
 1192      metadata += QStringLiteral( 
"<tr><td class=\"highlight\">" ) % tr( 
"Extensions Required" ) % QStringLiteral( 
"</td><td><ul><li>%1</li></ul></a>" ).arg( extensions.join( QLatin1String( 
"</li><li>" ) ) ) % QStringLiteral( 
"</td></tr>\n" );
 
 1195  if ( mShared->mTileset.contains( 
"extensionsUsed" ) )
 
 1197    QStringList extensions;
 
 1198    for ( 
const auto &item : mShared->mTileset[
"extensionsUsed"] )
 
 1200      extensions << QString::fromStdString( item.get<std::string>() );
 
 1202    if ( !extensions.isEmpty() )
 
 1204      metadata += QStringLiteral( 
"<tr><td class=\"highlight\">" ) % tr( 
"Extensions Used" ) % QStringLiteral( 
"</td><td><ul><li>%1</li></ul></a>" ).arg( extensions.join( QLatin1String( 
"</li><li>" ) ) ) % QStringLiteral( 
"</td></tr>\n" );
 
 1208  if ( !mShared->mZRange.isInfinite() )
 
 1210    metadata += QStringLiteral( 
"<tr><td class=\"highlight\">" ) % tr( 
"Z Range" ) % QStringLiteral( 
"</td><td>%1 - %2</a>" ).arg( QLocale().toString( mShared->mZRange.lower() ), QLocale().toString( mShared->mZRange.upper() ) ) % QStringLiteral( 
"</td></tr>\n" );
 
 1223  return mShared->mLayerMetadata;
 
 1233  return mShared->mSceneCrs ;
 
 1244  return mShared ? mShared->mBoundingVolume : nullVolume;
 
 1254  return mShared->mIndex;
 
 1264  return mShared->mZRange;
 
 1272QgsCesiumTilesProviderMetadata::QgsCesiumTilesProviderMetadata():
 
 1277QIcon QgsCesiumTilesProviderMetadata::icon()
 const 
 1284  return new QgsCesiumTilesDataProvider( uri, options, flags );
 
 1289  const QVariantMap parts = decodeUri( uri );
 
 1290  if ( parts.value( QStringLiteral( 
"file-name" ) ).toString().compare( QLatin1String( 
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
 
 1305int QgsCesiumTilesProviderMetadata::priorityForUri( 
const QString &uri )
 const 
 1307  const QVariantMap parts = decodeUri( uri );
 
 1308  if ( parts.value( QStringLiteral( 
"file-name" ) ).toString().compare( QLatin1String( 
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
 
 1314QList<Qgis::LayerType> QgsCesiumTilesProviderMetadata::validLayerTypesForUri( 
const QString &uri )
 const 
 1316  const QVariantMap parts = decodeUri( uri );
 
 1317  if ( parts.value( QStringLiteral( 
"file-name" ) ).toString().compare( QLatin1String( 
"tileset.json" ), Qt::CaseInsensitive ) == 0 )
 
 1320  return QList< Qgis::LayerType>();
 
 1323QVariantMap QgsCesiumTilesProviderMetadata::decodeUri( 
const QString &uri )
 const 
 1325  QVariantMap uriComponents;
 
 1326  QUrl url = QUrl::fromUserInput( uri );
 
 1327  uriComponents.insert( QStringLiteral( 
"file-name" ), url.fileName() );
 
 1328  uriComponents.insert( QStringLiteral( 
"path" ), uri );
 
 1329  return uriComponents;
 
 1345      return QObject::tr( 
"Cesium 3D Tiles" ) + QStringLiteral( 
" (tileset.json TILESET.JSON)" );
 
 1352  return FileBasedUris;
 
 1355QList<Qgis::LayerType> QgsCesiumTilesProviderMetadata::supportedLayerTypes()
 const 
 1360QString QgsCesiumTilesProviderMetadata::encodeUri( 
const QVariantMap &parts )
 const 
 1362  const QString path = parts.value( QStringLiteral( 
"path" ) ).toString();
 
 1368  return ProviderMetadataCapability::LayerTypesForUri
 
 1369         | ProviderMetadataCapability::PriorityForUri
 
 1370         | ProviderMetadataCapability::QuerySublayers;
 
The Qgis class provides global constants for use throughout the application.
 
QFlags< TiledSceneProviderCapability > TiledSceneProviderCapabilities
Tiled scene data provider capabilities.
 
QFlags< DataProviderFlag > DataProviderFlags
Data provider flags.
 
FileFilterType
Type of file filters.
 
@ TiledScene
Tiled scene layers (since QGIS 3.34)
 
@ VectorTile
Vector tile layers (since QGIS 3.32)
 
@ MeshDataset
Mesh datasets.
 
@ PointCloud
Point clouds (since QGIS 3.18)
 
@ FastExtent2D
Provider's 2D extent retrieval via QgsDataProvider::extent() is always guaranteed to be trivial/fast ...
 
@ ReadLayerMetadata
Provider can read layer metadata from data store. See QgsDataProvider::layerMetadata()
 
QFlags< SublayerQueryFlag > SublayerQueryFlags
Sublayer query flags.
 
TileChildrenAvailability
Possible availability states for a tile's children.
 
@ Available
Tile children are already available.
 
@ NeedFetching
Tile has children, but they are not yet available and must be fetched.
 
@ NoChildren
Tile is known to have no children.
 
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
 
@ NoHierarchyFetch
Do not allow hierarchy fetching when hierarchy is not currently available. Avoids network requests,...
 
@ Additive
When tile is refined its content should be used alongside its children simultaneously.
 
@ Replacement
When tile is refined then its children should be used in place of itself.
 
An abstract base class for tiled scene data provider indices.
 
virtual QgsTiledSceneTile rootTile() const =0
Returns the root tile for the index.
 
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
 
static QgsTileDownloadManager * tileDownloadManager()
Returns the application's tile download manager, used for download of map tiles when rendering.
 
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
 
bool updateNetworkRequest(QNetworkRequest &request, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkRequest with an authentication config.
 
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
 
@ NetworkError
A network error occurred.
 
@ ServerExceptionError
An exception was raised by the server.
 
@ NoError
No error was encountered.
 
@ TimeoutError
Timeout was reached before a reply was received.
 
A 3-dimensional box composed of x, y, z coordinates.
 
double zMaximum() const
Returns the maximum z value.
 
QgsRectangle toRectangle() const
Converts the box to a 2D rectangle.
 
QVector< QgsVector3D > corners() const
Returns an array of all box corners as 3D vectors.
 
double width() const
Returns the width of the box.
 
double zMinimum() const
Returns the minimum z value.
 
double height() const
Returns the height of the box.
 
bool isNull() const
Test if the box is null (holding no spatial information).
 
static QgsSphere parseSphere(const json &sphere)
Parses a sphere object from a Cesium JSON document.
 
static QgsOrientedBox3D parseBox(const json &box)
Parses a box object from a Cesium JSON document to an oriented bounding box.
 
static QgsBox3D parseRegion(const json ®ion)
Parses a region object from a Cesium JSON object to a 3D box.
 
static QgsSphere transformSphere(const QgsSphere &sphere, const QgsMatrix4x4 &transform)
Applies a transform to a sphere.
 
This class represents a coordinate reference system (CRS).
 
Contains information about the context in which a coordinate transform is executed.
 
Custom exception class for Coordinate Reference System related exceptions.
 
QFlags< ReadFlag > ReadFlags
 
Class for storing the component parts of a RDBMS data source URI (e.g.
 
void setEncodedUri(const QByteArray &uri)
Sets the complete encoded uri.
 
QgsHttpHeaders httpHeaders() const
Returns http headers.
 
QString param(const QString &key) const
Returns a generic parameter value corresponding to the specified key.
 
QString authConfigId() const
Returns any associated authentication configuration ID stored in the URI.
 
QgsRange which stores a range of double values.
 
QgsErrorMessage represents single error message.
 
Base class for feedback objects to be used for cancellation of something running in a worker thread.
 
bool isCanceled() const
Tells whether the operation has been canceled already.
 
void canceled()
Internal routines can connect to this signal if they use event loop.
 
A simple 4x4 matrix implementation useful for transformation in 3D space.
 
bool isIdentity() const
Returns whether this matrix is an identity matrix.
 
double * data()
Returns pointer to the matrix data (stored in column-major order)
 
static QgsNetworkReplyContent blockingGet(QNetworkRequest &request, const QString &authCfg=QString(), bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Posts a GET request to obtain the contents of the target request and returns a new QgsNetworkReplyCon...
 
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
 
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
 
QByteArray content() const
Returns the reply content.
 
Represents a oriented (rotated) box in 3 dimensions.
 
bool isNull() const
Returns true if the box is a null box.
 
static QgsOrientedBox3D fromBox3D(const QgsBox3D &box)
Constructs an oriented box from an axis-aligned bounding box.
 
Contains details about a sub layer available from a dataset.
 
void setUri(const QString &uri)
Sets the layer's uri.
 
void setType(Qgis::LayerType type)
Sets the layer type.
 
void setName(const QString &name)
Sets the layer's name.
 
void setProviderKey(const QString &key)
Sets the associated data provider key.
 
static QString suggestLayerNameFromFilePath(const QString &path)
Suggests a suitable layer name given only a file path.
 
The QgsReadWriteLocker class is a convenience class that simplifies locking and unlocking QReadWriteL...
 
A rectangle specified with double values.
 
A spherical geometry object.
 
bool isNull() const
Returns true if the sphere is a null (default constructed) sphere.
 
QgsBox3D boundingBox() const
Returns the 3-dimensional bounding box containing the sphere.
 
void finished()
Emitted when the reply has finished (either with a success or with a failure)
 
Represents a bounding volume for a tiled scene.
 
QgsOrientedBox3D box() const
Returns the volume's oriented box.
 
bool intersects(const QgsOrientedBox3D &box) const
Returns true if this bounds intersects the specified box.
 
void transform(const QgsMatrix4x4 &transform)
Applies a transform to the bounding volume.
 
Base class for data providers for QgsTiledSceneLayer.
 
An index for tiled scene data providers.
 
Allows representing QgsTiledSceneTiles in a hierarchical tree.
 
void addChild(QgsTiledSceneNode *child)
Adds a child to this node.
 
QgsTiledSceneNode * parentNode() const
Returns the parent of this node.
 
QList< QgsTiledSceneNode * > children() const
Returns this node's children.
 
QgsTiledSceneTile * tile()
Returns the tile associated with the node.
 
Tiled scene data request.
 
QgsOrientedBox3D filterBox() const
Returns the box from which data will be taken.
 
long long parentTileId() const
Returns the parent tile ID, if filtering is limited to children of a specific tile.
 
double requiredGeometricError() const
Returns the required geometric error threshold for the returned tiles, in scene CRS units.
 
QgsFeedback * feedback() const
Returns the feedback object that can be queried regularly by the request to check if it should be can...
 
Qgis::TiledSceneRequestFlags flags() const
Returns the flags which affect how tiles are fetched.
 
Represents an individual tile from a tiled scene data source.
 
void setTransform(const QgsMatrix4x4 &transform)
Sets the tile's transform.
 
Qgis::TileRefinementProcess refinementProcess() const
Returns the tile's refinement process.
 
const QgsTiledSceneBoundingVolume & boundingVolume() const
Returns the bounding volume for the tile.
 
long long id() const
Returns the tile's unique ID.
 
const QgsMatrix4x4 * transform() const
Returns the tile's transform.
 
void setResources(const QVariantMap &resources)
Sets the resources attached to the tile.
 
double geometricError() const
Returns the tile's geometric error, which is the error, in scene CRS units, of the tile's simplified ...
 
Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precisi...
 
double y() const
Returns Y coordinate.
 
double z() const
Returns Z coordinate.
 
double x() const
Returns X coordinate.
 
#define QgsDebugError(str)
 
#define QgsSetRequestInitiatorClass(request, _class)
 
#define QGIS_PROTECT_QOBJECT_THREAD_ACCESS
 
Setting options for creating vector data providers.