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