QGIS API Documentation 3.41.0-Master (3440c17df1d)
Loading...
Searching...
No Matches
qgsrasteriterator.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsrasteriterator.cpp
3 ---------------------
4 begin : July 2012
5 copyright : (C) 2012 by Marco Hugentobler
6 email : marco dot hugentobler at sourcepole dot ch
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15#include "qgsrasteriterator.h"
16#include "qgsrasterinterface.h"
18
20 : mInput( input )
21 , mTileOverlapPixels( tileOverlapPixels )
22 , mMaximumTileWidth( DEFAULT_MAXIMUM_TILE_WIDTH )
23 , mMaximumTileHeight( DEFAULT_MAXIMUM_TILE_HEIGHT )
24{
25 for ( QgsRasterInterface *ri = input; ri; ri = ri->input() )
26 {
27 QgsRasterDataProvider *rdp = dynamic_cast<QgsRasterDataProvider *>( ri );
28 if ( rdp )
29 {
30 mMaximumTileWidth = rdp->stepWidth() - 2 * mTileOverlapPixels;
31 mMaximumTileHeight = rdp->stepHeight() - 2 * mTileOverlapPixels;
32 break;
33 }
34 }
35}
36
37QgsRectangle QgsRasterIterator::subRegion( const QgsRectangle &rasterExtent, int rasterWidth, int rasterHeight, const QgsRectangle &subRegion, int &subRegionWidth, int &subRegionHeight, int &subRegionLeft, int &subRegionTop )
38{
39 const double xRes = rasterExtent.width() / rasterWidth;
40 const double yRes = rasterExtent.height() / rasterHeight;
41
42 int top = 0;
43 int bottom = rasterHeight - 1;
44 int left = 0;
45 int right = rasterWidth - 1;
46
47 if ( subRegion.yMaximum() < rasterExtent.yMaximum() )
48 {
49 top = static_cast< int >( std::floor( ( rasterExtent.yMaximum() - subRegion.yMaximum() ) / yRes ) );
50 }
51 if ( subRegion.yMinimum() > rasterExtent.yMinimum() )
52 {
53 bottom = static_cast< int >( std::ceil( ( rasterExtent.yMaximum() - subRegion.yMinimum() ) / yRes ) - 1 );
54 }
55
56 if ( subRegion.xMinimum() > rasterExtent.xMinimum() )
57 {
58 left = static_cast< int >( std::floor( ( subRegion.xMinimum() - rasterExtent.xMinimum() ) / xRes ) );
59 }
60 if ( subRegion.xMaximum() < rasterExtent.xMaximum() )
61 {
62 right = static_cast< int >( std::ceil( ( subRegion.xMaximum() - rasterExtent.xMinimum() ) / xRes ) - 1 );
63 }
64
65 subRegionWidth = right - left + 1;
66 subRegionHeight = bottom - top + 1;
67 subRegionLeft = left;
68 subRegionTop = top;
69
70 return QgsRectangle( rasterExtent.xMinimum() + ( left * xRes ),
71 rasterExtent.yMaximum() - ( ( top + subRegionHeight ) * yRes ),
72 rasterExtent.xMinimum() + ( ( left + subRegionWidth ) * xRes ),
73 rasterExtent.yMaximum() - ( top * yRes ) );
74}
75
76void QgsRasterIterator::startRasterRead( int bandNumber, qgssize nCols, qgssize nRows, const QgsRectangle &extent, QgsRasterBlockFeedback *feedback )
77{
78 if ( !mInput )
79 {
80 return;
81 }
82
83 mExtent = extent;
84 mFeedback = feedback;
85
86 //remove any previous part on that band
87 removePartInfo( bandNumber );
88
89 //split raster into small portions if necessary
90 RasterPartInfo pInfo;
91 pInfo.nCols = nCols;
92 pInfo.nRows = nRows;
93 pInfo.currentCol = 0;
94 pInfo.currentRow = 0;
95 mRasterPartInfos.insert( bandNumber, pInfo );
96
97 mNumberBlocksWidth = static_cast< int >( std::ceil( static_cast< double >( nCols ) / mMaximumTileWidth ) );
98 mNumberBlocksHeight = static_cast< int >( std::ceil( static_cast< double >( nRows ) / mMaximumTileHeight ) );
99}
100
101bool QgsRasterIterator::next( int bandNumber, int &columns, int &rows, int &topLeftColumn, int &topLeftRow, QgsRectangle &blockExtent )
102{
103 int outTileColumns = 0;
104 int outTileRows = 0;
105 int outTileTopLeftColumn = 0;
106 int outTileTopLeftRow = 0;
107 return readNextRasterPartInternal( bandNumber, columns, rows, nullptr, topLeftColumn, topLeftRow, &blockExtent, outTileColumns, outTileRows, outTileTopLeftColumn, outTileTopLeftRow );
108}
109
111 int &nCols, int &nRows,
112 QgsRasterBlock **block,
113 int &topLeftCol, int &topLeftRow )
114{
115 *block = nullptr;
116 std::unique_ptr< QgsRasterBlock > nextBlock;
117 const bool result = readNextRasterPart( bandNumber, nCols, nRows, nextBlock, topLeftCol, topLeftRow );
118 if ( result )
119 *block = nextBlock.release();
120 return result;
121}
122
123bool QgsRasterIterator::readNextRasterPart( int bandNumber, int &nCols, int &nRows, std::unique_ptr<QgsRasterBlock> &block, int &topLeftCol, int &topLeftRow, QgsRectangle *blockExtent, int *tileColumns, int *tileRows, int *tileTopLeftColumn, int *tileTopLeftRow )
124{
125 int outTileColumns = 0;
126 int outTileRows = 0;
127 int outTileTopLeftColumn = 0;
128 int outTileTopLeftRow = 0;
129 const bool res = readNextRasterPartInternal( bandNumber, nCols, nRows, &block, topLeftCol, topLeftRow, blockExtent, outTileColumns, outTileRows, outTileTopLeftColumn, outTileTopLeftRow );
130
131 if ( tileColumns )
132 *tileColumns = outTileColumns;
133 if ( tileRows )
134 *tileRows = outTileRows;
135 if ( tileTopLeftColumn )
136 *tileTopLeftColumn = outTileTopLeftColumn;
137 if ( tileTopLeftRow )
138 *tileTopLeftRow = outTileTopLeftRow;
139
140 return res;
141}
142
143bool QgsRasterIterator::readNextRasterPartInternal( int bandNumber, int &nCols, int &nRows, std::unique_ptr<QgsRasterBlock> *block, int &topLeftCol, int &topLeftRow, QgsRectangle *blockExtent, int &tileColumns, int &tileRows, int &tileTopLeftColumn, int &tileTopLeftRow )
144{
145 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
146 if ( block )
147 block->reset();
148 //get partinfo
149 const QMap<int, RasterPartInfo>::iterator partIt = mRasterPartInfos.find( bandNumber );
150 if ( partIt == mRasterPartInfos.end() )
151 {
152 return false;
153 }
154
155 RasterPartInfo &pInfo = partIt.value();
156
157 // If we started with zero cols or zero rows, just return (avoids divide by zero below)
158 if ( 0 == pInfo.nCols || 0 == pInfo.nRows )
159 {
160 return false;
161 }
162
163 //remove last data block
164
165 //already at end
166 if ( pInfo.currentCol == pInfo.nCols && pInfo.currentRow == pInfo.nRows )
167 {
168 return false;
169 }
170
171 //read data block
172
173 tileTopLeftColumn = pInfo.currentCol;
174 tileTopLeftRow = pInfo.currentRow;
175 tileColumns = static_cast< int >( std::min( static_cast< qgssize >( mMaximumTileWidth ), pInfo.nCols - tileTopLeftColumn ) );
176 tileRows = static_cast< int >( std::min( static_cast< qgssize >( mMaximumTileHeight ), pInfo.nRows - tileTopLeftRow ) );
177 const qgssize tileRight = tileTopLeftColumn + tileColumns;
178 const qgssize tileBottom = tileTopLeftRow + tileRows;
179
180 const qgssize blockLeft = tileTopLeftColumn >= mTileOverlapPixels ? ( tileTopLeftColumn - mTileOverlapPixels ) : 0;
181 const qgssize blockTop = tileTopLeftRow >= mTileOverlapPixels ? ( tileTopLeftRow - mTileOverlapPixels ) : 0;
182 const qgssize blockRight = std::min< qgssize >( tileRight + mTileOverlapPixels, pInfo.nCols );
183 const qgssize blockBottom = std::min< qgssize >( tileBottom + mTileOverlapPixels, pInfo.nRows );
184
185 nCols = blockRight - blockLeft;
186 nRows = blockBottom - blockTop;
187
188 QgsDebugMsgLevel( QStringLiteral( "nCols = %1 nRows = %2" ).arg( nCols ).arg( nRows ), 4 );
189
190 //get subrectangle
191 const QgsRectangle viewPortExtent = mExtent;
192 const double xmin = viewPortExtent.xMinimum() + blockLeft / static_cast< double >( pInfo.nCols ) * viewPortExtent.width();
193 const double xmax = blockLeft + nCols == pInfo.nCols ? viewPortExtent.xMaximum() : // avoid extra FP math if not necessary
194 viewPortExtent.xMinimum() + ( blockLeft + nCols ) / static_cast< double >( pInfo.nCols ) * viewPortExtent.width();
195 const double ymin = blockTop + nRows == pInfo.nRows ? viewPortExtent.yMinimum() : // avoid extra FP math if not necessary
196 viewPortExtent.yMaximum() - ( blockTop + nRows ) / static_cast< double >( pInfo.nRows ) * viewPortExtent.height();
197 const double ymax = viewPortExtent.yMaximum() - blockTop / static_cast< double >( pInfo.nRows ) * viewPortExtent.height();
198 const QgsRectangle blockRect( xmin, ymin, xmax, ymax );
199
200 if ( blockExtent )
201 *blockExtent = blockRect;
202
203 if ( block )
204 block->reset( mInput->block( bandNumber, blockRect, nCols, nRows, mFeedback ) );
205 topLeftCol = blockLeft;
206 topLeftRow = blockTop;
207
208 pInfo.currentCol = tileRight;
209 if ( pInfo.currentCol == pInfo.nCols && tileBottom == pInfo.nRows ) //end of raster
210 {
211 pInfo.currentRow = pInfo.nRows;
212 }
213 else if ( pInfo.currentCol == pInfo.nCols ) //start new row
214 {
215 pInfo.currentCol = 0;
216 pInfo.currentRow = tileBottom;
217 }
218
219 return true;
220}
221
223{
224 removePartInfo( bandNumber );
225}
226
227double QgsRasterIterator::progress( int bandNumber ) const
228{
229 const auto partIt = mRasterPartInfos.find( bandNumber );
230 if ( partIt == mRasterPartInfos.constEnd() )
231 {
232 return 0;
233 }
234
235 return ( ( static_cast< double >( partIt->currentRow ) / static_cast< double >( mMaximumTileHeight ) ) * mNumberBlocksWidth + static_cast< double >( partIt->currentCol ) / static_cast< double >( mMaximumTileWidth ) ) / ( static_cast< double >( mNumberBlocksWidth ) * static_cast< double >( mNumberBlocksHeight ) );
236}
237
238void QgsRasterIterator::removePartInfo( int bandNumber )
239{
240 const auto partIt = mRasterPartInfos.constFind( bandNumber );
241 if ( partIt != mRasterPartInfos.constEnd() )
242 {
243 mRasterPartInfos.remove( bandNumber );
244 }
245}
Feedback object tailored for raster block reading.
Raster data container.
Base class for raster data providers.
virtual int stepHeight() const
Step height for raster iterations.
virtual int stepWidth() const
Step width for raster iterations.
Base class for processing filters like renderers, reprojector, resampler etc.
virtual QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr)=0
Read block of data using given extent and size.
virtual QgsRasterInterface * input() const
Current input.
bool next(int bandNumber, int &columns, int &rows, int &topLeftColumn, int &topLeftRow, QgsRectangle &blockExtent)
Fetches details of the next part of the raster data.
QgsRasterIterator(QgsRasterInterface *input, int tileOverlapPixels=0)
Constructor for QgsRasterIterator, iterating over the specified input raster source.
const QgsRasterInterface * input() const
Returns the input raster interface which is being iterated over.
void stopRasterRead(int bandNumber)
Cancels the raster iteration and resets the iterator.
bool readNextRasterPart(int bandNumber, int &nCols, int &nRows, QgsRasterBlock **block, int &topLeftCol, int &topLeftRow)
Fetches next part of raster data, caller takes ownership of the block and caller should delete the bl...
static QgsRectangle subRegion(const QgsRectangle &rasterExtent, int rasterWidth, int rasterHeight, const QgsRectangle &subRegion, int &subRegionWidth, int &subRegionHeight, int &subRegionLeft, int &subRegionTop)
Given an overall raster extent and width and height in pixels, calculates the sub region of the raste...
void startRasterRead(int bandNumber, qgssize nCols, qgssize nRows, const QgsRectangle &extent, QgsRasterBlockFeedback *feedback=nullptr)
Start reading of raster band.
double progress(int bandNumber) const
Returns the raster iteration progress as a fraction from 0 to 1.0, for the specified bandNumber.
A rectangle specified with double values.
double xMinimum
double yMinimum
double xMaximum
double yMaximum
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
Definition qgis.h:6506
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39