QGIS API Documentation 4.3.0-Master (2b7e6c9893e)
Loading...
Searching...
No Matches
qgsalgorithmrastercellindex.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmrastercellindex.cpp
3 ---------------------
4 begin : September 2026
5 copyright : (C) 2026 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19
20#include "qgsrasterfilewriter.h"
22
23#include <QString>
24
25using namespace Qt::StringLiterals;
26
28
29QString QgsRasterCellIndexAlgorithm::name() const
30{
31 return u"rastercellindex"_s;
32}
33
34QString QgsRasterCellIndexAlgorithm::displayName() const
35{
36 return QObject::tr( "Raster grid cell index" );
37}
38
39QStringList QgsRasterCellIndexAlgorithm::tags() const
40{
41 return QObject::tr( "grid,cell,index,sort,rank,order,ascending,descending" ).split( ',' );
42}
43
44QString QgsRasterCellIndexAlgorithm::group() const
45{
46 return QObject::tr( "Raster analysis" );
47}
48
49QString QgsRasterCellIndexAlgorithm::groupId() const
50{
51 return u"rasteranalysis"_s;
52}
53
54QString QgsRasterCellIndexAlgorithm::shortHelpString() const
55{
56 return QObject::tr(
57 "This algorithm ranks valid non-NoData raster grid cells according to their value, "
58 "outputting a new grid where each cell contains its 0-based sorted index (rank).\n\n"
59 "NoData cells in the input layer are preserved as NoData in the output layer.\n\n"
60 "This algorithm is a port of the SAGA 'Grid Cell Index' tool."
61 );
62}
63
64QString QgsRasterCellIndexAlgorithm::shortDescription() const
65{
66 return QObject::tr( "Creates an index raster according to the cell values in either ascending or descending order." );
67}
68
69void QgsRasterCellIndexAlgorithm::initAlgorithm( const QVariantMap & )
70{
71 addParameter( new QgsProcessingParameterRasterLayer( u"INPUT"_s, QObject::tr( "Input layer" ) ) );
72
73 addParameter( new QgsProcessingParameterBand( u"BAND"_s, QObject::tr( "Band number" ), 1, u"INPUT"_s ) );
74
75 const QStringList orders = { QObject::tr( "Ascending" ), QObject::tr( "Descending" ) };
76 auto orderParam = std::make_unique<QgsProcessingParameterEnum>( u"ORDER"_s, QObject::tr( "Sort order" ), orders, false, 0 );
77 orderParam->setHelp( QObject::tr( "Sort order: Ascending (assigns 0 to the lowest value) or Descending (assigns 0 to the highest value)." ) );
78 addParameter( orderParam.release() );
79
80 auto outputNodataParam = std::make_unique<QgsProcessingParameterNumber>( u"NODATA"_s, QObject::tr( "Output NoData value" ), Qgis::ProcessingNumberParameterType::Integer, -9999 );
81 outputNodataParam->setHelp( QObject::tr( "The NODATA value to use in the output raster." ) );
82 outputNodataParam->setFlags( outputNodataParam->flags() | Qgis::ProcessingParameterFlag::Advanced );
83 addParameter( outputNodataParam.release() );
84
85 auto creationOptsParam = std::make_unique<QgsProcessingParameterString>( u"CREATION_OPTIONS"_s, QObject::tr( "Creation options" ), QVariant(), false, true );
86 creationOptsParam->setHelp( QObject::tr( "The raster creation options for the output raster. These options control things like colorimetry, compression, etc." ) );
87 creationOptsParam->setMetadata( QVariantMap( { { u"widget_wrapper"_s, QVariantMap( { { u"widget_type"_s, u"rasteroptions"_s } } ) } } ) );
88 creationOptsParam->setFlags( creationOptsParam->flags() | Qgis::ProcessingParameterFlag::Advanced );
89 addParameter( creationOptsParam.release() );
90
91 auto outputParam = std::make_unique<QgsProcessingParameterRasterDestination>( u"OUTPUT"_s, QObject::tr( "Output layer" ) );
92 addParameter( outputParam.release() );
93}
94
95QgsRasterCellIndexAlgorithm *QgsRasterCellIndexAlgorithm::createInstance() const
96{
97 return new QgsRasterCellIndexAlgorithm();
98}
99
100bool QgsRasterCellIndexAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
101{
102 QgsRasterLayer *layer = parameterAsRasterLayer( parameters, u"INPUT"_s, context );
103 if ( !layer )
104 throw QgsProcessingException( invalidRasterError( parameters, u"INPUT"_s ) );
105
106 mBand = parameterAsInt( parameters, u"BAND"_s, context );
107 if ( mBand < 1 || mBand > layer->bandCount() )
108 throw QgsProcessingException( QObject::tr( "Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand ).arg( layer->bandCount() ) );
109
110 mInterface.reset( layer->dataProvider()->clone() );
111 mLayerWidth = layer->width();
112 mLayerHeight = layer->height();
113 mExtent = layer->extent();
114 mCrs = layer->crs();
115
116 return true;
117}
118
119QVariantMap QgsRasterCellIndexAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
120{
121 QGS_MARK_ALGORITHM_SOURCE
122
123 const Qt::SortOrder sortOrder = ( parameterAsInt( parameters, u"ORDER"_s, context ) == 0 ) ? Qt::AscendingOrder : Qt::DescendingOrder;
124
125 const QString creationOptions = parameterAsString( parameters, u"CREATION_OPTIONS"_s, context ).trimmed();
126 const int outputNodata = parameterAsInt( parameters, u"NODATA"_s, context );
127
128 const QString outputFile = parameterAsOutputLayer( parameters, u"OUTPUT"_s, context );
129 const QString outputFormat = parameterAsOutputRasterFormat( parameters, u"OUTPUT"_s, context );
130
131 std::unique_ptr<QgsRasterBlock> inputBlock( mInterface->block( 1, mExtent, mLayerWidth, mLayerHeight ) );
132 if ( !inputBlock )
133 throw QgsProcessingException( QObject::tr( "Could not read input raster block." ) );
134
135 const QgsSortedRasterBlockIndex sortedIndex( inputBlock.get() );
136 const qgssize count = sortedIndex.sortedCount();
137
138 const qgssize totalCells = static_cast<qgssize>( mLayerWidth ) * mLayerHeight;
139 auto outputBlock = std::make_unique< QgsRasterBlock >( Qgis::DataType::Int32, mLayerWidth, mLayerHeight );
140 outputBlock->setNoDataValue( outputNodata );
141
142 int32_t *outputData = reinterpret_cast<int32_t *>( outputBlock->bits() );
143 std::fill_n( outputData, totalCells, static_cast<int32_t>( outputNodata ) );
144
145 for ( qgssize rank = 0; rank < count; ++rank )
146 {
147 if ( feedback->isCanceled() )
148 return {};
149
150 feedback->setProgress( 100.0 * static_cast<double>( rank ) / count );
151
152 const qgssize outputBlockIndex = sortedIndex.sortedIndex( rank, sortOrder );
153 outputData[outputBlockIndex] = static_cast<int32_t>( rank );
154 }
155
156 auto outputWriter = std::make_unique<QgsRasterFileWriter>( outputFile );
157 outputWriter->setOutputProviderKey( u"gdal"_s );
158 if ( !creationOptions.isEmpty() )
159 {
160 outputWriter->setCreationOptions( creationOptions.split( '|' ) );
161 }
162 outputWriter->setOutputFormat( outputFormat );
163
164 std::unique_ptr<QgsRasterDataProvider> destProvider( outputWriter->createOneBandRaster( Qgis::DataType::Int32, mLayerWidth, mLayerHeight, mExtent, mCrs ) );
165 if ( !destProvider )
166 throw QgsProcessingException( QObject::tr( "Could not create raster output: %1" ).arg( outputFile ) );
167 if ( !destProvider->isValid() )
168 throw QgsProcessingException( QObject::tr( "Could not create raster output %1: %2" ).arg( outputFile, destProvider->error().message( QgsErrorMessage::Text ) ) );
169
170 destProvider->setNoDataValue( 1, outputNodata );
171 destProvider->setEditable( true );
172 if ( !destProvider->writeBlock( outputBlock.get(), 1 ) )
173 {
174 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( destProvider->error().summary() ) );
175 }
176 destProvider->setEditable( false );
177
178 QVariantMap outputs;
179 outputs.insert( u"OUTPUT"_s, outputFile );
180 return outputs;
181}
182
183
@ Int32
Thirty two bit signed integer (qint32).
Definition qgis.h:400
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
Definition qgis.h:3984
@ Text
Plain text format.
Definition qgserror.h:40
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:56
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:65
virtual Q_INVOKABLE QgsRectangle extent() const
Returns the extent of the layer.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:90
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
A raster band parameter for Processing algorithms.
A raster layer parameter for processing algorithms.
QgsRasterDataProvider * clone() const override=0
Clone itself, create deep copy.
Represents a raster layer.
int height() const
Returns the height of the (unclipped) raster.
int bandCount() const
Returns the number of bands in this layer.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
int width() const
Returns the width of the (unclipped) raster.
Creates a flat index over a QgsRasterBlock, sorted by cell 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...
Definition qgis.h:8241