QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
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
20#include "qgsrasterfilewriter.h"
21
23
24QString QgsFillNoDataAlgorithm::name() const
25{
26 return QStringLiteral( "fillnodata" );
27}
28
29QString QgsFillNoDataAlgorithm::displayName() const
30{
31 return QObject::tr( "Fill NoData cells" );
32}
33
34QStringList QgsFillNoDataAlgorithm::tags() const
35{
36 return QObject::tr( "data,cells,fill,set" ).split( ',' );
37}
38
39QString QgsFillNoDataAlgorithm::group() const
40{
41 return QObject::tr( "Raster tools" );
42}
43
44QString QgsFillNoDataAlgorithm::groupId() const
45{
46 return QStringLiteral( "rastertools" );
47}
48
49void QgsFillNoDataAlgorithm::initAlgorithm( const QVariantMap & )
50{
51 addParameter( new QgsProcessingParameterRasterLayer( QStringLiteral( "INPUT" ), QStringLiteral( "Raster input" ) ) );
52 addParameter( new QgsProcessingParameterBand( QStringLiteral( "BAND" ), QObject::tr( "Band Number" ), 1, QStringLiteral( "INPUT" ) ) );
53 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FILL_VALUE" ), QObject::tr( "Fill value" ), Qgis::ProcessingNumberParameterType::Double, 1, false ) );
54
55 // backwards compatibility parameter
56 // TODO QGIS 4: remove parameter and related logic
57 auto createOptsParam = std::make_unique<QgsProcessingParameterString>( QStringLiteral( "CREATE_OPTIONS" ), QObject::tr( "Creation options" ), QVariant(), false, true );
58 createOptsParam->setMetadata( QVariantMap( { { QStringLiteral( "widget_wrapper" ), QVariantMap( { { QStringLiteral( "widget_type" ), QStringLiteral( "rasteroptions" ) } } ) } } ) );
59 createOptsParam->setFlags( createOptsParam->flags() | Qgis::ProcessingParameterFlag::Hidden );
60 addParameter( createOptsParam.release() );
61
62 auto creationOptsParam = std::make_unique<QgsProcessingParameterString>( QStringLiteral( "CREATION_OPTIONS" ), QObject::tr( "Creation options" ), QVariant(), false, true );
63 creationOptsParam->setMetadata( QVariantMap( { { QStringLiteral( "widget_wrapper" ), QVariantMap( { { QStringLiteral( "widget_type" ), QStringLiteral( "rasteroptions" ) } } ) } } ) );
64 creationOptsParam->setFlags( creationOptsParam->flags() | Qgis::ProcessingParameterFlag::Advanced );
65 addParameter( creationOptsParam.release() );
66
67 addParameter( new QgsProcessingParameterRasterDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Output raster" ) ) );
68}
69
70QString QgsFillNoDataAlgorithm::shortHelpString() const
71{
72 return QObject::tr( "This algorithm resets the NoData values in the input raster "
73 "to a chosen value, resulting in a raster dataset with no NoData pixels. "
74 "This value can be set by the user using the Fill value parameter. "
75 "The algorithm respects the input raster data type (eg. a floating point fill value will be truncated "
76 "when applied to an integer raster)." );
77}
78
79QString QgsFillNoDataAlgorithm::shortDescription() const
80{
81 return QObject::tr( "Generates a raster dataset with the NoData values in the input raster filled with a given value." );
82}
83
84QgsFillNoDataAlgorithm *QgsFillNoDataAlgorithm::createInstance() const
85{
86 return new QgsFillNoDataAlgorithm();
87}
88
89bool QgsFillNoDataAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
90{
91 Q_UNUSED( feedback );
92 mInputRaster = parameterAsRasterLayer( parameters, QStringLiteral( "INPUT" ), context );
93 mFillValue = parameterAsDouble( parameters, QStringLiteral( "FILL_VALUE" ), context );
94
95 if ( !mInputRaster )
96 throw QgsProcessingException( invalidRasterError( parameters, QStringLiteral( "INPUT" ) ) );
97
98 mBand = parameterAsInt( parameters, QStringLiteral( "BAND" ), context );
99 if ( mBand < 1 || mBand > mInputRaster->bandCount() )
100 throw QgsProcessingException( QObject::tr( "Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand ).arg( mInputRaster->bandCount() ) );
101
102 mInterface.reset( mInputRaster->dataProvider()->clone() );
103 mInputNoDataValue = mInputRaster->dataProvider()->sourceNoDataValue( mBand );
104 mExtent = mInputRaster->extent();
105 mLayerWidth = mInputRaster->width();
106 mLayerHeight = mInputRaster->height();
107 mCrs = mInputRaster->crs();
108 mNbCellsXProvider = mInterface->xSize();
109 mNbCellsYProvider = mInterface->ySize();
110 return true;
111}
112
113QVariantMap QgsFillNoDataAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
114{
115 //test if input dataset has NoData
116 if ( !mInputRaster->dataProvider()->sourceHasNoDataValue( mBand ) )
117 feedback->reportError( QObject::tr( "Input raster has no NoData values. There exist no NoData cells to fill." ), false );
118
119 //prepare output dataset
120 QString creationOptions = parameterAsString( parameters, QStringLiteral( "CREATION_OPTIONS" ), context ).trimmed();
121 // handle backwards compatibility parameter CREATE_OPTIONS
122 const QString optionsString = parameterAsString( parameters, QStringLiteral( "CREATE_OPTIONS" ), context );
123 if ( !optionsString.isEmpty() )
124 creationOptions = optionsString;
125
126 const QString outputFile = parameterAsOutputLayer( parameters, QStringLiteral( "OUTPUT" ), context );
127 const QFileInfo fi( outputFile );
128 const QString outputFormat = QgsRasterFileWriter::driverForExtension( fi.suffix() );
129 auto writer = std::make_unique<QgsRasterFileWriter>( outputFile );
130 writer->setOutputProviderKey( QStringLiteral( "gdal" ) );
131 if ( !creationOptions.isEmpty() )
132 {
133 writer->setCreationOptions( creationOptions.split( '|' ) );
134 }
135 writer->setOutputFormat( outputFormat );
136 std::unique_ptr<QgsRasterDataProvider> provider( writer->createOneBandRaster( mInterface->dataType( mBand ), mNbCellsXProvider, mNbCellsYProvider, mExtent, mCrs ) );
137 if ( !provider )
138 throw QgsProcessingException( QObject::tr( "Could not create raster output: %1" ).arg( outputFile ) );
139 if ( !provider->isValid() )
140 throw QgsProcessingException( QObject::tr( "Could not create raster output %1: %2" ).arg( outputFile, provider->error().message( QgsErrorMessage::Text ) ) );
141
142 //prepare output provider
143 QgsRasterDataProvider *destinationRasterProvider;
144 destinationRasterProvider = provider.get();
145 destinationRasterProvider->setEditable( true );
146
149 const int nbBlocksWidth = static_cast<int>( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
150 const int nbBlocksHeight = static_cast<int>( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
151 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
152
153 QgsRasterIterator iter( mInterface.get() );
154 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
155 int iterLeft = 0;
156 int iterTop = 0;
157 int iterCols = 0;
158 int iterRows = 0;
159 std::unique_ptr<QgsRasterBlock> filledRasterBlock;
160 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, filledRasterBlock, iterLeft, iterTop ) )
161 {
162 if ( feedback )
163 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
164
165 if ( feedback && feedback->isCanceled() )
166 break;
167
168 if ( !filledRasterBlock->hasNoDataValue() )
169 {
170 if ( !destinationRasterProvider->writeBlock( filledRasterBlock.get(), mBand, iterLeft, iterTop ) )
171 {
172 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( destinationRasterProvider->error().summary() ) );
173 }
174 continue;
175 }
176
177 for ( int row = 0; row < iterRows; row++ )
178 {
179 if ( feedback && feedback->isCanceled() )
180 break;
181 for ( int column = 0; column < iterCols; column++ )
182 {
183 if ( filledRasterBlock->isNoData( row, column ) )
184 filledRasterBlock->setValue( row, column, mFillValue );
185 }
186 }
187 if ( !destinationRasterProvider->writeBlock( filledRasterBlock.get(), mBand, iterLeft, iterTop ) )
188 {
189 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( destinationRasterProvider->error().summary() ) );
190 }
191 }
192 destinationRasterProvider->setEditable( false );
193
194 QVariantMap outputs;
195 outputs.insert( QStringLiteral( "OUTPUT" ), outputFile );
196 return outputs;
197}
198
@ Hidden
Parameter is hidden and should not be shown to users.
Definition qgis.h:3764
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
Definition qgis.h:3763
@ Double
Double/float values.
Definition qgis.h:3804
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:130
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.