QGIS API Documentation 3.41.0-Master (3440c17df1d)
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
21
22QString QgsRasterMinMaxAlgorithm::name() const
23{
24 return QStringLiteral( "rasterminmax" );
25}
26
27QString QgsRasterMinMaxAlgorithm::displayName() const
28{
29 return QObject::tr( "Raster minimum/maximum" );
30}
31
32QStringList QgsRasterMinMaxAlgorithm::tags() const
33{
34 return QObject::tr( "dem,statistics,value,extrema,extremes,largest,smallest" ).split( ',' );
35}
36
37QString QgsRasterMinMaxAlgorithm::group() const
38{
39 return QObject::tr( "Raster analysis" );
40}
41
42QString QgsRasterMinMaxAlgorithm::groupId() const
43{
44 return QStringLiteral( "rasteranalysis" );
45}
46
47void QgsRasterMinMaxAlgorithm::initAlgorithm( const QVariantMap & )
48{
49 addParameter( new QgsProcessingParameterRasterLayer( QStringLiteral( "INPUT" ),
50 QObject::tr( "Input layer" ) ) );
51 addParameter( new QgsProcessingParameterBand( QStringLiteral( "BAND" ),
52 QObject::tr( "Band number" ), 1, QStringLiteral( "INPUT" ) ) );
53 addParameter( new QgsProcessingParameterEnum( QStringLiteral( "EXTRACT" ),
54 QObject::tr( "Extract extrema" ), QStringList()
55 << QObject::tr( "Minimum and Maximum" )
56 << QObject::tr( "Minimum" )
57 << QObject::tr( "Maximum" ), false, 0 ) );
58
59 addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ),
60 QObject::tr( "Output" ), Qgis::ProcessingSourceType::VectorPoint, QVariant(), true, true ) );
61
62 addOutput( new QgsProcessingOutputNumber( QStringLiteral( "MINIMUM" ), QObject::tr( "Minimum" ) ) );
63 addOutput( new QgsProcessingOutputNumber( QStringLiteral( "MAXIMUM" ), QObject::tr( "Maximum" ) ) );
64}
65
66QString QgsRasterMinMaxAlgorithm::shortHelpString() const
67{
68 return QObject::tr( "This algorithm extracts extrema (minimum and maximum) values from a given band of the raster layer.\n\n"
69 "The output is a vector layer containing point features for the selected extrema, at the center of the associated pixel.\n\n"
70 "If multiple pixels in the raster share the minimum or maximum value, then only one of these pixels will be included in the output." );
71}
72
73QString QgsRasterMinMaxAlgorithm::shortDescription() const
74{
75 return QObject::tr( "Calculates the minimum and maximum pixel in a raster layer." );
76}
77
78QgsRasterMinMaxAlgorithm *QgsRasterMinMaxAlgorithm::createInstance() const
79{
80 return new QgsRasterMinMaxAlgorithm();
81}
82
83bool QgsRasterMinMaxAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
84{
85 QgsRasterLayer *layer = parameterAsRasterLayer( parameters, QStringLiteral( "INPUT" ), context );
86
87 if ( !layer )
88 throw QgsProcessingException( invalidRasterError( parameters, QStringLiteral( "INPUT" ) ) );
89
90 mBand = parameterAsInt( parameters, QStringLiteral( "BAND" ), context );
91 if ( mBand < 1 || mBand > layer->bandCount() )
92 throw QgsProcessingException( QObject::tr( "Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand )
93 .arg( layer->bandCount() ) );
94
95 mInterface.reset( layer->dataProvider()->clone() );
96 mHasNoDataValue = layer->dataProvider()->sourceHasNoDataValue( mBand );
97 mLayerWidth = layer->width();
98 mLayerHeight = layer->height();
99 mExtent = layer->extent();
100 mCrs = layer->crs();
101 mRasterUnitsPerPixelX = std::abs( layer->rasterUnitsPerPixelX() );
102 mRasterUnitsPerPixelY = std::abs( layer->rasterUnitsPerPixelY() );
103 return true;
104}
105
106QVariantMap QgsRasterMinMaxAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
107{
108 QString dest;
109 std::unique_ptr< QgsFeatureSink > sink;
110 if ( parameters.value( QStringLiteral( "OUTPUT" ) ).isValid() )
111 {
112 QgsFields outFields;
113 outFields.append( QgsField( QStringLiteral( "value" ), QMetaType::Type::Double, QString(), 20, 8 ) );
114 outFields.append( QgsField( QStringLiteral( "extremum_type" ), QMetaType::Type::QString ) );
115 sink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, outFields, Qgis::WkbType::Point, mCrs ) );
116 if ( !sink )
117 throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
118 }
119
120 const int extractType = parameterAsInt( parameters, QStringLiteral( "EXTRACT" ), context );
121
122 QgsRasterIterator iter( mInterface.get() );
123 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
124
125 int iterLeft = 0;
126 int iterTop = 0;
127 int iterCols = 0;
128 int iterRows = 0;
129 std::unique_ptr< QgsRasterBlock > rasterBlock;
130
131 double rasterMinimum = std::numeric_limits< double >::quiet_NaN();
132 double rasterMaximum = std::numeric_limits< double >::quiet_NaN();
133 QgsPointXY rasterMinPoint;
134 QgsPointXY rasterMaxPoint;
135
136 auto blockRowColToXY = [this]( const QgsRectangle & blockExtent, int row, int col ) -> QgsPointXY
137 {
138 return QgsPointXY( blockExtent.xMinimum() + mRasterUnitsPerPixelX * ( col + 0.5 ),
139 blockExtent.yMaximum() - mRasterUnitsPerPixelY * ( row + 0.5 ) );
140 };
141
142 QgsRectangle blockExtent;
143 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop, &blockExtent ) )
144 {
145 if ( feedback->isCanceled() )
146 break;
147
148 double blockMinimum = std::numeric_limits< double >::quiet_NaN();
149 double blockMaximum = std::numeric_limits< double >::quiet_NaN();
150 int blockMinRow = 0;
151 int blockMinCol = 0;
152 int blockMaxRow = 0;
153 int blockMaxCol = 0;
154 switch ( extractType )
155 {
156 case 0:
157 {
158 if ( rasterBlock->minimumMaximum( blockMinimum, blockMinRow, blockMinCol, blockMaximum, blockMaxRow, blockMaxCol ) )
159 {
160 if ( std::isnan( rasterMinimum ) || blockMinimum < rasterMinimum )
161 {
162 rasterMinimum = blockMinimum;
163 rasterMinPoint = blockRowColToXY( blockExtent, blockMinRow, blockMinCol );
164 }
165 if ( std::isnan( rasterMaximum ) || blockMaximum > rasterMaximum )
166 {
167 rasterMaximum = blockMaximum;
168 rasterMaxPoint = blockRowColToXY( blockExtent, blockMaxRow, blockMaxCol );
169 }
170 }
171 break;
172 }
173
174 case 1:
175 {
176 if ( rasterBlock->minimum( blockMinimum, blockMinRow, blockMinCol ) )
177 {
178 if ( std::isnan( rasterMinimum ) || blockMinimum < rasterMinimum )
179 {
180 rasterMinimum = blockMinimum;
181 rasterMinPoint = blockRowColToXY( blockExtent, blockMinRow, blockMinCol );
182 }
183 }
184 break;
185 }
186
187 case 2:
188 {
189 if ( rasterBlock->maximum( blockMaximum, blockMaxRow, blockMaxCol ) )
190 {
191 if ( std::isnan( rasterMaximum ) || blockMaximum > rasterMaximum )
192 {
193 rasterMaximum = blockMaximum;
194 rasterMaxPoint = blockRowColToXY( blockExtent, blockMaxRow, blockMaxCol );
195 }
196 }
197 break;
198 }
199 default:
200 break;
201 }
202 feedback->setProgress( 100 * iter.progress( mBand ) );
203 }
204
205 QVariantMap outputs;
206 if ( sink )
207 {
208 QgsFeature f;
209 if ( !std::isnan( rasterMinimum ) )
210 {
211
212 f.setAttributes( QgsAttributes() << rasterMinimum << QStringLiteral( "minimum" ) );
213 f.setGeometry( QgsGeometry::fromPointXY( rasterMinPoint ) );
214 if ( !sink->addFeature( f, QgsFeatureSink::FastInsert ) )
215 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
216 }
217 if ( !std::isnan( rasterMaximum ) )
218 {
219 f.setAttributes( QgsAttributes() << rasterMaximum << QStringLiteral( "maximum" ) );
220 f.setGeometry( QgsGeometry::fromPointXY( rasterMaxPoint ) );
221 if ( !sink->addFeature( f, QgsFeatureSink::FastInsert ) )
222 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
223 }
224 outputs.insert( QStringLiteral( "OUTPUT" ), dest );
225 }
226 outputs.insert( QStringLiteral( "MINIMUM" ), !std::isnan( rasterMinimum ) ? QVariant::fromValue( rasterMinimum ) : QVariant() );
227 outputs.insert( QStringLiteral( "MAXIMUM" ), !std::isnan( rasterMaximum ) ? QVariant::fromValue( rasterMaximum ) : QVariant() );
228 return outputs;
229}
230
231
@ VectorPoint
Vector point layers.
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:58
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:53
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:61
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:53
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:70
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:83
A class to represent a 2D point.
Definition qgspointxy.h:60
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