From 3f227c4af4ae802c9058442f5ca7c81450b5e27a Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Mon, 18 Jun 2012 17:26:56 +0200 Subject: [PATCH] resampler separated, reenabled transparency in renderers --- src/app/qgsrasterlayerproperties.cpp | 22 ++- src/core/CMakeLists.txt | 1 + src/core/raster/qgsmultibandcolorrenderer.cpp | 18 +- src/core/raster/qgspalettedrasterrenderer.cpp | 56 ++---- src/core/raster/qgsrasterlayer.cpp | 92 ++++++++- src/core/raster/qgsrasterlayer.h | 7 + src/core/raster/qgsrasterrenderer.cpp | 48 ----- src/core/raster/qgsrasterrenderer.h | 14 -- src/core/raster/qgsrasterresamplefilter.cpp | 178 ++++++++++++++++++ src/core/raster/qgsrasterresamplefilter.h | 75 ++++++++ .../raster/qgssinglebandcolordatarenderer.cpp | 17 +- src/core/raster/qgssinglebandgrayrenderer.cpp | 51 ++--- .../qgssinglebandpseudocolorrenderer.cpp | 54 ++---- 13 files changed, 421 insertions(+), 212 deletions(-) create mode 100644 src/core/raster/qgsrasterresamplefilter.cpp create mode 100644 src/core/raster/qgsrasterresamplefilter.h diff --git a/src/app/qgsrasterlayerproperties.cpp b/src/app/qgsrasterlayerproperties.cpp index 706a7cb88ba9..02a46aabbddc 100644 --- a/src/app/qgsrasterlayerproperties.cpp +++ b/src/app/qgsrasterlayerproperties.cpp @@ -201,8 +201,10 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer* lyr, QgsMapCanv mZoomedInResamplingComboBox->insertItem( 2, tr( "Cubic" ) ); mZoomedOutResamplingComboBox->insertItem( 0, tr( "Nearest neighbour" ) ); mZoomedOutResamplingComboBox->insertItem( 1, tr( "Average" ) ); + + const QgsRasterResampleFilter* resampleFilter = mRasterLayer->resampleFilter(); //set combo boxes to current resampling types - if ( renderer ) + if ( resampleFilter ) { //invert color map if ( renderer->invertColor() ) @@ -210,7 +212,7 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer* lyr, QgsMapCanv mInvertColorMapCheckBox->setCheckState( Qt::Checked ); } - const QgsRasterResampler* zoomedInResampler = renderer->zoomedInResampler(); + const QgsRasterResampler* zoomedInResampler = resampleFilter->zoomedInResampler(); if ( zoomedInResampler ) { if ( zoomedInResampler->type() == "bilinear" ) @@ -227,7 +229,7 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer* lyr, QgsMapCanv mZoomedInResamplingComboBox->setCurrentIndex( 0 ); } - const QgsRasterResampler* zoomedOutResampler = renderer->zoomedOutResampler(); + const QgsRasterResampler* zoomedOutResampler = resampleFilter->zoomedOutResampler(); if ( zoomedOutResampler ) { if ( zoomedOutResampler->type() == "bilinear" ) //bilinear resampler does averaging when zooming out @@ -798,6 +800,8 @@ void QgsRasterLayerProperties::apply() pixmapLegend->setScaledContents( true ); pixmapLegend->repaint(); + QgsRasterResampleFilter* resampleFilter = mRasterLayer->resampleFilter(); + QgsRasterResampler* zoomedInResampler = 0; QString zoomedInResamplingMethod = mZoomedInResamplingComboBox->currentText(); if ( zoomedInResamplingMethod == tr( "Bilinear" ) ) @@ -809,9 +813,9 @@ void QgsRasterLayerProperties::apply() zoomedInResampler = new QgsCubicRasterResampler(); } - if ( rasterRenderer ) + if ( resampleFilter ) { - rasterRenderer->setZoomedInResampler( zoomedInResampler ); + resampleFilter->setZoomedInResampler( zoomedInResampler ); } //raster resampling @@ -822,14 +826,14 @@ void QgsRasterLayerProperties::apply() zoomedOutResampler = new QgsBilinearRasterResampler(); } - if ( rasterRenderer ) + if ( resampleFilter ) { - rasterRenderer->setZoomedOutResampler( zoomedOutResampler ); + resampleFilter->setZoomedOutResampler( zoomedOutResampler ); } - if ( rasterRenderer ) + if ( resampleFilter ) { - rasterRenderer->setMaxOversampling( mMaximumOversamplingSpinBox->value() ); + resampleFilter->setMaxOversampling( mMaximumOversamplingSpinBox->value() ); } diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1741398191e9..b0d7909d40bc 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -167,6 +167,7 @@ SET(QGIS_CORE_SRCS raster/qgsrastershaderfunction.cpp raster/qgsrasterdrawer.cpp + raster/qgsrasterresamplefilter.cpp raster/qgsrasterrendererregistry.cpp raster/qgsrasterrenderer.cpp raster/qgsbilinearrasterresampler.cpp diff --git a/src/core/raster/qgsmultibandcolorrenderer.cpp b/src/core/raster/qgsmultibandcolorrenderer.cpp index 6cbd20f1c820..b66f41f0e5d2 100644 --- a/src/core/raster/qgsmultibandcolorrenderer.cpp +++ b/src/core/raster/qgsmultibandcolorrenderer.cpp @@ -101,7 +101,6 @@ QgsRasterRenderer* QgsMultiBandColorRenderer::create( const QDomElement& elem, Q return r; } -//void QgsMultiBandColorRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ) void * QgsMultiBandColorRenderer::readBlock( int bandNo, QgsRectangle const & extent, int width, int height ) { if ( !mInput ) @@ -171,31 +170,16 @@ void * QgsMultiBandColorRenderer::readBlock( int bandNo, QgsRectangle const & e for ( ; bandIt != bands.constEnd(); ++bandIt ) { bandData.insert( *bandIt, defaultPointer ); - //startRasterRead( *bandIt, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); } void* redData = 0; void* greenData = 0; void* blueData = 0; void* alphaData = 0; - //number of cols/rows in output pixels - int nCols = 0; - int nRows = 0; - //number of raster cols/rows with oversampling - int nRasterCols = 0; - int nRasterRows = 0; - //shift to top left point for the raster part - int topLeftCol = 0; - int topLeftRow = 0; - - bool readSuccess = true; - - //QSet::const_iterator bandIt = bands.constBegin(); + bandIt = bands.constBegin(); for ( ; bandIt != bands.constEnd(); ++bandIt ) { - //readSuccess = readSuccess && readNextRasterPart( *bandIt, oversamplingX, oversamplingY, viewPort, nCols, nRows, - // nRasterCols, nRasterRows, &bandData[*bandIt], topLeftCol, topLeftRow ); bandData[*bandIt] = mInput->readBlock( *bandIt, extent, width, height ); if ( !bandData[*bandIt] ) return 0; } diff --git a/src/core/raster/qgspalettedrasterrenderer.cpp b/src/core/raster/qgspalettedrasterrenderer.cpp index 0fc638fd49a9..8bb79adca125 100644 --- a/src/core/raster/qgspalettedrasterrenderer.cpp +++ b/src/core/raster/qgspalettedrasterrenderer.cpp @@ -81,7 +81,6 @@ QColor* QgsPalettedRasterRenderer::colors() const return colorArray; } -//void QgsPalettedRasterRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ) void * QgsPalettedRasterRenderer::readBlock( int bandNo, QgsRectangle const & extent, int width, int height ) { if ( !mInput ) @@ -89,30 +88,12 @@ void * QgsPalettedRasterRenderer::readBlock( int bandNo, QgsRectangle const & e return 0; } - //double oversamplingX, oversamplingY; - //QgsRasterFace::DataType transparencyType = QgsRasterFace::UnknownDataType; - //if ( mAlphaBand > 0 ) - //{ - //transparencyType = ( QgsRasterFace::DataType )mInput->dataType( mAlphaBand ); - //} - //startRasterRead( mBandNumber, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); - - ////Read alpha band if necessary - //if ( mAlphaBand > 0 && mAlphaBand != mBandNumber ) - //{ - //startRasterRead( mAlphaBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); - //} - - ////number of cols/rows in output pixels - //int nCols = 0; - //int nRows = 0; - ////number of raster cols/rows with oversampling - //int nRasterCols = 0; - //int nRasterRows = 0; - ////shift to top left point for the raster part - //int topLeftCol = 0; - //int topLeftRow = 0; - //int currentRasterPos = 0; + QgsRasterFace::DataType transparencyType = QgsRasterFace::UnknownDataType; + if ( mAlphaBand > 0 ) + { + transparencyType = ( QgsRasterFace::DataType )mInput->dataType( mAlphaBand ); + } + QgsRasterFace::DataType rasterType = ( QgsRasterFace::DataType )mInput->dataType( mBandNumber ); void* rasterData = mInput->readBlock( bandNo, extent, width, height ); double currentOpacity = mOpacity; @@ -123,15 +104,14 @@ void * QgsPalettedRasterRenderer::readBlock( int bandNo, QgsRectangle const & e //bool hasTransparency = usesTransparency( viewPort->mSrcCRS, viewPort->mDestCRS ); void* transparencyData = 0; - //if ( mAlphaBand > 0 && mAlphaBand != mBandNumber ) - //{ - //readNextRasterPart( mAlphaBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows, - //&transparencyData, topLeftCol, topLeftRow ); - //} - //else if ( mAlphaBand == mBandNumber ) - //{ - //transparencyData = rasterData; - //} + if ( mAlphaBand > 0 && mAlphaBand != mBandNumber ) + { + transparencyData = mInput->readBlock( mAlphaBand, extent, width, height ); + } + else if ( mAlphaBand == mBandNumber ) + { + transparencyData = rasterData; + } //create image QImage img( width, height, QImage::Format_ARGB32_Premultiplied ); @@ -156,10 +136,10 @@ void * QgsPalettedRasterRenderer::readBlock( int bandNo, QgsRectangle const & e { currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0; } - //if ( mAlphaBand > 0 ) - //{ - //currentOpacity *= ( readValue( transparencyData, transparencyType, currentRasterPos ) / 255.0 ); - //} + if ( mAlphaBand > 0 ) + { + currentOpacity *= ( readValue( transparencyData, transparencyType, currentRasterPos ) / 255.0 ); + } QColor& currentColor = mColors[val]; if ( mInvertColor ) diff --git a/src/core/raster/qgsrasterlayer.cpp b/src/core/raster/qgsrasterlayer.cpp index 73e7a3237c95..0c138ddb2a1d 100644 --- a/src/core/raster/qgsrasterlayer.cpp +++ b/src/core/raster/qgsrasterlayer.cpp @@ -117,6 +117,7 @@ QgsRasterLayer::QgsRasterLayer( , mWidth( std::numeric_limits::max() ) , mHeight( std::numeric_limits::max() ) , mRenderer( 0 ) + , mResampleFilter( 0 ) { QgsDebugMsg( "Entered" ); @@ -189,6 +190,7 @@ QgsRasterLayer::~QgsRasterLayer() mValid = false; delete mDataProvider; delete mRenderer; + delete mResampleFilter; } ////////////////////////////////////////////////////////// @@ -824,8 +826,16 @@ void QgsRasterLayer::draw( QPainter * theQPainter, if ( mRenderer ) { //mRenderer->draw( theQPainter, theRasterViewPort, theQgsMapToPixel ); - QgsRasterDrawer drawer( mRenderer ); + //if ( mResampleFilter ) + //{ + QgsRasterDrawer drawer( mResampleFilter ); drawer.draw( theQPainter, theRasterViewPort, theQgsMapToPixel ); + //} + //else + //{ + // QgsRasterDrawer drawer( mRenderer ); + // drawer.draw( theQPainter, theRasterViewPort, theQgsMapToPixel ); + //} } QgsDebugMsg( QString( "raster draw time (ms): %1" ).arg( time.elapsed() ) ); @@ -2062,8 +2072,27 @@ void QgsRasterLayer::setTransparentBandName( QString const & ) void QgsRasterLayer::setRenderer( QgsRasterRenderer* renderer ) { + QgsDebugMsg( "Entered" ); delete mRenderer; mRenderer = renderer; + + if ( !mResampleFilter ) + { + mResampleFilter = new QgsRasterResampleFilter( mRenderer ); + } + else + { + mResampleFilter->setInput( mRenderer ); + } +} + +// not sure if we want it +void QgsRasterLayer::setResampleFilter( QgsRasterResampleFilter* resampleFilter ) +{ + QgsDebugMsg( "Entered" ); + delete mResampleFilter; + mResampleFilter = resampleFilter; + mResampleFilter->setInput( mRenderer ); } void QgsRasterLayer::showProgress( int theValue ) @@ -2233,6 +2262,60 @@ bool QgsRasterLayer::readSymbology( const QDomNode& layer_node, QString& errorMe } } } + + //resampler + delete mResampleFilter; + mResampleFilter = new QgsRasterResampleFilter( mRenderer ); + + //max oversampling + QDomElement resampleElem = layer_node.firstChildElement( "rasterresampler" ); + if ( !resampleElem.isNull() ) + { + mResampleFilter->readXML( resampleElem ); + } + /* + if ( mResampleFilter ) + { + QDomElement maxOversamplingElem = mnl.firstChildElement( "maxOversampling" ); + if ( !maxOversamplingElem.isNull() ) + { + bool conversion; + double maxOversampling = maxOversamplingElem.text().toDouble( &conversion ); + if ( conversion ) + { + mResampleFilter->setMaxOversampling( maxOversampling ); + } + } + } + + QDomElement zoomedInResamplerElem = mnl.firstChildElement( "zoomedInResampler" ); + if ( mResampleFilter && !zoomedInResamplerElem.isNull() ) + { + QgsRasterResampler* zoomedInResampler = 0; + QString zoomedInResamplerType = zoomedInResamplerElem.text(); + if ( zoomedInResamplerType == "bilinear" ) + { + zoomedInResampler = new QgsBilinearRasterResampler(); + } + else if ( zoomedInResamplerType == "cubic" ) + { + zoomedInResampler = new QgsCubicRasterResampler(); + } + mResampleFilter->setZoomedInResampler( zoomedInResampler ); + } + QDomElement zoomedOutResamplerElem = mnl.firstChildElement( "zoomedOutResampler" ); + if ( mResampleFilter && !zoomedOutResamplerElem.isNull() ) + { + QgsRasterResampler* zoomedOutResampler = 0; + QString zoomedOutResamplerType = zoomedOutResamplerElem.text(); + if ( zoomedOutResamplerType == "bilinear" ) + { + zoomedOutResampler = new QgsBilinearRasterResampler(); + } + mResampleFilter->setZoomedOutResampler( zoomedOutResampler ); + } + */ + return true; } //readSymbology @@ -2365,11 +2448,18 @@ bool QgsRasterLayer::writeSymbology( QDomNode & layer_node, QDomDocument & docum { Q_UNUSED( errorMessage ); QDomElement layerElem = layer_node.toElement(); + if ( mRenderer ) { mRenderer->writeXML( document, layerElem ); } + if ( mResampleFilter ) + { + QDomElement layerElem = layer_node.toElement(); + mResampleFilter->writeXML( document, layerElem ); + } + return true; } // bool QgsRasterLayer::writeSymbology diff --git a/src/core/raster/qgsrasterlayer.h b/src/core/raster/qgsrasterlayer.h index 0543c6a8562b..1365dc724783 100644 --- a/src/core/raster/qgsrasterlayer.h +++ b/src/core/raster/qgsrasterlayer.h @@ -43,6 +43,7 @@ #include "qgsrastershaderfunction.h" #include "qgsrasterface.h" #include "qgsrasterdrawer.h" +#include "qgsrasterresamplefilter.h" #include "qgsrasterdataprovider.h" // @@ -353,6 +354,11 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer const QgsRasterRenderer* renderer() const { return mRenderer; } QgsRasterRenderer* renderer() { return mRenderer; } + /**Set raster resample filter. Takes ownership of the resample filter object*/ + void setResampleFilter( QgsRasterResampleFilter* resampleFilter ); + const QgsRasterResampleFilter* resampleFilter() const { return mResampleFilter; } + QgsRasterResampleFilter * resampleFilter() { return mResampleFilter; } + /** \brief Accessor to find out how many standard deviations are being plotted */ double standardDeviations() const { return mStandardDeviations; } @@ -855,6 +861,7 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer bool mValidNoDataValue; QgsRasterRenderer* mRenderer; + QgsRasterResampleFilter *mResampleFilter; }; #endif diff --git a/src/core/raster/qgsrasterrenderer.cpp b/src/core/raster/qgsrasterrenderer.cpp index bc0a648d114b..859330969e8e 100644 --- a/src/core/raster/qgsrasterrenderer.cpp +++ b/src/core/raster/qgsrasterrenderer.cpp @@ -40,28 +40,6 @@ QgsRasterRenderer::QgsRasterRenderer( QgsRasterFace* input, const QString& type QgsRasterRenderer::~QgsRasterRenderer() { - //remove remaining memory in partinfos - //QMap::iterator partIt = mRasterPartInfos.begin(); - //for ( ; partIt != mRasterPartInfos.end(); ++partIt ) - //{ - //CPLFree( partIt.value().data ); - //} - - delete mZoomedInResampler; - delete mZoomedOutResampler; - delete mRasterTransparency; -} - -void QgsRasterRenderer::setZoomedInResampler( QgsRasterResampler* r ) -{ - delete mZoomedInResampler; - mZoomedInResampler = r; -} - -void QgsRasterRenderer::setZoomedOutResampler( QgsRasterResampler* r ) -{ - delete mZoomedOutResampler; - mZoomedOutResampler = r; } /* @@ -335,16 +313,7 @@ void QgsRasterRenderer::_writeXML( QDomDocument& doc, QDomElement& rasterRendere rasterRendererElem.setAttribute( "type", mType ); rasterRendererElem.setAttribute( "opacity", QString::number( mOpacity ) ); rasterRendererElem.setAttribute( "alphaBand", mAlphaBand ); - rasterRendererElem.setAttribute( "maxOversampling", QString::number( mMaxOversampling ) ); rasterRendererElem.setAttribute( "invertColor", mInvertColor ); - if ( mZoomedInResampler ) - { - rasterRendererElem.setAttribute( "zoomedInResampler", mZoomedInResampler->type() ); - } - if ( mZoomedOutResampler ) - { - rasterRendererElem.setAttribute( "zoomedOutResampler", mZoomedOutResampler->type() ); - } if ( mRasterTransparency ) { @@ -362,25 +331,8 @@ void QgsRasterRenderer::readXML( const QDomElement& rendererElem ) mType = rendererElem.attribute( "type" ); mOpacity = rendererElem.attribute( "opacity", "1.0" ).toDouble(); mAlphaBand = rendererElem.attribute( "alphaBand", "-1" ).toInt(); - mMaxOversampling = rendererElem.attribute( "maxOversampling", "2.0" ).toDouble(); mInvertColor = rendererElem.attribute( "invertColor", "0" ).toInt(); - QString zoomedInResamplerType = rendererElem.attribute( "zoomedInResampler" ); - if ( zoomedInResamplerType == "bilinear" ) - { - mZoomedInResampler = new QgsBilinearRasterResampler(); - } - else if ( zoomedInResamplerType == "cubic" ) - { - mZoomedInResampler = new QgsCubicRasterResampler(); - } - - QString zoomedOutResamplerType = rendererElem.attribute( "zoomedOutResampler" ); - if ( zoomedOutResamplerType == "bilinear" ) - { - mZoomedOutResampler = new QgsBilinearRasterResampler(); - } - //todo: read mRasterTransparency QDomElement rasterTransparencyElem = rendererElem.firstChildElement( "rasterTransparency" ); if ( !rasterTransparencyElem.isNull() ) diff --git a/src/core/raster/qgsrasterrenderer.h b/src/core/raster/qgsrasterrenderer.h index 64618e10b4c3..bd2339b445a7 100644 --- a/src/core/raster/qgsrasterrenderer.h +++ b/src/core/raster/qgsrasterrenderer.h @@ -60,20 +60,6 @@ class CORE_EXPORT QgsRasterRenderer : public QgsRasterFace void setInvertColor( bool invert ) { mInvertColor = invert; } bool invertColor() const { return mInvertColor; } - /**Set resampler for zoomed in scales. Takes ownership of the object*/ - void setZoomedInResampler( QgsRasterResampler* r ); - const QgsRasterResampler* zoomedInResampler() const { return mZoomedInResampler; } - - /**Set resampler for zoomed out scales. Takes ownership of the object*/ - void setZoomedOutResampler( QgsRasterResampler* r ); - const QgsRasterResampler* zoomedOutResampler() const { return mZoomedOutResampler; } - - void setMaxOversampling( double os ) { mMaxOversampling = os; } - double maxOversampling() const { return mMaxOversampling; } - - /**Get symbology items if provided by renderer*/ - virtual void legendSymbologyItems( QList< QPair< QString, QColor > >& symbolItems ) const { Q_UNUSED( symbolItems ); } - virtual void writeXML( QDomDocument& doc, QDomElement& parentElem ) const = 0; /**Sets base class members from xml. Usually called from create() methods of subclasses*/ diff --git a/src/core/raster/qgsrasterresamplefilter.cpp b/src/core/raster/qgsrasterresamplefilter.cpp new file mode 100644 index 000000000000..5538a2e441b5 --- /dev/null +++ b/src/core/raster/qgsrasterresamplefilter.cpp @@ -0,0 +1,178 @@ +/*************************************************************************** + qgsrasterresamplefilter.cpp + --------------------- + begin : December 2011 + copyright : (C) 2011 by Marco Hugentobler + email : marco at sourcepole dot ch + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsrasterresamplefilter.h" +#include "qgsrasterresampler.h" +#include "qgsrasterprojector.h" +#include "qgsrastertransparency.h" +#include "qgsrasterviewport.h" +#include "qgsmaptopixel.h" + +//resamplers +#include "qgsbilinearrasterresampler.h" +#include "qgscubicrasterresampler.h" + +#include +#include +#include +#include + +QgsRasterResampleFilter::QgsRasterResampleFilter( QgsRasterFace* input ): QgsRasterFace( input ), + mZoomedInResampler( 0 ), mZoomedOutResampler( 0 ), + mMaxOversampling( 2.0 ) +{ +} + +QgsRasterResampleFilter::~QgsRasterResampleFilter() +{ + // TODO: currently we are using pointer to renderer, enable once moved here + //delete mZoomedInResampler; + //delete mZoomedOutResampler; + //delete mRasterTransparency; +} + +void QgsRasterResampleFilter::setZoomedInResampler( QgsRasterResampler* r ) +{ + //delete mZoomedInResampler; + mZoomedInResampler = r; +} + +void QgsRasterResampleFilter::setZoomedOutResampler( QgsRasterResampler* r ) +{ + //delete mZoomedOutResampler; + mZoomedOutResampler = r; +} + +void * QgsRasterResampleFilter::readBlock( int bandNo, QgsRectangle const & extent, int width, int height ) +{ + QgsDebugMsg( "Entered" ); + if ( !mInput ) return 0; + + double oversampling = 1.0; // approximate global oversampling factor + + if ( mZoomedInResampler || mZoomedOutResampler ) + { + // TODO: we must get it somehow from pipe (via projector), for now + oversampling = 2.; + /* + QgsRectangle providerExtent = mInput->extent(); + if ( viewPort->mSrcCRS.isValid() && viewPort->mDestCRS.isValid() && viewPort->mSrcCRS != viewPort->mDestCRS ) + { + QgsCoordinateTransform t( viewPort->mSrcCRS, viewPort->mDestCRS ); + providerExtent = t.transformBoundingBox( providerExtent ); + } + double pixelRatio = mapToPixel->mapUnitsPerPixel() / ( providerExtent.width() / mInput->xSize() ); + oversampling = ( pixelRatio > mMaxOversampling ) ? mMaxOversampling : pixelRatio; + */ + } + + //set oversampling back to 1.0 if no resampler for zoomed in / zoomed out (nearest neighbour) + if (( oversampling < 1.0 && !mZoomedInResampler ) || ( oversampling > 1.0 && !mZoomedOutResampler ) ) + { + oversampling = 1.0; + } + + QgsDebugMsg( QString( "oversampling %1" ).arg( oversampling ) ); + + //effective oversampling factors are different to global one because of rounding + double oversamplingX = (( double )width * oversampling ) / width; + double oversamplingY = (( double )height * oversampling ) / height; + + // TODO: we must also increase the extent to get correct result on borders of parts + + + int resWidth = width*oversamplingX; + int resHeight = height*oversamplingY; + + // At moment we know that we read rendered image + int bandNumber = 0; + void *rasterData = mInput->readBlock( bandNumber, extent, resWidth, resHeight ); + + //resample image + if (( mZoomedInResampler || mZoomedOutResampler ) && !doubleNear( oversamplingX, 1.0 ) && !doubleNear( oversamplingY, 1.0 ) ) + { + QImage img(( uchar * ) rasterData, resWidth, resHeight, QImage::Format_ARGB32_Premultiplied ); + + QImage dstImg = QImage( width, height, QImage::Format_ARGB32_Premultiplied ); + + if ( mZoomedInResampler && oversamplingX < 1.0 ) + { + QgsDebugMsg( "zoomed in resampling" ); + mZoomedInResampler->resample( img, dstImg ); + } + else if ( mZoomedOutResampler && oversamplingX > 1.0 ) + { + QgsDebugMsg( "zoomed out resampling" ); + mZoomedOutResampler->resample( img, dstImg ); + } + + // QImage does not delete data block passed to constructor + free( rasterData ); + + void * data = VSIMalloc( dstImg.byteCount() ); + return memcpy( data, dstImg.bits(), dstImg.byteCount() ); + } + + return rasterData; // No resampling +} + +void QgsRasterResampleFilter::writeXML( QDomDocument& doc, QDomElement& parentElem ) +{ + if ( parentElem.isNull() ) + { + return; + } + + QDomElement rasterRendererElem = doc.createElement( "rasterresampler" ); + + rasterRendererElem.setAttribute( "maxOversampling", mMaxOversampling ); + if ( mZoomedInResampler ) + { + rasterRendererElem.setAttribute( "zoomedInResampler", mZoomedInResampler->type() ); + } + if ( mZoomedOutResampler ) + { + rasterRendererElem.setAttribute( "zoomedOutResampler", mZoomedOutResampler->type() ); + } + parentElem.appendChild( rasterRendererElem ); +} + +void QgsRasterResampleFilter::readXML( const QDomElement& rendererElem ) +{ + if ( rendererElem.isNull() ) + { + return; + } + + mMaxOversampling = rendererElem.attribute( "maxOversampling", "2.0" ).toDouble(); + + QString zoomedInResamplerType = rendererElem.attribute( "zoomedInResampler" ); + if ( zoomedInResamplerType == "bilinear" ) + { + mZoomedInResampler = new QgsBilinearRasterResampler(); + } + else if ( zoomedInResamplerType == "cubic" ) + { + mZoomedInResampler = new QgsCubicRasterResampler(); + } + + QString zoomedOutResamplerType = rendererElem.attribute( "zoomedOutResampler" ); + if ( zoomedOutResamplerType == "bilinear" ) + { + mZoomedOutResampler = new QgsBilinearRasterResampler(); + } +} diff --git a/src/core/raster/qgsrasterresamplefilter.h b/src/core/raster/qgsrasterresamplefilter.h new file mode 100644 index 000000000000..7205b6df44e3 --- /dev/null +++ b/src/core/raster/qgsrasterresamplefilter.h @@ -0,0 +1,75 @@ +/*************************************************************************** + qgsrasterresamplefilter.h + ------------------- + begin : December 2011 + copyright : (C) 2011 by Marco Hugentobler + email : marco at sourcepole dot ch + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSRASTERRESAMPLEFILTER_H +#define QGSRASTERRESAMPLEFILTER_H + +#include "qgsrasterdataprovider.h" +#include "qgsrasterface.h" + +class QPainter; +class QgsMapToPixel; +class QgsRasterResampler; +class QgsRasterProjector; +class QgsRasterTransparency; +class QgsRasterViewPort; + +class QDomElement; + +class QgsRasterResampleFilter : public QgsRasterFace +{ + public: + QgsRasterResampleFilter( QgsRasterFace* input = 0 ); + ~QgsRasterResampleFilter(); + + void * readBlock( int bandNo, QgsRectangle const & extent, int width, int height ); + + /**Set resampler for zoomed in scales. Takes ownership of the object*/ + void setZoomedInResampler( QgsRasterResampler* r ); + const QgsRasterResampler* zoomedInResampler() const { return mZoomedInResampler; } + + /**Set resampler for zoomed out scales. Takes ownership of the object*/ + void setZoomedOutResampler( QgsRasterResampler* r ); + const QgsRasterResampler* zoomedOutResampler() const { return mZoomedOutResampler; } + + void setMaxOversampling( double os ) { mMaxOversampling = os; } + double maxOversampling() const { return mMaxOversampling; } + + void writeXML( QDomDocument& doc, QDomElement& parentElem ); + + /**Sets base class members from xml. Usually called from create() methods of subclasses*/ + void readXML( const QDomElement& resamplefilterElem ); + + protected: + + /**Write upper class info into element (called by writeXML method of subclasses)*/ + //void _writeXML( QDomDocument& doc, QDomElement& rasterRendererElem ) const; + + + /**Resampler used if screen resolution is higher than raster resolution (zoomed in). 0 means no resampling (nearest neighbour)*/ + QgsRasterResampler* mZoomedInResampler; + /**Resampler used if raster resolution is higher than raster resolution (zoomed out). 0 mean no resampling (nearest neighbour)*/ + QgsRasterResampler* mZoomedOutResampler; + //QMap mRasterPartInfos; + + /**Maximum boundary for oversampling (to avoid too much data traffic). Default: 2.0*/ + double mMaxOversampling; + + private: +}; + +#endif // QGSRASTERRESAMPLEFILTER_H diff --git a/src/core/raster/qgssinglebandcolordatarenderer.cpp b/src/core/raster/qgssinglebandcolordatarenderer.cpp index 5bdb91554314..51240b9d644e 100644 --- a/src/core/raster/qgssinglebandcolordatarenderer.cpp +++ b/src/core/raster/qgssinglebandcolordatarenderer.cpp @@ -51,18 +51,6 @@ void * QgsSingleBandColorDataRenderer::readBlock( int bandNo, QgsRectangle cons return 0; } - double oversamplingX, oversamplingY; - //startRasterRead( mBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); - - //number of cols/rows in output pixels - int nCols = 0; - int nRows = 0; - //number of raster cols/rows with oversampling - int nRasterCols = 0; - int nRasterRows = 0; - //shift to top left point for the raster part - int topLeftCol = 0; - int topLeftRow = 0; int currentRasterPos; //bool hasTransparency = usesTransparency( viewPort->mSrcCRS, viewPort->mDestCRS ); @@ -70,7 +58,6 @@ void * QgsSingleBandColorDataRenderer::readBlock( int bandNo, QgsRectangle cons QgsRasterFace::DataType rasterType = ( QgsRasterFace::DataType )mInput->dataType( mBand ); - void* rasterData = mInput->readBlock( bandNo, extent, width, height ); currentRasterPos = 0; @@ -81,8 +68,8 @@ void * QgsSingleBandColorDataRenderer::readBlock( int bandNo, QgsRectangle cons scanLine = img.scanLine( i ); if ( !hasTransparency ) { - memcpy( scanLine, &((( uint* )rasterData )[currentRasterPos] ), nCols * 4 ); - currentRasterPos += nRasterCols; + memcpy( scanLine, &((( uint* )rasterData )[currentRasterPos] ), width * 4 ); + currentRasterPos += width; } else { diff --git a/src/core/raster/qgssinglebandgrayrenderer.cpp b/src/core/raster/qgssinglebandgrayrenderer.cpp index 7d3e4f960117..9d5d3a0f0825 100644 --- a/src/core/raster/qgssinglebandgrayrenderer.cpp +++ b/src/core/raster/qgssinglebandgrayrenderer.cpp @@ -63,51 +63,32 @@ void QgsSingleBandGrayRenderer::setContrastEnhancement( QgsContrastEnhancement* //void QgsSingleBandGrayRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ) void * QgsSingleBandGrayRenderer::readBlock( int bandNo, QgsRectangle const & extent, int width, int height ) { - //if ( !mInput || !viewPort || !theQgsMapToPixel ) if ( !mInput ) { return 0; } - //double oversamplingX, oversamplingY; - //startRasterRead( mGrayBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); - //if ( mAlphaBand > 0 && mGrayBand != mAlphaBand ) - //{ - //startRasterRead( mAlphaBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); - //} - - //number of cols/rows in output pixels - //int nCols = 0; - //int nRows = 0; - ////number of raster cols/rows with oversampling - //int nRasterCols = 0; - //int nRasterRows = 0; - ////shift to top left point for the raster part - //int topLeftCol = 0; - //int topLeftRow = 0; - QgsRasterFace::DataType rasterType = ( QgsRasterFace::DataType )mInput->dataType( mGrayBand ); - //QgsRasterFace::DataType alphaType = QgsRasterFace::UnknownDataType; - //if ( mAlphaBand > 0 ) - //{ - //alphaType = ( QgsRasterFace::DataType )mInput->dataType( mAlphaBand ); - //} + QgsRasterFace::DataType alphaType = QgsRasterFace::UnknownDataType; + if ( mAlphaBand > 0 ) + { + alphaType = ( QgsRasterFace::DataType )mInput->dataType( mAlphaBand ); + } void* rasterData = mInput->readBlock( mGrayBand, extent, width, height ); - //void* alphaData; + void* alphaData; double currentAlpha = mOpacity; - int grayVal; + int grayVal, grayValOrig; QRgb myDefaultColor = qRgba( 0, 0, 0, 0 ); - //if ( mAlphaBand > 0 && mGrayBand != mAlphaBand ) - //{ - //readNextRasterPart( mAlphaBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows, - //&alphaData, topLeftCol, topLeftRow ); - //} - //else if ( mAlphaBand > 0 ) - //{ - //alphaData = rasterData; - //} + if ( mAlphaBand > 0 && mGrayBand != mAlphaBand ) + { + alphaData = mInput->readBlock( mAlphaBand, extent, width, height ); + } + else if ( mAlphaBand > 0 ) + { + alphaData = rasterData; + } //create image QImage img( width, height, QImage::Format_ARGB32_Premultiplied ); @@ -119,7 +100,7 @@ void * QgsSingleBandGrayRenderer::readBlock( int bandNo, QgsRectangle const & e imageScanLine = ( QRgb* )( img.scanLine( i ) ); for ( int j = 0; j < width; ++j ) { - grayVal = readValue( rasterData, rasterType, currentRasterPos ); + grayValOrig = grayVal = readValue( rasterData, rasterType, currentRasterPos ); //alpha currentAlpha = mOpacity; diff --git a/src/core/raster/qgssinglebandpseudocolorrenderer.cpp b/src/core/raster/qgssinglebandpseudocolorrenderer.cpp index 2190afa13b9a..9e772f7a5262 100644 --- a/src/core/raster/qgssinglebandpseudocolorrenderer.cpp +++ b/src/core/raster/qgssinglebandpseudocolorrenderer.cpp @@ -66,28 +66,13 @@ void * QgsSingleBandPseudoColorRenderer::readBlock( int bandNo, QgsRectangle co return 0; } - //double oversamplingX, oversamplingY; - //QgsRasterFace::DataType transparencyType = QgsRasterFace::UnknownDataType; - //if ( mAlphaBand > 0 ) - //{ - //transparencyType = ( QgsRasterFace::DataType )mInput->dataType( mAlphaBand ); - //} - //startRasterRead( mBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); - ////Read alpha band if necessary - //if ( mAlphaBand > 0 && mAlphaBand != mBand ) - //{ - //startRasterRead( mAlphaBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); - //} - - //number of cols/rows in output pixels - int nCols = 0; - int nRows = 0; - //number of raster cols/rows with oversampling - int nRasterCols = 0; - int nRasterRows = 0; - //shift to top left point for the raster part - int topLeftCol = 0; - int topLeftRow = 0; + QgsRasterFace::DataType transparencyType = QgsRasterFace::UnknownDataType; + if ( mAlphaBand > 0 ) + { + transparencyType = ( QgsRasterFace::DataType )mInput->dataType( mAlphaBand ); + } + + void* transparencyData; void* transparencyData = 0; double currentOpacity = mOpacity; QgsRasterFace::DataType rasterType = ( QgsRasterFace::DataType )mInput->dataType( mBand ); @@ -101,15 +86,14 @@ void * QgsSingleBandPseudoColorRenderer::readBlock( int bandNo, QgsRectangle co //bool hasTransparency = usesTransparency( viewPort->mSrcCRS, viewPort->mDestCRS ); bool hasTransparency = false; - //if ( mAlphaBand > 0 && mAlphaBand != mBand ) - //{ - //readNextRasterPart( mAlphaBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows, - //&transparencyData, topLeftCol, topLeftRow ); - //} - //else if ( mAlphaBand == mBand ) - //{ - //transparencyData = rasterData; - //} + if ( mAlphaBand > 0 && mAlphaBand != mBand ) + { + transparencyData = mInput->readBlock( mAlphaBand, extent, width, height ); + } + else if ( mAlphaBand == mBand ) + { + transparencyData = rasterData; + } //create image QImage img( width, height, QImage::Format_ARGB32_Premultiplied ); @@ -142,10 +126,10 @@ void * QgsSingleBandPseudoColorRenderer::readBlock( int bandNo, QgsRectangle co { currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0; } - //if ( mAlphaBand > 0 ) - //{ - //currentOpacity *= ( readValue( transparencyData, transparencyType, currentRasterPos ) / 255.0 ); - //} + if ( mAlphaBand > 0 ) + { + currentOpacity *= ( readValue( transparencyData, transparencyType, currentRasterPos ) / 255.0 ); + } imageScanLine[j] = qRgba( currentOpacity * red, currentOpacity * green, currentOpacity * blue, currentOpacity * 255 ); }