45#define TINYGLTF_NO_STB_IMAGE
46#define TINYGLTF_NO_STB_IMAGE_WRITE
51 , mLayerName( layer->name() )
53 , mEnableProfile( context.
flags() &
Qgis::RenderContextFlag::RecordProfile )
69 mLayerBoundingVolume = layer->
dataProvider()->boundingVolume();
72 mRenderTileBorders = mRenderer->isTileBorderRenderingEnabled();
76 mPreparationTime = timer.elapsed();
85 if ( !mIndex.isValid() )
88 std::unique_ptr< QgsScopedRuntimeProfile > profile;
91 profile = std::make_unique< QgsScopedRuntimeProfile >( mLayerName, QStringLiteral(
"rendering" ),
layerId() );
92 if ( mPreparationTime > 0 )
96 std::unique_ptr< QgsScopedRuntimeProfile > preparingProfile;
99 preparingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr(
"Preparing render" ), QStringLiteral(
"rendering" ) );
106 QPainter *painter = rc->
painter();
111 if ( !mClippingRegions.empty() )
113 bool needsPainterClipPath =
false;
115 if ( needsPainterClipPath )
116 rc->
painter()->setClipPath( path, Qt::IntersectClip );
119 mElapsedTimer.start();
123 mRenderer->startRender( context );
125 preparingProfile.reset();
126 std::unique_ptr< QgsScopedRuntimeProfile > renderingProfile;
127 if ( mEnableProfile )
129 renderingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr(
"Rendering" ), QStringLiteral(
"rendering" ) );
132 const bool result = renderTiles( context );
133 mRenderer->stopRender( context );
160 const double maximumErrorPixels = context->
convertToPainterUnits( mRenderer->maximumScreenError(), mRenderer->maximumScreenErrorUnit() );
162 const double mapYCenter = 0.5 * ( mapExtent.
yMinimum() + mapExtent.
yMaximum() );
163 const double mapXCenter = 0.5 * ( mapExtent.
xMinimum() + mapExtent.
xMaximum() );
165 double mapMetersPerPixel = 0;
170 QgsPointXY( mapXCenter + onePixelDistanceX, mapYCenter )
173 catch ( QgsCsException & )
176 QgsDebugError( QStringLiteral(
"An error occurred while calculating length" ) );
179 const double maximumErrorInMeters = maximumErrorPixels * mapMetersPerPixel;
181 QgsTiledSceneRequest request;
185 const QVector< QgsVector3D > corners = QgsBox3D( mapExtent, -10000, 10000 ).corners();
192 for (
int i = 0; i < 8; ++i )
194 const QgsVector3D &corner = corners[i];
195 x.append( corner.
x() );
196 y.append( corner.
y() );
197 z.append( corner.
z() );
201 const auto minMaxX = std::minmax_element( x.constBegin(), x.constEnd() );
202 const auto minMaxY = std::minmax_element( y.constBegin(), y.constEnd() );
203 const auto minMaxZ = std::minmax_element( z.constBegin(), z.constEnd() );
205 QgsOrientedBox3D::fromBox3D( QgsBox3D( *minMaxX.first, *minMaxY.first, *minMaxZ.first, *minMaxX.second, *minMaxY.second, *minMaxZ.second ) )
216 auto tileIsVisibleInMap = [mapExtent,
this](
const QgsTiledSceneTile & tile )->
bool
222 const QgsGeometry tileGeometry( tile.boundingVolume().as2DGeometry( mSceneToMapTransform ) );
223 return tileGeometry.intersects( mapExtent );
226 QgsTiledSceneRequest request = createBaseRequest();
227 QVector< long long > tileIds = mIndex.getTiles( request );
228 while ( !tileIds.empty() )
233 const long long tileId = tileIds.first();
236 const QgsTiledSceneTile tile = mIndex.getTile( tileId );
237 if ( !tile.
isValid() || !tileIsVisibleInMap( tile ) )
240 switch ( mIndex.childAvailability( tileId ) )
245 renderTile( tile, context );
251 if ( mIndex.fetchHierarchy( tileId,
feedback() ) )
254 const QVector< long long > newTileIdsToRender = mIndex.getTiles( request );
255 tileIds.append( newTileIdsToRender );
258 const QgsTiledSceneTile tile = mIndex.getTile( tileId );
266 renderTile( tile, context );
280 std::sort( mPrimitiveData.begin(), mPrimitiveData.end(), [](
const PrimitiveData & a,
const PrimitiveData & b )
283 if ( qgsDoubleNear( a.z, b.z, 0.001 ) )
286 if ( a.type == PrimitiveType::Line )
288 else if ( b.type == PrimitiveType::Line )
293 for (
const PrimitiveData &data : std::as_const( mPrimitiveData ) )
297 case PrimitiveType::Line:
298 mRenderer->renderLine( context, data.coordinates );
301 case PrimitiveType::Triangle:
306 data.textureCoords[2], data.textureCoords[3],
307 data.textureCoords[4], data.textureCoords[5] );
309 mRenderer->renderTriangle( context, data.coordinates );
314 if ( mRenderTileBorders )
316 QPainter *painter = renderContext()->painter();
317 for (
const TileDetails &tile : std::as_const( mTileDetails ) )
321 if ( tile.hasContent )
323 brush = QBrush( QColor( 0, 0, 255, 10 ) );
324 pen = QPen( QColor( 0, 0, 255, 150 ) );
328 brush = QBrush( QColor( 255, 0, 255, 10 ) );
329 pen = QPen( QColor( 255, 0, 255, 150 ) );
332 painter->setPen( pen );
333 painter->setBrush( brush );
334 painter->drawPolygon( tile.boundary );
337 format.
setColor( QColor( 255, 0, 0 ) );
340 QgsTextRenderer::drawText( QRectF( QPoint( 0, 0 ), renderContext()->outputSize() ).intersected( tile.boundary.boundingRect() ),
352 const bool hasContent = renderTileContent( tile, context );
354 if ( mRenderTileBorders )
356 const QgsTiledSceneBoundingVolume &volume = tile.
boundingVolume();
359 std::unique_ptr< QgsAbstractGeometry > volumeGeometry( volume.
as2DGeometry( mSceneToMapTransform ) );
362 QPolygonF volumePolygon = polygon->exteriorRing()->asQPolygonF( );
365 volumePolygon.erase( std::remove_if( volumePolygon.begin(), volumePolygon.end(),
366 [](
const QPointF point )
368 return !std::isfinite( point.x() ) || !std::isfinite( point.y() );
369 } ), volumePolygon.end() );
371 QPointF *ptr = volumePolygon.data();
372 for (
int i = 0; i < volumePolygon.size(); ++i, ++ptr )
378 details.boundary = volumePolygon;
379 details.hasContent = hasContent;
380 details.id = QString::number( tile.
id() );
381 mTileDetails.append( details );
384 catch ( QgsCsException & )
386 QgsDebugError( QStringLiteral(
"Error transforming bounding volume" ) );
393 const QString contentUri = tile.
resources().value( QStringLiteral(
"content" ) ).toString();
394 if ( contentUri.isEmpty() )
397 const QByteArray tileContent = mIndex.retrieveContent( contentUri,
feedback() );
402 tinygltf::Model model;
403 QgsVector3D centerOffset;
406 const auto &format = tile.
metadata().value( QStringLiteral(
"contentFormat" ) ).value<QString>();
407 if ( format == QLatin1String(
"quantizedmesh" ) )
411 QgsQuantizedMeshTile qmTile( tileContent );
412 qmTile.removeDegenerateTriangles();
413 model = qmTile.toGltf();
415 catch ( QgsQuantizedMeshParsingException &ex )
417 QgsDebugError( QStringLiteral(
"Failed to parse tile from '%1'" ).arg( contentUri ) );
421 else if ( format == QLatin1String(
"cesiumtiles" ) )
424 if ( content.
gltf.isEmpty() )
431 QString gltfWarnings;
432 const bool res = QgsGltfUtils::loadGltfModel( content.
gltf, model,
433 &gltfErrors, &gltfWarnings );
434 if ( !gltfErrors.isEmpty() )
436 if ( !
mErrors.contains( gltfErrors ) )
438 QgsDebugError( QStringLiteral(
"Error raised reading %1: %2" )
439 .arg( contentUri, gltfErrors ) );
441 if ( !gltfWarnings.isEmpty() )
443 QgsDebugError( QStringLiteral(
"Warnings raised reading %1: %2" )
444 .arg( contentUri, gltfWarnings ) );
446 if ( !res )
return false;
448 else if ( format == QLatin1String(
"draco" ) )
450 QgsGltfUtils::I3SNodeContext i3sContext;
454 if ( !QgsGltfUtils::loadDracoModel( tileContent, i3sContext, model, &
errors ) )
458 QgsDebugError( QStringLiteral(
"Error raised reading %1: %2" )
459 .arg( contentUri,
errors ) );
466 const QgsVector3D tileTranslationEcef =
468 QgsGltfUtils::extractTileTranslation(
471 .value( QStringLiteral(
"gltfUpAxis" ),
475 bool sceneOk =
false;
476 const std::size_t sceneIndex =
477 QgsGltfUtils::sourceSceneForModel( model, sceneOk );
480 const QString error = QObject::tr(
"No scenes found in model" );
483 QStringLiteral(
"Error raised reading %1: %2" ).arg( contentUri, error ) );
487 const tinygltf::Scene &scene = model.scenes[sceneIndex];
489 std::function< void(
int nodeIndex,
const QMatrix4x4 &transform ) > traverseNode;
490 traverseNode = [&model, &context, &tileTranslationEcef, &tile, &contentUri, &traverseNode,
this](
int nodeIndex,
const QMatrix4x4 & parentTransform )
492 const tinygltf::Node &gltfNode = model.nodes[nodeIndex];
493 std::unique_ptr< QMatrix4x4 > gltfLocalTransform = QgsGltfUtils::parseNodeTransform( gltfNode );
495 if ( !parentTransform.isIdentity() )
497 if ( gltfLocalTransform )
498 *gltfLocalTransform = parentTransform * *gltfLocalTransform;
501 gltfLocalTransform = std::make_unique<QMatrix4x4>( parentTransform );
505 if ( gltfNode.mesh >= 0 )
507 const tinygltf::Mesh &mesh = model.meshes[gltfNode.mesh];
509 for (
const tinygltf::Primitive &primitive : mesh.primitives )
511 if ( context.renderContext().renderingStopped() )
514 renderPrimitive( model, primitive, tile, tileTranslationEcef, gltfLocalTransform.get(), contentUri, context );
518 for (
int childNode : gltfNode.children )
520 traverseNode( childNode, gltfLocalTransform ? *gltfLocalTransform : QMatrix4x4() );
524 for (
int nodeIndex : scene.nodes )
526 traverseNode( nodeIndex, QMatrix4x4() );
532void QgsTiledSceneLayerRenderer::renderPrimitive(
const tinygltf::Model &model,
const tinygltf::Primitive &primitive,
const QgsTiledSceneTile &tile,
const QgsVector3D &tileTranslationEcef,
const QMatrix4x4 *gltfLocalTransform,
const QString &contentUri,
QgsTiledSceneRenderContext &context )
534 switch ( primitive.mode )
536 case TINYGLTF_MODE_TRIANGLES:
538 renderTrianglePrimitive( model, primitive, tile, tileTranslationEcef, gltfLocalTransform, contentUri, context );
541 case TINYGLTF_MODE_LINE:
543 renderLinePrimitive( model, primitive, tile, tileTranslationEcef, gltfLocalTransform, contentUri, context );
546 case TINYGLTF_MODE_POINTS:
547 if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_POINTS ) )
549 mErrors << QObject::tr(
"Point objects in tiled scenes are not supported" );
550 mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_POINTS );
554 case TINYGLTF_MODE_LINE_LOOP:
555 if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_LINE_LOOP ) )
557 mErrors << QObject::tr(
"Line loops in tiled scenes are not supported" );
558 mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_LINE_LOOP );
562 case TINYGLTF_MODE_LINE_STRIP:
563 if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_LINE_STRIP ) )
565 mErrors << QObject::tr(
"Line strips in tiled scenes are not supported" );
566 mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_LINE_STRIP );
570 case TINYGLTF_MODE_TRIANGLE_STRIP:
571 if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_TRIANGLE_STRIP ) )
573 mErrors << QObject::tr(
"Triangular strips in tiled scenes are not supported" );
574 mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_TRIANGLE_STRIP );
578 case TINYGLTF_MODE_TRIANGLE_FAN:
579 if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_TRIANGLE_FAN ) )
581 mErrors << QObject::tr(
"Triangular fans in tiled scenes are not supported" );
582 mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_TRIANGLE_FAN );
587 if ( !mWarnedPrimitiveTypes.contains( primitive.mode ) )
589 mErrors << QObject::tr(
"Primitive type %1 in tiled scenes are not supported" ).arg( primitive.mode );
590 mWarnedPrimitiveTypes.insert( primitive.mode );
596void QgsTiledSceneLayerRenderer::renderTrianglePrimitive(
const tinygltf::Model &model,
const tinygltf::Primitive &primitive,
const QgsTiledSceneTile &tile,
const QgsVector3D &tileTranslationEcef,
const QMatrix4x4 *gltfLocalTransform,
const QString &contentUri,
QgsTiledSceneRenderContext &context )
598 auto posIt = primitive.attributes.find(
"POSITION" );
599 if ( posIt == primitive.attributes.end() )
601 mErrors << QObject::tr(
"Could not find POSITION attribute for primitive" );
604 int positionAccessorIndex = posIt->second;
609 QgsGltfUtils::accessorToMapCoordinates(
611 &mSceneToMapTransform,
623 QVector< float > texturePointX;
624 QVector< float > texturePointY;
625 QPair< int, int > textureId{ -1, -1 };
626 if ( needsTextures && primitive.material != -1 )
628 const tinygltf::Material &material = model.materials[primitive.material];
629 const tinygltf::PbrMetallicRoughness &pbr = material.pbrMetallicRoughness;
631 if ( pbr.baseColorTexture.index >= 0
632 &&
static_cast< int >( model.textures.size() ) > pbr.baseColorTexture.index )
634 const tinygltf::Texture &tex = model.textures[pbr.baseColorTexture.index];
637 if ( tex.source >= 0 )
639 switch ( QgsGltfUtils::imageResourceType( model, tex.source ) )
641 case QgsGltfUtils::ResourceType::Embedded:
642 textureImage = QgsGltfUtils::extractEmbeddedImage( model, tex.source );
645 case QgsGltfUtils::ResourceType::Linked:
647 const QString linkedPath = QgsGltfUtils::linkedImagePath( model, tex.source );
648 const QString textureUri = QUrl( contentUri ).resolved( linkedPath ).toString();
649 const QByteArray rep = mIndex.retrieveContent( textureUri,
feedback() );
650 if ( !rep.isEmpty() )
652 textureImage = QImage::fromData( rep );
659 if ( !textureImage.isNull() )
661 auto texIt = primitive.attributes.find(
"TEXCOORD_0" );
662 if ( texIt != primitive.attributes.end() )
664 QgsGltfUtils::extractTextureCoordinates(
665 model, texIt->second, texturePointX, texturePointY
669 textureId = qMakePair( mCurrentModelId, pbr.baseColorTexture.index );
680 auto needTriangle = [&outputRect](
const QPolygonF & triangle ) ->
bool
682 return triangle.boundingRect().intersects( outputRect );
685 const bool useTexture = !textureImage.isNull();
686 bool hasStoredTexture =
false;
688 QVector< PrimitiveData > thisTileTriangleData;
690 if ( primitive.indices == -1 )
692 Q_ASSERT( x.size() % 3 == 0 );
694 thisTileTriangleData.reserve( x.size() );
695 for (
int i = 0; i < x.size(); i += 3 )
701 data.type = PrimitiveType::Triangle;
702 data.textureId = textureId;
705 data.textureCoords[0] = texturePointX[i];
706 data.textureCoords[1] = texturePointY[i];
707 data.textureCoords[2] = texturePointX[i + 1];
708 data.textureCoords[3] = texturePointY[i + 1];
709 data.textureCoords[4] = texturePointX[i + 2];
710 data.textureCoords[5] = texturePointY[i + 2];
712 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] ) };
713 data.z = ( z[i] + z[i + 1] + z[i + 2] ) / 3;
714 if ( needTriangle( data.coordinates ) )
716 thisTileTriangleData.push_back( data );
717 if ( !hasStoredTexture && !textureImage.isNull() )
720 mTextures.insert( textureId, textureImage.copy() );
721 hasStoredTexture =
true;
728 const tinygltf::Accessor &primitiveAccessor = model.accessors[primitive.indices];
729 const tinygltf::BufferView &bvPrimitive = model.bufferViews[primitiveAccessor.bufferView];
730 const tinygltf::Buffer &bPrimitive = model.buffers[bvPrimitive.buffer];
732 Q_ASSERT( ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT
733 || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT
734 || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
735 && primitiveAccessor.type == TINYGLTF_TYPE_SCALAR );
737 const char *primitivePtr =
reinterpret_cast< const char *
>( bPrimitive.data.data() ) + bvPrimitive.byteOffset + primitiveAccessor.byteOffset;
739 thisTileTriangleData.reserve( primitiveAccessor.count / 3 );
740 for ( std::size_t i = 0; i < primitiveAccessor.count / 3; i++ )
745 unsigned int index1 = 0;
746 unsigned int index2 = 0;
747 unsigned int index3 = 0;
750 data.type = PrimitiveType::Triangle;
751 data.textureId = textureId;
753 if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT )
755 const unsigned short *usPtrPrimitive =
reinterpret_cast< const unsigned short *
>( primitivePtr );
756 if ( bvPrimitive.byteStride )
757 primitivePtr += bvPrimitive.byteStride;
759 primitivePtr += 3 *
sizeof(
unsigned short );
761 index1 = usPtrPrimitive[0];
762 index2 = usPtrPrimitive[1];
763 index3 = usPtrPrimitive[2];
765 else if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
767 const unsigned char *usPtrPrimitive =
reinterpret_cast< const unsigned char *
>( primitivePtr );
768 if ( bvPrimitive.byteStride )
769 primitivePtr += bvPrimitive.byteStride;
771 primitivePtr += 3 *
sizeof(
unsigned char );
773 index1 = usPtrPrimitive[0];
774 index2 = usPtrPrimitive[1];
775 index3 = usPtrPrimitive[2];
779 const unsigned int *uintPtrPrimitive =
reinterpret_cast< const unsigned int *
>( primitivePtr );
780 if ( bvPrimitive.byteStride )
781 primitivePtr += bvPrimitive.byteStride;
783 primitivePtr += 3 *
sizeof(
unsigned int );
785 index1 = uintPtrPrimitive[0];
786 index2 = uintPtrPrimitive[1];
787 index3 = uintPtrPrimitive[2];
792 data.textureCoords[0] = texturePointX[index1];
793 data.textureCoords[1] = texturePointY[index1];
794 data.textureCoords[2] = texturePointX[index2];
795 data.textureCoords[3] = texturePointY[index2];
796 data.textureCoords[4] = texturePointX[index3];
797 data.textureCoords[5] = texturePointY[index3];
800 data.coordinates = { QVector<QPointF>{ QPointF( x[index1], y[index1] ), QPointF( x[index2], y[index2] ), QPointF( x[index3], y[index3] ), QPointF( x[index1], y[index1] ) } };
801 data.z = ( z[index1] + z[index2] + z[index3] ) / 3;
802 if ( needTriangle( data.coordinates ) )
804 thisTileTriangleData.push_back( data );
805 if ( !hasStoredTexture && !textureImage.isNull() )
808 mTextures.insert( textureId, textureImage.copy() );
809 hasStoredTexture =
true;
822 std::sort( thisTileTriangleData.begin(), thisTileTriangleData.end(), [](
const PrimitiveData & a,
const PrimitiveData & b )
827 for (
const PrimitiveData &data : std::as_const( thisTileTriangleData ) )
829 if ( useTexture && data.textureId.first >= 0 )
833 data.textureCoords[2], data.textureCoords[3],
834 data.textureCoords[4], data.textureCoords[5] );
836 mRenderer->renderTriangle( context, data.coordinates );
841 mPrimitiveData.append( thisTileTriangleData );
852void QgsTiledSceneLayerRenderer::renderLinePrimitive(
const tinygltf::Model &model,
const tinygltf::Primitive &primitive,
const QgsTiledSceneTile &tile,
const QgsVector3D &tileTranslationEcef,
const QMatrix4x4 *gltfLocalTransform,
const QString &,
QgsTiledSceneRenderContext &context )
854 auto posIt = primitive.attributes.find(
"POSITION" );
855 if ( posIt == primitive.attributes.end() )
857 mErrors << QObject::tr(
"Could not find POSITION attribute for primitive" );
860 int positionAccessorIndex = posIt->second;
865 QgsGltfUtils::accessorToMapCoordinates(
867 &mSceneToMapTransform,
877 auto needLine = [&outputRect](
const QPolygonF & line ) ->
bool
879 return line.boundingRect().intersects( outputRect );
882 QVector< PrimitiveData > thisTileLineData;
884 if ( primitive.indices == -1 )
886 Q_ASSERT( x.size() % 2 == 0 );
888 thisTileLineData.reserve( x.size() );
889 for (
int i = 0; i < x.size(); i += 2 )
895 data.type = PrimitiveType::Line;
896 data.coordinates = QVector<QPointF> { QPointF( x[i], y[i] ), QPointF( x[i + 1], y[i + 1] ) };
898 data.z = std::max( z[i], z[i + 1] );
899 if ( needLine( data.coordinates ) )
901 thisTileLineData.push_back( data );
907 const tinygltf::Accessor &primitiveAccessor = model.accessors[primitive.indices];
908 const tinygltf::BufferView &bvPrimitive = model.bufferViews[primitiveAccessor.bufferView];
909 const tinygltf::Buffer &bPrimitive = model.buffers[bvPrimitive.buffer];
911 Q_ASSERT( ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT
912 || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT
913 || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
914 && primitiveAccessor.type == TINYGLTF_TYPE_SCALAR );
916 const char *primitivePtr =
reinterpret_cast< const char *
>( bPrimitive.data.data() ) + bvPrimitive.byteOffset + primitiveAccessor.byteOffset;
918 thisTileLineData.reserve( primitiveAccessor.count / 2 );
919 for ( std::size_t i = 0; i < primitiveAccessor.count / 2; i++ )
924 unsigned int index1 = 0;
925 unsigned int index2 = 0;
928 data.type = PrimitiveType::Line;
930 if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT )
932 const unsigned short *usPtrPrimitive =
reinterpret_cast< const unsigned short *
>( primitivePtr );
933 if ( bvPrimitive.byteStride )
934 primitivePtr += bvPrimitive.byteStride;
936 primitivePtr += 2 *
sizeof(
unsigned short );
938 index1 = usPtrPrimitive[0];
939 index2 = usPtrPrimitive[1];
941 else if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
943 const unsigned char *usPtrPrimitive =
reinterpret_cast< const unsigned char *
>( primitivePtr );
944 if ( bvPrimitive.byteStride )
945 primitivePtr += bvPrimitive.byteStride;
947 primitivePtr += 2 *
sizeof(
unsigned char );
949 index1 = usPtrPrimitive[0];
950 index2 = usPtrPrimitive[1];
954 const unsigned int *uintPtrPrimitive =
reinterpret_cast< const unsigned int *
>( primitivePtr );
955 if ( bvPrimitive.byteStride )
956 primitivePtr += bvPrimitive.byteStride;
958 primitivePtr += 2 *
sizeof(
unsigned int );
960 index1 = uintPtrPrimitive[0];
961 index2 = uintPtrPrimitive[1];
964 data.coordinates = { QVector<QPointF>{ QPointF( x[index1], y[index1] ), QPointF( x[index2], y[index2] ) } };
966 data.z = std::max( z[index1], z[index2] );
967 if ( needLine( data.coordinates ) )
969 thisTileLineData.push_back( data );
981 std::sort( thisTileLineData.begin(), thisTileLineData.end(), [](
const PrimitiveData & a,
const PrimitiveData & b )
986 for (
const PrimitiveData &data : std::as_const( thisTileLineData ) )
988 mRenderer->renderLine( context, data.coordinates );
993 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.
static TileContents extractGltfFromTileContent(const QByteArray &tileContent)
Parses tile content.
virtual QgsCoordinateReferenceSystem crs() const =0
Returns the coordinate system for the data source.
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.
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.
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.
QStringList errors() const
Returns list of errors (problems) that happened during the rendering.
QgsMapLayerRenderer(const QString &layerID, QgsRenderContext *context=nullptr)
Constructor for QgsMapLayerRenderer, with the associated layerID and render context.
void transformInPlace(double &x, double &y) const
Transforms map coordinates to device coordinates.
static QgsOrientedBox3D fromBox3D(const QgsBox3D &box)
Constructs an oriented box from an axis-aligned bounding box.
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.
Scoped object for setting the current thread name.
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.
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.
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() override
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).
T qgsgeometry_cast(QgsAbstractGeometry *geom)
#define QgsDebugError(str)
QgsVector3D rtcCenter
Center position of relative-to-center coordinates (when used).
QByteArray gltf
GLTF binary content.