QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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( "Performs algebraic operations using raster layers and generates in-memory result." );
56}
57
58QgsVirtualRasterCalculatorAlgorithm *QgsVirtualRasterCalculatorAlgorithm::createInstance() const
59{
60 return new QgsVirtualRasterCalculatorAlgorithm();
61}
62
63void QgsVirtualRasterCalculatorAlgorithm::initAlgorithm( const QVariantMap & )
64{
65 addParameter( new QgsProcessingParameterMultipleLayers( QStringLiteral( "LAYERS" ), QObject::tr( "Input layers" ), Qgis::ProcessingSourceType::Raster ) );
66 addParameter( new QgsProcessingParameterExpression( QStringLiteral( "EXPRESSION" ), QObject::tr( "Expression" ), QVariant(), QStringLiteral( "LAYERS" ), false, Qgis::ExpressionType::RasterCalculator ) );
67 std::unique_ptr<QgsProcessingParameterExtent> extentParam = std::make_unique<QgsProcessingParameterExtent>( QStringLiteral( "EXTENT" ), QObject::tr( "Output extent" ), QVariant(), true );
68 extentParam->setHelp( QObject::tr( "Extent of the output layer. If not specified, the extent will be the overall extent of all input layers" ) );
69 addParameter( extentParam.release() );
70 std::unique_ptr<QgsProcessingParameterNumber> 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 );
71 cellSizeParam->setHelp( QObject::tr( "Cell size of the output layer. If not specified, the smallest cell size from the input layers will be used" ) );
72 addParameter( cellSizeParam.release() );
73 std::unique_ptr<QgsProcessingParameterCrs> crsParam = std::make_unique<QgsProcessingParameterCrs>( QStringLiteral( "CRS" ), QObject::tr( "Output CRS" ), QVariant(), true );
74 crsParam->setHelp( QObject::tr( "CRS of the output layer. If not specified, the CRS of the first input layer will be used" ) );
75 addParameter( crsParam.release() );
76 addParameter( new QgsProcessingParameterString( QStringLiteral( "LAYER_NAME" ), QObject::tr( "Output layer name" ), QVariant(), false, true ) );
77 addOutput( new QgsProcessingOutputRasterLayer( QStringLiteral( "OUTPUT" ), QObject::tr( "Calculated" ) ) );
78}
79
80QVariantMap QgsVirtualRasterCalculatorAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
81{
82 Q_UNUSED( feedback );
83
84 const QList< QgsMapLayer * > layers = parameterAsLayerList( parameters, QStringLiteral( "LAYERS" ), context );
85 if ( layers.isEmpty() )
86 {
87 throw QgsProcessingException( QObject::tr( "No input layers selected" ) );
88 }
89
91 if ( parameters.value( QStringLiteral( "CRS" ) ).isValid() )
92 {
93 crs = parameterAsCrs( parameters, QStringLiteral( "CRS" ), context );
94 }
95 else
96 {
97 crs = layers.at( 0 )->crs();
98 }
99
100 QgsRectangle bbox;
101 if ( parameters.value( QStringLiteral( "EXTENT" ) ).isValid() )
102 {
103 bbox = parameterAsExtent( parameters, QStringLiteral( "EXTENT" ), context, crs );
104 }
105 else
106 {
107 bbox = QgsProcessingUtils::combineLayerExtents( layers, crs, context );
108 }
109
110 double minCellSize = 1e9;
112
113 for ( const QgsMapLayer *layer : layers )
114 {
115 const QgsRasterLayer *rLayer = qobject_cast<const QgsRasterLayer *>( layer );
116 if ( !rLayer )
117 {
118 continue;
119 }
120
122 rasterLayer.name = rLayer->name();
123 rasterLayer.provider = rLayer->dataProvider()->name();
124 rasterLayer.uri = rLayer->source();
125 rasterParameters.rInputLayers.append( rasterLayer );
126
127 QgsRectangle ext = rLayer->extent();
128 if ( rLayer->crs() != crs )
129 {
130 QgsCoordinateTransform ct( rLayer->crs(), crs, context.transformContext() );
131 ext = ct.transformBoundingBox( ext );
132 }
133
134 double cellSize = ( ext.xMaximum() - ext.xMinimum() ) / rLayer->width();
135 if ( cellSize < minCellSize )
136 {
137 minCellSize = cellSize;
138 }
139 }
140
141 double cellSize = parameterAsDouble( parameters, QStringLiteral( "CELL_SIZE" ), context );
142 if ( cellSize == 0 )
143 {
144 cellSize = minCellSize;
145 }
146
147 const QString expression = parameterAsExpression( parameters, QStringLiteral( "EXPRESSION" ), context );
148 QString layerName = parameterAsString( parameters, QStringLiteral( "LAYER_NAME" ), context );
149 if ( layerName.isEmpty() )
150 {
151 layerName = expression;
152 }
153
154 double width = std::round( ( bbox.xMaximum() - bbox.xMinimum() ) / cellSize );
155 double height = std::round( ( bbox.yMaximum() - bbox.yMinimum() ) / cellSize );
156
157 rasterParameters.crs = crs;
158 rasterParameters.extent = bbox;
159 rasterParameters.width = width;
160 rasterParameters.height = height;
161 rasterParameters.formula = expression;
162
163 std::unique_ptr< QgsRasterLayer > layer;
164 layer = std::make_unique< QgsRasterLayer >( QgsRasterDataProvider::encodeVirtualRasterProviderUri( rasterParameters ),
165 layerName, QStringLiteral( "virtualraster" ) );
166 if ( !layer->isValid() )
167 {
168 feedback->reportError( QObject::tr( "Failed to create virtual raster layer" ) );
169 }
170 else
171 {
172 }
173 const QString layerId = layer->id();
174 const QgsProcessingContext::LayerDetails details( layer->name(), context.project(), QStringLiteral( "OUTPUT" ), QgsProcessingUtils::LayerHint::Raster );
175 context.addLayerToLoadOnCompletion( layerId, details );
176 context.temporaryLayerStore()->addMapLayer( layer.release() );
177
178 QVariantMap outputs;
179 outputs.insert( QStringLiteral( "OUTPUT" ), layerId );
180 return outputs;
181}
182
183Qgis::ProcessingAlgorithmFlags QgsVirtualRasterCalculatorModelerAlgorithm::flags() const
184{
186}
187
188QString QgsVirtualRasterCalculatorModelerAlgorithm::name() const
189{
190 return QStringLiteral( "modelervirtualrastercalc" );
191}
192
193QString QgsVirtualRasterCalculatorModelerAlgorithm::displayName() const
194{
195 return QObject::tr( "Raster calculator (virtual)" );
196}
197
198QStringList QgsVirtualRasterCalculatorModelerAlgorithm::tags() const
199{
200 return QObject::tr( "raster,calculator,virtual" ).split( ',' );
201}
202
203QString QgsVirtualRasterCalculatorModelerAlgorithm::group() const
204{
205 return QObject::tr( "Raster analysis" );
206}
207
208QString QgsVirtualRasterCalculatorModelerAlgorithm::groupId() const
209{
210 return QStringLiteral( "rasteranalysis" );
211}
212
213QgsVirtualRasterCalculatorModelerAlgorithm *QgsVirtualRasterCalculatorModelerAlgorithm::createInstance() const
214{
215 return new QgsVirtualRasterCalculatorModelerAlgorithm();
216}
217
218QVariantMap QgsVirtualRasterCalculatorModelerAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
219{
220 Q_UNUSED( feedback );
221
222 const QList< QgsMapLayer * > layers = parameterAsLayerList( parameters, QStringLiteral( "INPUT" ), context );
223 if ( layers.isEmpty() )
224 {
225 throw QgsProcessingException( QObject::tr( "No input layers selected" ) );
226 }
227
229 if ( parameters.value( QStringLiteral( "CRS" ) ).isValid() )
230 {
231 crs = parameterAsCrs( parameters, QStringLiteral( "CRS" ), context );
232 }
233 else
234 {
235 crs = layers.at( 0 )->crs();
236 }
237
238 QgsRectangle bbox;
239 if ( parameters.value( QStringLiteral( "EXTENT" ) ).isValid() )
240 {
241 bbox = parameterAsExtent( parameters, QStringLiteral( "EXTENT" ), context, crs );
242 }
243 else
244 {
245 bbox = QgsProcessingUtils::combineLayerExtents( layers, crs, context );
246 }
247
248 double minCellSize = 1e9;
250
251 int n = 0;
252 for ( const QgsMapLayer *layer : layers )
253 {
254 const QgsRasterLayer *rLayer = qobject_cast<const QgsRasterLayer *>( layer );
255 if ( !rLayer )
256 {
257 continue;
258 }
259
260 n++;
262 rasterLayer.name = indexToName( n );
263 rasterLayer.provider = rLayer->dataProvider()->name();
264 rasterLayer.uri = rLayer->source();
265 rasterParameters.rInputLayers.append( rasterLayer );
266
267 QgsRectangle ext = rLayer->extent();
268 if ( rLayer->crs() != crs )
269 {
270 QgsCoordinateTransform ct( rLayer->crs(), crs, context.transformContext() );
271 ext = ct.transformBoundingBox( ext );
272 }
273
274 double cellSize = ( ext.xMaximum() - ext.xMinimum() ) / rLayer->width();
275 if ( cellSize < minCellSize )
276 {
277 minCellSize = cellSize;
278 }
279 }
280
281 double cellSize = parameterAsDouble( parameters, QStringLiteral( "CELL_SIZE" ), context );
282 if ( cellSize == 0 )
283 {
284 cellSize = minCellSize;
285 }
286
287 const QString expression = parameterAsExpression( parameters, QStringLiteral( "EXPRESSION" ), context );
288 QString layerName = parameterAsString( parameters, QStringLiteral( "LAYER_NAME" ), context );
289 if ( layerName.isEmpty() )
290 {
291 layerName = expression;
292 }
293
294 double width = std::round( ( bbox.xMaximum() - bbox.xMinimum() ) / cellSize );
295 double height = std::round( ( bbox.yMaximum() - bbox.yMinimum() ) / cellSize );
296
297 rasterParameters.crs = crs;
298 rasterParameters.extent = bbox;
299 rasterParameters.width = width;
300 rasterParameters.height = height;
301 rasterParameters.formula = expression;
302
303 std::unique_ptr< QgsRasterLayer > layer;
304 layer = std::make_unique< QgsRasterLayer >( QgsRasterDataProvider::encodeVirtualRasterProviderUri( rasterParameters ),
305 layerName, QStringLiteral( "virtualraster" ) );
306 if ( !layer->isValid() )
307 {
308 feedback->reportError( QObject::tr( "Failed to create virtual raster layer" ) );
309 }
310 else
311 {
312 }
313 const QString layerId = layer->id();
314 const QgsProcessingContext::LayerDetails details( layer->name(), context.project(), QStringLiteral( "OUTPUT" ), QgsProcessingUtils::LayerHint::Raster );
315 context.addLayerToLoadOnCompletion( layerId, details );
316 context.temporaryLayerStore()->addMapLayer( layer.release() );
317
318 QVariantMap outputs;
319 outputs.insert( QStringLiteral( "OUTPUT" ), layerId );
320 return outputs;
321}
322
323QString QgsVirtualRasterCalculatorModelerAlgorithm::indexToName( int index ) const
324{
325 QString name;
326 int div = index;
327 int mod = 0;
328
329 while ( div > 0 )
330 {
331 mod = ( div - 1 ) % 26;
332 name = static_cast<char>( 65 + mod ) + name;
333 div = ( int )( ( div - mod ) / 26 );
334 }
335 return name;
336}
337
@ RasterCalculator
Raster calculator expression (since QGIS 3.34)
QFlags< ProcessingAlgorithmFlag > ProcessingAlgorithmFlags
Flags indicating how and when an algorithm operates and should be exposed to users.
Definition: qgis.h:2934
@ 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...
This class represents a coordinate reference system (CRS).
Class for doing transforms between two map 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:75
QString name
Definition: qgsmaplayer.h:78
virtual QgsRectangle extent() const
Returns the extent of the layer.
QString source() const
Returns the source for the layer.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:81
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.
Definition: qgsexception.h:83
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.
Definition: qgsrectangle.h:42
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:201
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:211
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:196
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:206
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