|
QGIS API Documentation
master-3f58142
|
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 }