54#include <Qt3DCore/QTransform>
55#include <Qt3DRender/QGeometryRenderer>
56#include <QtConcurrentRun>
58#include "moc_qgsannotationlayerchunkloader_p.cpp"
60using namespace Qt::StringLiterals;
70 const QgsMarkerSymbol *markerSymbol =
nullptr;
82 struct PictureBillboardGroup
88 bool operator<(
const PictureBillboardGroup &other )
const
90 if ( path != other.path )
91 return path < other.path;
92 return scaleMode < other.scaleMode;
96 struct PictureBillboard
104QgsAnnotationLayerChunkLoader::QgsAnnotationLayerChunkLoader(
111 const QColor &calloutLineColor,
112 double calloutLineWidth,
117 : mRenderContext( context )
119 , mLeafLevel( leafLevel )
121 .mClamping = clamping,
123 .mShowCallouts = showCallouts,
124 .mCalloutLineColor = calloutLineColor,
125 .mCalloutLineWidth = calloutLineWidth,
126 .mTextFormat = textFormat,
133 QgsDebugError( u
"Annotation layers in globe scenes are not supported yet!"_s );
134 setupQuadtree( QgsBox3D( -1e7, -1e7, -1e7, 1e7, 1e7, 1e7 ), -1, leafLevel );
141 if ( layerExtentInMapCrs.isValid() )
143 extent = context.extent().intersect( layerExtentInMapCrs );
145 if ( extent.isValid() )
147 QgsBox3D rootBox3D( extent, zMin, zMax );
150 rootBox3D.grow( 1.0 );
151 setupQuadtree( rootBox3D, -1, leafLevel );
155QFuture<QgsChunkLoaderResult> QgsAnnotationLayerChunkLoader::loadChunk( QgsChunkNode *node )
157 if ( node->level() < mLeafLevel )
159 return QtFuture::makeReadyValueFuture<QgsChunkLoaderResult>( { [
this, node]( Qt3DCore::QEntity *parent ) {
161 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity( parent );
162 entity->setObjectName( mLayer->name() +
"_CONTAINER_" + node->tileId().text() );
167 auto renderCtx = mRenderContext;
177 renderCtx.setExpressionContext( exprContext );
179 QgsCoordinateTransform layerToMapTransform( mLayer->crs(), renderCtx.crs(), renderCtx.transformContext() );
188 QgsDebugError( u
"Error transforming annotation layer extent to 3d map extent: %1"_s.arg( e.
what() ) );
189 return QtFuture::makeReadyValueFuture( QgsChunkLoaderResult::sEmpty );
193 const QStringList itemsList = mLayer->queryIndex( layerExtent );
194 QSet< QString > itemIds( itemsList.begin(), itemsList.end() );
201 itemIds.unite( mLayer->mNonIndexedItems );
203 std::vector< std::unique_ptr< QgsAnnotationItem > > itemsToRender;
204 itemsToRender.reserve( itemIds.size() );
205 std::transform( itemIds.begin(), itemIds.end(), std::back_inserter( itemsToRender ), [
this](
const QString &
id ) -> std::unique_ptr< QgsAnnotationItem > {
206 return std::unique_ptr< QgsAnnotationItem >( mLayer->item( id )->clone() );
209 QString layerName = mLayer->name();
214 return QtConcurrent::run( &QgsAnnotationLayerChunkLoader::loadChunkInWorker, node, rect, layerToMapTransform, layerName, std::move( itemsToRender ), chunkOrigin, renderCtx, mData )
215 .then(
this, [
this]( ChunkData chunkData ) {
217 return QgsChunkLoaderResult { std::bind_front( &QgsAnnotationLayerChunkLoader::createEntity,
this, std::move( chunkData ) ) };
221void QgsAnnotationLayerChunkLoader::loadChunkInWorker(
222 QPromise<ChunkData> &promise,
226 const QString &layerName,
227 const std::vector< std::unique_ptr< QgsAnnotationItem > > &itemsToRender,
230 const QgsAnnotationLayerChunkLoader::LoaderData &data
233 const QgsScopedEvent e( u
"3D"_s, u
"Annotation layer chunk load"_s );
235 QVector< QgsLineString > calloutLines;
236 double zMin = std::numeric_limits< double >::max();
237 double zMax = std::numeric_limits< double >::lowest();
239 std::vector< Billboard > billboards;
240 billboards.reserve( itemsToRender.size() );
241 QVector< QImage > textures;
242 textures.reserve(
static_cast< qsizetype
>( itemsToRender.size() ) );
244 std::vector< TextBillboard > textBillboards;
245 textBillboards.reserve( itemsToRender.size() );
246 QStringList textBillboardTexts;
247 textBillboardTexts.reserve(
static_cast< qsizetype
>( itemsToRender.size() ) );
249 QMap< PictureBillboardGroup, QVector< PictureBillboard > > groupedPictures;
251 QVector< PictureBillboards > pictureBillboards;
252 pictureBillboards.reserve(
static_cast< qsizetype
>( itemsToRender.size() ) );
254 auto addTextBillboard = [layerToMapTransform,
264 QString text = annotationText;
265 if ( annotationTextFormat.allowHtmlFormatting() )
271 if ( !text.isEmpty() )
276 if ( !rect.contains( mapPoint ) )
281 : renderCtx.terrainRenderingEnabled() && renderCtx.terrainGenerator()
282 ? static_cast<float>( renderCtx.terrainGenerator()->heightAt( mapPoint.x(), mapPoint.y(), renderCtx ) * renderCtx.terrainSettings()->verticalScale() )
285 switch ( data.mClamping )
287 case Qgis::AltitudeClamping::Absolute:
290 case Qgis::AltitudeClamping::Terrain:
293 case Qgis::AltitudeClamping::Relative:
294 z = terrainZ + data.mZOffset;
298 TextBillboard billboard;
299 billboard.position = (
QgsVector3D( mapPoint.
x(), mapPoint.
y(), z ) - chunkOrigin ).toVector3D();
300 billboard.text = text;
301 textBillboards.emplace_back( std::move( billboard ) );
302 textBillboardTexts.append( text );
304 if ( data.mShowCallouts )
306 calloutLines << QgsLineString( { mapPoint.x(), mapPoint.x() }, { mapPoint.y(), mapPoint.y() }, { terrainZ, z } );
309 zMax = std::max( zMax, data.mShowCallouts ? std::max( 0.0, z ) : z );
310 zMin = std::min( zMin, data.mShowCallouts ? std::min( 0.0, z ) : z );
319 for (
const std::unique_ptr< QgsAnnotationItem > &item : std::as_const( itemsToRender ) )
321 if ( promise.isCanceled() )
331 if ( marker->symbol() )
337 if ( !rect.contains( mapPoint ) )
342 : renderCtx.terrainRenderingEnabled() && renderCtx.terrainGenerator()
343 ? static_cast<float>( renderCtx.terrainGenerator()->heightAt( mapPoint.x(), mapPoint.y(), renderCtx ) * renderCtx.terrainSettings()->verticalScale() )
346 switch ( data.mClamping )
348 case Qgis::AltitudeClamping::Absolute:
351 case Qgis::AltitudeClamping::Terrain:
354 case Qgis::AltitudeClamping::Relative:
355 z = terrainZ + data.mZOffset;
360 billboard.position = (
QgsVector3D( mapPoint.
x(), mapPoint.
y(), z ) - chunkOrigin ).toVector3D();
361 billboard.textureId = -1;
363 for (
const Billboard &existingBillboard : billboards )
365 if ( existingBillboard.markerSymbol && marker->symbol()->rendersIdenticallyTo( existingBillboard.markerSymbol ) )
368 billboard.textureId = existingBillboard.textureId;
373 if ( billboard.textureId < 0 )
376 billboard.markerSymbol = marker->symbol();
377 billboard.textureId = textures.size();
378 textures.append( QgsPoint3DBillboardMaterial::renderSymbolToImage( marker->symbol(), renderCtx ) );
380 billboards.emplace_back( std::move( billboard ) );
382 if ( data.mShowCallouts )
384 calloutLines << QgsLineString( { mapPoint.x(), mapPoint.x() }, { mapPoint.y(), mapPoint.y() }, { terrainZ, z } );
387 zMax = std::max( zMax, data.mShowCallouts ? std::max( 0.0, z ) : z );
388 zMin = std::min( zMin, data.mShowCallouts ? std::min( 0.0, z ) : z );
398 addTextBillboard( pointText->point(), pointText->text(), pointText->format() );
403 std::unique_ptr< QgsPoint > point(
geos.pointOnSurface() );
406 addTextBillboard( *point, lineText->text(), lineText->format() );
411 switch ( rectText->placementMode() )
416 addTextBillboard( rectText->bounds().center(), rectText->text(), rectText->format() );
426 if ( pictureItem->path().isEmpty() )
435 const QgsPointXY p = pictureItem->bounds().center();
439 mapPoint = layerToMapTransform.
transform( p );
447 if ( !rect.contains( mapPoint ) )
452 : renderCtx.terrainRenderingEnabled() && renderCtx.terrainGenerator()
453 ? static_cast<float>( renderCtx.terrainGenerator()->heightAt( mapPoint.x(), mapPoint.y(), renderCtx ) * renderCtx.terrainSettings()->verticalScale() )
456 switch ( data.mClamping )
458 case Qgis::AltitudeClamping::Absolute:
461 case Qgis::AltitudeClamping::Terrain:
464 case Qgis::AltitudeClamping::Relative:
465 z = terrainZ + data.mZOffset;
469 PictureBillboardGroup billboardGroup;
470 billboardGroup.path = pictureItem->path();
471 billboardGroup.pictureFormat = pictureItem->format();
472 billboardGroup.scaleMode = pictureItem->billboard3DScaleMode();
474 PictureBillboard billboardItem;
475 billboardItem.position = (
QgsVector3D( mapPoint.
x(), mapPoint.
y(), z ) - chunkOrigin ).toVector3D();
476 billboardItem.size = pictureItem->billboard3DSize();
477 if ( billboardItem.size.isEmpty() )
479 constexpr QSizeF DEFAULT_FIXED_SIZE = QSizeF( 128, 128 );
480 constexpr QSizeF DEFAULT_WORLD_SIZE = QSizeF( 20, 20 );
481 billboardItem.size = billboardGroup.scaleMode == Qgis::BillboardScaleMode::ViewIndependent ? DEFAULT_FIXED_SIZE : DEFAULT_WORLD_SIZE;
484 groupedPictures[billboardGroup].append( billboardItem );
486 if ( data.mShowCallouts )
488 calloutLines << QgsLineString( { mapPoint.x(), mapPoint.x() }, { mapPoint.y(), mapPoint.y() }, { terrainZ, z } );
491 zMax = std::max( zMax, data.mShowCallouts ? std::max( 0.0, z ) : z );
492 zMin = std::min( zMin, data.mShowCallouts ? std::min( 0.0, z ) : z );
496 QImage billboardAtlas;
497 QVector< QgsBillboardGeometry::BillboardAtlasData > billboardPositions;
498 if ( !textures.isEmpty() )
504 billboardPositions.reserve(
static_cast< int >( billboards.size() ) );
505 for ( Billboard &billboard : billboards )
507 const QRect textureRect = atlas.
rect( billboard.textureId );
509 geometry.
position = billboard.position;
511 static_cast< float >( textureRect.left() ) /
static_cast< float>( billboardAtlas.width() ), 1 - (
static_cast< float >( textureRect.bottom() ) /
static_cast< float>( billboardAtlas.height() ) )
514 = QVector2D(
static_cast< float >( textureRect.width() ) /
static_cast< float>( billboardAtlas.width() ),
static_cast< float>( textureRect.height() ) /
static_cast< float>( billboardAtlas.height() ) );
515 geometry.
pixelOffset = QPoint( 0, textureRect.height() / 2 );
516 billboardPositions.append( geometry );
521 QgsDebugError( u
"Error encountered building texture atlas"_s );
522 billboardAtlas = QImage();
527 billboardAtlas = QImage();
528 billboardPositions.clear();
531 QImage textBillboardAtlas;
532 QVector< QgsBillboardGeometry::BillboardAtlasData > textBillboardPositions;
533 if ( !textBillboardTexts.isEmpty() )
539 textBillboardPositions.reserve(
static_cast< int >( textBillboards.size() ) );
540 for ( TextBillboard &billboard : textBillboards )
542 int graphemeIndex = 0;
543 const int graphemeCount = atlas.
graphemeCount( billboard.text );
545 const double xOffset = atlas.
totalWidth( billboard.text ) / 2.0;
546 for ( ; graphemeIndex < graphemeCount; ++graphemeIndex )
550 geometry.
position = billboard.position;
552 static_cast< float >( textureRect.left() ) /
static_cast< float>( textBillboardAtlas.width() ),
553 1 - (
static_cast< float >( textureRect.bottom() ) /
static_cast< float>( textBillboardAtlas.height() ) )
556 static_cast< float >( textureRect.width() ) /
static_cast< float>( textBillboardAtlas.width() ),
557 static_cast< float>( textureRect.height() ) /
static_cast< float>( textBillboardAtlas.height() )
561 = QPoint(
static_cast< int >( std::round( -xOffset + pixelOffset.x() + 0.5 * textureRect.width() ) ),
static_cast< int >( std::round( pixelOffset.y() + 0.5 * textureRect.height() ) ) );
562 textBillboardPositions.append( geometry );
568 QgsDebugError( u
"Error encountered building font texture atlas"_s );
569 textBillboardAtlas = QImage();
574 textBillboardAtlas = QImage();
575 textBillboardPositions.clear();
579 for (
auto it = groupedPictures.constBegin(); it != groupedPictures.constEnd(); ++it )
581 QSizeF maxGroupSize( 0, 0 );
582 for (
auto picIt = it.value().constBegin(); picIt != it.value().constEnd(); ++picIt )
584 if ( picIt->size.width() > maxGroupSize.width() )
586 maxGroupSize.setWidth( picIt->size.width() );
588 if ( picIt->size.height() > maxGroupSize.height() )
590 maxGroupSize.setHeight( picIt->size.height() );
595 bool fitsInCache =
false;
598 constexpr int MAXIMUM_PICTURE_TEXTURE_SIZE_FIXED_SIZE = 256;
600 constexpr int MAXIMUM_PICTURE_TEXTURE_SIZE_PERSPECTIVE = 1024;
602 switch ( it.key().pictureFormat )
607 QSize imageSize = originalSize;
608 if ( imageSize.isEmpty() )
610 imageSize = maxGroupSize.toSize();
612 if ( imageSize.width() >= imageSize.height() && imageSize.width() > textureSize )
614 imageSize = QSize( textureSize,
static_cast< int >( std::round( imageSize.height() * textureSize / imageSize.width() ) ) );
616 else if ( imageSize.height() > textureSize )
618 imageSize = QSize(
static_cast< int >( std::round( imageSize.width() * textureSize / imageSize.height() ) ), textureSize );
627 if ( !picture.isNull() && picture.boundingRect().width() > 0 && picture.boundingRect().height() > 0 )
629 const QRectF picRect = picture.boundingRect();
630 QSize imageSize = picRect.size().toSize();
631 if ( imageSize.width() >= imageSize.height() )
633 imageSize = QSize( textureSize,
static_cast< int >( std::round( picRect.height() *
static_cast< double >( textureSize ) / picRect.width() ) ) );
637 imageSize = QSize(
static_cast< int >( std::round( picRect.width() *
static_cast< double >( textureSize ) / picRect.height() ) ), textureSize );
640 image = QImage( imageSize, QImage::Format_ARGB32_Premultiplied );
641 image.fill( Qt::transparent );
643 const double scale =
static_cast< double >( imageSize.width() ) / picRect.width();
645 QPainter painter( &image );
646 painter.setRenderHint( QPainter::Antialiasing );
647 painter.scale( scale, scale );
659 PictureBillboards billboard;
660 billboard.scaleMode = it.key().scaleMode;
661 billboard.image = image;
662 billboard.positions.reserve( it.value().size() );
663 billboard.sizes.reserve( it.value().size() );
664 for (
const PictureBillboard &item : it.value() )
666 billboard.positions.append( item.position );
667 billboard.sizes.append( item.size );
670 pictureBillboards.append( billboard );
676 .layerName = layerName,
677 .chunkOrigin = chunkOrigin,
678 .renderContext = renderCtx,
679 .billboardPositions = std::move( billboardPositions ),
680 .textBillboardPositions = std::move( textBillboardPositions ),
681 .billboardAtlas = std::move( billboardAtlas ),
682 .textBillboardAtlas = std::move( textBillboardAtlas ),
683 .pictureBillboards = std::move( pictureBillboards ),
684 .calloutLines = std::move( calloutLines ),
691Qt3DCore::QEntity *QgsAnnotationLayerChunkLoader::createEntity(
const QgsAnnotationLayerChunkLoader::ChunkData &chunkData, Qt3DCore::QEntity *parent )
694 if ( chunkData.billboardPositions.empty() && chunkData.textBillboardPositions.empty() && chunkData.pictureBillboards.empty() )
698 chunkData.node->setExactBox3D(
QgsBox3D() );
699 chunkData.node->updateParentBoundingBoxesRecursively();
703 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity( parent );
704 entity->setObjectName( chunkData.layerName +
"_" + chunkData.node->tileId().text() );
706 QgsGeoTransform *billboardTransform =
new QgsGeoTransform;
707 billboardTransform->setGeoTranslation( chunkData.chunkOrigin );
708 entity->addComponent( billboardTransform );
710 if ( !chunkData.billboardPositions.empty() )
715 Qt3DRender::QGeometryRenderer *billboardGeometryRenderer =
new Qt3DRender::QGeometryRenderer;
716 billboardGeometryRenderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::TriangleStrip );
717 billboardGeometryRenderer->setGeometry( billboardGeometry );
718 billboardGeometryRenderer->setVertexCount( 4 );
719 billboardGeometryRenderer->setInstanceCount( billboardGeometry->
count() );
725 Qt3DCore::QEntity *billboardEntity =
new Qt3DCore::QEntity;
726 billboardEntity->addComponent( billboardMaterial );
727 billboardEntity->addComponent( billboardGeometryRenderer );
728 billboardEntity->setParent( entity );
731 if ( !chunkData.textBillboardPositions.empty() )
734 textBillboardGeometry->
setBillboardData( chunkData.textBillboardPositions,
true );
736 Qt3DRender::QGeometryRenderer *billboardGeometryRenderer =
new Qt3DRender::QGeometryRenderer;
737 billboardGeometryRenderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::TriangleStrip );
738 billboardGeometryRenderer->setGeometry( textBillboardGeometry );
739 billboardGeometryRenderer->setVertexCount( 4 );
740 billboardGeometryRenderer->setInstanceCount( textBillboardGeometry->
count() );
745 Qt3DCore::QEntity *billboardEntity =
new Qt3DCore::QEntity;
746 billboardEntity->addComponent( billboardMaterial );
747 billboardEntity->addComponent( billboardGeometryRenderer );
748 billboardEntity->setParent( entity );
751 for (
const PictureBillboards &pictureBillboard : chunkData.pictureBillboards )
755 Qt3DRender::QGeometryRenderer *pictureGeometryRenderer =
new Qt3DRender::QGeometryRenderer;
756 pictureGeometryRenderer->setPrimitiveType( Qt3DRender::QGeometryRenderer::TriangleStrip );
757 pictureGeometryRenderer->setGeometry( pictureGeometry );
758 pictureGeometryRenderer->setVertexCount( 4 );
759 pictureGeometryRenderer->setInstanceCount(
static_cast< int >( pictureBillboard.positions.size() ) );
765 Qt3DCore::QEntity *pictureEntity =
new Qt3DCore::QEntity;
766 pictureEntity->addComponent( pictureMaterial );
767 pictureEntity->addComponent( pictureGeometryRenderer );
768 pictureEntity->setParent( entity );
771 if ( mData.mShowCallouts )
773 QgsLineVertexData lineData;
774 lineData.geocentricCoordinates =
false;
779 lineData.addLineString( line, 0,
false );
782 if ( !lineData.pointsA.isEmpty() )
784 QgsLineMaterial *mat =
new QgsLineMaterial;
785 mat->setLineColor( mData.mCalloutLineColor );
786 mat->setLineWidth( mData.mCalloutLineWidth );
788 Qt3DCore::QEntity *calloutEntity = lineData.createSegmentEntity( mat );
789 calloutEntity->setObjectName( parent->objectName() +
"_CALLOUTS" );
790 calloutEntity->setParent( entity );
792 if ( Qt3DCore::QEntity *calloutJoinEntity = lineData.createJoinEntity( mat ) )
794 calloutJoinEntity->setObjectName( parent->objectName() +
"_CALLOUTS_JOINS" );
795 calloutJoinEntity->setParent( entity );
801 if ( chunkData.zMin != std::numeric_limits<double>::max() && chunkData.zMax != std::numeric_limits<double>::lowest() )
803 QgsBox3D box = chunkData.node->box3D();
806 chunkData.node->setExactBox3D( box );
807 chunkData.node->updateParentBoundingBoxesRecursively();
815QgsAnnotationLayerChunkedEntity::QgsAnnotationLayerChunkedEntity(
821 const QColor &calloutLineColor,
822 double calloutLineWidth,
827 : QgsAbstractFeatureBasedChunkedEntity(
830 new QgsAnnotationLayerChunkLoader(
Qgs3DRenderContext::fromMapSettings( map ), layer, 3, clamping, zOffset, showCallouts, calloutLineColor, calloutLineWidth, textFormat, zMin, zMax ),
834 onTerrainElevationOffsetChanged();
837QgsAnnotationLayerChunkedEntity::~QgsAnnotationLayerChunkedEntity()
844bool QgsAnnotationLayerChunkedEntity::applyTerrainOffset()
const
846 if (
auto loader =
static_cast<QgsAnnotationLayerChunkLoader *
>( mChunkLoader ) )
853QList<QgsRayCastHit> QgsAnnotationLayerChunkedEntity::rayIntersection(
const QgsRay3D &ray,
const QgsRayCastContext &context )
const
AltitudeClamping
Altitude clamping.
@ Absolute
Elevation is taken directly from feature and is independent of terrain height (final elevation = feat...
@ Geocentric
Geocentric CRS.
PictureFormat
Picture formats.
@ Unknown
Invalid or unknown image type.
@ Vertex
Clamp every vertex of feature.
BillboardScaleMode
3D billboard scaling modes.
@ Perspective
Billboard size is scaled with perspective distance from camera, using world units.
@ SpatialBounds
Item is rendered inside fixed spatial bounds, and size will depend on map scale.
@ FixedSize
Item is rendered at a fixed size, regardless of map scale. Item's location is georeferenced to a spat...
@ RelativeToMapFrame
Items size and placement is relative to the map's frame, and the item will always be rendered in the ...
@ Reverse
Reverse/inverse transform (from destination to source).
Rendering context for preparation of 3D entities.
QgsCoordinateReferenceSystem crs() const
Returns the coordinate reference system used in the 3D scene.
QgsRectangle extent() const
Returns the 3D scene's 2D extent in the 3D scene's CRS.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
static QgsRectangle tryReprojectExtent2D(const QgsRectangle &extent, const QgsCoordinateReferenceSystem &crs1, const QgsCoordinateReferenceSystem &crs2, const QgsCoordinateTransformContext &context)
Reprojects extent from crs1 to crs2 coordinate reference system with context context.
Abstract base class for annotation items which are drawn with QgsAnnotationLayers.
bool enabled() const
Returns true if the item is enabled and will be rendered in the layer.
Represents a map layer containing a set of georeferenced annotations, e.g.
An annotation item which renders text along a line geometry.
An annotation item which renders a marker symbol at a point location.
An annotation item which renders a picture.
An annotation item which renders a text string at a point location.
An annotation item which renders paragraphs of text within a rectangle.
static QgsImageCache * imageCache()
Returns the application's image cache, used for caching resampled versions of raster images.
static QgsSvgCache * svgCache()
Returns the application's SVG cache, used for caching SVG images and handling parameter replacement w...
Geometry of the billboard rendering for points in 3D map view.
void setBillboardData(const QVector< QgsBillboardGeometry::BillboardAtlasData > &billboards, bool includePixelOffsets=false)
Set the position and texture data for the billboard.
void setPositionsAndSizes(const QVector< QVector3D > &positions, const QVector< QSizeF > &sizes)
Sets per-instance positions and sizes for billboards sharing a single texture.
A 3-dimensional box composed of x, y, z coordinates.
void setZMinimum(double z)
Sets the minimum z value.
void setZMaximum(double z)
Sets the maximum z value.
Qgis::CrsType type() const
Returns the type of the CRS.
Custom exception class for Coordinate Reference System related exceptions.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
static QgsFontTextureAtlas create(const QgsTextFormat &format, const QStringList &strings)
Creates the texture atlas for a set of strings, using the specified text format.
Encapsulates a font texture atlas.
int graphemeCount(const QString &string) const
Returns the number of graphemes to render for a given string.
bool isValid() const
Returns true if the atlas is valid.
QImage renderAtlasTexture() const
Renders the combined texture atlas, containing all required characters.
int totalWidth(const QString &string) const
Returns the total width (in pixels) required for a given string.
QRect textureRectForGrapheme(const QString &string, int graphemeIndex) const
Returns the packed rectangle for the texture for the matching grapheme.
QPoint pixelOffsetForGrapheme(const QString &string, int graphemeIndex) const
Returns the pixel offset at which the texture for the matching grapheme should be placed.
Does vector analysis using the GEOS library and handles import, export, and exception handling.
QSize originalSize(const QString &path, bool blocking=false) const
Returns the original size (in pixels) of the image at the specified path.
QImage pathAsImage(const QString &path, const QSize size, const bool keepAspectRatio, const double opacity, bool &fitsInCache, bool blocking=false, double targetDpi=96, int frameNumber=-1, bool *isMissing=nullptr)
Returns the specified path rendered as an image.
Line string geometry type, with support for z-dimension and m-values.
static void drawPicture(QPainter *painter, const QPointF &point, const QPicture &picture)
Draws a picture onto a painter, correctly applying workarounds to avoid issues with incorrect scaling...
Material of the billboard rendering for points in 3D map view.
void setVerticalOffset(float offset)
Set the vertical offset.
void setTexture2DFromImage(const QImage &image)
Set the texture2D of the billboard from an image.
A representation of a ray in 3D.
Responsible for defining parameters of the ray casting operations in 3D map canvases.
A rectangle specified with double values.
QPicture svgAsPicture(const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor, bool forceVectorOutput=false, double fixedAspectRatio=0, bool blocking=false, const QMap< QString, QString > ¶meters=QMap< QString, QString >())
Returns an SVG drawing as a QPicture.
Represents a document consisting of one or more QgsTextBlock objects.
QStringList toPlainText() const
Returns a list of plain text lines of text representing the document.
static QgsTextDocument fromTextAndFormat(const QStringList &lines, const QgsTextFormat &format)
Constructor for QgsTextDocument consisting of a set of lines, respecting settings from a text format.
Container for all settings relating to text rendering.
static QgsTextureAtlas createFromImages(const QVector< QImage > &images, int maxSide=1000)
Creates a texture atlas for a set of images.
Encapsulates a texture atlas.
bool isValid() const
Returns true if the atlas is valid.
QRect rect(int index) const
Returns the packed rectangle for the texture with the specified index.
QImage renderAtlasTexture() const
Renders the combined texture atlas, containing all source images.
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
Contains geos related utilities and functions.
bool operator<(const QVariant &v1, const QVariant &v2)
Compares two QVariant values and returns whether the first is less than the second.
#define QgsDebugError(str)
#define QGIS_CHECK_MAIN_THREAD_ACCESS
Contains the billboard positions and texture information.
QPoint pixelOffset
Optional pixel offset for billboard.
QVector3D position
Vertex position for billboard placement.
QVector2D textureAtlasOffset
Texture atlas offset for associated billboard texture.
QVector2D textureAtlasSize
Texture atlas size for associated billboard texture.