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();
154 QGS_MARK_ALGORITHM_SOURCE
157 QString creationOptions = parameterAsString( parameters, u
"CREATION_OPTIONS"_s, context ).trimmed();
159 const QString optionsString = parameterAsString( parameters, u
"CREATE_OPTIONS"_s, context );
160 if ( !optionsString.isEmpty() )
161 creationOptions = optionsString;
163 const QString outputFile = parameterAsOutputLayer( parameters, u
"OUTPUT"_s, context );
164 const QString outputFormat = parameterAsOutputRasterFormat( parameters, u
"OUTPUT"_s, context );
165 auto writer = std::make_unique<QgsRasterFileWriter>( outputFile );
166 writer->setOutputProviderKey( u
"gdal"_s );
167 if ( !creationOptions.isEmpty() )
169 writer->setCreationOptions( creationOptions.split(
'|' ) );
171 writer->setOutputFormat( outputFormat );
172 std::unique_ptr<QgsRasterDataProvider> provider( writer->createOneBandRaster( mInterface->dataType( mBand ), mNbCellsXProvider, mNbCellsYProvider, mExtent, mCrs ) );
175 if ( !provider->isValid() )
180 destinationRasterProvider = provider.get();
182 destinationRasterProvider->
setNoDataValue( 1, mInputNoDataValue );
184 const bool hasReportsDuringClose = provider->hasReportsDuringClose();
185 const double maxProgressDuringBlockWriting = hasReportsDuringClose ? 50.0 : 100.0;
188 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
193 std::unique_ptr<QgsRasterBlock> analysisRasterBlock;
194 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, analysisRasterBlock, iterLeft, iterTop ) )
197 feedback->
setProgress( maxProgressDuringBlockWriting * iter.progress( mBand ) );
198 if ( mIsInteger && mDecimalPrecision > -1 )
201 analysisRasterBlock->setNoDataValue( mInputNoDataValue );
202 if ( !destinationRasterProvider->
writeBlock( analysisRasterBlock.get(), mBand, iterLeft, iterTop ) )
209 for (
int row = 0; row < iterRows; row++ )
213 for (
int column = 0; column < iterCols; column++ )
215 bool isNoData =
false;
216 const double val = analysisRasterBlock->valueAndNoData( row, column, isNoData );
219 analysisRasterBlock->setValue( row, column, mInputNoDataValue );
223 double roundedVal = mInputNoDataValue;
224 if ( mRoundingDirection == 0 && mDecimalPrecision < 0 )
226 roundedVal = roundUpBaseN( val );
228 else if ( mRoundingDirection == 0 && mDecimalPrecision > -1 )
230 const double m = ( val < 0.0 ) ? -1.0 : 1.0;
231 roundedVal = roundUp( val, m );
233 else if ( mRoundingDirection == 1 && mDecimalPrecision < 0 )
235 roundedVal = roundNearestBaseN( val );
237 else if ( mRoundingDirection == 1 && mDecimalPrecision > -1 )
239 const double m = ( val < 0.0 ) ? -1.0 : 1.0;
240 roundedVal = roundNearest( val, m );
242 else if ( mRoundingDirection == 2 && mDecimalPrecision < 0 )
244 roundedVal = roundDownBaseN( val );
248 const double m = ( val < 0.0 ) ? -1.0 : 1.0;
249 roundedVal = roundDown( val, m );
252 analysisRasterBlock->setValue( row, column, roundedVal );
256 if ( !destinationRasterProvider->
writeBlock( analysisRasterBlock.get(), mBand, iterLeft, iterTop ) )
264 if ( feedback && hasReportsDuringClose )
267 if ( !provider->closeWithProgress( scaledFeedback.get() ) )
276 outputs.insert( u
"OUTPUT"_s, outputFile );
280double QgsRoundRasterValuesAlgorithm::roundNearest(
double value,
double m )
282 return ( std::round( value * m * mScaleFactor ) / mScaleFactor ) * m;
285double QgsRoundRasterValuesAlgorithm::roundUp(
double value,
double m )
287 return ( std::ceil( value * m * mScaleFactor ) / mScaleFactor ) * m;
290double QgsRoundRasterValuesAlgorithm::roundDown(
double value,
double m )
292 return ( std::floor( value * m * mScaleFactor ) / mScaleFactor ) * m;
295double QgsRoundRasterValuesAlgorithm::roundNearestBaseN(
double value )
297 return static_cast<double>( mMultipleOfBaseN * round( value / mMultipleOfBaseN ) );
300double QgsRoundRasterValuesAlgorithm::roundUpBaseN(
double value )
302 return static_cast<double>( mMultipleOfBaseN * ceil( value / mMultipleOfBaseN ) );
305double QgsRoundRasterValuesAlgorithm::roundDownBaseN(
double value )
307 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 Q_INVOKABLE 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.