QGIS API Documentation 3.99.0-Master (d270888f95f)
Loading...
Searching...
No Matches
qgsannotationlayerrenderer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsannotationlayerrenderer.cpp
3 ------------------
4 copyright : (C) 2019 by Sandro Mani
5 email : smani at sourcepole dot ch
6 ***************************************************************************/
7
8/***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16
18
19#include <optional>
20
21#include "qgsannotationlayer.h"
22#include "qgsfeedback.h"
23#include "qgspainteffect.h"
24#include "qgsrendercontext.h"
26#include "qgsthreadingutils.h"
27
28#include <QString>
29
30using namespace Qt::StringLiterals;
31
33 : QgsMapLayerRenderer( layer->id(), &context )
34 , mFeedback( std::make_unique< QgsFeedback >() )
35 , mLayerName( layer->name() )
36 , mLayerOpacity( layer->opacity() )
37 , mLayerBlendMode( layer->blendMode() )
38{
39 if ( QgsMapLayer *linkedLayer = layer->linkedVisibilityLayer() )
40 {
41 if ( !context.customProperties().value( u"visible_layer_ids"_s ).toList().contains( linkedLayer->id() ) )
42 {
43 mReadyToCompose = true;
44 return;
45 }
46 }
47
48 // Clone items from layer which fall inside the rendered extent
49 // Because some items have scale dependent bounds, we have to accept some limitations here.
50 // first, we can use the layer's spatial index to very quickly retrieve items we know will fall within the visible
51 // extent. This will ONLY apply to items which have a non-scale-dependent bounding box though.
52
53 const QStringList itemsList = layer->queryIndex( context.extent() );
54 QSet< QString > items( itemsList.begin(), itemsList.end() );
55
56 // we also have NO choice but to clone ALL non-indexed items (i.e. those with a scale-dependent bounding box)
57 // since these won't be in the layer's spatial index, and it's too expensive to determine their actual bounding box
58 // upfront (we are blocking the main thread right now!)
59
60 // TODO -- come up with some brilliant way to avoid this and also index scale-dependent items ;)
61 items.unite( layer->mNonIndexedItems );
62
63 mItems.reserve( items.size() );
64 std::transform( items.begin(), items.end(), std::back_inserter( mItems ),
65 [layer]( const QString & id ) ->std::pair< QString, std::unique_ptr< QgsAnnotationItem > >
66 {
67 return std::make_pair( id, std::unique_ptr< QgsAnnotationItem >( layer->item( id )->clone() ) );
68 } );
69
70 std::sort( mItems.begin(), mItems.end(), [](
71 const std::pair< QString, std::unique_ptr< QgsAnnotationItem > > &a,
72 const std::pair< QString, std::unique_ptr< QgsAnnotationItem > > &b )
73 { return a.second->zIndex() < b.second->zIndex(); } );
74
75 if ( layer->paintEffect() && layer->paintEffect()->enabled() )
76 {
77 mPaintEffect.reset( layer->paintEffect()->clone() );
78 }
79}
80
82
84{
85 return mFeedback.get();
86}
87
89{
90 QgsScopedThreadName threadName( u"render:%1"_s.arg( mLayerName ) );
91
92 QgsRenderContext &context = *renderContext();
93
94 if ( mPaintEffect )
95 {
96 mPaintEffect->begin( context );
97 }
98
99 bool canceled = false;
100 for ( const std::pair< QString, std::unique_ptr< QgsAnnotationItem > > &item : std::as_const( mItems ) )
101 {
102 if ( mFeedback->isCanceled() )
103 {
104 canceled = true;
105 break;
106 }
107
108 if ( !item.second->enabled() )
109 continue;
110
111 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
112 if ( item.second->useSymbologyReferenceScale() && item.second->flags() & Qgis::AnnotationItemFlag::SupportsReferenceScale )
113 {
114 referenceScaleOverride.emplace( QgsScopedRenderContextReferenceScaleOverride( context, item.second->symbologyReferenceScale() ) );
115 }
116
117 const QgsRectangle bounds = item.second->boundingBox( context );
118 if ( bounds.intersects( context.extent() ) )
119 {
120 item.second->render( context, mFeedback.get() );
121 auto details = std::make_unique< QgsRenderedAnnotationItemDetails >( mLayerID, item.first );
122 details->setBoundingBox( bounds );
123 appendRenderedItemDetails( details.release() );
124 }
125 }
126
127 if ( mPaintEffect )
128 {
129 mPaintEffect->end( context );
130 }
131
132 return !canceled;
133}
134
136{
137 switch ( renderContext()->rasterizedRenderingPolicy() )
138 {
141 break;
142
144 return false;
145 }
146
147 if ( !qgsDoubleNear( mLayerOpacity, 1.0 ) )
148 return true;
149
150 if ( mLayerBlendMode != QPainter::CompositionMode_SourceOver )
151 return true;
152
153 return false;
154}
@ Default
Allow raster-based rendering in situations where it is required for correct rendering or where it wil...
Definition qgis.h:2762
@ PreferVector
Prefer vector-based rendering, when the result will still be visually near-identical to a raster-base...
Definition qgis.h:2763
@ ForceVector
Always force vector-based rendering, even when the result will be visually different to a raster-base...
Definition qgis.h:2764
@ SupportsReferenceScale
Item supports reference scale based rendering.
Definition qgis.h:2524
bool forceRasterRender() const override
Returns true if the renderer must be rendered to a raster paint device (e.g.
~QgsAnnotationLayerRenderer() override
bool render() override
Do the rendering (based on data stored in the class).
QgsFeedback * feedback() const override
Access to feedback object of the layer renderer (may be nullptr).
QgsAnnotationLayerRenderer(QgsAnnotationLayer *layer, QgsRenderContext &context)
Constructor for a QgsAnnotationLayerRenderer, for the specified layer.
Represents a map layer containing a set of georeferenced annotations, e.g.
QgsMapLayer * linkedVisibilityLayer()
Returns a linked layer, where the items in this annotation layer will only be visible when the linked...
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
void appendRenderedItemDetails(QgsRenderedItemDetails *details)
Appends the details of a rendered item to the renderer.
QgsRenderContext * renderContext()
Returns the render context associated with the renderer.
QgsMapLayerRenderer(const QString &layerID, QgsRenderContext *context=nullptr)
Constructor for QgsMapLayerRenderer, with the associated layerID and render context.
Base class for all map layer types.
Definition qgsmaplayer.h:83
A rectangle specified with double values.
bool intersects(const QgsRectangle &rect) const
Returns true when rectangle intersects with other rectangle.
Contains information about the context of a rendering operation.
double symbologyReferenceScale() const
Returns the symbology reference scale.
const QgsRectangle & extent() const
When rendering a map layer, calling this method returns the "clipping" extent for the layer (in the l...
Scoped object for temporary override of the symbologyReferenceScale property of a QgsRenderContext.
Scoped object for setting the current thread name.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6900