34#include <QQuickWindow>
35#include <QSGSimpleTextureNode>
39#include "moc_qgsquickmapcanvasmap.cpp"
41using namespace Qt::StringLiterals;
44 : QQuickItem( parent )
48 connect(
this, &QQuickItem::windowChanged,
this, &QgsQuickMapCanvasMap::onWindowChanged );
49 connect( &mRefreshTimer, &QTimer::timeout,
this, [
this] { refreshMap(); } );
50 connect( &mMapUpdateTimer, &QTimer::timeout,
this, &QgsQuickMapCanvasMap::renderJobUpdated );
60 mMapUpdateTimer.setSingleShot(
false );
61 mMapUpdateTimer.setInterval( 250 );
62 mRefreshTimer.setSingleShot(
true );
63 setTransformOrigin( QQuickItem::TopLeft );
64 setFlags( QQuickItem::ItemHasContents );
71 return mMapSettings.get();
78 QgsPoint mousePos( mMapSettings->screenToCoordinate( center ) );
80 QgsPointXY newCenter( mousePos.
x() + ( ( oldCenter.
x() - mousePos.
x() ) * scale ), mousePos.
y() + ( ( oldCenter.
y() - mousePos.
y() ) * scale ) );
83 extent.
scale( scale, &newCenter );
84 mMapSettings->setExtent( extent );
89 QgsPoint start = mMapSettings->screenToCoordinate( oldPos.toPoint() );
90 QgsPoint end = mMapSettings->screenToCoordinate( newPos.toPoint() );
92 double dx = end.
x() - start.
x();
93 double dy = end.
y() - start.
y();
103 mMapSettings->setExtent( extent );
106void QgsQuickMapCanvasMap::refreshMap()
110 if ( mCacheInvalidations.testFlag( CacheInvalidationType::Temporal ) )
112 clearTemporalCache();
113 mCacheInvalidations &= ~(
static_cast<int>( CacheInvalidationType::Temporal ) );
115 if ( mCacheInvalidations.testFlag( CacheInvalidationType::Elevation ) )
117 clearElevationCache();
118 mCacheInvalidations &= ~(
static_cast<int>( CacheInvalidationType::Elevation ) );
121 QgsMapSettings
mapSettings = mMapSettings->mapSettings();
126 QgsExpressionContext expressionContext;
130 QgsProject *project = mMapSettings->project();
138 QList<QgsMapLayer *> allLayers =
mapSettings.layers();
143 mapSettings.setExpressionContext( expressionContext );
152 mJob =
new QgsMapRendererParallelJob(
mapSettings );
154 if ( mIncrementalRendering )
155 mMapUpdateTimer.start();
159 mJob->setCache( mCache.get() );
163 if ( !mSilentRefresh )
169void QgsQuickMapCanvasMap::renderJobUpdated()
174 mImage = mJob->renderedImage();
175 mImageMapSettings = mJob->mapSettings();
186void QgsQuickMapCanvasMap::renderJobFinished()
192 for (
const QgsMapRendererJob::Error &error : errors )
199 delete mLabelingResults;
200 mLabelingResults = mJob->takeLabelingResults();
202 mImage = mJob->renderedImage();
203 mImageMapSettings = mJob->mapSettings();
210 mMapUpdateTimer.stop();
219 if ( !mSilentRefresh )
225 mSilentRefresh =
false;
228 if ( mDeferredRefreshPending )
230 mDeferredRefreshPending =
false;
231 mSilentRefresh =
true;
236void QgsQuickMapCanvasMap::layerRepaintRequested(
bool deferred )
238 if ( mMapSettings->outputSize().isNull() )
247 mSilentRefresh =
true;
252 mDeferredRefreshPending =
true;
262void QgsQuickMapCanvasMap::onWindowChanged( QQuickWindow *window )
264 if ( mWindow == window )
268 disconnect( mWindow, &QQuickWindow::screenChanged,
this, &QgsQuickMapCanvasMap::onScreenChanged );
272 connect( window, &QQuickWindow::screenChanged,
this, &QgsQuickMapCanvasMap::onScreenChanged );
273 onScreenChanged( window->screen() );
279void QgsQuickMapCanvasMap::onScreenChanged( QScreen *screen )
283 if ( screen->devicePixelRatio() > 0 )
285 mMapSettings->setDevicePixelRatio( screen->devicePixelRatio() );
287 mMapSettings->setOutputDpi( screen->physicalDotsPerInch() );
291void QgsQuickMapCanvasMap::onExtentChanged()
299void QgsQuickMapCanvasMap::onTemporalStateChanged()
301 mCacheInvalidations |= CacheInvalidationType::Temporal;
307void QgsQuickMapCanvasMap::onzRangeChanged()
309 mCacheInvalidations |= CacheInvalidationType::Elevation;
315void QgsQuickMapCanvasMap::updateTransform()
317 QgsRectangle imageExtent = mImageMapSettings.visibleExtent();
318 QgsRectangle newExtent = mMapSettings->mapSettings().visibleExtent();
319 setScale( imageExtent.
width() / newExtent.
width() );
321 QgsPointXY pixelPt = mMapSettings->coordinateToScreen( QgsPoint( imageExtent.
xMinimum(), imageExtent.
yMaximum() ) );
328 return mMapUpdateTimer.interval();
343 return mIncrementalRendering;
389 if ( mImage.isNull() )
394 QSGSimpleTextureNode *node =
static_cast<QSGSimpleTextureNode *
>( oldNode );
397 node =
new QSGSimpleTextureNode();
398 QSGTexture *texture = window()->createTextureFromImage( mImage );
399 node->setTexture( texture );
400 node->setOwnsTexture(
true );
403 QRectF rect( boundingRect() );
404 QSizeF size = mImage.size();
405 if ( !size.isEmpty() )
406 size /= mMapSettings->devicePixelRatio();
409 if ( !rect.isEmpty() && !size.isEmpty() && !
qgsDoubleNear( rect.width() / rect.height(), ( size.width() ) /
static_cast<double>( size.height() ), 3 ) )
413 rect.setHeight( rect.width() / size.width() * size.height() );
417 rect.setWidth( rect.height() / size.height() * size.width() );
421 node->setRect( rect );
428 QQuickItem::geometryChange( newGeometry, oldGeometry );
429 if ( newGeometry.size() != oldGeometry.size() )
431 mMapSettings->setOutputSize( newGeometry.size().toSize() );
436void QgsQuickMapCanvasMap::onLayersChanged()
438 if ( mMapSettings->extent().isEmpty() )
441 for (
const QMetaObject::Connection &conn : std::as_const( mLayerConnections ) )
445 mLayerConnections.clear();
447 const QList<QgsMapLayer *> layers = mMapSettings->layers();
448 for ( QgsMapLayer *layer : layers )
469 mJob->cancelWithoutBlocking();
474void QgsQuickMapCanvasMap::zoomToFullExtent()
477 const QList<QgsMapLayer *> layers = mMapSettings->layers();
480 if ( mMapSettings->destinationCrs() != layer->crs() )
482 QgsCoordinateTransform transform( layer->crs(), mMapSettings->destinationCrs(), mMapSettings->transformContext() );
487 catch (
const QgsCsException &exp )
497 mMapSettings->setExtent( extent );
504 if ( mMapSettings->outputSize().isNull() )
508 mRefreshTimer.start( 1 );
517void QgsQuickMapCanvasMap::clearTemporalCache()
521 bool invalidateLabels =
false;
522 const QList<QgsMapLayer *> layerList = mMapSettings->mapSettings().layers();
525 bool alreadyInvalidatedThisLayer =
false;
526 if (
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
532 mCache->invalidateCacheForLayer( layer );
533 alreadyInvalidatedThisLayer =
true;
539 if ( layer->temporalProperties() && layer->temporalProperties()->isActive() )
541 if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
543 if ( vl->labelsEnabled() || vl->diagramsEnabled() )
544 invalidateLabels =
true;
550 if ( !alreadyInvalidatedThisLayer )
551 mCache->invalidateCacheForLayer( layer );
553 else if ( QgsGroupLayer *gl = qobject_cast<QgsGroupLayer *>( layer ) )
555 const QList<QgsMapLayer *> childLayerList = gl->childLayers();
556 for ( QgsMapLayer *childLayer : childLayerList )
558 if ( childLayer->temporalProperties() && childLayer->temporalProperties()->isActive() )
563 mCache->invalidateCacheForLayer( layer );
570 if ( invalidateLabels )
572 mCache->clearCacheImage( u
"_labels_"_s );
573 mCache->clearCacheImage( u
"_preview_labels_"_s );
578void QgsQuickMapCanvasMap::clearElevationCache()
582 bool invalidateLabels =
false;
583 const QList<QgsMapLayer *> layerList = mMapSettings->mapSettings().layers();
584 for ( QgsMapLayer *layer : layerList )
586 if ( layer->elevationProperties() && layer->elevationProperties()->hasElevation() )
588 if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
590 if ( vl->labelsEnabled() || vl->diagramsEnabled() )
591 invalidateLabels =
true;
597 mCache->invalidateCacheForLayer( layer );
599 else if ( QgsGroupLayer *gl = qobject_cast<QgsGroupLayer *>( layer ) )
601 const QList<QgsMapLayer *> childLayerList = gl->childLayers();
602 for ( QgsMapLayer *childLayer : childLayerList )
604 if ( childLayer->elevationProperties() && childLayer->elevationProperties()->hasElevation() )
609 mCache->invalidateCacheForLayer( layer );
616 if ( invalidateLabels )
618 mCache->clearCacheImage( u
"_labels_"_s );
619 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.
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.
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).