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 )
43 QgsZonalStatistics::QgsZonalStatistics()
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 );