QGIS API Documentation 4.3.0-Master (d3b565c628d)
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(
56 new QgsProcessingParameterEnum( u"EXTRACT"_s, QObject::tr( "Extract extrema" ), QStringList() << QObject::tr( "Minimum and Maximum" ) << QObject::tr( "Minimum" ) << QObject::tr( "Maximum" ), false, 0 )
57 );
58
59 addParameter( new QgsProcessingParameterFeatureSink( u"OUTPUT"_s, QObject::tr( "Output" ), Qgis::ProcessingSourceType::VectorPoint, QVariant(), true, true ) );
60
61 addOutput( new QgsProcessingOutputNumber( u"MINIMUM"_s, QObject::tr( "Minimum" ) ) );
62 addOutput( new QgsProcessingOutputNumber( u"MAXIMUM"_s, QObject::tr( "Maximum" ) ) );
63}
64
65QString QgsRasterMinMaxAlgorithm::shortHelpString() const
66{
67 return QObject::tr(
68 "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}
73
74QString QgsRasterMinMaxAlgorithm::shortDescription() const
75{
76 return QObject::tr( "Calculates the minimum and maximum pixel in a raster layer." );
77}
78
79QgsRasterMinMaxAlgorithm *QgsRasterMinMaxAlgorithm::createInstance() const
80{
81 return new QgsRasterMinMaxAlgorithm();
82}
83
84bool QgsRasterMinMaxAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
85{
86 QgsRasterLayer *layer = parameterAsRasterLayer( parameters, u"INPUT"_s, context );
87
88 if ( !layer )
89 throw QgsProcessingException( invalidRasterError( parameters, u"INPUT"_s ) );
90
91 mBand = parameterAsInt( parameters, u"BAND"_s, context );
92 if ( mBand < 1 || mBand > layer->bandCount() )
93 throw QgsProcessingException( QObject::tr( "Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand ).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 QGS_MARK_ALGORITHM_SOURCE
109
110 QString dest;
111 std::unique_ptr<QgsFeatureSink> sink;
112 if ( parameters.value( u"OUTPUT"_s ).isValid() )
113 {
114 QgsFields outFields;
115 outFields.append( QgsField( u"value"_s, QMetaType::Type::Double, QString(), 20, 8 ) );
116 outFields.append( QgsField( u"extremum_type"_s, QMetaType::Type::QString ) );
117 sink.reset( parameterAsSink( parameters, u"OUTPUT"_s, context, dest, outFields, Qgis::WkbType::Point, mCrs ) );
118 if ( !sink )
119 throw QgsProcessingException( invalidSinkError( parameters, u"OUTPUT"_s ) );
120 }
121
122 const int extractType = parameterAsInt( parameters, u"EXTRACT"_s, context );
123
124 QgsRasterIterator iter( mInterface.get() );
125 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
126
127 int iterLeft = 0;
128 int iterTop = 0;
129 int iterCols = 0;
130 int iterRows = 0;
131 std::unique_ptr<QgsRasterBlock> rasterBlock;
132
133 double rasterMinimum = std::numeric_limits<double>::quiet_NaN();
134 double rasterMaximum = std::numeric_limits<double>::quiet_NaN();
135 QgsPointXY rasterMinPoint;
136 QgsPointXY rasterMaxPoint;
137
138 auto blockRowColToXY = [this]( const QgsRectangle &blockExtent, int row, int col ) -> QgsPointXY {
139 return QgsPointXY( blockExtent.xMinimum() + mRasterUnitsPerPixelX * ( col + 0.5 ), 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 f.setAttributes( QgsAttributes() << rasterMinimum << u"minimum"_s );
212 f.setGeometry( QgsGeometry::fromPointXY( rasterMinPoint ) );
213 if ( !sink->addFeature( f, QgsFeatureSink::FastInsert ) )
214 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, u"OUTPUT"_s ) );
215 else
216 feedback->featureAddedToSink( u"OUTPUT"_s );
217 }
218 if ( !std::isnan( rasterMaximum ) )
219 {
220 f.setAttributes( QgsAttributes() << rasterMaximum << u"maximum"_s );
221 f.setGeometry( QgsGeometry::fromPointXY( rasterMaxPoint ) );
222 if ( !sink->addFeature( f, QgsFeatureSink::FastInsert ) )
223 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, u"OUTPUT"_s ) );
224 else
225 feedback->featureAddedToSink( u"OUTPUT"_s );
226 }
227 sink->finalize();
228 feedback->featureSinkFinalized( u"OUTPUT"_s );
229 outputs.insert( u"OUTPUT"_s, dest );
230 }
231 outputs.insert( u"MINIMUM"_s, !std::isnan( rasterMinimum ) ? QVariant::fromValue( rasterMinimum ) : QVariant() );
232 outputs.insert( u"MAXIMUM"_s, !std::isnan( rasterMaximum ) ? QVariant::fromValue( rasterMaximum ) : QVariant() );
233 return outputs;
234}
235
236
@ VectorPoint
Vector point layers.
Definition qgis.h:3750
@ Point
Point.
Definition qgis.h:296
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:56
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:65
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:56
Container of fields for a vector layer.
Definition qgsfields.h:45
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
Definition qgsfields.cpp:75
static QgsGeometry fromPointXY(const QgsPointXY &point)
Creates a new geometry from a QgsPointXY object.
virtual Q_INVOKABLE 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.
void featureAddedToSink(const QString &output)
Reports that a feature was added to the the sink associated with the specified algorithm output.
void featureSinkFinalized(const QString &output)
Reports that a feature sink has been finalized.
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