Allow QgsRasterIterator to iterate over a raster layer, WITHOUT

actually fetching the raster block data

This allows for efficient iteration over a "reference" layer, where
you require the block extent/origin/pixel size/etc (but not the
reference layer block data itself!), in order to fetch a block from
a DIFFERENT set of rasters (but keeping these pixel-aligned to the
reference raster).
This commit is contained in:
Nyall Dawson 2019-01-21 12:11:28 +10:00
parent b391c0876f
commit d57c182d8b
4 changed files with 179 additions and 2 deletions

View File

@ -33,6 +33,28 @@ Start reading of raster band. Raster data can then be retrieved by calling readN
:param nRows: number of rows
:param extent: area to read
:param feedback: optional raster feedback object for cancelation/preview. Added in QGIS 3.0.
%End
bool next( int bandNumber, int &columns /Out/, int &rows /Out/, int &topLeftColumn /Out/, int &topLeftRow /Out/, QgsRectangle &blockExtent /Out/ );
%Docstring
Fetches details of the next part of the raster data. This method does NOT actually fetch the raster
data itself, rather it calculates and iterates over the details of the raster alone.
It's useful for iterating over several layers using a target "reference" layer. E.g. summing
the pixels in n rasters whilst aligning the result to a reference layer which is not being summed.
Note that calling this method also advances the iterator, just like calling readNextRasterPart().
:param bandNumber: band to read
:param rows: number of rows on output device
:param topLeftColumn: top left column
:param topLeftRow: top left row
:param blockExtent: exact extent of returned raster block
:return: - false if the last part was already returned
- columns: number of columns on output device
.. versionadded:: 3.6
%End
bool readNextRasterPart( int bandNumber,

View File

@ -57,6 +57,11 @@ void QgsRasterIterator::startRasterRead( int bandNumber, int nCols, int nRows, c
mRasterPartInfos.insert( bandNumber, pInfo );
}
bool QgsRasterIterator::next( int bandNumber, int &columns, int &rows, int &topLeftColumn, int &topLeftRow, QgsRectangle &blockExtent )
{
return readNextRasterPartInternal( bandNumber, columns, rows, nullptr, topLeftColumn, topLeftRow, &blockExtent );
}
bool QgsRasterIterator::readNextRasterPart( int bandNumber,
int &nCols, int &nRows,
QgsRasterBlock **block,
@ -71,9 +76,15 @@ bool QgsRasterIterator::readNextRasterPart( int bandNumber,
}
bool QgsRasterIterator::readNextRasterPart( int bandNumber, int &nCols, int &nRows, std::unique_ptr<QgsRasterBlock> &block, int &topLeftCol, int &topLeftRow, QgsRectangle *blockExtent )
{
return readNextRasterPartInternal( bandNumber, nCols, nRows, &block, topLeftCol, topLeftRow, blockExtent );
}
bool QgsRasterIterator::readNextRasterPartInternal( int bandNumber, int &nCols, int &nRows, std::unique_ptr<QgsRasterBlock> *block, int &topLeftCol, int &topLeftRow, QgsRectangle *blockExtent )
{
QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
block.reset();
if ( block )
block->reset();
//get partinfo
QMap<int, RasterPartInfo>::iterator partIt = mRasterPartInfos.find( bandNumber );
if ( partIt == mRasterPartInfos.end() )
@ -115,7 +126,8 @@ bool QgsRasterIterator::readNextRasterPart( int bandNumber, int &nCols, int &nRo
if ( blockExtent )
*blockExtent = blockRect;
block.reset( mInput->block( bandNumber, blockRect, nCols, nRows, mFeedback ) );
if ( block )
block->reset( mInput->block( bandNumber, blockRect, nCols, nRows, mFeedback ) );
topLeftCol = pInfo.currentCol;
topLeftRow = pInfo.currentRow;

View File

@ -49,6 +49,27 @@ class CORE_EXPORT QgsRasterIterator
*/
void startRasterRead( int bandNumber, int nCols, int nRows, const QgsRectangle &extent, QgsRasterBlockFeedback *feedback = nullptr );
/**
* Fetches details of the next part of the raster data. This method does NOT actually fetch the raster
* data itself, rather it calculates and iterates over the details of the raster alone.
*
* It's useful for iterating over several layers using a target "reference" layer. E.g. summing
* the pixels in n rasters whilst aligning the result to a reference layer which is not being summed.
*
* Note that calling this method also advances the iterator, just like calling readNextRasterPart().
*
* \param bandNumber band to read
* \param columns number of columns on output device
* \param rows number of rows on output device
* \param topLeftColumn top left column
* \param topLeftRow top left row
* \param blockExtent exact extent of returned raster block
* \returns false if the last part was already returned
*
* \since QGIS 3.6
*/
bool next( int bandNumber, int &columns SIP_OUT, int &rows SIP_OUT, int &topLeftColumn SIP_OUT, int &topLeftRow SIP_OUT, QgsRectangle &blockExtent SIP_OUT );
/**
* Fetches next part of raster data, caller takes ownership of the block and
* caller should delete the block.
@ -148,6 +169,7 @@ class CORE_EXPORT QgsRasterIterator
//! Remove part into and release memory
void removePartInfo( int bandNumber );
bool readNextRasterPartInternal( int bandNumber, int &nCols, int &nRows, std::unique_ptr<QgsRasterBlock> *block, int &topLeftCol, int &topLeftRow, QgsRectangle *blockExtent );
};
#endif // QGSRASTERITERATOR_H

View File

@ -39,6 +39,7 @@ class TestQgsRasterIterator : public QObject
void cleanup() {} // will be called after every testfunction.
void testBasic();
void testNoBlock();
private:
@ -232,6 +233,126 @@ void TestQgsRasterIterator::testBasic()
QVERIFY( !block.get() );
}
void TestQgsRasterIterator::testNoBlock()
{
// test iterating with no block
QgsRasterDataProvider *provider = mpRasterLayer->dataProvider();
QVERIFY( provider );
QgsRasterIterator it( provider );
QCOMPARE( it.input(), provider );
it.setMaximumTileHeight( 2500 );
QCOMPARE( it.maximumTileHeight(), 2500 );
it.setMaximumTileWidth( 3000 );
QCOMPARE( it.maximumTileWidth(), 3000 );
it.startRasterRead( 1, mpRasterLayer->width(), mpRasterLayer->height(), mpRasterLayer->extent() );
int nCols;
int nRows;
int topLeftCol;
int topLeftRow;
QgsRectangle blockExtent;
QVERIFY( it.next( 1, nCols, nRows, topLeftCol, topLeftRow, blockExtent ) );
QCOMPARE( nCols, 3000 );
QCOMPARE( nRows, 2500 );
QCOMPARE( topLeftCol, 0 );
QCOMPARE( topLeftRow, 0 );
QCOMPARE( blockExtent.xMinimum(), 497470.0 );
QCOMPARE( blockExtent.xMaximum(), 497770.0 );
QCOMPARE( blockExtent.yMinimum(), 7050880.0 );
QCOMPARE( blockExtent.yMaximum(), 7051130.0 );
QCOMPARE( blockExtent.xMinimum(), mpRasterLayer->extent().xMinimum() + topLeftCol * mpRasterLayer->rasterUnitsPerPixelX() );
QCOMPARE( blockExtent.yMinimum(), mpRasterLayer->extent().yMaximum() - nRows * mpRasterLayer->rasterUnitsPerPixelY() );
QCOMPARE( blockExtent.width(), nCols * mpRasterLayer->rasterUnitsPerPixelX() );
QCOMPARE( blockExtent.height(), nRows * mpRasterLayer->rasterUnitsPerPixelY() );
QVERIFY( it.next( 1, nCols, nRows, topLeftCol, topLeftRow, blockExtent ) );
QCOMPARE( nCols, 3000 );
QCOMPARE( nRows, 2500 );
QCOMPARE( topLeftCol, 3000 );
QCOMPARE( topLeftRow, 0 );
QCOMPARE( blockExtent.xMinimum(), mpRasterLayer->extent().xMinimum() + topLeftCol * mpRasterLayer->rasterUnitsPerPixelX() );
QCOMPARE( blockExtent.yMinimum(), mpRasterLayer->extent().yMaximum() - nRows * mpRasterLayer->rasterUnitsPerPixelY() );
QCOMPARE( blockExtent.width(), nCols * mpRasterLayer->rasterUnitsPerPixelX() );
QCOMPARE( blockExtent.height(), nRows * mpRasterLayer->rasterUnitsPerPixelY() );
QVERIFY( it.next( 1, nCols, nRows, topLeftCol, topLeftRow, blockExtent ) );
QCOMPARE( nCols, 1200 );
QCOMPARE( nRows, 2500 );
QCOMPARE( topLeftCol, 6000 );
QCOMPARE( topLeftRow, 0 );
QCOMPARE( blockExtent.xMinimum(), mpRasterLayer->extent().xMinimum() + topLeftCol * mpRasterLayer->rasterUnitsPerPixelX() );
QCOMPARE( blockExtent.yMinimum(), mpRasterLayer->extent().yMaximum() - nRows * mpRasterLayer->rasterUnitsPerPixelY() );
QCOMPARE( blockExtent.width(), nCols * mpRasterLayer->rasterUnitsPerPixelX() );
QCOMPARE( blockExtent.height(), nRows * mpRasterLayer->rasterUnitsPerPixelY() );
QVERIFY( it.next( 1, nCols, nRows, topLeftCol, topLeftRow, blockExtent ) );
QCOMPARE( nCols, 3000 );
QCOMPARE( nRows, 2500 );
QCOMPARE( topLeftCol, 0 );
QCOMPARE( topLeftRow, 2500 );
QCOMPARE( blockExtent.xMinimum(), mpRasterLayer->extent().xMinimum() + topLeftCol * mpRasterLayer->rasterUnitsPerPixelX() );
QCOMPARE( blockExtent.yMinimum(), mpRasterLayer->extent().yMaximum() - ( nRows + topLeftRow )* mpRasterLayer->rasterUnitsPerPixelY() );
QCOMPARE( blockExtent.width(), nCols * mpRasterLayer->rasterUnitsPerPixelX() );
QCOMPARE( blockExtent.height(), nRows * mpRasterLayer->rasterUnitsPerPixelY() );
QVERIFY( it.next( 1, nCols, nRows, topLeftCol, topLeftRow, blockExtent ) );
QCOMPARE( nCols, 3000 );
QCOMPARE( nRows, 2500 );
QCOMPARE( topLeftCol, 3000 );
QCOMPARE( topLeftRow, 2500 );
QCOMPARE( blockExtent.xMinimum(), mpRasterLayer->extent().xMinimum() + topLeftCol * mpRasterLayer->rasterUnitsPerPixelX() );
QCOMPARE( blockExtent.yMinimum(), mpRasterLayer->extent().yMaximum() - ( nRows + topLeftRow )* mpRasterLayer->rasterUnitsPerPixelY() );
QCOMPARE( blockExtent.width(), nCols * mpRasterLayer->rasterUnitsPerPixelX() );
QCOMPARE( blockExtent.height(), nRows * mpRasterLayer->rasterUnitsPerPixelY() );
QVERIFY( it.next( 1, nCols, nRows, topLeftCol, topLeftRow, blockExtent ) );
QCOMPARE( nCols, 1200 );
QCOMPARE( nRows, 2500 );
QCOMPARE( topLeftCol, 6000 );
QCOMPARE( topLeftRow, 2500 );
QCOMPARE( blockExtent.xMinimum(), mpRasterLayer->extent().xMinimum() + topLeftCol * mpRasterLayer->rasterUnitsPerPixelX() );
QCOMPARE( blockExtent.yMinimum(), mpRasterLayer->extent().yMaximum() - ( nRows + topLeftRow )* mpRasterLayer->rasterUnitsPerPixelY() );
QCOMPARE( blockExtent.width(), nCols * mpRasterLayer->rasterUnitsPerPixelX() );
QCOMPARE( blockExtent.height(), nRows * mpRasterLayer->rasterUnitsPerPixelY() );
QVERIFY( it.next( 1, nCols, nRows, topLeftCol, topLeftRow, blockExtent ) );
QCOMPARE( nCols, 3000 );
QCOMPARE( nRows, 450 );
QCOMPARE( topLeftCol, 0 );
QCOMPARE( topLeftRow, 5000 );
QCOMPARE( blockExtent.xMinimum(), mpRasterLayer->extent().xMinimum() + topLeftCol * mpRasterLayer->rasterUnitsPerPixelX() );
QCOMPARE( blockExtent.yMinimum(), mpRasterLayer->extent().yMaximum() - ( nRows + topLeftRow )* mpRasterLayer->rasterUnitsPerPixelY() );
QCOMPARE( blockExtent.width(), nCols * mpRasterLayer->rasterUnitsPerPixelX() );
QCOMPARE( blockExtent.height(), nRows * mpRasterLayer->rasterUnitsPerPixelY() );
QVERIFY( it.next( 1, nCols, nRows, topLeftCol, topLeftRow, blockExtent ) );
QCOMPARE( nCols, 3000 );
QCOMPARE( nRows, 450 );
QCOMPARE( topLeftCol, 3000 );
QCOMPARE( topLeftRow, 5000 );
QCOMPARE( blockExtent.xMinimum(), mpRasterLayer->extent().xMinimum() + topLeftCol * mpRasterLayer->rasterUnitsPerPixelX() );
QCOMPARE( blockExtent.yMinimum(), mpRasterLayer->extent().yMaximum() - ( nRows + topLeftRow )* mpRasterLayer->rasterUnitsPerPixelY() );
QCOMPARE( blockExtent.width(), nCols * mpRasterLayer->rasterUnitsPerPixelX() );
QCOMPARE( blockExtent.height(), nRows * mpRasterLayer->rasterUnitsPerPixelY() );
QVERIFY( it.next( 1, nCols, nRows, topLeftCol, topLeftRow, blockExtent ) );
QCOMPARE( nCols, 1200 );
QCOMPARE( nRows, 450 );
QCOMPARE( topLeftCol, 6000 );
QCOMPARE( topLeftRow, 5000 );
QCOMPARE( blockExtent.xMinimum(), mpRasterLayer->extent().xMinimum() + topLeftCol * mpRasterLayer->rasterUnitsPerPixelX() );
QCOMPARE( blockExtent.yMinimum(), mpRasterLayer->extent().yMaximum() - ( nRows + topLeftRow )* mpRasterLayer->rasterUnitsPerPixelY() );
QCOMPARE( blockExtent.width(), nCols * mpRasterLayer->rasterUnitsPerPixelX() );
QCOMPARE( blockExtent.height(), nRows * mpRasterLayer->rasterUnitsPerPixelY() );
QVERIFY( !it.next( 1, nCols, nRows, topLeftCol, topLeftRow, blockExtent ) );
}
QGSTEST_MAIN( TestQgsRasterIterator )