QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
Loading...
Searching...
No Matches
qgsquickmapcanvasmap.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsquickmapcanvasmap.cpp
3 --------------------------------------
4 Date : 10.12.2014
5 Copyright : (C) 2014 by Matthias Kuhn
6 Email : matthias (at) opengis.ch
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include "qgis.h"
19#include "qgsannotationlayer.h"
21#include "qgsgrouplayer.h"
22#include "qgslabelingresults.h"
25#include "qgsmaprenderercache.h"
27#include "qgsmessagelog.h"
28#include "qgspallabeling.h"
29#include "qgsproject.h"
30#include "qgsquickmapsettings.h"
32#include "qgssymbollayerutils.h"
33#include "qgsvectorlayer.h"
34
35#include <QQuickWindow>
36#include <QSGSimpleTextureNode>
37#include <QScreen>
38#include <QString>
39
40#include "moc_qgsquickmapcanvasmap.cpp"
41
42using namespace Qt::StringLiterals;
43
45 : QQuickItem( parent )
46 , mMapSettings( std::make_unique<QgsQuickMapSettings>() )
47 , mCache( std::make_unique<QgsMapRendererCache>() )
48{
49 connect( this, &QQuickItem::windowChanged, this, &QgsQuickMapCanvasMap::onWindowChanged );
50 connect( &mRefreshTimer, &QTimer::timeout, this, [this] { refreshMap(); } );
51 connect( &mMapUpdateTimer, &QTimer::timeout, this, &QgsQuickMapCanvasMap::renderJobUpdated );
52
53 connect( mMapSettings.get(), &QgsQuickMapSettings::extentChanged, this, &QgsQuickMapCanvasMap::onExtentChanged );
54 connect( mMapSettings.get(), &QgsQuickMapSettings::layersChanged, this, &QgsQuickMapCanvasMap::onLayersChanged );
55 connect( mMapSettings.get(), &QgsQuickMapSettings::temporalStateChanged, this, &QgsQuickMapCanvasMap::onTemporalStateChanged );
56 connect( mMapSettings.get(), &QgsQuickMapSettings::zRangeChanged, this, &QgsQuickMapCanvasMap::onzRangeChanged );
57
60
61 mMapUpdateTimer.setSingleShot( false );
62 mMapUpdateTimer.setInterval( 250 );
63 mRefreshTimer.setSingleShot( true );
64 setTransformOrigin( QQuickItem::TopLeft );
65 setFlags( QQuickItem::ItemHasContents );
66}
67
69
71{
72 return mMapSettings.get();
73}
74
75void QgsQuickMapCanvasMap::zoom( QPointF center, qreal scale )
76{
77 QgsRectangle extent = mMapSettings->extent();
78 QgsPoint oldCenter( extent.center() );
79 QgsPoint mousePos( mMapSettings->screenToCoordinate( center ) );
80
81 QgsPointXY newCenter( mousePos.x() + ( ( oldCenter.x() - mousePos.x() ) * scale ), mousePos.y() + ( ( oldCenter.y() - mousePos.y() ) * scale ) );
82
83 // same as zoomWithCenter (no coordinate transformations are needed)
84 extent.scale( scale, &newCenter );
85 mMapSettings->setExtent( extent );
86}
87
88void QgsQuickMapCanvasMap::pan( QPointF oldPos, QPointF newPos )
89{
90 QgsPoint start = mMapSettings->screenToCoordinate( oldPos.toPoint() );
91 QgsPoint end = mMapSettings->screenToCoordinate( newPos.toPoint() );
92
93 double dx = end.x() - start.x();
94 double dy = end.y() - start.y();
95
96 // modify the extent
97 QgsRectangle extent = mMapSettings->extent();
98
99 extent.setXMinimum( extent.xMinimum() + dx );
100 extent.setXMaximum( extent.xMaximum() + dx );
101 extent.setYMaximum( extent.yMaximum() + dy );
102 extent.setYMinimum( extent.yMinimum() + dy );
103
104 mMapSettings->setExtent( extent );
105}
106
107void QgsQuickMapCanvasMap::refreshMap()
108{
109 stopRendering(); // if any...
110
111 if ( mCacheInvalidations.testFlag( CacheInvalidationType::Temporal ) )
112 {
113 clearTemporalCache();
114 mCacheInvalidations &= ~( static_cast<int>( CacheInvalidationType::Temporal ) );
115 }
116 if ( mCacheInvalidations.testFlag( CacheInvalidationType::Elevation ) )
117 {
118 clearElevationCache();
119 mCacheInvalidations &= ~( static_cast<int>( CacheInvalidationType::Elevation ) );
120 }
121
122 QgsMapSettings mapSettings = mMapSettings->mapSettings();
123 if ( !mapSettings.hasValidSettings() )
124 return;
125
126 //build the expression context
127 QgsExpressionContext expressionContext;
129
130 QgsProject *project = mMapSettings->project();
131 if ( project )
132 {
133 expressionContext << QgsExpressionContextUtils::projectScope( project );
134
135 mapSettings.setLabelingEngineSettings( project->labelingEngineSettings() );
136 mapSettings.setSelectiveMaskingSourceSets( project->selectiveMaskingSourceSetManager()->sets() );
137
138 // render main annotation layer above all other layers
139 QList<QgsMapLayer *> allLayers = mapSettings.layers();
140 allLayers.insert( 0, project->mainAnnotationLayer() );
141 mapSettings.setLayers( allLayers );
142 }
143
144 mapSettings.setExpressionContext( expressionContext );
145
146 // enables on-the-fly simplification of geometries to spend less time rendering
148 // with incremental rendering - enables updates of partially rendered layers (good for WMTS, XYZ layers)
149 mapSettings.setFlag( Qgis::MapSettingsFlag::RenderPartialOutput, mIncrementalRendering );
150
151 // create the renderer job
152 Q_ASSERT( !mJob );
153 mJob = new QgsMapRendererParallelJob( mapSettings );
154
155 if ( mIncrementalRendering )
156 mMapUpdateTimer.start();
157
158 connect( mJob, &QgsMapRendererJob::renderingLayersFinished, this, &QgsQuickMapCanvasMap::renderJobUpdated );
159 connect( mJob, &QgsMapRendererJob::finished, this, &QgsQuickMapCanvasMap::renderJobFinished );
160 mJob->setCache( mCache.get() );
161
162 mJob->start();
163
164 if ( !mSilentRefresh )
165 {
166 emit renderStarting();
167 }
168}
169
170void QgsQuickMapCanvasMap::renderJobUpdated()
171{
172 if ( !mJob )
173 return;
174
175 mImage = mJob->renderedImage();
176 mImageMapSettings = mJob->mapSettings();
177 mDirty = true;
178 // Temporarily freeze the canvas, we only need to reset the geometry but not trigger a repaint
179 bool freeze = mFreeze;
180 mFreeze = true;
181 updateTransform();
182 mFreeze = freeze;
183
184 update();
185}
186
187void QgsQuickMapCanvasMap::renderJobFinished()
188{
189 if ( !mJob )
190 return;
191
192 const QgsMapRendererJob::Errors errors = mJob->errors();
193 for ( const QgsMapRendererJob::Error &error : errors )
194 {
195 QgsMessageLog::logMessage( u"%1 :: %2"_s.arg( error.layerID, error.message ), tr( "Rendering" ) );
196 }
197
198 // take labeling results before emitting renderComplete, so labeling map tools
199 // connected to signal work with correct results
200 delete mLabelingResults;
201 mLabelingResults = mJob->takeLabelingResults();
202
203 mImage = mJob->renderedImage();
204 mImageMapSettings = mJob->mapSettings();
205
206 // now we are in a slot called from mJob - do not delete it immediately
207 // so the class is still valid when the execution returns to the class
208 mJob->deleteLater();
209 mJob = nullptr;
210 mDirty = true;
211 mMapUpdateTimer.stop();
212
213 // Temporarily freeze the canvas, we only need to reset the geometry but not trigger a repaint
214 bool freeze = mFreeze;
215 mFreeze = true;
216 updateTransform();
217 mFreeze = freeze;
218
219 update();
220 if ( !mSilentRefresh )
221 {
222 emit mapCanvasRefreshed();
223 }
224 else
225 {
226 mSilentRefresh = false;
227 }
228
229 if ( mDeferredRefreshPending )
230 {
231 mDeferredRefreshPending = false;
232 mSilentRefresh = true;
233 refresh();
234 }
235}
236
237void QgsQuickMapCanvasMap::layerRepaintRequested( bool deferred )
238{
239 if ( mMapSettings->outputSize().isNull() )
240 return; // the map image size has not been set yet
241
242 if ( !mFreeze )
243 {
244 if ( deferred )
245 {
246 if ( !mJob )
247 {
248 mSilentRefresh = true;
249 refresh();
250 }
251 else
252 {
253 mDeferredRefreshPending = true;
254 }
255 }
256 else
257 {
258 refresh();
259 }
260 }
261}
262
263void QgsQuickMapCanvasMap::onWindowChanged( QQuickWindow *window )
264{
265 if ( mWindow == window )
266 return;
267
268 if ( mWindow )
269 disconnect( mWindow, &QQuickWindow::screenChanged, this, &QgsQuickMapCanvasMap::onScreenChanged );
270
271 if ( window )
272 {
273 connect( window, &QQuickWindow::screenChanged, this, &QgsQuickMapCanvasMap::onScreenChanged );
274 onScreenChanged( window->screen() );
275 }
276
277 mWindow = window;
278}
279
280void QgsQuickMapCanvasMap::onScreenChanged( QScreen *screen )
281{
282 if ( screen )
283 {
284 if ( screen->devicePixelRatio() > 0 )
285 {
286 mMapSettings->setDevicePixelRatio( screen->devicePixelRatio() );
287 }
288 mMapSettings->setOutputDpi( screen->physicalDotsPerInch() );
289 }
290}
291
292void QgsQuickMapCanvasMap::onExtentChanged()
293{
294 updateTransform();
295
296 // And trigger a new rendering job
297 refresh();
298}
299
300void QgsQuickMapCanvasMap::onTemporalStateChanged()
301{
302 mCacheInvalidations |= CacheInvalidationType::Temporal;
303
304 // And trigger a new rendering job
305 refresh();
306}
307
308void QgsQuickMapCanvasMap::onzRangeChanged()
309{
310 mCacheInvalidations |= CacheInvalidationType::Elevation;
311
312 // And trigger a new rendering job
313 refresh();
314}
315
316void QgsQuickMapCanvasMap::updateTransform()
317{
318 QgsRectangle imageExtent = mImageMapSettings.visibleExtent();
319 QgsRectangle newExtent = mMapSettings->mapSettings().visibleExtent();
320 setScale( imageExtent.width() / newExtent.width() );
321
322 QgsPointXY pixelPt = mMapSettings->coordinateToScreen( QgsPoint( imageExtent.xMinimum(), imageExtent.yMaximum() ) );
323 setX( pixelPt.x() );
324 setY( pixelPt.y() );
325}
326
328{
329 return mMapUpdateTimer.interval();
330}
331
333{
334 if ( mMapUpdateTimer.interval() == mapUpdateInterval )
335 return;
336
337 mMapUpdateTimer.setInterval( mapUpdateInterval );
338
340}
341
343{
344 return mIncrementalRendering;
345}
346
348{
349 if ( incrementalRendering == mIncrementalRendering )
350 return;
351
352 mIncrementalRendering = incrementalRendering;
354}
355
357{
358 return mFreeze;
359}
360
362{
363 if ( freeze == mFreeze )
364 return;
365
366 mFreeze = freeze;
367
368 if ( mFreeze )
370 else
371 refresh();
372
373 emit freezeChanged();
374}
375
377{
378 return mJob;
379}
380
381QSGNode *QgsQuickMapCanvasMap::updatePaintNode( QSGNode *oldNode, QQuickItem::UpdatePaintNodeData * )
382{
383 if ( mDirty )
384 {
385 delete oldNode;
386 oldNode = nullptr;
387 mDirty = false;
388 }
389
390 if ( mImage.isNull() )
391 {
392 return nullptr;
393 }
394
395 QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode *>( oldNode );
396 if ( !node )
397 {
398 node = new QSGSimpleTextureNode();
399 QSGTexture *texture = window()->createTextureFromImage( mImage );
400 node->setTexture( texture );
401 node->setOwnsTexture( true );
402 }
403
404 QRectF rect( boundingRect() );
405 QSizeF size = mImage.size();
406 if ( !size.isEmpty() )
407 size /= mMapSettings->devicePixelRatio();
408
409 // Check for resizes that change the w/h ratio
410 if ( !rect.isEmpty() && !size.isEmpty() && !qgsDoubleNear( rect.width() / rect.height(), ( size.width() ) / static_cast<double>( size.height() ), 3 ) )
411 {
412 if ( qgsDoubleNear( rect.height(), mImage.height() ) )
413 {
414 rect.setHeight( rect.width() / size.width() * size.height() );
415 }
416 else
417 {
418 rect.setWidth( rect.height() / size.height() * size.width() );
419 }
420 }
421
422 node->setRect( rect );
423
424 return node;
425}
426
427void QgsQuickMapCanvasMap::geometryChange( const QRectF &newGeometry, const QRectF &oldGeometry )
428{
429 QQuickItem::geometryChange( newGeometry, oldGeometry );
430 if ( newGeometry.size() != oldGeometry.size() )
431 {
432 mMapSettings->setOutputSize( newGeometry.size().toSize() );
433 refresh();
434 }
435}
436
437void QgsQuickMapCanvasMap::onLayersChanged()
438{
439 if ( mMapSettings->extent().isEmpty() )
440 zoomToFullExtent();
441
442 for ( const QMetaObject::Connection &conn : std::as_const( mLayerConnections ) )
443 {
444 disconnect( conn );
445 }
446 mLayerConnections.clear();
447
448 const QList<QgsMapLayer *> layers = mMapSettings->layers();
449 for ( QgsMapLayer *layer : layers )
450 {
451 mLayerConnections << connect( layer, &QgsMapLayer::repaintRequested, this, &QgsQuickMapCanvasMap::layerRepaintRequested );
452 }
453
454 refresh();
455}
456
457void QgsQuickMapCanvasMap::destroyJob( QgsMapRendererJob *job )
458{
459 job->cancel();
460 job->deleteLater();
461}
462
464{
465 if ( mJob )
466 {
467 disconnect( mJob, &QgsMapRendererJob::renderingLayersFinished, this, &QgsQuickMapCanvasMap::renderJobUpdated );
468 disconnect( mJob, &QgsMapRendererJob::finished, this, &QgsQuickMapCanvasMap::renderJobFinished );
469
470 mJob->cancelWithoutBlocking();
471 mJob = nullptr;
472 }
473}
474
475void QgsQuickMapCanvasMap::zoomToFullExtent()
476{
477 QgsRectangle extent;
478 const QList<QgsMapLayer *> layers = mMapSettings->layers();
479 for ( QgsMapLayer *layer : layers )
480 {
481 if ( mMapSettings->destinationCrs() != layer->crs() )
482 {
483 QgsCoordinateTransform transform( layer->crs(), mMapSettings->destinationCrs(), mMapSettings->transformContext() );
484 try
485 {
486 extent.combineExtentWith( transform.transformBoundingBox( layer->extent() ) );
487 }
488 catch ( const QgsCsException &exp )
489 {
490 // Ignore extent if it can't be transformed
491 }
492 }
493 else
494 {
495 extent.combineExtentWith( layer->extent() );
496 }
497 }
498 mMapSettings->setExtent( extent );
499
500 refresh();
501}
502
504{
505 if ( mMapSettings->outputSize().isNull() )
506 return; // the map image size has not been set yet
507
508 if ( !mFreeze )
509 mRefreshTimer.start( 1 );
510}
511
513{
514 if ( mCache )
515 mCache->clear();
516}
517
518void QgsQuickMapCanvasMap::clearTemporalCache()
519{
520 if ( mCache )
521 {
522 bool invalidateLabels = false;
523 const QList<QgsMapLayer *> layerList = mMapSettings->mapSettings().layers();
524 for ( QgsMapLayer *layer : layerList )
525 {
526 bool alreadyInvalidatedThisLayer = false;
527 if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
528 {
529 if ( vl->renderer() && QgsSymbolLayerUtils::rendererFrameRate( vl->renderer() ) > -1 )
530 {
531 // layer has an animated symbol assigned, so we have to redraw it regardless of whether
532 // or not it has temporal settings
533 mCache->invalidateCacheForLayer( layer );
534 alreadyInvalidatedThisLayer = true;
535 // we can't shortcut and "continue" here, as we still need to check whether the layer
536 // will cause label invalidation using the logic below
537 }
538 }
539
540 if ( layer->temporalProperties() && layer->temporalProperties()->isActive() )
541 {
542 if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
543 {
544 if ( vl->labelsEnabled() || vl->diagramsEnabled() )
545 invalidateLabels = true;
546 }
547
548 if ( layer->temporalProperties()->flags() & QgsTemporalProperty::FlagDontInvalidateCachedRendersWhenRangeChanges )
549 continue;
550
551 if ( !alreadyInvalidatedThisLayer )
552 mCache->invalidateCacheForLayer( layer );
553 }
554 else if ( QgsGroupLayer *gl = qobject_cast<QgsGroupLayer *>( layer ) )
555 {
556 const QList<QgsMapLayer *> childLayerList = gl->childLayers();
557 for ( QgsMapLayer *childLayer : childLayerList )
558 {
559 if ( childLayer->temporalProperties() && childLayer->temporalProperties()->isActive() )
560 {
561 if ( childLayer->temporalProperties()->flags() & QgsTemporalProperty::FlagDontInvalidateCachedRendersWhenRangeChanges )
562 continue;
563
564 mCache->invalidateCacheForLayer( layer );
565 break;
566 }
567 }
568 }
569 }
570
571 if ( invalidateLabels )
572 {
573 mCache->clearCacheImage( u"_labels_"_s );
574 mCache->clearCacheImage( u"_preview_labels_"_s );
575 }
576 }
577}
578
579void QgsQuickMapCanvasMap::clearElevationCache()
580{
581 if ( mCache )
582 {
583 bool invalidateLabels = false;
584 const QList<QgsMapLayer *> layerList = mMapSettings->mapSettings().layers();
585 for ( QgsMapLayer *layer : layerList )
586 {
587 if ( layer->elevationProperties() && layer->elevationProperties()->hasElevation() )
588 {
589 if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
590 {
591 if ( vl->labelsEnabled() || vl->diagramsEnabled() )
592 invalidateLabels = true;
593 }
594
596 continue;
597
598 mCache->invalidateCacheForLayer( layer );
599 }
600 else if ( QgsGroupLayer *gl = qobject_cast<QgsGroupLayer *>( layer ) )
601 {
602 const QList<QgsMapLayer *> childLayerList = gl->childLayers();
603 for ( QgsMapLayer *childLayer : childLayerList )
604 {
605 if ( childLayer->elevationProperties() && childLayer->elevationProperties()->hasElevation() )
606 {
607 if ( childLayer->elevationProperties()->flags() & QgsMapLayerElevationProperties::FlagDontInvalidateCachedRendersWhenRangeChanges )
608 continue;
609
610 mCache->invalidateCacheForLayer( layer );
611 break;
612 }
613 }
614 }
615 }
616
617 if ( invalidateLabels )
618 {
619 mCache->clearCacheImage( u"_labels_"_s );
620 mCache->clearCacheImage( u"_preview_labels_"_s );
621 }
622 }
623}
@ UseRenderingOptimization
Enable vector simplification and other rendering optimizations.
Definition qgis.h:2817
@ RenderPartialOutput
Whether to make extra effort to update map image with partially rendered layers (better for interacti...
Definition qgis.h:2821
Handles coordinate transforms between two coordinate systems.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * mapSettingsScope(const QgsMapSettings &mapSettings)
Creates a new scope which contains variables and functions relating to a QgsMapSettings object.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
@ FlagDontInvalidateCachedRendersWhenRangeChanges
Any cached rendering will not be invalidated when z range context is modified.
Base class for all map layer types.
Definition qgsmaplayer.h:83
void repaintRequested(bool deferredUpdate=false)
By emitting this signal the layer tells that either appearance or content have been changed and any v...
Responsible for keeping a cache of rendered images resulting from a map rendering job.
Abstract base class for map rendering implementations.
void renderingLayersFinished()
Emitted when the layers are rendered.
void finished()
emitted when asynchronous rendering is finished (or canceled).
QList< QgsMapRendererJob::Error > Errors
virtual void cancel()=0
Stop the rendering job - does not return until the job has terminated.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
Represents a 2D point.
Definition qgspointxy.h:62
double y
Definition qgspointxy.h:66
double x
Definition qgspointxy.h:65
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:53
double x
Definition qgspoint.h:56
double y
Definition qgspoint.h:57
QgsAnnotationLayer * mainAnnotationLayer()
Returns the main annotation layer associated with the project.
const QgsLabelingEngineSettings & labelingEngineSettings() const
Returns project's global labeling engine settings.
const QgsSelectiveMaskingSourceSetManager * selectiveMaskingSourceSetManager() const
Returns the project's selective masking set manager, which manages storage of a set of selective mask...
void freezeChanged()
When freeze property is set to true, the map canvas does not refresh.
bool isRendering
The isRendering property is set to true while a rendering job is pending for this map canvas map.
void mapCanvasRefreshed()
Signal is emitted when a canvas is refreshed.
void incrementalRenderingChanged()
When the incrementalRendering property is set to true, the automatic refresh of map canvas during ren...
int mapUpdateInterval
Interval in milliseconds after which the map canvas will be updated while a rendering job is ongoing.
void setMapUpdateInterval(int mapUpdateInterval)
Interval in milliseconds after which the map canvas will be updated while a rendering job is ongoing.
void pan(QPointF oldPos, QPointF newPos)
Set map setting's extent (pan the map) based on the difference of positions.
void renderStarting()
Signal is emitted when a rendering is starting.
void stopRendering()
Stop map rendering.
~QgsQuickMapCanvasMap() override
void zoom(QPointF center, qreal scale)
Set map setting's extent (zoom the map) on the center by given scale.
void setIncrementalRendering(bool incrementalRendering)
When the incrementalRendering property is set to true, the automatic refresh of map canvas during ren...
void clearCache()
Clears rendering cache.
void setFreeze(bool freeze)
When freeze property is set to true, the map canvas does not refresh.
QgsQuickMapSettings * mapSettings
The mapSettings property contains configuration for rendering of the map.
void refresh()
Refresh the map canvas.
QSGNode * updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *) override
void mapUpdateIntervalChanged()
Interval in milliseconds after which the map canvas will be updated while a rendering job is ongoing.
bool incrementalRendering
When the incrementalRendering property is set to true, the automatic refresh of map canvas during ren...
bool freeze
When freeze property is set to true, the map canvas does not refresh.
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override
QgsQuickMapCanvasMap(QQuickItem *parent=nullptr)
Create map canvas map.
void isRenderingChanged()
The isRendering property is set to true while a rendering job is pending for this map canvas map.
Encapsulates QgsMapSettings class to offer settings of configuration of map rendering via QML propert...
void extentChanged()
Geographical coordinates of the rectangle that should be rendered.
void layersChanged()
Set list of layers for map rendering.
void temporalStateChanged()
Emitted when the temporal state has changed.
void zRangeChanged()
Emitted when the Z range has changed.
A rectangle specified with double values.
void scale(double scaleFactor, const QgsPointXY *c=nullptr)
Scale the rectangle around its center point.
double xMinimum
double yMinimum
double xMaximum
void setYMinimum(double y)
Set the minimum y value.
void setXMinimum(double x)
Set the minimum x value.
void setYMaximum(double y)
Set the maximum y value.
void setXMaximum(double x)
Set the maximum x value.
double yMaximum
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
QgsPointXY center
QVector< QgsSelectiveMaskingSourceSet > sets() const
Returns a list of all sets contained in the manager.
static double rendererFrameRate(const QgsFeatureRenderer *renderer)
Calculates the frame rate (in frames per second) at which the given renderer must be redrawn.
@ FlagDontInvalidateCachedRendersWhenRangeChanges
Any cached rendering will not be invalidated when temporal range context is modified.
Represents a vector layer which manages a vector based dataset.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6975