QGIS API Documentation 3.43.0-Master (e01d6d7c4c0)
qgsalgorithmvirtualrastercalculator.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmvirtualrastercalculator.cpp
3 ---------------------
4 begin : August 2023
5 copyright : (C) 2023 by Alexander Bruy
6 email : alexander dot bruy at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
20
22
23Qgis::ProcessingAlgorithmFlags QgsVirtualRasterCalculatorAlgorithm::flags() const
24{
26}
27
28QString QgsVirtualRasterCalculatorAlgorithm::name() const
29{
30 return QStringLiteral( "virtualrastercalc" );
31}
32
33QString QgsVirtualRasterCalculatorAlgorithm::displayName() const
34{
35 return QObject::tr( "Raster calculator (virtual)" );
36}
37
38QStringList QgsVirtualRasterCalculatorAlgorithm::tags() const
39{
40 return QObject::tr( "raster,calculator,virtual" ).split( ',' );
41}
42
43QString QgsVirtualRasterCalculatorAlgorithm::group() const
44{
45 return QObject::tr( "Raster analysis" );
46}
47
48QString QgsVirtualRasterCalculatorAlgorithm::groupId() const
49{
50 return QStringLiteral( "rasteranalysis" );
51}
52
53QString QgsVirtualRasterCalculatorAlgorithm::shortHelpString() const
54{
55 return QObject::tr( "This algorithm performs algebraic operations using raster layers and generates in-memory result." );
56}
57
58QString QgsVirtualRasterCalculatorAlgorithm::shortDescription() const
59{
60 return QObject::tr( "Performs algebraic operations using raster layers and generates in-memory result." );
61}
62
63QgsVirtualRasterCalculatorAlgorithm *QgsVirtualRasterCalculatorAlgorithm::createInstance() const
64{
65 return new QgsVirtualRasterCalculatorAlgorithm();
66}
67
68void QgsVirtualRasterCalculatorAlgorithm::initAlgorithm( const QVariantMap & )
69{
70 addParameter( new QgsProcessingParameterMultipleLayers( QStringLiteral( "LAYERS" ), QObject::tr( "Input layers" ), Qgis::ProcessingSourceType::Raster ) );
71 addParameter( new QgsProcessingParameterExpression( QStringLiteral( "EXPRESSION" ), QObject::tr( "Expression" ), QVariant(), QStringLiteral( "LAYERS" ), false, Qgis::ExpressionType::RasterCalculator ) );
72 auto extentParam = std::make_unique<QgsProcessingParameterExtent>( QStringLiteral( "EXTENT" ), QObject::tr( "Output extent" ), QVariant(), true );
73 extentParam->setHelp( QObject::tr( "Extent of the output layer. If not specified, the extent will be the overall extent of all input layers" ) );
74 addParameter( extentParam.release() );
75 auto cellSizeParam = std::make_unique<QgsProcessingParameterNumber>( QStringLiteral( "CELL_SIZE" ), QObject::tr( "Output cell size (leave empty to set automatically)" ), Qgis::ProcessingNumberParameterType::Double, QVariant(), true, 0.0 );
76 cellSizeParam->setHelp( QObject::tr( "Cell size of the output layer. If not specified, the smallest cell size from the input layers will be used" ) );
77 addParameter( cellSizeParam.release() );
78 auto crsParam = std::make_unique<QgsProcessingParameterCrs>( QStringLiteral( "CRS" ), QObject::tr( "Output CRS" ), QVariant(), true );
79 crsParam->setHelp( QObject::tr( "CRS of the output layer. If not specified, the CRS of the first input layer will be used" ) );
80 addParameter( crsParam.release() );
81 addParameter( new QgsProcessingParameterString( QStringLiteral( "LAYER_NAME" ), QObject::tr( "Output layer name" ), QVariant(), false, true ) );
82 addOutput( new QgsProcessingOutputRasterLayer( QStringLiteral( "OUTPUT" ), QObject::tr( "Calculated" ) ) );
83}
84
85QVariantMap QgsVirtualRasterCalculatorAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
86{
87 Q_UNUSED( feedback );
88
89 const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, QStringLiteral( "LAYERS" ), context );
90 if ( layers.isEmpty() )
91 {
92 throw QgsProcessingException( QObject::tr( "No input layers selected" ) );
93 }
94
96 if ( parameters.value( QStringLiteral( "CRS" ) ).isValid() )
97 {
98 crs = parameterAsCrs( parameters, QStringLiteral( "CRS" ), context );
99 }
100 else
101 {
102 crs = layers.at( 0 )->crs();
103 }
104
105 QgsRectangle bbox;
106 if ( parameters.value( QStringLiteral( "EXTENT" ) ).isValid() )
107 {
108 bbox = parameterAsExtent( parameters, QStringLiteral( "EXTENT" ), context, crs );
109 }
110 else
111 {
112 bbox = QgsProcessingUtils::combineLayerExtents( layers, crs, context );
113 }
114
115 double minCellSize = 1e9;
117
118 for ( const QgsMapLayer *layer : layers )
119 {
120 const QgsRasterLayer *rLayer = qobject_cast<const QgsRasterLayer *>( layer );
121 if ( !rLayer )
122 {
123 continue;
124 }
125
127 rasterLayer.name = rLayer->name();
128 rasterLayer.provider = rLayer->dataProvider()->name();
129 rasterLayer.uri = rLayer->source();
130 rasterParameters.rInputLayers.append( rasterLayer );
131
132 QgsRectangle ext = rLayer->extent();
133 if ( rLayer->crs() != crs )
134 {
135 QgsCoordinateTransform ct( rLayer->crs(), crs, context.transformContext() );
136 ext = ct.transformBoundingBox( ext );
137 }
138
139 double cellSize = ( ext.xMaximum() - ext.xMinimum() ) / rLayer->width();
140 if ( cellSize < minCellSize )
141 {
142 minCellSize = cellSize;
143 }
144 }
145
146 double cellSize = parameterAsDouble( parameters, QStringLiteral( "CELL_SIZE" ), context );
147 if ( cellSize == 0 )
148 {
149 cellSize = minCellSize;
150 }
151
152 const QString expression = parameterAsExpression( parameters, QStringLiteral( "EXPRESSION" ), context );
153 QString layerName = parameterAsString( parameters, QStringLiteral( "LAYER_NAME" ), context );
154 if ( layerName.isEmpty() )
155 {
156 layerName = expression;
157 }
158
159 double width = std::round( ( bbox.xMaximum() - bbox.xMinimum() ) / cellSize );
160 double height = std::round( ( bbox.yMaximum() - bbox.yMinimum() ) / cellSize );
161
162 rasterParameters.crs = crs;
163 rasterParameters.extent = bbox;
164 rasterParameters.width = width;
165 rasterParameters.height = height;
166 rasterParameters.formula = expression;
167
168 std::unique_ptr<QgsRasterLayer> layer;
169 layer = std::make_unique<QgsRasterLayer>( QgsRasterDataProvider::encodeVirtualRasterProviderUri( rasterParameters ), layerName, QStringLiteral( "virtualraster" ) );
170 if ( !layer->isValid() )
171 {
172 feedback->reportError( QObject::tr( "Failed to create virtual raster layer" ) );
173 }
174 else
175 {
176 }
177 const QString layerId = layer->id();
178 const QgsProcessingContext::LayerDetails details( layer->name(), context.project(), QStringLiteral( "OUTPUT" ), QgsProcessingUtils::LayerHint::Raster );
179 context.addLayerToLoadOnCompletion( layerId, details );
180 context.temporaryLayerStore()->addMapLayer( layer.release() );
181
182 QVariantMap outputs;
183 outputs.insert( QStringLiteral( "OUTPUT" ), layerId );
184 return outputs;
185}
186
187Qgis::ProcessingAlgorithmFlags QgsVirtualRasterCalculatorModelerAlgorithm::flags() const
188{
190}
191
192QString QgsVirtualRasterCalculatorModelerAlgorithm::name() const
193{
194 return QStringLiteral( "modelervirtualrastercalc" );
195}
196
197QString QgsVirtualRasterCalculatorModelerAlgorithm::displayName() const
198{
199 return QObject::tr( "Raster calculator (virtual)" );
200}
201
202QStringList QgsVirtualRasterCalculatorModelerAlgorithm::tags() const
203{
204 return QObject::tr( "raster,calculator,virtual" ).split( ',' );
205}
206
207QString QgsVirtualRasterCalculatorModelerAlgorithm::group() const
208{
209 return QObject::tr( "Raster analysis" );
210}
211
212QString QgsVirtualRasterCalculatorModelerAlgorithm::groupId() const
213{
214 return QStringLiteral( "rasteranalysis" );
215}
216
217QgsVirtualRasterCalculatorModelerAlgorithm *QgsVirtualRasterCalculatorModelerAlgorithm::createInstance() const
218{
219 return new QgsVirtualRasterCalculatorModelerAlgorithm();
220}
221
222QVariantMap QgsVirtualRasterCalculatorModelerAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
223{
224 Q_UNUSED( feedback );
225
226 const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, QStringLiteral( "INPUT" ), context );
227 if ( layers.isEmpty() )
228 {
229 throw QgsProcessingException( QObject::tr( "No input layers selected" ) );
230 }
231
233 if ( parameters.value( QStringLiteral( "CRS" ) ).isValid() )
234 {
235 crs = parameterAsCrs( parameters, QStringLiteral( "CRS" ), context );
236 }
237 else
238 {
239 crs = layers.at( 0 )->crs();
240 }
241
242 QgsRectangle bbox;
243 if ( parameters.value( QStringLiteral( "EXTENT" ) ).isValid() )
244 {
245 bbox = parameterAsExtent( parameters, QStringLiteral( "EXTENT" ), context, crs );
246 }
247 else
248 {
249 bbox = QgsProcessingUtils::combineLayerExtents( layers, crs, context );
250 }
251
252 double minCellSize = 1e9;
254
255 int n = 0;
256 for ( const QgsMapLayer *layer : layers )
257 {
258 const QgsRasterLayer *rLayer = qobject_cast<const QgsRasterLayer *>( layer );
259 if ( !rLayer )
260 {
261 continue;
262 }
263
264 n++;
266 rasterLayer.name = indexToName( n );
267 rasterLayer.provider = rLayer->dataProvider()->name();
268 rasterLayer.uri = rLayer->source();
269 rasterParameters.rInputLayers.append( rasterLayer );
270
271 QgsRectangle ext = rLayer->extent();
272 if ( rLayer->crs() != crs )
273 {
274 QgsCoordinateTransform ct( rLayer->crs(), crs, context.transformContext() );
275 ext = ct.transformBoundingBox( ext );
276 }
277
278 double cellSize = ( ext.xMaximum() - ext.xMinimum() ) / rLayer->width();
279 if ( cellSize < minCellSize )
280 {
281 minCellSize = cellSize;
282 }
283 }
284
285 double cellSize = parameterAsDouble( parameters, QStringLiteral( "CELL_SIZE" ), context );
286 if ( cellSize == 0 )
287 {
288 cellSize = minCellSize;
289 }
290
291 const QString expression = parameterAsExpression( parameters, QStringLiteral( "EXPRESSION" ), context );
292 QString layerName = parameterAsString( parameters, QStringLiteral( "LAYER_NAME" ), context );
293 if ( layerName.isEmpty() )
294 {
295 layerName = expression;
296 }
297
298 double width = std::round( ( bbox.xMaximum() - bbox.xMinimum() ) / cellSize );
299 double height = std::round( ( bbox.yMaximum() - bbox.yMinimum() ) / cellSize );
300
301 rasterParameters.crs = crs;
302 rasterParameters.extent = bbox;
303 rasterParameters.width = width;
304 rasterParameters.height = height;
305 rasterParameters.formula = expression;
306
307 std::unique_ptr<QgsRasterLayer> layer;
308 layer = std::make_unique<QgsRasterLayer>( QgsRasterDataProvider::encodeVirtualRasterProviderUri( rasterParameters ), layerName, QStringLiteral( "virtualraster" ) );
309 if ( !layer->isValid() )
310 {
311 feedback->reportError( QObject::tr( "Failed to create virtual raster layer" ) );
312 }
313 else
314 {
315 }
316 const QString layerId = layer->id();
317 const QgsProcessingContext::LayerDetails details( layer->name(), context.project(), QStringLiteral( "OUTPUT" ), QgsProcessingUtils::LayerHint::Raster );
318 context.addLayerToLoadOnCompletion( layerId, details );
319 context.temporaryLayerStore()->addMapLayer( layer.release() );
320
321 QVariantMap outputs;
322 outputs.insert( QStringLiteral( "OUTPUT" ), layerId );
323 return outputs;
324}
325
326QString QgsVirtualRasterCalculatorModelerAlgorithm::indexToName( int index ) const
327{
328 QString name;
329 int div = index;
330 int mod = 0;
331
332 while ( div > 0 )
333 {
334 mod = ( div - 1 ) % 26;
335 name = static_cast<char>( 65 + mod ) + name;
336 div = ( int ) ( ( div - mod ) / 26 );
337 }
338 return name;
339}
340
@ RasterCalculator
Raster calculator expression.
QFlags< ProcessingAlgorithmFlag > ProcessingAlgorithmFlags
Flags indicating how and when an algorithm operates and should be exposed to users.
Definition qgis.h:3476
@ HideFromToolbox
Algorithm should be hidden from the toolbox.
@ HideFromModeler
Algorithm should be hidden from the modeler.
@ NoThreading
Algorithm is not thread safe and cannot be run in a background thread, e.g. for algorithms which mani...
Represents a coordinate reference system (CRS).
Handles coordinate transforms between two coordinate systems.
virtual QString name() const =0
Returns a provider name.
QgsMapLayer * addMapLayer(QgsMapLayer *layer, bool takeOwnership=true)
Add a layer to the store.
Base class for all map layer types.
Definition qgsmaplayer.h:77
QString name
Definition qgsmaplayer.h:81
virtual QgsRectangle extent() const
Returns the extent of the layer.
QString source() const
Returns the source for the layer.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:84
virtual Qgis::ProcessingAlgorithmFlags flags() const
Returns the flags indicating how and when the algorithm operates and should be exposed to users.
Details for layers to load into projects.
Contains information about the context in which a processing algorithm is executed.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
void addLayerToLoadOnCompletion(const QString &layer, const QgsProcessingContext::LayerDetails &details)
Adds a layer to load (by ID or datasource) into the canvas upon completion of the algorithm or model.
QgsProject * project() const
Returns the project in which the algorithm is being executed.
QgsMapLayerStore * temporaryLayerStore()
Returns a reference to the layer store used for storing temporary layers during algorithm execution.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
A raster layer output for processing algorithms.
An expression parameter for processing algorithms.
A parameter for processing algorithms which accepts multiple map layers.
A string parameter for processing algorithms.
@ Raster
Raster layer type.
static QgsRectangle combineLayerExtents(const QList< QgsMapLayer * > &layers, const QgsCoordinateReferenceSystem &crs, QgsProcessingContext &context)
Combines the extent of several map layers.
static QString encodeVirtualRasterProviderUri(const VirtualRasterParameters &parts)
Encodes the URI starting from the struct .
Represents a raster layer.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
int width() const
Returns the width of the (unclipped) raster.
A rectangle specified with double values.
double xMinimum
double yMinimum
double xMaximum
double yMaximum
const QgsCoordinateReferenceSystem & crs
Struct that stores information of the raster used in QgsVirtualRasterProvider for the calculations,...
Struct that stores the information about the parameters that should be given to the QgsVirtualRasterP...
QList< QgsRasterDataProvider::VirtualRasterInputLayers > rInputLayers