24 #include "cpl_string.h" 25 #include <QProgressDialog> 28 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800 29 #define TO8F(x) (x).toUtf8().constData() 31 #define TO8F(x) QFile::encodeName( x ).constData() 35 : mRasterFilePath( rasterFile )
36 , mRasterBand( rasterBand )
37 , mPolygonLayer( polygonLayer )
38 , mAttributePrefix( attributePrefix )
39 , mInputNodataValue( -1 )
40 , mStatistics( stats )
47 , mPolygonLayer(
nullptr )
48 , mInputNodataValue( -1 )
62 if ( !vectorProvider )
69 GDALDatasetH inputDataset = GDALOpen(
TO8F( mRasterFilePath ), GA_ReadOnly );
75 if ( GDALGetRasterCount( inputDataset ) < ( mRasterBand - 1 ) )
77 GDALClose( inputDataset );
81 GDALRasterBandH rasterBand = GDALGetRasterBand( inputDataset, mRasterBand );
84 GDALClose( inputDataset );
87 mInputNodataValue = GDALGetRasterNoDataValue( rasterBand,
nullptr );
90 int nCellsXGDAL = GDALGetRasterXSize( inputDataset );
91 int nCellsYGDAL = GDALGetRasterYSize( inputDataset );
92 double geoTransform[6];
93 if ( GDALGetGeoTransform( inputDataset, geoTransform ) != CE_None )
95 GDALClose( inputDataset );
98 double cellsizeX = geoTransform[1];
101 cellsizeX = -cellsizeX;
103 double cellsizeY = geoTransform[5];
106 cellsizeY = -cellsizeY;
108 QgsRectangle rasterBBox( geoTransform[0], geoTransform[3] - ( nCellsYGDAL * cellsizeY ),
109 geoTransform[0] + ( nCellsXGDAL * cellsizeX ), geoTransform[3] );
116 countFieldName = getUniqueFieldName( mAttributePrefix +
"count" );
117 QgsField countField( countFieldName, QVariant::Double,
"double precision" );
123 sumFieldName = getUniqueFieldName( mAttributePrefix +
"sum" );
124 QgsField sumField( sumFieldName, QVariant::Double,
"double precision" );
130 meanFieldName = getUniqueFieldName( mAttributePrefix +
"mean" );
131 QgsField meanField( meanFieldName, QVariant::Double,
"double precision" );
137 medianFieldName = getUniqueFieldName( mAttributePrefix +
"median" );
138 QgsField medianField( medianFieldName, QVariant::Double,
"double precision" );
144 stdevFieldName = getUniqueFieldName( mAttributePrefix +
"stdev" );
145 QgsField stdField( stdevFieldName, QVariant::Double,
"double precision" );
151 minFieldName = getUniqueFieldName( mAttributePrefix +
"min" );
152 QgsField minField( minFieldName, QVariant::Double,
"double precision" );
158 maxFieldName = getUniqueFieldName( mAttributePrefix +
"max" );
159 QgsField maxField( maxFieldName, QVariant::Double,
"double precision" );
165 rangeFieldName = getUniqueFieldName( mAttributePrefix +
"range" );
166 QgsField rangeField( rangeFieldName, QVariant::Double,
"double precision" );
172 minorityFieldName = getUniqueFieldName( mAttributePrefix +
"minority" );
173 QgsField minorityField( minorityFieldName, QVariant::Double,
"double precision" );
179 majorityFieldName = getUniqueFieldName( mAttributePrefix +
"majority" );
180 QgsField majField( majorityFieldName, QVariant::Double,
"double precision" );
186 varietyFieldName = getUniqueFieldName( mAttributePrefix +
"variety" );
187 QgsField varietyField( varietyFieldName, QVariant::Int,
"int" );
193 int countIndex = mStatistics & QgsZonalStatistics::Count ? vectorProvider->
fieldNameIndex( countFieldName ) : -1;
194 int sumIndex = mStatistics & QgsZonalStatistics::Sum ? vectorProvider->
fieldNameIndex( sumFieldName ) : -1;
195 int meanIndex = mStatistics & QgsZonalStatistics::Mean ? vectorProvider->
fieldNameIndex( meanFieldName ) : -1;
196 int medianIndex = mStatistics & QgsZonalStatistics::Median ? vectorProvider->
fieldNameIndex( medianFieldName ) : -1;
197 int stdevIndex = mStatistics & QgsZonalStatistics::StDev ? vectorProvider->
fieldNameIndex( stdevFieldName ) : -1;
198 int minIndex = mStatistics & QgsZonalStatistics::Min ? vectorProvider->
fieldNameIndex( minFieldName ) : -1;
199 int maxIndex = mStatistics & QgsZonalStatistics::Max ? vectorProvider->
fieldNameIndex( maxFieldName ) : -1;
200 int rangeIndex = mStatistics & QgsZonalStatistics::Range ? vectorProvider->
fieldNameIndex( rangeFieldName ) : -1;
201 int minorityIndex = mStatistics & QgsZonalStatistics::Minority ? vectorProvider->
fieldNameIndex( minorityFieldName ) : -1;
202 int majorityIndex = mStatistics & QgsZonalStatistics::Majority ? vectorProvider->
fieldNameIndex( majorityFieldName ) : -1;
203 int varietyIndex = mStatistics & QgsZonalStatistics::Variety ? vectorProvider->
fieldNameIndex( varietyFieldName ) : -1;
205 if (( mStatistics & QgsZonalStatistics::Count && countIndex == -1 )
206 || ( mStatistics & QgsZonalStatistics::Sum && sumIndex == -1 )
207 || ( mStatistics & QgsZonalStatistics::Mean && meanIndex == -1 )
208 || ( mStatistics & QgsZonalStatistics::Median && medianIndex == -1 )
209 || ( mStatistics & QgsZonalStatistics::StDev && stdevIndex == -1 )
210 || ( mStatistics & QgsZonalStatistics::Min && minIndex == -1 )
211 || ( mStatistics & QgsZonalStatistics::Max && maxIndex == -1 )
212 || ( mStatistics & QgsZonalStatistics::Range && rangeIndex == -1 )
213 || ( mStatistics & QgsZonalStatistics::Minority && minorityIndex == -1 )
214 || ( mStatistics & QgsZonalStatistics::Majority && majorityIndex == -1 )
215 || ( mStatistics & QgsZonalStatistics::Variety && varietyIndex == -1 )
237 ( mStatistics & QgsZonalStatistics::StDev );
239 ( mStatistics & QgsZonalStatistics::Majority );
241 FeatureStats featureStats( statsStoreValues, statsStoreValueCount );
242 int featureCounter = 0;
271 int offsetX, offsetY, nCellsX, nCellsY;
272 if ( cellInfoForBBox( rasterBBox, featureRect, cellsizeX, cellsizeY, offsetX, offsetY, nCellsX, nCellsY ) != 0 )
279 if (( offsetX + nCellsX ) > nCellsXGDAL )
281 nCellsX = nCellsXGDAL - offsetX;
283 if (( offsetY + nCellsY ) > nCellsYGDAL )
285 nCellsY = nCellsYGDAL - offsetY;
288 statisticsFromMiddlePointTest( rasterBand, featureGeometry, offsetX, offsetY, nCellsX, nCellsY, cellsizeX, cellsizeY,
289 rasterBBox, featureStats );
291 if ( featureStats.count <= 1 )
294 statisticsFromPreciseIntersection( rasterBand, featureGeometry, offsetX, offsetY, nCellsX, nCellsY, cellsizeX, cellsizeY,
295 rasterBBox, featureStats );
300 if ( mStatistics & QgsZonalStatistics::Count )
301 changeAttributeMap.
insert( countIndex,
QVariant( featureStats.count ) );
302 if ( mStatistics & QgsZonalStatistics::Sum )
303 changeAttributeMap.
insert( sumIndex,
QVariant( featureStats.sum ) );
304 if ( featureStats.count > 0 )
306 double mean = featureStats.sum / featureStats.count;
307 if ( mStatistics & QgsZonalStatistics::Mean )
309 if ( mStatistics & QgsZonalStatistics::Median )
311 qSort( featureStats.values.begin(), featureStats.values.end() );
312 int size = featureStats.values.count();
313 bool even = ( size % 2 ) < 1;
317 medianValue = ( featureStats.values.at( size / 2 - 1 ) + featureStats.values.at( size / 2 ) ) / 2;
321 medianValue = featureStats.values.at(( size + 1 ) / 2 - 1 );
323 changeAttributeMap.
insert( medianIndex,
QVariant( medianValue ) );
325 if ( mStatistics & QgsZonalStatistics::StDev )
327 double sumSquared = 0;
328 for (
int i = 0; i < featureStats.values.count(); ++i )
330 double diff = featureStats.values.at( i ) - mean;
331 sumSquared += diff * diff;
333 double stdev = qPow( sumSquared / featureStats.values.count(), 0.5 );
336 if ( mStatistics & QgsZonalStatistics::Min )
337 changeAttributeMap.
insert( minIndex,
QVariant( featureStats.min ) );
338 if ( mStatistics & QgsZonalStatistics::Max )
339 changeAttributeMap.
insert( maxIndex,
QVariant( featureStats.max ) );
340 if ( mStatistics & QgsZonalStatistics::Range )
341 changeAttributeMap.
insert( rangeIndex,
QVariant( featureStats.max - featureStats.min ) );
342 if ( mStatistics & QgsZonalStatistics::Minority || mStatistics & QgsZonalStatistics::Majority )
344 QList<int> vals = featureStats.valueCount.values();
346 if ( mStatistics & QgsZonalStatistics::Minority )
348 float minorityKey = featureStats.valueCount.key( vals.
first() );
349 changeAttributeMap.
insert( minorityIndex,
QVariant( minorityKey ) );
351 if ( mStatistics & QgsZonalStatistics::Majority )
353 float majKey = featureStats.valueCount.key( vals.
last() );
357 if ( mStatistics & QgsZonalStatistics::Variety )
358 changeAttributeMap.
insert( varietyIndex,
QVariant( featureStats.valueCount.count() ) );
361 changeMap.
insert( f.
id(), changeAttributeMap );
372 GDALClose( inputDataset );
383 int QgsZonalStatistics::cellInfoForBBox(
const QgsRectangle& rasterBBox,
const QgsRectangle& featureBBox,
double cellSizeX,
double cellSizeY,
384 int& offsetX,
int& offsetY,
int& nCellsX,
int& nCellsY )
const 398 offsetX = ( int )(( intersectBox.
xMinimum() - rasterBBox.
xMinimum() ) / cellSizeX );
399 offsetY = ( int )(( rasterBBox.
yMaximum() - intersectBox.
yMaximum() ) / cellSizeY );
401 int maxColumn = ( int )(( intersectBox.
xMaximum() - rasterBBox.
xMinimum() ) / cellSizeX ) + 1;
402 int maxRow = ( int )(( rasterBBox.
yMaximum() - intersectBox.
yMinimum() ) / cellSizeY ) + 1;
404 nCellsX = maxColumn - offsetX;
405 nCellsY = maxRow - offsetY;
410 void QgsZonalStatistics::statisticsFromMiddlePointTest(
void* band,
const QgsGeometry* poly,
int pixelOffsetX,
411 int pixelOffsetY,
int nCellsX,
int nCellsY,
double cellSizeX,
double cellSizeY,
const QgsRectangle& rasterBBox, FeatureStats &stats )
413 double cellCenterX, cellCenterY;
415 float* scanLine = (
float * ) CPLMalloc(
sizeof(
float ) * nCellsX );
416 cellCenterY = rasterBBox.
yMaximum() - pixelOffsetY * cellSizeY - cellSizeY / 2;
419 const GEOSGeometry* polyGeos = poly->
asGeos();
426 const GEOSPreparedGeometry* polyGeosPrepared = GEOSPrepare_r( geosctxt, poly->
asGeos() );
427 if ( !polyGeosPrepared )
432 GEOSCoordSequence* cellCenterCoords =
nullptr;
433 GEOSGeometry* currentCellCenter =
nullptr;
435 for (
int i = 0; i < nCellsY; ++i )
437 if ( GDALRasterIO( band, GF_Read, pixelOffsetX, pixelOffsetY + i, nCellsX, 1, scanLine, nCellsX, 1, GDT_Float32, 0, 0 )
442 cellCenterX = rasterBBox.
xMinimum() + pixelOffsetX * cellSizeX + cellSizeX / 2;
443 for (
int j = 0; j < nCellsX; ++j )
445 if ( validPixel( scanLine[j] ) )
447 GEOSGeom_destroy_r( geosctxt, currentCellCenter );
448 cellCenterCoords = GEOSCoordSeq_create_r( geosctxt, 1, 2 );
449 GEOSCoordSeq_setX_r( geosctxt, cellCenterCoords, 0, cellCenterX );
450 GEOSCoordSeq_setY_r( geosctxt, cellCenterCoords, 0, cellCenterY );
451 currentCellCenter = GEOSGeom_createPoint_r( geosctxt, cellCenterCoords );
452 if ( GEOSPreparedContains_r( geosctxt, polyGeosPrepared, currentCellCenter ) )
454 stats.addValue( scanLine[j] );
457 cellCenterX += cellSizeX;
459 cellCenterY -= cellSizeY;
461 GEOSGeom_destroy_r( geosctxt, currentCellCenter );
463 GEOSPreparedGeom_destroy_r( geosctxt, polyGeosPrepared );
466 void QgsZonalStatistics::statisticsFromPreciseIntersection(
void* band,
const QgsGeometry* poly,
int pixelOffsetX,
467 int pixelOffsetY,
int nCellsX,
int nCellsY,
double cellSizeX,
double cellSizeY,
const QgsRectangle& rasterBBox, FeatureStats &stats )
471 double currentY = rasterBBox.
yMaximum() - pixelOffsetY * cellSizeY - cellSizeY / 2;
472 float* pixelData = (
float * ) CPLMalloc(
sizeof(
float ) );
475 double hCellSizeX = cellSizeX / 2.0;
476 double hCellSizeY = cellSizeY / 2.0;
477 double pixelArea = cellSizeX * cellSizeY;
480 for (
int row = 0; row < nCellsY; ++row )
482 double currentX = rasterBBox.
xMinimum() + cellSizeX / 2.0 + pixelOffsetX * cellSizeX;
483 for (
int col = 0; col < nCellsX; ++col )
485 if ( GDALRasterIO( band, GF_Read, pixelOffsetX + col, pixelOffsetY + row, nCellsX, 1, pixelData, 1, 1, GDT_Float32, 0, 0 ) != CE_None )
490 if ( !validPixel( *pixelData ) )
494 if ( pixelRectGeometry )
498 if ( intersectGeometry )
500 double intersectionArea = intersectGeometry->
area();
501 if ( intersectionArea >= 0.0 )
503 weight = intersectionArea / pixelArea;
504 stats.addValue( *pixelData, weight );
506 delete intersectGeometry;
508 delete pixelRectGeometry;
509 pixelRectGeometry =
nullptr;
511 currentX += cellSizeX;
513 currentY -= cellSizeY;
515 CPLFree( pixelData );
518 bool QgsZonalStatistics::validPixel(
float value )
const 520 if ( value == mInputNodataValue || qIsNaN( value ) )
527 QString QgsZonalStatistics::getUniqueFieldName(
const QString& fieldName )
540 for (
int idx = 0; idx < providerFields.
count(); ++idx )
542 if ( shortName == providerFields[idx].name() )
555 shortName =
QString(
"%1_%2" ).
arg( fieldName.
mid( 0, 8 ) ).arg( n );
560 for (
int idx = 0; idx < providerFields.
count(); ++idx )
562 if ( shortName == providerFields[idx].name() )
567 shortName =
QString(
"%1_%2" ).
arg( fieldName.
mid( 0, 8 ) ).arg( n );
571 shortName =
QString(
"%1_%2" ).
arg( fieldName.
mid( 0, 7 ) ).arg( n );
void updateFields()
Assembles mUpdatedFields considering provider fields, joined fields and added fields.
Wrapper for iterator of features from vector data provider or vector layer.
A rectangle specified with double values.
virtual bool addAttributes(const QList< QgsField > &attributes)
Adds new attributes.
void setMaximum(int maximum)
void push_back(const T &value)
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Container of fields for a vector layer.
A geometry is the spatial representation of a feature.
QgsRectangle intersect(const QgsRectangle *rect) const
return the intersection with the given rectangle
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
int count() const
Return number of items.
Minority of pixel values.
Variety (count of distinct) pixel values.
void setValue(int progress)
bool isEmpty() const
test if rectangle is empty.
virtual bool changeAttributeValues(const QgsChangedAttributesMap &attr_map)
Changes attribute values of existing features.
virtual long featureCount() const =0
Number of features in the layer.
Majority of pixel values.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QList< int > QgsAttributeList
int fieldNameIndex(const QString &fieldName) const
Returns the index of a field name or -1 if the field does not exist.
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())=0
Query the provider for features specified in request.
QGis::GeometryType geometryType() const
Returns point, line or polygon.
Encapsulate a field in an attribute table or data source.
QgsFeatureId id() const
Get the feature ID for this feature.
bool contains(QChar ch, Qt::CaseSensitivity cs) const
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
double xMaximum() const
Get the x maximum value (right side of rectangle)
Range of pixel values (max - min)
virtual const QgsFields & fields() const =0
Return a map of indexes with field names for this layer.
int calculateStatistics(QProgressDialog *p)
Starts the calculation.
QString mid(int position, int n) const
static GEOSContextHandle_t getGEOSHandler()
Return GEOS context handle.
const GEOSGeometry * asGeos(double precision=0) const
Returns a geos geometry.
QgsRectangle boundingBox() const
Returns the bounding box of this feature.
QgsGeometry * intersection(const QgsGeometry *geometry) const
Returns a geometry representing the points shared by this geometry and other.
static QgsGeometry * fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
double xMinimum() const
Get the x minimum value (left side of rectangle)
double yMaximum() const
Get the y maximum value (top side of rectangle)
iterator insert(const Key &key, const T &value)
virtual QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
QgsZonalStatistics(QgsVectorLayer *polygonLayer, const QString &rasterFile, const QString &attributePrefix="", int rasterBand=1, const Statistics &stats=Statistics(Count|Sum|Mean))
double area() const
Returns the area of the geometry using GEOS.
QgsVectorDataProvider * dataProvider()
Returns the data provider.
bool nextFeature(QgsFeature &f)
This is the base class for vector data providers.
Represents a vector layer which manages a vector based data sets.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
Standard deviation of pixel values.