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 double mapWidthMeters = 0;
167 QgsDebugError( QStringLiteral(
"An error occurred while calculating length" ) );
170 const double mapMetersPerPixel = mapWidthMeters / context->
outputSize().width();
171 const double maximumErrorInMeters = maximumErrorPixels * mapMetersPerPixel;
177 const QVector< QgsVector3D > corners =
QgsBox3D( mapExtent, -10000, 10000 ).
corners();
184 for (
int i = 0; i < 8; ++i )
187 x.append( corner.
x() );
188 y.append( corner.
y() );
189 z.append( corner.
z() );
193 const auto minMaxX = std::minmax_element( x.constBegin(), x.constEnd() );
194 const auto minMaxY = std::minmax_element( y.constBegin(), y.constEnd() );
195 const auto minMaxZ = std::minmax_element( z.constBegin(), z.constEnd() );
208 auto tileIsVisibleInMap = [mapExtent,
this](
const QgsTiledSceneTile & tile )->
bool
214 const QgsGeometry tileGeometry( tile.boundingVolume().as2DGeometry( mSceneToMapTransform ) );
215 return tileGeometry.intersects( mapExtent );
219 QVector< long long > tileIds = mIndex.
getTiles( request );
220 while ( !tileIds.empty() )
225 const long long tileId = tileIds.first();
229 if ( !tile.
isValid() || !tileIsVisibleInMap( tile ) )
237 renderTile( tile, context );
246 const QVector< long long > newTileIdsToRender = mIndex.
getTiles( request );
247 tileIds.append( newTileIdsToRender );
258 renderTile( tile, context );
272 std::sort( mPrimitiveData.begin(), mPrimitiveData.end(), [](
const PrimitiveData & a,
const PrimitiveData & b )
275 if ( qgsDoubleNear( a.z, b.z, 0.001 ) )
278 if ( a.type == PrimitiveType::Line )
280 else if ( b.type == PrimitiveType::Line )
285 for (
const PrimitiveData &data : std::as_const( mPrimitiveData ) )
289 case PrimitiveType::Line:
290 mRenderer->renderLine( context, data.coordinates );
293 case PrimitiveType::Triangle:
298 data.textureCoords[2], data.textureCoords[3],
299 data.textureCoords[4], data.textureCoords[5] );
301 mRenderer->renderTriangle( context, data.coordinates );
306 if ( mRenderTileBorders )
308 QPainter *painter = renderContext()->painter();
309 for (
const TileDetails &tile : std::as_const( mTileDetails ) )
313 if ( tile.hasContent )
315 brush = QBrush( QColor( 0, 0, 255, 10 ) );
316 pen = QPen( QColor( 0, 0, 255, 150 ) );
320 brush = QBrush( QColor( 255, 0, 255, 10 ) );
321 pen = QPen( QColor( 255, 0, 255, 150 ) );
324 painter->setPen( pen );
325 painter->setBrush( brush );
326 painter->drawPolygon( tile.boundary );
329 format.
setColor( QColor( 255, 0, 0 ) );
332 QgsTextRenderer::drawText( QRectF( QPoint( 0, 0 ), renderContext()->outputSize() ).intersected( tile.boundary.boundingRect() ),
344 const bool hasContent = renderTileContent( tile, context );
346 if ( mRenderTileBorders )
351 std::unique_ptr< QgsAbstractGeometry > volumeGeometry( volume.
as2DGeometry( mSceneToMapTransform ) );
352 if (
QgsCurvePolygon *polygon = qgsgeometry_cast< QgsCurvePolygon * >( volumeGeometry.get() ) )
354 QPolygonF volumePolygon = polygon->exteriorRing()->asQPolygonF( );
357 volumePolygon.erase( std::remove_if( volumePolygon.begin(), volumePolygon.end(),
358 [](
const QPointF point )
360 return !std::isfinite( point.x() ) || !std::isfinite( point.y() );
361 } ), volumePolygon.end() );
363 QPointF *ptr = volumePolygon.data();
364 for (
int i = 0; i < volumePolygon.size(); ++i, ++ptr )
370 details.boundary = volumePolygon;
371 details.hasContent = hasContent;
372 details.id = QString::number( tile.
id() );
373 mTileDetails.append( details );
378 QgsDebugError( QStringLiteral(
"Error transforming bounding volume" ) );
385 const QString contentUri = tile.
resources().value( QStringLiteral(
"content" ) ).toString();
386 if ( contentUri.isEmpty() )
394 tinygltf::Model model;
398 const auto &format = tile.
metadata().value( QStringLiteral(
"contentFormat" ) ).value<QString>();
399 if ( format == QLatin1String(
"quantizedmesh" ) )
404 qmTile.removeDegenerateTriangles();
405 model = qmTile.toGltf();
409 QgsDebugError( QStringLiteral(
"Failed to parse tile from '%1'" ).arg( contentUri ) );
413 else if ( format == QLatin1String(
"cesiumtiles" ) )
416 if ( content.
gltf.isEmpty() )
423 QString gltfWarnings;
424 const bool res = QgsGltfUtils::loadGltfModel( content.
gltf, model,
425 &gltfErrors, &gltfWarnings );
426 if ( !gltfErrors.isEmpty() )
428 if ( !
mErrors.contains( gltfErrors ) )
430 QgsDebugError( QStringLiteral(
"Error raised reading %1: %2" )
431 .arg( contentUri, gltfErrors ) );
433 if ( !gltfWarnings.isEmpty() )
435 QgsDebugError( QStringLiteral(
"Warnings raised reading %1: %2" )
436 .arg( contentUri, gltfWarnings ) );
438 if ( !res )
return false;
445 QgsGltfUtils::extractTileTranslation(
448 .value( QStringLiteral(
"gltfUpAxis" ),
452 bool sceneOk =
false;
453 const std::size_t sceneIndex =
454 QgsGltfUtils::sourceSceneForModel( model, sceneOk );
457 const QString error = QObject::tr(
"No scenes found in model" );
460 QStringLiteral(
"Error raised reading %1: %2" ).arg( contentUri, error ) );
464 const tinygltf::Scene &scene = model.scenes[sceneIndex];
466 std::function< void(
int nodeIndex,
const QMatrix4x4 &transform ) > traverseNode;
467 traverseNode = [&model, &context, &tileTranslationEcef, &tile, &contentUri, &traverseNode,
this](
int nodeIndex,
const QMatrix4x4 & parentTransform )
469 const tinygltf::Node &gltfNode = model.nodes[nodeIndex];
470 std::unique_ptr< QMatrix4x4 > gltfLocalTransform = QgsGltfUtils::parseNodeTransform( gltfNode );
472 if ( !parentTransform.isIdentity() )
474 if ( gltfLocalTransform )
475 *gltfLocalTransform = parentTransform * *gltfLocalTransform;
478 gltfLocalTransform.reset(
new QMatrix4x4( parentTransform ) );
482 if ( gltfNode.mesh >= 0 )
484 const tinygltf::Mesh &mesh = model.meshes[gltfNode.mesh];
486 for (
const tinygltf::Primitive &primitive : mesh.primitives )
488 if ( context.renderContext().renderingStopped() )
491 renderPrimitive( model, primitive, tile, tileTranslationEcef, gltfLocalTransform.get(), contentUri, context );
495 for (
int childNode : gltfNode.children )
497 traverseNode( childNode, gltfLocalTransform ? *gltfLocalTransform : QMatrix4x4() );
501 for (
int nodeIndex : scene.nodes )
503 traverseNode( nodeIndex, QMatrix4x4() );
509void QgsTiledSceneLayerRenderer::renderPrimitive(
const tinygltf::Model &model,
const tinygltf::Primitive &primitive,
const QgsTiledSceneTile &tile,
const QgsVector3D &tileTranslationEcef,
const QMatrix4x4 *gltfLocalTransform,
const QString &contentUri,
QgsTiledSceneRenderContext &context )
511 switch ( primitive.mode )
513 case TINYGLTF_MODE_TRIANGLES:
515 renderTrianglePrimitive( model, primitive, tile, tileTranslationEcef, gltfLocalTransform, contentUri, context );
518 case TINYGLTF_MODE_LINE:
520 renderLinePrimitive( model, primitive, tile, tileTranslationEcef, gltfLocalTransform, contentUri, context );
523 case TINYGLTF_MODE_POINTS:
524 if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_POINTS ) )
526 mErrors << QObject::tr(
"Point objects in tiled scenes are not supported" );
527 mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_POINTS );
531 case TINYGLTF_MODE_LINE_LOOP:
532 if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_LINE_LOOP ) )
534 mErrors << QObject::tr(
"Line loops in tiled scenes are not supported" );
535 mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_LINE_LOOP );
539 case TINYGLTF_MODE_LINE_STRIP:
540 if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_LINE_STRIP ) )
542 mErrors << QObject::tr(
"Line strips in tiled scenes are not supported" );
543 mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_LINE_STRIP );
547 case TINYGLTF_MODE_TRIANGLE_STRIP:
548 if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_TRIANGLE_STRIP ) )
550 mErrors << QObject::tr(
"Triangular strips in tiled scenes are not supported" );
551 mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_TRIANGLE_STRIP );
555 case TINYGLTF_MODE_TRIANGLE_FAN:
556 if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_TRIANGLE_FAN ) )
558 mErrors << QObject::tr(
"Triangular fans in tiled scenes are not supported" );
559 mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_TRIANGLE_FAN );
564 if ( !mWarnedPrimitiveTypes.contains( primitive.mode ) )
566 mErrors << QObject::tr(
"Primitive type %1 in tiled scenes are not supported" ).arg( primitive.mode );
567 mWarnedPrimitiveTypes.insert( primitive.mode );
573void QgsTiledSceneLayerRenderer::renderTrianglePrimitive(
const tinygltf::Model &model,
const tinygltf::Primitive &primitive,
const QgsTiledSceneTile &tile,
const QgsVector3D &tileTranslationEcef,
const QMatrix4x4 *gltfLocalTransform,
const QString &contentUri,
QgsTiledSceneRenderContext &context )
575 auto posIt = primitive.attributes.find(
"POSITION" );
576 if ( posIt == primitive.attributes.end() )
578 mErrors << QObject::tr(
"Could not find POSITION attribute for primitive" );
581 int positionAccessorIndex = posIt->second;
586 QgsGltfUtils::accessorToMapCoordinates(
588 &mSceneToMapTransform,
591 static_cast<
Qgis::Axis >( tile.metadata().value( QStringLiteral(
"gltfUpAxis" ), static_cast< int >(
Qgis::Axis::Y ) ).toInt() ),
600 QVector< float > texturePointX;
601 QVector< float > texturePointY;
602 QPair< int, int > textureId{ -1, -1 };
603 if ( needsTextures && primitive.material != -1 )
605 const tinygltf::Material &material = model.materials[primitive.material];
606 const tinygltf::PbrMetallicRoughness &pbr = material.pbrMetallicRoughness;
608 if ( pbr.baseColorTexture.index >= 0
609 &&
static_cast< int >( model.textures.size() ) > pbr.baseColorTexture.index )
611 const tinygltf::Texture &tex = model.textures[pbr.baseColorTexture.index];
613 switch ( QgsGltfUtils::imageResourceType( model, tex.source ) )
615 case QgsGltfUtils::ResourceType::Embedded:
616 textureImage = QgsGltfUtils::extractEmbeddedImage( model, tex.source );
619 case QgsGltfUtils::ResourceType::Linked:
621 const QString linkedPath = QgsGltfUtils::linkedImagePath( model, tex.source );
622 const QString textureUri = QUrl( contentUri ).resolved( linkedPath ).toString();
624 if ( !rep.isEmpty() )
626 textureImage = QImage::fromData( rep );
632 if ( !textureImage.isNull() )
634 auto texIt = primitive.attributes.find(
"TEXCOORD_0" );
635 if ( texIt != primitive.attributes.end() )
637 QgsGltfUtils::extractTextureCoordinates(
638 model, texIt->second, texturePointX, texturePointY
642 textureId = qMakePair( mCurrentModelId, pbr.baseColorTexture.index );
653 auto needTriangle = [&outputRect](
const QPolygonF & triangle ) ->
bool
655 return triangle.boundingRect().intersects( outputRect );
658 const bool useTexture = !textureImage.isNull();
659 bool hasStoredTexture =
false;
661 QVector< PrimitiveData > thisTileTriangleData;
663 if ( primitive.indices == -1 )
665 Q_ASSERT( x.size() % 3 == 0 );
667 thisTileTriangleData.reserve( x.size() );
668 for (
int i = 0; i < x.size(); i += 3 )
674 data.type = PrimitiveType::Triangle;
675 data.textureId = textureId;
678 data.textureCoords[0] = texturePointX[i];
679 data.textureCoords[1] = texturePointY[i];
680 data.textureCoords[2] = texturePointX[i + 1];
681 data.textureCoords[3] = texturePointY[i + 1];
682 data.textureCoords[4] = texturePointX[i + 2];
683 data.textureCoords[5] = texturePointY[i + 2];
685 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] ) };
686 data.z = ( z[i] + z[i + 1] + z[i + 2] ) / 3;
687 if ( needTriangle( data.coordinates ) )
689 thisTileTriangleData.push_back( data );
690 if ( !hasStoredTexture && !textureImage.isNull() )
693 mTextures.insert( textureId, textureImage.copy() );
694 hasStoredTexture =
true;
701 const tinygltf::Accessor &primitiveAccessor = model.accessors[primitive.indices];
702 const tinygltf::BufferView &bvPrimitive = model.bufferViews[primitiveAccessor.bufferView];
703 const tinygltf::Buffer &bPrimitive = model.buffers[bvPrimitive.buffer];
705 Q_ASSERT( ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT
706 || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT
707 || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
708 && primitiveAccessor.type == TINYGLTF_TYPE_SCALAR );
710 const char *primitivePtr =
reinterpret_cast< const char *
>( bPrimitive.data.data() ) + bvPrimitive.byteOffset + primitiveAccessor.byteOffset;
712 thisTileTriangleData.reserve( primitiveAccessor.count / 3 );
713 for ( std::size_t i = 0; i < primitiveAccessor.count / 3; i++ )
718 unsigned int index1 = 0;
719 unsigned int index2 = 0;
720 unsigned int index3 = 0;
723 data.type = PrimitiveType::Triangle;
724 data.textureId = textureId;
726 if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT )
728 const unsigned short *usPtrPrimitive =
reinterpret_cast< const unsigned short *
>( primitivePtr );
729 if ( bvPrimitive.byteStride )
730 primitivePtr += bvPrimitive.byteStride;
732 primitivePtr += 3 *
sizeof(
unsigned short );
734 index1 = usPtrPrimitive[0];
735 index2 = usPtrPrimitive[1];
736 index3 = usPtrPrimitive[2];
738 else if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
740 const unsigned char *usPtrPrimitive =
reinterpret_cast< const unsigned char *
>( primitivePtr );
741 if ( bvPrimitive.byteStride )
742 primitivePtr += bvPrimitive.byteStride;
744 primitivePtr += 3 *
sizeof(
unsigned char );
746 index1 = usPtrPrimitive[0];
747 index2 = usPtrPrimitive[1];
748 index3 = usPtrPrimitive[2];
752 const unsigned int *uintPtrPrimitive =
reinterpret_cast< const unsigned int *
>( primitivePtr );
753 if ( bvPrimitive.byteStride )
754 primitivePtr += bvPrimitive.byteStride;
756 primitivePtr += 3 *
sizeof(
unsigned int );
758 index1 = uintPtrPrimitive[0];
759 index2 = uintPtrPrimitive[1];
760 index3 = uintPtrPrimitive[2];
765 data.textureCoords[0] = texturePointX[index1];
766 data.textureCoords[1] = texturePointY[index1];
767 data.textureCoords[2] = texturePointX[index2];
768 data.textureCoords[3] = texturePointY[index2];
769 data.textureCoords[4] = texturePointX[index3];
770 data.textureCoords[5] = texturePointY[index3];
773 data.coordinates = { QVector<QPointF>{ QPointF( x[index1], y[index1] ), QPointF( x[index2], y[index2] ), QPointF( x[index3], y[index3] ), QPointF( x[index1], y[index1] ) } };
774 data.z = ( z[index1] + z[index2] + z[index3] ) / 3;
775 if ( needTriangle( data.coordinates ) )
777 thisTileTriangleData.push_back( data );
778 if ( !hasStoredTexture && !textureImage.isNull() )
781 mTextures.insert( textureId, textureImage.copy() );
782 hasStoredTexture =
true;
795 std::sort( thisTileTriangleData.begin(), thisTileTriangleData.end(), [](
const PrimitiveData & a,
const PrimitiveData & b )
800 for (
const PrimitiveData &data : std::as_const( thisTileTriangleData ) )
802 if ( useTexture && data.textureId.first >= 0 )
806 data.textureCoords[2], data.textureCoords[3],
807 data.textureCoords[4], data.textureCoords[5] );
809 mRenderer->renderTriangle( context, data.coordinates );
814 mPrimitiveData.append( thisTileTriangleData );
825void QgsTiledSceneLayerRenderer::renderLinePrimitive(
const tinygltf::Model &model,
const tinygltf::Primitive &primitive,
const QgsTiledSceneTile &tile,
const QgsVector3D &tileTranslationEcef,
const QMatrix4x4 *gltfLocalTransform,
const QString &,
QgsTiledSceneRenderContext &context )
827 auto posIt = primitive.attributes.find(
"POSITION" );
828 if ( posIt == primitive.attributes.end() )
830 mErrors << QObject::tr(
"Could not find POSITION attribute for primitive" );
833 int positionAccessorIndex = posIt->second;
838 QgsGltfUtils::accessorToMapCoordinates(
840 &mSceneToMapTransform,
843 static_cast<
Qgis::Axis >( tile.metadata().value( QStringLiteral(
"gltfUpAxis" ), static_cast< int >(
Qgis::Axis::Y ) ).toInt() ),
850 auto needLine = [&outputRect](
const QPolygonF & line ) ->
bool
852 return line.boundingRect().intersects( outputRect );
855 QVector< PrimitiveData > thisTileLineData;
857 if ( primitive.indices == -1 )
859 Q_ASSERT( x.size() % 2 == 0 );
861 thisTileLineData.reserve( x.size() );
862 for (
int i = 0; i < x.size(); i += 2 )
868 data.type = PrimitiveType::Line;
869 data.coordinates = QVector<QPointF> { QPointF( x[i], y[i] ), QPointF( x[i + 1], y[i + 1] ) };
871 data.z = std::max( z[i], z[i + 1] );
872 if ( needLine( data.coordinates ) )
874 thisTileLineData.push_back( data );
880 const tinygltf::Accessor &primitiveAccessor = model.accessors[primitive.indices];
881 const tinygltf::BufferView &bvPrimitive = model.bufferViews[primitiveAccessor.bufferView];
882 const tinygltf::Buffer &bPrimitive = model.buffers[bvPrimitive.buffer];
884 Q_ASSERT( ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT
885 || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT
886 || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
887 && primitiveAccessor.type == TINYGLTF_TYPE_SCALAR );
889 const char *primitivePtr =
reinterpret_cast< const char *
>( bPrimitive.data.data() ) + bvPrimitive.byteOffset + primitiveAccessor.byteOffset;
891 thisTileLineData.reserve( primitiveAccessor.count / 2 );
892 for ( std::size_t i = 0; i < primitiveAccessor.count / 2; i++ )
897 unsigned int index1 = 0;
898 unsigned int index2 = 0;
901 data.type = PrimitiveType::Line;
903 if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT )
905 const unsigned short *usPtrPrimitive =
reinterpret_cast< const unsigned short *
>( primitivePtr );
906 if ( bvPrimitive.byteStride )
907 primitivePtr += bvPrimitive.byteStride;
909 primitivePtr += 2 *
sizeof(
unsigned short );
911 index1 = usPtrPrimitive[0];
912 index2 = usPtrPrimitive[1];
914 else if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
916 const unsigned char *usPtrPrimitive =
reinterpret_cast< const unsigned char *
>( primitivePtr );
917 if ( bvPrimitive.byteStride )
918 primitivePtr += bvPrimitive.byteStride;
920 primitivePtr += 2 *
sizeof(
unsigned char );
922 index1 = usPtrPrimitive[0];
923 index2 = usPtrPrimitive[1];
927 const unsigned int *uintPtrPrimitive =
reinterpret_cast< const unsigned int *
>( primitivePtr );
928 if ( bvPrimitive.byteStride )
929 primitivePtr += bvPrimitive.byteStride;
931 primitivePtr += 2 *
sizeof(
unsigned int );
933 index1 = uintPtrPrimitive[0];
934 index2 = uintPtrPrimitive[1];
937 data.coordinates = { QVector<QPointF>{ QPointF( x[index1], y[index1] ), QPointF( x[index2], y[index2] ) } };
939 data.z = std::max( z[index1], z[index2] );
940 if ( needLine( data.coordinates ) )
942 thisTileLineData.push_back( data );
954 std::sort( thisTileLineData.begin(), thisTileLineData.end(), [](
const PrimitiveData & a,
const PrimitiveData & b )
959 for (
const PrimitiveData &data : std::as_const( thisTileLineData ) )
961 mRenderer->renderLine( context, data.coordinates );
966 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 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.
A class to represent a 2D point.
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.
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
Center position of relative-to-center coordinates (when used)
QByteArray gltf
GLTF binary content.