24using namespace Qt::StringLiterals;
28QString QgsRoundRasterValuesAlgorithm::name()
const
30 return u
"roundrastervalues"_s;
33QString QgsRoundRasterValuesAlgorithm::displayName()
const
35 return QObject::tr(
"Round raster" );
38QStringList QgsRoundRasterValuesAlgorithm::tags()
const
40 return QObject::tr(
"data,cells,round,truncate" ).split(
',' );
43QString QgsRoundRasterValuesAlgorithm::group()
const
45 return QObject::tr(
"Raster analysis" );
48QString QgsRoundRasterValuesAlgorithm::groupId()
const
50 return u
"rasteranalysis"_s;
53void QgsRoundRasterValuesAlgorithm::initAlgorithm(
const QVariantMap & )
58 new QgsProcessingParameterEnum( u
"ROUNDING_DIRECTION"_s, QObject::tr(
"Rounding direction" ), QStringList() << QObject::tr(
"Round up" ) << QObject::tr(
"Round to nearest" ) << QObject::tr(
"Round down" ),
false, 1 )
61 std::unique_ptr<QgsProcessingParameterDefinition> baseParameter
64 addParameter( baseParameter.release() );
68 auto createOptsParam = std::make_unique<QgsProcessingParameterString>( u
"CREATE_OPTIONS"_s, QObject::tr(
"Creation options" ), QVariant(),
false,
true );
69 createOptsParam->setMetadata( QVariantMap( { { u
"widget_wrapper"_s, QVariantMap( { { u
"widget_type"_s, u
"rasteroptions"_s } } ) } } ) );
71 addParameter( createOptsParam.release() );
73 auto creationOptsParam = std::make_unique<QgsProcessingParameterString>( u
"CREATION_OPTIONS"_s, QObject::tr(
"Creation options" ), QVariant(),
false,
true );
74 creationOptsParam->setMetadata( QVariantMap( { { u
"widget_wrapper"_s, QVariantMap( { { u
"widget_type"_s, u
"rasteroptions"_s } } ) } } ) );
76 addParameter( creationOptsParam.release() );
81QString QgsRoundRasterValuesAlgorithm::shortHelpString()
const
84 "This algorithm rounds the cell values of a raster dataset to the specified number of decimals.\n "
85 "Alternatively, a negative number of decimal places may be used to round values to powers of a base n "
86 "(specified in the advanced parameter Base n). For example, with a Base value n of 10 and Decimal places of -1 "
87 "the algorithm rounds cell values to multiples of 10, -2 rounds to multiples of 100, and so on. Arbitrary base values "
88 "may be chosen, the algorithm applies the same multiplicative principle. Rounding cell values to multiples of "
89 "a base n may be used to generalize raster layers.\n"
90 "The algorithm preserves the data type of the input raster. Therefore byte/integer rasters can only be rounded "
91 "to multiples of a base n, otherwise a warning is raised and the raster gets copied as byte/integer raster."
95QString QgsRoundRasterValuesAlgorithm::shortDescription()
const
97 return QObject::tr(
"Rounds the cell values of a raster dataset to a specified number of decimals." );
100QgsRoundRasterValuesAlgorithm *QgsRoundRasterValuesAlgorithm::createInstance()
const
102 return new QgsRoundRasterValuesAlgorithm();
107 Q_UNUSED( feedback );
108 QgsRasterLayer *inputRaster = parameterAsRasterLayer( parameters, u
"INPUT"_s, context );
109 mDecimalPrecision = parameterAsInt( parameters, u
"DECIMAL_PLACES"_s, context );
110 mBaseN = parameterAsInt( parameters, u
"BASE_N"_s, context );
111 mMultipleOfBaseN = pow( mBaseN, abs( mDecimalPrecision ) );
112 mScaleFactor = std::pow( 10.0, mDecimalPrecision );
117 mBand = parameterAsInt( parameters, u
"BAND"_s, context );
118 if ( mBand < 1 || mBand > inputRaster->
bandCount() )
119 throw QgsProcessingException( QObject::tr(
"Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand ).arg( inputRaster->
bandCount() ) );
121 mRoundingDirection = parameterAsEnum( parameters, u
"ROUNDING_DIRECTION"_s, context );
124 mDataType = mInterface->dataType( mBand );
134 if ( mDecimalPrecision > -1 )
135 feedback->
reportError( QObject::tr(
"Input raster is of byte or integer type. The cell values cannot be rounded and will be output using the same data type." ),
false );
143 mExtent = inputRaster->
extent();
144 mLayerWidth = inputRaster->
width();
145 mLayerHeight = inputRaster->
height();
146 mCrs = inputRaster->
crs();
147 mNbCellsXProvider = mInterface->xSize();
148 mNbCellsYProvider = mInterface->ySize();
155 QString creationOptions = parameterAsString( parameters, u
"CREATION_OPTIONS"_s, context ).trimmed();
157 const QString optionsString = parameterAsString( parameters, u
"CREATE_OPTIONS"_s, context );
158 if ( !optionsString.isEmpty() )
159 creationOptions = optionsString;
161 const QString outputFile = parameterAsOutputLayer( parameters, u
"OUTPUT"_s, context );
162 const QString outputFormat = parameterAsOutputRasterFormat( parameters, u
"OUTPUT"_s, context );
163 auto writer = std::make_unique<QgsRasterFileWriter>( outputFile );
164 writer->setOutputProviderKey( u
"gdal"_s );
165 if ( !creationOptions.isEmpty() )
167 writer->setCreationOptions( creationOptions.split(
'|' ) );
169 writer->setOutputFormat( outputFormat );
170 std::unique_ptr<QgsRasterDataProvider> provider( writer->createOneBandRaster( mInterface->dataType( mBand ), mNbCellsXProvider, mNbCellsYProvider, mExtent, mCrs ) );
173 if ( !provider->isValid() )
178 destinationRasterProvider = provider.get();
180 destinationRasterProvider->
setNoDataValue( 1, mInputNoDataValue );
182 const bool hasReportsDuringClose = provider->hasReportsDuringClose();
183 const double maxProgressDuringBlockWriting = hasReportsDuringClose ? 50.0 : 100.0;
186 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
191 std::unique_ptr<QgsRasterBlock> analysisRasterBlock;
192 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, analysisRasterBlock, iterLeft, iterTop ) )
195 feedback->
setProgress( maxProgressDuringBlockWriting * iter.progress( mBand ) );
196 if ( mIsInteger && mDecimalPrecision > -1 )
199 analysisRasterBlock->setNoDataValue( mInputNoDataValue );
200 if ( !destinationRasterProvider->
writeBlock( analysisRasterBlock.get(), mBand, iterLeft, iterTop ) )
207 for (
int row = 0; row < iterRows; row++ )
211 for (
int column = 0; column < iterCols; column++ )
213 bool isNoData =
false;
214 const double val = analysisRasterBlock->valueAndNoData( row, column, isNoData );
217 analysisRasterBlock->setValue( row, column, mInputNoDataValue );
221 double roundedVal = mInputNoDataValue;
222 if ( mRoundingDirection == 0 && mDecimalPrecision < 0 )
224 roundedVal = roundUpBaseN( val );
226 else if ( mRoundingDirection == 0 && mDecimalPrecision > -1 )
228 const double m = ( val < 0.0 ) ? -1.0 : 1.0;
229 roundedVal = roundUp( val, m );
231 else if ( mRoundingDirection == 1 && mDecimalPrecision < 0 )
233 roundedVal = roundNearestBaseN( val );
235 else if ( mRoundingDirection == 1 && mDecimalPrecision > -1 )
237 const double m = ( val < 0.0 ) ? -1.0 : 1.0;
238 roundedVal = roundNearest( val, m );
240 else if ( mRoundingDirection == 2 && mDecimalPrecision < 0 )
242 roundedVal = roundDownBaseN( val );
246 const double m = ( val < 0.0 ) ? -1.0 : 1.0;
247 roundedVal = roundDown( val, m );
250 analysisRasterBlock->setValue( row, column, roundedVal );
254 if ( !destinationRasterProvider->
writeBlock( analysisRasterBlock.get(), mBand, iterLeft, iterTop ) )
262 if ( feedback && hasReportsDuringClose )
265 if ( !provider->closeWithProgress( scaledFeedback.get() ) )
274 outputs.insert( u
"OUTPUT"_s, outputFile );
278double QgsRoundRasterValuesAlgorithm::roundNearest(
double value,
double m )
280 return ( std::round( value * m * mScaleFactor ) / mScaleFactor ) * m;
283double QgsRoundRasterValuesAlgorithm::roundUp(
double value,
double m )
285 return ( std::ceil( value * m * mScaleFactor ) / mScaleFactor ) * m;
288double QgsRoundRasterValuesAlgorithm::roundDown(
double value,
double m )
290 return ( std::floor( value * m * mScaleFactor ) / mScaleFactor ) * m;
293double QgsRoundRasterValuesAlgorithm::roundNearestBaseN(
double value )
295 return static_cast<double>( mMultipleOfBaseN * round( value / mMultipleOfBaseN ) );
298double QgsRoundRasterValuesAlgorithm::roundUpBaseN(
double value )
300 return static_cast<double>( mMultipleOfBaseN * ceil( value / mMultipleOfBaseN ) );
303double QgsRoundRasterValuesAlgorithm::roundDownBaseN(
double value )
305 return static_cast<double>( mMultipleOfBaseN * floor( value / mMultipleOfBaseN ) );
@ Int16
Sixteen bit signed integer (qint16).
@ UInt16
Sixteen bit unsigned integer (quint16).
@ Byte
Eight bit unsigned integer (quint8).
@ Int32
Thirty two bit signed integer (qint32).
@ UInt32
Thirty two bit unsigned integer (quint32).
@ Hidden
Parameter is hidden and should not be shown to users.
@ 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.
bool isCanceled() const
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
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 QgsRectangle extent() const
Returns the extent of the layer.
QgsCoordinateReferenceSystem crs
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.
An enum based parameter for processing algorithms, allowing for selection from predefined values.
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.
QgsRasterDataProvider * clone() const override=0
Clone itself, create deep copy.
virtual bool setNoDataValue(int bandNo, double noDataValue)
Set no data value on created dataset.
virtual double sourceNoDataValue(int bandNo) const
Value representing no data value.
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.
Iterator for sequentially processing raster cells.
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.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
int width() const
Returns the width of the (unclipped) raster.