38#define TINYGLTF_NO_STB_IMAGE          
   39#define TINYGLTF_NO_STB_IMAGE_WRITE    
   44  , mLayerName( layer->name() )
 
   46  , mEnableProfile( context.flags() & 
Qgis::RenderContextFlag::RecordProfile )
 
   64  mRenderTileBorders = mRenderer->isTileBorderRenderingEnabled();
 
   68  mPreparationTime = timer.elapsed();
 
 
   78  std::unique_ptr< QgsScopedRuntimeProfile > profile;
 
   81    profile = std::make_unique< QgsScopedRuntimeProfile >( mLayerName, QStringLiteral( 
"rendering" ), 
layerId() );
 
   82    if ( mPreparationTime > 0 )
 
   86  std::unique_ptr< QgsScopedRuntimeProfile > preparingProfile;
 
   89    preparingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( 
"Preparing render" ), QStringLiteral( 
"rendering" ) );
 
   96  QPainter *painter = rc->
painter();
 
  101  if ( !mClippingRegions.empty() )
 
  103    bool needsPainterClipPath = 
false;
 
  105    if ( needsPainterClipPath )
 
  106      rc->
painter()->setClipPath( path, Qt::IntersectClip );
 
  109  mElapsedTimer.start();
 
  113  mRenderer->startRender( context );
 
  115  preparingProfile.reset();
 
  116  std::unique_ptr< QgsScopedRuntimeProfile > renderingProfile;
 
  117  if ( mEnableProfile )
 
  119    renderingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( 
"Rendering" ), QStringLiteral( 
"rendering" ) );
 
  122  const bool result = renderTiles( context );
 
  123  mRenderer->stopRender( context );
 
 
  150  const double maximumErrorPixels = context->
convertToPainterUnits( mRenderer->maximumScreenError(), mRenderer->maximumScreenErrorUnit() );
 
  152  const double mapYCenter = 0.5 * ( mapExtent.
yMinimum() + mapExtent.
yMaximum() );
 
  157  const double mapMetersPerPixel = mapWidthMeters / context->
outputSize().width();
 
  158  const double maximumErrorInMeters = maximumErrorPixels * mapMetersPerPixel;
 
  164  const QVector< QgsVector3D > corners = 
QgsBox3D( mapExtent, -10000, 10000 ).
corners();
 
  171  for ( 
int i = 0; i < 8; ++i )
 
  174    x.append( corner.
x() );
 
  175    y.append( corner.
y() );
 
  176    z.append( corner.
z() );
 
  180  const auto minMaxX = std::minmax_element( x.constBegin(), x.constEnd() );
 
  181  const auto minMaxY = std::minmax_element( y.constBegin(), y.constEnd() );
 
  182  const auto minMaxZ = std::minmax_element( z.constBegin(), z.constEnd() );
 
  195  auto tileIsVisibleInMap = [mapExtent, 
this]( 
const QgsTiledSceneTile & tile )->
bool 
  201    const QgsGeometry tileGeometry( tile.boundingVolume().as2DGeometry( mSceneToMapTransform ) );
 
  202    return tileGeometry.intersects( mapExtent );
 
  206  QVector< long long > tileIds = mIndex.
getTiles( request );
 
  207  while ( !tileIds.empty() )
 
  212    const long long tileId = tileIds.first();
 
  216    if ( !tile.
isValid() || !tileIsVisibleInMap( tile ) )
 
  224        renderTile( tile, context );
 
  233          const QVector< long long > newTileIdsToRender = mIndex.
getTiles( request );
 
  234          tileIds.append( newTileIdsToRender );
 
  245                renderTile( tile, context );
 
  259  std::sort( mPrimitiveData.begin(), mPrimitiveData.end(), []( 
const PrimitiveData & a, 
const PrimitiveData & b )
 
  262    if ( qgsDoubleNear( a.z, b.z, 0.001 ) )
 
  265      if ( a.type == PrimitiveType::Line )
 
  267      else if ( b.type == PrimitiveType::Line )
 
  272  for ( 
const PrimitiveData &data : std::as_const( mPrimitiveData ) )
 
  276      case PrimitiveType::Line:
 
  277        mRenderer->renderLine( context, data.coordinates );
 
  280      case PrimitiveType::Triangle:
 
  285                                         data.textureCoords[2], data.textureCoords[3],
 
  286                                         data.textureCoords[4], data.textureCoords[5] );
 
  288        mRenderer->renderTriangle( context, data.coordinates );
 
  293  if ( mRenderTileBorders )
 
  295    QPainter *painter = renderContext()->painter();
 
  296    for ( 
const TileDetails &tile : std::as_const( mTileDetails ) )
 
  300      if ( tile.hasContent )
 
  302        brush = QBrush( QColor( 0, 0, 255, 10 ) );
 
  303        pen = QPen( QColor( 0, 0, 255, 150 ) );
 
  307        brush = QBrush( QColor( 255, 0, 255, 10 ) );
 
  308        pen = QPen( QColor( 255, 0, 255, 150 ) );
 
  311      painter->setPen( pen );
 
  312      painter->setBrush( brush );
 
  313      painter->drawPolygon( tile.boundary );
 
  316      format.
setColor( QColor( 255, 0, 0 ) );
 
  319      QgsTextRenderer::drawText( QRectF( QPoint( 0, 0 ), renderContext()->outputSize() ).intersected( tile.boundary.boundingRect() ),
 
  331  const bool hasContent = renderTileContent( tile, context );
 
  333  if ( mRenderTileBorders )
 
  338      std::unique_ptr< QgsAbstractGeometry > volumeGeometry( volume.
as2DGeometry( mSceneToMapTransform ) );
 
  339      if ( 
QgsCurvePolygon *polygon = qgsgeometry_cast< QgsCurvePolygon * >( volumeGeometry.get() ) )
 
  341        QPolygonF volumePolygon = polygon->exteriorRing()->asQPolygonF( );
 
  344        volumePolygon.erase( std::remove_if( volumePolygon.begin(), volumePolygon.end(),
 
  345                                             []( 
const QPointF point )
 
  347          return !std::isfinite( point.x() ) || !std::isfinite( point.y() );
 
  348        } ), volumePolygon.end() );
 
  350        QPointF *ptr = volumePolygon.data();
 
  351        for ( 
int i = 0; i < volumePolygon.size(); ++i, ++ptr )
 
  357        details.boundary = volumePolygon;
 
  358        details.hasContent = hasContent;
 
  359        details.id = QString::number( tile.
id() );
 
  360        mTileDetails.append( details );
 
  365      QgsDebugError( QStringLiteral( 
"Error transforming bounding volume" ) );
 
  372  const QString contentUri = tile.
resources().value( QStringLiteral( 
"content" ) ).toString();
 
  373  if ( contentUri.isEmpty() )
 
  378  if ( content.
gltf.isEmpty() )
 
  383  tinygltf::Model model;
 
  385  QString gltfWarnings;
 
  387  const bool res = QgsGltfUtils::loadGltfModel( content.
gltf, model, &gltfErrors, &gltfWarnings );
 
  390    const QgsVector3D tileTranslationEcef = content.
rtcCenter + QgsGltfUtils::extractTileTranslation( model,
 
  393    bool sceneOk = 
false;
 
  394    const std::size_t sceneIndex = QgsGltfUtils::sourceSceneForModel( model, sceneOk );
 
  397      const QString error = QObject::tr( 
"No scenes found in model" );
 
  399      QgsDebugError( QStringLiteral( 
"Error raised reading %1: %2" ).arg( contentUri, error ) );
 
  403      const tinygltf::Scene &scene = model.scenes[sceneIndex];
 
  405      std::function< void( 
int nodeIndex, 
const QMatrix4x4 &transform ) > traverseNode;
 
  406      traverseNode = [&model, &context, &tileTranslationEcef, &tile, &contentUri, &traverseNode, 
this]( 
int nodeIndex, 
const QMatrix4x4 & parentTransform )
 
  408        const tinygltf::Node &gltfNode = model.nodes[nodeIndex];
 
  409        std::unique_ptr< QMatrix4x4 > gltfLocalTransform = QgsGltfUtils::parseNodeTransform( gltfNode );
 
  411        if ( !parentTransform.isIdentity() )
 
  413          if ( gltfLocalTransform )
 
  414            *gltfLocalTransform = parentTransform * *gltfLocalTransform;
 
  417            gltfLocalTransform.reset( 
new QMatrix4x4( parentTransform ) );
 
  421        if ( gltfNode.mesh >= 0 )
 
  423          const tinygltf::Mesh &mesh = model.meshes[gltfNode.mesh];
 
  425          for ( 
const tinygltf::Primitive &primitive : mesh.primitives )
 
  427            if ( context.renderContext().renderingStopped() )
 
  430            renderPrimitive( model, primitive, tile, tileTranslationEcef, gltfLocalTransform.get(), contentUri, context );
 
  434        for ( 
int childNode : gltfNode.children )
 
  436          traverseNode( childNode, gltfLocalTransform ? *gltfLocalTransform : QMatrix4x4() );
 
  440      for ( 
int nodeIndex : scene.nodes )
 
  442        traverseNode( nodeIndex, QMatrix4x4() );
 
  446  else if ( !gltfErrors.isEmpty() )
 
  448    if ( !
mErrors.contains( gltfErrors ) )
 
  450    QgsDebugError( QStringLiteral( 
"Error raised reading %1: %2" ).arg( contentUri, gltfErrors ) );
 
  452  if ( !gltfWarnings.isEmpty() )
 
  454    QgsDebugError( QStringLiteral( 
"Warnings raised reading %1: %2" ).arg( contentUri, gltfWarnings ) );
 
  459void QgsTiledSceneLayerRenderer::renderPrimitive( 
const tinygltf::Model &model, 
const tinygltf::Primitive &primitive, 
const QgsTiledSceneTile &tile, 
const QgsVector3D &tileTranslationEcef, 
const QMatrix4x4 *gltfLocalTransform, 
const QString &contentUri, 
QgsTiledSceneRenderContext &context )
 
  461  switch ( primitive.mode )
 
  463    case TINYGLTF_MODE_TRIANGLES:
 
  465        renderTrianglePrimitive( model, primitive, tile, tileTranslationEcef, gltfLocalTransform, contentUri, context );
 
  468    case TINYGLTF_MODE_LINE:
 
  470        renderLinePrimitive( model, primitive, tile, tileTranslationEcef, gltfLocalTransform, contentUri, context );
 
  473    case TINYGLTF_MODE_POINTS:
 
  474      if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_POINTS ) )
 
  476        mErrors << QObject::tr( 
"Point objects in tiled scenes are not supported" );
 
  477        mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_POINTS );
 
  481    case TINYGLTF_MODE_LINE_LOOP:
 
  482      if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_LINE_LOOP ) )
 
  484        mErrors << QObject::tr( 
"Line loops in tiled scenes are not supported" );
 
  485        mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_LINE_LOOP );
 
  489    case TINYGLTF_MODE_LINE_STRIP:
 
  490      if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_LINE_STRIP ) )
 
  492        mErrors << QObject::tr( 
"Line strips in tiled scenes are not supported" );
 
  493        mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_LINE_STRIP );
 
  497    case TINYGLTF_MODE_TRIANGLE_STRIP:
 
  498      if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_TRIANGLE_STRIP ) )
 
  500        mErrors << QObject::tr( 
"Triangular strips in tiled scenes are not supported" );
 
  501        mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_TRIANGLE_STRIP );
 
  505    case TINYGLTF_MODE_TRIANGLE_FAN:
 
  506      if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_TRIANGLE_FAN ) )
 
  508        mErrors << QObject::tr( 
"Triangular fans in tiled scenes are not supported" );
 
  509        mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_TRIANGLE_FAN );
 
  514      if ( !mWarnedPrimitiveTypes.contains( primitive.mode ) )
 
  516        mErrors << QObject::tr( 
"Primitive type %1 in tiled scenes are not supported" ).arg( primitive.mode );
 
  517        mWarnedPrimitiveTypes.insert( primitive.mode );
 
  523void QgsTiledSceneLayerRenderer::renderTrianglePrimitive( 
const tinygltf::Model &model, 
const tinygltf::Primitive &primitive, 
const QgsTiledSceneTile &tile, 
const QgsVector3D &tileTranslationEcef, 
const QMatrix4x4 *gltfLocalTransform, 
const QString &contentUri, 
QgsTiledSceneRenderContext &context )
 
  525  auto posIt = primitive.attributes.find( 
"POSITION" );
 
  526  if ( posIt == primitive.attributes.end() )
 
  528    mErrors << QObject::tr( 
"Could not find POSITION attribute for primitive" );
 
  531  int positionAccessorIndex = posIt->second;
 
  536  QgsGltfUtils::accessorToMapCoordinates(
 
  538    &mSceneToMapTransform,
 
  541    static_cast< 
Qgis::Axis >( tile.metadata().value( QStringLiteral( 
"gltfUpAxis" ), static_cast< int >( 
Qgis::Axis::Y ) ).toInt() ),
 
  550  QVector< float > texturePointX;
 
  551  QVector< float > texturePointY;
 
  552  QPair< int, int > textureId{ -1, -1 };
 
  555    const tinygltf::Material &material = model.materials[primitive.material];
 
  556    const tinygltf::PbrMetallicRoughness &pbr = material.pbrMetallicRoughness;
 
  558    if ( pbr.baseColorTexture.index >= 0
 
  559         && 
static_cast< int >( model.textures.size() ) > pbr.baseColorTexture.index )
 
  561      const tinygltf::Texture &tex = model.textures[pbr.baseColorTexture.index];
 
  563      switch ( QgsGltfUtils::imageResourceType( model, tex.source ) )
 
  565        case QgsGltfUtils::ResourceType::Embedded:
 
  566          textureImage = QgsGltfUtils::extractEmbeddedImage( model, tex.source );
 
  569        case QgsGltfUtils::ResourceType::Linked:
 
  571          const QString linkedPath = QgsGltfUtils::linkedImagePath( model, tex.source );
 
  572          const QString textureUri = QUrl( contentUri ).resolved( linkedPath ).toString();
 
  574          if ( !rep.isEmpty() )
 
  576            textureImage = QImage::fromData( rep );
 
  582      if ( !textureImage.isNull() )
 
  584        auto texIt = primitive.attributes.find( 
"TEXCOORD_0" );
 
  585        if ( texIt != primitive.attributes.end() )
 
  587          QgsGltfUtils::extractTextureCoordinates(
 
  588            model, texIt->second, texturePointX, texturePointY
 
  592        textureId = qMakePair( mCurrentModelId, pbr.baseColorTexture.index );
 
  603  auto needTriangle = [&outputRect]( 
const QPolygonF & triangle ) -> 
bool 
  605    return triangle.boundingRect().intersects( outputRect );
 
  608  const bool useTexture = !textureImage.isNull();
 
  609  bool hasStoredTexture = 
false;
 
  611  QVector< PrimitiveData > thisTileTriangleData;
 
  613  if ( primitive.indices == -1 )
 
  615    Q_ASSERT( x.size() % 3 == 0 );
 
  617    thisTileTriangleData.reserve( x.size() );
 
  618    for ( 
int i = 0; i < x.size(); i += 3 )
 
  624      data.type = PrimitiveType::Triangle;
 
  625      data.textureId = textureId;
 
  628        data.textureCoords[0] = texturePointX[i];
 
  629        data.textureCoords[1] = texturePointY[i];
 
  630        data.textureCoords[2] = texturePointX[i + 1];
 
  631        data.textureCoords[3] = texturePointY[i + 1];
 
  632        data.textureCoords[4] = texturePointX[i + 2];
 
  633        data.textureCoords[5] = texturePointY[i + 2];
 
  635      data.coordinates = QVector<QPointF> { QPointF( x[i], y[i] ), QPointF( x[i + 1], y[i + 1] ), QPointF( x[i + 2], y[i + 2] ), QPointF( x[i], y[i] ) };
 
  636      data.z = ( z[i] + z[i + 1] + z[i + 2] ) / 3;
 
  637      if ( needTriangle( data.coordinates ) )
 
  639        thisTileTriangleData.push_back( data );
 
  640        if ( !hasStoredTexture && !textureImage.isNull() )
 
  643          mTextures.insert( textureId, textureImage.copy() );
 
  644          hasStoredTexture = 
true;
 
  651    const tinygltf::Accessor &primitiveAccessor = model.accessors[primitive.indices];
 
  652    const tinygltf::BufferView &bvPrimitive = model.bufferViews[primitiveAccessor.bufferView];
 
  653    const tinygltf::Buffer &bPrimitive = model.buffers[bvPrimitive.buffer];
 
  655    Q_ASSERT( ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT
 
  656                || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT
 
  657                || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
 
  658              && primitiveAccessor.type == TINYGLTF_TYPE_SCALAR );
 
  660    const char *primitivePtr = 
reinterpret_cast< const char * 
>( bPrimitive.data.data() ) + bvPrimitive.byteOffset + primitiveAccessor.byteOffset;
 
  662    thisTileTriangleData.reserve( primitiveAccessor.count / 3 );
 
  663    for ( std::size_t i = 0; i < primitiveAccessor.count / 3; i++ )
 
  668      unsigned int index1 = 0;
 
  669      unsigned int index2 = 0;
 
  670      unsigned int index3 = 0;
 
  673      data.type = PrimitiveType::Triangle;
 
  674      data.textureId = textureId;
 
  676      if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT )
 
  678        const unsigned short *usPtrPrimitive = 
reinterpret_cast< const unsigned short * 
>( primitivePtr );
 
  679        if ( bvPrimitive.byteStride )
 
  680          primitivePtr += bvPrimitive.byteStride;
 
  682          primitivePtr += 3 * 
sizeof( 
unsigned short );
 
  684        index1 = usPtrPrimitive[0];
 
  685        index2 = usPtrPrimitive[1];
 
  686        index3 = usPtrPrimitive[2];
 
  688      else if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
 
  690        const unsigned char *usPtrPrimitive = 
reinterpret_cast< const unsigned char * 
>( primitivePtr );
 
  691        if ( bvPrimitive.byteStride )
 
  692          primitivePtr += bvPrimitive.byteStride;
 
  694          primitivePtr += 3 * 
sizeof( 
unsigned char );
 
  696        index1 = usPtrPrimitive[0];
 
  697        index2 = usPtrPrimitive[1];
 
  698        index3 = usPtrPrimitive[2];
 
  702        const unsigned int *uintPtrPrimitive = 
reinterpret_cast< const unsigned int * 
>( primitivePtr );
 
  703        if ( bvPrimitive.byteStride )
 
  704          primitivePtr += bvPrimitive.byteStride;
 
  706          primitivePtr += 3 * 
sizeof( 
unsigned int );
 
  708        index1 = uintPtrPrimitive[0];
 
  709        index2 = uintPtrPrimitive[1];
 
  710        index3 = uintPtrPrimitive[2];
 
  715        data.textureCoords[0] = texturePointX[index1];
 
  716        data.textureCoords[1] = texturePointY[index1];
 
  717        data.textureCoords[2] = texturePointX[index2];
 
  718        data.textureCoords[3] = texturePointY[index2];
 
  719        data.textureCoords[4] = texturePointX[index3];
 
  720        data.textureCoords[5] = texturePointY[index3];
 
  723      data.coordinates = { QVector<QPointF>{ QPointF( x[index1], y[index1] ), QPointF( x[index2], y[index2] ), QPointF( x[index3], y[index3] ), QPointF( x[index1], y[index1] ) } };
 
  724      data.z = ( z[index1] + z[index2] + z[index3] ) / 3;
 
  725      if ( needTriangle( data.coordinates ) )
 
  727        thisTileTriangleData.push_back( data );
 
  728        if ( !hasStoredTexture && !textureImage.isNull() )
 
  731          mTextures.insert( textureId, textureImage.copy() );
 
  732          hasStoredTexture = 
true;
 
  745    std::sort( thisTileTriangleData.begin(), thisTileTriangleData.end(), []( 
const PrimitiveData & a, 
const PrimitiveData & b )
 
  750    for ( 
const PrimitiveData &data : std::as_const( thisTileTriangleData ) )
 
  752      if ( useTexture && data.textureId.first >= 0 )
 
  756                                       data.textureCoords[2], data.textureCoords[3],
 
  757                                       data.textureCoords[4], data.textureCoords[5] );
 
  759      mRenderer->renderTriangle( context, data.coordinates );
 
  764  mPrimitiveData.append( thisTileTriangleData );
 
  775void QgsTiledSceneLayerRenderer::renderLinePrimitive( 
const tinygltf::Model &model, 
const tinygltf::Primitive &primitive, 
const QgsTiledSceneTile &tile, 
const QgsVector3D &tileTranslationEcef, 
const QMatrix4x4 *gltfLocalTransform, 
const QString &, 
QgsTiledSceneRenderContext &context )
 
  777  auto posIt = primitive.attributes.find( 
"POSITION" );
 
  778  if ( posIt == primitive.attributes.end() )
 
  780    mErrors << QObject::tr( 
"Could not find POSITION attribute for primitive" );
 
  783  int positionAccessorIndex = posIt->second;
 
  788  QgsGltfUtils::accessorToMapCoordinates(
 
  790    &mSceneToMapTransform,
 
  793    static_cast< 
Qgis::Axis >( tile.metadata().value( QStringLiteral( 
"gltfUpAxis" ), static_cast< int >( 
Qgis::Axis::Y ) ).toInt() ),
 
  800  auto needLine = [&outputRect]( 
const QPolygonF & line ) -> 
bool 
  802    return line.boundingRect().intersects( outputRect );
 
  805  QVector< PrimitiveData > thisTileLineData;
 
  807  if ( primitive.indices == -1 )
 
  809    Q_ASSERT( x.size() % 2 == 0 );
 
  811    thisTileLineData.reserve( x.size() );
 
  812    for ( 
int i = 0; i < x.size(); i += 2 )
 
  818      data.type = PrimitiveType::Line;
 
  819      data.coordinates = QVector<QPointF> { QPointF( x[i], y[i] ), QPointF( x[i + 1], y[i + 1] ) };
 
  821      data.z = std::max( z[i], z[i + 1] );
 
  822      if ( needLine( data.coordinates ) )
 
  824        thisTileLineData.push_back( data );
 
  830    const tinygltf::Accessor &primitiveAccessor = model.accessors[primitive.indices];
 
  831    const tinygltf::BufferView &bvPrimitive = model.bufferViews[primitiveAccessor.bufferView];
 
  832    const tinygltf::Buffer &bPrimitive = model.buffers[bvPrimitive.buffer];
 
  834    Q_ASSERT( ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT
 
  835                || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT
 
  836                || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
 
  837              && primitiveAccessor.type == TINYGLTF_TYPE_SCALAR );
 
  839    const char *primitivePtr = 
reinterpret_cast< const char * 
>( bPrimitive.data.data() ) + bvPrimitive.byteOffset + primitiveAccessor.byteOffset;
 
  841    thisTileLineData.reserve( primitiveAccessor.count / 2 );
 
  842    for ( std::size_t i = 0; i < primitiveAccessor.count / 2; i++ )
 
  847      unsigned int index1 = 0;
 
  848      unsigned int index2 = 0;
 
  851      data.type = PrimitiveType::Line;
 
  853      if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT )
 
  855        const unsigned short *usPtrPrimitive = 
reinterpret_cast< const unsigned short * 
>( primitivePtr );
 
  856        if ( bvPrimitive.byteStride )
 
  857          primitivePtr += bvPrimitive.byteStride;
 
  859          primitivePtr += 2 * 
sizeof( 
unsigned short );
 
  861        index1 = usPtrPrimitive[0];
 
  862        index2 = usPtrPrimitive[1];
 
  864      else if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
 
  866        const unsigned char *usPtrPrimitive = 
reinterpret_cast< const unsigned char * 
>( primitivePtr );
 
  867        if ( bvPrimitive.byteStride )
 
  868          primitivePtr += bvPrimitive.byteStride;
 
  870          primitivePtr += 2 * 
sizeof( 
unsigned char );
 
  872        index1 = usPtrPrimitive[0];
 
  873        index2 = usPtrPrimitive[1];
 
  877        const unsigned int *uintPtrPrimitive = 
reinterpret_cast< const unsigned int * 
>( primitivePtr );
 
  878        if ( bvPrimitive.byteStride )
 
  879          primitivePtr += bvPrimitive.byteStride;
 
  881          primitivePtr += 2 * 
sizeof( 
unsigned int );
 
  883        index1 = uintPtrPrimitive[0];
 
  884        index2 = uintPtrPrimitive[1];
 
  887      data.coordinates = { QVector<QPointF>{ QPointF( x[index1], y[index1] ), QPointF( x[index2], y[index2] ) } };
 
  889      data.z = std::max( z[index1], z[index2] );
 
  890      if ( needLine( data.coordinates ) )
 
  892        thisTileLineData.push_back( data );
 
  904    std::sort( thisTileLineData.begin(), thisTileLineData.end(), []( 
const PrimitiveData & a, 
const PrimitiveData & b )
 
  909    for ( 
const PrimitiveData &data : std::as_const( thisTileLineData ) )
 
  911      mRenderer->renderLine( context, data.coordinates );
 
  916  mPrimitiveData.append( thisTileLineData );
 
The Qgis class provides global constants for use throughout the application.
 
QFlags< MapLayerRendererFlag > MapLayerRendererFlags
Flags which control how map layer renderers behave.
 
@ RendersLines
Renderer can render line primitives.
 
@ RequiresTextures
Renderer requires textures.
 
@ ForceRasterRender
Layer should always be rendered as a raster image.
 
@ RendersTriangles
Renderer can render triangle primitives.
 
@ 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.
 
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
 
@ RenderPartialOutputOverPreviousCachedImage
When rendering temporary in-progress preview renders, these preview renders can be drawn over any pre...
 
@ RenderPartialOutputs
The renderer benefits from rendering temporary in-progress preview renders. These are temporary resul...
 
@ VerticalCenter
Center align.
 
@ 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.
 
@ Reverse
Reverse/inverse transform (from destination to source)
 
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
 
A 3-dimensional box composed of x, y, z coordinates.
 
QVector< QgsVector3D > corners() const
Returns an array of all box corners as 3D vectors.
 
static TileContents extractGltfFromTileContent(const QByteArray &tileContent)
Parses tile content.
 
Custom exception class for Coordinate Reference System related exceptions.
 
Curve polygon geometry type.
 
double measureLine(const QVector< QgsPointXY > &points) const
Measures the length of a line with multiple segments.
 
Base class for feedback objects to be used for cancellation of something running in a worker thread.
 
A geometry is the spatial representation of a feature.
 
static QPainterPath calculatePainterClipRegion(const QList< QgsMapClippingRegion > ®ions, const QgsRenderContext &context, Qgis::LayerType layerType, bool &shouldClip)
Returns a QPainterPath representing the intersection of clipping regions from context which should be...
 
static QList< QgsMapClippingRegion > collectClippingRegionsForLayer(const QgsRenderContext &context, const QgsMapLayer *layer)
Collects the list of map clipping regions from a context which apply to a map layer.
 
Base class for utility classes that encapsulate information necessary for rendering of map layers.
 
bool mReadyToCompose
The flag must be set to false in renderer's constructor if wants to use the smarter map redraws funct...
 
static constexpr int MAX_TIME_TO_USE_CACHED_PREVIEW_IMAGE
Maximum time (in ms) to allow display of a previously cached preview image while rendering layers,...
 
QString layerId() const
Gets access to the ID of the layer rendered by this class.
 
QgsRenderContext * renderContext()
Returns the render context associated with the renderer.
 
void transformInPlace(double &x, double &y) const
Transforms device coordinates to map coordinates.
 
A simple 4x4 matrix implementation useful for transformation in 3D space.
 
static QgsOrientedBox3D fromBox3D(const QgsBox3D &box)
Constructs an oriented box from an axis-aligned bounding box.
 
A class to represent a 2D point.
 
A rectangle specified with double values.
 
double xMinimum() const
Returns the x minimum value (left side of rectangle).
 
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
 
double xMaximum() const
Returns the x maximum value (right side of rectangle).
 
double yMaximum() const
Returns the y maximum value (top side of rectangle).
 
Contains information about the context of a rendering operation.
 
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
 
const QgsDistanceArea & distanceArea() const
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
 
QPainter * painter()
Returns the destination QPainter for the render operation.
 
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
 
QgsCoordinateTransformContext transformContext() const
Returns the context's coordinate transform context, which stores various information regarding which ...
 
QSize outputSize() const
Returns the size of the resulting rendered image, in pixels.
 
QgsRectangle mapExtent() const
Returns the original extent of the map being rendered.
 
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
 
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
 
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
 
QPainter * previewRenderPainter()
Returns the const destination QPainter for temporary in-progress preview renders.
 
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
 
void record(const QString &name, double time, const QString &group="startup", const QString &id=QString())
Manually adds a profile event with the given name and total time (in seconds).
 
Scoped object for saving and restoring a QPainter object's state.
 
void setEnabled(bool enabled)
Sets whether the text buffer will be drawn.
 
Container for all settings relating to text rendering.
 
void setColor(const QColor &color)
Sets the color that text will be rendered in.
 
QgsTextBufferSettings & buffer()
Returns a reference to the text buffer settings.
 
static void drawText(const QRectF &rect, double rotation, Qgis::TextHorizontalAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool drawAsOutlines=true, Qgis::TextVerticalAlignment vAlignment=Qgis::TextVerticalAlignment::Top, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), Qgis::TextLayoutMode mode=Qgis::TextLayoutMode::Rectangle)
Draws text within a rectangle using the specified settings.
 
Represents a bounding volume for a tiled scene.
 
QgsAbstractGeometry * as2DGeometry(const QgsCoordinateTransform &transform=QgsCoordinateTransform(), Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const
Returns a new geometry representing the 2-dimensional X/Y center slice of the volume.
 
virtual const QgsCoordinateReferenceSystem sceneCrs() const =0
Returns the original coordinate reference system for the tiled scene data.
 
virtual QgsTiledSceneIndex index() const =0
Returns the provider's tile index.
 
virtual const QgsTiledSceneBoundingVolume & boundingVolume() const =0
Returns the bounding volume for the data provider.
 
Qgis::TileChildrenAvailability childAvailability(long long id) const
Returns the availability for a tile's children.
 
QByteArray retrieveContent(const QString &uri, QgsFeedback *feedback=nullptr)
Retrieves index content for the specified uri.
 
bool fetchHierarchy(long long id, QgsFeedback *feedback=nullptr)
Populates the tile with the given id by fetching any sub datasets attached to the tile.
 
QgsTiledSceneTile getTile(long long id)
Returns the tile with matching id, or an invalid tile if the matching tile is not available.
 
QVector< long long > getTiles(const QgsTiledSceneRequest &request)
Returns the list of tile IDs which match the given request.
 
bool isValid() const
Returns true if the index is valid.
 
bool forceRasterRender() const override
Returns true if the renderer must be rendered to a raster paint device (e.g.
 
QgsTiledSceneLayerRenderer(QgsTiledSceneLayer *layer, QgsRenderContext &context)
Ctor.
 
QgsFeedback * feedback() const override
Access to feedback object of the layer renderer (may be nullptr)
 
bool render() override
Do the rendering (based on data stored in the class).
 
~QgsTiledSceneLayerRenderer()
 
Qgis::MapLayerRendererFlags flags() const override
Returns flags which control how the map layer rendering behaves.
 
Represents a map layer supporting display of tiled scene objects.
 
QgsTiledSceneDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
 
QgsTiledSceneRenderer * renderer()
Returns the 2D renderer for the tiled scene.
 
Encapsulates the render context for a 2D tiled scene rendering operation.
 
void setTextureImage(const QImage &image)
Sets the current texture image.
 
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
 
void setTextureCoordinates(float textureX1, float textureY1, float textureX2, float textureY2, float textureX3, float textureY3)
Sets the current texture coordinates.
 
virtual QgsTiledSceneRenderer * clone() const =0
Create a deep copy of this renderer.
 
Tiled scene data request.
 
void setParentTileId(long long id)
Sets the parent tile id, if filtering is to be limited to children of a specific tile.
 
void setFilterBox(const QgsOrientedBox3D &box)
Sets the box from which data will be taken.
 
void setFeedback(QgsFeedback *feedback)
Attach a feedback object that can be queried regularly by the request to check if it should be cancel...
 
void setRequiredGeometricError(double error)
Sets the required geometric error threshold for the returned tiles, in scene CRS units.
 
Represents an individual tile from a tiled scene data source.
 
bool isValid() const
Returns true if the tile is a valid tile (i.e.
 
Qgis::TileRefinementProcess refinementProcess() const
Returns the tile's refinement process.
 
QVariantMap resources() const
Returns the resources attached to the tile.
 
const QgsTiledSceneBoundingVolume & boundingVolume() const
Returns the bounding volume for the tile.
 
QVariantMap metadata() const
Returns additional metadata attached to the tile.
 
long long id() const
Returns the tile's unique ID.
 
const QgsMatrix4x4 * transform() const
Returns the tile's transform.
 
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.
 
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
 
#define QgsDebugError(str)
 
Encapsulates the contents of a 3D tile.
 
QgsVector3D rtcCenter
Optional RTC center.
 
QByteArray gltf
GLTF binary content.