QGIS API Documentation  2.2.0-Valmiera
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups 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 }