QGIS API Documentation 3.43.0-Master (9e873c7bc91)
qgsalgorithmfillnodata.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmfillnodata.cpp
3 ---------------------
4 begin : January 2020
5 copyright : (C) 2020 by Clemens Raffler
6 email : clemens dot raffler 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#include "qgsrasterfilewriter.h"
20
22
23QString QgsFillNoDataAlgorithm::name() const
24{
25 return QStringLiteral( "fillnodata" );
26}
27
28QString QgsFillNoDataAlgorithm::displayName() const
29{
30 return QObject::tr( "Fill NoData cells" );
31}
32
33QStringList QgsFillNoDataAlgorithm::tags() const
34{
35 return QObject::tr( "data,cells,fill,set" ).split( ',' );
36}
37
38QString QgsFillNoDataAlgorithm::group() const
39{
40 return QObject::tr( "Raster tools" );
41}
42
43QString QgsFillNoDataAlgorithm::groupId() const
44{
45 return QStringLiteral( "rastertools" );
46}
47
48void QgsFillNoDataAlgorithm::initAlgorithm( const QVariantMap & )
49{
50 addParameter( new QgsProcessingParameterRasterLayer( QStringLiteral( "INPUT" ), QStringLiteral( "Raster input" ) ) );
51 addParameter( new QgsProcessingParameterBand( QStringLiteral( "BAND" ), QObject::tr( "Band Number" ), 1, QStringLiteral( "INPUT" ) ) );
52 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FILL_VALUE" ), QObject::tr( "Fill value" ), Qgis::ProcessingNumberParameterType::Double, 1, false ) );
53
54 auto createOptsParam = std::make_unique<QgsProcessingParameterString>( QStringLiteral( "CREATE_OPTIONS" ), QObject::tr( "Creation options" ), QVariant(), false, true );
55 createOptsParam->setMetadata( QVariantMap( { { QStringLiteral( "widget_wrapper" ), QVariantMap( { { QStringLiteral( "widget_type" ), QStringLiteral( "rasteroptions" ) } } ) } } ) );
56 createOptsParam->setFlags( createOptsParam->flags() | Qgis::ProcessingParameterFlag::Advanced );
57 addParameter( createOptsParam.release() );
58
59 addParameter( new QgsProcessingParameterRasterDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Output raster" ) ) );
60}
61
62QString QgsFillNoDataAlgorithm::shortHelpString() const
63{
64 return QObject::tr( "This algorithm resets the NoData values in the input raster "
65 "to a chosen value, resulting in a raster dataset with no NoData pixels. "
66 "This value can be set by the user using the Fill value parameter. "
67 "The algorithm respects the input raster data type (eg. a floating point fill value will be truncated "
68 "when applied to an integer raster)." );
69}
70
71QgsFillNoDataAlgorithm *QgsFillNoDataAlgorithm::createInstance() const
72{
73 return new QgsFillNoDataAlgorithm();
74}
75
76bool QgsFillNoDataAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
77{
78 Q_UNUSED( feedback );
79 mInputRaster = parameterAsRasterLayer( parameters, QStringLiteral( "INPUT" ), context );
80 mFillValue = parameterAsDouble( parameters, QStringLiteral( "FILL_VALUE" ), context );
81
82 if ( !mInputRaster )
83 throw QgsProcessingException( invalidRasterError( parameters, QStringLiteral( "INPUT" ) ) );
84
85 mBand = parameterAsInt( parameters, QStringLiteral( "BAND" ), context );
86 if ( mBand < 1 || mBand > mInputRaster->bandCount() )
87 throw QgsProcessingException( QObject::tr( "Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand ).arg( mInputRaster->bandCount() ) );
88
89 mInterface.reset( mInputRaster->dataProvider()->clone() );
90 mInputNoDataValue = mInputRaster->dataProvider()->sourceNoDataValue( mBand );
91 mExtent = mInputRaster->extent();
92 mLayerWidth = mInputRaster->width();
93 mLayerHeight = mInputRaster->height();
94 mCrs = mInputRaster->crs();
95 mNbCellsXProvider = mInterface->xSize();
96 mNbCellsYProvider = mInterface->ySize();
97 return true;
98}
99
100QVariantMap QgsFillNoDataAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
101{
102 //test if input dataset has NoData
103 if ( !mInputRaster->dataProvider()->sourceHasNoDataValue( mBand ) )
104 feedback->reportError( QObject::tr( "Input raster has no NoData values. There exist no NoData cells to fill." ), false );
105
106 //prepare output dataset
107 const QString createOptions = parameterAsString( parameters, QStringLiteral( "CREATE_OPTIONS" ), context ).trimmed();
108 const QString outputFile = parameterAsOutputLayer( parameters, QStringLiteral( "OUTPUT" ), context );
109 const QFileInfo fi( outputFile );
110 const QString outputFormat = QgsRasterFileWriter::driverForExtension( fi.suffix() );
111 auto writer = std::make_unique<QgsRasterFileWriter>( outputFile );
112 writer->setOutputProviderKey( QStringLiteral( "gdal" ) );
113 if ( !createOptions.isEmpty() )
114 {
115 writer->setCreateOptions( createOptions.split( '|' ) );
116 }
117 writer->setOutputFormat( outputFormat );
118 std::unique_ptr<QgsRasterDataProvider> provider( writer->createOneBandRaster( mInterface->dataType( mBand ), mNbCellsXProvider, mNbCellsYProvider, mExtent, mCrs ) );
119 if ( !provider )
120 throw QgsProcessingException( QObject::tr( "Could not create raster output: %1" ).arg( outputFile ) );
121 if ( !provider->isValid() )
122 throw QgsProcessingException( QObject::tr( "Could not create raster output %1: %2" ).arg( outputFile, provider->error().message( QgsErrorMessage::Text ) ) );
123
124 //prepare output provider
125 QgsRasterDataProvider *destinationRasterProvider;
126 destinationRasterProvider = provider.get();
127 destinationRasterProvider->setEditable( true );
128
131 const int nbBlocksWidth = static_cast<int>( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
132 const int nbBlocksHeight = static_cast<int>( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
133 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
134
135 QgsRasterIterator iter( mInterface.get() );
136 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
137 int iterLeft = 0;
138 int iterTop = 0;
139 int iterCols = 0;
140 int iterRows = 0;
141 std::unique_ptr<QgsRasterBlock> filledRasterBlock;
142 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, filledRasterBlock, iterLeft, iterTop ) )
143 {
144 if ( feedback )
145 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
146
147 if ( feedback && feedback->isCanceled() )
148 break;
149
150 if ( !filledRasterBlock->hasNoDataValue() )
151 {
152 if ( !destinationRasterProvider->writeBlock( filledRasterBlock.get(), mBand, iterLeft, iterTop ) )
153 {
154 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( destinationRasterProvider->error().summary() ) );
155 }
156 continue;
157 }
158
159 for ( int row = 0; row < iterRows; row++ )
160 {
161 if ( feedback && feedback->isCanceled() )
162 break;
163 for ( int column = 0; column < iterCols; column++ )
164 {
165 if ( filledRasterBlock->isNoData( row, column ) )
166 filledRasterBlock->setValue( row, column, mFillValue );
167 }
168 }
169 if ( !destinationRasterProvider->writeBlock( filledRasterBlock.get(), mBand, iterLeft, iterTop ) )
170 {
171 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( destinationRasterProvider->error().summary() ) );
172 }
173 }
174 destinationRasterProvider->setEditable( false );
175
176 QVariantMap outputs;
177 outputs.insert( QStringLiteral( "OUTPUT" ), outputFile );
178 return outputs;
179}
180
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
virtual QgsError error() const
Gets current status error.
QString summary() const
Short error description, usually the first error in chain, the real error.
Definition qgserror.cpp:129
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:53
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:61
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.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
A raster band parameter for Processing algorithms.
A numeric parameter for processing algorithms.
A raster layer destination parameter, for specifying the destination path for a raster layer created ...
A raster layer parameter for processing algorithms.
Base class for raster data providers.
bool writeBlock(QgsRasterBlock *block, int band, int xOffset=0, int yOffset=0)
Writes pixel data from a raster block into the provider data source.
virtual bool setEditable(bool enabled)
Turns on/off editing mode of the provider.
static QString driverForExtension(const QString &extension)
Returns the GDAL driver name for a specified file extension.
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.