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(
"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." );
58QgsRasterRankAlgorithm *QgsRasterRankAlgorithm::createInstance()
const
60 return new QgsRasterRankAlgorithm();
63void QgsRasterRankAlgorithm::initAlgorithm(
const QVariantMap & )
66 auto ranksParameter = std::make_unique<QgsProcessingParameterString>( QStringLiteral(
"RANKS" ), QObject::tr(
"Rank(s) (separate multiple ranks using commas)" ), 1 );
67 ranksParameter->setHelp( QObject::tr(
"A rank value must be numerical, with multiple ranks separated by commas. The rank will be used to "
68 "generate output values from sorted lists of input layers’ cell values. A rank value of 1 will pick "
69 "the first value from a given sorted input layers’ cell values list (i.e. the minimum value). "
70 "Negative rank values are supported, and will behave like a negative index. A rank value of -2 will "
71 "pick the second to last value in sorted input values lists, while a rank value of -1 will pick the "
72 "last value (i.e. the maximum value)." ) );
73 addParameter( ranksParameter.release() );
74 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 ) );
76 auto extentParam = std::make_unique<QgsProcessingParameterExtent>( QStringLiteral(
"EXTENT" ), QObject::tr(
"Output extent" ), QVariant(),
true );
77 extentParam->setHelp( QObject::tr(
"Extent of the output layer. If not specified, the extent will be the overall extent of all input layers" ) );
79 addParameter( extentParam.release() );
81 cellSizeParam->setHelp( QObject::tr(
"Cell size of the output layer. If not specified, the smallest cell size from the input layers will be used" ) );
83 addParameter( cellSizeParam.release() );
84 auto crsParam = std::make_unique<QgsProcessingParameterCrs>( QStringLiteral(
"CRS" ), QObject::tr(
"Output CRS" ), QVariant(),
true );
85 crsParam->setHelp( QObject::tr(
"CRS of the output layer. If not specified, the CRS of the first input layer will be used" ) );
87 addParameter( crsParam.release() );
94 const QStringList rankStrings = parameterAsString( parameters, QStringLiteral(
"RANKS" ), context ).split( QLatin1String(
"," ) );
95 for (
const QString &rankString : rankStrings )
98 const int rank = rankString.toInt( &ok );
99 if ( ok && rank != 0 )
105 throw QgsProcessingException( QObject::tr(
"Rank values must be integers (found \"%1\")" ).arg( rankString ) );
109 if ( mRanks.isEmpty() )
115 const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, QStringLiteral(
"INPUT_RASTERS" ), context );
116 for (
const QgsMapLayer *layer : std::as_const( layers ) )
118 if ( !qobject_cast<const QgsRasterLayer *>( layer ) || !layer->dataProvider() )
121 std::unique_ptr<QgsMapLayer> clonedLayer;
122 clonedLayer.reset( layer->clone() );
123 clonedLayer->moveToThread(
nullptr );
124 mLayers.push_back( std::move( clonedLayer ) );
127 if ( mLayers.empty() )
139 QList<QgsMapLayer *> layers;
140 for (
auto &layer : mLayers )
142 layer->moveToThread( QThread::currentThread() );
143 layers << layer.get();
147 if ( parameters.value( QStringLiteral(
"CRS" ) ).isValid() )
149 outputCrs = parameterAsCrs( parameters, QStringLiteral(
"CRS" ), context );
157 QgsRasterLayer *templateRasterLayer = qobject_cast<QgsRasterLayer *>( mLayers[0].get() );
159 double outputNoData = 0.0;
166 outputNoData = -FLT_MAX;
168 const bool outputNoDataOverride = parameterAsInt( parameters, QStringLiteral(
"NODATA_HANDLING" ), context ) == 1;
171 if ( parameters.value( QStringLiteral(
"EXTENT" ) ).isValid() )
173 outputExtent = parameterAsExtent( parameters, QStringLiteral(
"EXTENT" ), context,
outputCrs );
180 double minCellSizeX = 1e9;
181 double minCellSizeY = 1e9;
182 for (
auto &layer : mLayers )
184 QgsRasterLayer *rasterLayer = qobject_cast<QgsRasterLayer *>( layer.get() );
190 extent = ct.transformBoundingBox( extent );
193 minCellSizeX = std::min( minCellSizeX, ( extent.
xMaximum() - extent.
xMinimum() ) / rasterLayer->
width() );
194 minCellSizeY = std::min( minCellSizeY, ( extent.
yMaximum() - extent.
yMinimum() ) / rasterLayer->
height() );
197 double outputCellSizeX = parameterAsDouble( parameters, QStringLiteral(
"CELL_SIZE" ), context );
198 double outputCellSizeY = outputCellSizeX;
199 if ( outputCellSizeX == 0 )
201 outputCellSizeX = minCellSizeX;
202 outputCellSizeY = minCellSizeY;
208 const QString outputFile = parameterAsOutputLayer( parameters, QStringLiteral(
"OUTPUT" ), context );
209 const QFileInfo fi( outputFile );
212 auto writer = std::make_unique<QgsRasterFileWriter>( outputFile );
213 writer->setOutputFormat( outputFormat );
214 std::unique_ptr<QgsRasterDataProvider> provider( writer->createMultiBandRaster( outputDataType, cols, rows, outputExtent,
outputCrs, mRanks.size() ) );
217 if ( !provider->isValid() )
219 provider->setNoDataValue( 1, outputNoData );
221 std::map<QString, std::unique_ptr<QgsRasterInterface>> newProjectorInterfaces;
222 std::map<QString, QgsRasterInterface *> inputInterfaces;
223 std::map<QString, std::unique_ptr<QgsRasterBlock>> inputBlocks;
224 std::vector<std::unique_ptr<QgsRasterBlock>> outputBlocks;
225 outputBlocks.resize( mRanks.size() );
226 for (
auto &layer : mLayers )
228 QgsRasterLayer *rasterLayer = qobject_cast<QgsRasterLayer *>( layer.get() );
235 newProjectorInterfaces[rasterLayer->
id()].reset( projector );
236 inputInterfaces[rasterLayer->
id()] = projector;
245 rasterIterator.startRasterRead( 1, cols, rows, outputExtent );
246 int blockCount =
static_cast<int>( rasterIterator.blockCount() );
248 const double step = blockCount > 0 ? 100.0 / blockCount : 0;
249 std::vector<double> inputValues;
250 inputValues.resize( mLayers.size() );
251 for (
int currentBlock = 0; currentBlock < blockCount; currentBlock++ )
264 rasterIterator.next( 1, iterCols, iterRows, iterLeft, iterTop, blockExtent );
266 for (
const auto &inputInterface : inputInterfaces )
268 inputBlocks[inputInterface.first].reset( inputInterface.second->block( 1, blockExtent, iterCols, iterRows ) );
271 for (
int i = 0; i < mRanks.size(); i++ )
273 outputBlocks[i].reset(
new QgsRasterBlock( outputDataType, iterCols, iterRows ) );
274 outputBlocks[i]->setNoDataValue( outputNoData );
277 for (
int row = 0; row < iterRows; row++ )
279 for (
int col = 0; col < iterCols; col++ )
282 for (
const auto &inputBlock : inputBlocks )
284 bool isNoData =
false;
285 const double value = inputBlock.second->valueAndNoData( row, col, isNoData );
288 inputValues[valuesCount] = value;
291 else if ( outputNoDataOverride )
297 std::sort( inputValues.begin(), inputValues.begin() + valuesCount );
299 for (
int i = 0; i < mRanks.size(); i++ )
301 if ( valuesCount >= std::abs( mRanks[i] ) )
303 outputBlocks[i]->setValue( row, col, inputValues[mRanks[i] > 0 ? mRanks[i] - 1 : valuesCount + mRanks[i]] );
307 outputBlocks[i]->setValue( row, col, outputNoData );
313 for (
int i = 0; i < mRanks.size(); i++ )
315 if ( !provider->writeBlock( outputBlocks[i].get(), i + 1, iterLeft, iterTop ) )
317 throw QgsProcessingException( QObject::tr(
"Could not write output raster block: %1" ).arg( provider->error().summary() ) );
323 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.
This class 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