32#include "moc_qgsmaphittest.cpp"
37 mSettings.setLayerFilterExpressions( layerFilterExpression );
38 mSettings.setFilterPolygon( polygon );
44 mSettings.setLayerFilterExpressions( layerFilterExpression );
49 : mSettings( settings )
58 tmpImage.setDotsPerMeterX(
static_cast< int >( std::round( mapSettings.
outputDpi() * 25.4 ) ) );
59 tmpImage.setDotsPerMeterY(
static_cast< int >( std::round( mapSettings.
outputDpi() * 25.4 ) ) );
60 QPainter painter( &tmpImage );
65 const QList< QgsMapLayer * > layers = mSettings.layers();
71 if ( !layer->isInScaleRange( mapSettings.
scale() ) )
76 extent = mSettings.combinedVisibleExtentForLayer( layer );
82 if (
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
84 if ( !vl->renderer() )
88 SymbolSet &usedSymbols = mHitTest[vl->id()];
89 SymbolSet &usedSymbolsRuleKey = mHitTestRuleKey[vl->id()];
95 auto source = std::make_unique< QgsVectorLayerFeatureSource >( vl );
96 runHitTestFeatureSource( source.get(), vl->id(), vl->fields(), vl->renderer(), usedSymbols, usedSymbolsRuleKey, context,
nullptr, extent );
98 else if (
QgsRasterLayer *rl = qobject_cast<QgsRasterLayer *>( layer ) )
100 if ( !rl->renderer() || !rl->dataProvider() )
105 runHitTestRasterSource( rl->dataProvider(), rl->id(), rl->renderer()->inputBand(), minMaxOrigin, minMaxOrigin.
limits(), context,
nullptr, extent );
107 else if (
QgsMeshLayer *ml = qobject_cast<QgsMeshLayer *>( layer ) )
112 runHitTestMeshSource( ml, ml->id(), datasetIndex, context,
nullptr, extent );
121 return mHitTestRuleKey;
125QMap<QString, QList<QString> > QgsMapHitTest::resultsPy()
const
127 QMap<QString, QList<QString> > res;
128 for (
auto it = mHitTestRuleKey.begin(); it != mHitTestRuleKey.end(); ++it )
130 res.insert( it.key(), qgis::setToList( it.value() ) );
138 if ( !symbol || !layer )
141 auto it = mHitTest.constFind( layer->
id() );
142 if ( it == mHitTest.constEnd() )
153 auto it = mHitTestRuleKey.constFind( layer->
id() );
154 if ( it == mHitTestRuleKey.constEnd() )
157 return it->contains( ruleKey );
160void QgsMapHitTest::runHitTestFeatureSource(
162 const QString &layerId,
165 SymbolSet &usedSymbols,
166 SymbolSet &usedSymbolsRuleKey,
172 std::unique_ptr< QgsFeatureRenderer > r( renderer->
clone() );
174 r->startRender( context, fields );
177 if ( r->canSkipRender() )
179 r->stopRender( context );
184 QSet< QString > remainingKeysToFind = r->legendKeys();
185 if ( remainingKeysToFind.empty() )
187 r->stopRender( context );
191 QgsFeatureRequest request;
195 const QString rendererFilterExpression = r->filter( fields );
196 if ( !rendererFilterExpression.isEmpty() )
203 QSet<QString> requiredAttributes = r->usedAttributes( context );
205 QgsGeometry transformedPolygon = visibleExtent;
208 transformedPolygon = QgsGeometry();
213 r->stopRender( context );
217 const QMap<QString, QString> layerFilterExpressions = mSettings.layerFilterExpressions();
218 if (
auto it = layerFilterExpressions.constFind( layerId ); it != layerFilterExpressions.constEnd() )
220 const QString expression = *it;
221 QgsExpression expr( expression );
224 requiredAttributes.unite( expr.referencedColumns() );
230 std::unique_ptr< QgsGeometryEngine > polygonEngine;
233 if ( transformedPolygon.
isNull() )
242 polygonEngine->prepareGeometry();
248 r->stopRender( context );
252 QgsFeatureIterator fi = source->
getFeatures( request );
255 usedSymbolsRuleKey.clear();
276 const QSet< QString > legendKeysForFeature = r->legendKeysForFeature( f, context );
277 for (
const QString &legendKey : legendKeysForFeature )
279 usedSymbolsRuleKey.insert( legendKey );
280 remainingKeysToFind.remove( legendKey );
283 if ( moreSymbolsPerFeature )
285 const QgsSymbolList originalSymbolsForFeature = r->originalSymbolsForFeature( f, context );
286 for ( QgsSymbol *s : originalSymbolsForFeature )
294 QgsSymbol *s = r->originalSymbolForFeature( f, context );
299 if ( remainingKeysToFind.empty() )
305 r->stopRender( context );
308void QgsMapHitTest::runHitTestRasterSource(
310 const QString &layerId,
322 QgsRectangle transformedExtent;
325 transformedExtent = context.
extent();
332 double min = std::numeric_limits<double>::quiet_NaN();
333 double max = std::numeric_limits<double>::quiet_NaN();
336 switch ( minMaxOrigin.
extent() )
354 mHitTestRenderersUpdatedCanvas.insert( layerId, std::pair<double, double>( min, max ) );
358void QgsMapHitTest::runHitTestMeshSource(
365 QgsRectangle transformedExtent;
368 transformedExtent = context.
extent();
378 double min = std::numeric_limits<double>::quiet_NaN();
379 double max = std::numeric_limits<double>::quiet_NaN();
384 switch ( rangeExtent )
388 switch ( rangeLimit )
408 mHitTestRenderersUpdatedCanvas.insert( layerId, std::pair<double, double>( min, max ) );
418 , mSettings( settings )
429QMap<QString, QList<QString> > QgsMapHitTestTask::resultsPy()
const
431 QMap<QString, QList<QString> > res;
432 for (
auto it = mResults.begin(); it != mResults.end(); ++it )
434 res.insert( it.key(), qgis::setToList( it.value() ) );
440void QgsMapHitTestTask::prepare()
442 const QgsMapSettings &mapSettings = mSettings.mapSettings();
444 const QList< QgsMapLayer * > layers = mSettings.layers();
448 for ( QgsMapLayer *layer : layers )
458 extent = mSettings.combinedVisibleExtentForLayer( layer );
461 if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
463 if ( !vl->renderer() )
466 QgsMapLayerStyleOverride styleOverride( vl );
470 PreparedLayerData layerData;
471 layerData.source = std::make_unique< QgsVectorLayerFeatureSource >( vl );
472 layerData.layerId = vl->id();
473 layerData.fields = vl->fields();
474 layerData.renderer.reset( vl->renderer()->clone() );
476 layerData.extent = extent;
479 mPreparedData.emplace_back( std::move( layerData ) );
481 else if ( QgsRasterLayer *rl = qobject_cast<QgsRasterLayer *>( layer ) )
483 if ( !rl->dataProvider() || !rl->renderer() )
486 QgsRasterMinMaxOrigin minMaxOrigin = rl->renderer()->minMaxOrigin();
488 PreparedRasterData rasterData;
489 rasterData.provider = std::unique_ptr< QgsRasterDataProvider >( rl->dataProvider()->clone() );
490 rasterData.provider->moveToThread(
nullptr );
492 rasterData.layerId = rl->id();
493 rasterData.band = rl->renderer()->inputBand();
494 rasterData.minMaxOrigin = minMaxOrigin;
495 rasterData.rangeLimit = minMaxOrigin.
limits();
497 rasterData.extent = extent;
499 mPreparedRasterData.emplace_back( std::move( rasterData ) );
501 else if ( QgsMeshLayer *ml = qobject_cast<QgsMeshLayer *>( layer ) )
503 PreparedMeshData meshData;
504 meshData.layer = std::unique_ptr< QgsMeshLayer >( ml->clone() );
505 meshData.layer->moveToThread(
nullptr );
507 meshData.layerId = ml->id();
508 meshData.datasetIndex = ml->activeScalarDatasetIndex( context );
510 meshData.extent = extent;
512 mPreparedMeshData.emplace_back( std::move( meshData ) );
527 mFeedback = std::make_unique< QgsFeedback >();
530 auto hitTest = std::make_unique< QgsMapHitTest >( mSettings );
536 tmpImage.setDotsPerMeterX(
static_cast< int >( std::round( mapSettings.
outputDpi() * 25.4 ) ) );
537 tmpImage.setDotsPerMeterY(
static_cast< int >( std::round( mapSettings.
outputDpi() * 25.4 ) ) );
538 QPainter painter( &tmpImage );
544 std::size_t layerIdx = 0;
545 const std::size_t totalCount = mPreparedData.size() + mPreparedRasterData.size() + mPreparedMeshData.size();
547 for (
auto &layerData : mPreparedData )
549 mFeedback->setProgress(
static_cast< double >( layerIdx ) /
static_cast< double >( totalCount ) * 100.0 );
550 if ( mFeedback->isCanceled() )
553 QgsMapHitTest::SymbolSet &usedSymbols = hitTest->mHitTest[layerData.layerId];
554 QgsMapHitTest::SymbolSet &usedSymbolsRuleKey = hitTest->mHitTestRuleKey[layerData.layerId];
557 context.
setExtent( layerData.extent.boundingBox() );
562 hitTest->runHitTestFeatureSource( layerData.source.get(), layerData.layerId, layerData.fields, layerData.renderer.get(), usedSymbols, usedSymbolsRuleKey, context, mFeedback.get(), layerData.
extent );
567 for ( PreparedRasterData &rasterData : mPreparedRasterData )
569 rasterData.provider->moveToThread( QThread::currentThread() );
571 mFeedback->setProgress( (
static_cast<double>( mPreparedData.size() ) +
static_cast< double >( layerIdx ) ) /
static_cast< double >( totalCount ) * 100.0 );
572 if ( mFeedback->isCanceled() )
576 context.
setExtent( rasterData.extent.boundingBox() );
578 hitTest->runHitTestRasterSource( rasterData.provider.get(), rasterData.layerId, rasterData.band, rasterData.minMaxOrigin, rasterData.rangeLimit, context, mFeedback.get(), rasterData.
extent );
583 for ( PreparedMeshData &meshData : mPreparedMeshData )
585 mFeedback->setProgress(
586 (
static_cast<double>( mPreparedData.size() ) +
static_cast<double>( mPreparedRasterData.size() ) +
static_cast< double >( layerIdx ) ) /
static_cast< double >( totalCount ) * 100.0
588 if ( mFeedback->isCanceled() )
592 context.
setExtent( meshData.extent.boundingBox() );
594 meshData.layer->moveToThread( QThread::currentThread() );
595 meshData.layer->updateTriangularMesh();
597 hitTest->runHitTestMeshSource( meshData.layer.get(), meshData.layerId, meshData.datasetIndex, context, mFeedback.get(), meshData.
extent );
601 mResults = hitTest->mHitTestRuleKey;
603 mResultsRenderersUpdatedCanvas = hitTest->mHitTestRenderersUpdatedCanvas;
610 mPreparedRasterData.clear();
612 mPreparedMeshData.clear();
MeshRangeLimit
Describes the limits used to compute mesh ranges (min/max values).
@ MinimumMaximum
Real min-max values.
RasterRangeLimit
Describes the limits used to compute raster ranges (min/max values).
@ SkipVisibilityCheck
If set, the standard visibility check should be skipped.
@ ExactIntersect
Use exact geometry intersection (slower) instead of bounding boxes.
MeshRangeExtent
Describes the extent used to compute mesh ranges (min/max values).
@ UpdatedCanvas
Constantly updated extent of the canvas is used to compute statistics.
@ WholeMesh
Whole mesh is used to compute statistics.
@ FixedCanvas
Current extent of the canvas (at the time of computation) is used to compute statistics.
@ UpdatedCanvas
Constantly updated extent of the canvas is used to compute statistics.
@ WholeRaster
Whole raster is used to compute statistics.
@ FixedCanvas
Current extent of the canvas (at the time of computation) is used to compute statistics.
Base class that can be used for any class that is capable of returning features.
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())=0
Gets an iterator for features matching the specified request.
RAII class to pop scope from an expression context on destruction.
Single scope for storing variables and functions for use within a QgsExpressionContext.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
Abstract base class for all 2D vector feature renderers.
@ MoreSymbolsPerFeature
May use more than one symbol to render a feature: symbolsForFeature() will return them.
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & combineFilterExpression(const QString &expression)
Modifies the existing filter expression to add an additional expression filter.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
void setFeedback(QgsFeedback *feedback)
Attach a feedback object that can be queried regularly by the iterator to check if it should be cance...
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const
Tells whether the operation has been canceled already.
void progressChanged(double progress)
Emitted when the feedback object reports a progress change.
Container of fields for a vector layer.
A geometry is the spatial representation of a feature.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry, double precision=0.0, Qgis::GeosCreationFlags flags=Qgis::GeosCreationFlag::SkipEmptyInteriorRings)
Creates and returns a new geometry engine representing the specified geometry using precision on a gr...
Contains settings relating to filtering the contents of QgsLayerTreeModel and views.
QMap< QString, QSet< QString > > results() const
Returns the hit test results, which are a map of layer ID to visible symbol legend keys.
QgsMapHitTestTask(const QgsLayerTreeFilterSettings &settings)
Constructor for QgsMapHitTestTask, using the specified filter settings.
bool run() override
Performs the task's operation.
PRIVATE void cancel() override
Notifies the task that it should terminate.
void run()
Runs the map hit test.
bool symbolVisible(QgsSymbol *symbol, QgsVectorLayer *layer) const
Tests whether a symbol is visible for a specified layer.
bool legendKeyVisible(const QString &ruleKey, QgsVectorLayer *layer) const
Tests whether a given legend key is visible for a specified layer.
QgsMapHitTest(const QgsMapSettings &settings, const QgsGeometry &polygon=QgsGeometry(), const QgsMapHitTest::LayerFilterExpression &layerFilterExpression=QgsMapHitTest::LayerFilterExpression())
Constructor for QgsMapHitTest.
QMap< QString, QSet< QString > > results() const
Returns the hit test results, which are a map of layer ID to visible symbol legend keys.
QMap< QString, QString > LayerFilterExpression
Maps an expression string to a layer id.
Restore overridden layer style on destruction.
void setOverrideStyle(const QString &style)
Temporarily apply a different style to the layer.
Base class for all map layer types.
bool isInScaleRange(double scale) const
Tests whether the layer should be visible at the specified scale.
Contains configuration for rendering maps.
double scale() const
Returns the calculated map scale.
QgsCoordinateTransform layerTransform(const QgsMapLayer *layer) const
Returns the coordinate transform from layer's CRS to destination CRS.
QSize outputSize() const
Returns the size of the resulting map image, in pixels.
QImage::Format outputImageFormat() const
format of internal QImage, default QImage::Format_ARGB32_Premultiplied
double outputDpi() const
Returns the DPI (dots per inch) used for conversion between real world units (e.g.
QMap< QString, QString > layerStyleOverrides() const
Returns the map of map layer style overrides (key: layer ID, value: style name) where a different sty...
An index that identifies the dataset group (e.g.
bool isValid() const
Returns whether index is valid, ie at least groups is set.
int group() const
Returns a group index.
int dataset() const
Returns a dataset index within group().
Represents a mesh layer supporting display of data on structured or unstructured meshes.
QgsMeshRendererSettings rendererSettings() const
Returns renderer settings.
bool minimumMaximumActiveScalarDataset(const QgsRectangle &extent, const QgsMeshDatasetIndex &datasetIndex, double &min, double &max)
Extracts minimum and maximum value for active scalar dataset on mesh faces.
Represents a mesh renderer settings for scalar datasets.
Qgis::MeshRangeExtent extent() const
Returns the mesh extent for minimum maximum calculation.
Qgis::MeshRangeLimit limits() const
Returns the range limits type for minimum maximum calculation.
QgsMeshRendererScalarSettings scalarSettings(int groupIndex) const
Returns renderer settings.
Base class for raster data providers.
QgsRectangle extent() const override=0
Returns the extent of the layer.
static void computeMinMax(QgsRasterDataProvider *provider, int band, const QgsRasterMinMaxOrigin &mmo, Qgis::RasterRangeLimit limits, const QgsRectangle &extent, int sampleSize, double &min, double &max)
Compute the min max values for provider along band according to MinMaxOrigin parameters mmo and exten...
Represents a raster layer.
static const double SAMPLE_SIZE
Default sample size (number of pixels) for estimated statistics/histogram calculation.
Describes the origin of minimum and maximum values in a raster.
Qgis::RasterRangeExtent extent() const
Returns the raster extent.
Qgis::RasterRangeLimit limits() const
Returns the raster limits.
bool intersects(const QgsRectangle &rect) const
Returns true when rectangle intersects with other rectangle.
Contains information about the context of a rendering operation.
void setCoordinateTransform(const QgsCoordinateTransform &t)
Sets the current coordinate transform for the context.
QgsExpressionContext & expressionContext()
Gets the expression context.
const QgsRectangle & extent() const
When rendering a map layer, calling this method returns the "clipping" extent for the layer (in the l...
void setExtent(const QgsRectangle &extent)
When rendering a map layer, calling this method sets the "clipping" extent for the layer (in the laye...
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
static QString symbolProperties(QgsSymbol *symbol)
Returns a string representing the symbol.
Abstract base class for all rendered symbols.
void progressChanged(double progress)
Will be emitted by task when its progress changes.
virtual void cancel()
Notifies the task that it should terminate.
QgsTask(const QString &description=QString(), QgsTask::Flags flags=AllFlags)
Constructor for QgsTask.
@ CanCancel
Task can be canceled.
@ CancelWithoutPrompt
Task can be canceled without any users prompts, e.g. when closing a project or QGIS.
@ Silent
Don't show task updates (such as completion/failure messages) as operating-system level notifications...
Represents a vector layer which manages a vector based dataset.
QList< QgsSymbol * > QgsSymbolList