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