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