35#include <QQuickWindow>
36#include <QSGSimpleTextureNode>
40#include "moc_qgsquickmapcanvasmap.cpp"
42using namespace Qt::StringLiterals;
45 : QQuickItem( parent )
49 connect(
this, &QQuickItem::windowChanged,
this, &QgsQuickMapCanvasMap::onWindowChanged );
50 connect( &mRefreshTimer, &QTimer::timeout,
this, [
this] { refreshMap(); } );
51 connect( &mMapUpdateTimer, &QTimer::timeout,
this, &QgsQuickMapCanvasMap::renderJobUpdated );
61 mMapUpdateTimer.setSingleShot(
false );
62 mMapUpdateTimer.setInterval( 250 );
63 mRefreshTimer.setSingleShot(
true );
64 setTransformOrigin( QQuickItem::TopLeft );
65 setFlags( QQuickItem::ItemHasContents );
72 return mMapSettings.get();
79 QgsPoint mousePos( mMapSettings->screenToCoordinate( center ) );
81 QgsPointXY newCenter( mousePos.
x() + ( ( oldCenter.
x() - mousePos.
x() ) * scale ), mousePos.
y() + ( ( oldCenter.
y() - mousePos.
y() ) * scale ) );
84 extent.
scale( scale, &newCenter );
85 mMapSettings->setExtent( extent );
90 QgsPoint start = mMapSettings->screenToCoordinate( oldPos.toPoint() );
91 QgsPoint end = mMapSettings->screenToCoordinate( newPos.toPoint() );
93 double dx = end.
x() - start.
x();
94 double dy = end.
y() - start.
y();
104 mMapSettings->setExtent( extent );
107void QgsQuickMapCanvasMap::refreshMap()
111 if ( mCacheInvalidations.testFlag( CacheInvalidationType::Temporal ) )
113 clearTemporalCache();
114 mCacheInvalidations &= ~(
static_cast<int>( CacheInvalidationType::Temporal ) );
116 if ( mCacheInvalidations.testFlag( CacheInvalidationType::Elevation ) )
118 clearElevationCache();
119 mCacheInvalidations &= ~(
static_cast<int>( CacheInvalidationType::Elevation ) );
122 QgsMapSettings
mapSettings = mMapSettings->mapSettings();
127 QgsExpressionContext expressionContext;
131 QgsProject *project = mMapSettings->project();
140 QList<QgsMapLayer *> allLayers =
mapSettings.layers();
145 mapSettings.setExpressionContext( expressionContext );
154 mJob =
new QgsMapRendererParallelJob(
mapSettings );
156 if ( mIncrementalRendering )
157 mMapUpdateTimer.start();
161 mJob->setCache( mCache.get() );
165 if ( !mSilentRefresh )
171void QgsQuickMapCanvasMap::renderJobUpdated()
176 mImage = mJob->renderedImage();
177 mImageMapSettings = mJob->mapSettings();
188void QgsQuickMapCanvasMap::renderJobFinished()
194 for (
const QgsMapRendererJob::Error &error : errors )
201 delete mLabelingResults;
202 mLabelingResults = mJob->takeLabelingResults();
204 mImage = mJob->renderedImage();
205 mImageMapSettings = mJob->mapSettings();
212 mMapUpdateTimer.stop();
221 if ( !mSilentRefresh )
227 mSilentRefresh =
false;
230 if ( mDeferredRefreshPending )
232 mDeferredRefreshPending =
false;
233 mSilentRefresh =
true;
238void QgsQuickMapCanvasMap::layerRepaintRequested(
bool deferred )
240 if ( mMapSettings->outputSize().isNull() )
249 mSilentRefresh =
true;
254 mDeferredRefreshPending =
true;
264void QgsQuickMapCanvasMap::onWindowChanged( QQuickWindow *window )
266 if ( mWindow == window )
270 disconnect( mWindow, &QQuickWindow::screenChanged,
this, &QgsQuickMapCanvasMap::onScreenChanged );
274 connect( window, &QQuickWindow::screenChanged,
this, &QgsQuickMapCanvasMap::onScreenChanged );
275 onScreenChanged( window->screen() );
281void QgsQuickMapCanvasMap::onScreenChanged( QScreen *screen )
285 if ( screen->devicePixelRatio() > 0 )
287 mMapSettings->setDevicePixelRatio( screen->devicePixelRatio() );
289 mMapSettings->setOutputDpi( screen->physicalDotsPerInch() );
293void QgsQuickMapCanvasMap::onExtentChanged()
301void QgsQuickMapCanvasMap::onTemporalStateChanged()
303 mCacheInvalidations |= CacheInvalidationType::Temporal;
309void QgsQuickMapCanvasMap::onzRangeChanged()
311 mCacheInvalidations |= CacheInvalidationType::Elevation;
317void QgsQuickMapCanvasMap::updateTransform()
319 QgsRectangle imageExtent = mImageMapSettings.visibleExtent();
320 QgsRectangle newExtent = mMapSettings->mapSettings().visibleExtent();
321 setScale( imageExtent.
width() / newExtent.
width() );
323 QgsPointXY pixelPt = mMapSettings->coordinateToScreen( QgsPoint( imageExtent.
xMinimum(), imageExtent.
yMaximum() ) );
330 return mMapUpdateTimer.interval();
345 return mIncrementalRendering;
391 if ( mImage.isNull() )
396 QSGSimpleTextureNode *node =
static_cast<QSGSimpleTextureNode *
>( oldNode );
399 node =
new QSGSimpleTextureNode();
400 QSGTexture *texture = window()->createTextureFromImage( mImage );
401 node->setTexture( texture );
402 node->setOwnsTexture(
true );
405 QRectF rect( boundingRect() );
406 QSizeF size = mImage.size();
407 if ( !size.isEmpty() )
408 size /= mMapSettings->devicePixelRatio();
411 if ( !rect.isEmpty() && !size.isEmpty() && !
qgsDoubleNear( rect.width() / rect.height(), ( size.width() ) /
static_cast<double>( size.height() ), 3 ) )
415 rect.setHeight( rect.width() / size.width() * size.height() );
419 rect.setWidth( rect.height() / size.height() * size.width() );
423 node->setRect( rect );
430 QQuickItem::geometryChange( newGeometry, oldGeometry );
431 if ( newGeometry.size() != oldGeometry.size() )
433 mMapSettings->setOutputSize( newGeometry.size().toSize() );
438void QgsQuickMapCanvasMap::onLayersChanged()
440 if ( mMapSettings->extent().isEmpty() )
443 for (
const QMetaObject::Connection &conn : std::as_const( mLayerConnections ) )
447 mLayerConnections.clear();
449 const QList<QgsMapLayer *> layers = mMapSettings->layers();
450 for ( QgsMapLayer *layer : layers )
471 mJob->cancelWithoutBlocking();
476void QgsQuickMapCanvasMap::zoomToFullExtent()
479 const QList<QgsMapLayer *> layers = mMapSettings->layers();
482 if ( mMapSettings->destinationCrs() != layer->crs() )
484 QgsCoordinateTransform transform( layer->crs(), mMapSettings->destinationCrs(), mMapSettings->transformContext() );
489 catch (
const QgsCsException &exp )
499 mMapSettings->setExtent( extent );
506 if ( mMapSettings->outputSize().isNull() )
510 mRefreshTimer.start( 1 );
519void QgsQuickMapCanvasMap::clearTemporalCache()
523 bool invalidateLabels =
false;
524 const QList<QgsMapLayer *> layerList = mMapSettings->mapSettings().layers();
527 bool alreadyInvalidatedThisLayer =
false;
528 if (
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
534 mCache->invalidateCacheForLayer( layer );
535 alreadyInvalidatedThisLayer =
true;
541 if ( layer->temporalProperties() && layer->temporalProperties()->isActive() )
543 if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
545 if ( vl->labelsEnabled() || vl->diagramsEnabled() )
546 invalidateLabels =
true;
552 if ( !alreadyInvalidatedThisLayer )
553 mCache->invalidateCacheForLayer( layer );
555 else if ( QgsGroupLayer *gl = qobject_cast<QgsGroupLayer *>( layer ) )
557 const QList<QgsMapLayer *> childLayerList = gl->childLayers();
558 for ( QgsMapLayer *childLayer : childLayerList )
560 if ( childLayer->temporalProperties() && childLayer->temporalProperties()->isActive() )
565 mCache->invalidateCacheForLayer( layer );
572 if ( invalidateLabels )
574 mCache->clearCacheImage( u
"_labels_"_s );
575 mCache->clearCacheImage( u
"_preview_labels_"_s );
580void QgsQuickMapCanvasMap::clearElevationCache()
584 bool invalidateLabels =
false;
585 const QList<QgsMapLayer *> layerList = mMapSettings->mapSettings().layers();
586 for ( QgsMapLayer *layer : layerList )
588 if ( layer->elevationProperties() && layer->elevationProperties()->hasElevation() )
590 if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
592 if ( vl->labelsEnabled() || vl->diagramsEnabled() )
593 invalidateLabels =
true;
599 mCache->invalidateCacheForLayer( layer );
601 else if ( QgsGroupLayer *gl = qobject_cast<QgsGroupLayer *>( layer ) )
603 const QList<QgsMapLayer *> childLayerList = gl->childLayers();
604 for ( QgsMapLayer *childLayer : childLayerList )
606 if ( childLayer->elevationProperties() && childLayer->elevationProperties()->hasElevation() )
611 mCache->invalidateCacheForLayer( layer );
618 if ( invalidateLabels )
620 mCache->clearCacheImage( u
"_labels_"_s );
621 mCache->clearCacheImage( u
"_preview_labels_"_s );
@ UseRenderingOptimization
Enable vector simplification and other rendering optimizations.
@ RenderPartialOutput
Whether to make extra effort to update map image with partially rendered layers (better for interacti...
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.
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())
Adds a message to the log instance (and creates it if necessary).
Point geometry type, with support for z-dimension and m-values.
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.
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.
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
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).