QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
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<
81 QgsProcessingParameterNumber>( u"CELL_SIZE"_s, QObject::tr( "Output cell size (leave empty to set automatically)" ), Qgis::ProcessingNumberParameterType::Double, QVariant(), true, 0.0 );
82 cellSizeParam->setHelp( QObject::tr( "Cell size of the output layer. If not specified, the smallest cell size from the input layers will be used" ) );
83 addParameter( cellSizeParam.release() );
84 auto crsParam = std::make_unique<QgsProcessingParameterCrs>( u"CRS"_s, QObject::tr( "Output CRS" ), QVariant(), true );
85 crsParam->setHelp( QObject::tr( "CRS of the output layer. If not specified, the CRS of the first input layer will be used" ) );
86 addParameter( crsParam.release() );
87 addParameter( new QgsProcessingParameterString( u"LAYER_NAME"_s, QObject::tr( "Output layer name" ), QVariant(), false, true ) );
88 addOutput( new QgsProcessingOutputRasterLayer( u"OUTPUT"_s, QObject::tr( "Calculated" ) ) );
89}
90
91QVariantMap QgsVirtualRasterCalculatorAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
92{
93 Q_UNUSED( feedback );
94
95 const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, u"LAYERS"_s, context );
96 if ( layers.isEmpty() )
97 {
98 throw QgsProcessingException( QObject::tr( "No input layers selected" ) );
99 }
100
102 if ( parameters.value( u"CRS"_s ).isValid() )
103 {
104 crs = parameterAsCrs( parameters, u"CRS"_s, context );
105 }
106 else
107 {
108 crs = layers.at( 0 )->crs();
109 }
110
111 QgsRectangle bbox;
112 if ( parameters.value( u"EXTENT"_s ).isValid() )
113 {
114 bbox = parameterAsExtent( parameters, u"EXTENT"_s, context, crs );
115 }
116 else
117 {
118 bbox = QgsProcessingUtils::combineLayerExtents( layers, crs, context );
119 }
120
121 double minCellSize = 1e9;
123
124 for ( const QgsMapLayer *layer : layers )
125 {
126 const QgsRasterLayer *rLayer = qobject_cast<const QgsRasterLayer *>( layer );
127 if ( !rLayer )
128 {
129 continue;
130 }
131
133 rasterLayer.name = rLayer->name();
134 rasterLayer.provider = rLayer->dataProvider()->name();
135 rasterLayer.uri = rLayer->source();
136 rasterParameters.rInputLayers.append( rasterLayer );
137
138 QgsRectangle ext = rLayer->extent();
139 if ( rLayer->crs() != crs )
140 {
141 QgsCoordinateTransform ct( rLayer->crs(), crs, context.transformContext() );
142 ext = ct.transformBoundingBox( ext );
143 }
144
145 double cellSize = ( ext.xMaximum() - ext.xMinimum() ) / rLayer->width();
146 if ( cellSize < minCellSize )
147 {
148 minCellSize = cellSize;
149 }
150 }
151
152 double cellSize = parameterAsDouble( parameters, u"CELL_SIZE"_s, context );
153 if ( cellSize == 0 )
154 {
155 cellSize = minCellSize;
156 }
157
158 const QString expression = parameterAsExpression( parameters, u"EXPRESSION"_s, context );
159 QString layerName = parameterAsString( parameters, u"LAYER_NAME"_s, context );
160 if ( layerName.isEmpty() )
161 {
162 layerName = expression;
163 }
164
165 double width = std::round( ( bbox.xMaximum() - bbox.xMinimum() ) / cellSize );
166 double height = std::round( ( bbox.yMaximum() - bbox.yMinimum() ) / cellSize );
167
168 rasterParameters.crs = crs;
169 rasterParameters.extent = bbox;
170 rasterParameters.width = width;
171 rasterParameters.height = height;
172 rasterParameters.formula = expression;
173
174 std::unique_ptr<QgsRasterLayer> layer;
175 layer = std::make_unique<QgsRasterLayer>( QgsRasterDataProvider::encodeVirtualRasterProviderUri( rasterParameters ), layerName, u"virtualraster"_s );
176 if ( !layer->isValid() )
177 {
178 feedback->reportError( QObject::tr( "Failed to create virtual raster layer" ) );
179 }
180 else
181 {
182 }
183 const QString layerId = layer->id();
184 const QgsProcessingContext::LayerDetails details( layer->name(), context.project(), u"OUTPUT"_s, QgsProcessingUtils::LayerHint::Raster );
185 context.addLayerToLoadOnCompletion( layerId, details );
186 context.temporaryLayerStore()->addMapLayer( layer.release() );
187
188 QVariantMap outputs;
189 outputs.insert( u"OUTPUT"_s, layerId );
190 return outputs;
191}
192
193Qgis::ProcessingAlgorithmFlags QgsVirtualRasterCalculatorModelerAlgorithm::flags() const
194{
196}
197
198QString QgsVirtualRasterCalculatorModelerAlgorithm::name() const
199{
200 return u"modelervirtualrastercalc"_s;
201}
202
203QString QgsVirtualRasterCalculatorModelerAlgorithm::displayName() const
204{
205 return QObject::tr( "Raster calculator (virtual)" );
206}
207
208QStringList QgsVirtualRasterCalculatorModelerAlgorithm::tags() const
209{
210 return QObject::tr( "raster,calculator,virtual" ).split( ',' );
211}
212
213QString QgsVirtualRasterCalculatorModelerAlgorithm::group() const
214{
215 return QObject::tr( "Raster analysis" );
216}
217
218QString QgsVirtualRasterCalculatorModelerAlgorithm::groupId() const
219{
220 return u"rasteranalysis"_s;
221}
222
223QgsVirtualRasterCalculatorModelerAlgorithm *QgsVirtualRasterCalculatorModelerAlgorithm::createInstance() const
224{
225 return new QgsVirtualRasterCalculatorModelerAlgorithm();
226}
227
228QVariantMap QgsVirtualRasterCalculatorModelerAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
229{
230 Q_UNUSED( feedback );
231
232 const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, u"INPUT"_s, context );
233 if ( layers.isEmpty() )
234 {
235 throw QgsProcessingException( QObject::tr( "No input layers selected" ) );
236 }
237
239 if ( parameters.value( u"CRS"_s ).isValid() )
240 {
241 crs = parameterAsCrs( parameters, u"CRS"_s, context );
242 }
243 else
244 {
245 crs = layers.at( 0 )->crs();
246 }
247
248 QgsRectangle bbox;
249 if ( parameters.value( u"EXTENT"_s ).isValid() )
250 {
251 bbox = parameterAsExtent( parameters, u"EXTENT"_s, context, crs );
252 }
253 else
254 {
255 bbox = QgsProcessingUtils::combineLayerExtents( layers, crs, context );
256 }
257
258 double minCellSize = 1e9;
260
261 int n = 0;
262 for ( const QgsMapLayer *layer : layers )
263 {
264 const QgsRasterLayer *rLayer = qobject_cast<const QgsRasterLayer *>( layer );
265 if ( !rLayer )
266 {
267 continue;
268 }
269
270 n++;
272 rasterLayer.name = indexToName( n );
273 rasterLayer.provider = rLayer->dataProvider()->name();
274 rasterLayer.uri = rLayer->source();
275 rasterParameters.rInputLayers.append( rasterLayer );
276
277 QgsRectangle ext = rLayer->extent();
278 if ( rLayer->crs() != crs )
279 {
280 QgsCoordinateTransform ct( rLayer->crs(), crs, context.transformContext() );
281 ext = ct.transformBoundingBox( ext );
282 }
283
284 double cellSize = ( ext.xMaximum() - ext.xMinimum() ) / rLayer->width();
285 if ( cellSize < minCellSize )
286 {
287 minCellSize = cellSize;
288 }
289 }
290
291 double cellSize = parameterAsDouble( parameters, u"CELL_SIZE"_s, context );
292 if ( cellSize == 0 )
293 {
294 cellSize = minCellSize;
295 }
296
297 const QString expression = parameterAsExpression( parameters, u"EXPRESSION"_s, context );
298 QString layerName = parameterAsString( parameters, u"LAYER_NAME"_s, context );
299 if ( layerName.isEmpty() )
300 {
301 layerName = expression;
302 }
303
304 double width = std::round( ( bbox.xMaximum() - bbox.xMinimum() ) / cellSize );
305 double height = std::round( ( bbox.yMaximum() - bbox.yMinimum() ) / cellSize );
306
307 rasterParameters.crs = crs;
308 rasterParameters.extent = bbox;
309 rasterParameters.width = width;
310 rasterParameters.height = height;
311 rasterParameters.formula = expression;
312
313 std::unique_ptr<QgsRasterLayer> layer;
314 layer = std::make_unique<QgsRasterLayer>( QgsRasterDataProvider::encodeVirtualRasterProviderUri( rasterParameters ), layerName, u"virtualraster"_s );
315 if ( !layer->isValid() )
316 {
317 feedback->reportError( QObject::tr( "Failed to create virtual raster layer" ) );
318 }
319 else
320 {
321 }
322 const QString layerId = layer->id();
323 const QgsProcessingContext::LayerDetails details( layer->name(), context.project(), u"OUTPUT"_s, QgsProcessingUtils::LayerHint::Raster );
324 context.addLayerToLoadOnCompletion( layerId, details );
325 context.temporaryLayerStore()->addMapLayer( layer.release() );
326
327 QVariantMap outputs;
328 outputs.insert( u"OUTPUT"_s, layerId );
329 return outputs;
330}
331
332QString QgsVirtualRasterCalculatorModelerAlgorithm::indexToName( int index ) const
333{
334 QString name;
335 int div = index;
336 int mod = 0;
337
338 while ( div > 0 )
339 {
340 mod = ( div - 1 ) % 26;
341 name = static_cast<char>( 65 + mod ) + name;
342 div = ( int ) ( ( div - mod ) / 26 );
343 }
344 return name;
345}
346
@ Raster
Raster layers.
Definition qgis.h:3651
@ RasterCalculator
Raster calculator expression.
Definition qgis.h:5901
QFlags< ProcessingAlgorithmFlag > ProcessingAlgorithmFlags
Flags indicating how and when an algorithm operates and should be exposed to users.
Definition qgis.h:3724
@ HideFromToolbox
Algorithm should be hidden from the toolbox.
Definition qgis.h:3698
@ HideFromModeler
Algorithm should be hidden from the modeler.
Definition qgis.h:3699
@ NoThreading
Algorithm is not thread safe and cannot be run in a background thread, e.g. for algorithms which mani...
Definition qgis.h:3703
@ Double
Double/float values.
Definition qgis.h:3921
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.
void setHelp(const QString &help)
Sets the help for the parameter.
An expression parameter for processing algorithms.
A parameter for processing algorithms which accepts multiple map layers.
A numeric parameter for processing algorithms.
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