Skip to content

Commit

Permalink
Added class QgsRasterIterator
Browse files Browse the repository at this point in the history
  • Loading branch information
mhugent committed Jul 7, 2012
1 parent 2b53f49 commit 3f1056a
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -161,6 +161,7 @@ SET(QGIS_CORE_SRCS
raster/qgslinearminmaxenhancementwithclip.cpp
raster/qgspseudocolorshader.cpp
raster/qgsrasterinterface.cpp
raster/qgsrasteriterator.cpp
raster/qgsrasterlayer.cpp
raster/qgsrastertransparency.cpp
raster/qgsrasterpipe.cpp
Expand Down
127 changes: 127 additions & 0 deletions src/core/raster/qgsrasteriterator.cpp
@@ -0,0 +1,127 @@
#include "qgsrasteriterator.h"
#include "qgsrasterinterface.h"
#include "qgsrasterprojector.h"
#include "qgsrasterviewport.h"

QgsRasterIterator::QgsRasterIterator( QgsRasterInterface* input ): mInput( input )
{
}

QgsRasterIterator::~QgsRasterIterator()
{
}

void QgsRasterIterator::startRasterRead( int bandNumber, QgsRasterViewPort* viewPort, const QgsMapToPixel* mapToPixel )
{
if ( !viewPort || !mapToPixel || !mInput )
{
return;
}

//remove any previous part on that band
removePartInfo( bandNumber );

//split raster into small portions if necessary
RasterPartInfo pInfo;
pInfo.nCols = viewPort->drawableAreaXDim;
pInfo.nRows = viewPort->drawableAreaYDim;

//effective oversampling factors are different to global one because of rounding
//oversamplingX = (( double )pInfo.nCols * oversampling ) / viewPort->drawableAreaXDim;
//oversamplingY = (( double )pInfo.nRows * oversampling ) / viewPort->drawableAreaYDim;

// TODO : we dont know oversampling (grid size) here - how to get totalMemoryUsage ?
//int totalMemoryUsage = pInfo.nCols * oversamplingX * pInfo.nRows * oversamplingY * mInput->dataTypeSize( bandNumber );
int totalMemoryUsage = pInfo.nCols * pInfo.nRows * mInput->dataTypeSize( bandNumber );
int parts = totalMemoryUsage / 100000000 + 1;
int nPartsPerDimension = sqrt( parts );
pInfo.nColsPerPart = pInfo.nCols / nPartsPerDimension;
pInfo.nRowsPerPart = pInfo.nRows / nPartsPerDimension;
pInfo.currentCol = 0;
pInfo.currentRow = 0;
pInfo.data = 0;
pInfo.prj = 0;
mRasterPartInfos.insert( bandNumber, pInfo );
}

bool QgsRasterIterator::readNextRasterPart( int bandNumber, QgsRasterViewPort* viewPort,
int& nCols, int& nRows,
void** rasterData,
int& topLeftCol, int& topLeftRow )
{
if ( !viewPort )
{
return false;
}

//get partinfo
QMap<int, RasterPartInfo>::iterator partIt = mRasterPartInfos.find( bandNumber );
if ( partIt == mRasterPartInfos.end() )
{
return false;
}

RasterPartInfo& pInfo = partIt.value();

//remove last data block
// TODO: data are released somewhere else (check)
//free( pInfo.data );
pInfo.data = 0;
delete pInfo.prj;
pInfo.prj = 0;

//already at end
if ( pInfo.currentCol == pInfo.nCols && pInfo.currentRow == pInfo.nRows )
{
return false;
}

//read data block
nCols = qMin( pInfo.nColsPerPart, pInfo.nCols - pInfo.currentCol );
nRows = qMin( pInfo.nRowsPerPart, pInfo.nRows - pInfo.currentRow );

//get subrectangle
QgsRectangle viewPortExtent = viewPort->mDrawnExtent;
double xmin = viewPortExtent.xMinimum() + pInfo.currentCol / ( double )pInfo.nCols * viewPortExtent.width();
double xmax = viewPortExtent.xMinimum() + ( pInfo.currentCol + nCols ) / ( double )pInfo.nCols * viewPortExtent.width();
double ymin = viewPortExtent.yMaximum() - ( pInfo.currentRow + nRows ) / ( double )pInfo.nRows * viewPortExtent.height();
double ymax = viewPortExtent.yMaximum() - pInfo.currentRow / ( double )pInfo.nRows * viewPortExtent.height();
QgsRectangle blockRect( xmin, ymin, xmax, ymax );

pInfo.data = mInput->block( bandNumber, blockRect, nCols, nRows );

*rasterData = pInfo.data;
topLeftCol = pInfo.currentCol;
topLeftRow = pInfo.currentRow;

pInfo.currentCol += nCols;
if ( pInfo.currentCol == pInfo.nCols && pInfo.currentRow + nRows == pInfo.nRows ) //end of raster
{
pInfo.currentRow = pInfo.nRows;
}
else if ( pInfo.currentCol == pInfo.nCols ) //start new row
{
pInfo.currentCol = 0;
pInfo.currentRow += pInfo.nRowsPerPart;
}

return true;
}

void QgsRasterIterator::stopRasterRead( int bandNumber )
{
removePartInfo( bandNumber );
}

void QgsRasterIterator::removePartInfo( int bandNumber )
{
QMap<int, RasterPartInfo>::iterator partIt = mRasterPartInfos.find( bandNumber );
if ( partIt != mRasterPartInfos.end() )
{
RasterPartInfo& pInfo = partIt.value();
//CPLFree( pInfo.data );
free( pInfo.data );
delete pInfo.prj;
mRasterPartInfos.remove( bandNumber );
}
}
56 changes: 56 additions & 0 deletions src/core/raster/qgsrasteriterator.h
@@ -0,0 +1,56 @@
#ifndef QGSRASTERITERATOR_H
#define QGSRASTERITERATOR_H

#include <QMap>

class QgsMapToPixel;
class QgsRasterInterface;
class QgsRasterProjector;
class QgsRasterViewPort;

class QgsRasterIterator
{
public:
//Stores information about reading of a raster band. Columns and rows are in unsampled coordinates
struct RasterPartInfo
{
int currentCol;
int currentRow;
int nCols;
int nRows;
int nColsPerPart;
int nRowsPerPart;
void* data; //data (can be in oversampled/undersampled resolution)
QgsRasterProjector* prj; //raster projector (or 0 if no reprojection is done)
};

QgsRasterIterator( QgsRasterInterface* input );
~QgsRasterIterator();

/**Start reading of raster band. Raster data can then be retrieved by calling readNextRasterPart until it returns false.
@param bandNumer number of raster band to read
@param viewPort describes raster position on screen
*/
void startRasterRead( int bandNumber, QgsRasterViewPort* viewPort, const QgsMapToPixel* mapToPixel );

/**Fetches next part of raster data
@param nCols number of columns on output device
@param nRows number of rows on output device
@param nColsRaster number of raster columns (different to nCols if oversamplingX != 1.0)
@param nRowsRaster number of raster rows (different to nRows if oversamplingY != 0)*/
bool readNextRasterPart( int bandNumber, QgsRasterViewPort* viewPort,
int& nCols, int& nRows,
void** rasterData,
int& topLeftCol, int& topLeftRow );

void stopRasterRead( int bandNumber );

private:
QgsRasterInterface* mInput;
QMap<int, RasterPartInfo> mRasterPartInfos;

/**Remove part into and release memory*/
void removePartInfo( int bandNumber );
};

#endif // QGSRASTERITERATOR_H

0 comments on commit 3f1056a

Please sign in to comment.