QGIS API Documentation 3.99.0-Master (357b655ed83)
Loading...
Searching...
No Matches
qgsalgorithmrasterminmax.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmrasterminmax.cpp
3 ---------------------
4 begin : October 2024
5 copyright : (C) 2024 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 <QString>
21
22using namespace Qt::StringLiterals;
23
25
26QString QgsRasterMinMaxAlgorithm::name() const
27{
28 return u"rasterminmax"_s;
29}
30
31QString QgsRasterMinMaxAlgorithm::displayName() const
32{
33 return QObject::tr( "Raster minimum/maximum" );
34}
35
36QStringList QgsRasterMinMaxAlgorithm::tags() const
37{
38 return QObject::tr( "dem,statistics,value,extrema,extremes,largest,smallest" ).split( ',' );
39}
40
41QString QgsRasterMinMaxAlgorithm::group() const
42{
43 return QObject::tr( "Raster analysis" );
44}
45
46QString QgsRasterMinMaxAlgorithm::groupId() const
47{
48 return u"rasteranalysis"_s;
49}
50
51void QgsRasterMinMaxAlgorithm::initAlgorithm( const QVariantMap & )
52{
53 addParameter( new QgsProcessingParameterRasterLayer( u"INPUT"_s, QObject::tr( "Input layer" ) ) );
54 addParameter( new QgsProcessingParameterBand( u"BAND"_s, QObject::tr( "Band number" ), 1, u"INPUT"_s ) );
55 addParameter( new QgsProcessingParameterEnum( u"EXTRACT"_s, QObject::tr( "Extract extrema" ), QStringList() << QObject::tr( "Minimum and Maximum" ) << QObject::tr( "Minimum" ) << QObject::tr( "Maximum" ), false, 0 ) );
56
57 addParameter( new QgsProcessingParameterFeatureSink( u"OUTPUT"_s, QObject::tr( "Output" ), Qgis::ProcessingSourceType::VectorPoint, QVariant(), true, true ) );
58
59 addOutput( new QgsProcessingOutputNumber( u"MINIMUM"_s, QObject::tr( "Minimum" ) ) );
60 addOutput( new QgsProcessingOutputNumber( u"MAXIMUM"_s, QObject::tr( "Maximum" ) ) );
61}
62
63QString QgsRasterMinMaxAlgorithm::shortHelpString() const
64{
65 return QObject::tr( "This algorithm extracts extrema (minimum and maximum) values from a given band of the raster layer.\n\n"
66 "The output is a vector layer containing point features for the selected extrema, at the center of the associated pixel.\n\n"
67 "If multiple pixels in the raster share the minimum or maximum value, then only one of these pixels will be included in the output." );
68}
69
70QString QgsRasterMinMaxAlgorithm::shortDescription() const
71{
72 return QObject::tr( "Calculates the minimum and maximum pixel in a raster layer." );
73}
74
75QgsRasterMinMaxAlgorithm *QgsRasterMinMaxAlgorithm::createInstance() const
76{
77 return new QgsRasterMinMaxAlgorithm();
78}
79
80bool QgsRasterMinMaxAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
81{
82 QgsRasterLayer *layer = parameterAsRasterLayer( parameters, u"INPUT"_s, context );
83
84 if ( !layer )
85 throw QgsProcessingException( invalidRasterError( parameters, u"INPUT"_s ) );
86
87 mBand = parameterAsInt( parameters, u"BAND"_s, context );
88 if ( mBand < 1 || mBand > layer->bandCount() )
89 throw QgsProcessingException( QObject::tr( "Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand ).arg( layer->bandCount() ) );
90
91 mInterface.reset( layer->dataProvider()->clone() );
92 mHasNoDataValue = layer->dataProvider()->sourceHasNoDataValue( mBand );
93 mLayerWidth = layer->width();
94 mLayerHeight = layer->height();
95 mExtent = layer->extent();
96 mCrs = layer->crs();
97 mRasterUnitsPerPixelX = std::abs( layer->rasterUnitsPerPixelX() );
98 mRasterUnitsPerPixelY = std::abs( layer->rasterUnitsPerPixelY() );
99 return true;
100}
101
102QVariantMap QgsRasterMinMaxAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
103{
104 QString dest;
105 std::unique_ptr<QgsFeatureSink> sink;
106 if ( parameters.value( u"OUTPUT"_s ).isValid() )
107 {
108 QgsFields outFields;
109 outFields.append( QgsField( u"value"_s, QMetaType::Type::Double, QString(), 20, 8 ) );
110 outFields.append( QgsField( u"extremum_type"_s, QMetaType::Type::QString ) );
111 sink.reset( parameterAsSink( parameters, u"OUTPUT"_s, context, dest, outFields, Qgis::WkbType::Point, mCrs ) );
112 if ( !sink )
113 throw QgsProcessingException( invalidSinkError( parameters, u"OUTPUT"_s ) );
114 }
115
116 const int extractType = parameterAsInt( parameters, u"EXTRACT"_s, context );
117
118 QgsRasterIterator iter( mInterface.get() );
119 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
120
121 int iterLeft = 0;
122 int iterTop = 0;
123 int iterCols = 0;
124 int iterRows = 0;
125 std::unique_ptr<QgsRasterBlock> rasterBlock;
126
127 double rasterMinimum = std::numeric_limits<double>::quiet_NaN();
128 double rasterMaximum = std::numeric_limits<double>::quiet_NaN();
129 QgsPointXY rasterMinPoint;
130 QgsPointXY rasterMaxPoint;
131
132 auto blockRowColToXY = [this]( const QgsRectangle &blockExtent, int row, int col ) -> QgsPointXY {
133 return QgsPointXY( blockExtent.xMinimum() + mRasterUnitsPerPixelX * ( col + 0.5 ), blockExtent.yMaximum() - mRasterUnitsPerPixelY * ( row + 0.5 ) );
134 };
135
136 QgsRectangle blockExtent;
137 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop, &blockExtent ) )
138 {
139 if ( feedback->isCanceled() )
140 break;
141
142 double blockMinimum = std::numeric_limits<double>::quiet_NaN();
143 double blockMaximum = std::numeric_limits<double>::quiet_NaN();
144 int blockMinRow = 0;
145 int blockMinCol = 0;
146 int blockMaxRow = 0;
147 int blockMaxCol = 0;
148 switch ( extractType )
149 {
150 case 0:
151 {
152 if ( rasterBlock->minimumMaximum( blockMinimum, blockMinRow, blockMinCol, blockMaximum, blockMaxRow, blockMaxCol ) )
153 {
154 if ( std::isnan( rasterMinimum ) || blockMinimum < rasterMinimum )
155 {
156 rasterMinimum = blockMinimum;
157 rasterMinPoint = blockRowColToXY( blockExtent, blockMinRow, blockMinCol );
158 }
159 if ( std::isnan( rasterMaximum ) || blockMaximum > rasterMaximum )
160 {
161 rasterMaximum = blockMaximum;
162 rasterMaxPoint = blockRowColToXY( blockExtent, blockMaxRow, blockMaxCol );
163 }
164 }
165 break;
166 }
167
168 case 1:
169 {
170 if ( rasterBlock->minimum( blockMinimum, blockMinRow, blockMinCol ) )
171 {
172 if ( std::isnan( rasterMinimum ) || blockMinimum < rasterMinimum )
173 {
174 rasterMinimum = blockMinimum;
175 rasterMinPoint = blockRowColToXY( blockExtent, blockMinRow, blockMinCol );
176 }
177 }
178 break;
179 }
180
181 case 2:
182 {
183 if ( rasterBlock->maximum( blockMaximum, blockMaxRow, blockMaxCol ) )
184 {
185 if ( std::isnan( rasterMaximum ) || blockMaximum > rasterMaximum )
186 {
187 rasterMaximum = blockMaximum;
188 rasterMaxPoint = blockRowColToXY( blockExtent, blockMaxRow, blockMaxCol );
189 }
190 }
191 break;
192 }
193 default:
194 break;
195 }
196 feedback->setProgress( 100 * iter.progress( mBand ) );
197 }
198
199 QVariantMap outputs;
200 if ( sink )
201 {
202 QgsFeature f;
203 if ( !std::isnan( rasterMinimum ) )
204 {
205 f.setAttributes( QgsAttributes() << rasterMinimum << u"minimum"_s );
206 f.setGeometry( QgsGeometry::fromPointXY( rasterMinPoint ) );
207 if ( !sink->addFeature( f, QgsFeatureSink::FastInsert ) )
208 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, u"OUTPUT"_s ) );
209 }
210 if ( !std::isnan( rasterMaximum ) )
211 {
212 f.setAttributes( QgsAttributes() << rasterMaximum << u"maximum"_s );
213 f.setGeometry( QgsGeometry::fromPointXY( rasterMaxPoint ) );
214 if ( !sink->addFeature( f, QgsFeatureSink::FastInsert ) )
215 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, u"OUTPUT"_s ) );
216 }
217 outputs.insert( u"OUTPUT"_s, dest );
218 }
219 outputs.insert( u"MINIMUM"_s, !std::isnan( rasterMinimum ) ? QVariant::fromValue( rasterMinimum ) : QVariant() );
220 outputs.insert( u"MAXIMUM"_s, !std::isnan( rasterMaximum ) ? QVariant::fromValue( rasterMaximum ) : QVariant() );
221 return outputs;
222}
223
224
@ VectorPoint
Vector point layers.
Definition qgis.h:3605
@ Point
Point.
Definition qgis.h:282
A vector of attributes.
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:60
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:55
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:63
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:56
Container of fields for a vector layer.
Definition qgsfields.h:46
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
Definition qgsfields.cpp:76
static QgsGeometry fromPointXY(const QgsPointXY &point)
Creates a new geometry from a QgsPointXY object.
virtual QgsRectangle extent() const
Returns the extent of the layer.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:90
Represents a 2D point.
Definition qgspointxy.h:62
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 numeric output for processing algorithms.
A raster band parameter for Processing algorithms.
An enum based parameter for processing algorithms, allowing for selection from predefined values.
A feature sink output for processing algorithms.
A raster layer parameter for processing algorithms.
QgsRasterDataProvider * clone() const override=0
Clone itself, create deep copy.
virtual bool sourceHasNoDataValue(int bandNo) const
Returns true if source band has no data value.
Iterator for sequentially processing raster cells.
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.
double rasterUnitsPerPixelX() const
Returns the number of raster units per each raster pixel in X axis.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
double rasterUnitsPerPixelY() const
Returns the number of raster units per each raster pixel in Y axis.
int width() const
Returns the width of the (unclipped) raster.
A rectangle specified with double values.
double xMinimum
double yMaximum