[QGIS Commit] r13012 - trunk/qgis/src/analysis/vector

svn_qgis at osgeo.org svn_qgis at osgeo.org
Sat Mar 6 11:10:33 EST 2010


Author: mhugent
Date: 2010-03-06 11:10:32 -0500 (Sat, 06 Mar 2010)
New Revision: 13012

Modified:
   trunk/qgis/src/analysis/vector/qgszonalstatistics.cpp
   trunk/qgis/src/analysis/vector/qgszonalstatistics.h
Log:
Added a slightly faster zonal statistics method (but still not as fast as it could be)

Modified: trunk/qgis/src/analysis/vector/qgszonalstatistics.cpp
===================================================================
--- trunk/qgis/src/analysis/vector/qgszonalstatistics.cpp	2010-03-06 13:49:55 UTC (rev 13011)
+++ trunk/qgis/src/analysis/vector/qgszonalstatistics.cpp	2010-03-06 16:10:32 UTC (rev 13012)
@@ -137,6 +137,7 @@
 
   while ( vectorProvider->nextFeature( f ) )
   {
+    qWarning( QString::number( featureCounter ).toLocal8Bit().data() );
     if ( p )
     {
       p->setValue( featureCounter );
@@ -161,8 +162,8 @@
       continue;
     }
 
-    statisticsFromMiddlePointTest( rasterBand, featureGeometry, offsetX, offsetY, nCellsX, nCellsY, cellsizeX, cellsizeY, \
-                                   rasterBBox, sum, count );
+    statisticsFromMiddlePointTest_improved( rasterBand, featureGeometry, offsetX, offsetY, nCellsX, nCellsY, cellsizeX, cellsizeY, \
+                                            rasterBBox, sum, count );
 
     if ( count <= 1 )
     {
@@ -304,6 +305,124 @@
   CPLFree( pixelData );
 }
 
+void QgsZonalStatistics::statisticsFromMiddlePointTest_improved( void* band, QgsGeometry* poly, int pixelOffsetX, int pixelOffsetY, int nCellsX, int nCellsY, \
+    double cellSizeX, double cellSizeY, const QgsRectangle& rasterBBox, double& sum, double& count )
+{
+  double cellCenterX, cellCenterY;
+  QgsPoint currentCellCenter;
 
+  float* scanLine = ( float * ) CPLMalloc( sizeof( float ) * nCellsX );
+  cellCenterY = rasterBBox.yMaximum() - pixelOffsetY * cellSizeY - cellSizeY / 2;
+  count = 0;
+  sum = 0;
 
+  for ( int i = 0; i < nCellsY; ++i )
+  {
+    GDALRasterIO( band, GF_Read, pixelOffsetX, pixelOffsetY + i, nCellsX, 1, scanLine, nCellsX, 1, GDT_Float32, 0, 0 );
+    cellCenterX = rasterBBox.xMinimum() + pixelOffsetX * cellSizeX + cellSizeX / 2;
 
+    //do intersection of scanline with geometry
+    GEOSCoordSequence* scanLineSequence = GEOSCoordSeq_create( 2, 2 );
+    GEOSCoordSeq_setX( scanLineSequence, 0, cellCenterX );
+    GEOSCoordSeq_setY( scanLineSequence, 0, cellCenterY );
+    GEOSCoordSeq_setX( scanLineSequence, 1, cellCenterX + nCellsX * cellSizeX );
+    GEOSCoordSeq_setY( scanLineSequence, 1, cellCenterY );
+    GEOSGeometry* scanLineGeos = GEOSGeom_createLineString( scanLineSequence ); //todo: delete
+    GEOSGeometry* polyGeos = poly->asGeos();
+    GEOSGeometry* scanLineIntersection = GEOSIntersection( scanLineGeos, polyGeos );
+    GEOSGeom_destroy( scanLineGeos );
+    if ( !scanLineIntersection )
+    {
+      cellCenterY -= cellSizeY;
+      continue;
+    }
+
+    //debug
+    char* scanLineIntersectionType = GEOSGeomType( scanLineIntersection );
+
+    int numGeoms = GEOSGetNumGeometries( scanLineIntersection );
+    if ( numGeoms < 1 )
+    {
+      GEOSGeom_destroy( scanLineIntersection );
+      cellCenterY -= cellSizeY;
+      continue;
+    }
+
+    QList<double> scanLineList;
+    double currentValue;
+    GEOSGeometry* currentGeom = 0;
+    for ( int z = 0; z < numGeoms; ++z )
+    {
+      if ( numGeoms == 1 )
+      {
+        currentGeom = scanLineIntersection;
+      }
+      else
+      {
+        currentGeom = GEOSGeom_clone( GEOSGetGeometryN( scanLineIntersection, z ) );
+      }
+      const GEOSCoordSequence* scanLineCoordSequence = GEOSGeom_getCoordSeq( currentGeom );
+      if ( !scanLineCoordSequence )
+      {
+        //error
+      }
+      unsigned int scanLineIntersectionSize;
+      GEOSCoordSeq_getSize( scanLineCoordSequence, &scanLineIntersectionSize );
+      if ( !scanLineCoordSequence || scanLineIntersectionSize < 2 || ( scanLineIntersectionSize & 1 ) )
+      {
+        //error
+      }
+      for ( int k = 0; k < scanLineIntersectionSize; ++k )
+      {
+        GEOSCoordSeq_getX( scanLineCoordSequence, k, &currentValue );
+        scanLineList.push_back( currentValue );
+      }
+
+      if ( numGeoms != 1 )
+      {
+        GEOSGeom_destroy( currentGeom );
+      }
+    }
+    GEOSGeom_destroy( scanLineIntersection );
+    qSort( scanLineList );
+
+    if ( scanLineList.size() < 1 )
+    {
+      cellCenterY -= cellSizeY;
+      continue;
+    }
+
+    int listPlace = -1;
+    for ( int j = 0; j < nCellsX; ++j )
+    {
+      //currentCellCenter = QgsPoint( cellCenterX, cellCenterY );
+
+      //instead of doing a contained test every time, find the place of scanLineList and check if even / odd
+      if ( listPlace >= scanLineList.size() - 1 )
+      {
+        break;
+      }
+      if ( cellCenterX >= scanLineList.at( listPlace + 1 ) )
+      {
+        ++listPlace;
+        if ( listPlace >= scanLineList.size() )
+        {
+          break;
+        }
+      }
+      if ( listPlace >= 0 && listPlace < ( scanLineList.size() - 1 ) && !( listPlace & 1 ) )
+      {
+        if ( scanLine[j] != mInputNodataValue ) //don't consider nodata values
+        {
+          sum += scanLine[j];
+          ++count;
+        }
+      }
+      cellCenterX += cellSizeX;
+    }
+    cellCenterY -= cellSizeY;
+  }
+  CPLFree( scanLine );
+}
+
+

Modified: trunk/qgis/src/analysis/vector/qgszonalstatistics.h
===================================================================
--- trunk/qgis/src/analysis/vector/qgszonalstatistics.h	2010-03-06 13:49:55 UTC (rev 13011)
+++ trunk/qgis/src/analysis/vector/qgszonalstatistics.h	2010-03-06 16:10:32 UTC (rev 13012)
@@ -47,6 +47,9 @@
     void statisticsFromMiddlePointTest( void* band, QgsGeometry* poly, int pixelOffsetX, int pixelOffsetY, int nCellsX, int nCellsY, \
                                         double cellSizeX, double cellSizeY, const QgsRectangle& rasterBBox, double& sum, double& count );
 
+    void statisticsFromMiddlePointTest_improved( void* band, QgsGeometry* poly, int pixelOffsetX, int pixelOffsetY, int nCellsX, int nCellsY, \
+        double cellSizeX, double cellSizeY, const QgsRectangle& rasterBBox, double& sum, double& count );
+
     /**Returns statistics with precise pixel - polygon intersection test (slow) */
     void statisticsFromPreciseIntersection( void* band, QgsGeometry* poly, int pixelOffsetX, int pixelOffsetY, int nCellsX, int nCellsY, \
                                             double cellSizeX, double cellSizeY, const QgsRectangle& rasterBBox, double& sum, double& count );



More information about the QGIS-commit mailing list