Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsalgorithmzonalstatisticsfeaturebased.cpp
3 : : ---------------------
4 : : begin : September 2020
5 : : copyright : (C) 2020 by Matthias Kuhn
6 : : email : matthias@opengis.ch
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 : :
18 : : #include "qgsalgorithmzonalstatisticsfeaturebased.h"
19 : :
20 : : ///@cond PRIVATE
21 : :
22 : 2 : const std::vector< QgsZonalStatistics::Statistic > STATS
23 : 2 : {
24 : : QgsZonalStatistics::Count,
25 : : QgsZonalStatistics::Sum,
26 : : QgsZonalStatistics::Mean,
27 : : QgsZonalStatistics::Median,
28 : : QgsZonalStatistics::StDev,
29 : : QgsZonalStatistics::Min,
30 : : QgsZonalStatistics::Max,
31 : : QgsZonalStatistics::Range,
32 : : QgsZonalStatistics::Minority,
33 : : QgsZonalStatistics::Majority,
34 : : QgsZonalStatistics::Variety,
35 : : QgsZonalStatistics::Variance,
36 : : };
37 : :
38 : 0 : QString QgsZonalStatisticsFeatureBasedAlgorithm::name() const
39 : : {
40 : 0 : return QStringLiteral( "zonalstatisticsfb" );
41 : : }
42 : :
43 : 0 : QString QgsZonalStatisticsFeatureBasedAlgorithm::displayName() const
44 : : {
45 : 0 : return QObject::tr( "Zonal statistics" );
46 : : }
47 : :
48 : 0 : QStringList QgsZonalStatisticsFeatureBasedAlgorithm::tags() const
49 : : {
50 : 0 : return QObject::tr( "stats,statistics,zones,layer,sum,maximum,minimum,mean,count,standard,deviation,"
51 : 0 : "median,range,majority,minority,variety,variance,summary,raster" ).split( ',' );
52 : 0 : }
53 : :
54 : 0 : QString QgsZonalStatisticsFeatureBasedAlgorithm::group() const
55 : : {
56 : 0 : return QObject::tr( "Raster analysis" );
57 : : }
58 : :
59 : 0 : QString QgsZonalStatisticsFeatureBasedAlgorithm::groupId() const
60 : : {
61 : 0 : return QStringLiteral( "rasteranalysis" );
62 : : }
63 : :
64 : 0 : QString QgsZonalStatisticsFeatureBasedAlgorithm::shortHelpString() const
65 : : {
66 : 0 : return QObject::tr( "This algorithm calculates statistics of a raster layer for each feature "
67 : : "of an overlapping polygon vector layer." );
68 : : }
69 : :
70 : 0 : QList<int> QgsZonalStatisticsFeatureBasedAlgorithm::inputLayerTypes() const
71 : : {
72 : 0 : return QList<int>() << QgsProcessing::TypeVectorPolygon;
73 : 0 : }
74 : :
75 : 0 : QgsZonalStatisticsFeatureBasedAlgorithm *QgsZonalStatisticsFeatureBasedAlgorithm::createInstance() const
76 : : {
77 : 0 : return new QgsZonalStatisticsFeatureBasedAlgorithm();
78 : 0 : }
79 : :
80 : 0 : void QgsZonalStatisticsFeatureBasedAlgorithm::initParameters( const QVariantMap &configuration )
81 : : {
82 : 0 : Q_UNUSED( configuration )
83 : 0 : QStringList statChoices;
84 : 0 : statChoices.reserve( STATS.size() );
85 : 0 : for ( QgsZonalStatistics::Statistic stat : STATS )
86 : : {
87 : 0 : statChoices << QgsZonalStatistics::displayName( stat );
88 : : }
89 : :
90 : 0 : addParameter( new QgsProcessingParameterRasterLayer( QStringLiteral( "INPUT_RASTER" ), QObject::tr( "Raster layer" ) ) );
91 : 0 : addParameter( new QgsProcessingParameterBand( QStringLiteral( "RASTER_BAND" ),
92 : 0 : QObject::tr( "Raster band" ), 1, QStringLiteral( "INPUT_RASTER" ) ) );
93 : :
94 : 0 : addParameter( new QgsProcessingParameterString( QStringLiteral( "COLUMN_PREFIX" ), QObject::tr( "Output column prefix" ), QStringLiteral( "_" ) ) );
95 : :
96 : 0 : addParameter( new QgsProcessingParameterEnum( QStringLiteral( "STATISTICS" ), QObject::tr( "Statistics to calculate" ),
97 : 0 : statChoices, true, QVariantList() << 0 << 1 << 2 ) );
98 : 0 : }
99 : :
100 : 0 : QString QgsZonalStatisticsFeatureBasedAlgorithm::outputName() const
101 : : {
102 : 0 : return QObject::tr( "Zonal Statistics" );
103 : : }
104 : :
105 : 0 : QgsFields QgsZonalStatisticsFeatureBasedAlgorithm::outputFields( const QgsFields &inputFields ) const
106 : : {
107 : 0 : Q_UNUSED( inputFields )
108 : 0 : return mOutputFields;
109 : : }
110 : :
111 : 0 : bool QgsZonalStatisticsFeatureBasedAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * )
112 : : {
113 : 0 : mPrefix = parameterAsString( parameters, QStringLiteral( "COLUMN_PREFIX" ), context );
114 : :
115 : 0 : const QList< int > stats = parameterAsEnums( parameters, QStringLiteral( "STATISTICS" ), context );
116 : 0 : mStats = QgsZonalStatistics::Statistics();
117 : 0 : for ( int s : stats )
118 : : {
119 : 0 : mStats |= STATS.at( s );
120 : : }
121 : :
122 : 0 : QgsRasterLayer *rasterLayer = parameterAsRasterLayer( parameters, QStringLiteral( "INPUT_RASTER" ), context );
123 : 0 : if ( !rasterLayer )
124 : 0 : throw QgsProcessingException( invalidRasterError( parameters, QStringLiteral( "INPUT_RASTER" ) ) );
125 : :
126 : 0 : mBand = parameterAsInt( parameters, QStringLiteral( "RASTER_BAND" ), context );
127 : 0 : if ( mBand < 1 || mBand > rasterLayer->bandCount() )
128 : 0 : throw QgsProcessingException( QObject::tr( "Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand )
129 : 0 : .arg( rasterLayer->bandCount() ) );
130 : :
131 : 0 : if ( !rasterLayer->dataProvider() )
132 : 0 : throw QgsProcessingException( QObject::tr( "Invalid raster layer. Layer %1 is invalid." ).arg( rasterLayer->id() ) );
133 : :
134 : 0 : mRaster.reset( rasterLayer->dataProvider()->clone() );
135 : 0 : mCrs = rasterLayer->crs();
136 : 0 : mPixelSizeX = rasterLayer->rasterUnitsPerPixelX();
137 : 0 : mPixelSizeY = rasterLayer->rasterUnitsPerPixelY();
138 : 0 : std::unique_ptr<QgsFeatureSource> source( parameterAsSource( parameters, inputParameterName(), context ) );
139 : :
140 : 0 : mOutputFields = source->fields();
141 : :
142 : 0 : for ( QgsZonalStatistics::Statistic stat : STATS )
143 : : {
144 : 0 : if ( mStats & stat )
145 : : {
146 : 0 : QgsField field = QgsField( mPrefix + QgsZonalStatistics::shortName( stat ), QVariant::Double, QStringLiteral( "double precision" ) );
147 : 0 : if ( mOutputFields.names().contains( field.name() ) )
148 : : {
149 : 0 : throw QgsProcessingException( QObject::tr( "Field %1 already exists" ).arg( field.name() ) );
150 : : }
151 : 0 : mOutputFields.append( field );
152 : 0 : mStatFieldsMapping.insert( stat, mOutputFields.size() - 1 );
153 : 0 : }
154 : : }
155 : :
156 : : return true;
157 : 0 : }
158 : :
159 : 0 : QgsFeatureList QgsZonalStatisticsFeatureBasedAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
160 : : {
161 : 0 : Q_UNUSED( context )
162 : : Q_UNUSED( feedback )
163 : 0 : QgsAttributes attributes = feature.attributes();
164 : 0 : attributes.resize( mOutputFields.size() );
165 : :
166 : 0 : QMap<QgsZonalStatistics::Statistic, QVariant> results = QgsZonalStatistics::calculateStatistics( mRaster.get(), feature.geometry(), mPixelSizeX, mPixelSizeY, mBand, mStats );
167 : 0 : for ( auto result = results.constBegin(); result != results.constEnd(); ++result )
168 : : {
169 : 0 : attributes.replace( mStatFieldsMapping.value( result.key() ), result.value() );
170 : 0 : }
171 : :
172 : 0 : QgsFeature resultFeature = feature;
173 : 0 : resultFeature.setAttributes( attributes );
174 : :
175 : 0 : return QgsFeatureList { resultFeature };
176 : 0 : }
177 : :
178 : 0 : bool QgsZonalStatisticsFeatureBasedAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const
179 : : {
180 : : Q_UNUSED( layer )
181 : 0 : return false;
182 : : }
183 : :
184 : : ///@endcond
|