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;
130 QgsProject *project = mMapSettings->project();
139 QList<QgsMapLayer *> allLayers =
mapSettings.layers();
144 mapSettings.setExpressionContext( expressionContext );
153 mJob =
new QgsMapRendererParallelJob(
mapSettings );
155 if ( mIncrementalRendering )
156 mMapUpdateTimer.start();
160 mJob->setCache( mCache.get() );
164 if ( !mSilentRefresh )
170void QgsQuickMapCanvasMap::renderJobUpdated()
175 mImage = mJob->renderedImage();
176 mImageMapSettings = mJob->mapSettings();
187void QgsQuickMapCanvasMap::renderJobFinished()
193 for (
const QgsMapRendererJob::Error &error : errors )
200 delete mLabelingResults;
201 mLabelingResults = mJob->takeLabelingResults();
203 mImage = mJob->renderedImage();
204 mImageMapSettings = mJob->mapSettings();
211 mMapUpdateTimer.stop();
220 if ( !mSilentRefresh )
226 mSilentRefresh =
false;
229 if ( mDeferredRefreshPending )
231 mDeferredRefreshPending =
false;
232 mSilentRefresh =
true;
237void QgsQuickMapCanvasMap::layerRepaintRequested(
bool deferred )
239 if ( mMapSettings->outputSize().isNull() )
248 mSilentRefresh =
true;
253 mDeferredRefreshPending =
true;
263void QgsQuickMapCanvasMap::onWindowChanged( QQuickWindow *window )
265 if ( mWindow == window )
269 disconnect( mWindow, &QQuickWindow::screenChanged,
this, &QgsQuickMapCanvasMap::onScreenChanged );
273 connect( window, &QQuickWindow::screenChanged,
this, &QgsQuickMapCanvasMap::onScreenChanged );
274 onScreenChanged( window->screen() );
280void QgsQuickMapCanvasMap::onScreenChanged( QScreen *screen )
284 if ( screen->devicePixelRatio() > 0 )
286 mMapSettings->setDevicePixelRatio( screen->devicePixelRatio() );
288 mMapSettings->setOutputDpi( screen->physicalDotsPerInch() );
292void QgsQuickMapCanvasMap::onExtentChanged()
300void QgsQuickMapCanvasMap::onTemporalStateChanged()
302 mCacheInvalidations |= CacheInvalidationType::Temporal;
308void QgsQuickMapCanvasMap::onzRangeChanged()
310 mCacheInvalidations |= CacheInvalidationType::Elevation;
316void QgsQuickMapCanvasMap::updateTransform()
318 QgsRectangle imageExtent = mImageMapSettings.visibleExtent();
319 QgsRectangle newExtent = mMapSettings->mapSettings().visibleExtent();
320 setScale( imageExtent.
width() / newExtent.
width() );
322 QgsPointXY pixelPt = mMapSettings->coordinateToScreen( QgsPoint( imageExtent.
xMinimum(), imageExtent.
yMaximum() ) );
329 return mMapUpdateTimer.interval();
344 return mIncrementalRendering;
390 if ( mImage.isNull() )
395 QSGSimpleTextureNode *node =
static_cast<QSGSimpleTextureNode *
>( oldNode );
398 node =
new QSGSimpleTextureNode();
399 QSGTexture *texture = window()->createTextureFromImage( mImage );
400 node->setTexture( texture );
401 node->setOwnsTexture(
true );
404 QRectF rect( boundingRect() );
405 QSizeF size = mImage.size();
406 if ( !size.isEmpty() )
407 size /= mMapSettings->devicePixelRatio();
410 if ( !rect.isEmpty() && !size.isEmpty() && !
qgsDoubleNear( rect.width() / rect.height(), ( size.width() ) /
static_cast<double>( size.height() ), 3 ) )
414 rect.setHeight( rect.width() / size.width() * size.height() );
418 rect.setWidth( rect.height() / size.height() * size.width() );
422 node->setRect( rect );
429 QQuickItem::geometryChange( newGeometry, oldGeometry );
430 if ( newGeometry.size() != oldGeometry.size() )
432 mMapSettings->setOutputSize( newGeometry.size().toSize() );
437void QgsQuickMapCanvasMap::onLayersChanged()
439 if ( mMapSettings->extent().isEmpty() )
442 for (
const QMetaObject::Connection &conn : std::as_const( mLayerConnections ) )
446 mLayerConnections.clear();
448 const QList<QgsMapLayer *> layers = mMapSettings->layers();
449 for ( QgsMapLayer *layer : layers )
470 mJob->cancelWithoutBlocking();
475void QgsQuickMapCanvasMap::zoomToFullExtent()
478 const QList<QgsMapLayer *> layers = mMapSettings->layers();
481 if ( mMapSettings->destinationCrs() != layer->crs() )
483 QgsCoordinateTransform transform( layer->crs(), mMapSettings->destinationCrs(), mMapSettings->transformContext() );
488 catch (
const QgsCsException &exp )
498 mMapSettings->setExtent( extent );
505 if ( mMapSettings->outputSize().isNull() )
509 mRefreshTimer.start( 1 );
518void QgsQuickMapCanvasMap::clearTemporalCache()
522 bool invalidateLabels =
false;
523 const QList<QgsMapLayer *> layerList = mMapSettings->mapSettings().layers();
526 bool alreadyInvalidatedThisLayer =
false;
527 if (
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
533 mCache->invalidateCacheForLayer( layer );
534 alreadyInvalidatedThisLayer =
true;
540 if ( layer->temporalProperties() && layer->temporalProperties()->isActive() )
542 if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
544 if ( vl->labelsEnabled() || vl->diagramsEnabled() )
545 invalidateLabels =
true;
551 if ( !alreadyInvalidatedThisLayer )
552 mCache->invalidateCacheForLayer( layer );
554 else if ( QgsGroupLayer *gl = qobject_cast<QgsGroupLayer *>( layer ) )
556 const QList<QgsMapLayer *> childLayerList = gl->childLayers();
557 for ( QgsMapLayer *childLayer : childLayerList )
559 if ( childLayer->temporalProperties() && childLayer->temporalProperties()->isActive() )
564 mCache->invalidateCacheForLayer( layer );
571 if ( invalidateLabels )
573 mCache->clearCacheImage( u
"_labels_"_s );
574 mCache->clearCacheImage( u
"_preview_labels_"_s );
579void QgsQuickMapCanvasMap::clearElevationCache()
583 bool invalidateLabels =
false;
584 const QList<QgsMapLayer *> layerList = mMapSettings->mapSettings().layers();
585 for ( QgsMapLayer *layer : layerList )
587 if ( layer->elevationProperties() && layer->elevationProperties()->hasElevation() )
589 if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
591 if ( vl->labelsEnabled() || vl->diagramsEnabled() )
592 invalidateLabels =
true;
598 mCache->invalidateCacheForLayer( layer );
600 else if ( QgsGroupLayer *gl = qobject_cast<QgsGroupLayer *>( layer ) )
602 const QList<QgsMapLayer *> childLayerList = gl->childLayers();
603 for ( QgsMapLayer *childLayer : childLayerList )
605 if ( childLayer->elevationProperties() && childLayer->elevationProperties()->hasElevation() )
610 mCache->invalidateCacheForLayer( layer );
617 if ( invalidateLabels )
619 mCache->clearCacheImage( u
"_labels_"_s );
620 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(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
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).