QGIS API Documentation 4.3.0-Master (0d5b841b09e)
Loading...
Searching...
No Matches
qgsalgorithmrasterdtmslopebasedfilter.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmrasterdtmslopebasedfilter.cpp
3 ---------------------
4 begin : July 2023
5 copyright : (C) 2023 by Nyall Dawson
6 email : nyall dot dawson 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
20#include <algorithm>
21
23#include "qgsrasterfilewriter.h"
24
25#include <QString>
26
27using namespace Qt::StringLiterals;
28
30
31QString QgsRasterDtmSlopeBasedFilterAlgorithm::name() const
32{
33 return u"dtmslopebasedfilter"_s;
34}
35
36QString QgsRasterDtmSlopeBasedFilterAlgorithm::displayName() const
37{
38 return QObject::tr( "DTM filter (slope-based)" );
39}
40
41QStringList QgsRasterDtmSlopeBasedFilterAlgorithm::tags() const
42{
43 return QObject::tr( "dem,filter,slope,dsm,dtm,terrain" ).split( ',' );
44}
45
46QString QgsRasterDtmSlopeBasedFilterAlgorithm::group() const
47{
48 return QObject::tr( "Raster terrain analysis" );
49}
50
51QString QgsRasterDtmSlopeBasedFilterAlgorithm::groupId() const
52{
53 return u"rasterterrainanalysis"_s;
54}
55
56QString QgsRasterDtmSlopeBasedFilterAlgorithm::shortHelpString() const
57{
58 return QObject::tr(
59 "This algorithm can be used to filter a Digital Elevation Model in order to classify its cells into ground and object (non-ground) cells.\n\n"
60 "The tool uses concepts as described by Vosselman (2000) and is based on the assumption that a large height difference between two nearby "
61 "cells is unlikely to be caused by a steep slope in the terrain. The probability that the higher cell might be non-ground increases when "
62 "the distance between the two cells decreases. Therefore the filter defines a maximum height difference (<i>dz_max</i>) between two cells as a "
63 "function of the distance (<i>d</i>) between the cells (<i>dz_max( d ) = d</i>).\n\n"
64 "A cell is classified as terrain if there is no cell within the kernel radius to which the height difference is larger than the allowed "
65 "maximum height difference at the distance between these two cells.\n\n"
66 "The approximate terrain slope (<i>s</i>) parameter is used to modify the filter function to match the overall slope in the study "
67 "area (<i>dz_max( d ) = d * s</i>).\n\n"
68 "A 5 % confidence interval (<i>ci = 1.65 * sqrt( 2 * stddev )</i>) may be used to modify the filter function even further by either "
69 "relaxing (<i>dz_max( d ) = d * s + ci</i>) or amplifying (<i>dz_max( d ) = d * s - ci</i>) the filter criterium.\n\n"
70 "This algorithm is a port of the SAGA 'DTM Filter (slope-based)' tool."
71 );
72}
73
74QList<QgsAcademicReference> QgsRasterDtmSlopeBasedFilterAlgorithm::academicReferences() const
75{
76 const QgsAcademicReference ref
77 = QgsAcademicReference::createJournalArticle( { u"Vosselman, G."_s }, 2000, u"Slope based filtering of laser altimetry data"_s, u"IAPRS"_s, u"Vol. XXXIII"_s, QString(), u"935-942"_s );
78 return { ref };
79}
80
81QList<QgsProcessingAlgorithm::ExternalLink> QgsRasterDtmSlopeBasedFilterAlgorithm::externalLinks() const
82{
83 return {
84 QgsProcessingAlgorithm::ExternalLink { QObject::tr( "SAGA tool source code" ), u"https://sourceforge.net/p/saga-gis/code/ci/d0dd586dac6e8bf3644b3012d6fc9466353b2af8/tree/saga-gis/src/tools/grid/grid_filter/Filter_Terrain_SlopeBased.cpp"_s }
85 };
86}
87
88QString QgsRasterDtmSlopeBasedFilterAlgorithm::shortDescription() const
89{
90 return QObject::tr( "Filters a Digital Elevation Model in order to classify its cells into ground and object (non-ground) cells." );
91}
92
93void QgsRasterDtmSlopeBasedFilterAlgorithm::initAlgorithm( const QVariantMap & )
94{
95 addParameter( new QgsProcessingParameterRasterLayer( u"INPUT"_s, QObject::tr( "Input layer" ) ) );
96
97 addParameter( new QgsProcessingParameterBand( u"BAND"_s, QObject::tr( "Band number" ), 1, u"INPUT"_s ) );
98
99 auto radiusParam = std::make_unique<QgsProcessingParameterNumber>( u"RADIUS"_s, QObject::tr( "Kernel radius (pixels)" ), Qgis::ProcessingNumberParameterType::Integer, 5, false, 1, 1000 );
100 radiusParam->setHelp( QObject::tr( "The radius of the filter kernel (in pixels). Must be large enough to reach ground cells next to non-ground objects." ) );
101 addParameter( radiusParam.release() );
102
103 auto terrainSlopeParam
104 = std::make_unique<QgsProcessingParameterNumber>( u"TERRAIN_SLOPE"_s, QObject::tr( "Terrain slope (%, pixel size/vertical units)" ), Qgis::ProcessingNumberParameterType::Double, 30, false, 0, 1000 );
105 terrainSlopeParam->setHelp(
106 QObject::tr( "The approximate terrain slope in %. The terrain slope must be adjusted to account for the ratio of height units vs raster pixel dimensions. Used to relax the filter criterium in steeper terrain." )
107 );
108 addParameter( terrainSlopeParam.release() );
109
110 auto filterModificationParam = std::make_unique<
111 QgsProcessingParameterEnum>( u"FILTER_MODIFICATION"_s, QObject::tr( "Filter modification" ), QStringList { QObject::tr( "None" ), QObject::tr( "Relax filter" ), QObject::tr( "Amplify" ) }, false, 0 );
112 filterModificationParam->setHelp( QObject::tr( "Choose whether to apply the filter kernel without modification or to use a confidence interval to relax or amplify the height criterium." ) );
113 addParameter( filterModificationParam.release() );
114
115 auto stDevParam = std::make_unique<QgsProcessingParameterNumber>( u"STANDARD_DEVIATION"_s, QObject::tr( "Standard deviation" ), Qgis::ProcessingNumberParameterType::Double, 0.1, false, 0, 1000 );
116 stDevParam->setHelp( QObject::tr( "The standard deviation used to calculate a 5% confidence interval applied to the height threshold." ) );
117 addParameter( stDevParam.release() );
118
119 // backwards compatibility parameter
120 // TODO QGIS 5: remove parameter and related logic
121 auto createOptsParam = std::make_unique<QgsProcessingParameterString>( u"CREATE_OPTIONS"_s, QObject::tr( "Creation options" ), QVariant(), false, true );
122 createOptsParam->setMetadata( QVariantMap( { { u"widget_wrapper"_s, QVariantMap( { { u"widget_type"_s, u"rasteroptions"_s } } ) } } ) );
123 createOptsParam->setFlags( createOptsParam->flags() | Qgis::ProcessingParameterFlag::Hidden );
124 addParameter( createOptsParam.release() );
125
126 auto creationOptsParam = std::make_unique<QgsProcessingParameterString>( u"CREATION_OPTIONS"_s, QObject::tr( "Creation options" ), QVariant(), false, true );
127 creationOptsParam->setMetadata( QVariantMap( { { u"widget_wrapper"_s, QVariantMap( { { u"widget_type"_s, u"rasteroptions"_s } } ) } } ) );
128 creationOptsParam->setFlags( creationOptsParam->flags() | Qgis::ProcessingParameterFlag::Advanced );
129 addParameter( creationOptsParam.release() );
130
131 auto outputLayerGroundParam = std::make_unique<QgsProcessingParameterRasterDestination>( u"OUTPUT_GROUND"_s, QObject::tr( "Output layer (ground)" ), QVariant(), true, true );
132 outputLayerGroundParam->setHelp( QObject::tr( "The filtered DEM containing only cells classified as ground." ) );
133 addParameter( outputLayerGroundParam.release() );
134
135 auto outputLayerNonGroundParam = std::make_unique<QgsProcessingParameterRasterDestination>( u"OUTPUT_NONGROUND"_s, QObject::tr( "Output layer (non-ground objects)" ), QVariant(), true, false );
136 outputLayerNonGroundParam->setHelp( QObject::tr( "The non-ground objects removed by the filter." ) );
137 addParameter( outputLayerNonGroundParam.release() );
138}
139
140QgsRasterDtmSlopeBasedFilterAlgorithm *QgsRasterDtmSlopeBasedFilterAlgorithm::createInstance() const
141{
142 return new QgsRasterDtmSlopeBasedFilterAlgorithm();
143}
144
145bool QgsRasterDtmSlopeBasedFilterAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
146{
147 QgsRasterLayer *layer = parameterAsRasterLayer( parameters, u"INPUT"_s, context );
148 if ( !layer )
149 throw QgsProcessingException( invalidRasterError( parameters, u"INPUT"_s ) );
150
151 const int band = parameterAsInt( parameters, u"BAND"_s, context );
152
153 mBand = parameterAsInt( parameters, u"BAND"_s, context );
154 if ( mBand < 1 || mBand > layer->bandCount() )
155 throw QgsProcessingException( QObject::tr( "Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand ).arg( layer->bandCount() ) );
156
157 mInterface.reset( layer->dataProvider()->clone() );
158 mHasNoDataValue = layer->dataProvider()->sourceHasNoDataValue( band );
159 mLayerWidth = layer->width();
160 mLayerHeight = layer->height();
161 mExtent = layer->extent();
162 mCrs = layer->crs();
163 mRasterUnitsPerPixelX = layer->rasterUnitsPerPixelX();
164 mRasterUnitsPerPixelY = layer->rasterUnitsPerPixelY();
165 mDataType = layer->dataProvider()->dataType( mBand );
166 mNoData = layer->dataProvider()->sourceNoDataValue( mBand );
167 return true;
168}
169
170QVariantMap QgsRasterDtmSlopeBasedFilterAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
171{
172 QGS_MARK_ALGORITHM_SOURCE
173
174 QString creationOptions = parameterAsString( parameters, u"CREATION_OPTIONS"_s, context ).trimmed();
175 // handle backwards compatibility parameter CREATE_OPTIONS
176 const QString optionsString = parameterAsString( parameters, u"CREATE_OPTIONS"_s, context );
177 if ( !optionsString.isEmpty() )
178 creationOptions = optionsString;
179
180 const QString groundOutputFile = parameterAsOutputLayer( parameters, u"OUTPUT_GROUND"_s, context );
181 std::unique_ptr<QgsRasterFileWriter> groundWriter;
182 std::unique_ptr<QgsRasterDataProvider> groundDestProvider;
183
184 if ( !groundOutputFile.isEmpty() )
185 {
186 const QString outputFormat = parameterAsOutputRasterFormat( parameters, u"OUTPUT_GROUND"_s, context );
187
188 groundWriter = std::make_unique<QgsRasterFileWriter>( groundOutputFile );
189 groundWriter->setOutputProviderKey( u"gdal"_s );
190 if ( !creationOptions.isEmpty() )
191 {
192 groundWriter->setCreationOptions( creationOptions.split( '|' ) );
193 }
194 groundWriter->setOutputFormat( outputFormat );
195
196 groundDestProvider.reset( groundWriter->createOneBandRaster( mDataType, mLayerWidth, mLayerHeight, mExtent, mCrs ) );
197
198 if ( !groundDestProvider )
199 throw QgsProcessingException( QObject::tr( "Could not create raster output: %1" ).arg( groundOutputFile ) );
200 if ( !groundDestProvider->isValid() )
201 throw QgsProcessingException( QObject::tr( "Could not create raster output %1: %2" ).arg( groundOutputFile, groundDestProvider->error().message( QgsErrorMessage::Text ) ) );
202
203 groundDestProvider->setNoDataValue( 1, mNoData );
204 groundDestProvider->setEditable( true );
205 }
206
207 const QString nonGroundOutputFile = parameterAsOutputLayer( parameters, u"OUTPUT_NONGROUND"_s, context );
208 std::unique_ptr<QgsRasterFileWriter> nonGroundWriter;
209 std::unique_ptr<QgsRasterDataProvider> nonGroundDestProvider;
210
211 if ( !nonGroundOutputFile.isEmpty() )
212 {
213 const QString outputFormat = parameterAsOutputRasterFormat( parameters, u"OUTPUT_NONGROUND"_s, context );
214
215 nonGroundWriter = std::make_unique<QgsRasterFileWriter>( nonGroundOutputFile );
216 nonGroundWriter->setOutputProviderKey( u"gdal"_s );
217 if ( !creationOptions.isEmpty() )
218 {
219 nonGroundWriter->setCreationOptions( creationOptions.split( '|' ) );
220 }
221 nonGroundWriter->setOutputFormat( outputFormat );
222
223 nonGroundDestProvider.reset( nonGroundWriter->createOneBandRaster( mDataType, mLayerWidth, mLayerHeight, mExtent, mCrs ) );
224
225 if ( !nonGroundDestProvider )
226 throw QgsProcessingException( QObject::tr( "Could not create raster output: %1" ).arg( nonGroundOutputFile ) );
227 if ( !nonGroundDestProvider->isValid() )
228 throw QgsProcessingException( QObject::tr( "Could not create raster output %1: %2" ).arg( nonGroundOutputFile, nonGroundDestProvider->error().message( QgsErrorMessage::Text ) ) );
229
230 nonGroundDestProvider->setNoDataValue( 1, mNoData );
231 nonGroundDestProvider->setEditable( true );
232 }
233
236 const int numBlocksX = static_cast<int>( std::ceil( 1.0 * mLayerWidth / blockWidth ) );
237 const int numBlocksY = static_cast<int>( std::ceil( 1.0 * mLayerHeight / blockHeight ) );
238 const int numBlocks = numBlocksX * numBlocksY;
239
240 const int radius = parameterAsInt( parameters, u"RADIUS"_s, context );
241
242 const double terrainSlopePercent = parameterAsDouble( parameters, u"TERRAIN_SLOPE"_s, context ) / 100; //20.0 / 100 * 0.143;
243 const int filterModification = parameterAsEnum( parameters, u"FILTER_MODIFICATION"_s, context );
244 const double standardDeviation = parameterAsDouble( parameters, u"STANDARD_DEVIATION"_s, context );
245
246 // create kernel
247 QVector<double> kernel;
248 kernel.reserve( ( radius * 2 ) * ( radius * 2 ) );
249 int kernelSize = 0;
250 for ( int y = -radius; y <= radius; y++ )
251 {
252 for ( int x = -radius; x <= radius; x++ )
253 {
254 const double distance = std::sqrt( x * x + y * y );
255 if ( distance < radius )
256 {
257 kernelSize++;
258 kernel.push_back( x );
259 kernel.push_back( y );
260 switch ( filterModification )
261 {
262 case 0:
263 kernel.push_back( distance * terrainSlopePercent );
264 break;
265
266 case 1:
267 kernel.push_back( distance * terrainSlopePercent + 1.65 * std::sqrt( 2 * standardDeviation ) );
268 break;
269
270 case 2:
271 {
272 const double dz = distance * terrainSlopePercent - 1.65 * std::sqrt( 2 * standardDeviation );
273 kernel.push_back( dz > 0 ? dz : 0 );
274 break;
275 }
276 }
277 }
278 }
279 }
280
281 QgsRasterIterator iter( mInterface.get(), radius );
282 iter.startRasterRead( 1, mLayerWidth, mLayerHeight, mExtent );
283 int iterLeft = 0;
284 int iterTop = 0;
285 int iterCols = 0;
286 int iterRows = 0;
287 int tileLeft = 0;
288 int tileTop = 0;
289 int tileCols = 0;
290 int tileRows = 0;
291
292 QgsRectangle blockExtent;
293
294 const bool hasGroundsReportsDuringClose = groundDestProvider && groundDestProvider->hasReportsDuringClose();
295 const bool hasNonGroundsReportsDuringClose = nonGroundDestProvider && nonGroundDestProvider->hasReportsDuringClose();
296 const double maxProgressDuringBlockWriting = 100.0 / ( 1 + ( hasGroundsReportsDuringClose ? 1 : 0 ) + ( hasNonGroundsReportsDuringClose ? 1 : 0 ) );
297
298 std::unique_ptr<QgsRasterBlock> inputBlock;
299 int blockIndex = 0;
300 while ( iter.readNextRasterPart( 1, iterCols, iterRows, inputBlock, iterLeft, iterTop, &blockExtent, &tileCols, &tileRows, &tileLeft, &tileTop ) )
301 {
302 std::unique_ptr<QgsRasterBlock> outputGroundBlock;
303 if ( groundDestProvider )
304 outputGroundBlock = std::make_unique<QgsRasterBlock>( mDataType, tileCols, tileRows );
305
306 std::unique_ptr<QgsRasterBlock> outputNonGroundBlock;
307 if ( nonGroundDestProvider )
308 outputNonGroundBlock = std::make_unique<QgsRasterBlock>( mDataType, tileCols, tileRows );
309
310 double baseProgress = static_cast<double>( blockIndex ) / numBlocks;
311 feedback->setProgress( maxProgressDuringBlockWriting * baseProgress );
312 blockIndex++;
313 if ( feedback->isCanceled() )
314 break;
315
316 const int tileBoundaryLeft = tileLeft - iterLeft;
317 const int tileBoundaryTop = tileTop - iterTop;
318
319 const double rowProgressStep = 1.0 / numBlocks / tileRows;
320 double rowProgress = 0;
321 for ( int row = tileBoundaryTop; row < tileBoundaryTop + tileRows; row++ )
322 {
323 if ( feedback->isCanceled() )
324 break;
325
326 feedback->setProgress( maxProgressDuringBlockWriting * ( baseProgress + rowProgress ) );
327 rowProgress += rowProgressStep;
328
329 for ( int col = tileBoundaryLeft; col < tileBoundaryLeft + tileCols; col++ )
330 {
331 if ( feedback->isCanceled() )
332 break;
333
334 bool isNoData = false;
335 const double val = inputBlock->valueAndNoData( row, col, isNoData );
336 if ( isNoData )
337 {
338 if ( outputGroundBlock )
339 outputGroundBlock->setValue( row - tileBoundaryTop, col - tileBoundaryLeft, mNoData );
340 if ( outputNonGroundBlock )
341 outputNonGroundBlock->setValue( row - tileBoundaryTop, col - tileBoundaryLeft, mNoData );
342 }
343 else
344 {
345 bool nonGround = false;
346 const double *kernelData = kernel.constData();
347 for ( int i = 0; i < kernelSize; ++i )
348 {
349 const int dx = static_cast<int>( *kernelData++ );
350 const int dy = static_cast<int>( *kernelData++ );
351 const double distance = *kernelData++;
352 const int rCol = col + dx;
353 const int rRow = row + dy;
354 if ( rCol >= 0 && ( rCol < ( iterLeft + iterCols ) ) && rRow >= 0 && ( rRow < ( iterTop + iterRows ) ) )
355 {
356 bool otherIsNoData = false;
357 const double otherVal = inputBlock->valueAndNoData( rRow, rCol, otherIsNoData );
358 if ( !otherIsNoData )
359 {
360 const double dz = val - otherVal;
361 if ( dz > 0 && dz > distance )
362 {
363 nonGround = true;
364 break;
365 }
366 }
367 }
368 }
369 if ( nonGround )
370 {
371 if ( outputGroundBlock )
372 outputGroundBlock->setValue( row - tileBoundaryTop, col - tileBoundaryLeft, mNoData );
373 if ( outputNonGroundBlock )
374 outputNonGroundBlock->setValue( row - tileBoundaryTop, col - tileBoundaryLeft, val );
375 }
376 else
377 {
378 if ( outputGroundBlock )
379 outputGroundBlock->setValue( row - tileBoundaryTop, col - tileBoundaryLeft, val );
380 if ( outputNonGroundBlock )
381 outputNonGroundBlock->setValue( row - tileBoundaryTop, col - tileBoundaryLeft, mNoData );
382 }
383 }
384 }
385 }
386 if ( groundDestProvider )
387 {
388 if ( !groundDestProvider->writeBlock( outputGroundBlock.get(), mBand, tileLeft, tileTop ) )
389 {
390 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( groundDestProvider->error().summary() ) );
391 }
392 }
393 if ( nonGroundDestProvider )
394 {
395 if ( !nonGroundDestProvider->writeBlock( outputNonGroundBlock.get(), mBand, tileLeft, tileTop ) )
396 {
397 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( nonGroundDestProvider->error().summary() ) );
398 }
399 }
400 }
401
402 double lastProgress = maxProgressDuringBlockWriting;
403
404 if ( groundDestProvider )
405 {
406 groundDestProvider->setEditable( false );
407 if ( feedback && hasGroundsReportsDuringClose )
408 {
409 const double nextProgress = hasNonGroundsReportsDuringClose ? 100.0 * 2 / 3 : 100.0;
410 std::unique_ptr<QgsFeedback> scaledFeedback( QgsFeedback::createScaledFeedback( feedback, lastProgress, nextProgress ) );
411 if ( !groundDestProvider->closeWithProgress( scaledFeedback.get() ) )
412 {
413 if ( feedback->isCanceled() )
414 return {};
415 throw QgsProcessingException( QObject::tr( "Could not write raster dataset" ) );
416 }
417 lastProgress = nextProgress;
418 }
419 }
420 if ( nonGroundDestProvider )
421 {
422 nonGroundDestProvider->setEditable( false );
423 if ( feedback && hasNonGroundsReportsDuringClose )
424 {
425 std::unique_ptr<QgsFeedback> scaledFeedback( QgsFeedback::createScaledFeedback( feedback, lastProgress, 100.0 ) );
426 if ( !nonGroundDestProvider->closeWithProgress( scaledFeedback.get() ) )
427 {
428 if ( feedback->isCanceled() )
429 return {};
430 throw QgsProcessingException( QObject::tr( "Could not write raster dataset" ) );
431 }
432 }
433 }
434
435 QVariantMap outputs;
436 outputs.insert( u"OUTPUT_GROUND"_s, groundOutputFile );
437 outputs.insert( u"OUTPUT_NONGROUND"_s, nonGroundOutputFile );
438 return outputs;
439}
440
441
@ Hidden
Parameter is hidden and should not be shown to users.
Definition qgis.h:3985
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
Definition qgis.h:3984
@ Double
Double/float values.
Definition qgis.h:4025
Encapsulates an academic reference and formats it according to style guidelines.
static QgsAcademicReference createJournalArticle(const QStringList &authors, int year, const QString &title, const QString &journal, const QString &volume=QString(), const QString &issue=QString(), const QString &pages=QString())
Creates a journal article reference.
@ Text
Plain text format.
Definition qgserror.h:40
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:56
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:65
static std::unique_ptr< QgsFeedback > createScaledFeedback(QgsFeedback *parentFeedback, double startPercentage, double endPercentage)
Returns a feedback object whose [0, 100] progression range will be mapped to parentFeedback [startPer...
virtual Q_INVOKABLE QgsRectangle extent() const
Returns the extent of the layer.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:90
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
A raster band parameter for Processing algorithms.
void setHelp(const QString &help)
Sets the help for the parameter.
An enum based parameter for processing algorithms, allowing for selection from predefined values.
A raster layer parameter for processing algorithms.
QgsRasterDataProvider * clone() const override=0
Clone itself, create deep copy.
virtual bool sourceHasNoDataValue(int bandNo) const
Returns true if source band has no data value.
virtual double sourceNoDataValue(int bandNo) const
Value representing no data value.
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
Iterator for sequentially processing raster cells.
static const int DEFAULT_MAXIMUM_TILE_WIDTH
Default maximum tile width.
static const int DEFAULT_MAXIMUM_TILE_HEIGHT
Default maximum tile height.
Represents a raster layer.
int height() const
Returns the height of the (unclipped) raster.
int bandCount() const
Returns the number of bands in this layer.
double rasterUnitsPerPixelX() const
Returns the number of raster units per each raster pixel in X axis.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
double rasterUnitsPerPixelY() const
Returns the number of raster units per each raster pixel in Y axis.
int width() const
Returns the width of the (unclipped) raster.
A rectangle specified with double values.