QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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
98bool QgsRasterIterator::next( int bandNumber, int &columns, int &rows, int &topLeftColumn, int &topLeftRow, QgsRectangle &blockExtent )
99{
100 int outTileColumns = 0;
101 int outTileRows = 0;
102 int outTileTopLeftColumn = 0;
103 int outTileTopLeftRow = 0;
104 return readNextRasterPartInternal( bandNumber, columns, rows, nullptr, topLeftColumn, topLeftRow, &blockExtent, outTileColumns, outTileRows, outTileTopLeftColumn, outTileTopLeftRow );
105}
106
108 int &nCols, int &nRows,
109 QgsRasterBlock **block,
110 int &topLeftCol, int &topLeftRow )
111{
112 *block = nullptr;
113 std::unique_ptr< QgsRasterBlock > nextBlock;
114 const bool result = readNextRasterPart( bandNumber, nCols, nRows, nextBlock, topLeftCol, topLeftRow );
115 if ( result )
116 *block = nextBlock.release();
117 return result;
118}
119
120bool 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 )
121{
122 int outTileColumns = 0;
123 int outTileRows = 0;
124 int outTileTopLeftColumn = 0;
125 int outTileTopLeftRow = 0;
126 const bool res = readNextRasterPartInternal( bandNumber, nCols, nRows, &block, topLeftCol, topLeftRow, blockExtent, outTileColumns, outTileRows, outTileTopLeftColumn, outTileTopLeftRow );
127
128 if ( tileColumns )
129 *tileColumns = outTileColumns;
130 if ( tileRows )
131 *tileRows = outTileRows;
132 if ( tileTopLeftColumn )
133 *tileTopLeftColumn = outTileTopLeftColumn;
134 if ( tileTopLeftRow )
135 *tileTopLeftRow = outTileTopLeftRow;
136
137 return res;
138}
139
140bool 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 )
141{
142 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
143 if ( block )
144 block->reset();
145 //get partinfo
146 const QMap<int, RasterPartInfo>::iterator partIt = mRasterPartInfos.find( bandNumber );
147 if ( partIt == mRasterPartInfos.end() )
148 {
149 return false;
150 }
151
152 RasterPartInfo &pInfo = partIt.value();
153
154 // If we started with zero cols or zero rows, just return (avoids divide by zero below)
155 if ( 0 == pInfo.nCols || 0 == pInfo.nRows )
156 {
157 return false;
158 }
159
160 //remove last data block
161
162 //already at end
163 if ( pInfo.currentCol == pInfo.nCols && pInfo.currentRow == pInfo.nRows )
164 {
165 return false;
166 }
167
168 //read data block
169
170 tileTopLeftColumn = pInfo.currentCol;
171 tileTopLeftRow = pInfo.currentRow;
172 tileColumns = static_cast< int >( std::min( static_cast< qgssize >( mMaximumTileWidth ), pInfo.nCols - tileTopLeftColumn ) );
173 tileRows = static_cast< int >( std::min( static_cast< qgssize >( mMaximumTileHeight ), pInfo.nRows - tileTopLeftRow ) );
174 const qgssize tileRight = tileTopLeftColumn + tileColumns;
175 const qgssize tileBottom = tileTopLeftRow + tileRows;
176
177 const qgssize blockLeft = tileTopLeftColumn >= mTileOverlapPixels ? ( tileTopLeftColumn - mTileOverlapPixels ) : 0;
178 const qgssize blockTop = tileTopLeftRow >= mTileOverlapPixels ? ( tileTopLeftRow - mTileOverlapPixels ) : 0;
179 const qgssize blockRight = std::min< qgssize >( tileRight + mTileOverlapPixels, pInfo.nCols );
180 const qgssize blockBottom = std::min< qgssize >( tileBottom + mTileOverlapPixels, pInfo.nRows );
181
182 nCols = blockRight - blockLeft;
183 nRows = blockBottom - blockTop;
184
185 QgsDebugMsgLevel( QStringLiteral( "nCols = %1 nRows = %2" ).arg( nCols ).arg( nRows ), 4 );
186
187 //get subrectangle
188 const QgsRectangle viewPortExtent = mExtent;
189 const double xmin = viewPortExtent.xMinimum() + blockLeft / static_cast< double >( pInfo.nCols ) * viewPortExtent.width();
190 const double xmax = blockLeft + nCols == pInfo.nCols ? viewPortExtent.xMaximum() : // avoid extra FP math if not necessary
191 viewPortExtent.xMinimum() + ( blockLeft + nCols ) / static_cast< double >( pInfo.nCols ) * viewPortExtent.width();
192 const double ymin = blockTop + nRows == pInfo.nRows ? viewPortExtent.yMinimum() : // avoid extra FP math if not necessary
193 viewPortExtent.yMaximum() - ( blockTop + nRows ) / static_cast< double >( pInfo.nRows ) * viewPortExtent.height();
194 const double ymax = viewPortExtent.yMaximum() - blockTop / static_cast< double >( pInfo.nRows ) * viewPortExtent.height();
195 const QgsRectangle blockRect( xmin, ymin, xmax, ymax );
196
197 if ( blockExtent )
198 *blockExtent = blockRect;
199
200 if ( block )
201 block->reset( mInput->block( bandNumber, blockRect, nCols, nRows, mFeedback ) );
202 topLeftCol = blockLeft;
203 topLeftRow = blockTop;
204
205 pInfo.currentCol = tileRight;
206 if ( pInfo.currentCol == pInfo.nCols && tileBottom == pInfo.nRows ) //end of raster
207 {
208 pInfo.currentRow = pInfo.nRows;
209 }
210 else if ( pInfo.currentCol == pInfo.nCols ) //start new row
211 {
212 pInfo.currentCol = 0;
213 pInfo.currentRow = tileBottom;
214 }
215
216 return true;
217}
218
220{
221 removePartInfo( bandNumber );
222}
223
224void QgsRasterIterator::removePartInfo( int bandNumber )
225{
226 const auto partIt = mRasterPartInfos.constFind( bandNumber );
227 if ( partIt != mRasterPartInfos.constEnd() )
228 {
229 mRasterPartInfos.remove( bandNumber );
230 }
231}
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.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:201
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:211
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:236
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:196
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:206
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:243
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:5747
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39