20
20
#include " qgsgeometry.h"
21
21
#include " qgsvectordataprovider.h"
22
22
#include " qgsvectorlayer.h"
23
+ #include " qgsrasterdataprovider.h"
24
+ #include " qgsrasterlayer.h"
25
+ #include " qgsrasterblock.h"
23
26
#include " qmath.h"
24
- #include " gdal.h"
25
- #include " cpl_string.h"
26
27
#include " qgslogger.h"
27
28
28
29
#include < QProgressDialog>
29
30
#include < QFile>
30
31
31
- QgsZonalStatistics::QgsZonalStatistics ( QgsVectorLayer* polygonLayer, const QString& rasterFile , const QString& attributePrefix, int rasterBand, Statistics stats )
32
- : mRasterFilePath( rasterFile )
32
+ QgsZonalStatistics::QgsZonalStatistics ( QgsVectorLayer* polygonLayer, QgsRasterLayer* rasterLayer , const QString& attributePrefix, int rasterBand, Statistics stats )
33
+ : mRasterLayer( rasterLayer )
33
34
, mRasterBand( rasterBand )
34
35
, mPolygonLayer( polygonLayer )
35
36
, mAttributePrefix( attributePrefix )
@@ -40,7 +41,8 @@ QgsZonalStatistics::QgsZonalStatistics( QgsVectorLayer* polygonLayer, const QStr
40
41
}
41
42
42
43
QgsZonalStatistics::QgsZonalStatistics ()
43
- : mRasterBand( 0 )
44
+ : mRasterLayer( nullptr )
45
+ , mRasterBand( 0 )
44
46
, mPolygonLayer( nullptr )
45
47
, mInputNodataValue( -1 )
46
48
, mStatistics( QgsZonalStatistics::All )
@@ -61,49 +63,33 @@ int QgsZonalStatistics::calculateStatistics( QProgressDialog* p )
61
63
return 2 ;
62
64
}
63
65
64
- // open the raster layer and the raster band
65
- GDALAllRegister ();
66
- GDALDatasetH inputDataset = GDALOpen ( mRasterFilePath .toUtf8 ().constData (), GA_ReadOnly );
67
- if ( !inputDataset )
66
+ if ( !mRasterLayer )
68
67
{
69
68
return 3 ;
70
69
}
71
70
72
- if ( GDALGetRasterCount ( inputDataset ) < ( mRasterBand - 1 ) )
71
+ if ( mRasterLayer -> bandCount ( ) < mRasterBand )
73
72
{
74
- GDALClose ( inputDataset );
75
73
return 4 ;
76
74
}
77
75
78
- GDALRasterBandH rasterBand = GDALGetRasterBand ( inputDataset, mRasterBand );
79
- if ( !rasterBand )
80
- {
81
- GDALClose ( inputDataset );
82
- return 5 ;
83
- }
84
- mInputNodataValue = GDALGetRasterNoDataValue ( rasterBand, nullptr );
76
+ mRasterProvider = mRasterLayer ->dataProvider ();
77
+ mInputNodataValue = mRasterProvider ->sourceNoDataValue ( mRasterBand );
85
78
86
79
// get geometry info about raster layer
87
- int nCellsXGDAL = GDALGetRasterXSize ( inputDataset );
88
- int nCellsYGDAL = GDALGetRasterYSize ( inputDataset );
89
- double geoTransform[6 ];
90
- if ( GDALGetGeoTransform ( inputDataset, geoTransform ) != CE_None )
91
- {
92
- GDALClose ( inputDataset );
93
- return 6 ;
94
- }
95
- double cellsizeX = geoTransform[1 ];
80
+ int nCellsXProvider = mRasterProvider ->xSize ();
81
+ int nCellsYProvider = mRasterProvider ->ySize ();
82
+ double cellsizeX = mRasterLayer ->rasterUnitsPerPixelX ();
96
83
if ( cellsizeX < 0 )
97
84
{
98
85
cellsizeX = -cellsizeX;
99
86
}
100
- double cellsizeY = geoTransform[ 5 ] ;
87
+ double cellsizeY = mRasterLayer -> rasterUnitsPerPixelY () ;
101
88
if ( cellsizeY < 0 )
102
89
{
103
90
cellsizeY = -cellsizeY;
104
91
}
105
- QgsRectangle rasterBBox ( geoTransform[0 ], geoTransform[3 ] - ( nCellsYGDAL * cellsizeY ),
106
- geoTransform[0 ] + ( nCellsXGDAL * cellsizeX ), geoTransform[3 ] );
92
+ QgsRectangle rasterBBox = mRasterProvider ->extent ();
107
93
108
94
// add the new fields to the provider
109
95
QList<QgsField> newFieldList;
@@ -223,7 +209,6 @@ int QgsZonalStatistics::calculateStatistics( QProgressDialog* p )
223
209
p->setMaximum ( featureCount );
224
210
}
225
211
226
-
227
212
// iterate over each polygon
228
213
QgsFeatureRequest request;
229
214
request.setSubsetOfAttributes ( QgsAttributeList () );
@@ -273,22 +258,22 @@ int QgsZonalStatistics::calculateStatistics( QProgressDialog* p )
273
258
}
274
259
275
260
// avoid access to cells outside of the raster (may occur because of rounding)
276
- if (( offsetX + nCellsX ) > nCellsXGDAL )
261
+ if (( offsetX + nCellsX ) > nCellsXProvider )
277
262
{
278
- nCellsX = nCellsXGDAL - offsetX;
263
+ nCellsX = nCellsXProvider - offsetX;
279
264
}
280
- if (( offsetY + nCellsY ) > nCellsYGDAL )
265
+ if (( offsetY + nCellsY ) > nCellsYProvider )
281
266
{
282
- nCellsY = nCellsYGDAL - offsetY;
267
+ nCellsY = nCellsYProvider - offsetY;
283
268
}
284
269
285
- statisticsFromMiddlePointTest ( rasterBand, featureGeometry, offsetX, offsetY, nCellsX, nCellsY, cellsizeX, cellsizeY,
270
+ statisticsFromMiddlePointTest ( featureGeometry, offsetX, offsetY, nCellsX, nCellsY, cellsizeX, cellsizeY,
286
271
rasterBBox, featureStats );
287
272
288
273
if ( featureStats.count <= 1 )
289
274
{
290
275
// the cell resolution is probably larger than the polygon area. We switch to precise pixel - polygon intersection in this case
291
- statisticsFromPreciseIntersection ( rasterBand, featureGeometry, offsetX, offsetY, nCellsX, nCellsY, cellsizeX, cellsizeY,
276
+ statisticsFromPreciseIntersection ( featureGeometry, offsetX, offsetY, nCellsX, nCellsY, cellsizeX, cellsizeY,
292
277
rasterBBox, featureStats );
293
278
}
294
279
@@ -366,7 +351,6 @@ int QgsZonalStatistics::calculateStatistics( QProgressDialog* p )
366
351
p->setValue ( featureCount );
367
352
}
368
353
369
- GDALClose ( inputDataset );
370
354
mPolygonLayer ->updateFields ();
371
355
372
356
if ( p && p->wasCanceled () )
@@ -404,12 +388,11 @@ int QgsZonalStatistics::cellInfoForBBox( const QgsRectangle& rasterBBox, const Q
404
388
return 0 ;
405
389
}
406
390
407
- void QgsZonalStatistics::statisticsFromMiddlePointTest ( void * band, const QgsGeometry& poly, int pixelOffsetX,
391
+ void QgsZonalStatistics::statisticsFromMiddlePointTest ( const QgsGeometry& poly, int pixelOffsetX,
408
392
int pixelOffsetY, int nCellsX, int nCellsY, double cellSizeX, double cellSizeY, const QgsRectangle& rasterBBox, FeatureStats &stats )
409
393
{
410
394
double cellCenterX, cellCenterY;
411
395
412
- float * scanLine = ( float * ) CPLMalloc ( sizeof ( float ) * nCellsX );
413
396
cellCenterY = rasterBBox.yMaximum () - pixelOffsetY * cellSizeY - cellSizeY / 2 ;
414
397
stats.reset ();
415
398
@@ -430,17 +413,16 @@ void QgsZonalStatistics::statisticsFromMiddlePointTest( void* band, const QgsGeo
430
413
GEOSCoordSequence* cellCenterCoords = nullptr ;
431
414
GEOSGeometry* currentCellCenter = nullptr ;
432
415
416
+ QgsRectangle featureBBox = poly.boundingBox ().intersect ( &rasterBBox );
417
+ QgsRectangle intersectBBox = rasterBBox.intersect ( &featureBBox );
418
+
419
+ QgsRasterBlock* block = mRasterProvider ->block ( mRasterBand , intersectBBox, nCellsX, nCellsY );
433
420
for ( int i = 0 ; i < nCellsY; ++i )
434
421
{
435
- if ( GDALRasterIO ( band, GF_Read, pixelOffsetX, pixelOffsetY + i, nCellsX, 1 , scanLine, nCellsX, 1 , GDT_Float32, 0 , 0 )
436
- != CPLE_None )
437
- {
438
- continue ;
439
- }
440
422
cellCenterX = rasterBBox.xMinimum () + pixelOffsetX * cellSizeX + cellSizeX / 2 ;
441
423
for ( int j = 0 ; j < nCellsX; ++j )
442
424
{
443
- if ( validPixel ( scanLine[j] ) )
425
+ if ( validPixel ( block-> value ( i, j ) ) )
444
426
{
445
427
GEOSGeom_destroy_r ( geosctxt, currentCellCenter );
446
428
cellCenterCoords = GEOSCoordSeq_create_r ( geosctxt, 1 , 2 );
@@ -449,45 +431,46 @@ void QgsZonalStatistics::statisticsFromMiddlePointTest( void* band, const QgsGeo
449
431
currentCellCenter = GEOSGeom_createPoint_r ( geosctxt, cellCenterCoords );
450
432
if ( GEOSPreparedContains_r ( geosctxt, polyGeosPrepared, currentCellCenter ) )
451
433
{
452
- stats.addValue ( scanLine[j] );
434
+ stats.addValue ( block-> value ( i, j ) );
453
435
}
454
436
}
455
437
cellCenterX += cellSizeX;
456
438
}
457
439
cellCenterY -= cellSizeY;
458
440
}
441
+
459
442
GEOSGeom_destroy_r ( geosctxt, currentCellCenter );
460
- CPLFree ( scanLine );
461
443
GEOSPreparedGeom_destroy_r ( geosctxt, polyGeosPrepared );
462
444
GEOSGeom_destroy_r ( geosctxt, polyGeos );
445
+ delete block;
463
446
}
464
447
465
- void QgsZonalStatistics::statisticsFromPreciseIntersection ( void * band, const QgsGeometry& poly, int pixelOffsetX,
448
+ void QgsZonalStatistics::statisticsFromPreciseIntersection ( const QgsGeometry& poly, int pixelOffsetX,
466
449
int pixelOffsetY, int nCellsX, int nCellsY, double cellSizeX, double cellSizeY, const QgsRectangle& rasterBBox, FeatureStats &stats )
467
450
{
468
451
stats.reset ();
469
452
470
453
double currentY = rasterBBox.yMaximum () - pixelOffsetY * cellSizeY - cellSizeY / 2 ;
471
- float * pixelData = ( float * ) CPLMalloc ( sizeof ( float ) );
472
454
QgsGeometry pixelRectGeometry;
473
455
474
456
double hCellSizeX = cellSizeX / 2.0 ;
475
457
double hCellSizeY = cellSizeY / 2.0 ;
476
458
double pixelArea = cellSizeX * cellSizeY;
477
459
double weight = 0 ;
478
460
479
- for ( int row = 0 ; row < nCellsY; ++row )
461
+ QgsRectangle featureBBox = poly.boundingBox ().intersect ( &rasterBBox );
462
+ QgsRectangle intersectBBox = rasterBBox.intersect ( &featureBBox );
463
+
464
+ QgsRasterBlock* block = mRasterProvider ->block ( mRasterBand , intersectBBox, nCellsX, nCellsY );
465
+ for ( int i = 0 ; i < nCellsY; ++i )
480
466
{
481
467
double currentX = rasterBBox.xMinimum () + cellSizeX / 2.0 + pixelOffsetX * cellSizeX;
482
- for ( int col = 0 ; col < nCellsX; ++col )
468
+ for ( int j = 0 ; j < nCellsX; ++j )
483
469
{
484
- if ( GDALRasterIO ( band, GF_Read, pixelOffsetX + col, pixelOffsetY + row, nCellsX, 1 , pixelData, 1 , 1 , GDT_Float32, 0 , 0 ) != CE_None )
470
+ if ( ! validPixel ( block-> value ( i, j ) ) )
485
471
{
486
- QgsDebugMsg ( " Raster IO Error" );
487
- }
488
-
489
- if ( !validPixel ( *pixelData ) )
490
472
continue ;
473
+ }
491
474
492
475
pixelRectGeometry = QgsGeometry::fromRect ( QgsRectangle ( currentX - hCellSizeX, currentY - hCellSizeY, currentX + hCellSizeX, currentY + hCellSizeY ) );
493
476
if ( !pixelRectGeometry.isNull () )
@@ -500,7 +483,7 @@ void QgsZonalStatistics::statisticsFromPreciseIntersection( void* band, const Qg
500
483
if ( intersectionArea >= 0.0 )
501
484
{
502
485
weight = intersectionArea / pixelArea;
503
- stats.addValue ( *pixelData , weight );
486
+ stats.addValue ( block-> value ( i, j ) , weight );
504
487
}
505
488
}
506
489
pixelRectGeometry = QgsGeometry ();
@@ -509,7 +492,7 @@ void QgsZonalStatistics::statisticsFromPreciseIntersection( void* band, const Qg
509
492
}
510
493
currentY -= cellSizeY;
511
494
}
512
- CPLFree ( pixelData ) ;
495
+ delete block ;
513
496
}
514
497
515
498
bool QgsZonalStatistics::validPixel ( float value ) const
0 commit comments