QGIS API Documentation  2.7.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 ), mZoomedOutResampler( 0 ),
38  mMaxOversampling( 2.0 )
39 {
40 }
41 
43 {
44  delete mZoomedInResampler;
45  delete mZoomedOutResampler;
46 }
47 
49 {
50  QgsDebugMsg( "Entered" );
51  QgsRasterResampleFilter * resampler = new QgsRasterResampleFilter( 0 );
52  if ( mZoomedInResampler )
53  {
55  }
56  if ( mZoomedOutResampler )
57  {
59  }
61  return resampler;
62 }
63 
65 {
66  if ( mOn ) return 1;
67 
68  if ( mInput ) return mInput->bandCount();
69 
70  return 0;
71 }
72 
74 {
75  if ( mOn ) return QGis::ARGB32_Premultiplied;
76 
77  if ( mInput ) return mInput->dataType( bandNo );
78 
79  return QGis::UnknownDataType;
80 }
81 
83 {
84  QgsDebugMsg( "Entered" );
85 
86  // Resampler can only work with single band ARGB32_Premultiplied
87  if ( !input )
88  {
89  QgsDebugMsg( "No input" );
90  return false;
91  }
92 
93  if ( !mOn )
94  {
95  // In off mode we can connect to anything
96  QgsDebugMsg( "OK" );
97  mInput = input;
98  return true;
99  }
100 
101  if ( input->bandCount() < 1 )
102  {
103  QgsDebugMsg( "No input band" );
104  return false;
105  }
106 
107  if ( input->dataType( 1 ) != QGis::ARGB32_Premultiplied &&
108  input->dataType( 1 ) != QGis::ARGB32 )
109  {
110  QgsDebugMsg( "Unknown input data type" );
111  return false;
112  }
113 
114  mInput = input;
115  QgsDebugMsg( "OK" );
116  return true;
117 }
118 
120 {
121  delete mZoomedInResampler;
122  mZoomedInResampler = r;
123 }
124 
126 {
127  delete mZoomedOutResampler;
129 }
130 
131 QgsRasterBlock * QgsRasterResampleFilter::block( int bandNo, QgsRectangle const & extent, int width, int height )
132 {
133  Q_UNUSED( bandNo );
134  QgsDebugMsg( QString( "width = %1 height = %2 extent = %3" ).arg( width ).arg( height ).arg( extent.toString() ) );
135  QgsRasterBlock *outputBlock = new QgsRasterBlock();
136  if ( !mInput ) return outputBlock;
137 
138  double oversampling = 1.0; // approximate global oversampling factor
139 
141  {
142  QgsRasterDataProvider *provider = dynamic_cast<QgsRasterDataProvider*>( mInput->srcInput() );
143  if ( provider && ( provider->capabilities() & QgsRasterDataProvider::Size ) )
144  {
145  double xRes = extent.width() / width;
146  double providerXRes = provider->extent().width() / provider->xSize();
147  double pixelRatio = xRes / providerXRes;
148  oversampling = ( pixelRatio > mMaxOversampling ) ? mMaxOversampling : pixelRatio;
149  QgsDebugMsg( QString( "xRes = %1 providerXRes = %2 pixelRatio = %3 oversampling = %4" ).arg( xRes ).arg( providerXRes ).arg( pixelRatio ).arg( oversampling ) );
150  }
151  else
152  {
153  // We don't know exact data source resolution (WMS) so we expect that
154  // server data have higher resolution (which is not always true) and use
155  // mMaxOversampling
156  oversampling = mMaxOversampling;
157  }
158  }
159 
160  QgsDebugMsg( QString( "oversampling %1" ).arg( oversampling ) );
161 
162  int bandNumber = 1;
163 
164  // Do no oversampling if no resampler for zoomed in / zoomed out (nearest neighbour)
165  // We do mZoomedInResampler if oversampling == 1 (otherwise for example reprojected
166  // zoom in rasters are never resampled because projector limits resolution.
167  if ((( oversampling < 1.0 || qgsDoubleNear( oversampling, 1.0 ) ) && !mZoomedInResampler ) || ( oversampling > 1.0 && !mZoomedOutResampler ) )
168  {
169  QgsDebugMsg( "No oversampling." );
170  return mInput->block( bandNumber, extent, width, height );
171  }
172 
173  //effective oversampling factors are different to global one because of rounding
174  double oversamplingX = (( double )width * oversampling ) / width;
175  double oversamplingY = (( double )height * oversampling ) / height;
176 
177  // TODO: we must also increase the extent to get correct result on borders of parts
178 
179  int resWidth = width * oversamplingX;
180  int resHeight = height * oversamplingY;
181 
182  QgsRasterBlock *inputBlock = mInput->block( bandNumber, extent, resWidth, resHeight );
183  if ( !inputBlock || inputBlock->isEmpty() )
184  {
185  QgsDebugMsg( "No raster data!" );
186  delete inputBlock;
187  return outputBlock;
188  }
189 
190  if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
191  {
192  delete inputBlock;
193  return outputBlock;
194  }
195 
196  //resample image
197  QImage img = inputBlock->image();
198 
199  QImage dstImg = QImage( width, height, QImage::Format_ARGB32_Premultiplied );
200 
201  if ( mZoomedInResampler && ( oversamplingX < 1.0 || qgsDoubleNear( oversampling, 1.0 ) ) )
202  {
203  QgsDebugMsg( "zoomed in resampling" );
204  mZoomedInResampler->resample( img, dstImg );
205  }
206  else if ( mZoomedOutResampler && oversamplingX > 1.0 )
207  {
208  QgsDebugMsg( "zoomed out resampling" );
209  mZoomedOutResampler->resample( img, dstImg );
210  }
211  else
212  {
213  // Should not happen
214  QgsDebugMsg( "Unexpected resampling" );
215  dstImg = img.scaled( width, height );
216  }
217 
218  outputBlock->setImage( &dstImg );
219 
220  delete inputBlock;
221  return outputBlock; // No resampling
222 }
223 
224 void QgsRasterResampleFilter::writeXML( QDomDocument& doc, QDomElement& parentElem ) const
225 {
226  if ( parentElem.isNull() )
227  {
228  return;
229  }
230 
231  QDomElement rasterRendererElem = doc.createElement( "rasterresampler" );
232 
233  rasterRendererElem.setAttribute( "maxOversampling", QString::number( mMaxOversampling ) );
234  if ( mZoomedInResampler )
235  {
236  rasterRendererElem.setAttribute( "zoomedInResampler", mZoomedInResampler->type() );
237  }
238  if ( mZoomedOutResampler )
239  {
240  rasterRendererElem.setAttribute( "zoomedOutResampler", mZoomedOutResampler->type() );
241  }
242  parentElem.appendChild( rasterRendererElem );
243 }
244 
245 void QgsRasterResampleFilter::readXML( const QDomElement& filterElem )
246 {
247  if ( filterElem.isNull() )
248  {
249  return;
250  }
251 
252  mMaxOversampling = filterElem.attribute( "maxOversampling", "2.0" ).toDouble();
253 
254  QString zoomedInResamplerType = filterElem.attribute( "zoomedInResampler" );
255  if ( zoomedInResamplerType == "bilinear" )
256  {
258  }
259  else if ( zoomedInResamplerType == "cubic" )
260  {
262  }
263 
264  QString zoomedOutResamplerType = filterElem.attribute( "zoomedOutResampler" );
265  if ( zoomedOutResamplerType == "bilinear" )
266  {
268  }
269 }
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:325
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:198
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.