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