QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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"
17#include "qgsrasterprojector.h"
18#include "qgsrasterviewport.h"
20
22 : mInput( input )
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();
32 mMaximumTileHeight = rdp->stepHeight();
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 )
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 subRegionWidth = right - left + 1;
67 subRegionHeight = bottom - top + 1;
68 subRegionLeft = left;
69 subRegionTop = top;
70
71 return QgsRectangle( rasterExtent.xMinimum() + ( left * xRes ),
72 rasterExtent.yMaximum() - ( ( top + subRegionHeight ) * yRes ),
73 rasterExtent.xMinimum() + ( ( left + subRegionWidth ) * xRes ),
74 rasterExtent.yMaximum() - ( top * yRes ) );
75}
76
77void QgsRasterIterator::startRasterRead( int bandNumber, qgssize nCols, qgssize nRows, const QgsRectangle &extent, QgsRasterBlockFeedback *feedback )
78{
79 if ( !mInput )
80 {
81 return;
82 }
83
84 mExtent = extent;
85 mFeedback = feedback;
86
87 //remove any previous part on that band
88 removePartInfo( bandNumber );
89
90 //split raster into small portions if necessary
91 RasterPartInfo pInfo;
92 pInfo.nCols = nCols;
93 pInfo.nRows = nRows;
94 pInfo.currentCol = 0;
95 pInfo.currentRow = 0;
96 mRasterPartInfos.insert( bandNumber, pInfo );
97}
98
99bool QgsRasterIterator::next( int bandNumber, int &columns, int &rows, int &topLeftColumn, int &topLeftRow, QgsRectangle &blockExtent )
100{
101 return readNextRasterPartInternal( bandNumber, columns, rows, nullptr, topLeftColumn, topLeftRow, &blockExtent );
102}
103
105 int &nCols, int &nRows,
106 QgsRasterBlock **block,
107 int &topLeftCol, int &topLeftRow )
108{
109 *block = nullptr;
110 std::unique_ptr< QgsRasterBlock > nextBlock;
111 const bool result = readNextRasterPart( bandNumber, nCols, nRows, nextBlock, topLeftCol, topLeftRow );
112 if ( result )
113 *block = nextBlock.release();
114 return result;
115}
116
117bool QgsRasterIterator::readNextRasterPart( int bandNumber, int &nCols, int &nRows, std::unique_ptr<QgsRasterBlock> &block, int &topLeftCol, int &topLeftRow, QgsRectangle *blockExtent )
118{
119 return readNextRasterPartInternal( bandNumber, nCols, nRows, &block, topLeftCol, topLeftRow, blockExtent );
120}
121
122bool QgsRasterIterator::readNextRasterPartInternal( int bandNumber, int &nCols, int &nRows, std::unique_ptr<QgsRasterBlock> *block, int &topLeftCol, int &topLeftRow, QgsRectangle *blockExtent )
123{
124 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
125 if ( block )
126 block->reset();
127 //get partinfo
128 const QMap<int, RasterPartInfo>::iterator partIt = mRasterPartInfos.find( bandNumber );
129 if ( partIt == mRasterPartInfos.end() )
130 {
131 return false;
132 }
133
134 RasterPartInfo &pInfo = partIt.value();
135
136 // If we started with zero cols or zero rows, just return (avoids divide by zero below)
137 if ( 0 == pInfo.nCols || 0 == pInfo.nRows )
138 {
139 return false;
140 }
141
142 //remove last data block
143
144 //already at end
145 if ( pInfo.currentCol == pInfo.nCols && pInfo.currentRow == pInfo.nRows )
146 {
147 return false;
148 }
149
150 //read data block
151 nCols = static_cast< int >( std::min( static_cast< qgssize >( mMaximumTileWidth ), pInfo.nCols - pInfo.currentCol ) );
152 nRows = static_cast< int >( std::min( static_cast< qgssize >( mMaximumTileHeight ), pInfo.nRows - pInfo.currentRow ) );
153 QgsDebugMsgLevel( QStringLiteral( "nCols = %1 nRows = %2" ).arg( nCols ).arg( nRows ), 4 );
154
155 //get subrectangle
156 const QgsRectangle viewPortExtent = mExtent;
157 const double xmin = viewPortExtent.xMinimum() + pInfo.currentCol / static_cast< double >( pInfo.nCols ) * viewPortExtent.width();
158 const double xmax = pInfo.currentCol + nCols == pInfo.nCols ? viewPortExtent.xMaximum() : // avoid extra FP math if not necessary
159 viewPortExtent.xMinimum() + ( pInfo.currentCol + nCols ) / static_cast< double >( pInfo.nCols ) * viewPortExtent.width();
160 const double ymin = pInfo.currentRow + nRows == pInfo.nRows ? viewPortExtent.yMinimum() : // avoid extra FP math if not necessary
161 viewPortExtent.yMaximum() - ( pInfo.currentRow + nRows ) / static_cast< double >( pInfo.nRows ) * viewPortExtent.height();
162 const double ymax = viewPortExtent.yMaximum() - pInfo.currentRow / static_cast< double >( pInfo.nRows ) * viewPortExtent.height();
163 const QgsRectangle blockRect( xmin, ymin, xmax, ymax );
164
165 if ( blockExtent )
166 *blockExtent = blockRect;
167
168 if ( block )
169 block->reset( mInput->block( bandNumber, blockRect, nCols, nRows, mFeedback ) );
170 topLeftCol = pInfo.currentCol;
171 topLeftRow = pInfo.currentRow;
172
173 pInfo.currentCol += nCols;
174 if ( pInfo.currentCol == pInfo.nCols && pInfo.currentRow + nRows == pInfo.nRows ) //end of raster
175 {
176 pInfo.currentRow = pInfo.nRows;
177 }
178 else if ( pInfo.currentCol == pInfo.nCols ) //start new row
179 {
180 pInfo.currentCol = 0;
181 pInfo.currentRow += nRows;
182 }
183
184 return true;
185}
186
188{
189 removePartInfo( bandNumber );
190}
191
192void QgsRasterIterator::removePartInfo( int bandNumber )
193{
194 const auto partIt = mRasterPartInfos.constFind( bandNumber );
195 if ( partIt != mRasterPartInfos.constEnd() )
196 {
197 mRasterPartInfos.remove( bandNumber );
198 }
199}
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.
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.
QgsRasterIterator(QgsRasterInterface *input)
Constructor for QgsRasterIterator, iterating over the specified input raster source.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:183
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
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:3032
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39