Skip to content

Commit

Permalink
Reading of rasters in several parts
Browse files Browse the repository at this point in the history
  • Loading branch information
mhugent committed Dec 24, 2011
1 parent 583d61f commit c81f4fb
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 1 deletion.
48 changes: 48 additions & 0 deletions src/core/raster/qgspalettedrasterrenderer.cpp
Expand Up @@ -42,6 +42,53 @@ void QgsPalettedRasterRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort,
return;
}

double oversampling;
startRasterRead( mBandNumber, viewPort, theQgsMapToPixel, oversampling );

int nCols = 0;
int nRows = 0;
int topLeftCol = 0;
int topLeftRow = 0;
int currentRasterPos = 0;
QgsRasterDataProvider::DataType rasterType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mBandNumber );
void* rasterData;

while ( readNextRasterPart( mBandNumber, viewPort, nCols, nRows, &rasterData, topLeftCol, topLeftRow ) )
{
//create image
QImage img( nCols, nRows, QImage::Format_ARGB32_Premultiplied );
QRgb* imageScanLine = 0;
int val = 0;

for ( int i = 0; i < nRows; ++i )
{
imageScanLine = ( QRgb* )( img.scanLine( i ) );
for ( int j = 0; j < nCols; ++j )
{
val = readValue( rasterData, rasterType, currentRasterPos );
imageScanLine[j] = mColors[ val ].rgba();
++currentRasterPos;
}
}

//top left position in device coords
QPointF tlPoint = QPointF( viewPort->topLeftPoint.x(), viewPort->topLeftPoint.y() );
tlPoint += QPointF( topLeftCol / oversampling, topLeftRow / oversampling );

//draw image
if ( mResampler ) //resample to output resolution
{
QImage dstImg( viewPort->drawableAreaXDim, viewPort->drawableAreaYDim, QImage::Format_ARGB32_Premultiplied );
mResampler->resample( img, dstImg );
p->drawImage( tlPoint, dstImg );
}
else //use original image
{
p->drawImage( tlPoint, img );
}
}

#if 0
int nCols, nRows;
if ( mResampler )
{
Expand Down Expand Up @@ -97,4 +144,5 @@ void QgsPalettedRasterRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort,
{
p->drawImage( QPointF( viewPort->topLeftPoint.x(), viewPort->topLeftPoint.y() ), img );
}
#endif //0
}
2 changes: 1 addition & 1 deletion src/core/raster/qgsrasterlayer.cpp
Expand Up @@ -851,7 +851,7 @@ void QgsRasterLayer::draw( QPainter * theQPainter,

//QgsBilinearRasterResampler resampler;
QgsCubicRasterResampler resampler;
QgsPalettedRasterRenderer renderer( mDataProvider, bNumber, colorArray, itemList.size(), &resampler );
QgsPalettedRasterRenderer renderer( mDataProvider, bNumber, colorArray, itemList.size(), 0 /*&resampler*/ );
renderer.draw( theQPainter, theRasterViewPort, theQgsMapToPixel );
#if 0
drawPalettedSingleBandColor( theQPainter, theRasterViewPort,
Expand Down
99 changes: 99 additions & 0 deletions src/core/raster/qgsrasterrenderer.cpp
Expand Up @@ -16,6 +16,8 @@
***************************************************************************/

#include "qgsrasterrenderer.h"
#include "qgsrasterviewport.h"
#include "qgsmaptopixel.h"

QgsRasterRenderer::QgsRasterRenderer( QgsRasterDataProvider* provider, QgsRasterResampler* resampler ): mProvider( provider ), mResampler( resampler )
{
Expand All @@ -24,3 +26,100 @@ QgsRasterRenderer::QgsRasterRenderer( QgsRasterDataProvider* provider, QgsRaster
QgsRasterRenderer::~QgsRasterRenderer()
{
}

void QgsRasterRenderer::startRasterRead( int bandNumber, QgsRasterViewPort* viewPort, const QgsMapToPixel* mapToPixel, double& oversampling )
{
oversampling = 1.0; //default (e.g. for nearest neighbour)
if ( !viewPort || !mapToPixel || !mProvider )
{
return;
}

//calculate oversampling factor
if ( mResampler )
{
QgsRectangle providerExtent = mProvider->extent();
if ( viewPort->mSrcCRS.isValid() && viewPort->mDestCRS.isValid() && viewPort->mSrcCRS != viewPort->mDestCRS )
{
QgsCoordinateTransform t( viewPort->mSrcCRS, viewPort->mDestCRS );
providerExtent = t.transformBoundingBox( providerExtent );
}
double pixelRatio = mapToPixel->mapUnitsPerPixel() / ( providerExtent.width() / mProvider->xSize() );
oversampling = pixelRatio > 1.0 ? 2.5 : pixelRatio;
}

//split raster into small portions if necessary
RasterPartInfo pInfo;
pInfo.nCols = viewPort->drawableAreaXDim * oversampling;
pInfo.nRows = viewPort->drawableAreaYDim * oversampling;
int totalMemoryUsage = pInfo.nCols * pInfo.nRows * mProvider->dataTypeSize( bandNumber );
int parts = totalMemoryUsage / 100000000 + 1;
pInfo.nPartsPerDimension = sqrt( parts );
pInfo.nColsPerPart = pInfo.nCols / pInfo.nPartsPerDimension;
pInfo.nRowsPerPart = pInfo.nRows / pInfo.nPartsPerDimension;
pInfo.currentCol = 0;
pInfo.currentRow = 0;
pInfo.data = 0;
mRasterPartInfos.insert( bandNumber, pInfo );
}

bool QgsRasterRenderer::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
CPLFree( pInfo.data );
pInfo.data = 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 );
int typeSize = mProvider->dataTypeSize( bandNumber ) / 8;
pInfo.data = VSIMalloc( typeSize * nCols * nRows );

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

mProvider->readBlock( bandNumber, blockRect, nCols, nRows, viewPort->mSrcCRS, viewPort->mDestCRS, pInfo.data );
*rasterData = pInfo.data;
topLeftCol = pInfo.currentCol;
topLeftRow = pInfo.currentRow;

pInfo.currentCol += nCols;
pInfo.currentRow += nRows;

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

return true;
}

void QgsRasterRenderer::stopRasterRead( int bandNumber )
{
}
19 changes: 19 additions & 0 deletions src/core/raster/qgsrasterrenderer.h
Expand Up @@ -28,15 +28,34 @@ class QgsRasterViewPort;
class QgsRasterRenderer
{
public:

struct RasterPartInfo
{
int currentCol;
int currentRow;
int nCols;
int nRows;
int nColsPerPart;
int nRowsPerPart;
int nPartsPerDimension;
void* data;
};

QgsRasterRenderer( QgsRasterDataProvider* provider, QgsRasterResampler* resampler = 0 );
virtual ~QgsRasterRenderer();
virtual void draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ) = 0;

protected:
inline double readValue( void *data, QgsRasterDataProvider::DataType type, int index );

void startRasterRead( int bandNumber, QgsRasterViewPort* viewPort, const QgsMapToPixel* mapToPixel, double& oversampling );
bool readNextRasterPart( int bandNumber, QgsRasterViewPort* viewPort, int& nCols, int& nRows, void** rasterData, int& topLeftCol, int& topLeftRow );
void stopRasterRead( int bandNumber );


QgsRasterDataProvider* mProvider;
QgsRasterResampler* mResampler;
QMap<int, RasterPartInfo> mRasterPartInfos;
};

inline double QgsRasterRenderer::readValue( void *data, QgsRasterDataProvider::DataType type, int index )
Expand Down

0 comments on commit c81f4fb

Please sign in to comment.