QGIS API Documentation  master-3f58142
src/core/raster/qgsrasterresamplefilter.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                          qgsrasterresamplefilter.cpp
00003                          ---------------------
00004     begin                : December 2011
00005     copyright            : (C) 2011 by Marco Hugentobler
00006     email                : marco at sourcepole dot ch
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include "qgsrasterdataprovider.h"
00019 #include "qgsrasterresamplefilter.h"
00020 #include "qgsrasterresampler.h"
00021 #include "qgsrasterprojector.h"
00022 #include "qgsrastertransparency.h"
00023 #include "qgsrasterviewport.h"
00024 #include "qgsmaptopixel.h"
00025 
00026 //resamplers
00027 #include "qgsbilinearrasterresampler.h"
00028 #include "qgscubicrasterresampler.h"
00029 
00030 #include <QDomDocument>
00031 #include <QDomElement>
00032 #include <QImage>
00033 #include <QPainter>
00034 
00035 QgsRasterResampleFilter::QgsRasterResampleFilter( QgsRasterInterface* input )
00036     : QgsRasterInterface( input ),
00037     mZoomedInResampler( 0 ), mZoomedOutResampler( 0 ),
00038     mMaxOversampling( 2.0 )
00039 {
00040 }
00041 
00042 QgsRasterResampleFilter::~QgsRasterResampleFilter()
00043 {
00044   delete mZoomedInResampler;
00045   delete mZoomedOutResampler;
00046 }
00047 
00048 QgsRasterInterface * QgsRasterResampleFilter::clone() const
00049 {
00050   QgsDebugMsg( "Entered" );
00051   QgsRasterResampleFilter * resampler = new QgsRasterResampleFilter( 0 );
00052   if ( mZoomedInResampler )
00053   {
00054     resampler->setZoomedInResampler( mZoomedInResampler->clone() );
00055   }
00056   if ( mZoomedOutResampler )
00057   {
00058     resampler->setZoomedOutResampler( mZoomedOutResampler->clone() );
00059   }
00060   resampler->setMaxOversampling( mMaxOversampling );
00061   return resampler;
00062 }
00063 
00064 int QgsRasterResampleFilter::bandCount() const
00065 {
00066   if ( mOn ) return 1;
00067 
00068   if ( mInput ) return mInput->bandCount();
00069 
00070   return 0;
00071 }
00072 
00073 QGis::DataType QgsRasterResampleFilter::dataType( int bandNo ) const
00074 {
00075   if ( mOn ) return QGis::ARGB32_Premultiplied;
00076 
00077   if ( mInput ) return mInput->dataType( bandNo );
00078 
00079   return QGis::UnknownDataType;
00080 }
00081 
00082 bool QgsRasterResampleFilter::setInput( QgsRasterInterface* input )
00083 {
00084   QgsDebugMsg( "Entered" );
00085 
00086   // Resampler can only work with single band ARGB32_Premultiplied
00087   if ( !input )
00088   {
00089     QgsDebugMsg( "No input" );
00090     return false;
00091   }
00092 
00093   if ( !mOn )
00094   {
00095     // In off mode we can connect to anything
00096     QgsDebugMsg( "OK" );
00097     mInput = input;
00098     return true;
00099   }
00100 
00101   if ( input->bandCount() < 1 )
00102   {
00103     QgsDebugMsg( "No input band" );
00104     return false;
00105   }
00106 
00107   if ( input->dataType( 1 ) != QGis::ARGB32_Premultiplied &&
00108        input->dataType( 1 ) != QGis::ARGB32 )
00109   {
00110     QgsDebugMsg( "Unknown input data type" );
00111     return false;
00112   }
00113 
00114   mInput = input;
00115   QgsDebugMsg( "OK" );
00116   return true;
00117 }
00118 
00119 void QgsRasterResampleFilter::setZoomedInResampler( QgsRasterResampler* r )
00120 {
00121   delete mZoomedInResampler;
00122   mZoomedInResampler = r;
00123 }
00124 
00125 void QgsRasterResampleFilter::setZoomedOutResampler( QgsRasterResampler* r )
00126 {
00127   delete mZoomedOutResampler;
00128   mZoomedOutResampler = r;
00129 }
00130 
00131 QgsRasterBlock * QgsRasterResampleFilter::block( int bandNo, QgsRectangle  const & extent, int width, int height )
00132 {
00133   Q_UNUSED( bandNo );
00134   QgsDebugMsg( QString( "width = %1 height = %2 extent = %3" ).arg( width ).arg( height ).arg( extent.toString() ) );
00135   QgsRasterBlock *outputBlock = new QgsRasterBlock();
00136   if ( !mInput ) return outputBlock;
00137 
00138   double oversampling = 1.0; // approximate global oversampling factor
00139 
00140   if ( mZoomedInResampler || mZoomedOutResampler )
00141   {
00142     QgsRasterDataProvider *provider = dynamic_cast<QgsRasterDataProvider*>( mInput->srcInput() );
00143     if ( provider && ( provider->capabilities() & QgsRasterDataProvider::Size ) )
00144     {
00145       double xRes = extent.width() / width;
00146       double providerXRes = provider->extent().width() / provider->xSize();
00147       double pixelRatio = xRes / providerXRes;
00148       oversampling = ( pixelRatio > mMaxOversampling ) ? mMaxOversampling : pixelRatio;
00149       QgsDebugMsg( QString( "xRes = %1 providerXRes = %2 pixelRatio = %3 oversampling = %4" ).arg( xRes ).arg( providerXRes ).arg( pixelRatio ).arg( oversampling ) );
00150     }
00151     else
00152     {
00153       // We don't know exact data source resolution (WMS) so we expect that
00154       // server data have higher resolution (which is not always true) and use
00155       // mMaxOversampling
00156       oversampling = mMaxOversampling;
00157     }
00158   }
00159 
00160   QgsDebugMsg( QString( "oversampling %1" ).arg( oversampling ) );
00161 
00162   int bandNumber = 1;
00163 
00164   // Do no oversampling if no resampler for zoomed in / zoomed out (nearest neighbour)
00165   // We do mZoomedInResampler if oversampling == 1 (otherwise for example reprojected
00166   // zoom in rasters are never resampled because projector limits resolution.
00167   if ((( oversampling < 1.0 || qgsDoubleNear( oversampling, 1.0 ) ) && !mZoomedInResampler ) || ( oversampling > 1.0 && !mZoomedOutResampler ) )
00168   {
00169     QgsDebugMsg( "No oversampling." );
00170     return mInput->block( bandNumber, extent, width, height );
00171   }
00172 
00173   //effective oversampling factors are different to global one because of rounding
00174   double oversamplingX = (( double )width * oversampling ) / width;
00175   double oversamplingY = (( double )height * oversampling ) / height;
00176 
00177   // TODO: we must also increase the extent to get correct result on borders of parts
00178 
00179   int resWidth = width * oversamplingX;
00180   int resHeight = height * oversamplingY;
00181 
00182   QgsRasterBlock *inputBlock = mInput->block( bandNumber, extent, resWidth, resHeight );
00183   if ( !inputBlock || inputBlock->isEmpty() )
00184   {
00185     QgsDebugMsg( "No raster data!" );
00186     delete inputBlock;
00187     return outputBlock;
00188   }
00189 
00190   if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
00191   {
00192     delete inputBlock;
00193     return outputBlock;
00194   }
00195 
00196   //resample image
00197   QImage img = inputBlock->image();
00198 
00199   QImage dstImg = QImage( width, height, QImage::Format_ARGB32_Premultiplied );
00200 
00201   if ( mZoomedInResampler && ( oversamplingX < 1.0 || qgsDoubleNear( oversampling, 1.0 ) ) )
00202   {
00203     QgsDebugMsg( "zoomed in resampling" );
00204     mZoomedInResampler->resample( img, dstImg );
00205   }
00206   else if ( mZoomedOutResampler && oversamplingX > 1.0 )
00207   {
00208     QgsDebugMsg( "zoomed out resampling" );
00209     mZoomedOutResampler->resample( img, dstImg );
00210   }
00211   else
00212   {
00213     // Should not happen
00214     QgsDebugMsg( "Unexpected resampling" );
00215     dstImg = img.scaled( width, height );
00216   }
00217 
00218   outputBlock->setImage( &dstImg );
00219 
00220   delete inputBlock;
00221   return outputBlock; // No resampling
00222 }
00223 
00224 void QgsRasterResampleFilter::writeXML( QDomDocument& doc, QDomElement& parentElem ) const
00225 {
00226   if ( parentElem.isNull() )
00227   {
00228     return;
00229   }
00230 
00231   QDomElement rasterRendererElem = doc.createElement( "rasterresampler" );
00232 
00233   rasterRendererElem.setAttribute( "maxOversampling", QString::number( mMaxOversampling ) );
00234   if ( mZoomedInResampler )
00235   {
00236     rasterRendererElem.setAttribute( "zoomedInResampler", mZoomedInResampler->type() );
00237   }
00238   if ( mZoomedOutResampler )
00239   {
00240     rasterRendererElem.setAttribute( "zoomedOutResampler", mZoomedOutResampler->type() );
00241   }
00242   parentElem.appendChild( rasterRendererElem );
00243 }
00244 
00245 void QgsRasterResampleFilter::readXML( const QDomElement& filterElem )
00246 {
00247   if ( filterElem.isNull() )
00248   {
00249     return;
00250   }
00251 
00252   mMaxOversampling = filterElem.attribute( "maxOversampling", "2.0" ).toDouble();
00253 
00254   QString zoomedInResamplerType = filterElem.attribute( "zoomedInResampler" );
00255   if ( zoomedInResamplerType == "bilinear" )
00256   {
00257     mZoomedInResampler = new QgsBilinearRasterResampler();
00258   }
00259   else if ( zoomedInResamplerType == "cubic" )
00260   {
00261     mZoomedInResampler = new QgsCubicRasterResampler();
00262   }
00263 
00264   QString zoomedOutResamplerType = filterElem.attribute( "zoomedOutResampler" );
00265   if ( zoomedOutResamplerType == "bilinear" )
00266   {
00267     mZoomedOutResampler = new QgsBilinearRasterResampler();
00268   }
00269 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines