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