QGIS API Documentation 3.41.0-Master (af5edcb665c)
Loading...
Searching...
No Matches
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 ), layerName, QStringLiteral( "virtualraster" ) );
165 if ( !layer->isValid() )
166 {
167 feedback->reportError( QObject::tr( "Failed to create virtual raster layer" ) );
168 }
169 else
170 {
171 }
172 const QString layerId = layer->id();
173 const QgsProcessingContext::LayerDetails details( layer->name(), context.project(), QStringLiteral( "OUTPUT" ), QgsProcessingUtils::LayerHint::Raster );
174 context.addLayerToLoadOnCompletion( layerId, details );
175 context.temporaryLayerStore()->addMapLayer( layer.release() );
176
177 QVariantMap outputs;
178 outputs.insert( QStringLiteral( "OUTPUT" ), layerId );
179 return outputs;
180}
181
182Qgis::ProcessingAlgorithmFlags QgsVirtualRasterCalculatorModelerAlgorithm::flags() const
183{
185}
186
187QString QgsVirtualRasterCalculatorModelerAlgorithm::name() const
188{
189 return QStringLiteral( "modelervirtualrastercalc" );
190}
191
192QString QgsVirtualRasterCalculatorModelerAlgorithm::displayName() const
193{
194 return QObject::tr( "Raster calculator (virtual)" );
195}
196
197QStringList QgsVirtualRasterCalculatorModelerAlgorithm::tags() const
198{
199 return QObject::tr( "raster,calculator,virtual" ).split( ',' );
200}
201
202QString QgsVirtualRasterCalculatorModelerAlgorithm::group() const
203{
204 return QObject::tr( "Raster analysis" );
205}
206
207QString QgsVirtualRasterCalculatorModelerAlgorithm::groupId() const
208{
209 return QStringLiteral( "rasteranalysis" );
210}
211
212QgsVirtualRasterCalculatorModelerAlgorithm *QgsVirtualRasterCalculatorModelerAlgorithm::createInstance() const
213{
214 return new QgsVirtualRasterCalculatorModelerAlgorithm();
215}
216
217QVariantMap QgsVirtualRasterCalculatorModelerAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
218{
219 Q_UNUSED( feedback );
220
221 const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, QStringLiteral( "INPUT" ), context );
222 if ( layers.isEmpty() )
223 {
224 throw QgsProcessingException( QObject::tr( "No input layers selected" ) );
225 }
226
228 if ( parameters.value( QStringLiteral( "CRS" ) ).isValid() )
229 {
230 crs = parameterAsCrs( parameters, QStringLiteral( "CRS" ), context );
231 }
232 else
233 {
234 crs = layers.at( 0 )->crs();
235 }
236
237 QgsRectangle bbox;
238 if ( parameters.value( QStringLiteral( "EXTENT" ) ).isValid() )
239 {
240 bbox = parameterAsExtent( parameters, QStringLiteral( "EXTENT" ), context, crs );
241 }
242 else
243 {
244 bbox = QgsProcessingUtils::combineLayerExtents( layers, crs, context );
245 }
246
247 double minCellSize = 1e9;
249
250 int n = 0;
251 for ( const QgsMapLayer *layer : layers )
252 {
253 const QgsRasterLayer *rLayer = qobject_cast<const QgsRasterLayer *>( layer );
254 if ( !rLayer )
255 {
256 continue;
257 }
258
259 n++;
261 rasterLayer.name = indexToName( n );
262 rasterLayer.provider = rLayer->dataProvider()->name();
263 rasterLayer.uri = rLayer->source();
264 rasterParameters.rInputLayers.append( rasterLayer );
265
266 QgsRectangle ext = rLayer->extent();
267 if ( rLayer->crs() != crs )
268 {
269 QgsCoordinateTransform ct( rLayer->crs(), crs, context.transformContext() );
270 ext = ct.transformBoundingBox( ext );
271 }
272
273 double cellSize = ( ext.xMaximum() - ext.xMinimum() ) / rLayer->width();
274 if ( cellSize < minCellSize )
275 {
276 minCellSize = cellSize;
277 }
278 }
279
280 double cellSize = parameterAsDouble( parameters, QStringLiteral( "CELL_SIZE" ), context );
281 if ( cellSize == 0 )
282 {
283 cellSize = minCellSize;
284 }
285
286 const QString expression = parameterAsExpression( parameters, QStringLiteral( "EXPRESSION" ), context );
287 QString layerName = parameterAsString( parameters, QStringLiteral( "LAYER_NAME" ), context );
288 if ( layerName.isEmpty() )
289 {
290 layerName = expression;
291 }
292
293 double width = std::round( ( bbox.xMaximum() - bbox.xMinimum() ) / cellSize );
294 double height = std::round( ( bbox.yMaximum() - bbox.yMinimum() ) / cellSize );
295
296 rasterParameters.crs = crs;
297 rasterParameters.extent = bbox;
298 rasterParameters.width = width;
299 rasterParameters.height = height;
300 rasterParameters.formula = expression;
301
302 std::unique_ptr<QgsRasterLayer> layer;
303 layer = std::make_unique<QgsRasterLayer>( QgsRasterDataProvider::encodeVirtualRasterProviderUri( rasterParameters ), layerName, QStringLiteral( "virtualraster" ) );
304 if ( !layer->isValid() )
305 {
306 feedback->reportError( QObject::tr( "Failed to create virtual raster layer" ) );
307 }
308 else
309 {
310 }
311 const QString layerId = layer->id();
312 const QgsProcessingContext::LayerDetails details( layer->name(), context.project(), QStringLiteral( "OUTPUT" ), QgsProcessingUtils::LayerHint::Raster );
313 context.addLayerToLoadOnCompletion( layerId, details );
314 context.temporaryLayerStore()->addMapLayer( layer.release() );
315
316 QVariantMap outputs;
317 outputs.insert( QStringLiteral( "OUTPUT" ), layerId );
318 return outputs;
319}
320
321QString QgsVirtualRasterCalculatorModelerAlgorithm::indexToName( int index ) const
322{
323 QString name;
324 int div = index;
325 int mod = 0;
326
327 while ( div > 0 )
328 {
329 mod = ( div - 1 ) % 26;
330 name = static_cast<char>( 65 + mod ) + name;
331 div = ( int ) ( ( div - mod ) / 26 );
332 }
333 return name;
334}
335
@ RasterCalculator
Raster calculator expression.
QFlags< ProcessingAlgorithmFlag > ProcessingAlgorithmFlags
Flags indicating how and when an algorithm operates and should be exposed to users.
Definition qgis.h:3410
@ 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:76
QString name
Definition qgsmaplayer.h:80
virtual QgsRectangle extent() const
Returns the extent of the layer.
QString source() const
Returns the source for the layer.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:83
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