41#define TINYGLTF_NO_STB_IMAGE          
   42#define TINYGLTF_NO_STB_IMAGE_WRITE    
   47  , mLayerName( layer->name() )
 
   49  , mEnableProfile( context.flags() & 
Qgis::RenderContextFlag::RecordProfile )
 
   67  mRenderTileBorders = mRenderer->isTileBorderRenderingEnabled();
 
   71  mPreparationTime = timer.elapsed();
 
 
   81  std::unique_ptr< QgsScopedRuntimeProfile > profile;
 
   84    profile = std::make_unique< QgsScopedRuntimeProfile >( mLayerName, QStringLiteral( 
"rendering" ), 
layerId() );
 
   85    if ( mPreparationTime > 0 )
 
   89  std::unique_ptr< QgsScopedRuntimeProfile > preparingProfile;
 
   92    preparingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( 
"Preparing render" ), QStringLiteral( 
"rendering" ) );
 
   99  QPainter *painter = rc->
painter();
 
  104  if ( !mClippingRegions.empty() )
 
  106    bool needsPainterClipPath = 
false;
 
  108    if ( needsPainterClipPath )
 
  109      rc->
painter()->setClipPath( path, Qt::IntersectClip );
 
  112  mElapsedTimer.start();
 
  116  mRenderer->startRender( context );
 
  118  preparingProfile.reset();
 
  119  std::unique_ptr< QgsScopedRuntimeProfile > renderingProfile;
 
  120  if ( mEnableProfile )
 
  122    renderingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( 
"Rendering" ), QStringLiteral( 
"rendering" ) );
 
  125  const bool result = renderTiles( context );
 
  126  mRenderer->stopRender( context );
 
 
  153  const double maximumErrorPixels = context->
convertToPainterUnits( mRenderer->maximumScreenError(), mRenderer->maximumScreenErrorUnit() );
 
  155  const double mapYCenter = 0.5 * ( mapExtent.
yMinimum() + mapExtent.
yMaximum() );
 
  156  const double mapXCenter = 0.5 * ( mapExtent.
xMinimum() + mapExtent.
xMaximum() );
 
  158  double mapMetersPerPixel = 0;
 
  163                          QgsPointXY( mapXCenter + onePixelDistanceX, mapYCenter )
 
  169    QgsDebugError( QStringLiteral( 
"An error occurred while calculating length" ) );
 
  172  const double maximumErrorInMeters = maximumErrorPixels * mapMetersPerPixel;
 
  178  const QVector< QgsVector3D > corners = 
QgsBox3D( mapExtent, -10000, 10000 ).
corners();
 
  185  for ( 
int i = 0; i < 8; ++i )
 
  188    x.append( corner.
x() );
 
  189    y.append( corner.
y() );
 
  190    z.append( corner.
z() );
 
  194  const auto minMaxX = std::minmax_element( x.constBegin(), x.constEnd() );
 
  195  const auto minMaxY = std::minmax_element( y.constBegin(), y.constEnd() );
 
  196  const auto minMaxZ = std::minmax_element( z.constBegin(), z.constEnd() );
 
  209  auto tileIsVisibleInMap = [mapExtent, 
this]( 
const QgsTiledSceneTile & tile )->
bool 
  215    const QgsGeometry tileGeometry( tile.boundingVolume().as2DGeometry( mSceneToMapTransform ) );
 
  216    return tileGeometry.intersects( mapExtent );
 
  220  QVector< long long > tileIds = mIndex.
getTiles( request );
 
  221  while ( !tileIds.empty() )
 
  226    const long long tileId = tileIds.first();
 
  230    if ( !tile.
isValid() || !tileIsVisibleInMap( tile ) )
 
  238        renderTile( tile, context );
 
  247          const QVector< long long > newTileIdsToRender = mIndex.
getTiles( request );
 
  248          tileIds.append( newTileIdsToRender );
 
  259                renderTile( tile, context );
 
  273  std::sort( mPrimitiveData.begin(), mPrimitiveData.end(), []( 
const PrimitiveData & a, 
const PrimitiveData & b )
 
  276    if ( qgsDoubleNear( a.z, b.z, 0.001 ) )
 
  279      if ( a.type == PrimitiveType::Line )
 
  281      else if ( b.type == PrimitiveType::Line )
 
  286  for ( 
const PrimitiveData &data : std::as_const( mPrimitiveData ) )
 
  290      case PrimitiveType::Line:
 
  291        mRenderer->renderLine( context, data.coordinates );
 
  294      case PrimitiveType::Triangle:
 
  299                                         data.textureCoords[2], data.textureCoords[3],
 
  300                                         data.textureCoords[4], data.textureCoords[5] );
 
  302        mRenderer->renderTriangle( context, data.coordinates );
 
  307  if ( mRenderTileBorders )
 
  309    QPainter *painter = renderContext()->painter();
 
  310    for ( 
const TileDetails &tile : std::as_const( mTileDetails ) )
 
  314      if ( tile.hasContent )
 
  316        brush = QBrush( QColor( 0, 0, 255, 10 ) );
 
  317        pen = QPen( QColor( 0, 0, 255, 150 ) );
 
  321        brush = QBrush( QColor( 255, 0, 255, 10 ) );
 
  322        pen = QPen( QColor( 255, 0, 255, 150 ) );
 
  325      painter->setPen( pen );
 
  326      painter->setBrush( brush );
 
  327      painter->drawPolygon( tile.boundary );
 
  330      format.
setColor( QColor( 255, 0, 0 ) );
 
  333      QgsTextRenderer::drawText( QRectF( QPoint( 0, 0 ), renderContext()->outputSize() ).intersected( tile.boundary.boundingRect() ),
 
  345  const bool hasContent = renderTileContent( tile, context );
 
  347  if ( mRenderTileBorders )
 
  352      std::unique_ptr< QgsAbstractGeometry > volumeGeometry( volume.
as2DGeometry( mSceneToMapTransform ) );
 
  353      if ( 
QgsCurvePolygon *polygon = qgsgeometry_cast< QgsCurvePolygon * >( volumeGeometry.get() ) )
 
  355        QPolygonF volumePolygon = polygon->exteriorRing()->asQPolygonF( );
 
  358        volumePolygon.erase( std::remove_if( volumePolygon.begin(), volumePolygon.end(),
 
  359                                             []( 
const QPointF point )
 
  361          return !std::isfinite( point.x() ) || !std::isfinite( point.y() );
 
  362        } ), volumePolygon.end() );
 
  364        QPointF *ptr = volumePolygon.data();
 
  365        for ( 
int i = 0; i < volumePolygon.size(); ++i, ++ptr )
 
  371        details.boundary = volumePolygon;
 
  372        details.hasContent = hasContent;
 
  373        details.id = QString::number( tile.
id() );
 
  374        mTileDetails.append( details );
 
  379      QgsDebugError( QStringLiteral( 
"Error transforming bounding volume" ) );
 
  386  const QString contentUri = tile.
resources().value( QStringLiteral( 
"content" ) ).toString();
 
  387  if ( contentUri.isEmpty() )
 
  395  tinygltf::Model model;
 
  399  const auto &format = tile.
metadata().value( QStringLiteral( 
"contentFormat" ) ).value<QString>();
 
  400  if ( format == QLatin1String( 
"quantizedmesh" ) )
 
  405      qmTile.removeDegenerateTriangles();
 
  406      model = qmTile.toGltf();
 
  410      QgsDebugError( QStringLiteral( 
"Failed to parse tile from '%1'" ).arg( contentUri ) );
 
  414  else if ( format == QLatin1String( 
"cesiumtiles" ) )
 
  417    if ( content.
gltf.isEmpty() )
 
  424    QString gltfWarnings;
 
  425    const bool res = QgsGltfUtils::loadGltfModel( content.
gltf, model,
 
  426                     &gltfErrors, &gltfWarnings );
 
  427    if ( !gltfErrors.isEmpty() )
 
  429      if ( !
mErrors.contains( gltfErrors ) )
 
  431      QgsDebugError( QStringLiteral( 
"Error raised reading %1: %2" )
 
  432                     .arg( contentUri, gltfErrors ) );
 
  434    if ( !gltfWarnings.isEmpty() )
 
  436      QgsDebugError( QStringLiteral( 
"Warnings raised reading %1: %2" )
 
  437                     .arg( contentUri, gltfWarnings ) );
 
  439    if ( !res ) 
return false;
 
  446    QgsGltfUtils::extractTileTranslation(
 
  449                               .value( QStringLiteral( 
"gltfUpAxis" ),
 
  453  bool sceneOk = 
false;
 
  454  const std::size_t sceneIndex =
 
  455    QgsGltfUtils::sourceSceneForModel( model, sceneOk );
 
  458    const QString error = QObject::tr( 
"No scenes found in model" );
 
  461      QStringLiteral( 
"Error raised reading %1: %2" ).arg( contentUri, error ) );
 
  465    const tinygltf::Scene &scene = model.scenes[sceneIndex];
 
  467    std::function< void( 
int nodeIndex, 
const QMatrix4x4 &transform ) > traverseNode;
 
  468    traverseNode = [&model, &context, &tileTranslationEcef, &tile, &contentUri, &traverseNode, 
this]( 
int nodeIndex, 
const QMatrix4x4 & parentTransform )
 
  470      const tinygltf::Node &gltfNode = model.nodes[nodeIndex];
 
  471      std::unique_ptr< QMatrix4x4 > gltfLocalTransform = QgsGltfUtils::parseNodeTransform( gltfNode );
 
  473      if ( !parentTransform.isIdentity() )
 
  475        if ( gltfLocalTransform )
 
  476          *gltfLocalTransform = parentTransform * *gltfLocalTransform;
 
  479          gltfLocalTransform.reset( 
new QMatrix4x4( parentTransform ) );
 
  483      if ( gltfNode.mesh >= 0 )
 
  485        const tinygltf::Mesh &mesh = model.meshes[gltfNode.mesh];
 
  487        for ( 
const tinygltf::Primitive &primitive : mesh.primitives )
 
  489          if ( context.renderContext().renderingStopped() )
 
  492          renderPrimitive( model, primitive, tile, tileTranslationEcef, gltfLocalTransform.get(), contentUri, context );
 
  496      for ( 
int childNode : gltfNode.children )
 
  498        traverseNode( childNode, gltfLocalTransform ? *gltfLocalTransform : QMatrix4x4() );
 
  502    for ( 
int nodeIndex : scene.nodes )
 
  504      traverseNode( nodeIndex, QMatrix4x4() );
 
  510void QgsTiledSceneLayerRenderer::renderPrimitive( 
const tinygltf::Model &model, 
const tinygltf::Primitive &primitive, 
const QgsTiledSceneTile &tile, 
const QgsVector3D &tileTranslationEcef, 
const QMatrix4x4 *gltfLocalTransform, 
const QString &contentUri, 
QgsTiledSceneRenderContext &context )
 
  512  switch ( primitive.mode )
 
  514    case TINYGLTF_MODE_TRIANGLES:
 
  516        renderTrianglePrimitive( model, primitive, tile, tileTranslationEcef, gltfLocalTransform, contentUri, context );
 
  519    case TINYGLTF_MODE_LINE:
 
  521        renderLinePrimitive( model, primitive, tile, tileTranslationEcef, gltfLocalTransform, contentUri, context );
 
  524    case TINYGLTF_MODE_POINTS:
 
  525      if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_POINTS ) )
 
  527        mErrors << QObject::tr( 
"Point objects in tiled scenes are not supported" );
 
  528        mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_POINTS );
 
  532    case TINYGLTF_MODE_LINE_LOOP:
 
  533      if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_LINE_LOOP ) )
 
  535        mErrors << QObject::tr( 
"Line loops in tiled scenes are not supported" );
 
  536        mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_LINE_LOOP );
 
  540    case TINYGLTF_MODE_LINE_STRIP:
 
  541      if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_LINE_STRIP ) )
 
  543        mErrors << QObject::tr( 
"Line strips in tiled scenes are not supported" );
 
  544        mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_LINE_STRIP );
 
  548    case TINYGLTF_MODE_TRIANGLE_STRIP:
 
  549      if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_TRIANGLE_STRIP ) )
 
  551        mErrors << QObject::tr( 
"Triangular strips in tiled scenes are not supported" );
 
  552        mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_TRIANGLE_STRIP );
 
  556    case TINYGLTF_MODE_TRIANGLE_FAN:
 
  557      if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_TRIANGLE_FAN ) )
 
  559        mErrors << QObject::tr( 
"Triangular fans in tiled scenes are not supported" );
 
  560        mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_TRIANGLE_FAN );
 
  565      if ( !mWarnedPrimitiveTypes.contains( primitive.mode ) )
 
  567        mErrors << QObject::tr( 
"Primitive type %1 in tiled scenes are not supported" ).arg( primitive.mode );
 
  568        mWarnedPrimitiveTypes.insert( primitive.mode );
 
  574void QgsTiledSceneLayerRenderer::renderTrianglePrimitive( 
const tinygltf::Model &model, 
const tinygltf::Primitive &primitive, 
const QgsTiledSceneTile &tile, 
const QgsVector3D &tileTranslationEcef, 
const QMatrix4x4 *gltfLocalTransform, 
const QString &contentUri, 
QgsTiledSceneRenderContext &context )
 
  576  auto posIt = primitive.attributes.find( 
"POSITION" );
 
  577  if ( posIt == primitive.attributes.end() )
 
  579    mErrors << QObject::tr( 
"Could not find POSITION attribute for primitive" );
 
  582  int positionAccessorIndex = posIt->second;
 
  587  QgsGltfUtils::accessorToMapCoordinates(
 
  589    &mSceneToMapTransform,
 
  592    static_cast< 
Qgis::Axis >( tile.metadata().value( QStringLiteral( 
"gltfUpAxis" ), static_cast< int >( 
Qgis::Axis::Y ) ).toInt() ),
 
  601  QVector< float > texturePointX;
 
  602  QVector< float > texturePointY;
 
  603  QPair< int, int > textureId{ -1, -1 };
 
  604  if ( needsTextures && primitive.material != -1 )
 
  606    const tinygltf::Material &material = model.materials[primitive.material];
 
  607    const tinygltf::PbrMetallicRoughness &pbr = material.pbrMetallicRoughness;
 
  609    if ( pbr.baseColorTexture.index >= 0
 
  610         && 
static_cast< int >( model.textures.size() ) > pbr.baseColorTexture.index )
 
  612      const tinygltf::Texture &tex = model.textures[pbr.baseColorTexture.index];
 
  615      if ( tex.source >= 0 )
 
  617        switch ( QgsGltfUtils::imageResourceType( model, tex.source ) )
 
  619          case QgsGltfUtils::ResourceType::Embedded:
 
  620            textureImage = QgsGltfUtils::extractEmbeddedImage( model, tex.source );
 
  623          case QgsGltfUtils::ResourceType::Linked:
 
  625            const QString linkedPath = QgsGltfUtils::linkedImagePath( model, tex.source );
 
  626            const QString textureUri = QUrl( contentUri ).resolved( linkedPath ).toString();
 
  628            if ( !rep.isEmpty() )
 
  630              textureImage = QImage::fromData( rep );
 
  637      if ( !textureImage.isNull() )
 
  639        auto texIt = primitive.attributes.find( 
"TEXCOORD_0" );
 
  640        if ( texIt != primitive.attributes.end() )
 
  642          QgsGltfUtils::extractTextureCoordinates(
 
  643            model, texIt->second, texturePointX, texturePointY
 
  647        textureId = qMakePair( mCurrentModelId, pbr.baseColorTexture.index );
 
  658  auto needTriangle = [&outputRect]( 
const QPolygonF & triangle ) -> 
bool 
  660    return triangle.boundingRect().intersects( outputRect );
 
  663  const bool useTexture = !textureImage.isNull();
 
  664  bool hasStoredTexture = 
false;
 
  666  QVector< PrimitiveData > thisTileTriangleData;
 
  668  if ( primitive.indices == -1 )
 
  670    Q_ASSERT( x.size() % 3 == 0 );
 
  672    thisTileTriangleData.reserve( x.size() );
 
  673    for ( 
int i = 0; i < x.size(); i += 3 )
 
  679      data.type = PrimitiveType::Triangle;
 
  680      data.textureId = textureId;
 
  683        data.textureCoords[0] = texturePointX[i];
 
  684        data.textureCoords[1] = texturePointY[i];
 
  685        data.textureCoords[2] = texturePointX[i + 1];
 
  686        data.textureCoords[3] = texturePointY[i + 1];
 
  687        data.textureCoords[4] = texturePointX[i + 2];
 
  688        data.textureCoords[5] = texturePointY[i + 2];
 
  690      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] ) };
 
  691      data.z = ( z[i] + z[i + 1] + z[i + 2] ) / 3;
 
  692      if ( needTriangle( data.coordinates ) )
 
  694        thisTileTriangleData.push_back( data );
 
  695        if ( !hasStoredTexture && !textureImage.isNull() )
 
  698          mTextures.insert( textureId, textureImage.copy() );
 
  699          hasStoredTexture = 
true;
 
  706    const tinygltf::Accessor &primitiveAccessor = model.accessors[primitive.indices];
 
  707    const tinygltf::BufferView &bvPrimitive = model.bufferViews[primitiveAccessor.bufferView];
 
  708    const tinygltf::Buffer &bPrimitive = model.buffers[bvPrimitive.buffer];
 
  710    Q_ASSERT( ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT
 
  711                || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT
 
  712                || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
 
  713              && primitiveAccessor.type == TINYGLTF_TYPE_SCALAR );
 
  715    const char *primitivePtr = 
reinterpret_cast< const char * 
>( bPrimitive.data.data() ) + bvPrimitive.byteOffset + primitiveAccessor.byteOffset;
 
  717    thisTileTriangleData.reserve( primitiveAccessor.count / 3 );
 
  718    for ( std::size_t i = 0; i < primitiveAccessor.count / 3; i++ )
 
  723      unsigned int index1 = 0;
 
  724      unsigned int index2 = 0;
 
  725      unsigned int index3 = 0;
 
  728      data.type = PrimitiveType::Triangle;
 
  729      data.textureId = textureId;
 
  731      if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT )
 
  733        const unsigned short *usPtrPrimitive = 
reinterpret_cast< const unsigned short * 
>( primitivePtr );
 
  734        if ( bvPrimitive.byteStride )
 
  735          primitivePtr += bvPrimitive.byteStride;
 
  737          primitivePtr += 3 * 
sizeof( 
unsigned short );
 
  739        index1 = usPtrPrimitive[0];
 
  740        index2 = usPtrPrimitive[1];
 
  741        index3 = usPtrPrimitive[2];
 
  743      else if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
 
  745        const unsigned char *usPtrPrimitive = 
reinterpret_cast< const unsigned char * 
>( primitivePtr );
 
  746        if ( bvPrimitive.byteStride )
 
  747          primitivePtr += bvPrimitive.byteStride;
 
  749          primitivePtr += 3 * 
sizeof( 
unsigned char );
 
  751        index1 = usPtrPrimitive[0];
 
  752        index2 = usPtrPrimitive[1];
 
  753        index3 = usPtrPrimitive[2];
 
  757        const unsigned int *uintPtrPrimitive = 
reinterpret_cast< const unsigned int * 
>( primitivePtr );
 
  758        if ( bvPrimitive.byteStride )
 
  759          primitivePtr += bvPrimitive.byteStride;
 
  761          primitivePtr += 3 * 
sizeof( 
unsigned int );
 
  763        index1 = uintPtrPrimitive[0];
 
  764        index2 = uintPtrPrimitive[1];
 
  765        index3 = uintPtrPrimitive[2];
 
  770        data.textureCoords[0] = texturePointX[index1];
 
  771        data.textureCoords[1] = texturePointY[index1];
 
  772        data.textureCoords[2] = texturePointX[index2];
 
  773        data.textureCoords[3] = texturePointY[index2];
 
  774        data.textureCoords[4] = texturePointX[index3];
 
  775        data.textureCoords[5] = texturePointY[index3];
 
  778      data.coordinates = { QVector<QPointF>{ QPointF( x[index1], y[index1] ), QPointF( x[index2], y[index2] ), QPointF( x[index3], y[index3] ), QPointF( x[index1], y[index1] ) } };
 
  779      data.z = ( z[index1] + z[index2] + z[index3] ) / 3;
 
  780      if ( needTriangle( data.coordinates ) )
 
  782        thisTileTriangleData.push_back( data );
 
  783        if ( !hasStoredTexture && !textureImage.isNull() )
 
  786          mTextures.insert( textureId, textureImage.copy() );
 
  787          hasStoredTexture = 
true;
 
  800    std::sort( thisTileTriangleData.begin(), thisTileTriangleData.end(), []( 
const PrimitiveData & a, 
const PrimitiveData & b )
 
  805    for ( 
const PrimitiveData &data : std::as_const( thisTileTriangleData ) )
 
  807      if ( useTexture && data.textureId.first >= 0 )
 
  811                                       data.textureCoords[2], data.textureCoords[3],
 
  812                                       data.textureCoords[4], data.textureCoords[5] );
 
  814      mRenderer->renderTriangle( context, data.coordinates );
 
  819  mPrimitiveData.append( thisTileTriangleData );
 
  830void QgsTiledSceneLayerRenderer::renderLinePrimitive( 
const tinygltf::Model &model, 
const tinygltf::Primitive &primitive, 
const QgsTiledSceneTile &tile, 
const QgsVector3D &tileTranslationEcef, 
const QMatrix4x4 *gltfLocalTransform, 
const QString &, 
QgsTiledSceneRenderContext &context )
 
  832  auto posIt = primitive.attributes.find( 
"POSITION" );
 
  833  if ( posIt == primitive.attributes.end() )
 
  835    mErrors << QObject::tr( 
"Could not find POSITION attribute for primitive" );
 
  838  int positionAccessorIndex = posIt->second;
 
  843  QgsGltfUtils::accessorToMapCoordinates(
 
  845    &mSceneToMapTransform,
 
  848    static_cast< 
Qgis::Axis >( tile.metadata().value( QStringLiteral( 
"gltfUpAxis" ), static_cast< int >( 
Qgis::Axis::Y ) ).toInt() ),
 
  855  auto needLine = [&outputRect]( 
const QPolygonF & line ) -> 
bool 
  857    return line.boundingRect().intersects( outputRect );
 
  860  QVector< PrimitiveData > thisTileLineData;
 
  862  if ( primitive.indices == -1 )
 
  864    Q_ASSERT( x.size() % 2 == 0 );
 
  866    thisTileLineData.reserve( x.size() );
 
  867    for ( 
int i = 0; i < x.size(); i += 2 )
 
  873      data.type = PrimitiveType::Line;
 
  874      data.coordinates = QVector<QPointF> { QPointF( x[i], y[i] ), QPointF( x[i + 1], y[i + 1] ) };
 
  876      data.z = std::max( z[i], z[i + 1] );
 
  877      if ( needLine( data.coordinates ) )
 
  879        thisTileLineData.push_back( data );
 
  885    const tinygltf::Accessor &primitiveAccessor = model.accessors[primitive.indices];
 
  886    const tinygltf::BufferView &bvPrimitive = model.bufferViews[primitiveAccessor.bufferView];
 
  887    const tinygltf::Buffer &bPrimitive = model.buffers[bvPrimitive.buffer];
 
  889    Q_ASSERT( ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT
 
  890                || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT
 
  891                || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
 
  892              && primitiveAccessor.type == TINYGLTF_TYPE_SCALAR );
 
  894    const char *primitivePtr = 
reinterpret_cast< const char * 
>( bPrimitive.data.data() ) + bvPrimitive.byteOffset + primitiveAccessor.byteOffset;
 
  896    thisTileLineData.reserve( primitiveAccessor.count / 2 );
 
  897    for ( std::size_t i = 0; i < primitiveAccessor.count / 2; i++ )
 
  902      unsigned int index1 = 0;
 
  903      unsigned int index2 = 0;
 
  906      data.type = PrimitiveType::Line;
 
  908      if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT )
 
  910        const unsigned short *usPtrPrimitive = 
reinterpret_cast< const unsigned short * 
>( primitivePtr );
 
  911        if ( bvPrimitive.byteStride )
 
  912          primitivePtr += bvPrimitive.byteStride;
 
  914          primitivePtr += 2 * 
sizeof( 
unsigned short );
 
  916        index1 = usPtrPrimitive[0];
 
  917        index2 = usPtrPrimitive[1];
 
  919      else if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
 
  921        const unsigned char *usPtrPrimitive = 
reinterpret_cast< const unsigned char * 
>( primitivePtr );
 
  922        if ( bvPrimitive.byteStride )
 
  923          primitivePtr += bvPrimitive.byteStride;
 
  925          primitivePtr += 2 * 
sizeof( 
unsigned char );
 
  927        index1 = usPtrPrimitive[0];
 
  928        index2 = usPtrPrimitive[1];
 
  932        const unsigned int *uintPtrPrimitive = 
reinterpret_cast< const unsigned int * 
>( primitivePtr );
 
  933        if ( bvPrimitive.byteStride )
 
  934          primitivePtr += bvPrimitive.byteStride;
 
  936          primitivePtr += 2 * 
sizeof( 
unsigned int );
 
  938        index1 = uintPtrPrimitive[0];
 
  939        index2 = uintPtrPrimitive[1];
 
  942      data.coordinates = { QVector<QPointF>{ QPointF( x[index1], y[index1] ), QPointF( x[index2], y[index2] ) } };
 
  944      data.z = std::max( z[index1], z[index2] );
 
  945      if ( needLine( data.coordinates ) )
 
  947        thisTileLineData.push_back( data );
 
  959    std::sort( thisTileLineData.begin(), thisTileLineData.end(), []( 
const PrimitiveData & a, 
const PrimitiveData & b )
 
  964    for ( 
const PrimitiveData &data : std::as_const( thisTileLineData ) )
 
  966      mRenderer->renderLine( context, data.coordinates );
 
  971  mPrimitiveData.append( thisTileLineData );
 
Provides global constants and enumerations 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 map coordinates to device 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.
 
Exception thrown on failure to parse Quantized Mesh tile (malformed data).
 
A rectangle specified with double values.
 
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 meters.
 
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.
 
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.
 
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
Center position of relative-to-center coordinates (when used)
 
QByteArray gltf
GLTF binary content.