QGIS API Documentation  2.9.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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  , mZoomedInResampler( 0 )
38  , mZoomedOutResampler( 0 )
39  , mMaxOversampling( 2.0 )
40 {
41 }
42 
44 {
45  delete mZoomedInResampler;
46  delete mZoomedOutResampler;
47 }
48 
50 {
51  QgsDebugMsg( "Entered" );
52  QgsRasterResampleFilter * resampler = new QgsRasterResampleFilter( 0 );
53  if ( mZoomedInResampler )
54  {
56  }
57  if ( mZoomedOutResampler )
58  {
60  }
62  return resampler;
63 }
64 
66 {
67  if ( mOn ) return 1;
68 
69  if ( mInput ) return mInput->bandCount();
70 
71  return 0;
72 }
73 
75 {
76  if ( mOn ) return QGis::ARGB32_Premultiplied;
77 
78  if ( mInput ) return mInput->dataType( bandNo );
79 
80  return QGis::UnknownDataType;
81 }
82 
84 {
85  QgsDebugMsg( "Entered" );
86 
87  // Resampler can only work with single band ARGB32_Premultiplied
88  if ( !input )
89  {
90  QgsDebugMsg( "No input" );
91  return false;
92  }
93 
94  if ( !mOn )
95  {
96  // In off mode we can connect to anything
97  QgsDebugMsg( "OK" );
98  mInput = input;
99  return true;
100  }
101 
102  if ( input->bandCount() < 1 )
103  {
104  QgsDebugMsg( "No input band" );
105  return false;
106  }
107 
108  if ( input->dataType( 1 ) != QGis::ARGB32_Premultiplied &&
109  input->dataType( 1 ) != QGis::ARGB32 )
110  {
111  QgsDebugMsg( "Unknown input data type" );
112  return false;
113  }
114 
115  mInput = input;
116  QgsDebugMsg( "OK" );
117  return true;
118 }
119 
121 {
122  delete mZoomedInResampler;
123  mZoomedInResampler = r;
124 }
125 
127 {
128  delete mZoomedOutResampler;
130 }
131 
132 QgsRasterBlock * QgsRasterResampleFilter::block( int bandNo, QgsRectangle const & extent, int width, int height )
133 {
134  Q_UNUSED( bandNo );
135  QgsDebugMsg( QString( "width = %1 height = %2 extent = %3" ).arg( width ).arg( height ).arg( extent.toString() ) );
136  QgsRasterBlock *outputBlock = new QgsRasterBlock();
137  if ( !mInput ) return outputBlock;
138 
139  double oversampling = 1.0; // approximate global oversampling factor
140 
142  {
143  QgsRasterDataProvider *provider = dynamic_cast<QgsRasterDataProvider*>( mInput->srcInput() );
144  if ( provider && ( provider->capabilities() & QgsRasterDataProvider::Size ) )
145  {
146  double xRes = extent.width() / width;
147  double providerXRes = provider->extent().width() / provider->xSize();
148  double pixelRatio = xRes / providerXRes;
149  oversampling = ( pixelRatio > mMaxOversampling ) ? mMaxOversampling : pixelRatio;
150  QgsDebugMsg( QString( "xRes = %1 providerXRes = %2 pixelRatio = %3 oversampling = %4" ).arg( xRes ).arg( providerXRes ).arg( pixelRatio ).arg( oversampling ) );
151  }
152  else
153  {
154  // We don't know exact data source resolution (WMS) so we expect that
155  // server data have higher resolution (which is not always true) and use
156  // mMaxOversampling
157  oversampling = mMaxOversampling;
158  }
159  }
160 
161  QgsDebugMsg( QString( "oversampling %1" ).arg( oversampling ) );
162 
163  int bandNumber = 1;
164 
165  // Do no oversampling if no resampler for zoomed in / zoomed out (nearest neighbour)
166  // We do mZoomedInResampler if oversampling == 1 (otherwise for example reprojected
167  // zoom in rasters are never resampled because projector limits resolution.
168  if ((( oversampling < 1.0 || qgsDoubleNear( oversampling, 1.0 ) ) && !mZoomedInResampler ) || ( oversampling > 1.0 && !mZoomedOutResampler ) )
169  {
170  QgsDebugMsg( "No oversampling." );
171  delete outputBlock;
172  return mInput->block( bandNumber, extent, width, height );
173  }
174 
175  //effective oversampling factors are different to global one because of rounding
176  double oversamplingX = (( double )width * oversampling ) / width;
177  double oversamplingY = (( double )height * oversampling ) / height;
178 
179  // TODO: we must also increase the extent to get correct result on borders of parts
180 
181  int resWidth = width * oversamplingX;
182  int resHeight = height * oversamplingY;
183 
184  QgsRasterBlock *inputBlock = mInput->block( bandNumber, extent, resWidth, resHeight );
185  if ( !inputBlock || inputBlock->isEmpty() )
186  {
187  QgsDebugMsg( "No raster data!" );
188  delete inputBlock;
189  return outputBlock;
190  }
191 
192  if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
193  {
194  delete inputBlock;
195  return outputBlock;
196  }
197 
198  //resample image
199  QImage img = inputBlock->image();
200 
201  QImage dstImg = QImage( width, height, QImage::Format_ARGB32_Premultiplied );
202 
203  if ( mZoomedInResampler && ( oversamplingX < 1.0 || qgsDoubleNear( oversampling, 1.0 ) ) )
204  {
205  QgsDebugMsg( "zoomed in resampling" );
206  mZoomedInResampler->resample( img, dstImg );
207  }
208  else if ( mZoomedOutResampler && oversamplingX > 1.0 )
209  {
210  QgsDebugMsg( "zoomed out resampling" );
211  mZoomedOutResampler->resample( img, dstImg );
212  }
213  else
214  {
215  // Should not happen
216  QgsDebugMsg( "Unexpected resampling" );
217  dstImg = img.scaled( width, height );
218  }
219 
220  outputBlock->setImage( &dstImg );
221 
222  delete inputBlock;
223  return outputBlock; // No resampling
224 }
225 
226 void QgsRasterResampleFilter::writeXML( QDomDocument& doc, QDomElement& parentElem ) const
227 {
228  if ( parentElem.isNull() )
229  {
230  return;
231  }
232 
233  QDomElement rasterRendererElem = doc.createElement( "rasterresampler" );
234 
235  rasterRendererElem.setAttribute( "maxOversampling", QString::number( mMaxOversampling ) );
236  if ( mZoomedInResampler )
237  {
238  rasterRendererElem.setAttribute( "zoomedInResampler", mZoomedInResampler->type() );
239  }
240  if ( mZoomedOutResampler )
241  {
242  rasterRendererElem.setAttribute( "zoomedOutResampler", mZoomedOutResampler->type() );
243  }
244  parentElem.appendChild( rasterRendererElem );
245 }
246 
247 void QgsRasterResampleFilter::readXML( const QDomElement& filterElem )
248 {
249  if ( filterElem.isNull() )
250  {
251  return;
252  }
253 
254  mMaxOversampling = filterElem.attribute( "maxOversampling", "2.0" ).toDouble();
255 
256  QString zoomedInResamplerType = filterElem.attribute( "zoomedInResampler" );
257  if ( zoomedInResamplerType == "bilinear" )
258  {
260  }
261  else if ( zoomedInResamplerType == "cubic" )
262  {
264  }
265 
266  QString zoomedOutResamplerType = filterElem.attribute( "zoomedOutResampler" );
267  if ( zoomedOutResamplerType == "bilinear" )
268  {
270  }
271 }
virtual int bandCount() const =0
Get number of bands.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
Cubic Raster Resampler.
QGis::DataType dataType(int bandNo) const override
Returns data type for the band specified by number.
Interface for resampling rasters (e.g.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
virtual void resample(const QImage &srcImage, QImage &dstImage)=0
virtual const QgsRasterInterface * srcInput() const
Get source / raw input, the first in pipe, usually provider.
virtual QgsRasterInterface * input() const
Current input.
Resample filter pipe for rasters.
void readXML(const QDomElement &filterElem) override
Sets base class members from xml.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:347
QgsRasterResampler * mZoomedOutResampler
Resampler used if raster resolution is higher than raster resolution (zoomed out).
Raster data container.
virtual QString type() const =0
bool setImage(const QImage *image)
set image.
DataType
Raster data types.
Definition: qgis.h:204
virtual QGis::DataType dataType(int bandNo) const =0
Returns data type for the band specified by number.
Base class for processing filters like renderers, reprojector, resampler etc.
double mMaxOversampling
Maximum boundary for oversampling (to avoid too much data traffic).
bool reset(QGis::DataType theDataType, int theWidth, int theHeight)
Reset block.
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
bool setInput(QgsRasterInterface *input) override
Set input.
virtual QgsRectangle extent() override=0
Get the extent of the data source.
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height) override
Read block of data using given extent and size.
QgsRasterInterface * clone() const override
Clone itself, create deep copy.
void setZoomedInResampler(QgsRasterResampler *r)
Set resampler for zoomed in scales.
virtual int xSize() const
Get raster size.
Bilinear Raster Resampler.
virtual QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height)=0
Read block of data using given extent and size.
virtual QgsRasterResampler * clone() const =0
void setZoomedOutResampler(QgsRasterResampler *r)
Set resampler for zoomed out scales.
QgsRasterResampler * mZoomedInResampler
Resampler used if screen resolution is higher than raster resolution (zoomed in). ...
QgsRasterResampleFilter(QgsRasterInterface *input=0)
QImage image() const
Get image if type is color.
void writeXML(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:202
QgsRasterInterface * mInput
QString toString(bool automaticPrecision=false) const
returns string representation of form xmin,ymin xmax,ymax
int bandCount() const override
Get number of bands.
bool isEmpty() const
Returns true if block is empty, i.e.
Base class for raster data providers.