46using namespace Qt::StringLiterals;
48#define TINYGLTF_NO_STB_IMAGE
49#define TINYGLTF_NO_STB_IMAGE_WRITE
54 , mLayerName( layer->name() )
56 , mEnableProfile( context.
flags() &
Qgis::RenderContextFlag::RecordProfile )
72 mLayerBoundingVolume = layer->
dataProvider()->boundingVolume();
75 mRenderTileBorders = mRenderer->isTileBorderRenderingEnabled();
79 mPreparationTime = timer.elapsed();
88 if ( !mIndex.isValid() )
91 std::unique_ptr< QgsScopedRuntimeProfile > profile;
94 profile = std::make_unique< QgsScopedRuntimeProfile >( mLayerName, u
"rendering"_s,
layerId() );
95 if ( mPreparationTime > 0 )
99 std::unique_ptr< QgsScopedRuntimeProfile > preparingProfile;
100 if ( mEnableProfile )
102 preparingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr(
"Preparing render" ), u
"rendering"_s );
109 QPainter *painter = rc->
painter();
114 if ( !mClippingRegions.empty() )
116 bool needsPainterClipPath =
false;
118 if ( needsPainterClipPath )
119 rc->
painter()->setClipPath( path, Qt::IntersectClip );
122 mElapsedTimer.start();
126 mRenderer->startRender( context );
128 preparingProfile.reset();
129 std::unique_ptr< QgsScopedRuntimeProfile > renderingProfile;
130 if ( mEnableProfile )
132 renderingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr(
"Rendering" ), u
"rendering"_s );
135 const bool result = renderTiles( context );
136 mRenderer->stopRender( context );
163 const double maximumErrorPixels = context->
convertToPainterUnits( mRenderer->maximumScreenError(), mRenderer->maximumScreenErrorUnit() );
165 const double mapYCenter = 0.5 * ( mapExtent.
yMinimum() + mapExtent.
yMaximum() );
166 const double mapXCenter = 0.5 * ( mapExtent.
xMinimum() + mapExtent.
xMaximum() );
168 double mapMetersPerPixel = 0;
173 catch ( QgsCsException & )
176 QgsDebugError( u
"An error occurred while calculating length"_s );
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() );
214 auto tileIsVisibleInMap = [mapExtent,
this](
const QgsTiledSceneTile &tile ) ->
bool {
219 const QgsGeometry tileGeometry( tile.boundingVolume().as2DGeometry( mSceneToMapTransform ) );
220 return tileGeometry.intersects( mapExtent );
223 QgsTiledSceneRequest request = createBaseRequest();
224 QVector< long long > tileIds = mIndex.getTiles( request );
225 while ( !tileIds.empty() )
230 const long long tileId = tileIds.first();
233 const QgsTiledSceneTile tile = mIndex.getTile( tileId );
234 if ( !tile.
isValid() || !tileIsVisibleInMap( tile ) )
237 switch ( mIndex.childAvailability( tileId ) )
242 renderTile( tile, context );
248 if ( mIndex.fetchHierarchy( tileId,
feedback() ) )
251 const QVector< long long > newTileIdsToRender = mIndex.getTiles( request );
252 tileIds.append( newTileIdsToRender );
255 const QgsTiledSceneTile tile = mIndex.getTile( tileId );
263 renderTile( tile, context );
277 std::sort( mPrimitiveData.begin(), mPrimitiveData.end(), [](
const PrimitiveData &a,
const PrimitiveData &b ) {
279 if ( qgsDoubleNear( a.z, b.z, 0.001 ) )
282 if ( a.type == PrimitiveType::Line )
284 else if ( b.type == PrimitiveType::Line )
289 for (
const PrimitiveData &data : std::as_const( mPrimitiveData ) )
293 case PrimitiveType::Line:
294 mRenderer->renderLine( context, data.coordinates );
297 case PrimitiveType::Triangle:
301 context.
setTextureCoordinates( data.textureCoords[0], data.textureCoords[1], data.textureCoords[2], data.textureCoords[3], data.textureCoords[4], data.textureCoords[5] );
303 mRenderer->renderTriangle( context, data.coordinates );
308 if ( mRenderTileBorders )
310 QPainter *painter = renderContext()->painter();
311 for (
const TileDetails &tile : std::as_const( mTileDetails ) )
315 if ( tile.hasContent )
317 brush = QBrush( QColor( 0, 0, 255, 10 ) );
318 pen = QPen( QColor( 0, 0, 255, 150 ) );
322 brush = QBrush( QColor( 255, 0, 255, 10 ) );
323 pen = QPen( QColor( 255, 0, 255, 150 ) );
326 painter->setPen( pen );
327 painter->setBrush( brush );
328 painter->drawPolygon( tile.boundary );
331 format.
setColor( QColor( 255, 0, 0 ) );
345 const bool hasContent = renderTileContent( tile, context );
347 if ( mRenderTileBorders )
349 const QgsTiledSceneBoundingVolume &volume = tile.
boundingVolume();
352 std::unique_ptr< QgsAbstractGeometry > volumeGeometry( volume.
as2DGeometry( mSceneToMapTransform ) );
355 QPolygonF volumePolygon = polygon->exteriorRing()->asQPolygonF();
359 .erase( std::remove_if( volumePolygon.begin(), volumePolygon.end(), [](
const QPointF point ) { return !std::isfinite( point.x() ) || !std::isfinite( point.y() ); } ), volumePolygon.end() );
361 QPointF *ptr = volumePolygon.data();
362 for (
int i = 0; i < volumePolygon.size(); ++i, ++ptr )
368 details.boundary = volumePolygon;
369 details.hasContent = hasContent;
370 details.id = QString::number( tile.
id() );
371 mTileDetails.append( details );
374 catch ( QgsCsException & )
383 const QString contentUri = tile.
resources().value( u
"content"_s ).toString();
384 if ( contentUri.isEmpty() )
387 const QByteArray tileContent = mIndex.retrieveContent( contentUri,
feedback() );
394 const auto &format = tile.
metadata().value( u
"contentFormat"_s ).value<QString>();
395 if ( format ==
"quantizedmesh"_L1 )
399 QgsQuantizedMeshTile qmTile( tileContent );
400 qmTile.removeDegenerateTriangles();
401 tinygltf::Model model = qmTile.toGltf();
402 renderModel( model, QgsVector3D(), tile, context );
405 catch ( QgsQuantizedMeshParsingException &ex )
407 QgsDebugError( u
"Failed to parse tile from '%1'"_s.arg( contentUri ) );
411 else if ( format ==
"cesiumtiles"_L1 )
414 if ( contents.isEmpty() )
419 for (
int i = 0; i < contents.size(); ++i )
421 const QgsCesiumUtils::TileContents &content = contents[i];
422 if ( content.
gltf.isEmpty() )
425 tinygltf::Model innerModel;
427 QString gltfWarnings;
428 const bool res = QgsGltfUtils::loadGltfModel( content.
gltf, innerModel, &gltfErrors, &gltfWarnings );
429 if ( !gltfErrors.isEmpty() )
431 if ( !
mErrors.contains( gltfErrors ) )
433 QgsDebugError( u
"Error raised reading %1: %2"_s.arg( contentUri, gltfErrors ) );
435 if ( !gltfWarnings.isEmpty() )
437 QgsDebugError( u
"Warnings raised reading %1: %2"_s.arg( contentUri, gltfWarnings ) );
441 QgsDebugMsgLevel( u
"renderTileContent: failed to load glTF model for entry %1"_s.arg( i + 1 ), 2 );
445 renderModel( innerModel, content.
rtcCenter, tile, context );
450 else if ( format ==
"draco"_L1 )
452 QgsGltfUtils::I3SNodeContext i3sContext;
455 tinygltf::Model model;
457 if ( !QgsGltfUtils::loadDracoModel( tileContent, i3sContext, model, &
errors ) )
465 renderModel( model, QgsVector3D(), tile, context );
474 const QString contentUri = tile.
resources().value( u
"content"_s ).toString();
476 const QgsVector3D tileTranslationEcef = centerOffset
477 + QgsGltfUtils::extractTileTranslation( model,
static_cast<Qgis::Axis>( tile.
metadata().value( u
"gltfUpAxis"_s,
static_cast<int>(
Qgis::Axis::Y ) ).toInt() ) );
479 bool sceneOk =
false;
480 const std::size_t sceneIndex = QgsGltfUtils::sourceSceneForModel( model, sceneOk );
483 const QString error = QObject::tr(
"No scenes found in model" );
485 QgsDebugError( u
"Error raised reading %1: %2"_s.arg( contentUri, error ) );
489 const tinygltf::Scene &scene = model.scenes[sceneIndex];
491 std::function< void(
int nodeIndex,
const QMatrix4x4 &transform ) > traverseNode;
492 traverseNode = [&model, &context, &tileTranslationEcef, &tile, &contentUri, &traverseNode,
this](
int nodeIndex,
const QMatrix4x4 &parentTransform ) {
493 const tinygltf::Node &gltfNode = model.nodes[nodeIndex];
494 std::unique_ptr< QMatrix4x4 > gltfLocalTransform = QgsGltfUtils::parseNodeTransform( gltfNode );
496 if ( !parentTransform.isIdentity() )
498 if ( gltfLocalTransform )
499 *gltfLocalTransform = parentTransform * *gltfLocalTransform;
502 gltfLocalTransform = std::make_unique<QMatrix4x4>( parentTransform );
506 if ( gltfNode.mesh >= 0 )
508 const tinygltf::Mesh &mesh = model.meshes[gltfNode.mesh];
510 for (
const tinygltf::Primitive &primitive : mesh.primitives )
512 if ( context.renderContext().renderingStopped() )
515 renderPrimitive( model, primitive, tile, tileTranslationEcef, gltfLocalTransform.get(), contentUri, context );
519 for (
int childNode : gltfNode.children )
521 traverseNode( childNode, gltfLocalTransform ? *gltfLocalTransform : QMatrix4x4() );
525 for (
int nodeIndex : scene.nodes )
527 traverseNode( nodeIndex, QMatrix4x4() );
532void QgsTiledSceneLayerRenderer::renderPrimitive(
533 const tinygltf::Model &model,
534 const tinygltf::Primitive &primitive,
537 const QMatrix4x4 *gltfLocalTransform,
538 const QString &contentUri,
542 switch ( primitive.mode )
544 case TINYGLTF_MODE_TRIANGLES:
546 renderTrianglePrimitive( model, primitive, tile, tileTranslationEcef, gltfLocalTransform, contentUri, context );
549 case TINYGLTF_MODE_LINE:
551 renderLinePrimitive( model, primitive, tile, tileTranslationEcef, gltfLocalTransform, contentUri, context );
554 case TINYGLTF_MODE_POINTS:
555 if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_POINTS ) )
557 mErrors << QObject::tr(
"Point objects in tiled scenes are not supported" );
558 mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_POINTS );
562 case TINYGLTF_MODE_LINE_LOOP:
563 if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_LINE_LOOP ) )
565 mErrors << QObject::tr(
"Line loops in tiled scenes are not supported" );
566 mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_LINE_LOOP );
570 case TINYGLTF_MODE_LINE_STRIP:
571 if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_LINE_STRIP ) )
573 mErrors << QObject::tr(
"Line strips in tiled scenes are not supported" );
574 mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_LINE_STRIP );
578 case TINYGLTF_MODE_TRIANGLE_STRIP:
579 if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_TRIANGLE_STRIP ) )
581 mErrors << QObject::tr(
"Triangular strips in tiled scenes are not supported" );
582 mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_TRIANGLE_STRIP );
586 case TINYGLTF_MODE_TRIANGLE_FAN:
587 if ( !mWarnedPrimitiveTypes.contains( TINYGLTF_MODE_TRIANGLE_FAN ) )
589 mErrors << QObject::tr(
"Triangular fans in tiled scenes are not supported" );
590 mWarnedPrimitiveTypes.insert( TINYGLTF_MODE_TRIANGLE_FAN );
595 if ( !mWarnedPrimitiveTypes.contains( primitive.mode ) )
597 mErrors << QObject::tr(
"Primitive type %1 in tiled scenes are not supported" ).arg( primitive.mode );
598 mWarnedPrimitiveTypes.insert( primitive.mode );
604void QgsTiledSceneLayerRenderer::renderTrianglePrimitive(
605 const tinygltf::Model &model,
606 const tinygltf::Primitive &primitive,
609 const QMatrix4x4 *gltfLocalTransform,
610 const QString &contentUri,
614 auto posIt = primitive.attributes.find(
"POSITION" );
615 if ( posIt == primitive.attributes.end() )
617 mErrors << QObject::tr(
"Could not find POSITION attribute for primitive" );
620 int positionAccessorIndex = posIt->second;
625 QgsGltfUtils::accessorToMapCoordinates(
627 positionAccessorIndex,
629 &mSceneToMapTransform,
643 QVector< float > texturePointX;
644 QVector< float > texturePointY;
645 QPair< int, int > textureId { -1, -1 };
646 if ( needsTextures && primitive.material != -1 )
648 const tinygltf::Material &material = model.materials[primitive.material];
649 const tinygltf::PbrMetallicRoughness &pbr = material.pbrMetallicRoughness;
651 if ( pbr.baseColorTexture.index >= 0 &&
static_cast< int >( model.textures.size() ) > pbr.baseColorTexture.index )
653 const tinygltf::Texture &tex = model.textures[pbr.baseColorTexture.index];
656 if ( tex.source >= 0 )
658 switch ( QgsGltfUtils::imageResourceType( model, tex.source ) )
660 case QgsGltfUtils::ResourceType::Embedded:
661 textureImage = QgsGltfUtils::extractEmbeddedImage( model, tex.source );
664 case QgsGltfUtils::ResourceType::Linked:
666 const QString linkedPath = QgsGltfUtils::linkedImagePath( model, tex.source );
667 const QString textureUri = QUrl( contentUri ).resolved( linkedPath ).toString();
668 const QByteArray rep = mIndex.retrieveContent( textureUri,
feedback() );
669 if ( !rep.isEmpty() )
671 textureImage = QImage::fromData( rep );
678 if ( !textureImage.isNull() )
680 auto texIt = primitive.attributes.find(
"TEXCOORD_0" );
681 if ( texIt != primitive.attributes.end() )
683 QgsGltfUtils::extractTextureCoordinates( model, texIt->second, texturePointX, texturePointY );
686 textureId = qMakePair( mCurrentModelId, pbr.baseColorTexture.index );
697 auto needTriangle = [&outputRect](
const QPolygonF &triangle ) ->
bool {
return triangle.boundingRect().intersects( outputRect ); };
699 const bool useTexture = !textureImage.isNull();
700 bool hasStoredTexture =
false;
702 QVector< PrimitiveData > thisTileTriangleData;
704 if ( primitive.indices == -1 )
706 Q_ASSERT( x.size() % 3 == 0 );
708 thisTileTriangleData.reserve( x.size() );
709 for (
int i = 0; i < x.size(); i += 3 )
715 data.type = PrimitiveType::Triangle;
716 data.textureId = textureId;
719 data.textureCoords[0] = texturePointX[i];
720 data.textureCoords[1] = texturePointY[i];
721 data.textureCoords[2] = texturePointX[i + 1];
722 data.textureCoords[3] = texturePointY[i + 1];
723 data.textureCoords[4] = texturePointX[i + 2];
724 data.textureCoords[5] = texturePointY[i + 2];
726 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] ) };
727 data.z = ( z[i] + z[i + 1] + z[i + 2] ) / 3;
728 if ( needTriangle( data.coordinates ) )
730 thisTileTriangleData.push_back( data );
731 if ( !hasStoredTexture && !textureImage.isNull() )
734 mTextures.insert( textureId, textureImage.copy() );
735 hasStoredTexture =
true;
742 const tinygltf::Accessor &primitiveAccessor = model.accessors[primitive.indices];
743 const tinygltf::BufferView &bvPrimitive = model.bufferViews[primitiveAccessor.bufferView];
744 const tinygltf::Buffer &bPrimitive = model.buffers[bvPrimitive.buffer];
747 ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT
748 || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT
749 || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
750 && primitiveAccessor.type == TINYGLTF_TYPE_SCALAR
753 const char *primitivePtr =
reinterpret_cast< const char *
>( bPrimitive.data.data() ) + bvPrimitive.byteOffset + primitiveAccessor.byteOffset;
755 thisTileTriangleData.reserve( primitiveAccessor.count / 3 );
756 for ( std::size_t i = 0; i < primitiveAccessor.count / 3; i++ )
761 unsigned int index1 = 0;
762 unsigned int index2 = 0;
763 unsigned int index3 = 0;
766 data.type = PrimitiveType::Triangle;
767 data.textureId = textureId;
769 if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT )
771 const unsigned short *usPtrPrimitive =
reinterpret_cast< const unsigned short *
>( primitivePtr );
772 if ( bvPrimitive.byteStride )
773 primitivePtr += bvPrimitive.byteStride;
775 primitivePtr += 3 *
sizeof(
unsigned short );
777 index1 = usPtrPrimitive[0];
778 index2 = usPtrPrimitive[1];
779 index3 = usPtrPrimitive[2];
781 else if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
783 const unsigned char *usPtrPrimitive =
reinterpret_cast< const unsigned char *
>( primitivePtr );
784 if ( bvPrimitive.byteStride )
785 primitivePtr += bvPrimitive.byteStride;
787 primitivePtr += 3 *
sizeof(
unsigned char );
789 index1 = usPtrPrimitive[0];
790 index2 = usPtrPrimitive[1];
791 index3 = usPtrPrimitive[2];
795 const unsigned int *uintPtrPrimitive =
reinterpret_cast< const unsigned int *
>( primitivePtr );
796 if ( bvPrimitive.byteStride )
797 primitivePtr += bvPrimitive.byteStride;
799 primitivePtr += 3 *
sizeof(
unsigned int );
801 index1 = uintPtrPrimitive[0];
802 index2 = uintPtrPrimitive[1];
803 index3 = uintPtrPrimitive[2];
808 data.textureCoords[0] = texturePointX[index1];
809 data.textureCoords[1] = texturePointY[index1];
810 data.textureCoords[2] = texturePointX[index2];
811 data.textureCoords[3] = texturePointY[index2];
812 data.textureCoords[4] = texturePointX[index3];
813 data.textureCoords[5] = texturePointY[index3];
816 data.coordinates = { QVector<QPointF> { QPointF( x[index1], y[index1] ), QPointF( x[index2], y[index2] ), QPointF( x[index3], y[index3] ), QPointF( x[index1], y[index1] ) } };
817 data.z = ( z[index1] + z[index2] + z[index3] ) / 3;
818 if ( needTriangle( data.coordinates ) )
820 thisTileTriangleData.push_back( data );
821 if ( !hasStoredTexture && !textureImage.isNull() )
824 mTextures.insert( textureId, textureImage.copy() );
825 hasStoredTexture =
true;
838 std::sort( thisTileTriangleData.begin(), thisTileTriangleData.end(), [](
const PrimitiveData &a,
const PrimitiveData &b ) { return a.z < b.z; } );
840 for (
const PrimitiveData &data : std::as_const( thisTileTriangleData ) )
842 if ( useTexture && data.textureId.first >= 0 )
845 context.
setTextureCoordinates( data.textureCoords[0], data.textureCoords[1], data.textureCoords[2], data.textureCoords[3], data.textureCoords[4], data.textureCoords[5] );
847 mRenderer->renderTriangle( context, data.coordinates );
852 mPrimitiveData.append( thisTileTriangleData );
863void QgsTiledSceneLayerRenderer::renderLinePrimitive(
864 const tinygltf::Model &model,
865 const tinygltf::Primitive &primitive,
868 const QMatrix4x4 *gltfLocalTransform,
873 auto posIt = primitive.attributes.find(
"POSITION" );
874 if ( posIt == primitive.attributes.end() )
876 mErrors << QObject::tr(
"Could not find POSITION attribute for primitive" );
879 int positionAccessorIndex = posIt->second;
884 QgsGltfUtils::accessorToMapCoordinates(
886 positionAccessorIndex,
888 &mSceneToMapTransform,
900 auto needLine = [&outputRect](
const QPolygonF &line ) ->
bool {
return line.boundingRect().intersects( outputRect ); };
902 QVector< PrimitiveData > thisTileLineData;
904 if ( primitive.indices == -1 )
906 Q_ASSERT( x.size() % 2 == 0 );
908 thisTileLineData.reserve( x.size() );
909 for (
int i = 0; i < x.size(); i += 2 )
915 data.type = PrimitiveType::Line;
916 data.coordinates = QVector<QPointF> { QPointF( x[i], y[i] ), QPointF( x[i + 1], y[i + 1] ) };
918 data.z = std::max( z[i], z[i + 1] );
919 if ( needLine( data.coordinates ) )
921 thisTileLineData.push_back( data );
927 const tinygltf::Accessor &primitiveAccessor = model.accessors[primitive.indices];
928 const tinygltf::BufferView &bvPrimitive = model.bufferViews[primitiveAccessor.bufferView];
929 const tinygltf::Buffer &bPrimitive = model.buffers[bvPrimitive.buffer];
932 ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT
933 || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT
934 || primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
935 && primitiveAccessor.type == TINYGLTF_TYPE_SCALAR
938 const char *primitivePtr =
reinterpret_cast< const char *
>( bPrimitive.data.data() ) + bvPrimitive.byteOffset + primitiveAccessor.byteOffset;
940 thisTileLineData.reserve( primitiveAccessor.count / 2 );
941 for ( std::size_t i = 0; i < primitiveAccessor.count / 2; i++ )
946 unsigned int index1 = 0;
947 unsigned int index2 = 0;
950 data.type = PrimitiveType::Line;
952 if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT )
954 const unsigned short *usPtrPrimitive =
reinterpret_cast< const unsigned short *
>( primitivePtr );
955 if ( bvPrimitive.byteStride )
956 primitivePtr += bvPrimitive.byteStride;
958 primitivePtr += 2 *
sizeof(
unsigned short );
960 index1 = usPtrPrimitive[0];
961 index2 = usPtrPrimitive[1];
963 else if ( primitiveAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE )
965 const unsigned char *usPtrPrimitive =
reinterpret_cast< const unsigned char *
>( primitivePtr );
966 if ( bvPrimitive.byteStride )
967 primitivePtr += bvPrimitive.byteStride;
969 primitivePtr += 2 *
sizeof(
unsigned char );
971 index1 = usPtrPrimitive[0];
972 index2 = usPtrPrimitive[1];
976 const unsigned int *uintPtrPrimitive =
reinterpret_cast< const unsigned int *
>( primitivePtr );
977 if ( bvPrimitive.byteStride )
978 primitivePtr += bvPrimitive.byteStride;
980 primitivePtr += 2 *
sizeof(
unsigned int );
982 index1 = uintPtrPrimitive[0];
983 index2 = uintPtrPrimitive[1];
986 data.coordinates = { QVector<QPointF> { QPointF( x[index1], y[index1] ), QPointF( x[index2], y[index2] ) } };
988 data.z = std::max( z[index1], z[index2] );
989 if ( needLine( data.coordinates ) )
991 thisTileLineData.push_back( data );
1003 std::sort( thisTileLineData.begin(), thisTileLineData.end(), [](
const PrimitiveData &a,
const PrimitiveData &b ) { return a.z < b.z; } );
1005 for (
const PrimitiveData &data : std::as_const( thisTileLineData ) )
1007 mRenderer->renderLine( context, data.coordinates );
1012 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 QVector< QgsCesiumUtils::TileContents > extractTileContent(const QByteArray &tileContent)
Parses tile content and returns a list of TileContents.
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 QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)
QgsVector3D rtcCenter
Center position of relative-to-center coordinates (when used).
QByteArray gltf
GLTF binary content.