23 QString QgsRoundRasterValuesAlgorithm::name()
const
25 return QStringLiteral(
"roundrastervalues" );
28 QString QgsRoundRasterValuesAlgorithm::displayName()
const
30 return QObject::tr(
"Round raster" );
33 QStringList QgsRoundRasterValuesAlgorithm::tags()
const
35 return QObject::tr(
"data,cells,round,truncate" ).split(
',' );
38 QString QgsRoundRasterValuesAlgorithm::group()
const
40 return QObject::tr(
"Raster analysis" );
43 QString QgsRoundRasterValuesAlgorithm::groupId()
const
45 return QStringLiteral(
"rasteranalysis" );
48 void QgsRoundRasterValuesAlgorithm::initAlgorithm(
const QVariantMap & )
51 addParameter(
new QgsProcessingParameterBand( QStringLiteral(
"BAND" ), QObject::tr(
"Band number" ), 1, QStringLiteral(
"INPUT" ) ) );
52 addParameter(
new QgsProcessingParameterEnum( QStringLiteral(
"ROUNDING_DIRECTION" ), QObject::tr(
"Rounding direction" ), QStringList() << QObject::tr(
"Round up" ) << QObject::tr(
"Round to nearest" ) << QObject::tr(
"Round down" ),
false, 1 ) );
55 std::unique_ptr< QgsProcessingParameterDefinition > baseParameter = std::make_unique< QgsProcessingParameterNumber >( QStringLiteral(
"BASE_N" ), QObject::tr(
"Base n for rounding to multiples of n" ),
QgsProcessingParameterNumber::Integer, 10,
true, 1 );
57 addParameter( baseParameter.release() );
60 QString QgsRoundRasterValuesAlgorithm::shortHelpString()
const
62 return QObject::tr(
"This algorithm rounds the cell values of a raster dataset according to the specified number of decimals.\n "
63 "Alternatively, a negative number of decimal places may be used to round values to powers of a base n "
64 "(specified in the advanced parameter Base n). For example, with a Base value n of 10 and Decimal places of -1 "
65 "the algorithm rounds cell values to multiples of 10, -2 rounds to multiples of 100, and so on. Arbitrary base values "
66 "may be chosen, the algorithm applies the same multiplicative principle. Rounding cell values to multiples of "
67 "a base n may be used to generalize raster layers.\n"
68 "The algorithm preserves the data type of the input raster. Therefore byte/integer rasters can only be rounded "
69 "to multiples of a base n, otherwise a warning is raised and the raster gets copied as byte/integer raster" );
72 QgsRoundRasterValuesAlgorithm *QgsRoundRasterValuesAlgorithm::createInstance()
const
74 return new QgsRoundRasterValuesAlgorithm();
80 QgsRasterLayer *inputRaster = parameterAsRasterLayer( parameters, QStringLiteral(
"INPUT" ), context );
81 mDecimalPrecision = parameterAsInt( parameters, QStringLiteral(
"DECIMAL_PLACES" ), context );
82 mBaseN = parameterAsInt( parameters, QStringLiteral(
"BASE_N" ), context );
83 mMultipleOfBaseN = pow( mBaseN, abs( mDecimalPrecision ) );
84 mScaleFactor = std::pow( 10.0, mDecimalPrecision );
89 mBand = parameterAsInt( parameters, QStringLiteral(
"BAND" ), context );
90 if ( mBand < 1 || mBand > inputRaster->
bandCount() )
91 throw QgsProcessingException( QObject::tr(
"Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand ).arg( inputRaster->
bandCount() ) );
93 mRoundingDirection = parameterAsEnum( parameters, QStringLiteral(
"ROUNDING_DIRECTION" ), context );
96 mDataType = mInterface->dataType( mBand );
106 if ( mDecimalPrecision > -1 )
107 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 );
115 mExtent = inputRaster->
extent();
116 mLayerWidth = inputRaster->
width();
117 mLayerHeight = inputRaster->
height();
118 mCrs = inputRaster->
crs();
119 mNbCellsXProvider = mInterface->xSize();
120 mNbCellsYProvider = mInterface->ySize();
127 const QString outputFile = parameterAsOutputLayer( parameters, QStringLiteral(
"OUTPUT" ), context );
128 const QFileInfo fi( outputFile );
130 std::unique_ptr< QgsRasterFileWriter > writer = std::make_unique< QgsRasterFileWriter >( outputFile );
131 writer->setOutputProviderKey( QStringLiteral(
"gdal" ) );
132 writer->setOutputFormat( outputFormat );
133 std::unique_ptr<QgsRasterDataProvider > provider( writer->createOneBandRaster( mInterface->dataType( mBand ), mNbCellsXProvider, mNbCellsYProvider, mExtent, mCrs ) );
136 if ( !provider->isValid() )
141 destinationRasterProvider = provider.get();
143 destinationRasterProvider->
setNoDataValue( 1, mInputNoDataValue );
147 const int nbBlocksWidth =
static_cast< int >( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
148 const int nbBlocksHeight =
static_cast< int >( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
149 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
152 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
157 std::unique_ptr< QgsRasterBlock > analysisRasterBlock;
158 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, analysisRasterBlock, iterLeft, iterTop ) )
161 feedback->
setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
162 if ( mIsInteger && mDecimalPrecision > -1 )
165 analysisRasterBlock->setNoDataValue( mInputNoDataValue );
166 destinationRasterProvider->
writeBlock( analysisRasterBlock.get(), mBand, iterLeft, iterTop );
170 for (
int row = 0; row < iterRows; row++ )
174 for (
int column = 0; column < iterCols; column++ )
176 bool isNoData =
false;
177 const double val = analysisRasterBlock->valueAndNoData( row, column, isNoData );
180 analysisRasterBlock->setValue( row, column, mInputNoDataValue );
184 double roundedVal = mInputNoDataValue;
185 if ( mRoundingDirection == 0 && mDecimalPrecision < 0 )
187 roundedVal = roundUpBaseN( val );
189 else if ( mRoundingDirection == 0 && mDecimalPrecision > -1 )
191 const double m = ( val < 0.0 ) ? -1.0 : 1.0;
192 roundedVal = roundUp( val, m );
194 else if ( mRoundingDirection == 1 && mDecimalPrecision < 0 )
196 roundedVal = roundNearestBaseN( val );
198 else if ( mRoundingDirection == 1 && mDecimalPrecision > -1 )
200 const double m = ( val < 0.0 ) ? -1.0 : 1.0;
201 roundedVal = roundNearest( val, m );
203 else if ( mRoundingDirection == 2 && mDecimalPrecision < 0 )
205 roundedVal = roundDownBaseN( val );
209 const double m = ( val < 0.0 ) ? -1.0 : 1.0;
210 roundedVal = roundDown( val, m );
213 analysisRasterBlock->setValue( row, column, roundedVal );
217 destinationRasterProvider->
writeBlock( analysisRasterBlock.get(), mBand, iterLeft, iterTop );
223 outputs.insert( QStringLiteral(
"OUTPUT" ), outputFile );
227 double QgsRoundRasterValuesAlgorithm::roundNearest(
double value,
double m )
229 return ( std::round( value * m * mScaleFactor ) / mScaleFactor ) * m;
232 double QgsRoundRasterValuesAlgorithm::roundUp(
double value,
double m )
234 return ( std::ceil( value * m * mScaleFactor ) / mScaleFactor ) * m;
237 double QgsRoundRasterValuesAlgorithm::roundDown(
double value,
double m )
239 return ( std::floor( value * m * mScaleFactor ) / mScaleFactor ) * m;
243 double QgsRoundRasterValuesAlgorithm::roundNearestBaseN(
double value )
245 return static_cast<double>( mMultipleOfBaseN * round( value / mMultipleOfBaseN ) );
248 double QgsRoundRasterValuesAlgorithm::roundUpBaseN(
double value )
250 return static_cast<double>( mMultipleOfBaseN * ceil( value / mMultipleOfBaseN ) );
253 double QgsRoundRasterValuesAlgorithm::roundDownBaseN(
double value )
255 return static_cast<double>( mMultipleOfBaseN * floor( value / mMultipleOfBaseN ) );