24QString QgsRasterRankAlgorithm::name()
 const 
   26  return QStringLiteral( 
"rasterrank" );
 
   29QString QgsRasterRankAlgorithm::displayName()
 const 
   31  return QObject::tr( 
"Raster rank" );
 
   34QStringList QgsRasterRankAlgorithm::tags()
 const 
   36  return QObject::tr( 
"raster,rank" ).split( 
',' );
 
   39QString QgsRasterRankAlgorithm::group()
 const 
   41  return QObject::tr( 
"Raster analysis" );
 
   44QString QgsRasterRankAlgorithm::groupId()
 const 
   46  return QStringLiteral( 
"rasteranalysis" );
 
   49QString QgsRasterRankAlgorithm::shortHelpString()
 const 
   51  return QObject::tr( 
"This algorithm performs a cell-by-cell analysis in which output values match the rank of a " 
   52                      "sorted list of overlapping cell values from input layers. The output raster " 
   53                      "will be multi-band if multiple ranks are provided.\n" 
   54                      "If multiband rasters are used in the data raster stack, the algorithm will always " 
   55                      "perform the analysis on the first band of the rasters." );
 
   58QString QgsRasterRankAlgorithm::shortDescription()
 const 
   60  return QObject::tr( 
"Performs a cell-by-cell analysis in which output values match the rank of a " 
   61                      "sorted list of overlapping cell values from input layers." );
 
   64QgsRasterRankAlgorithm *QgsRasterRankAlgorithm::createInstance()
 const 
   66  return new QgsRasterRankAlgorithm();
 
   69void QgsRasterRankAlgorithm::initAlgorithm( 
const QVariantMap & )
 
   72  auto ranksParameter = std::make_unique<QgsProcessingParameterString>( QStringLiteral( 
"RANKS" ), QObject::tr( 
"Rank(s) (separate multiple ranks using commas)" ), 1 );
 
   73  ranksParameter->setHelp( QObject::tr( 
"A rank value must be numerical, with multiple ranks separated by commas. The rank will be used to " 
   74                                        "generate output values from sorted lists of input layers’ cell values. A rank value of 1 will pick " 
   75                                        "the first value from a given sorted input layers’ cell values list (i.e. the minimum value). " 
   76                                        "Negative rank values are supported, and will behave like a negative index. A rank value of -2 will " 
   77                                        "pick the second to last value in sorted input values lists, while a rank value of -1 will pick the " 
   78                                        "last value (i.e. the maximum value)." ) );
 
   79  addParameter( ranksParameter.release() );
 
   80  addParameter( 
new QgsProcessingParameterEnum( QStringLiteral( 
"NODATA_HANDLING" ), QObject::tr( 
"NoData value handling" ), QStringList() << QObject::tr( 
"Exclude NoData from values lists" ) << QObject::tr( 
"Presence of NoData in a values list results in NoData output cell" ), 
false, 0 ) );
 
   82  auto extentParam = std::make_unique<QgsProcessingParameterExtent>( QStringLiteral( 
"EXTENT" ), QObject::tr( 
"Output extent" ), QVariant(), 
true );
 
   83  extentParam->setHelp( QObject::tr( 
"Extent of the output layer. If not specified, the extent will be the overall extent of all input layers" ) );
 
   85  addParameter( extentParam.release() );
 
   87  cellSizeParam->setHelp( QObject::tr( 
"Cell size of the output layer. If not specified, the smallest cell size from the input layers will be used" ) );
 
   89  addParameter( cellSizeParam.release() );
 
   90  auto crsParam = std::make_unique<QgsProcessingParameterCrs>( QStringLiteral( 
"CRS" ), QObject::tr( 
"Output CRS" ), QVariant(), 
true );
 
   91  crsParam->setHelp( QObject::tr( 
"CRS of the output layer. If not specified, the CRS of the first input layer will be used" ) );
 
   93  addParameter( crsParam.release() );
 
  100  const QStringList rankStrings = parameterAsString( parameters, QStringLiteral( 
"RANKS" ), context ).split( QLatin1String( 
"," ) );
 
  101  for ( 
const QString &rankString : rankStrings )
 
  104    const int rank = rankString.toInt( &ok );
 
  105    if ( ok && rank != 0 )
 
  111      throw QgsProcessingException( QObject::tr( 
"Rank values must be integers (found \"%1\")" ).arg( rankString ) );
 
  115  if ( mRanks.isEmpty() )
 
  121  const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, QStringLiteral( 
"INPUT_RASTERS" ), context );
 
  122  for ( 
const QgsMapLayer *layer : std::as_const( layers ) )
 
  124    if ( !qobject_cast<const QgsRasterLayer *>( layer ) || !layer->dataProvider() )
 
  127    std::unique_ptr<QgsMapLayer> clonedLayer;
 
  128    clonedLayer.reset( layer->clone() );
 
  129    clonedLayer->moveToThread( 
nullptr );
 
  130    mLayers.push_back( std::move( clonedLayer ) );
 
  133  if ( mLayers.empty() )
 
  145  QList<QgsMapLayer *> layers; 
 
  146  for ( 
auto &layer : mLayers )
 
  148    layer->moveToThread( QThread::currentThread() );
 
  149    layers << layer.get();
 
  153  if ( parameters.value( QStringLiteral( 
"CRS" ) ).isValid() )
 
  155    outputCrs = parameterAsCrs( parameters, QStringLiteral( 
"CRS" ), context );
 
  163  QgsRasterLayer *templateRasterLayer = qobject_cast<QgsRasterLayer *>( mLayers[0].get() );
 
  165  double outputNoData = 0.0;
 
  172    outputNoData = -FLT_MAX;
 
  174  const bool outputNoDataOverride = parameterAsInt( parameters, QStringLiteral( 
"NODATA_HANDLING" ), context ) == 1;
 
  177  if ( parameters.value( QStringLiteral( 
"EXTENT" ) ).isValid() )
 
  179    outputExtent = parameterAsExtent( parameters, QStringLiteral( 
"EXTENT" ), context, 
outputCrs );
 
  186  double minCellSizeX = 1e9;
 
  187  double minCellSizeY = 1e9;
 
  188  for ( 
auto &layer : mLayers )
 
  190    QgsRasterLayer *rasterLayer = qobject_cast<QgsRasterLayer *>( layer.get() );
 
  196      extent = ct.transformBoundingBox( extent );
 
  199    const int width = rasterLayer->
width();
 
  200    const int height = rasterLayer->
height();
 
  201    if ( width <= 0 || height <= 0 )
 
  204    minCellSizeX = std::min( minCellSizeX, ( extent.
xMaximum() - extent.
xMinimum() ) / width );
 
  205    minCellSizeY = std::min( minCellSizeY, ( extent.
yMaximum() - extent.
yMinimum() ) / height );
 
  208  double outputCellSizeX = parameterAsDouble( parameters, QStringLiteral( 
"CELL_SIZE" ), context );
 
  209  double outputCellSizeY = outputCellSizeX;
 
  210  if ( outputCellSizeX == 0 )
 
  212    outputCellSizeX = minCellSizeX;
 
  213    outputCellSizeY = minCellSizeY;
 
  219  const QString outputFile = parameterAsOutputLayer( parameters, QStringLiteral( 
"OUTPUT" ), context );
 
  220  const QFileInfo fi( outputFile );
 
  223  auto writer = std::make_unique<QgsRasterFileWriter>( outputFile );
 
  224  writer->setOutputFormat( outputFormat );
 
  225  std::unique_ptr<QgsRasterDataProvider> provider( writer->createMultiBandRaster( outputDataType, cols, rows, outputExtent, 
outputCrs, mRanks.size() ) );
 
  228  if ( !provider->isValid() )
 
  230  provider->setNoDataValue( 1, outputNoData );
 
  232  std::map<QString, std::unique_ptr<QgsRasterInterface>> newProjectorInterfaces;
 
  233  std::map<QString, QgsRasterInterface *> inputInterfaces;
 
  234  std::map<QString, std::unique_ptr<QgsRasterBlock>> inputBlocks;
 
  235  std::vector<std::unique_ptr<QgsRasterBlock>> outputBlocks;
 
  236  outputBlocks.resize( mRanks.size() );
 
  237  for ( 
auto &layer : mLayers )
 
  239    QgsRasterLayer *rasterLayer = qobject_cast<QgsRasterLayer *>( layer.get() );
 
  246      newProjectorInterfaces[rasterLayer->
id()].reset( projector );
 
  247      inputInterfaces[rasterLayer->
id()] = projector;
 
  256  rasterIterator.startRasterRead( 1, cols, rows, outputExtent );
 
  257  int blockCount = 
static_cast<int>( rasterIterator.blockCount() );
 
  259  const double step = blockCount > 0 ? 100.0 / blockCount : 0;
 
  260  std::vector<double> inputValues;
 
  261  inputValues.resize( mLayers.size() );
 
  262  for ( 
int currentBlock = 0; currentBlock < blockCount; currentBlock++ )
 
  275    rasterIterator.next( 1, iterCols, iterRows, iterLeft, iterTop, blockExtent );
 
  277    for ( 
const auto &inputInterface : inputInterfaces )
 
  279      inputBlocks[inputInterface.first].reset( inputInterface.second->block( 1, blockExtent, iterCols, iterRows ) );
 
  282    for ( 
int i = 0; i < mRanks.size(); i++ )
 
  284      outputBlocks[i].reset( 
new QgsRasterBlock( outputDataType, iterCols, iterRows ) );
 
  285      outputBlocks[i]->setNoDataValue( outputNoData );
 
  288    for ( 
int row = 0; row < iterRows; row++ )
 
  290      for ( 
int col = 0; col < iterCols; col++ )
 
  293        for ( 
const auto &inputBlock : inputBlocks )
 
  295          bool isNoData = 
false;
 
  296          const double value = inputBlock.second->valueAndNoData( row, col, isNoData );
 
  299            inputValues[valuesCount] = value;
 
  302          else if ( outputNoDataOverride )
 
  308        std::sort( inputValues.begin(), inputValues.begin() + valuesCount );
 
  310        for ( 
int i = 0; i < mRanks.size(); i++ )
 
  312          if ( valuesCount >= std::abs( mRanks[i] ) )
 
  314            outputBlocks[i]->setValue( row, col, inputValues[mRanks[i] > 0 ? mRanks[i] - 1 : valuesCount + mRanks[i]] );
 
  318            outputBlocks[i]->setValue( row, col, outputNoData );
 
  324    for ( 
int i = 0; i < mRanks.size(); i++ )
 
  326      if ( !provider->writeBlock( outputBlocks[i].get(), i + 1, iterLeft, iterTop ) )
 
  328        throw QgsProcessingException( QObject::tr( 
"Could not write output raster block: %1" ).arg( provider->error().summary() ) );
 
  334  outputs.insert( QStringLiteral( 
"OUTPUT" ), outputFile );
 
DataType
Raster data types.
 
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
 
@ Double
Double/float values.
 
Represents a coordinate reference system (CRS).
 
bool isCanceled() const
Tells whether the operation has been canceled already.
 
void setProgress(double progress)
Sets the current progress for the feedback object.
 
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.
 
An enum based parameter for processing algorithms, allowing for selection from predefined values.
 
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 ...
 
static QgsRectangle combineLayerExtents(const QList< QgsMapLayer * > &layers, const QgsCoordinateReferenceSystem &crs, QgsProcessingContext &context)
Combines the extent of several map layers.
 
virtual bool sourceHasNoDataValue(int bandNo) const
Returns true if source band has no data value.
 
virtual double sourceNoDataValue(int bandNo) const
Value representing no data value.
 
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
 
static QString driverForExtension(const QString &extension)
Returns the GDAL driver name for a specified file extension.
 
virtual bool setInput(QgsRasterInterface *input)
Set input.
 
Iterator for sequentially processing raster cells.
 
Represents a raster layer.
 
int height() const
Returns the height of the (unclipped) raster.
 
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
 
int width() const
Returns the width of the (unclipped) raster.
 
Implements approximate projection support for optimised raster transformation.
 
void setPrecision(Precision precision)
 
@ Exact
Exact, precise but slow.
 
Q_DECL_DEPRECATED void setCrs(const QgsCoordinateReferenceSystem &srcCRS, const QgsCoordinateReferenceSystem &destCRS, int srcDatumTransform=-1, int destDatumTransform=-1)
Sets the source and destination CRS.
 
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...
 
const QgsCoordinateReferenceSystem & outputCrs