29 QString QgsRasterStackPositionAlgorithmBase::group()
const
31 return QObject::tr(
"Raster analysis" );
34 QString QgsRasterStackPositionAlgorithmBase::groupId()
const
36 return QStringLiteral(
"rasteranalysis" );
39 void QgsRasterStackPositionAlgorithmBase::initAlgorithm(
const QVariantMap & )
48 std::unique_ptr< QgsProcessingParameterNumber > output_nodata_parameter = std::make_unique< QgsProcessingParameterNumber >( QStringLiteral(
"OUTPUT_NODATA_VALUE" ), QObject::tr(
"Output NoData value" ),
QgsProcessingParameterNumber::Double, -9999,
true );
50 addParameter( output_nodata_parameter.release() );
53 QObject::tr(
"Output layer" ) ) );
63 QgsRasterLayer *referenceLayer = parameterAsRasterLayer( parameters, QStringLiteral(
"REFERENCE_LAYER" ), context );
64 if ( !referenceLayer )
67 mIgnoreNoData = parameterAsBool( parameters, QStringLiteral(
"IGNORE_NODATA" ), context );
68 mNoDataValue = parameterAsDouble( parameters, QStringLiteral(
"OUTPUT_NODATA_VALUE" ), context );
70 mCrs = referenceLayer->
crs();
73 mLayerWidth = referenceLayer->
width();
74 mLayerHeight = referenceLayer->
height();
75 mExtent = referenceLayer->
extent();
77 const QList< QgsMapLayer * > layers = parameterAsLayerList( parameters, QStringLiteral(
"INPUT_RASTERS" ), context );
78 QList< QgsRasterLayer * > rasterLayers;
79 rasterLayers.reserve( layers.count() );
88 QgsRasterAnalysisUtils::RasterLogicInput input;
92 input.interface = input.sourceDataProvider.get();
94 if ( layer->
crs() != mCrs )
96 input.projector = std::make_unique< QgsRasterProjector >();
97 input.projector->setInput( input.sourceDataProvider.get() );
99 input.interface = input.projector.get();
101 mInputs.emplace_back( std::move( input ) );
110 const QString outputFile = parameterAsOutputLayer( parameters, QStringLiteral(
"OUTPUT" ), context );
111 const QFileInfo fi( outputFile );
114 std::unique_ptr< QgsRasterFileWriter > writer = std::make_unique< QgsRasterFileWriter >( outputFile );
115 writer->setOutputProviderKey( QStringLiteral(
"gdal" ) );
116 writer->setOutputFormat( outputFormat );
117 std::unique_ptr<QgsRasterDataProvider > provider( writer->createOneBandRaster(
Qgis::DataType::Int32, mLayerWidth, mLayerHeight, mExtent, mCrs ) );
120 if ( !provider->isValid() )
123 provider->setNoDataValue( 1, mNoDataValue );
124 const qgssize layerSize =
static_cast< qgssize >( mLayerWidth ) *
static_cast< qgssize >( mLayerHeight );
128 const int nbBlocksWidth =
static_cast< int>( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
129 const int nbBlocksHeight =
static_cast< int >( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
130 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
131 provider->setEditable(
true );
134 iter.startRasterRead( 1, mLayerWidth, mLayerHeight, mExtent );
141 std::unique_ptr< QgsRasterBlock > outputBlock;
142 while ( iter.readNextRasterPart( 1, iterCols, iterRows, outputBlock, iterLeft, iterTop, &blockExtent ) )
144 std::vector< std::unique_ptr< QgsRasterBlock > > inputBlocks;
145 for (
const QgsRasterAnalysisUtils::RasterLogicInput &i : mInputs )
149 for (
const int band : i.bands )
153 std::unique_ptr< QgsRasterBlock > b( i.interface->block( band, blockExtent, iterCols, iterRows ) );
154 inputBlocks.emplace_back( std::move( b ) );
158 feedback->
setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
159 for (
int row = 0; row < iterRows; row++ )
164 for (
int col = 0; col < iterCols; col++ )
166 bool noDataInStack =
false;
168 if ( !inputBlocks.empty() )
170 const int position = findPosition( inputBlocks, row, col, noDataInStack );
172 if ( position == -1 || ( noDataInStack && !mIgnoreNoData ) )
177 outputBlock->setValue( row, col, mNoDataValue );
181 outputBlock->setValue( row, col, position );
186 outputBlock->setValue( row, col, mNoDataValue );
190 provider->writeBlock( outputBlock.get(), 1, iterLeft, iterTop );
192 provider->setEditable(
false );
195 outputs.insert( QStringLiteral(
"EXTENT" ), mExtent.toString() );
196 outputs.insert( QStringLiteral(
"CRS_AUTHID" ), mCrs.authid() );
197 outputs.insert( QStringLiteral(
"WIDTH_IN_PIXELS" ), mLayerWidth );
198 outputs.insert( QStringLiteral(
"HEIGHT_IN_PIXELS" ), mLayerHeight );
199 outputs.insert( QStringLiteral(
"TOTAL_PIXEL_COUNT" ), layerSize );
200 outputs.insert( QStringLiteral(
"OUTPUT" ), outputFile );
208 QString QgsRasterStackLowestPositionAlgorithm::displayName()
const
210 return QObject::tr(
"Lowest position in raster stack" );
213 QString QgsRasterStackLowestPositionAlgorithm::name()
const
215 return QStringLiteral(
"lowestpositioninrasterstack" );
218 QStringList QgsRasterStackLowestPositionAlgorithm::tags()
const
220 return QObject::tr(
"cell,lowest,position,pixel,stack" ).split(
',' );
223 QString QgsRasterStackLowestPositionAlgorithm::shortHelpString()
const
225 return QObject::tr(
"The lowest position algorithm evaluates on a cell-by-cell basis the position "
226 "of the raster with the lowest value in a stack of rasters. Position counts start "
227 "with 1 and range to the total number of input rasters. The order of the input "
228 "rasters is relevant for the algorithm. If multiple rasters feature the lowest value, "
229 "the first raster will be used for the position value.\n "
230 "If multiband rasters are used in the data raster stack, the algorithm will always "
231 "perform the analysis on the first band of the rasters - use GDAL to use other bands in the analysis. "
232 "Any NoData cells in the raster layer stack will result in a NoData cell "
233 "in the output raster unless the \"ignore NoData\" parameter is checked. "
234 "The output NoData value can be set manually. The output rasters extent and resolution "
235 "is defined by a reference raster layer and is always of int32 type." );
238 QgsRasterStackLowestPositionAlgorithm *QgsRasterStackLowestPositionAlgorithm::createInstance()
const
240 return new QgsRasterStackLowestPositionAlgorithm();
243 int QgsRasterStackLowestPositionAlgorithm::findPosition( std::vector< std::unique_ptr<QgsRasterBlock> > &inputBlocks,
int &row,
int &col,
bool &noDataInRasterBlockStack )
245 int lowestPosition = 0;
248 const int inputBlocksCount = inputBlocks.size();
249 int currentPosition = 0;
251 double firstValue = mNoDataValue;
252 bool firstValueIsNoData =
true;
254 while ( firstValueIsNoData && ( currentPosition < inputBlocksCount ) )
257 std::unique_ptr<QgsRasterBlock> &firstBlock = inputBlocks.at( currentPosition );
258 firstValue = firstBlock->valueAndNoData( row, col, firstValueIsNoData );
260 if ( !firstBlock->isValid() || firstValueIsNoData )
262 noDataInRasterBlockStack =
true;
267 lowestPosition = currentPosition;
272 if ( noDataCount == inputBlocksCount )
274 noDataInRasterBlockStack =
true;
280 while ( currentPosition < inputBlocksCount )
282 std::unique_ptr< QgsRasterBlock > ¤tBlock = inputBlocks.at( currentPosition );
284 bool currentValueIsNoData =
false;
285 const double currentValue = currentBlock->valueAndNoData( row, col, currentValueIsNoData );
287 if ( !currentBlock->isValid() || currentValueIsNoData )
289 noDataInRasterBlockStack =
true;
294 if ( currentValue < firstValue )
296 firstValue = currentValue;
297 lowestPosition = currentPosition;
304 return ++lowestPosition;
311 QString QgsRasterStackHighestPositionAlgorithm::displayName()
const
313 return QObject::tr(
"Highest position in raster stack" );
316 QString QgsRasterStackHighestPositionAlgorithm::name()
const
318 return QStringLiteral(
"highestpositioninrasterstack" );
321 QStringList QgsRasterStackHighestPositionAlgorithm::tags()
const
323 return QObject::tr(
"cell,highest,position,pixel,stack" ).split(
',' );
326 QString QgsRasterStackHighestPositionAlgorithm::shortHelpString()
const
328 return QObject::tr(
"The highest position algorithm evaluates on a cell-by-cell basis the position "
329 "of the raster with the highest value in a stack of rasters. Position counts start "
330 "with 1 and range to the total number of input rasters. The order of the input "
331 "rasters is relevant for the algorithm. If multiple rasters feature the highest value, "
332 "the first raster will be used for the position value.\n "
333 "If multiband rasters are used in the data raster stack, the algorithm will always "
334 "perform the analysis on the first band of the rasters - use GDAL to use other bands in the analysis. "
335 "Any NoData cells in the raster layer stack will result in a NoData cell "
336 "in the output raster unless the \"ignore NoData\" parameter is checked. "
337 "The output NoData value can be set manually. The output rasters extent and resolution "
338 "is defined by a reference raster layer and is always of int32 type." );
341 QgsRasterStackHighestPositionAlgorithm *QgsRasterStackHighestPositionAlgorithm::createInstance()
const
343 return new QgsRasterStackHighestPositionAlgorithm();
346 int QgsRasterStackHighestPositionAlgorithm::findPosition( std::vector< std::unique_ptr< QgsRasterBlock> > &inputBlocks,
int &row,
int &col,
bool &noDataInRasterBlockStack )
348 int highestPosition = 0;
351 const int inputBlocksCount = inputBlocks.size();
352 int currentPosition = 0;
354 double firstValue = mNoDataValue;
355 bool firstValueIsNoData =
true;
357 while ( firstValueIsNoData && ( currentPosition < inputBlocksCount ) )
360 std::unique_ptr<QgsRasterBlock> &firstBlock = inputBlocks.at( currentPosition );
361 firstValue = firstBlock->valueAndNoData( row, col, firstValueIsNoData );
363 if ( !firstBlock->isValid() || firstValueIsNoData )
365 noDataInRasterBlockStack =
true;
370 highestPosition = currentPosition;
376 if ( noDataCount == inputBlocksCount )
378 noDataInRasterBlockStack =
true;
384 while ( currentPosition < inputBlocksCount )
386 std::unique_ptr< QgsRasterBlock > ¤tBlock = inputBlocks.at( currentPosition );
388 bool currentValueIsNoData =
false;
389 const double currentValue = currentBlock->valueAndNoData( row, col, currentValueIsNoData );
391 if ( !currentBlock->isValid() || currentValueIsNoData )
393 noDataInRasterBlockStack =
true;
398 if ( currentValue > firstValue )
400 firstValue = currentValue;
401 highestPosition = currentPosition;
408 return ++highestPosition;