QGIS API Documentation 3.99.0-Master (2fe06baccd8)
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
18#include "qgsrasterinterface.h"
19
21 : mInput( input )
22 , mTileOverlapPixels( tileOverlapPixels )
23 , mMaximumTileWidth( DEFAULT_MAXIMUM_TILE_WIDTH )
24 , mMaximumTileHeight( DEFAULT_MAXIMUM_TILE_HEIGHT )
25{
26 for ( QgsRasterInterface *ri = input; ri; ri = ri->input() )
27 {
28 QgsRasterDataProvider *rdp = dynamic_cast<QgsRasterDataProvider *>( ri );
29 if ( rdp )
30 {
31 mMaximumTileWidth = rdp->stepWidth() - 2 * mTileOverlapPixels;
32 mMaximumTileHeight = rdp->stepHeight() - 2 * mTileOverlapPixels;
33 break;
34 }
35 }
36}
37
38QgsRectangle QgsRasterIterator::subRegion( const QgsRectangle &rasterExtent, int rasterWidth, int rasterHeight, const QgsRectangle &subRegion, int &subRegionWidth, int &subRegionHeight, int &subRegionLeft, int &subRegionTop, int resamplingFactor )
39{
40 const double xRes = rasterExtent.width() / rasterWidth;
41 const double yRes = rasterExtent.height() / rasterHeight;
42
43 int top = 0;
44 int bottom = rasterHeight - 1;
45 int left = 0;
46 int right = rasterWidth - 1;
47
48 if ( subRegion.yMaximum() < rasterExtent.yMaximum() )
49 {
50 top = static_cast< int >( std::floor( ( rasterExtent.yMaximum() - subRegion.yMaximum() ) / yRes ) );
51 }
52 if ( subRegion.yMinimum() > rasterExtent.yMinimum() )
53 {
54 bottom = static_cast< int >( std::ceil( ( rasterExtent.yMaximum() - subRegion.yMinimum() ) / yRes ) - 1 );
55 }
56
57 if ( subRegion.xMinimum() > rasterExtent.xMinimum() )
58 {
59 left = static_cast< int >( std::floor( ( subRegion.xMinimum() - rasterExtent.xMinimum() ) / xRes ) );
60 }
61 if ( subRegion.xMaximum() < rasterExtent.xMaximum() )
62 {
63 right = static_cast< int >( std::ceil( ( subRegion.xMaximum() - rasterExtent.xMinimum() ) / xRes ) - 1 );
64 }
65
66 if ( resamplingFactor > 1 )
67 {
68 // Round up the starting boundaries to resampling grid
69 left = ( ( left + resamplingFactor - 1 ) / resamplingFactor ) * resamplingFactor;
70 top = ( ( top + resamplingFactor - 1 ) / resamplingFactor ) * resamplingFactor;
71
72 // Round down the ending boundaries to resampling grid
73 right = ( right / resamplingFactor ) * resamplingFactor - 1;
74 bottom = ( bottom / resamplingFactor ) * resamplingFactor - 1;
75 }
76
77 subRegionWidth = right - left + 1;
78 subRegionHeight = bottom - top + 1;
79
80 subRegionLeft = left;
81 subRegionTop = top;
82
83 return QgsRectangle( rasterExtent.xMinimum() + ( left * xRes ),
84 rasterExtent.yMaximum() - ( ( top + subRegionHeight ) * yRes ),
85 rasterExtent.xMinimum() + ( ( left + subRegionWidth ) * xRes ),
86 rasterExtent.yMaximum() - ( top * yRes ) );
87}
88
89void QgsRasterIterator::startRasterRead( int bandNumber, qgssize nCols, qgssize nRows, const QgsRectangle &extent, QgsRasterBlockFeedback *feedback )
90{
91 if ( !mInput )
92 {
93 return;
94 }
95
96 mExtent = extent;
97 mFeedback = feedback;
98
99 //remove any previous part on that band
100 removePartInfo( bandNumber );
101
102 //split raster into small portions if necessary
103 RasterPartInfo pInfo;
104 pInfo.nCols = nCols;
105 pInfo.nRows = nRows;
106 pInfo.currentCol = 0;
107 pInfo.currentRow = 0;
108 mRasterPartInfos.insert( bandNumber, pInfo );
109
110 mNumberBlocksWidth = static_cast< int >( std::ceil( static_cast< double >( nCols ) / mMaximumTileWidth ) );
111 mNumberBlocksHeight = static_cast< int >( std::ceil( static_cast< double >( nRows ) / mMaximumTileHeight ) );
112}
113
114bool QgsRasterIterator::next( int bandNumber, int &columns, int &rows, int &topLeftColumn, int &topLeftRow, QgsRectangle &blockExtent )
115{
116 int outTileColumns = 0;
117 int outTileRows = 0;
118 int outTileTopLeftColumn = 0;
119 int outTileTopLeftRow = 0;
120 return readNextRasterPartInternal( bandNumber, columns, rows, nullptr, topLeftColumn, topLeftRow, &blockExtent, outTileColumns, outTileRows, outTileTopLeftColumn, outTileTopLeftRow );
121}
122
124 int &nCols, int &nRows,
125 QgsRasterBlock **block,
126 int &topLeftCol, int &topLeftRow )
127{
128 *block = nullptr;
129 std::unique_ptr< QgsRasterBlock > nextBlock;
130 const bool result = readNextRasterPart( bandNumber, nCols, nRows, nextBlock, topLeftCol, topLeftRow );
131 if ( result )
132 *block = nextBlock.release();
133 return result;
134}
135
136bool 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 )
137{
138 int outTileColumns = 0;
139 int outTileRows = 0;
140 int outTileTopLeftColumn = 0;
141 int outTileTopLeftRow = 0;
142 const bool res = readNextRasterPartInternal( bandNumber, nCols, nRows, &block, topLeftCol, topLeftRow, blockExtent, outTileColumns, outTileRows, outTileTopLeftColumn, outTileTopLeftRow );
143
144 if ( tileColumns )
145 *tileColumns = outTileColumns;
146 if ( tileRows )
147 *tileRows = outTileRows;
148 if ( tileTopLeftColumn )
149 *tileTopLeftColumn = outTileTopLeftColumn;
150 if ( tileTopLeftRow )
151 *tileTopLeftRow = outTileTopLeftRow;
152
153 return res;
154}
155
156bool 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 )
157{
158 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
159 if ( block )
160 block->reset();
161 //get partinfo
162 const QMap<int, RasterPartInfo>::iterator partIt = mRasterPartInfos.find( bandNumber );
163 if ( partIt == mRasterPartInfos.end() )
164 {
165 return false;
166 }
167
168 RasterPartInfo &pInfo = partIt.value();
169
170 // If we started with zero cols or zero rows, just return (avoids divide by zero below)
171 if ( 0 == pInfo.nCols || 0 == pInfo.nRows )
172 {
173 return false;
174 }
175
176 //remove last data block
177
178 //already at end
179 if ( pInfo.currentCol == pInfo.nCols && pInfo.currentRow == pInfo.nRows )
180 {
181 return false;
182 }
183
184 //read data block
185 tileTopLeftColumn = pInfo.currentCol;
186 tileTopLeftRow = pInfo.currentRow;
187
188 tileColumns = static_cast< int >( std::min( static_cast< qgssize >( mMaximumTileWidth ), pInfo.nCols - tileTopLeftColumn ) );
189 tileRows = static_cast< int >( std::min( static_cast< qgssize >( mMaximumTileHeight ), pInfo.nRows - tileTopLeftRow ) );
190
191 if ( mSnapToPixelFactor > 1 )
192 {
193 // Round down tile dimensions to snap factor
194 tileColumns = ( tileColumns / mSnapToPixelFactor ) * mSnapToPixelFactor;
195 tileRows = ( tileRows / mSnapToPixelFactor ) * mSnapToPixelFactor;
196 }
197
198 const qgssize tileRight = tileTopLeftColumn + tileColumns;
199 const qgssize tileBottom = tileTopLeftRow + tileRows;
200
201 const qgssize blockLeft = tileTopLeftColumn >= mTileOverlapPixels ? ( tileTopLeftColumn - mTileOverlapPixels ) : 0;
202 const qgssize blockTop = tileTopLeftRow >= mTileOverlapPixels ? ( tileTopLeftRow - mTileOverlapPixels ) : 0;
203 const qgssize blockRight = std::min< qgssize >( tileRight + mTileOverlapPixels, pInfo.nCols );
204 const qgssize blockBottom = std::min< qgssize >( tileBottom + mTileOverlapPixels, pInfo.nRows );
205
206 nCols = blockRight - blockLeft;
207 nRows = blockBottom - blockTop;
208
209 if ( mSnapToPixelFactor > 1 )
210 {
211 // Ensure overlap dimensions are also multiples of snap factor
212 nCols = ( nCols / mSnapToPixelFactor ) * mSnapToPixelFactor;
213 nRows = ( nRows / mSnapToPixelFactor ) * mSnapToPixelFactor;
214 if ( nCols == 0 || nRows == 0 )
215 return false;
216 }
217
218 QgsDebugMsgLevel( QStringLiteral( "nCols = %1 nRows = %2" ).arg( nCols ).arg( nRows ), 4 );
219
220 //get subrectangle
221 const QgsRectangle viewPortExtent = mExtent;
222 const double xmin = viewPortExtent.xMinimum() + blockLeft / static_cast< double >( pInfo.nCols ) * viewPortExtent.width();
223 const double xmax = blockLeft + nCols == pInfo.nCols ? viewPortExtent.xMaximum() : // avoid extra FP math if not necessary
224 viewPortExtent.xMinimum() + ( blockLeft + nCols ) / static_cast< double >( pInfo.nCols ) * viewPortExtent.width();
225 const double ymin = blockTop + nRows == pInfo.nRows ? viewPortExtent.yMinimum() : // avoid extra FP math if not necessary
226 viewPortExtent.yMaximum() - ( blockTop + nRows ) / static_cast< double >( pInfo.nRows ) * viewPortExtent.height();
227 const double ymax = viewPortExtent.yMaximum() - blockTop / static_cast< double >( pInfo.nRows ) * viewPortExtent.height();
228 const QgsRectangle blockRect( xmin, ymin, xmax, ymax );
229
230 if ( blockExtent )
231 *blockExtent = blockRect;
232
233 if ( block )
234 block->reset( mInput->block( bandNumber, blockRect, nCols, nRows, mFeedback ) );
235 topLeftCol = blockLeft;
236 topLeftRow = blockTop;
237
238 pInfo.currentCol = tileRight;
239 if ( pInfo.currentCol == pInfo.nCols && tileBottom == pInfo.nRows ) //end of raster
240 {
241 pInfo.currentRow = pInfo.nRows;
242 }
243 else if ( pInfo.currentCol == pInfo.nCols ) //start new row
244 {
245 pInfo.currentCol = 0;
246 pInfo.currentRow = tileBottom;
247 }
248
249 return true;
250}
251
253{
254 removePartInfo( bandNumber );
255}
256
257double QgsRasterIterator::progress( int bandNumber ) const
258{
259 const auto partIt = mRasterPartInfos.find( bandNumber );
260 if ( partIt == mRasterPartInfos.constEnd() )
261 {
262 return 0;
263 }
264
265 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 ) );
266}
267
268void QgsRasterIterator::removePartInfo( int bandNumber )
269{
270 const auto partIt = mRasterPartInfos.constFind( bandNumber );
271 if ( partIt != mRasterPartInfos.constEnd() )
272 {
273 mRasterPartInfos.remove( bandNumber );
274 }
275}
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.
static QgsRectangle subRegion(const QgsRectangle &rasterExtent, int rasterWidth, int rasterHeight, const QgsRectangle &subRegion, int &subRegionWidth, int &subRegionHeight, int &subRegionLeft, int &subRegionTop, int resamplingFactor=1)
Given an overall raster extent and width and height in pixels, calculates the sub region of the raste...
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.
static const int DEFAULT_MAXIMUM_TILE_WIDTH
Default maximum tile width.
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 const int DEFAULT_MAXIMUM_TILE_HEIGHT
Default maximum tile height.
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:7142
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:61