27QString QgsRasterRankAlgorithm::name()
const
29 return QStringLiteral(
"rasterrank" );
32QString QgsRasterRankAlgorithm::displayName()
const
34 return QObject::tr(
"Raster rank" );
37QStringList QgsRasterRankAlgorithm::tags()
const
39 return QObject::tr(
"raster,rank" ).split(
',' );
42QString QgsRasterRankAlgorithm::group()
const
44 return QObject::tr(
"Raster analysis" );
47QString QgsRasterRankAlgorithm::groupId()
const
49 return QStringLiteral(
"rasteranalysis" );
52QString QgsRasterRankAlgorithm::shortHelpString()
const
54 return QObject::tr(
"This algorithm performs a cell-by-cell analysis in which output values match the rank of a "
55 "sorted list of overlapping cell values from input layers. The output raster "
56 "will be multi-band if multiple ranks are provided.\n"
57 "If multiband rasters are used in the data raster stack, the algorithm will always "
58 "perform the analysis on the first band of the rasters." );
61QString QgsRasterRankAlgorithm::shortDescription()
const
63 return QObject::tr(
"Performs a cell-by-cell analysis in which output values match the rank of a "
64 "sorted list of overlapping cell values from input layers." );
67QgsRasterRankAlgorithm *QgsRasterRankAlgorithm::createInstance()
const
69 return new QgsRasterRankAlgorithm();
72void QgsRasterRankAlgorithm::initAlgorithm(
const QVariantMap & )
75 auto ranksParameter = std::make_unique<QgsProcessingParameterString>( QStringLiteral(
"RANKS" ), QObject::tr(
"Rank(s) (separate multiple ranks using commas)" ), 1 );
76 ranksParameter->setHelp( QObject::tr(
"A rank value must be numerical, with multiple ranks separated by commas. The rank will be used to "
77 "generate output values from sorted lists of input layers’ cell values. A rank value of 1 will pick "
78 "the first value from a given sorted input layers’ cell values list (i.e. the minimum value). "
79 "Negative rank values are supported, and will behave like a negative index. A rank value of -2 will "
80 "pick the second to last value in sorted input values lists, while a rank value of -1 will pick the "
81 "last value (i.e. the maximum value)." ) );
82 addParameter( ranksParameter.release() );
83 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 ) );
85 auto extentParam = std::make_unique<QgsProcessingParameterExtent>( QStringLiteral(
"EXTENT" ), QObject::tr(
"Output extent" ), QVariant(),
true );
86 extentParam->setHelp( QObject::tr(
"Extent of the output layer. If not specified, the extent will be the overall extent of all input layers" ) );
88 addParameter( extentParam.release() );
90 cellSizeParam->setHelp( QObject::tr(
"Cell size of the output layer. If not specified, the smallest cell size from the input layers will be used" ) );
92 addParameter( cellSizeParam.release() );
93 auto crsParam = std::make_unique<QgsProcessingParameterCrs>( QStringLiteral(
"CRS" ), QObject::tr(
"Output CRS" ), QVariant(),
true );
94 crsParam->setHelp( QObject::tr(
"CRS of the output layer. If not specified, the CRS of the first input layer will be used" ) );
96 addParameter( crsParam.release() );
103 const QStringList rankStrings = parameterAsString( parameters, QStringLiteral(
"RANKS" ), context ).split( QLatin1String(
"," ) );
104 for (
const QString &rankString : rankStrings )
107 const int rank = rankString.toInt( &ok );
108 if ( ok && rank != 0 )
114 throw QgsProcessingException( QObject::tr(
"Rank values must be integers (found \"%1\")" ).arg( rankString ) );
118 if ( mRanks.isEmpty() )
124 const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, QStringLiteral(
"INPUT_RASTERS" ), context );
125 for (
const QgsMapLayer *layer : std::as_const( layers ) )
127 if ( !qobject_cast<const QgsRasterLayer *>( layer ) || !layer->dataProvider() )
130 std::unique_ptr<QgsMapLayer> clonedLayer;
131 clonedLayer.reset( layer->clone() );
132 clonedLayer->moveToThread(
nullptr );
133 mLayers.push_back( std::move( clonedLayer ) );
136 if ( mLayers.empty() )
148 QList<QgsMapLayer *> layers;
149 for (
auto &layer : mLayers )
151 layer->moveToThread( QThread::currentThread() );
152 layers << layer.get();
156 if ( parameters.value( QStringLiteral(
"CRS" ) ).isValid() )
158 outputCrs = parameterAsCrs( parameters, QStringLiteral(
"CRS" ), context );
162 outputCrs = mLayers[0]->crs();
166 QgsRasterLayer *templateRasterLayer = qobject_cast<QgsRasterLayer *>( mLayers[0].get() );
168 double outputNoData = 0.0;
175 outputNoData = -FLT_MAX;
177 const bool outputNoDataOverride = parameterAsInt( parameters, QStringLiteral(
"NODATA_HANDLING" ), context ) == 1;
180 if ( parameters.value( QStringLiteral(
"EXTENT" ) ).isValid() )
182 outputExtent = parameterAsExtent( parameters, QStringLiteral(
"EXTENT" ), context, outputCrs );
189 double minCellSizeX = 1e9;
190 double minCellSizeY = 1e9;
191 for (
auto &layer : mLayers )
193 QgsRasterLayer *rasterLayer = qobject_cast<QgsRasterLayer *>( layer.get() );
196 if ( rasterLayer->
crs() != outputCrs )
199 extent = ct.transformBoundingBox( extent );
202 const int width = rasterLayer->
width();
203 const int height = rasterLayer->
height();
204 if ( width <= 0 || height <= 0 )
207 minCellSizeX = std::min( minCellSizeX, ( extent.
xMaximum() - extent.
xMinimum() ) / width );
208 minCellSizeY = std::min( minCellSizeY, ( extent.
yMaximum() - extent.
yMinimum() ) / height );
211 double outputCellSizeX = parameterAsDouble( parameters, QStringLiteral(
"CELL_SIZE" ), context );
212 double outputCellSizeY = outputCellSizeX;
213 if ( outputCellSizeX == 0 )
215 outputCellSizeX = minCellSizeX;
216 outputCellSizeY = minCellSizeY;
222 const QString outputFile = parameterAsOutputLayer( parameters, QStringLiteral(
"OUTPUT" ), context );
223 const QString outputFormat = parameterAsOutputRasterFormat( parameters, QStringLiteral(
"OUTPUT" ), context );
225 auto writer = std::make_unique<QgsRasterFileWriter>( outputFile );
226 writer->setOutputFormat( outputFormat );
227 std::unique_ptr<QgsRasterDataProvider> provider( writer->createMultiBandRaster( outputDataType, cols, rows, outputExtent, outputCrs, mRanks.size() ) );
230 if ( !provider->isValid() )
232 provider->setNoDataValue( 1, outputNoData );
234 std::map<QString, std::unique_ptr<QgsRasterInterface>> newProjectorInterfaces;
235 std::map<QString, QgsRasterInterface *> inputInterfaces;
236 std::map<QString, std::unique_ptr<QgsRasterBlock>> inputBlocks;
237 std::vector<std::unique_ptr<QgsRasterBlock>> outputBlocks;
238 outputBlocks.resize( mRanks.size() );
239 for (
auto &layer : mLayers )
241 QgsRasterLayer *rasterLayer = qobject_cast<QgsRasterLayer *>( layer.get() );
242 if ( rasterLayer->
crs() != outputCrs )
248 newProjectorInterfaces[rasterLayer->
id()].reset( projector );
249 inputInterfaces[rasterLayer->
id()] = projector;
258 rasterIterator.startRasterRead( 1, cols, rows, outputExtent );
259 int blockCount =
static_cast<int>( rasterIterator.blockCount() );
261 const double step = blockCount > 0 ? 100.0 / blockCount : 0;
262 std::vector<double> inputValues;
263 inputValues.resize( mLayers.size() );
264 for (
int currentBlock = 0; currentBlock < blockCount; currentBlock++ )
277 rasterIterator.next( 1, iterCols, iterRows, iterLeft, iterTop, blockExtent );
279 for (
const auto &inputInterface : inputInterfaces )
281 inputBlocks[inputInterface.first].reset( inputInterface.second->block( 1, blockExtent, iterCols, iterRows ) );
284 for (
int i = 0; i < mRanks.size(); i++ )
286 outputBlocks[i] = std::make_unique<QgsRasterBlock>( outputDataType, iterCols, iterRows );
287 outputBlocks[i]->setNoDataValue( outputNoData );
290 for (
int row = 0; row < iterRows; row++ )
292 for (
int col = 0; col < iterCols; col++ )
295 for (
const auto &inputBlock : inputBlocks )
297 bool isNoData =
false;
298 const double value = inputBlock.second->valueAndNoData( row, col, isNoData );
301 inputValues[valuesCount] = value;
304 else if ( outputNoDataOverride )
310 std::sort( inputValues.begin(), inputValues.begin() + valuesCount );
312 for (
int i = 0; i < mRanks.size(); i++ )
314 if ( valuesCount >= std::abs( mRanks[i] ) )
316 outputBlocks[i]->setValue( row, col, inputValues[mRanks[i] > 0 ? mRanks[i] - 1 : valuesCount + mRanks[i]] );
320 outputBlocks[i]->setValue( row, col, outputNoData );
326 for (
int i = 0; i < mRanks.size(); i++ )
328 if ( !provider->writeBlock( outputBlocks[i].get(), i + 1, iterLeft, iterTop ) )
330 throw QgsProcessingException( QObject::tr(
"Could not write output raster block: %1" ).arg( provider->error().summary() ) );
336 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.
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...