23 #include "cpl_string.h" 24 #include <QProgressDialog> 27 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800 28 #define TO8F(x) (x).toUtf8().constData() 30 #define TO8F(x) QFile::encodeName( x ).constData() 34 : mRasterFilePath( rasterFile )
35 , mRasterBand( rasterBand )
36 , mPolygonLayer( polygonLayer )
37 , mAttributePrefix( attributePrefix )
38 , mInputNodataValue( -1 )
46 , mInputNodataValue( -1 )
64 if ( !vectorProvider )
71 GDALDatasetH inputDataset = GDALOpen(
TO8F( mRasterFilePath ), GA_ReadOnly );
72 if ( inputDataset == NULL )
77 if ( GDALGetRasterCount( inputDataset ) < ( mRasterBand - 1 ) )
79 GDALClose( inputDataset );
83 GDALRasterBandH rasterBand = GDALGetRasterBand( inputDataset, mRasterBand );
84 if ( rasterBand == NULL )
86 GDALClose( inputDataset );
89 mInputNodataValue = GDALGetRasterNoDataValue( rasterBand, NULL );
92 int nCellsXGDAL = GDALGetRasterXSize( inputDataset );
93 int nCellsYGDAL = GDALGetRasterYSize( inputDataset );
94 double geoTransform[6];
95 if ( GDALGetGeoTransform( inputDataset, geoTransform ) != CE_None )
97 GDALClose( inputDataset );
100 double cellsizeX = geoTransform[1];
103 cellsizeX = -cellsizeX;
105 double cellsizeY = geoTransform[5];
108 cellsizeY = -cellsizeY;
110 QgsRectangle rasterBBox( geoTransform[0], geoTransform[3] - ( nCellsYGDAL * cellsizeY ),
111 geoTransform[0] + ( nCellsXGDAL * cellsizeX ), geoTransform[3] );
114 QList<QgsField> newFieldList;
115 QString countFieldName = getUniqueFieldName( mAttributePrefix +
"count" );
116 QString sumFieldName = getUniqueFieldName( mAttributePrefix +
"sum" );
117 QString meanFieldName = getUniqueFieldName( mAttributePrefix +
"mean" );
118 QgsField countField( countFieldName, QVariant::Double,
"double precision" );
119 QgsField sumField( sumFieldName, QVariant::Double,
"double precision" );
120 QgsField meanField( meanFieldName, QVariant::Double,
"double precision" );
121 newFieldList.push_back( countField );
122 newFieldList.push_back( sumField );
123 newFieldList.push_back( meanField );
127 int countIndex = vectorProvider->
fieldNameIndex( countFieldName );
131 if ( countIndex == -1 || sumIndex == -1 || meanIndex == -1 )
140 p->setMaximum( featureCount );
152 int featureCounter = 0;
158 p->setValue( featureCounter );
161 if ( p && p->wasCanceled() )
167 if ( !featureGeometry )
180 int offsetX, offsetY, nCellsX, nCellsY;
181 if ( cellInfoForBBox( rasterBBox, featureRect, cellsizeX, cellsizeY, offsetX, offsetY, nCellsX, nCellsY ) != 0 )
188 if (( offsetX + nCellsX ) > nCellsXGDAL )
190 nCellsX = nCellsXGDAL - offsetX;
192 if (( offsetY + nCellsY ) > nCellsYGDAL )
194 nCellsY = nCellsYGDAL - offsetY;
197 statisticsFromMiddlePointTest( rasterBand, featureGeometry, offsetX, offsetY, nCellsX, nCellsY, cellsizeX, cellsizeY,
198 rasterBBox, sum, count );
203 statisticsFromPreciseIntersection( rasterBand, featureGeometry, offsetX, offsetY, nCellsX, nCellsY, cellsizeX, cellsizeY,
204 rasterBBox, sum, count );
220 changeAttributeMap.insert( countIndex, QVariant( count ) );
221 changeAttributeMap.insert( sumIndex, QVariant( sum ) );
222 changeAttributeMap.insert( meanIndex, QVariant( mean ) );
223 changeMap.insert( f.
id(), changeAttributeMap );
231 p->setValue( featureCount );
234 GDALClose( inputDataset );
237 if ( p && p->wasCanceled() )
245 int QgsZonalStatistics::cellInfoForBBox(
const QgsRectangle& rasterBBox,
const QgsRectangle& featureBBox,
double cellSizeX,
double cellSizeY,
246 int& offsetX,
int& offsetY,
int& nCellsX,
int& nCellsY )
const 252 nCellsX = 0; nCellsY = 0; offsetX = 0; offsetY = 0;
257 offsetX = ( int )(( intersectBox.
xMinimum() - rasterBBox.
xMinimum() ) / cellSizeX );
258 offsetY = ( int )(( rasterBBox.
yMaximum() - intersectBox.
yMaximum() ) / cellSizeY );
260 int maxColumn = ( int )(( intersectBox.
xMaximum() - rasterBBox.
xMinimum() ) / cellSizeX ) + 1;
261 int maxRow = ( int )(( rasterBBox.
yMaximum() - intersectBox.
yMinimum() ) / cellSizeY ) + 1;
263 nCellsX = maxColumn - offsetX;
264 nCellsY = maxRow - offsetY;
269 void QgsZonalStatistics::statisticsFromMiddlePointTest(
void* band,
QgsGeometry* poly,
int pixelOffsetX,
270 int pixelOffsetY,
int nCellsX,
int nCellsY,
double cellSizeX,
double cellSizeY,
const QgsRectangle& rasterBBox,
double& sum,
double& count )
272 double cellCenterX, cellCenterY;
274 float* scanLine = (
float * ) CPLMalloc(
sizeof(
float ) * nCellsX );
275 cellCenterY = rasterBBox.
yMaximum() - pixelOffsetY * cellSizeY - cellSizeY / 2;
279 const GEOSGeometry* polyGeos = poly->
asGeos();
286 const GEOSPreparedGeometry* polyGeosPrepared = GEOSPrepare_r( geosctxt, poly->
asGeos() );
287 if ( !polyGeosPrepared )
292 GEOSCoordSequence* cellCenterCoords = 0;
293 GEOSGeometry* currentCellCenter = 0;
295 for (
int i = 0; i < nCellsY; ++i )
297 if ( GDALRasterIO( band, GF_Read, pixelOffsetX, pixelOffsetY + i, nCellsX, 1, scanLine, nCellsX, 1, GDT_Float32, 0, 0 )
302 cellCenterX = rasterBBox.
xMinimum() + pixelOffsetX * cellSizeX + cellSizeX / 2;
303 for (
int j = 0; j < nCellsX; ++j )
305 if ( validPixel( scanLine[j] ) )
307 GEOSGeom_destroy_r( geosctxt, currentCellCenter );
308 cellCenterCoords = GEOSCoordSeq_create_r( geosctxt, 1, 2 );
309 GEOSCoordSeq_setX_r( geosctxt, cellCenterCoords, 0, cellCenterX );
310 GEOSCoordSeq_setY_r( geosctxt, cellCenterCoords, 0, cellCenterY );
311 currentCellCenter = GEOSGeom_createPoint_r( geosctxt, cellCenterCoords );
312 if ( GEOSPreparedContains_r( geosctxt, polyGeosPrepared, currentCellCenter ) )
318 cellCenterX += cellSizeX;
320 cellCenterY -= cellSizeY;
322 GEOSGeom_destroy_r( geosctxt, currentCellCenter );
324 GEOSPreparedGeom_destroy_r( geosctxt, polyGeosPrepared );
327 void QgsZonalStatistics::statisticsFromPreciseIntersection(
void* band,
QgsGeometry* poly,
int pixelOffsetX,
328 int pixelOffsetY,
int nCellsX,
int nCellsY,
double cellSizeX,
double cellSizeY,
const QgsRectangle& rasterBBox,
double& sum,
double& count )
332 double currentY = rasterBBox.
yMaximum() - pixelOffsetY * cellSizeY - cellSizeY / 2;
333 float* pixelData = (
float * ) CPLMalloc(
sizeof(
float ) );
336 double hCellSizeX = cellSizeX / 2.0;
337 double hCellSizeY = cellSizeY / 2.0;
338 double pixelArea = cellSizeX * cellSizeY;
341 for (
int row = 0; row < nCellsY; ++row )
343 double currentX = rasterBBox.
xMinimum() + cellSizeX / 2.0 + pixelOffsetX * cellSizeX;
344 for (
int col = 0; col < nCellsX; ++col )
346 GDALRasterIO( band, GF_Read, pixelOffsetX + col, pixelOffsetY + row, nCellsX, 1, pixelData, 1, 1, GDT_Float32, 0, 0 );
347 if ( !validPixel( *pixelData ) )
351 if ( pixelRectGeometry )
355 if ( intersectGeometry )
357 double intersectionArea = intersectGeometry->
area();
358 if ( intersectionArea >= 0.0 )
360 weight = intersectionArea / pixelArea;
362 sum += *pixelData * weight;
364 delete intersectGeometry;
366 delete pixelRectGeometry;
367 pixelRectGeometry = 0;
369 currentX += cellSizeX;
371 currentY -= cellSizeY;
373 CPLFree( pixelData );
376 bool QgsZonalStatistics::validPixel(
float value )
const 378 if ( value == mInputNodataValue || qIsNaN( value ) )
385 QString QgsZonalStatistics::getUniqueFieldName( QString fieldName )
389 if ( !dp->
storageType().contains(
"ESRI Shapefile" ) )
395 QString shortName = fieldName.mid( 0, 10 );
398 for (
int idx = 0; idx < providerFields.
count(); ++idx )
400 if ( shortName == providerFields[idx].name() )
413 shortName = QString(
"%1_%2" ).arg( fieldName.mid( 0, 8 ) ).arg( n );
418 for (
int idx = 0; idx < providerFields.
count(); ++idx )
420 if ( shortName == providerFields[idx].name() )
425 shortName = QString(
"%1_%2" ).arg( fieldName.mid( 0, 8 ) ).arg( n );
429 shortName = QString(
"%1_%2" ).arg( fieldName.mid( 0, 7 ) ).arg( n );
QgsFeatureId id() const
Get the feature id for this feature.
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.
bool isEmpty() const
test if rectangle is empty.
QMap< int, QVariant > QgsAttributeMap
virtual bool addAttributes(const QList< QgsField > &attributes)
Adds new attributes.
double yMaximum() const
Get the y maximum value (top side of rectangle)
QgsGeometry * geometry() const
Get the geometry object associated with this feature.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Container of fields for a vector layer.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
int fieldNameIndex(const QString &fieldName) const
Returns the index of a field name or -1 if the field does not exist.
double area()
get area of geometry using GEOS
const GEOSGeometry * asGeos() const
Returns a geos geometry.
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
double xMaximum() const
Get the x maximum value (right side of rectangle)
virtual bool changeAttributeValues(const QgsChangedAttributesMap &attr_map)
Changes attribute values of existing features.
virtual QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
virtual long featureCount() const =0
Number of features in the layer.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QList< int > QgsAttributeList
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())=0
Query the provider for features specified in request.
int count() const
Return number of items.
QGis::GeometryType geometryType() const
Returns point, line or polygon.
Encapsulate a field in an attribute table or data source.
QgsZonalStatistics(QgsVectorLayer *polygonLayer, const QString &rasterFile, const QString &attributePrefix="", int rasterBand=1)
QgsGeometry * intersection(QgsGeometry *geometry)
Returns a geometry representing the points shared by this geometry and other.
QgsRectangle boundingBox()
Returns the bounding box of this feature.
virtual const QgsFields & fields() const =0
Return a map of indexes with field names for this layer.
int calculateStatistics(QProgressDialog *p)
Starts the calculation.
QMap< QgsFeatureId, QgsAttributeMap > QgsChangedAttributesMap
static GEOSContextHandle_t getGEOSHandler()
return GEOS context handle
QgsRectangle intersect(const QgsRectangle *rect) const
return the intersection with the given rectangle
static QgsGeometry * fromRect(const QgsRectangle &rect)
construct geometry from a rectangle
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.
double xMinimum() const
Get the x minimum value (left side of rectangle)