QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsrasterresamplefilter.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrasterresamplefilter.cpp
3  ---------------------
4  begin : December 2011
5  copyright : (C) 2011 by Marco Hugentobler
6  email : marco at sourcepole dot ch
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgsrasterdataprovider.h"
20 #include "qgsrasterresampler.h"
21 #include "qgsrasterprojector.h"
22 #include "qgsrastertransparency.h"
23 #include "qgsrasterviewport.h"
24 #include "qgsmaptopixel.h"
25 
26 //resamplers
29 
30 #include <QDomDocument>
31 #include <QDomElement>
32 #include <QImage>
33 #include <QPainter>
34 
36  : QgsRasterInterface( input )
37 {
38 }
39 
41 {
42  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
43  QgsRasterResampleFilter *resampler = new QgsRasterResampleFilter( nullptr );
44  if ( mZoomedInResampler )
45  {
46  resampler->setZoomedInResampler( mZoomedInResampler->clone() );
47  }
48  if ( mZoomedOutResampler )
49  {
50  resampler->setZoomedOutResampler( mZoomedOutResampler->clone() );
51  }
53  return resampler;
54 }
55 
57 {
58  if ( mOn ) return 1;
59 
60  if ( mInput ) return mInput->bandCount();
61 
62  return 0;
63 }
64 
66 {
68 
69  if ( mInput ) return mInput->dataType( bandNo );
70 
72 }
73 
75 {
76  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
77 
78  // Resampler can only work with single band ARGB32_Premultiplied
79  if ( !input )
80  {
81  QgsDebugMsg( QStringLiteral( "No input" ) );
82  return false;
83  }
84 
85  if ( !mOn )
86  {
87  // In off mode we can connect to anything
88  QgsDebugMsgLevel( QStringLiteral( "OK" ), 4 );
89  mInput = input;
90  return true;
91  }
92 
93  if ( input->bandCount() < 1 )
94  {
95  QgsDebugMsg( QStringLiteral( "No input band" ) );
96  return false;
97  }
98 
101  {
102  QgsDebugMsg( QStringLiteral( "Unknown input data type" ) );
103  return false;
104  }
105 
106  mInput = input;
107  QgsDebugMsgLevel( QStringLiteral( "OK" ), 4 );
108  return true;
109 }
110 
112 {
113  mZoomedInResampler.reset( r );
114 }
115 
117 {
118  mZoomedOutResampler.reset( r );
119 }
120 
121 QgsRasterBlock *QgsRasterResampleFilter::block( int bandNo, QgsRectangle const &extent, int width, int height, QgsRasterBlockFeedback *feedback )
122 {
123  if ( !mOn && mInput )
124  return mInput->block( bandNo, extent, width, height, feedback );
125 
126  const int bandNumber = 1;
127 
128  QgsDebugMsgLevel( QStringLiteral( "width = %1 height = %2 extent = %3" ).arg( width ).arg( height ).arg( extent.toString() ), 4 );
129  std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() );
130  if ( !mInput )
131  return outputBlock.release();
132 
133  double oversampling = 1.0; // approximate global oversampling factor
134  double outputXRes;
135  double providerXRes = 0;
137  {
138  QgsRasterDataProvider *provider = dynamic_cast<QgsRasterDataProvider *>( mInput->sourceInput() );
139  if ( provider && ( provider->capabilities() & QgsRasterDataProvider::Size ) )
140  {
141  outputXRes = extent.width() / width;
142  providerXRes = provider->extent().width() / provider->xSize();
143  const double pixelRatio = outputXRes / providerXRes;
144  oversampling = ( pixelRatio > mMaxOversampling ) ? mMaxOversampling : pixelRatio;
145  QgsDebugMsgLevel( QStringLiteral( "xRes = %1 providerXRes = %2 pixelRatio = %3 oversampling = %4" ).arg( outputXRes ).arg( providerXRes ).arg( pixelRatio ).arg( oversampling ), 4 );
146  }
147  else
148  {
149  // We don't know exact data source resolution (WMS) so we expect that
150  // server data have higher resolution (which is not always true) and use
151  // mMaxOversampling
152  oversampling = mMaxOversampling;
153  }
154  }
155 
156  QgsDebugMsgLevel( QStringLiteral( "oversampling %1" ).arg( oversampling ), 4 );
157 
158  // Do no oversampling if no resampler for zoomed in / zoomed out (nearest neighbour)
159  // We do mZoomedInResampler if oversampling == 1 (otherwise for example reprojected
160  // zoom in rasters are never resampled because projector limits resolution.
161  if ( ( ( oversampling < 1.0 || qgsDoubleNear( oversampling, 1.0 ) ) && !mZoomedInResampler ) || ( oversampling > 1.0 && !mZoomedOutResampler ) )
162  {
163  QgsDebugMsgLevel( QStringLiteral( "No oversampling." ), 4 );
164  return mInput->block( bandNumber, extent, width, height, feedback );
165  }
166 
167  //effective oversampling factors are different to global one because of rounding
168  const double oversamplingX = ( static_cast< double >( width ) * oversampling ) / width;
169  const double oversamplingY = ( static_cast< double >( height ) * oversampling ) / height;
170 
171  // we must also increase the extent to get correct result on borders of parts
172  int tileBufferPixels = 0;
173  if ( providerXRes != 0 )
174  {
175  if ( mZoomedInResampler && ( oversamplingX < 1.0 || qgsDoubleNear( oversampling, 1.0 ) ) )
176  {
177  tileBufferPixels = static_cast< int >( std::ceil( mZoomedInResampler->tileBufferPixels() * oversampling ) );
178  }
179  else if ( mZoomedOutResampler && oversamplingX > 1.0 )
180  {
181  tileBufferPixels = static_cast< int >( std::ceil( mZoomedOutResampler->tileBufferPixels() * oversampling ) );
182  }
183  }
184  const double sourceTileBufferSize = providerXRes * tileBufferPixels;
185 
186  const QgsRectangle bufferedExtent( extent.xMinimum() - sourceTileBufferSize,
187  extent.yMinimum() - sourceTileBufferSize,
188  extent.xMaximum() + sourceTileBufferSize,
189  extent.yMaximum() + sourceTileBufferSize
190  );
191 
192  const int resWidth = static_cast< int >( std::round( width * oversamplingX ) ) + 2 * tileBufferPixels;
193  const int resHeight = static_cast< int >( std::round( height * oversamplingY ) ) + 2 * tileBufferPixels;
194 
195  std::unique_ptr< QgsRasterBlock > inputBlock( mInput->block( bandNumber, bufferedExtent, resWidth, resHeight, feedback ) );
196  if ( !inputBlock || inputBlock->isEmpty() )
197  {
198  QgsDebugMsg( QStringLiteral( "No raster data!" ) );
199  return outputBlock.release();
200  }
201 
202  if ( !outputBlock->reset( Qgis::DataType::ARGB32_Premultiplied, width, height ) )
203  {
204  return outputBlock.release();
205  }
206 
207  //resample image
208  const QImage img = inputBlock->image();
209 
210  const int resampleWidth = static_cast< int >( std::round( width * ( bufferedExtent.width() / extent.width() ) ) );
211  const int resampleHeight = static_cast< int >( std::round( height * ( bufferedExtent.height() / extent.height() ) ) );
212 
213  QImage dstImg;
214  if ( mZoomedInResampler && ( oversamplingX < 1.0 || qgsDoubleNear( oversampling, 1.0 ) ) )
215  {
216  QgsDebugMsgLevel( QStringLiteral( "zoomed in resampling" ), 4 );
217 
218  if ( QgsRasterResamplerV2 *resamplerV2 = dynamic_cast< QgsRasterResamplerV2 * >( mZoomedInResampler.get( ) ) )
219  {
220  dstImg = resamplerV2->resampleV2( img, QSize( resampleWidth, resampleHeight ) );
221  }
222  else
223  {
224  // old inefficient interface
226  QImage dstImg = QImage( resampleWidth, resampleHeight, QImage::Format_ARGB32_Premultiplied );
227  mZoomedInResampler->resample( img, dstImg );
229  }
230  }
231  else if ( mZoomedOutResampler && oversamplingX > 1.0 )
232  {
233  QgsDebugMsgLevel( QStringLiteral( "zoomed out resampling" ), 4 );
234 
235  if ( QgsRasterResamplerV2 *resamplerV2 = dynamic_cast< QgsRasterResamplerV2 * >( mZoomedOutResampler.get( ) ) )
236  {
237  dstImg = resamplerV2->resampleV2( img, QSize( resampleWidth, resampleHeight ) );
238  }
239  else
240  {
241  // old inefficient interface
243  QImage dstImg = QImage( resampleWidth, resampleHeight, QImage::Format_ARGB32_Premultiplied );
244  mZoomedOutResampler->resample( img, dstImg );
246  }
247  }
248  else
249  {
250  // Should not happen
251  QgsDebugMsg( QStringLiteral( "Unexpected resampling" ) );
252  dstImg = img.scaled( width, height );
253  }
254 
255  // extract desired part of dstImage
256  const QImage cropped = tileBufferPixels > 0 ? dstImg.copy( ( resampleWidth - width ) / 2, ( resampleHeight - height ) / 2, width, height )
257  : dstImg; // otherwise implicit copy, nice and cheap
258  outputBlock->setImage( &cropped );
259 
260  return outputBlock.release(); // No resampling
261 }
262 
263 void QgsRasterResampleFilter::writeXml( QDomDocument &doc, QDomElement &parentElem ) const
264 {
265  if ( parentElem.isNull() )
266  {
267  return;
268  }
269 
270  QDomElement rasterRendererElem = doc.createElement( QStringLiteral( "rasterresampler" ) );
271 
272  rasterRendererElem.setAttribute( QStringLiteral( "maxOversampling" ), QString::number( mMaxOversampling ) );
273  if ( mZoomedInResampler )
274  {
275  rasterRendererElem.setAttribute( QStringLiteral( "zoomedInResampler" ), mZoomedInResampler->type() );
276  }
277  if ( mZoomedOutResampler )
278  {
279  rasterRendererElem.setAttribute( QStringLiteral( "zoomedOutResampler" ), mZoomedOutResampler->type() );
280  }
281  parentElem.appendChild( rasterRendererElem );
282 }
283 
284 void QgsRasterResampleFilter::readXml( const QDomElement &filterElem )
285 {
286  if ( filterElem.isNull() )
287  {
288  return;
289  }
290 
291  mMaxOversampling = filterElem.attribute( QStringLiteral( "maxOversampling" ), QStringLiteral( "2.0" ) ).toDouble();
292 
293  const QString zoomedInResamplerType = filterElem.attribute( QStringLiteral( "zoomedInResampler" ) );
294  if ( zoomedInResamplerType == QLatin1String( "bilinear" ) )
295  {
297  }
298  else if ( zoomedInResamplerType == QLatin1String( "cubic" ) )
299  {
301  }
302 
303  const QString zoomedOutResamplerType = filterElem.attribute( QStringLiteral( "zoomedOutResampler" ) );
304  if ( zoomedOutResamplerType == QLatin1String( "bilinear" ) )
305  {
307  }
308  else if ( zoomedOutResamplerType == QLatin1String( "cubic" ) )
309  {
311  }
312 }
QgsRasterResampleFilter::bandCount
int bandCount() const override
Gets number of bands.
Definition: qgsrasterresamplefilter.cpp:56
qgsrasterprojector.h
QgsRectangle::height
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
qgsbilinearrasterresampler.h
QgsRasterResampleFilter::block
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
Definition: qgsrasterresamplefilter.cpp:121
QgsRasterInterface::Size
@ Size
Original data source size (and thus resolution) is known, it is not always available,...
Definition: qgsrasterinterface.h:205
QgsRasterInterface::mInput
QgsRasterInterface * mInput
Definition: qgsrasterinterface.h:500
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
qgsrasterviewport.h
qgsmaptopixel.h
QgsRectangle::yMinimum
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
QgsRasterResampler
Interface for resampling rasters (e.g. to have a smoother appearance)
Definition: qgsrasterresampler.h:33
Qgis::DataType
DataType
Raster data types.
Definition: qgis.h:128
QgsRasterDataProvider::extent
QgsRectangle extent() const override=0
Returns the extent of the layer.
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
qgsrasterresampler.h
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
qgscubicrasterresampler.h
QgsBilinearRasterResampler
Bilinear Raster Resampler.
Definition: qgsbilinearrasterresampler.h:33
Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:2820
QgsRectangle::xMaximum
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:183
QgsRasterInterface::sourceInput
virtual const QgsRasterInterface * sourceInput() const
Gets source / raw input, the first in pipe, usually provider.
Definition: qgsrasterinterface.h:316
QgsRasterInterface::xSize
virtual int xSize() const
Gets raster size.
Definition: qgsrasterinterface.h:263
QgsRasterResampleFilter::readXml
void readXml(const QDomElement &filterElem) override
Sets base class members from xml. Usually called from create() methods of subclasses.
Definition: qgsrasterresamplefilter.cpp:284
QgsRasterResampleFilter::mMaxOversampling
double mMaxOversampling
Maximum boundary for oversampling (to avoid too much data traffic). Default: 2.0.
Definition: qgsrasterresamplefilter.h:70
QgsRasterInterface::dataType
virtual Qgis::DataType dataType(int bandNo) const =0
Returns data type for the band specified by number.
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2265
QgsRasterResampleFilter::setInput
bool setInput(QgsRasterInterface *input) override
Set input.
Definition: qgsrasterresamplefilter.cpp:74
QgsRasterResamplerV2
Interface for resampling rasters (V2) (e.g. to have a smoother appearance), which provides a more eff...
Definition: qgsrasterresampler.h:96
Qgis::DataType::UnknownDataType
@ UnknownDataType
Unknown or unspecified type.
QgsRasterResampleFilter::QgsRasterResampleFilter
QgsRasterResampleFilter(QgsRasterInterface *input=nullptr)
Definition: qgsrasterresamplefilter.cpp:35
QgsCubicRasterResampler
Cubic Raster Resampler.
Definition: qgscubicrasterresampler.h:32
QgsRasterResampleFilter::setZoomedInResampler
void setZoomedInResampler(QgsRasterResampler *r)
Sets resampler for zoomed in scales. Takes ownership of the object.
Definition: qgsrasterresamplefilter.cpp:111
Qgis::DataType::ARGB32_Premultiplied
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
QgsRectangle::xMinimum
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
qgsrastertransparency.h
qgsrasterresamplefilter.h
Qgis::DataType::ARGB32
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
QgsRectangle::toString
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
Definition: qgsrectangle.cpp:127
QgsRasterResampleFilter::mZoomedInResampler
std::unique_ptr< QgsRasterResampler > mZoomedInResampler
Resampler used if screen resolution is higher than raster resolution (zoomed in). 0 means no resampli...
Definition: qgsrasterresamplefilter.h:65
QgsRasterInterface::mOn
bool mOn
Definition: qgsrasterinterface.h:509
QgsRasterInterface
Base class for processing filters like renderers, reprojector, resampler etc.
Definition: qgsrasterinterface.h:135
QgsRectangle::yMaximum
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
QgsRectangle::width
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
QgsRasterResampleFilter
Resample filter pipe for rasters.
Definition: qgsrasterresamplefilter.h:32
QgsRasterInterface::input
virtual QgsRasterInterface * input() const
Current input.
Definition: qgsrasterinterface.h:302
QgsRasterBlockFeedback
Feedback object tailored for raster block reading.
Definition: qgsrasterinterface.h:41
QgsRasterResampleFilter::mZoomedOutResampler
std::unique_ptr< QgsRasterResampler > mZoomedOutResampler
Resampler used if raster resolution is higher than raster resolution (zoomed out)....
Definition: qgsrasterresamplefilter.h:67
QgsRasterResampleFilter::writeXml
void writeXml(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
Definition: qgsrasterresamplefilter.cpp:263
QgsRasterResampleFilter::dataType
Qgis::DataType dataType(int bandNo) const override
Returns data type for the band specified by number.
Definition: qgsrasterresamplefilter.cpp:65
QgsRasterInterface::bandCount
virtual int bandCount() const =0
Gets number of bands.
QgsRasterInterface::block
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.
QgsRasterResampleFilter::clone
QgsRasterResampleFilter * clone() const override
Clone itself, create deep copy.
Definition: qgsrasterresamplefilter.cpp:40
Q_NOWARN_DEPRECATED_PUSH
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2819
QgsRasterInterface::capabilities
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
Definition: qgsrasterinterface.h:225
QgsRasterResampleFilter::setMaxOversampling
void setMaxOversampling(double os)
Definition: qgsrasterresamplefilter.h:55
QgsRasterDataProvider
Base class for raster data providers.
Definition: qgsrasterdataprovider.h:88
QgsRasterResampleFilter::setZoomedOutResampler
void setZoomedOutResampler(QgsRasterResampler *r)
Sets resampler for zoomed out scales. Takes ownership of the object.
Definition: qgsrasterresamplefilter.cpp:116
QgsRasterBlock
Raster data container.
Definition: qgsrasterblock.h:36
QgsRasterInterface::extent
virtual QgsRectangle extent() const
Gets the extent of the interface.
Definition: qgsrasterinterface.h:248
qgsrasterdataprovider.h