@@ -87,8 +87,8 @@ int QgsZonalStatistics::calculateStatistics( QProgressDialog* p )
87
87
mInputNodataValue = GDALGetRasterNoDataValue ( rasterBand, NULL );
88
88
89
89
// get geometry info about raster layer
90
- int nCellsX = GDALGetRasterXSize ( inputDataset );
91
- int nCellsY = GDALGetRasterYSize ( inputDataset );
90
+ int nCellsXGDAL = GDALGetRasterXSize ( inputDataset );
91
+ int nCellsYGDAL = GDALGetRasterYSize ( inputDataset );
92
92
double geoTransform[6 ];
93
93
if ( GDALGetGeoTransform ( inputDataset, geoTransform ) != CE_None )
94
94
{
@@ -105,7 +105,8 @@ int QgsZonalStatistics::calculateStatistics( QProgressDialog* p )
105
105
{
106
106
cellsizeY = -cellsizeY;
107
107
}
108
- QgsRectangle rasterBBox ( geoTransform[0 ], geoTransform[3 ] - ( nCellsY * cellsizeY ), geoTransform[0 ] + ( nCellsX * cellsizeX ), geoTransform[3 ] );
108
+ QgsRectangle rasterBBox ( geoTransform[0 ], geoTransform[3 ] - ( nCellsYGDAL * cellsizeY ),
109
+ geoTransform[0 ] + ( nCellsXGDAL * cellsizeX ), geoTransform[3 ] );
109
110
110
111
// add the new count, sum, mean fields to the provider
111
112
QList<QgsField> newFieldList;
@@ -145,7 +146,6 @@ int QgsZonalStatistics::calculateStatistics( QProgressDialog* p )
145
146
146
147
while ( vectorProvider->nextFeature ( f ) )
147
148
{
148
- qWarning ( " %d" , featureCounter );
149
149
if ( p )
150
150
{
151
151
p->setValue ( featureCounter );
@@ -163,15 +163,32 @@ int QgsZonalStatistics::calculateStatistics( QProgressDialog* p )
163
163
continue ;
164
164
}
165
165
166
+ QgsRectangle featureRect = featureGeometry->boundingBox ().intersect ( &rasterBBox );
167
+ if ( featureRect.isEmpty () )
168
+ {
169
+ ++featureCounter;
170
+ continue ;
171
+ }
172
+
166
173
int offsetX, offsetY, nCellsX, nCellsY;
167
- if ( cellInfoForBBox ( rasterBBox, featureGeometry-> boundingBox () , cellsizeX, cellsizeY, offsetX, offsetY, nCellsX, nCellsY ) != 0 )
174
+ if ( cellInfoForBBox ( rasterBBox, featureRect , cellsizeX, cellsizeY, offsetX, offsetY, nCellsX, nCellsY ) != 0 )
168
175
{
169
176
++featureCounter;
170
177
continue ;
171
178
}
172
179
173
- statisticsFromMiddlePointTest_improved ( rasterBand, featureGeometry, offsetX, offsetY, nCellsX, nCellsY, cellsizeX, cellsizeY,
174
- rasterBBox, sum, count );
180
+ // avoid access to cells outside of the raster (may occur because of rounding)
181
+ if (( offsetX + nCellsX ) > nCellsXGDAL )
182
+ {
183
+ nCellsX = nCellsXGDAL - offsetX;
184
+ }
185
+ if (( offsetY + nCellsY ) > nCellsYGDAL )
186
+ {
187
+ nCellsY = nCellsYGDAL - offsetY;
188
+ }
189
+
190
+ statisticsFromMiddlePointTest ( rasterBand, featureGeometry, offsetX, offsetY, nCellsX, nCellsY, cellsizeX, cellsizeY,
191
+ rasterBBox, sum, count );
175
192
176
193
if ( count <= 1 )
177
194
{
@@ -246,21 +263,44 @@ void QgsZonalStatistics::statisticsFromMiddlePointTest( void* band, QgsGeometry*
246
263
int pixelOffsetY, int nCellsX, int nCellsY, double cellSizeX, double cellSizeY, const QgsRectangle& rasterBBox, double & sum, double & count )
247
264
{
248
265
double cellCenterX, cellCenterY;
249
- QgsPoint currentCellCenter;
250
266
251
267
float * scanLine = ( float * ) CPLMalloc ( sizeof ( float ) * nCellsX );
252
268
cellCenterY = rasterBBox.yMaximum () - pixelOffsetY * cellSizeY - cellSizeY / 2 ;
253
269
count = 0 ;
254
270
sum = 0 ;
255
271
272
+ GEOSGeometry* polyGeos = poly->asGeos ();
273
+ if ( !polyGeos )
274
+ {
275
+ return ;
276
+ }
277
+
278
+ const GEOSPreparedGeometry* polyGeosPrepared = GEOSPrepare ( poly->asGeos () );
279
+ if ( !polyGeosPrepared )
280
+ {
281
+ return ;
282
+ }
283
+
284
+ GEOSCoordSequence* cellCenterCoords = 0 ;
285
+ GEOSGeometry* currentCellCenter = 0 ;
286
+
256
287
for ( int i = 0 ; i < nCellsY; ++i )
257
288
{
258
- GDALRasterIO ( band, GF_Read, pixelOffsetX, pixelOffsetY + i, nCellsX, 1 , scanLine, nCellsX, 1 , GDT_Float32, 0 , 0 );
289
+ if ( GDALRasterIO ( band, GF_Read, pixelOffsetX, pixelOffsetY + i, nCellsX, 1 , scanLine, nCellsX, 1 , GDT_Float32, 0 , 0 )
290
+ != CPLE_None )
291
+ {
292
+ continue ;
293
+ }
259
294
cellCenterX = rasterBBox.xMinimum () + pixelOffsetX * cellSizeX + cellSizeX / 2 ;
260
295
for ( int j = 0 ; j < nCellsX; ++j )
261
296
{
262
- currentCellCenter = QgsPoint ( cellCenterX, cellCenterY );
263
- if ( poly->contains ( ¤tCellCenter ) )
297
+ GEOSGeom_destroy ( currentCellCenter );
298
+ cellCenterCoords = GEOSCoordSeq_create ( 1 , 2 );
299
+ GEOSCoordSeq_setX ( cellCenterCoords, 0 , cellCenterX );
300
+ GEOSCoordSeq_setY ( cellCenterCoords, 0 , cellCenterY );
301
+ currentCellCenter = GEOSGeom_createPoint ( cellCenterCoords );
302
+
303
+ if ( GEOSPreparedContains ( polyGeosPrepared, currentCellCenter ) )
264
304
{
265
305
if ( scanLine[j] != mInputNodataValue ) // don't consider nodata values
266
306
{
@@ -273,6 +313,7 @@ void QgsZonalStatistics::statisticsFromMiddlePointTest( void* band, QgsGeometry*
273
313
cellCenterY -= cellSizeY;
274
314
}
275
315
CPLFree ( scanLine );
316
+ GEOSPreparedGeom_destroy ( polyGeosPrepared );
276
317
}
277
318
278
319
void QgsZonalStatistics::statisticsFromPreciseIntersection ( void * band, QgsGeometry* poly, int pixelOffsetX,
@@ -319,124 +360,4 @@ void QgsZonalStatistics::statisticsFromPreciseIntersection( void* band, QgsGeome
319
360
CPLFree ( pixelData );
320
361
}
321
362
322
- void QgsZonalStatistics::statisticsFromMiddlePointTest_improved ( void * band, QgsGeometry* poly, int pixelOffsetX, int pixelOffsetY, int nCellsX, int nCellsY,
323
- double cellSizeX, double cellSizeY, const QgsRectangle& rasterBBox, double & sum, double & count )
324
- {
325
- double cellCenterX, cellCenterY;
326
- QgsPoint currentCellCenter;
327
-
328
- float * scanLine = ( float * ) CPLMalloc ( sizeof ( float ) * nCellsX );
329
- cellCenterY = rasterBBox.yMaximum () - pixelOffsetY * cellSizeY - cellSizeY / 2 ;
330
- count = 0 ;
331
- sum = 0 ;
332
-
333
- for ( int i = 0 ; i < nCellsY; ++i )
334
- {
335
- GDALRasterIO ( band, GF_Read, pixelOffsetX, pixelOffsetY + i, nCellsX, 1 , scanLine, nCellsX, 1 , GDT_Float32, 0 , 0 );
336
- cellCenterX = rasterBBox.xMinimum () + pixelOffsetX * cellSizeX + cellSizeX / 2 ;
337
-
338
- // do intersection of scanline with geometry
339
- GEOSCoordSequence* scanLineSequence = GEOSCoordSeq_create ( 2 , 2 );
340
- GEOSCoordSeq_setX ( scanLineSequence, 0 , cellCenterX );
341
- GEOSCoordSeq_setY ( scanLineSequence, 0 , cellCenterY );
342
- GEOSCoordSeq_setX ( scanLineSequence, 1 , cellCenterX + nCellsX * cellSizeX );
343
- GEOSCoordSeq_setY ( scanLineSequence, 1 , cellCenterY );
344
- GEOSGeometry* scanLineGeos = GEOSGeom_createLineString ( scanLineSequence ); // todo: delete
345
- GEOSGeometry* polyGeos = poly->asGeos ();
346
- GEOSGeometry* scanLineIntersection = GEOSIntersection ( scanLineGeos, polyGeos );
347
- GEOSGeom_destroy ( scanLineGeos );
348
- if ( !scanLineIntersection )
349
- {
350
- cellCenterY -= cellSizeY;
351
- continue ;
352
- }
353
-
354
- // debug
355
- // char* scanLineIntersectionType = GEOSGeomType( scanLineIntersection );
356
-
357
- int numGeoms = GEOSGetNumGeometries ( scanLineIntersection );
358
- if ( numGeoms < 1 )
359
- {
360
- GEOSGeom_destroy ( scanLineIntersection );
361
- cellCenterY -= cellSizeY;
362
- continue ;
363
- }
364
-
365
- QList<double > scanLineList;
366
- double currentValue;
367
- GEOSGeometry* currentGeom = 0 ;
368
- for ( int z = 0 ; z < numGeoms; ++z )
369
- {
370
- if ( numGeoms == 1 )
371
- {
372
- currentGeom = scanLineIntersection;
373
- }
374
- else
375
- {
376
- currentGeom = GEOSGeom_clone ( GEOSGetGeometryN ( scanLineIntersection, z ) );
377
- }
378
- const GEOSCoordSequence* scanLineCoordSequence = GEOSGeom_getCoordSeq ( currentGeom );
379
- if ( !scanLineCoordSequence )
380
- {
381
- // error
382
- }
383
- unsigned int scanLineIntersectionSize;
384
- GEOSCoordSeq_getSize ( scanLineCoordSequence, &scanLineIntersectionSize );
385
- if ( !scanLineCoordSequence || scanLineIntersectionSize < 2 || ( scanLineIntersectionSize & 1 ) )
386
- {
387
- // error
388
- }
389
- for ( unsigned int k = 0 ; k < scanLineIntersectionSize; ++k )
390
- {
391
- GEOSCoordSeq_getX ( scanLineCoordSequence, k, ¤tValue );
392
- scanLineList.push_back ( currentValue );
393
- }
394
-
395
- if ( numGeoms != 1 )
396
- {
397
- GEOSGeom_destroy ( currentGeom );
398
- }
399
- }
400
- GEOSGeom_destroy ( scanLineIntersection );
401
- qSort ( scanLineList );
402
-
403
- if ( scanLineList.size () < 1 )
404
- {
405
- cellCenterY -= cellSizeY;
406
- continue ;
407
- }
408
-
409
- int listPlace = -1 ;
410
- for ( int j = 0 ; j < nCellsX; ++j )
411
- {
412
- // currentCellCenter = QgsPoint( cellCenterX, cellCenterY );
413
-
414
- // instead of doing a contained test every time, find the place of scanLineList and check if even / odd
415
- if ( listPlace >= scanLineList.size () - 1 )
416
- {
417
- break ;
418
- }
419
- if ( cellCenterX >= scanLineList.at ( listPlace + 1 ) )
420
- {
421
- ++listPlace;
422
- if ( listPlace >= scanLineList.size () )
423
- {
424
- break ;
425
- }
426
- }
427
- if ( listPlace >= 0 && listPlace < ( scanLineList.size () - 1 ) && !( listPlace & 1 ) )
428
- {
429
- if ( scanLine[j] != mInputNodataValue ) // don't consider nodata values
430
- {
431
- sum += scanLine[j];
432
- ++count;
433
- }
434
- }
435
- cellCenterX += cellSizeX;
436
- }
437
- cellCenterY -= cellSizeY;
438
- }
439
- CPLFree ( scanLine );
440
- }
441
-
442
363
0 commit comments