26using namespace Qt::StringLiterals;
34QString QgsRasterStackPositionAlgorithmBase::group()
const
36 return QObject::tr(
"Raster analysis" );
39QString QgsRasterStackPositionAlgorithmBase::groupId()
const
41 return u
"rasteranalysis"_s;
44void QgsRasterStackPositionAlgorithmBase::initAlgorithm(
const QVariantMap & )
54 addParameter( output_nodata_parameter.release() );
58 auto createOptsParam = std::make_unique<QgsProcessingParameterString>( u
"CREATE_OPTIONS"_s, QObject::tr(
"Creation options" ), QVariant(),
false,
true );
59 createOptsParam->setMetadata( QVariantMap( { { u
"widget_wrapper"_s, QVariantMap( { { u
"widget_type"_s, u
"rasteroptions"_s } } ) } } ) );
61 addParameter( createOptsParam.release() );
63 auto creationOptsParam = std::make_unique<QgsProcessingParameterString>( u
"CREATION_OPTIONS"_s, QObject::tr(
"Creation options" ), QVariant(),
false,
true );
64 creationOptsParam->setMetadata( QVariantMap( { { u
"widget_wrapper"_s, QVariantMap( { { u
"widget_type"_s, u
"rasteroptions"_s } } ) } } ) );
66 addParameter( creationOptsParam.release() );
78 QgsRasterLayer *referenceLayer = parameterAsRasterLayer( parameters, u
"REFERENCE_LAYER"_s, context );
79 if ( !referenceLayer )
82 mIgnoreNoData = parameterAsBool( parameters, u
"IGNORE_NODATA"_s, context );
83 mNoDataValue = parameterAsDouble( parameters, u
"OUTPUT_NODATA_VALUE"_s, context );
85 mCrs = referenceLayer->
crs();
88 mLayerWidth = referenceLayer->
width();
89 mLayerHeight = referenceLayer->
height();
90 mExtent = referenceLayer->
extent();
92 const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, u
"INPUT_RASTERS"_s, context );
93 QList<QgsRasterLayer *> rasterLayers;
94 rasterLayers.reserve( layers.count() );
103 QgsRasterAnalysisUtils::RasterLogicInput input;
107 input.interface = input.sourceDataProvider.get();
109 if ( layer->
crs() != mCrs )
111 input.projector = std::make_unique<QgsRasterProjector>();
112 input.projector->setInput( input.sourceDataProvider.get() );
114 input.interface = input.projector.get();
116 mInputs.emplace_back( std::move( input ) );
125 QString creationOptions = parameterAsString( parameters, u
"CREATION_OPTIONS"_s, context ).trimmed();
127 const QString optionsString = parameterAsString( parameters, u
"CREATE_OPTIONS"_s, context );
128 if ( !optionsString.isEmpty() )
129 creationOptions = optionsString;
131 const QString outputFile = parameterAsOutputLayer( parameters, u
"OUTPUT"_s, context );
132 const QString outputFormat = parameterAsOutputRasterFormat( parameters, u
"OUTPUT"_s, context );
134 auto writer = std::make_unique<QgsRasterFileWriter>( outputFile );
135 writer->setOutputProviderKey( u
"gdal"_s );
136 if ( !creationOptions.isEmpty() )
138 writer->setCreationOptions( creationOptions.split(
'|' ) );
140 writer->setOutputFormat( outputFormat );
141 std::unique_ptr<QgsRasterDataProvider> provider( writer->createOneBandRaster(
Qgis::DataType::Int32, mLayerWidth, mLayerHeight, mExtent, mCrs ) );
144 if ( !provider->isValid() )
147 provider->setNoDataValue( 1, mNoDataValue );
148 const qgssize layerSize =
static_cast<qgssize>( mLayerWidth ) *
static_cast<qgssize>( mLayerHeight );
150 provider->setEditable(
true );
153 iter.startRasterRead( 1, mLayerWidth, mLayerHeight, mExtent );
160 const bool hasReportsDuringClose = provider->hasReportsDuringClose();
161 const double maxProgressDuringBlockWriting = hasReportsDuringClose ? 50.0 : 100.0;
163 std::unique_ptr<QgsRasterBlock> outputBlock;
164 while ( iter.readNextRasterPart( 1, iterCols, iterRows, outputBlock, iterLeft, iterTop, &blockExtent ) )
166 std::vector<std::unique_ptr<QgsRasterBlock>> inputBlocks;
167 for (
const QgsRasterAnalysisUtils::RasterLogicInput &i : mInputs )
171 for (
const int band : i.bands )
175 std::unique_ptr<QgsRasterBlock> b( i.interface->block( band, blockExtent, iterCols, iterRows ) );
176 inputBlocks.emplace_back( std::move( b ) );
180 feedback->
setProgress( maxProgressDuringBlockWriting * iter.progress( 1 ) );
181 for (
int row = 0; row < iterRows; row++ )
186 for (
int col = 0; col < iterCols; col++ )
188 bool noDataInStack =
false;
190 if ( !inputBlocks.empty() )
192 const int position = findPosition( inputBlocks, row, col, noDataInStack );
194 if ( position == -1 || ( noDataInStack && !mIgnoreNoData ) )
199 outputBlock->setValue( row, col, mNoDataValue );
203 outputBlock->setValue( row, col, position );
208 outputBlock->setValue( row, col, mNoDataValue );
212 if ( !provider->writeBlock( outputBlock.get(), 1, iterLeft, iterTop ) )
214 throw QgsProcessingException( QObject::tr(
"Could not write raster block: %1" ).arg( provider->error().summary() ) );
217 provider->setEditable(
false );
219 if ( feedback && hasReportsDuringClose )
222 if ( !provider->closeWithProgress( scaledFeedback.get() ) )
231 outputs.insert( u
"EXTENT"_s, mExtent.toString() );
232 outputs.insert( u
"CRS_AUTHID"_s, mCrs.authid() );
233 outputs.insert( u
"WIDTH_IN_PIXELS"_s, mLayerWidth );
234 outputs.insert( u
"HEIGHT_IN_PIXELS"_s, mLayerHeight );
235 outputs.insert( u
"TOTAL_PIXEL_COUNT"_s, layerSize );
236 outputs.insert( u
"OUTPUT"_s, outputFile );
244QString QgsRasterStackLowestPositionAlgorithm::displayName()
const
246 return QObject::tr(
"Lowest position in raster stack" );
249QString QgsRasterStackLowestPositionAlgorithm::name()
const
251 return u
"lowestpositioninrasterstack"_s;
254QStringList QgsRasterStackLowestPositionAlgorithm::tags()
const
256 return QObject::tr(
"cell,lowest,position,pixel,stack" ).split(
',' );
259QString QgsRasterStackLowestPositionAlgorithm::shortDescription()
const
261 return QObject::tr(
"Evaluates on a cell-by-cell basis the position "
262 "of the raster with the lowest value in a stack of rasters." );
265QString QgsRasterStackLowestPositionAlgorithm::shortHelpString()
const
267 return QObject::tr(
"This algorithm evaluates on a cell-by-cell basis the position "
268 "of the raster with the lowest value in a stack of rasters. Position counts start "
269 "with 1 and range to the total number of input rasters. The order of the input "
270 "rasters is relevant for the algorithm. If multiple rasters feature the lowest value, "
271 "the first raster will be used for the position value.\n "
272 "If multiband rasters are used in the data raster stack, the algorithm will always "
273 "perform the analysis on the first band of the rasters - use GDAL to use other bands in the analysis. "
274 "Any NoData cells in the raster layer stack will result in a NoData cell "
275 "in the output raster unless the \"ignore NoData\" parameter is checked. "
276 "The output NoData value can be set manually. The output rasters extent and resolution "
277 "is defined by a reference raster layer and is always of int32 type." );
280QgsRasterStackLowestPositionAlgorithm *QgsRasterStackLowestPositionAlgorithm::createInstance()
const
282 return new QgsRasterStackLowestPositionAlgorithm();
285int QgsRasterStackLowestPositionAlgorithm::findPosition( std::vector<std::unique_ptr<QgsRasterBlock>> &inputBlocks,
int &row,
int &col,
bool &noDataInRasterBlockStack )
287 int lowestPosition = 0;
290 const int inputBlocksCount = inputBlocks.size();
291 int currentPosition = 0;
293 double firstValue = mNoDataValue;
294 bool firstValueIsNoData =
true;
296 while ( firstValueIsNoData && ( currentPosition < inputBlocksCount ) )
299 std::unique_ptr<QgsRasterBlock> &firstBlock = inputBlocks.at( currentPosition );
300 firstValue = firstBlock->valueAndNoData( row, col, firstValueIsNoData );
302 if ( !firstBlock->isValid() || firstValueIsNoData )
304 noDataInRasterBlockStack =
true;
309 lowestPosition = currentPosition;
314 if ( noDataCount == inputBlocksCount )
316 noDataInRasterBlockStack =
true;
322 while ( currentPosition < inputBlocksCount )
324 std::unique_ptr<QgsRasterBlock> ¤tBlock = inputBlocks.at( currentPosition );
326 bool currentValueIsNoData =
false;
327 const double currentValue = currentBlock->valueAndNoData( row, col, currentValueIsNoData );
329 if ( !currentBlock->isValid() || currentValueIsNoData )
331 noDataInRasterBlockStack =
true;
336 if ( currentValue < firstValue )
338 firstValue = currentValue;
339 lowestPosition = currentPosition;
346 return ++lowestPosition;
353QString QgsRasterStackHighestPositionAlgorithm::displayName()
const
355 return QObject::tr(
"Highest position in raster stack" );
358QString QgsRasterStackHighestPositionAlgorithm::name()
const
360 return u
"highestpositioninrasterstack"_s;
363QStringList QgsRasterStackHighestPositionAlgorithm::tags()
const
365 return QObject::tr(
"cell,highest,position,pixel,stack" ).split(
',' );
368QString QgsRasterStackHighestPositionAlgorithm::shortDescription()
const
370 return QObject::tr(
"Evaluates on a cell-by-cell basis the position "
371 "of the raster with the highest value in a stack of rasters." );
374QString QgsRasterStackHighestPositionAlgorithm::shortHelpString()
const
376 return QObject::tr(
"This algorithm evaluates on a cell-by-cell basis the position "
377 "of the raster with the highest value in a stack of rasters. Position counts start "
378 "with 1 and range to the total number of input rasters. The order of the input "
379 "rasters is relevant for the algorithm. If multiple rasters feature the highest value, "
380 "the first raster will be used for the position value.\n "
381 "If multiband rasters are used in the data raster stack, the algorithm will always "
382 "perform the analysis on the first band of the rasters - use GDAL to use other bands in the analysis. "
383 "Any NoData cells in the raster layer stack will result in a NoData cell "
384 "in the output raster unless the \"ignore NoData\" parameter is checked. "
385 "The output NoData value can be set manually. The output rasters extent and resolution "
386 "is defined by a reference raster layer and is always of int32 type." );
389QgsRasterStackHighestPositionAlgorithm *QgsRasterStackHighestPositionAlgorithm::createInstance()
const
391 return new QgsRasterStackHighestPositionAlgorithm();
394int QgsRasterStackHighestPositionAlgorithm::findPosition( std::vector<std::unique_ptr<QgsRasterBlock>> &inputBlocks,
int &row,
int &col,
bool &noDataInRasterBlockStack )
396 int highestPosition = 0;
399 const int inputBlocksCount = inputBlocks.size();
400 int currentPosition = 0;
402 double firstValue = mNoDataValue;
403 bool firstValueIsNoData =
true;
405 while ( firstValueIsNoData && ( currentPosition < inputBlocksCount ) )
408 std::unique_ptr<QgsRasterBlock> &firstBlock = inputBlocks.at( currentPosition );
409 firstValue = firstBlock->valueAndNoData( row, col, firstValueIsNoData );
411 if ( !firstBlock->isValid() || firstValueIsNoData )
413 noDataInRasterBlockStack =
true;
418 highestPosition = currentPosition;
424 if ( noDataCount == inputBlocksCount )
426 noDataInRasterBlockStack =
true;
432 while ( currentPosition < inputBlocksCount )
434 std::unique_ptr<QgsRasterBlock> ¤tBlock = inputBlocks.at( currentPosition );
436 bool currentValueIsNoData =
false;
437 const double currentValue = currentBlock->valueAndNoData( row, col, currentValueIsNoData );
439 if ( !currentBlock->isValid() || currentValueIsNoData )
441 noDataInRasterBlockStack =
true;
446 if ( currentValue > firstValue )
448 firstValue = currentValue;
449 highestPosition = currentPosition;
456 return ++highestPosition;
@ Int32
Thirty two bit signed integer (qint32).
@ 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.
@ Double
Double/float values.
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...
Base class for all map layer types.
virtual QgsRectangle extent() const
Returns the extent of the layer.
QgsCoordinateReferenceSystem crs
Contains information about the context in which a processing algorithm is executed.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
A numeric output for processing algorithms.
A string output for processing algorithms.
A boolean parameter for processing algorithms.
A parameter for processing algorithms which accepts multiple map layers.
A raster layer destination parameter, for specifying the destination path for a raster layer created ...
A raster layer parameter for processing algorithms.
QgsRasterDataProvider * clone() const override=0
Clone itself, create deep copy.
virtual bool sourceHasNoDataValue(int bandNo) const
Returns true if source band has no data value.
Iterator for sequentially processing raster cells.
Represents a raster layer.
int height() const
Returns the height of the (unclipped) raster.
double rasterUnitsPerPixelX() const
Returns the number of raster units per each raster pixel in X axis.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
double rasterUnitsPerPixelY() const
Returns the number of raster units per each raster pixel in Y axis.
int width() const
Returns the width of the (unclipped) raster.
A rectangle specified with double values.
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...