33using namespace Qt::StringLiterals;
38 rasterLayer ? rasterLayer->dataProvider() : nullptr,
40 rasterLayer ? rasterLayer->rasterUnitsPerPixelX() : 0,
41 rasterLayer ? rasterLayer->rasterUnitsPerPixelY() : 0,
45 overwriteExistingFields
53 double rasterUnitsPerPixelX,
54 double rasterUnitsPerPixelY,
55 const QString &attributePrefix,
58 bool overwriteExistingFields
60 : mRasterInterface( rasterInterface )
61 , mRasterCrs( rasterCrs )
62 , mCellSizeX( std::fabs( rasterUnitsPerPixelX ) )
63 , mCellSizeY( std::fabs( rasterUnitsPerPixelY ) )
64 , mRasterBand( rasterBand )
65 , mPolygonLayer( polygonLayer )
66 , mAttributePrefix( attributePrefix )
67 , mStatistics( stats )
68 , mOverwriteExistingFields( overwriteExistingFields )
73 if ( !mRasterInterface )
78 if ( mRasterInterface->bandCount() < mRasterBand )
89 if ( !vectorProvider )
94 QMap<Qgis::ZonalStatistic, int> statFieldIndexes;
97 int oldFieldCount = vectorProvider->
fields().
count();
98 QList<QgsField> newFieldList;
113 if ( mStatistics & stat )
118 if ( mOverwriteExistingFields && targetIndex != -1 )
120 statFieldIndexes.insert( stat, targetIndex );
124 if ( mOverwriteExistingFields && targetIndex == -1 )
129 QString fieldName = getUniqueFieldName( targetFieldName, newFieldList );
130 QgsField field( fieldName, QMetaType::Type::Double, u
"double precision"_s );
131 newFieldList.push_back( field );
132 statFieldIndexes.insert( stat, oldFieldCount + newFieldList.count() - 1 );
148 int featureCounter = 0;
161 feedback->
setProgress( 100.0 *
static_cast<double>( featureCounter ) / featureCount );
166 QMap<Qgis::ZonalStatistic, QVariant> results =
calculateStatistics( mRasterInterface, featureGeometry, mCellSizeX, mCellSizeY, mRasterBand, mStatistics );
168 if ( results.empty() )
172 for (
const auto &result : results.toStdMap() )
174 changeAttributeMap.insert( statFieldIndexes.value( result.first ), result.second );
177 changeMap.insert( feature.
id(), changeAttributeMap );
181 mPolygonLayer->updateFields();
194QString QgsZonalStatistics::getUniqueFieldName(
const QString &fieldName,
const QList<QgsField> &newFields )
197 const bool isShapefile = provider->
storageType().contains(
"ESRI Shapefile"_L1 );
199 QList<QgsField> allFields = provider->
fields().
toList();
200 allFields.append( newFields );
202 QString baseName = isShapefile ? fieldName.mid( 0, 10 ) : fieldName;
204 auto fieldExists = [&allFields](
const QString &name ) ->
bool {
205 for (
const QgsField &field : std::as_const( allFields ) )
207 if ( field.name().compare( name, Qt::CaseSensitivity::CaseSensitive ) == 0 )
215 if ( !fieldExists( baseName ) )
226 newName = u
"%1_%2"_s.arg( fieldName.mid( 0, n < 9 ? 8 : 7 ) ).arg( n );
230 newName = u
"%1_%2"_s.arg( fieldName ).arg( n );
233 if ( !fieldExists( newName ) )
245 return QObject::tr(
"Count" );
247 return QObject::tr(
"Sum" );
249 return QObject::tr(
"Mean" );
251 return QObject::tr(
"Median" );
253 return QObject::tr(
"St dev" );
255 return QObject::tr(
"Minimum" );
257 return QObject::tr(
"Maximum" );
259 return QObject::tr(
"Minimum point" );
261 return QObject::tr(
"Maximum point" );
263 return QObject::tr(
"Range" );
265 return QObject::tr(
"Minority" );
267 return QObject::tr(
"Majority" );
269 return QObject::tr(
"Variety" );
271 return QObject::tr(
"Variance" );
298 return u
"minpoint"_s;
300 return u
"maxpoint"_s;
304 return u
"minority"_s;
306 return u
"majority"_s;
310 return u
"variance"_s;
319QMap<int, QVariant> QgsZonalStatistics::calculateStatisticsInt(
324 QMap<int, QVariant> pyResult;
325 for (
auto it = result.constBegin(); it != result.constEnd(); ++it )
327 pyResult.insert(
static_cast<int>( it.key() ), it.value() );
337 QMap<Qgis::ZonalStatistic, QVariant> results;
352 FeatureStats featureStats( statsStoreValues, statsStoreValueCount );
354 int nCellsXProvider = rasterInterface->
xSize();
355 int nCellsYProvider = rasterInterface->
ySize();
357 int nCellsX, nCellsY;
359 QgsRasterAnalysisUtils::cellInfoForBBox( rasterBBox, featureRect, cellSizeX, cellSizeY, nCellsX, nCellsY, nCellsXProvider, nCellsYProvider, rasterBlockExtent );
361 featureStats.reset();
362 QgsRasterAnalysisUtils::statisticsFromMiddlePointTest( rasterInterface, rasterBand, geometry, nCellsX, nCellsY, cellSizeX, cellSizeY, rasterBlockExtent, [&featureStats](
double value,
const QgsPointXY &point ) {
363 featureStats.addValue( value, point );
366 if ( featureStats.count <= 1 )
369 featureStats.reset();
370 QgsRasterAnalysisUtils::
371 statisticsFromPreciseIntersection( rasterInterface, rasterBand, geometry, nCellsX, nCellsY, cellSizeX, cellSizeY, rasterBlockExtent, [&featureStats](
double value,
double weight,
const QgsPointXY &point ) {
372 featureStats.addValue( value, point, weight );
382 if ( featureStats.count > 0 )
384 double mean = featureStats.sum / featureStats.count;
389 std::sort( featureStats.values.begin(), featureStats.values.end() );
390 int size = featureStats.values.count();
391 bool even = ( size % 2 ) < 1;
395 medianValue = ( featureStats.values.at( size / 2 - 1 ) + featureStats.values.at( size / 2 ) ) / 2;
399 medianValue = featureStats.values.at( ( size + 1 ) / 2 - 1 );
405 double sumSquared = 0;
406 for (
int i = 0; i < featureStats.values.count(); ++i )
408 double diff = featureStats.values.at( i ) - mean;
409 sumSquared += diff * diff;
411 double variance = sumSquared / featureStats.values.count();
414 double stdev = std::pow( variance, 0.5 );
432 int64_t lowestCount = std::numeric_limits<int64_t>::max();
433 int64_t highestCount = 0;
434 double valueWithLowestCount = 0;
435 double valueWithHighestCount = 0;
436 for (
auto [value, count] : std::as_const( featureStats.valueCount ) )
438 if ( count < lowestCount )
441 valueWithLowestCount = value;
443 if ( count > highestCount )
445 highestCount = count;
446 valueWithHighestCount = value;
ZonalStatistic
Statistics to be calculated during a zonal statistics operation.
@ StDev
Standard deviation of pixel values.
@ Mean
Mean of pixel values.
@ Median
Median of pixel values.
@ Max
Max of pixel values.
@ Variance
Variance of pixel values.
@ MinimumPoint
Pixel centroid for minimum pixel value.
@ Min
Min of pixel values.
@ Default
Default statistics.
@ Range
Range of pixel values (max - min).
@ Sum
Sum of pixel values.
@ Minority
Minority of pixel values.
@ All
All statistics. For QGIS 3.x this includes ONLY numeric statistics, but for 4.0 this will be extended...
@ Majority
Majority of pixel values.
@ Variety
Variety (count of distinct) pixel values.
@ MaximumPoint
Pixel centroid for maximum pixel value.
@ Warning
Warning message.
ZonalStatisticResult
Zonal statistics result codes.
@ Canceled
Algorithm was canceled.
@ LayerTypeWrong
Layer is not a polygon layer.
@ RasterBandInvalid
The raster band does not exist on the raster layer.
@ RasterInvalid
Raster layer is invalid.
@ LayerInvalid
Layer is invalid.
QFlags< ZonalStatistic > ZonalStatistics
Statistics to be calculated during a zonal statistics operation.
Represents a coordinate reference system (CRS).
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature's geometries.
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
Encapsulate a field in an attribute table or data source.
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Q_INVOKABLE int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
A geometry is the spatial representation of a feature.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
static QgsProject * instance()
Returns the QgsProject singleton instance.
Base class for processing filters like renderers, reprojector, resampler etc.
virtual int xSize() const
Gets raster size.
virtual int ySize() const
virtual QgsRectangle extent() const
Gets the extent of the interface.
Represents a raster layer.
A rectangle specified with double values.
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
Base class for vector data providers.
long long featureCount() const override=0
Number of features in the layer.
virtual QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
virtual bool changeAttributeValues(const QgsChangedAttributesMap &attr_map)
Changes attribute values of existing features.
QgsFields fields() const override=0
Returns the fields associated with this data provider.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const override=0
Query the provider for features specified in request.
virtual bool addAttributes(const QList< QgsField > &attributes)
Adds new attributes to the provider.
Represents a vector layer which manages a vector based dataset.
QgsVectorDataProvider * dataProvider() final
Returns the layer's data provider, it may be nullptr.
Qgis::ZonalStatisticResult calculateStatistics(QgsFeedback *feedback)
Runs the calculation.
static QString displayName(Qgis::ZonalStatistic statistic)
Returns the friendly display name for a statistic.
QgsZonalStatistics(QgsVectorLayer *polygonLayer, QgsRasterLayer *rasterLayer, const QString &attributePrefix=QString(), int rasterBand=1, Qgis::ZonalStatistics stats=Qgis::ZonalStatistic::Default, bool overwriteExistingFields=false)
Convenience constructor for QgsZonalStatistics, using an input raster layer.
static QString shortName(Qgis::ZonalStatistic statistic)
Returns a short, friendly display name for a statistic, suitable for use in a field name.
QMap< int, QVariant > QgsAttributeMap
QMap< QgsFeatureId, QgsAttributeMap > QgsChangedAttributesMap