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 ), 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  delete outputBlock;
171  return mInput->block( bandNumber, extent, width, height );
172  }
173 
174  //effective oversampling factors are different to global one because of rounding
175  double oversamplingX = (( double )width * oversampling ) / width;
176  double oversamplingY = (( double )height * oversampling ) / height;
177 
178  // TODO: we must also increase the extent to get correct result on borders of parts
179 
180  int resWidth = width * oversamplingX;
181  int resHeight = height * oversamplingY;
182 
183  QgsRasterBlock *inputBlock = mInput->block( bandNumber, extent, resWidth, resHeight );
184  if ( !inputBlock || inputBlock->isEmpty() )
185  {
186  QgsDebugMsg( "No raster data!" );
187  delete inputBlock;
188  return outputBlock;
189  }
190 
191  if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
192  {
193  delete inputBlock;
194  return outputBlock;
195  }
196 
197  //resample image
198  QImage img = inputBlock->image();
199 
200  QImage dstImg = QImage( width, height, QImage::Format_ARGB32_Premultiplied );
201 
202  if ( mZoomedInResampler && ( oversamplingX < 1.0 || qgsDoubleNear( oversampling, 1.0 ) ) )
203  {
204  QgsDebugMsg( "zoomed in resampling" );
205  mZoomedInResampler->resample( img, dstImg );
206  }
207  else if ( mZoomedOutResampler && oversamplingX > 1.0 )
208  {
209  QgsDebugMsg( "zoomed out resampling" );
210  mZoomedOutResampler->resample( img, dstImg );
211  }
212  else
213  {
214  // Should not happen
215  QgsDebugMsg( "Unexpected resampling" );
216  dstImg = img.scaled( width, height );
217  }
218 
219  outputBlock->setImage( &dstImg );
220 
221  delete inputBlock;
222  return outputBlock; // No resampling
223 }
224 
225 void QgsRasterResampleFilter::writeXML( QDomDocument& doc, QDomElement& parentElem ) const
226 {
227  if ( parentElem.isNull() )
228  {
229  return;
230  }
231 
232  QDomElement rasterRendererElem = doc.createElement( "rasterresampler" );
233 
234  rasterRendererElem.setAttribute( "maxOversampling", QString::number( mMaxOversampling ) );
235  if ( mZoomedInResampler )
236  {
237  rasterRendererElem.setAttribute( "zoomedInResampler", mZoomedInResampler->type() );
238  }
239  if ( mZoomedOutResampler )
240  {
241  rasterRendererElem.setAttribute( "zoomedOutResampler", mZoomedOutResampler->type() );
242  }
243  parentElem.appendChild( rasterRendererElem );
244 }
245 
246 void QgsRasterResampleFilter::readXML( const QDomElement& filterElem )
247 {
248  if ( filterElem.isNull() )
249  {
250  return;
251  }
252 
253  mMaxOversampling = filterElem.attribute( "maxOversampling", "2.0" ).toDouble();
254 
255  QString zoomedInResamplerType = filterElem.attribute( "zoomedInResampler" );
256  if ( zoomedInResamplerType == "bilinear" )
257  {
259  }
260  else if ( zoomedInResamplerType == "cubic" )
261  {
263  }
264 
265  QString zoomedOutResamplerType = filterElem.attribute( "zoomedOutResampler" );
266  if ( zoomedOutResamplerType == "bilinear" )
267  {
269  }
270 }
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: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.