87 changes: 74 additions & 13 deletions src/app/qgsoptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
#include "qgsnetworkaccessmanager.h"
#include "qgsproject.h"

#include "qgsrasterformatsaveoptionswidget.h"
#include "qgsdialog.h"

#include <QInputDialog>
#include <QFileDialog>
#include <QSettings>
Expand Down Expand Up @@ -579,7 +582,10 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WFlags fl ) :
// load gdal driver list only when gdal tab is first opened
mLoadedGdalDriverList = false;

tabWidget->setCurrentIndex( settings.value( "/Windows/Options/row" ).toInt() );
// tabWidget->setCurrentIndex( settings.value( "/Windows/Options/row" ).toInt() );
int currentTab = settings.value( "/Windows/Options/row" ).toInt();
tabWidget->setCurrentIndex( currentTab );
on_tabWidget_currentChanged( currentTab );
}

//! Destructor
Expand Down Expand Up @@ -1063,6 +1069,51 @@ void QgsOptions::on_pbnSelectOtfProjection_clicked()
}
}

void QgsOptions::on_lstGdalDrivers_itemDoubleClicked( QTreeWidgetItem * item, int column )
{
Q_UNUSED( column );
// edit driver if driver supports write
if ( item && ( cmbEditCreateOptions->findText( item->text( 0 ) ) != -1 ) )
{
editGdalDriver( item->text( 0 ) );
}
}

void QgsOptions::on_pbnEditCreateOptions_pressed()
{
editGdalDriver( cmbEditCreateOptions->currentText() );
}

void QgsOptions::on_pbnEditPyramidsOptions_pressed()
{
editGdalDriver( "_pyramids" );
}

void QgsOptions::editGdalDriver( const QString& driverName )
{
if ( driverName.isEmpty() )
return;

QgsDialog dlg( this, 0, QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
QVBoxLayout *layout = dlg.layout();
QString title = tr( "Create Options - %1 Driver" ).arg( driverName );
if ( driverName == "_pyramids" )
title = tr( "Create Options - pyramids" );
dlg.setWindowTitle( title );
QLabel *label = new QLabel( title, &dlg );
label->setAlignment( Qt::AlignHCenter );
layout->addWidget( label );
QgsRasterFormatSaveOptionsWidget* optionsWidget =
new QgsRasterFormatSaveOptionsWidget( &dlg, driverName,
QgsRasterFormatSaveOptionsWidget::Full, "gdal" );
layout->addWidget( optionsWidget );

if ( dlg.exec() == QDialog::Accepted )
{
optionsWidget->apply();
}
}

// Return state of the visibility flag for newly added layers. If

bool QgsOptions::newVisible()
Expand Down Expand Up @@ -1343,6 +1394,7 @@ void QgsOptions::loadGdalDriverList()
GDALDriverH myGdalDriver; // current driver
QString myGdalDriverDescription;
QStringList myDrivers;
QStringList myGdalWriteDrivers;
QMap<QString, QString> myDriversFlags, myDriversExt, myDriversLongName;

// make sure we save list when accept()
Expand Down Expand Up @@ -1372,7 +1424,10 @@ void QgsOptions::loadGdalDriverList()
// get driver R/W flags, taken from GDALGeneralCmdLineProcessor()
const char *pszRWFlag, *pszVirtualIO;
if ( GDALGetMetadataItem( myGdalDriver, GDAL_DCAP_CREATE, NULL ) )
{
myGdalWriteDrivers << myGdalDriverDescription;
pszRWFlag = "rw+";
}
else if ( GDALGetMetadataItem( myGdalDriver, GDAL_DCAP_CREATECOPY,
NULL ) )
pszRWFlag = "rw";
Expand All @@ -1399,18 +1454,11 @@ void QgsOptions::loadGdalDriverList()
// sort list case insensitive - no existing function for this!
QMap<QString, QString> strMap;
foreach( QString str, myDrivers )
{
strMap.insert( str.toLower(), str );
}
strMap.insert( str.toLower(), str );
myDrivers = strMap.values();

QStringListIterator myIterator( myDrivers );

while ( myIterator.hasNext() )
foreach( QString myName, myDrivers )
{
QString myName = myIterator.next();

// QListWidgetItem * mypItem = new QListWidgetItem( myName );
QTreeWidgetItem * mypItem = new QTreeWidgetItem( QStringList( myName ) );
if ( mySkippedDrivers.contains( myName ) )
{
Expand All @@ -1423,9 +1471,9 @@ void QgsOptions::loadGdalDriverList()

// add driver metadata
mypItem->setText( 1, myDriversExt[myName] );
mypItem->setText( 2, myDriversFlags[myName] );
QString myFlags = myDriversFlags[myName];
mypItem->setText( 2, myFlags );
mypItem->setText( 3, myDriversLongName[myName] );

lstGdalDrivers->addTopLevelItem( mypItem );
}
// adjust column width
Expand All @@ -1434,13 +1482,26 @@ void QgsOptions::loadGdalDriverList()
lstGdalDrivers->resizeColumnToContents( i );
lstGdalDrivers->setColumnWidth( i, lstGdalDrivers->columnWidth( i ) + 5 );
}

// populate cmbEditCreateOptions with gdal write drivers - sorted, GTiff first
strMap.clear();
foreach( QString str, myGdalWriteDrivers )
strMap.insert( str.toLower(), str );
myGdalWriteDrivers = strMap.values();
myGdalWriteDrivers.removeAll( "Gtiff" );
myGdalWriteDrivers.prepend( "GTiff" );
cmbEditCreateOptions->clear();
foreach( QString myName, myGdalWriteDrivers )
{
cmbEditCreateOptions->addItem( myName );
}

}

void QgsOptions::saveGdalDriverList()
{
for ( int i = 0; i < lstGdalDrivers->topLevelItemCount(); i++ )
{
// QListWidgetItem * mypItem = lstGdalDrivers->item( i );
QTreeWidgetItem * mypItem = lstGdalDrivers->topLevelItem( i );
if ( mypItem->checkState( 0 ) == Qt::Unchecked )
{
Expand Down
4 changes: 4 additions & 0 deletions src/app/qgsoptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ class QgsOptions : public QDialog, private Ui::QgsOptionsBase
void on_pbnSelectProjection_clicked();
//! Slot called when user chooses to change the default 'on the fly' projection.
void on_pbnSelectOtfProjection_clicked();
void on_lstGdalDrivers_itemDoubleClicked( QTreeWidgetItem * item, int column );
void on_pbnEditCreateOptions_pressed();
void on_pbnEditPyramidsOptions_pressed();
void editGdalDriver( const QString& driverName );
void saveOptions();
//! Slot to change the theme this is handled when the user
// activates or highlights a theme name in the drop-down list
Expand Down
132 changes: 120 additions & 12 deletions src/app/qgsrasterlayerproperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
***************************************************************************/

#include <limits>
#include <typeinfo>

#include "qgsmaptopixel.h"
#include "qgsmapcanvas.h"
Expand Down Expand Up @@ -184,16 +185,18 @@ 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() )
{
mInvertColorMapCheckBox->setCheckState( Qt::Checked );
}

const QgsRasterResampler* zoomedInResampler = renderer->zoomedInResampler();
const QgsRasterResampler* zoomedInResampler = resampleFilter->zoomedInResampler();
if ( zoomedInResampler )
{
if ( zoomedInResampler->type() == "bilinear" )
Expand All @@ -210,7 +213,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
Expand All @@ -222,7 +225,7 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer* lyr, QgsMapCanv
{
mZoomedOutResamplingComboBox->setCurrentIndex( 0 );
}
mMaximumOversamplingSpinBox->setValue( renderer->maxOversampling() );
mMaximumOversamplingSpinBox->setValue( resampleFilter->maxOversampling() );
}

//transparency band
Expand Down Expand Up @@ -294,6 +297,8 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer* lyr, QgsMapCanv
}
on_mRenderTypeComboBox_currentIndexChanged( mRenderTypeComboBox->currentIndex() );

updatePipeList();

// update based on lyr's current state
sync();

Expand Down Expand Up @@ -444,7 +449,8 @@ void QgsRasterLayerProperties::sync()
{
QSettings myQSettings;

if ( mRasterLayer->dataProvider()->dataType( 1 ) == QgsRasterDataProvider::ARGBDataType )
if ( mRasterLayer->dataProvider()->dataType( 1 ) == QgsRasterDataProvider::ARGB32
|| mRasterLayer->dataProvider()->dataType( 1 ) == QgsRasterDataProvider::ARGB32_Premultiplied )
{
gboxNoDataValue->setEnabled( false );
gboxCustomTransparency->setEnabled( false );
Expand Down Expand Up @@ -535,7 +541,8 @@ void QgsRasterLayerProperties::sync()
lblRows->setText( tr( "Rows: " ) + tr( "n/a" ) );
}

if ( mRasterLayer->dataProvider()->dataType( 1 ) == QgsRasterDataProvider::ARGBDataType )
if ( mRasterLayer->dataProvider()->dataType( 1 ) == QgsRasterDataProvider::ARGB32
|| mRasterLayer->dataProvider()->dataType( 1 ) == QgsRasterDataProvider::ARGB32_Premultiplied )
{
lblNoData->setText( tr( "No-Data Value: " ) + tr( "n/a" ) );
}
Expand Down Expand Up @@ -808,6 +815,8 @@ void QgsRasterLayerProperties::apply()
pixmapLegend->setScaledContents( true );
pixmapLegend->repaint();

QgsRasterResampleFilter* resampleFilter = mRasterLayer->resampleFilter();

QgsRasterResampler* zoomedInResampler = 0;
QString zoomedInResamplingMethod = mZoomedInResamplingComboBox->currentText();
if ( zoomedInResamplingMethod == tr( "Bilinear" ) )
Expand All @@ -819,9 +828,9 @@ void QgsRasterLayerProperties::apply()
zoomedInResampler = new QgsCubicRasterResampler();
}

if ( rasterRenderer )
if ( resampleFilter )
{
rasterRenderer->setZoomedInResampler( zoomedInResampler );
resampleFilter->setZoomedInResampler( zoomedInResampler );
}

//raster resampling
Expand All @@ -832,14 +841,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() );
}


Expand All @@ -862,6 +871,8 @@ void QgsRasterLayerProperties::apply()

// notify the project we've made a change
QgsProject::instance()->dirty( true );

updatePipeList();
}//apply

void QgsRasterLayerProperties::on_buttonBuildPyramids_clicked()
Expand Down Expand Up @@ -1477,3 +1488,100 @@ void QgsRasterLayerProperties::toggleBuildPyramidsButton()
}
}

void QgsRasterLayerProperties::updatePipeList()
{
QgsDebugMsg( "Entered" );

#ifndef QGISDEBUG
tabBar->removeTab( tabBar->indexOf( tabPagePipe ) );
#else
mPipeTreeWidget->clear();

mPipeTreeWidget->header()->setResizeMode( QHeaderView::ResizeToContents );

if ( mPipeTreeWidget->columnCount() <= 1 )
{
QStringList labels;
labels << tr( "Filter" ) << tr( "Bands" ) << tr( "Time" );
mPipeTreeWidget->setHeaderLabels( labels );
connect( mPipeTreeWidget, SIGNAL( itemClicked( QTreeWidgetItem *, int ) ), this, SLOT( pipeItemClicked( QTreeWidgetItem *, int ) ) );
}

QgsRasterPipe *pipe = mRasterLayer->pipe();
for ( int i = 0; i < pipe->size(); i++ )
{
QgsRasterInterface * interface = pipe->at( i );
QStringList texts;
QString name;
// Unfortunately at this moment not all interfaces inherits from QObject
QObject *o = dynamic_cast<QObject*>( interface );
if ( o )
{
//name = o->objectName(); // gives empty with provider
name = o->metaObject()->className();
}
else
{
name = QString( typeid( *interface ).name() ).replace( QRegExp( ".*Qgs" ), "Qgs" );
}

texts << name << QString( "%1" ).arg( interface->bandCount() );
texts << QString( "%1 ms" ).arg( interface->time() );
QTreeWidgetItem *item = new QTreeWidgetItem( texts );

// Switching on/off would be possible but problematic - drawer is not pipe
// memer so we dont know required output format
// Checkobxes are very usefel however for QgsRasterPipe debugging.
//bool on = interface->on();
//item->setCheckState( 0, on ? Qt::Checked : Qt::Unchecked );

//Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
Qt::ItemFlags flags = Qt::ItemIsEnabled;
item->setFlags( flags );

mPipeTreeWidget->addTopLevelItem( item );
}
updatePipeItems();
#endif
}

void QgsRasterLayerProperties::pipeItemClicked( QTreeWidgetItem * item, int column )
{
QgsDebugMsg( "Entered" );
int idx = mPipeTreeWidget->indexOfTopLevelItem( item );

// This should not fail because we have enabled only checkboxes of items
// which may be changed
mRasterLayer->pipe()->setOn( idx, item->checkState( 0 ) );

updatePipeItems();
}

void QgsRasterLayerProperties::updatePipeItems()
{
QgsDebugMsg( "Entered" );

QgsRasterPipe *pipe = mRasterLayer->pipe();

for ( int i = 0; i < pipe->size(); i++ )
{
if ( i >= mPipeTreeWidget->topLevelItemCount() ) break;
QgsRasterInterface * interface = pipe->at( i );
QTreeWidgetItem *item = mPipeTreeWidget->topLevelItem( i );
if ( !item ) continue;
// Checkboxes disabled for now, see above
/*
bool on = interface->on();
Qt::ItemFlags flags = item->flags();
if ( pipe->canSetOn( i, !on ) )
{
flags |= Qt::ItemIsUserCheckable;
}
else
{
flags |= ( Qt::ItemFlags )~Qt::ItemIsUserCheckable;
}
item->setFlags( flags );
*/
}
}
9 changes: 9 additions & 0 deletions src/app/qgsrasterlayerproperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ class QgsRasterLayerProperties : public QDialog, private Ui::QgsRasterLayerPrope
/**Enable or disable Build pyramids button depending on selection in pyramids list*/
void toggleBuildPyramidsButton();

/** Update items in pipe list */
void pipeItemClicked( QTreeWidgetItem * item, int column );

signals:
/** emitted when changes to layer were saved to update legend */
void refreshLegend( QString layerID, bool expandItem );
Expand Down Expand Up @@ -149,6 +152,12 @@ class QgsRasterLayerProperties : public QDialog, private Ui::QgsRasterLayerPrope
qreal mGradientHeight;
qreal mGradientWidth;

/** Update pipe tab - interfaces list */
void updatePipeList();

/** Update items in pipe list */
void updatePipeItems();

QgsMapCanvas* mMapCanvas;
QgsMapToolEmitPoint* mPixelSelectorTool;

Expand Down
8 changes: 8 additions & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,17 @@ SET(QGIS_CORE_SRCS
raster/qgslinearminmaxenhancement.cpp
raster/qgslinearminmaxenhancementwithclip.cpp
raster/qgspseudocolorshader.cpp
raster/qgsrasterinterface.cpp
raster/qgsrasteriterator.cpp
raster/qgsrasterlayer.cpp
raster/qgsrastertransparency.cpp
raster/qgsrasterpipe.cpp
raster/qgsrastershader.cpp
raster/qgsrastershaderfunction.cpp

raster/qgsrasterdrawer.cpp
raster/qgsrasterfilewriter.cpp
raster/qgsrasterresamplefilter.cpp
raster/qgsrasterrendererregistry.cpp
raster/qgsrasterrenderer.cpp
raster/qgsbilinearrasterresampler.cpp
Expand Down Expand Up @@ -384,8 +390,10 @@ SET(QGIS_CORE_HDRS
raster/qgspseudocolorshader.h
raster/qgsrasterpyramid.h
raster/qgsrasterbandstats.h
raster/qgsrasterinterface.h
raster/qgsrasterlayer.h
raster/qgsrastertransparency.h
raster/qgsrasterpipe.h
raster/qgsrastershader.h
raster/qgsrastershaderfunction.h
raster/qgsrasterviewport.h
Expand Down
19 changes: 2 additions & 17 deletions src/core/qgsproviderregistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,23 +389,8 @@ QgsDataProvider *QgsProviderRegistry::provider( QString const & providerKey, QSt
QgsDebugMsg( "Instantiated the data provider plugin" );
QgsDebugMsg( "provider name: " + dataProvider->name() );

if ( dataProvider->isValid() )
{
delete myLib;
return dataProvider;
}
else
{
// this is likely because the dataSource is invalid, and isn't
// necessarily a reflection on the data provider itself
QgsDebugMsg( "Invalid data provider" );

delete dataProvider;

myLib->unload();
delete myLib;
return 0;
}
delete myLib;
return dataProvider;
}
else
{
Expand Down
25 changes: 24 additions & 1 deletion src/core/qgsrasterdataprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,26 @@ void QgsRasterDataProvider::readBlock( int bandNo, QgsRectangle
free( mySrcData );
}

void * QgsRasterDataProvider::readBlock( int bandNo, QgsRectangle const & extent, int width, int height )
{
QgsDebugMsg( QString( "bandNo = %1 width = %2 height = %3" ).arg( bandNo ).arg( width ).arg( height ) );

// TODO: replace VSIMalloc, it is GDAL function
void * data = VSIMalloc( dataTypeSize( bandNo ) * width * height );
readBlock( bandNo, extent, width, height, data );

return data;
}

QgsRasterDataProvider::QgsRasterDataProvider(): mDpi( -1 )
QgsRasterDataProvider::QgsRasterDataProvider()
: QgsRasterInterface( 0 )
, mDpi( -1 )
{
}

QgsRasterDataProvider::QgsRasterDataProvider( QString const & uri )
: QgsDataProvider( uri )
, QgsRasterInterface( 0 )
, mDpi( -1 )
{
}
Expand Down Expand Up @@ -172,6 +185,16 @@ QString QgsRasterDataProvider::capabilitiesString() const
abilitiesList += tr( "Build Pyramids" );
}

if ( abilities & QgsRasterDataProvider::Create )
{
abilitiesList += tr( "Create Datasources" );
}

if ( abilities & QgsRasterDataProvider::Remove )
{
abilitiesList += tr( "Remove Datasources" );
}

QgsDebugMsg( "Capability: " + abilitiesList.join( ", " ) );

return abilitiesList.join( ", " );
Expand Down
118 changes: 51 additions & 67 deletions src/core/qgsrasterdataprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "qgslogger.h"
#include "qgsrectangle.h"
#include "qgsdataprovider.h"
#include "qgsrasterinterface.h"
#include "qgscolorrampshader.h"
#include "qgsrasterpyramid.h"
#include "qgscoordinatereferencesystem.h"
Expand All @@ -47,7 +48,7 @@ class QByteArray;
* QgsVectorDataProvider, and does not yet make
* sense for Raster layers.
*/
class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider
class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRasterInterface
{

Q_OBJECT
Expand All @@ -64,26 +65,9 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider
EstimatedMinimumMaximum = 1 << 3,
BuildPyramids = 1 << 4,
Histogram = 1 << 5,
Size = 1 << 6 // has fixed source type
};

// This is modified copy of GDALDataType
enum DataType
{
/*! Unknown or unspecified type */ UnknownDataType = 0,
/*! Eight bit unsigned integer */ Byte = 1,
/*! Sixteen bit unsigned integer */ UInt16 = 2,
/*! Sixteen bit signed integer */ Int16 = 3,
/*! Thirty two bit unsigned integer */ UInt32 = 4,
/*! Thirty two bit signed integer */ Int32 = 5,
/*! Thirty two bit floating point */ Float32 = 6,
/*! Sixty four bit floating point */ Float64 = 7,
/*! Complex Int16 */ CInt16 = 8,
/*! Complex Int32 */ CInt32 = 9,
/*! Complex Float32 */ CFloat32 = 10,
/*! Complex Float64 */ CFloat64 = 11,
/*! Color, alpha, red, green, blue, 4 bytes */ ARGBDataType = 12,
TypeCount = 13 /* maximum type # + 1 */
Size = 1 << 6, // has fixed source type
Create = 1 << 7, //create new datasets
Remove = 1 << 8 //delete datasets
};

// This is modified copy of GDALColorInterp
Expand Down Expand Up @@ -123,6 +107,10 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider

virtual ~QgsRasterDataProvider() {};

QgsRasterInterface * srcInput() { return this; }

/* It makes no sense to set input on provider */
bool setInput( QgsRasterInterface* input ) { Q_UNUSED( input ); return false; }

/**
* Add the list of WMS layer names to be rendered by this server
Expand Down Expand Up @@ -175,64 +163,20 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider
// TODO: Get the file masks supported by this provider, suitable for feeding into the file open dialog box

/** Returns data type for the band specified by number */
virtual int dataType( int bandNo ) const
virtual QgsRasterInterface::DataType dataType( int bandNo ) const
{
return srcDataType( bandNo );
}

/** Returns source data type for the band specified by number,
* source data type may be shorter than dataType
*/
virtual int srcDataType( int bandNo ) const
virtual QgsRasterInterface::DataType srcDataType( int bandNo ) const
{
Q_UNUSED( bandNo );
return QgsRasterDataProvider::UnknownDataType;
}

int typeSize( int dataType ) const
{
// modified copy from GDAL
switch ( dataType )
{
case Byte:
return 8;

case UInt16:
case Int16:
return 16;

case UInt32:
case Int32:
case Float32:
case CInt16:
return 32;

case Float64:
case CInt32:
case CFloat32:
return 64;

case CFloat64:
return 128;

case ARGBDataType:
return 32;

default:
return 0;
}
}
int dataTypeSize( int bandNo ) const
{
return typeSize( dataType( bandNo ) );
}

/** Get numbur of bands */
virtual int bandCount() const
{
return 1;
}

/** Returns data type for the band specified by number */
virtual int colorInterpretation( int theBandNo ) const
{
Expand Down Expand Up @@ -328,6 +272,9 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider
/** read block of data using give extent and size */
virtual void readBlock( int bandNo, QgsRectangle const & viewExtent, int width, int height, QgsCoordinateReferenceSystem theSrcCRS, QgsCoordinateReferenceSystem theDestCRS, void *data );

/** Read block of data using given extent and size. */
virtual void * readBlock( int bandNo, QgsRectangle const & extent, int width, int height );

/* Read a value from a data block at a given index. */
virtual double readValue( void *data, int type, int index );

Expand Down Expand Up @@ -501,6 +448,43 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider
/** Current time stamp of data source */
virtual QDateTime dataTimestamp() const { return QDateTime(); }

/**Writes into the provider datasource*/
virtual bool write( void* data, int band, int width, int height, int xOffset, int yOffset )
{
Q_UNUSED( data );
Q_UNUSED( band );
Q_UNUSED( width );
Q_UNUSED( height );
Q_UNUSED( xOffset );
Q_UNUSED( yOffset );
return false;
}

/** Creates a new dataset with mDataSourceURI
@return true in case of success*/
virtual bool create( const QString& format, int nBands,
QgsRasterDataProvider::DataType type,
int width, int height, double* geoTransform,
const QgsCoordinateReferenceSystem& crs,
QStringList createOptions = QStringList() /*e.v. color table*/ )
{
Q_UNUSED( format );
Q_UNUSED( nBands );
Q_UNUSED( type );
Q_UNUSED( width );
Q_UNUSED( height );
Q_UNUSED( geoTransform );
Q_UNUSED( crs );
Q_UNUSED( createOptions );
return false;
}

/**Returns the formats supported by create()*/
virtual QStringList createFormats() const { return QStringList(); }

/** Remove dataset*/
virtual bool remove() { return false; }

signals:
/** Emit a signal to notify of the progress event.
* Emited theProgress is in percents (0.0-100.0) */
Expand Down
171 changes: 157 additions & 14 deletions src/core/qgsrasterprojector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* *
***************************************************************************/

#include "qgsrasterdataprovider.h"
#include "qgslogger.h"
#include "qgsrasterprojector.h"
#include "qgscoordinatetransform.h"
Expand All @@ -26,17 +27,93 @@ QgsRasterProjector::QgsRasterProjector(
int theDestRows, int theDestCols,
double theMaxSrcXRes, double theMaxSrcYRes,
QgsRectangle theExtent )
: mSrcCRS( theSrcCRS )
: QgsRasterInterface( 0 )
, mSrcCRS( theSrcCRS )
, mDestCRS( theDestCRS )
, mCoordinateTransform( theDestCRS, theSrcCRS )
, mDestExtent( theDestExtent )
, mExtent( theExtent )
, mDestRows( theDestRows ), mDestCols( theDestCols )
, mMaxSrcXRes( theMaxSrcXRes ), mMaxSrcYRes( theMaxSrcYRes )
, pHelperTop( 0 ), pHelperBottom( 0 )
{
QgsDebugMsg( "Entered" );
QgsDebugMsg( "theDestExtent = " + theDestExtent.toString() );

calc();
}

QgsRasterProjector::QgsRasterProjector(
QgsCoordinateReferenceSystem theSrcCRS,
QgsCoordinateReferenceSystem theDestCRS,
double theMaxSrcXRes, double theMaxSrcYRes,
QgsRectangle theExtent )
: QgsRasterInterface( 0 )
, mSrcCRS( theSrcCRS )
, mDestCRS( theDestCRS )
, mCoordinateTransform( theDestCRS, theSrcCRS )
, mExtent( theExtent )
, mMaxSrcXRes( theMaxSrcXRes ), mMaxSrcYRes( theMaxSrcYRes )
, pHelperTop( 0 ), pHelperBottom( 0 )
{
QgsDebugMsg( "Entered" );
}

QgsRasterProjector::QgsRasterProjector()
: QgsRasterInterface( 0 )
, pHelperTop( 0 ), pHelperBottom( 0 )
{
QgsDebugMsg( "Entered" );
}

QgsRasterProjector::~QgsRasterProjector()
{
delete[] pHelperTop;
delete[] pHelperBottom;
}

int QgsRasterProjector::bandCount() const
{
if ( mInput ) return mInput->bandCount();

return 0;
}

QgsRasterInterface::DataType QgsRasterProjector::dataType( int bandNo ) const
{
if ( mInput ) return mInput->dataType( bandNo );

return QgsRasterInterface::UnknownDataType;
}

void QgsRasterProjector::setCRS( QgsCoordinateReferenceSystem theSrcCRS, QgsCoordinateReferenceSystem theDestCRS )
{
mSrcCRS = theSrcCRS;
mDestCRS = theDestCRS;
mCoordinateTransform.setSourceCrs( theDestCRS );
mCoordinateTransform.setDestCRS( theSrcCRS );
}

void QgsRasterProjector::calc()
{
QgsDebugMsg( "Entered" );
mCPMatrix.clear();
delete[] pHelperTop;
pHelperTop = 0;
delete[] pHelperBottom;
pHelperBottom = 0;

// Get max source resolution if possible
if ( mInput )
{
QgsRasterDataProvider *provider = dynamic_cast<QgsRasterDataProvider*>( mInput->srcInput() );
if ( provider && ( provider->capabilities() & QgsRasterDataProvider::ExactResolution ) )
{
mMaxSrcXRes = provider->extent().width() / provider->xSize();
mMaxSrcYRes = provider->extent().height() / provider->ySize();
}
}

mDestXRes = mDestExtent.width() / ( mDestCols );
mDestYRes = mDestExtent.height() / ( mDestRows );

Expand Down Expand Up @@ -88,13 +165,13 @@ QgsRasterProjector::QgsRasterProjector(
mApproximate = false;
break;
}

}
QgsDebugMsg( QString( "CPMatrix size: mCPRows = %1 mCPCols = %2" ).arg( mCPRows ).arg( mCPCols ) );
mDestRowsPerMatrixRow = ( float )mDestRows / ( mCPRows - 1 );
mDestColsPerMatrixCol = ( float )mDestCols / ( mCPCols - 1 );

//QgsDebugMsg( "CPMatrix:\n" + cpToString() );
QgsDebugMsgLevel( "CPMatrix:", 5 );
QgsDebugMsgLevel( cpToString(), 5 );

// Calculate source dimensions
calcSrcExtent();
Expand All @@ -110,11 +187,6 @@ QgsRasterProjector::QgsRasterProjector(
mHelperTopRow = 0;
}

QgsRasterProjector::~QgsRasterProjector()
{
//delete mCoordinateTransform;
}

void QgsRasterProjector::calcSrcExtent()
{
/* Run around the mCPMatrix and find source extent */
Expand Down Expand Up @@ -287,6 +359,7 @@ void QgsRasterProjector::calcHelper( int theMatrixRow, QgsPoint *thePoints )
}
void QgsRasterProjector::nextHelper()
{
// We just switch pHelperTop and pHelperBottom, memory is not lost
QgsPoint *tmp;
tmp = pHelperTop;
pHelperTop = pHelperBottom;
Expand All @@ -304,23 +377,33 @@ void QgsRasterProjector::srcRowCol( int theDestRow, int theDestCol, int *theSrcR

void QgsRasterProjector::preciseSrcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol )
{
//QgsDebugMsg( QString( "theDestRow = %1" ).arg(theDestRow) );
//QgsDebugMsg( QString( "theDestRow = %1 mDestExtent.yMaximum() = %2 mDestYRes = %3" ).arg(theDestRow).arg(mDestExtent.yMaximum()).arg(mDestYRes) );
#ifdef QGISDEBUG
QgsDebugMsgLevel( QString( "theDestRow = %1" ).arg( theDestRow ), 5 );
QgsDebugMsgLevel( QString( "theDestRow = %1 mDestExtent.yMaximum() = %2 mDestYRes = %3" ).arg( theDestRow ).arg( mDestExtent.yMaximum() ).arg( mDestYRes ), 5 );
#endif

// Get coordinate of center of destination cell
double x = mDestExtent.xMinimum() + ( theDestCol + 0.5 ) * mDestXRes;
double y = mDestExtent.yMaximum() - ( theDestRow + 0.5 ) * mDestYRes;
double z = 0;

//QgsDebugMsg( QString( "x = %1 y = %2" ).arg(x).arg(y) );
#ifdef QGISDEBUG
QgsDebugMsgLevel( QString( "x = %1 y = %2" ).arg( x ).arg( y ), 5 );
#endif

mCoordinateTransform.transformInPlace( x, y, z );
//QgsDebugMsg( QString( "x = %1 y = %2" ).arg(x).arg(y) );

#ifdef QGISDEBUG
QgsDebugMsgLevel( QString( "x = %1 y = %2" ).arg( x ).arg( y ), 5 );
#endif

// Get source row col
*theSrcRow = ( int ) floor(( mSrcExtent.yMaximum() - y ) / mSrcYRes );
*theSrcCol = ( int ) floor(( x - mSrcExtent.xMinimum() ) / mSrcXRes );
//QgsDebugMsg( QString( "mSrcExtent.yMaximum() = %1 mSrcYRes = %2" ).arg(mSrcExtent.yMaximum()).arg(mSrcYRes) );
//QgsDebugMsg( QString( "theSrcRow = %1 theSrcCol = %2" ).arg(*theSrcRow).arg(*theSrcCol) );
#ifdef QGISDEBUG
QgsDebugMsgLevel( QString( "mSrcExtent.yMaximum() = %1 mSrcYRes = %2" ).arg( mSrcExtent.yMaximum() ).arg( mSrcYRes ), 5 );
QgsDebugMsgLevel( QString( "theSrcRow = %1 theSrcCol = %2" ).arg( *theSrcRow ).arg( *theSrcCol ), 5 );
#endif

// With epsg 32661 (Polar Stereographic) it was happening that *theSrcCol == mSrcCols
// For now silently correct limits to avoid crashes
Expand Down Expand Up @@ -508,3 +591,63 @@ bool QgsRasterProjector::checkRows()
}
return true;
}

void * QgsRasterProjector::readBlock( int bandNo, QgsRectangle const & extent, int width, int height )
{
QgsDebugMsg( QString( "extent:\n%1" ).arg( extent.toString() ) );
QgsDebugMsg( QString( "width = %1 height = %1" ).arg( width ).arg( height ) );
if ( !mInput ) return 0;

if ( ! mSrcCRS.isValid() || ! mDestCRS.isValid() || mSrcCRS == mDestCRS )
{
QgsDebugMsg( "No projection necessary" );
return mInput->block( bandNo, extent, width, height );
}

mDestExtent = extent;
mDestRows = height;
mDestCols = width;
calc();

QgsDebugMsg( QString( "srcExtent:\n%1" ).arg( srcExtent().toString() ) );
QgsDebugMsg( QString( "srcCols = %1 srcRows = %1" ).arg( srcCols() ).arg( srcRows() ) );

// If we zoom out too much, projector srcRows / srcCols maybe 0, which can cause problems in providers
if ( srcRows() <= 0 || srcCols() <= 0 )
{
return 0;
}

void * inputData = mInput->block( bandNo, srcExtent(), srcCols(), srcRows() );

if ( !inputData ) return 0;

// ARGB32 only for now
int pixelSize = 4;

int inputSize = pixelSize * srcCols() * srcRows();

int outputSize = width * height * pixelSize;
void * outputData = malloc( outputSize );

// TODO: fill by transparent

int srcRow, srcCol;
for ( int i = 0; i < height; ++i )
{
for ( int j = 0; j < width; ++j )
{
srcRowCol( i, j, &srcRow, &srcCol );
int srcIndex = pixelSize * ( srcRow * mSrcCols + srcCol );
int destIndex = pixelSize * ( i * width + j );

if ( srcIndex >= inputSize || destIndex >= outputSize ) continue; // should not happen

memcpy(( char* )outputData + destIndex, ( char* )inputData + srcIndex, pixelSize );
}
}

free( inputData );

return outputData;
}
34 changes: 27 additions & 7 deletions src/core/qgsrasterprojector.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,17 @@
#include <QVector>
#include <QList>


#include "qgsrectangle.h"
#include "qgscoordinatereferencesystem.h"
#include "qgscoordinatetransform.h"
#include "qgsrasterinterface.h"

#include <cmath>

//class QgsRectangle;
class QgsPoint;

//class CORE_EXPORT QgsRasterProjector
class QgsRasterProjector
class CORE_EXPORT QgsRasterProjector : public QgsRasterInterface
{
// Q_OBJECT
public:
/** \brief QgsRasterProjector implements approximate projection support for
* it calculates grid of points in source CRS for target CRS + extent
Expand All @@ -53,10 +50,29 @@ class QgsRasterProjector
double theMaxSrcXRes, double theMaxSrcYRes,
QgsRectangle theExtent
);
QgsRasterProjector(
QgsCoordinateReferenceSystem theSrcCRS,
QgsCoordinateReferenceSystem theDestCRS,
double theMaxSrcXRes, double theMaxSrcYRes,
QgsRectangle theExtent
);
QgsRasterProjector();

/** \brief The destructor */
~QgsRasterProjector();

int bandCount() const;

QgsRasterInterface::DataType dataType( int bandNo ) const;

/** \brief set source and destination CRS */
void setCRS( QgsCoordinateReferenceSystem theSrcCRS, QgsCoordinateReferenceSystem theDestCRS );

/** \brief set maximum source resolution */
void setMaxSrcRes( double theMaxSrcXRes, double theMaxSrcYRes )
{
mMaxSrcXRes = theMaxSrcXRes; mMaxSrcYRes = theMaxSrcYRes;
}

/** \brief get destination point for _current_ destination position */
void destPointOnCPMatrix( int theRow, int theCol, double *theX, double *theY );
Expand All @@ -77,6 +93,9 @@ class QgsRasterProjector
/** \brief Get source row and column indexes for current source extent and resolution */
void srcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol );

/** \brief Calculate matrix */
void calc();

/** \brief insert rows to matrix */
void insertRows();

Expand Down Expand Up @@ -107,7 +126,6 @@ class QgsRasterProjector
bool checkRows();

/** Calculate array of src helper points */
//void calcHelper ( int theMatrixRow, QList<QgsPoint> *thePoints );
void calcHelper( int theMatrixRow, QgsPoint *thePoints );

/** Calc / switch helper */
Expand All @@ -128,14 +146,16 @@ class QgsRasterProjector
int dstRows() const { return mDestRows; }
int dstCols() const { return mDestCols; }

void * readBlock( int bandNo, QgsRectangle const & extent, int width, int height );

private:
/** Source CRS */
QgsCoordinateReferenceSystem mSrcCRS;

/** Destination CRS */
QgsCoordinateReferenceSystem mDestCRS;

/** Coordinate transform */
/** Reverse coordinate transform (from destination to source) */
QgsCoordinateTransform mCoordinateTransform;

/** Destination extent */
Expand Down
2 changes: 1 addition & 1 deletion src/core/raster/qgsbilinearrasterresampler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ QgsBilinearRasterResampler::~QgsBilinearRasterResampler()

void QgsBilinearRasterResampler::resample( const QImage& srcImage, QImage& dstImage )
{
dstImage = srcImage.scaled( dstImage.width(), dstImage.height(), Qt::KeepAspectRatio, Qt::SmoothTransformation );
dstImage = srcImage.scaled( dstImage.width(), dstImage.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
}
290 changes: 136 additions & 154 deletions src/core/raster/qgsmultibandcolorrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@
#include <QImage>
#include <QSet>

QgsMultiBandColorRenderer::QgsMultiBandColorRenderer( QgsRasterDataProvider* provider, int redBand, int greenBand, int blueBand,
QgsMultiBandColorRenderer::QgsMultiBandColorRenderer( QgsRasterInterface* input, int redBand, int greenBand, int blueBand,
QgsContrastEnhancement* redEnhancement,
QgsContrastEnhancement* greenEnhancement,
QgsContrastEnhancement* blueEnhancement ):
QgsRasterRenderer( provider, "multibandcolor" ), mRedBand( redBand ), mGreenBand( greenBand ), mBlueBand( blueBand ),
QgsRasterRenderer( input, "multibandcolor" ), mRedBand( redBand ), mGreenBand( greenBand ), mBlueBand( blueBand ),
mRedContrastEnhancement( redEnhancement ), mGreenContrastEnhancement( greenEnhancement ), mBlueContrastEnhancement( blueEnhancement )
{
}
Expand All @@ -55,7 +55,7 @@ void QgsMultiBandColorRenderer::setBlueContrastEnhancement( QgsContrastEnhanceme
delete mBlueContrastEnhancement; mBlueContrastEnhancement = ce;
}

QgsRasterRenderer* QgsMultiBandColorRenderer::create( const QDomElement& elem, QgsRasterDataProvider* provider )
QgsRasterRenderer* QgsMultiBandColorRenderer::create( const QDomElement& elem, QgsRasterInterface* input )
{
if ( elem.isNull() )
{
Expand All @@ -73,7 +73,7 @@ QgsRasterRenderer* QgsMultiBandColorRenderer::create( const QDomElement& elem, Q
if ( !redContrastElem.isNull() )
{
redContrastEnhancement = new QgsContrastEnhancement(( QgsContrastEnhancement::QgsRasterDataType )(
provider->dataType( redBand ) ) );
input->dataType( redBand ) ) );
redContrastEnhancement->readXML( redContrastElem );
}

Expand All @@ -82,7 +82,7 @@ QgsRasterRenderer* QgsMultiBandColorRenderer::create( const QDomElement& elem, Q
if ( !greenContrastElem.isNull() )
{
greenContrastEnhancement = new QgsContrastEnhancement(( QgsContrastEnhancement::QgsRasterDataType )(
provider->dataType( greenBand ) ) );
input->dataType( greenBand ) ) );
greenContrastEnhancement->readXML( greenContrastElem );
}

Expand All @@ -91,49 +91,49 @@ QgsRasterRenderer* QgsMultiBandColorRenderer::create( const QDomElement& elem, Q
if ( !blueContrastElem.isNull() )
{
blueContrastEnhancement = new QgsContrastEnhancement(( QgsContrastEnhancement::QgsRasterDataType )(
provider->dataType( blueBand ) ) );
input->dataType( blueBand ) ) );
blueContrastEnhancement->readXML( blueContrastElem );
}

QgsRasterRenderer* r = new QgsMultiBandColorRenderer( provider, redBand, greenBand, blueBand, redContrastEnhancement,
QgsRasterRenderer* r = new QgsMultiBandColorRenderer( input, redBand, greenBand, blueBand, redContrastEnhancement,
greenContrastEnhancement, blueContrastEnhancement );
r->readXML( elem );
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 ( !p || !mProvider || !viewPort || !theQgsMapToPixel )
if ( !mInput )
{
return;
return 0;
}

//In some (common) cases, we can simplify the drawing loop considerably and save render time
bool fastDraw = (
!usesTransparency( viewPort->mSrcCRS, viewPort->mDestCRS )
bool fastDraw = ( !usesTransparency()
&& mRedBand > 0 && mGreenBand > 0 && mBlueBand > 0
&& mAlphaBand < 1 && !mRedContrastEnhancement && !mGreenContrastEnhancement && !mBlueContrastEnhancement
&& !mInvertColor );

QgsRasterDataProvider::DataType redType = QgsRasterDataProvider::UnknownDataType;
QgsRasterInterface::DataType redType = QgsRasterInterface::UnknownDataType;

if ( mRedBand > 0 )
{
redType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mRedBand );
redType = ( QgsRasterInterface::DataType )mInput->dataType( mRedBand );
}
QgsRasterDataProvider::DataType greenType = QgsRasterDataProvider::UnknownDataType;
QgsRasterInterface::DataType greenType = QgsRasterInterface::UnknownDataType;
if ( mGreenBand > 0 )
{
greenType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mGreenBand );
greenType = ( QgsRasterInterface::DataType )mInput->dataType( mGreenBand );
}
QgsRasterDataProvider::DataType blueType = QgsRasterDataProvider::UnknownDataType;
QgsRasterInterface::DataType blueType = QgsRasterInterface::UnknownDataType;
if ( mBlueBand > 0 )
{
blueType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mBlueBand );
blueType = ( QgsRasterInterface::DataType )mInput->dataType( mBlueBand );
}
QgsRasterDataProvider::DataType transparencyType = QgsRasterDataProvider::UnknownDataType;
QgsRasterInterface::DataType transparencyType = QgsRasterInterface::UnknownDataType;
if ( mAlphaBand > 0 )
{
transparencyType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mAlphaBand );
transparencyType = ( QgsRasterInterface::DataType )mInput->dataType( mAlphaBand );
}

double oversamplingX = 1.0, oversamplingY = 1.0;
Expand All @@ -152,7 +152,7 @@ void QgsMultiBandColorRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort,
}
if ( bands.size() < 1 )
{
return; //no need to draw anything if no band is set
return 0; //no need to draw anything if no band is set
}

if ( mAlphaBand > 0 )
Expand All @@ -166,161 +166,143 @@ void QgsMultiBandColorRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort,
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;
while ( true )

bandIt = bands.constBegin();
for ( ; bandIt != bands.constEnd(); ++bandIt )
{
QSet<int>::const_iterator 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->block( *bandIt, extent, width, height );
if ( !bandData[*bandIt] ) return 0;
}

if ( !readSuccess )
{
break;
}
if ( mRedBand > 0 )
{
redData = bandData[mRedBand];
}
if ( mGreenBand > 0 )
{
greenData = bandData[mGreenBand];
}
if ( mBlueBand > 0 )
{
blueData = bandData[mBlueBand];
}
if ( mAlphaBand > 0 )
{
alphaData = bandData[mAlphaBand];
}

if ( mRedBand > 0 )
{
redData = bandData[mRedBand];
}
if ( mGreenBand > 0 )
{
greenData = bandData[mGreenBand];
}
if ( mBlueBand > 0 )
{
blueData = bandData[mBlueBand];
}
if ( mAlphaBand > 0 )
QImage img( width, height, QImage::Format_ARGB32_Premultiplied );
QRgb* imageScanLine = 0;
int currentRasterPos = 0;
int redVal = 0;
int greenVal = 0;
int blueVal = 0;
int redDataVal = 0;
int greenDataVal = 0;
int blueDataVal = 0;
QRgb defaultColor = qRgba( 255, 255, 255, 0 );
double currentOpacity = mOpacity; //opacity (between 0 and 1)

for ( int i = 0; i < height; ++i )
{
imageScanLine = ( QRgb* )( img.scanLine( i ) );
for ( int j = 0; j < width; ++j )
{
alphaData = bandData[mAlphaBand];
}
if ( fastDraw ) //fast rendering if no transparency, stretching, color inversion, etc.
{
redVal = readValue( redData, redType, currentRasterPos );
greenVal = readValue( greenData, greenType, currentRasterPos );
blueVal = readValue( blueData, blueType, currentRasterPos );
imageScanLine[j] = qRgba( redVal, greenVal, blueVal, 255 );
++currentRasterPos;
continue;
}

QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied );
QRgb* imageScanLine = 0;
int currentRasterPos = 0;
int redVal = 0;
int greenVal = 0;
int blueVal = 0;
int redDataVal = 0;
int greenDataVal = 0;
int blueDataVal = 0;
QRgb defaultColor = qRgba( 255, 255, 255, 0 );
double currentOpacity = mOpacity; //opacity (between 0 and 1)

for ( int i = 0; i < nRasterRows; ++i )
{
imageScanLine = ( QRgb* )( img.scanLine( i ) );
for ( int j = 0; j < nRasterCols; ++j )
if ( mRedBand > 0 )
{
redVal = readValue( redData, redType, currentRasterPos );
redDataVal = redVal;
}
if ( mGreenBand > 0 )
{
greenVal = readValue( greenData, greenType, currentRasterPos );
greenDataVal = greenVal;
}
if ( mBlueBand > 0 )
{
blueVal = readValue( blueData, blueType, currentRasterPos );
blueDataVal = blueVal;
}

if ( fastDraw ) //fast rendering if no transparency, stretching, color inversion, etc.
{
redVal = readValue( redData, redType, currentRasterPos );
greenVal = readValue( greenData, greenType, currentRasterPos );
blueVal = readValue( blueData, blueType, currentRasterPos );
imageScanLine[j] = qRgba( redVal, greenVal, blueVal, 255 );
++currentRasterPos;
continue;
}

if ( mRedBand > 0 )
{
redVal = readValue( redData, redType, currentRasterPos );
redDataVal = redVal;
}
if ( mGreenBand > 0 )
{
greenVal = readValue( greenData, greenType, currentRasterPos );
greenDataVal = greenVal;
}
if ( mBlueBand > 0 )
{
blueVal = readValue( blueData, blueType, currentRasterPos );
blueDataVal = blueVal;
}

//apply default color if red, green or blue not in displayable range
if (( mRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( redVal ) )
|| ( mGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( redVal ) )
|| ( mBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( redVal ) ) )
{
imageScanLine[j] = defaultColor;
++currentRasterPos;
continue;
}

//stretch color values
if ( mRedContrastEnhancement )
{
redVal = mRedContrastEnhancement->enhanceContrast( redVal );
}
if ( mGreenContrastEnhancement )
{
greenVal = mGreenContrastEnhancement->enhanceContrast( greenVal );
}
if ( mBlueContrastEnhancement )
{
blueVal = mBlueContrastEnhancement->enhanceContrast( blueVal );
}

if ( mInvertColor )
{
redVal = 255 - redVal;
greenVal = 255 - greenVal;
blueVal = 255 - blueVal;
}

//opacity
currentOpacity = mOpacity;
if ( mRasterTransparency )
{
currentOpacity = mRasterTransparency->alphaValue( redDataVal, greenDataVal, blueDataVal, mOpacity * 255 ) / 255.0;
}
if ( mAlphaBand > 0 )
{
currentOpacity *= ( readValue( alphaData, transparencyType, currentRasterPos ) / 255.0 );
}

if ( doubleNear( currentOpacity, 1.0 ) )
{
imageScanLine[j] = qRgba( redVal, greenVal, blueVal, 255 );
}
else
{
imageScanLine[j] = qRgba( currentOpacity * redVal, currentOpacity * greenVal, currentOpacity * blueVal, currentOpacity * 255 );
}
//apply default color if red, green or blue not in displayable range
if (( mRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( redVal ) )
|| ( mGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( redVal ) )
|| ( mBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( redVal ) ) )
{
imageScanLine[j] = defaultColor;
++currentRasterPos;
continue;
}

//stretch color values
if ( mRedContrastEnhancement )
{
redVal = mRedContrastEnhancement->enhanceContrast( redVal );
}
if ( mGreenContrastEnhancement )
{
greenVal = mGreenContrastEnhancement->enhanceContrast( greenVal );
}
if ( mBlueContrastEnhancement )
{
blueVal = mBlueContrastEnhancement->enhanceContrast( blueVal );
}

if ( mInvertColor )
{
redVal = 255 - redVal;
greenVal = 255 - greenVal;
blueVal = 255 - blueVal;
}

//opacity
currentOpacity = mOpacity;
if ( mRasterTransparency )
{
currentOpacity = mRasterTransparency->alphaValue( redVal, greenVal, blueVal, mOpacity * 255 ) / 255.0;
}
if ( mAlphaBand > 0 )
{
currentOpacity *= ( readValue( alphaData, transparencyType, currentRasterPos ) / 255.0 );
}

if ( doubleNear( currentOpacity, 1.0 ) )
{
imageScanLine[j] = qRgba( redVal, greenVal, blueVal, 255 );
}
else
{
imageScanLine[j] = qRgba( currentOpacity * redVal, currentOpacity * greenVal, currentOpacity * blueVal, currentOpacity * 255 );
}
}

drawImage( p, viewPort, img, topLeftCol, topLeftRow, nCols, nRows, oversamplingX, oversamplingY );
++currentRasterPos;
}
}

bandIt = bands.constBegin();
for ( ; bandIt != bands.constEnd(); ++bandIt )
{
stopRasterRead( *bandIt );
VSIFree( bandData[*bandIt] );
}

void * data = VSIMalloc( img.byteCount() );
return memcpy( data, img.bits(), img.byteCount() );
}

void QgsMultiBandColorRenderer::writeXML( QDomDocument& doc, QDomElement& parentElem ) const
Expand Down
6 changes: 3 additions & 3 deletions src/core/raster/qgsmultibandcolorrenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ class QDomElement;
class CORE_EXPORT QgsMultiBandColorRenderer: public QgsRasterRenderer
{
public:
QgsMultiBandColorRenderer( QgsRasterDataProvider* provider, int redBand, int greenBand, int blueBand,
QgsMultiBandColorRenderer( QgsRasterInterface* input, int redBand, int greenBand, int blueBand,
QgsContrastEnhancement* redEnhancement = 0, QgsContrastEnhancement* greenEnhancement = 0,
QgsContrastEnhancement* blueEnhancement = 0 );
~QgsMultiBandColorRenderer();

static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterDataProvider* provider );
static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterInterface* input );

void draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel );
void * readBlock( int bandNo, QgsRectangle const & extent, int width, int height );

int redBand() const { return mRedBand; }
void setRedBand( int band ) { mRedBand = band; }
Expand Down
132 changes: 52 additions & 80 deletions src/core/raster/qgspalettedrasterrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
#include <QDomElement>
#include <QImage>

QgsPalettedRasterRenderer::QgsPalettedRasterRenderer( QgsRasterDataProvider* provider, int bandNumber,
QgsPalettedRasterRenderer::QgsPalettedRasterRenderer( QgsRasterInterface* input, int bandNumber,
QColor* colorArray, int nColors ):
QgsRasterRenderer( provider, "paletted" ), mBandNumber( bandNumber ), mColors( colorArray ), mNColors( nColors )
QgsRasterRenderer( input, "paletted" ), mBandNumber( bandNumber ), mColors( colorArray ), mNColors( nColors )
{
}

Expand All @@ -34,7 +34,7 @@ QgsPalettedRasterRenderer::~QgsPalettedRasterRenderer()
delete[] mColors;
}

QgsRasterRenderer* QgsPalettedRasterRenderer::create( const QDomElement& elem, QgsRasterDataProvider* provider )
QgsRasterRenderer* QgsPalettedRasterRenderer::create( const QDomElement& elem, QgsRasterInterface* input )
{
if ( elem.isNull() )
{
Expand Down Expand Up @@ -62,7 +62,7 @@ QgsRasterRenderer* QgsPalettedRasterRenderer::create( const QDomElement& elem, Q
colors[value] = QColor( entryElem.attribute( "color", "#000000" ) );
}
}
QgsRasterRenderer* r = new QgsPalettedRasterRenderer( provider, bandNumber, colors, nColors );
QgsRasterRenderer* r = new QgsPalettedRasterRenderer( input, bandNumber, colors, nColors );
r->readXML( elem );
return r;
}
Expand All @@ -81,109 +81,81 @@ 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 ( !p || !mProvider || !viewPort || !theQgsMapToPixel )
if ( !mInput )
{
return;
return 0;
}

double oversamplingX, oversamplingY;
QgsRasterDataProvider::DataType transparencyType = QgsRasterDataProvider::UnknownDataType;
QgsRasterInterface::DataType transparencyType = QgsRasterInterface::UnknownDataType;
if ( mAlphaBand > 0 )
{
transparencyType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mAlphaBand );
transparencyType = ( QgsRasterInterface::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;
QgsRasterDataProvider::DataType rasterType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mBandNumber );
void* rasterData;
QgsRasterInterface::DataType rasterType = ( QgsRasterInterface::DataType )mInput->dataType( mBandNumber );
void* rasterData = mInput->block( bandNo, extent, width, height );
double currentOpacity = mOpacity;

//rendering is faster without considering user-defined transparency
bool hasTransparency = usesTransparency( viewPort->mSrcCRS, viewPort->mDestCRS );
bool hasTransparency = usesTransparency();
void* transparencyData = 0;

while ( readNextRasterPart( mBandNumber, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows,
&rasterData, topLeftCol, topLeftRow ) )
if ( mAlphaBand > 0 && mAlphaBand != mBandNumber )
{
if ( mAlphaBand > 0 && mAlphaBand != mBandNumber )
{
readNextRasterPart( mAlphaBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows,
&transparencyData, topLeftCol, topLeftRow );
}
else if ( mAlphaBand == mBandNumber )
{
transparencyData = rasterData;
}
transparencyData = mInput->block( mAlphaBand, extent, width, height );
}
else if ( mAlphaBand == mBandNumber )
{
transparencyData = rasterData;
}

//create image
QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied );
QRgb* imageScanLine = 0;
int val = 0;
currentRasterPos = 0;
//create image
QImage img( width, height, QImage::Format_ARGB32_Premultiplied );
QRgb* imageScanLine = 0;
int val = 0;
int currentRasterPos = 0;

for ( int i = 0; i < nRasterRows; ++i )
for ( int i = 0; i < height; ++i )
{
imageScanLine = ( QRgb* )( img.scanLine( i ) );
for ( int j = 0; j < width; ++j )
{
imageScanLine = ( QRgb* )( img.scanLine( i ) );
for ( int j = 0; j < nRasterCols; ++j )
val = readValue( rasterData, rasterType, currentRasterPos );
if ( !hasTransparency )
{
val = readValue( rasterData, rasterType, currentRasterPos );
if ( !hasTransparency )
imageScanLine[j] = mColors[ val ].rgba();
}
else
{
currentOpacity = mOpacity;
if ( mRasterTransparency )
{
currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0;
}
if ( mAlphaBand > 0 )
{
imageScanLine[j] = mColors[ val ].rgba();
currentOpacity *= ( readValue( transparencyData, transparencyType, currentRasterPos ) / 255.0 );
}
QColor& currentColor = mColors[val];

if ( mInvertColor )
{
imageScanLine[j] = qRgba( currentOpacity * currentColor.blue(), currentOpacity * currentColor.green(), currentOpacity * currentColor.red(), currentOpacity * 255 );
}
else
{
currentOpacity = mOpacity;
if ( mRasterTransparency )
{
currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0;
}
if ( mAlphaBand > 0 )
{
currentOpacity *= ( readValue( transparencyData, transparencyType, currentRasterPos ) / 255.0 );
}
QColor& currentColor = mColors[val];

if ( mInvertColor )
{
imageScanLine[j] = qRgba( currentOpacity * currentColor.blue(), currentOpacity * currentColor.green(), currentOpacity * currentColor.red(), currentOpacity * 255 );
}
else
{
imageScanLine[j] = qRgba( currentOpacity * currentColor.red(), currentOpacity * currentColor.green(), currentOpacity * currentColor.blue(), currentOpacity * 255 );
}
imageScanLine[j] = qRgba( currentOpacity * currentColor.red(), currentOpacity * currentColor.green(), currentOpacity * currentColor.blue(), currentOpacity * 255 );
}
++currentRasterPos;
}
++currentRasterPos;
}

drawImage( p, viewPort, img, topLeftCol, topLeftRow, nCols, nRows, oversamplingX, oversamplingY );
}

//stop raster reading
stopRasterRead( mBandNumber );
if ( mAlphaBand > 0 && mAlphaBand != mBandNumber )
{
stopRasterRead( mAlphaBand );
}
VSIFree( rasterData );
void * data = VSIMalloc( img.byteCount() );
return memcpy( data, img.bits(), img.byteCount() );
}

void QgsPalettedRasterRenderer::writeXML( QDomDocument& doc, QDomElement& parentElem ) const
Expand Down
6 changes: 4 additions & 2 deletions src/core/raster/qgspalettedrasterrenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ class CORE_EXPORT QgsPalettedRasterRenderer: public QgsRasterRenderer
{
public:
/**Renderer owns color array*/
QgsPalettedRasterRenderer( QgsRasterDataProvider* provider, int bandNumber, QColor* colorArray, int nColors );
QgsPalettedRasterRenderer( QgsRasterInterface* input, int bandNumber, QColor* colorArray, int nColors );
~QgsPalettedRasterRenderer();
static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterDataProvider* provider );
static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterInterface* input );

void draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel );

void * readBlock( int bandNo, QgsRectangle const & extent, int width, int height );

/**Returns number of colors*/
int nColors() const { return mNColors; }
/**Returns copy of color array (caller takes ownership)*/
Expand Down
89 changes: 89 additions & 0 deletions src/core/raster/qgsrasterdrawer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/***************************************************************************
qgsrasterdrawer.cpp
---------------------
begin : June 2012
copyright : (C) 2012 by Radim Blazek
email : radim dot blazek at gmail.com
***************************************************************************/

/***************************************************************************
* *
* 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 "qgslogger.h"
#include "qgsrasterdrawer.h"
#include "qgsrasteriterator.h"
#include "qgsrasterviewport.h"
#include "qgsmaptopixel.h"
#include <QImage>
#include <QPainter>

QgsRasterDrawer::QgsRasterDrawer( QgsRasterIterator* iterator ): mIterator( iterator )
{
}

QgsRasterDrawer::~QgsRasterDrawer()
{
}

void QgsRasterDrawer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel )
{
QgsDebugMsg( "Entered" );
if ( !p || !mIterator || !viewPort || !theQgsMapToPixel )
{
return;
}

// last pipe filter has only 1 band
int bandNumber = 1;
mIterator->startRasterRead( bandNumber, viewPort->drawableAreaXDim, viewPort->drawableAreaYDim, viewPort->mDrawnExtent );

//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;

// We know that the output data type of last pipe filter is QImage data
//QgsRasterDataProvider::DataType rasterType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mGrayBand );

void* rasterData;

// readNextRasterPart calcs and resets nCols, nRows, topLeftCol, topLeftRow
while ( mIterator->readNextRasterPart( bandNumber, nCols, nRows,
&rasterData, topLeftCol, topLeftRow ) )
{
//create image
//QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied );

// TODO: the exact format should be read from input
QImage img(( uchar * ) rasterData, nCols, nRows, QImage::Format_ARGB32_Premultiplied );
drawImage( p, viewPort, img, topLeftCol, topLeftRow );

// QImage does not delete data block passed to constructor
free( rasterData );
}
}

void QgsRasterDrawer::drawImage( QPainter* p, QgsRasterViewPort* viewPort, const QImage& img, int topLeftCol, int topLeftRow ) const
{
if ( !p || !viewPort )
{
return;
}

//top left position in device coords
QPoint tlPoint = QPoint( viewPort->topLeftPoint.x() + topLeftCol, viewPort->topLeftPoint.y() + topLeftRow );

p->drawImage( tlPoint, img );
}

48 changes: 48 additions & 0 deletions src/core/raster/qgsrasterdrawer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/***************************************************************************
qgsrasterdrawer.h
-------------------
begin : June 2012
copyright : (C) 2012 by Radim Blazek
email : radim dot blazek at gmail.com
***************************************************************************/

/***************************************************************************
* *
* 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 QGSRASTERDRAWER_H
#define QGSRASTERDRAWER_H

#include "qgsrasterinterface.h"
#include <QMap>

class QPainter;
class QImage;
class QgsMapToPixel;
class QgsRasterViewPort;
class QgsRasterIterator;

class QgsRasterDrawer
{
public:
QgsRasterDrawer( QgsRasterIterator* iterator );
~QgsRasterDrawer();

void draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel );

protected:
/**Draws raster part
@param topLeftCol Left position relative to left border of viewport
@param topLeftRow Top position relative to top border of viewport*/
void drawImage( QPainter* p, QgsRasterViewPort* viewPort, const QImage& img, int topLeftCol, int topLeftRow ) const;

private:
QgsRasterIterator* mIterator;
};

#endif // QGSRASTERDRAWER_H
544 changes: 544 additions & 0 deletions src/core/raster/qgsrasterfilewriter.cpp

Large diffs are not rendered by default.

104 changes: 104 additions & 0 deletions src/core/raster/qgsrasterfilewriter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#ifndef QGSRASTERFILEWRITER_H
#define QGSRASTERFILEWRITER_H

#include "qgscoordinatereferencesystem.h"
#include "qgsrasterdataprovider.h"
#include "qgsrectangle.h"
#include <QDomDocument>
#include <QDomElement>
#include <QString>

class QProgressDialog;
class QgsRasterIterator;

class CORE_EXPORT QgsRasterFileWriter
{
public:
enum WriterError
{
NoError = 0,
SourceProviderError = 1,
DestProviderError = 2,
CreateDatasourceError = 3,
WriteError = 4
};

QgsRasterFileWriter( const QString& outputUrl );
~QgsRasterFileWriter();

/**Write raster file
@param nCols number of output columns
@param nRows number of output rows (or -1 to automatically calculate row number to have square pixels)*/
WriterError writeRaster( QgsRasterIterator* iter, int nCols, int nRows, QgsRectangle outputExtent,
const QgsCoordinateReferenceSystem& crs, QProgressDialog* p = 0 );

void setOutputFormat( const QString& format ) { mOutputFormat = format; }
QString outputFormat() const { return mOutputFormat; }

void setOutputProviderKey( const QString& key ) { mOutputProviderKey = key; }
QString outputProviderKey() const { return mOutputProviderKey; }

void setTiledMode( bool t ) { mTiledMode = t; }
bool tiledMode() const { return mTiledMode; }

void setMaxTileWidth( int w ) { mMaxTileWidth = w; }
int maxTileWidth() const { return mMaxTileWidth; }

void setMaxTileHeight( int h ) { mMaxTileHeight = h; }
int maxTileHeight() const { return mMaxTileHeight; }

// for now not putting createOptions in all methods, use createOptions()
void setCreateOptions( const QStringList& list ) { mCreateOptions = list; }
QStringList createOptions() const { return mCreateOptions; }

private:
QgsRasterFileWriter(); //forbidden
WriterError writeDataRaster( QgsRasterIterator* iter, int nCols, int nRows, const QgsRectangle& outputExtent,
const QgsCoordinateReferenceSystem& crs );
WriterError writeImageRaster( QgsRasterIterator* iter, int nCols, int nRows, const QgsRectangle& outputExtent,
const QgsCoordinateReferenceSystem& crs );

//initialize vrt member variables
void createVRT( int xSize, int ySize, const QgsCoordinateReferenceSystem& crs, double* geoTransform );
//write vrt document to disk
bool writeVRT( const QString& file );
//add file entry to vrt
void addToVRT( const QString& filename, int band, int xSize, int ySize, int xOffset, int yOffset );
void buildPyramids( const QString& filename );

static int pyramidsProgress( double dfComplete, const char *pszMessage, void* pData );

/**Create provider and datasource for a part image (vrt mode)*/
QgsRasterDataProvider* createPartProvider( const QgsRectangle& extent, int nCols, int iterCols, int iterRows,
int iterLeft, int iterTop,
const QString& outputUrl, int fileIndex, int nBands, QgsRasterInterface::DataType type,
const QgsCoordinateReferenceSystem& crs );

/**Init VRT (for tiled mode) or create global output provider (single-file mode)*/
QgsRasterDataProvider* initOutput( int nCols, int nRows, const QgsCoordinateReferenceSystem& crs, double* geoTransform, int nBands,
QgsRasterInterface::DataType type );

/**Calculate nRows, geotransform and pixel size for output*/
void globalOutputParameters( const QgsRectangle& extent, int nCols, int& nRows, double* geoTransform, double& pixelSize );

QString mOutputUrl;
QString mOutputProviderKey;
QString mOutputFormat;
QStringList mCreateOptions;
QgsCoordinateReferenceSystem mOutputCRS;

/**False: Write one file, true: create a directory and add the files numbered*/
bool mTiledMode;
double mMaxTileWidth;
double mMaxTileHeight;

QDomDocument mVRTDocument;
QDomElement mVRTRedBand;
QDomElement mVRTGreenBand;
QDomElement mVRTBlueBand;
QDomElement mVRTAlphaBand;

QProgressDialog* mProgressDialog;
};

#endif // QGSRASTERFILEWRITER_H
144 changes: 144 additions & 0 deletions src/core/raster/qgsrasterinterface.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/***************************************************************************
qgsrasterface.cpp - Internal raster processing modules interface
--------------------------------------
Date : Jun 21, 2012
Copyright : (C) 2012 by Radim Blazek
email : radim dot blazek at gmail dot com
***************************************************************************/

/***************************************************************************
* *
* 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 <typeinfo>

#include <QByteArray>
#include <QTime>

#include "qgslogger.h"
#include "qgsrasterinterface.h"

QgsRasterInterface::QgsRasterInterface( QgsRasterInterface * input )
: mInput( input )
, mOn( true )
, mStatsOn( false )
{
}

QgsRasterInterface::~QgsRasterInterface()
{
}

bool QgsRasterInterface::typeIsNumeric( DataType dataType ) const
{
switch ( dataType )
{
case Byte:
case UInt16:
case Int16:
case UInt32:
case Int32:
case Float32:
case CInt16:
case Float64:
case CInt32:
case CFloat32:
case CFloat64:
return true;
}
return false;
}

bool QgsRasterInterface::typeIsColor( DataType dataType ) const
{
switch ( dataType )
{
case ARGB32:
case ARGB32_Premultiplied:
return true;
}
return false;
}

// To give to an image preallocated memory is the only way to avoid memcpy
// when we want to keep data but delete QImage
QImage * QgsRasterInterface::createImage( int width, int height, QImage::Format format )
{
// Qt has its own internal function depthForFormat(), unfortunately it is not public

QImage img( 1, 1, format );

// We ignore QImage::Format_Mono and QImage::Format_MonoLSB ( depth 1)
int size = width * height * img.bytesPerLine();
uchar * data = ( uchar * ) malloc( size );
return new QImage( data, width, height, format );
}

void * QgsRasterInterface::block( int bandNo, QgsRectangle const & extent, int width, int height )
{
QTime time;
time.start();

void * b = 0;

if ( !mOn )
{
// Switched off, pass input data unchanged
if ( mInput )
{
b = mInput->block( bandNo, extent, width, height );
}
}
else
{
b = readBlock( bandNo, extent, width, height );
}

if ( mStatsOn )
{
if ( mTime.size() <= bandNo )
{
mTime.resize( bandNo + 1 );
}
// QTime counts only in miliseconds
// We are adding time until next clear, this way the time may be collected
// for the whole QgsRasterLayer::draw() for example, not just for a single part
mTime[bandNo] += time.elapsed();
QgsDebugMsg( QString( "bandNo = %2 time = %3" ).arg( bandNo ).arg( mTime[bandNo] ) );
}
return b;
}

void QgsRasterInterface::setStatsOn( bool on )
{
if ( on )
{
mTime.clear();
}
if ( mInput ) mInput->setStatsOn( on );
mStatsOn = on;
}

double QgsRasterInterface::time( bool cumulative )
{
// We can calculate total time only, because we have to subtract time of previous
// interface(s) and we dont know how to assign bands to each other
double t = 0;
for ( int i = 1; i < mTime.size(); i++ )
{
t += mTime[i];
}
if ( cumulative ) return t;

if ( mInput )
{
QgsDebugMsgLevel( QString( "%1 cumulative time = %2 time = %3" ).arg( typeid( *( this ) ).name() ).arg( t ).arg( t - mInput->time( true ) ), 3 );
t -= mInput->time( true );
}
return t;
}
188 changes: 188 additions & 0 deletions src/core/raster/qgsrasterinterface.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/***************************************************************************
qgsrasterface.h - Internal raster processing modules interface
--------------------------------------
Date : Jun 21, 2012
Copyright : (C) 2012 by Radim Blazek
email : radim dot blazek at gmail dot com
***************************************************************************/

/***************************************************************************
* *
* 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 QGSRASTERINTERFACE_H
#define QGSRASTERINTERFACE_H

#include <QImage>

#include "qgsrectangle.h"

/** \ingroup core
* Base class for processing modules.
*/
// TODO: inherit from QObject? It would be probably better but QgsDataProvider inherits already from QObject and multiple inheritance from QObject is not allowed
class CORE_EXPORT QgsRasterInterface
{
public:

/** Data types.
* This is modified and extended copy of GDALDataType.
*/
enum DataType
{
/*! Unknown or unspecified type */ UnknownDataType = 0,
/*! Eight bit unsigned integer */ Byte = 1,
/*! Sixteen bit unsigned integer */ UInt16 = 2,
/*! Sixteen bit signed integer */ Int16 = 3,
/*! Thirty two bit unsigned integer */ UInt32 = 4,
/*! Thirty two bit signed integer */ Int32 = 5,
/*! Thirty two bit floating point */ Float32 = 6,
/*! Sixty four bit floating point */ Float64 = 7,
/*! Complex Int16 */ CInt16 = 8,
/*! Complex Int32 */ CInt32 = 9,
/*! Complex Float32 */ CFloat32 = 10,
/*! Complex Float64 */ CFloat64 = 11,
/*! Color, alpha, red, green, blue, 4 bytes the same as
QImage::Format_ARGB32 */ ARGB32 = 12,
/*! Color, alpha, red, green, blue, 4 bytes the same as
QImage::Format_ARGB32_Premultiplied */ ARGB32_Premultiplied = 13,

TypeCount = 14 /* maximum type # + 1 */
};

QgsRasterInterface( QgsRasterInterface * input = 0 );

virtual ~QgsRasterInterface();

int typeSize( int dataType ) const
{
// Modified and extended copy from GDAL
switch ( dataType )
{
case Byte:
return 8;

case UInt16:
case Int16:
return 16;

case UInt32:
case Int32:
case Float32:
case CInt16:
return 32;

case Float64:
case CInt32:
case CFloat32:
return 64;

case CFloat64:
return 128;

case ARGB32:
case ARGB32_Premultiplied:
return 32;

default:
return 0;
}
}

int dataTypeSize( int bandNo ) const
{
return typeSize( dataType( bandNo ) );
}

/** Returns true if data type is numeric */
bool typeIsNumeric( DataType type ) const;

/** Returns true if data type is color */
bool typeIsColor( DataType type ) const;

/** Returns data type for the band specified by number */
virtual DataType dataType( int bandNo ) const
{
Q_UNUSED( bandNo );
return UnknownDataType;
}

/** Get number of bands */
virtual int bandCount() const
{
return 1;
}

/** Retruns value representing 'no data' (NULL) */
virtual double noDataValue() const { return 0; }

/** Read block of data using given extent and size.
* Returns pointer to data.
* Caller is responsible to free the memory returned.
*/
void * block( int bandNo, QgsRectangle const & extent, int width, int height );

/** Read block of data using given extent and size.
* Method to be implemented by subclasses.
* Returns pointer to data.
* Caller is responsible to free the memory returned.
*/
virtual void * readBlock( int bandNo, QgsRectangle const & extent, int width, int height )
{
Q_UNUSED( bandNo ); Q_UNUSED( extent ); Q_UNUSED( width ); Q_UNUSED( height );
return 0;
}

/** Set input.
* Returns true if set correctly, false if cannot use that input */
virtual bool setInput( QgsRasterInterface* input ) { mInput = input; return true; }

/** Is on/off */
virtual bool on( ) { return mOn; }

/** Set on/off */
virtual void setOn( bool on ) { mOn = on; }

/** Get source / raw input, the first in pipe, usually provider.
* It may be used to get info about original data, e.g. resolution to decide
* resampling etc.
*/
virtual QgsRasterInterface * srcInput() { return mInput ? mInput->srcInput() : 0; }

/** Create a new image with extraneous data, such data may be used
* after the image is destroyed. The memory is not initialized.
*/
QImage * createImage( int width, int height, QImage::Format format );

/** Switch on (and clear old statistics) or off collection of statistics */
void setStatsOn( bool on );

/** Last total time (for allbands) consumed by this interface for call to block()
* If cumulative is true, the result includes also time spent in all preceding
* interfaces. If cumulative is false, only time consumed by this interface is
* returned. */
double time( bool cumulative = false );

protected:
// QgsRasterInterface used as input
QgsRasterInterface* mInput;

// On/off state, if off, it does not do anything, replicates input
bool mOn;

private:
// Last rendering cumulative (this and all preceding interfaces) times, from index 1
QVector<double> mTime;

// Collect statistics
int mStatsOn;
};

#endif


113 changes: 113 additions & 0 deletions src/core/raster/qgsrasteriterator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#include "qgsrasteriterator.h"
#include "qgsrasterinterface.h"
#include "qgsrasterprojector.h"
#include "qgsrasterviewport.h"

QgsRasterIterator::QgsRasterIterator( QgsRasterInterface* input ): mInput( input ),
mMaximumTileWidth( 2000 ), mMaximumTileHeight( 2000 )
{
}

QgsRasterIterator::~QgsRasterIterator()
{
}

void QgsRasterIterator::startRasterRead( int bandNumber, int nCols, int nRows, const QgsRectangle& extent )
{
if ( !mInput )
{
return;
}

mExtent = extent;

//remove any previous part on that band
removePartInfo( bandNumber );

//split raster into small portions if necessary
RasterPartInfo pInfo;
pInfo.nCols = nCols;
pInfo.nRows = nRows;
pInfo.currentCol = 0;
pInfo.currentRow = 0;
pInfo.data = 0;
pInfo.prj = 0;
mRasterPartInfos.insert( bandNumber, pInfo );
}

bool QgsRasterIterator::readNextRasterPart( int bandNumber,
int& nCols, int& nRows,
void** rasterData,
int& topLeftCol, int& topLeftRow )
{
//get partinfo
QMap<int, RasterPartInfo>::iterator partIt = mRasterPartInfos.find( bandNumber );
if ( partIt == mRasterPartInfos.end() )
{
return false;
}

RasterPartInfo& pInfo = partIt.value();

//remove last data block
// TODO: data are released somewhere else (check)
//free( pInfo.data );
pInfo.data = 0;
delete pInfo.prj;
pInfo.prj = 0;

//already at end
if ( pInfo.currentCol == pInfo.nCols && pInfo.currentRow == pInfo.nRows )
{
return false;
}

//read data block
nCols = qMin( mMaximumTileWidth, pInfo.nCols - pInfo.currentCol );
nRows = qMin( mMaximumTileHeight, pInfo.nRows - pInfo.currentRow );

//get subrectangle
QgsRectangle viewPortExtent = mExtent;
double xmin = viewPortExtent.xMinimum() + pInfo.currentCol / ( double )pInfo.nCols * viewPortExtent.width();
double xmax = viewPortExtent.xMinimum() + ( pInfo.currentCol + nCols ) / ( double )pInfo.nCols * viewPortExtent.width();
double ymin = viewPortExtent.yMaximum() - ( pInfo.currentRow + nRows ) / ( double )pInfo.nRows * viewPortExtent.height();
double ymax = viewPortExtent.yMaximum() - pInfo.currentRow / ( double )pInfo.nRows * viewPortExtent.height();
QgsRectangle blockRect( xmin, ymin, xmax, ymax );

pInfo.data = mInput->block( bandNumber, blockRect, nCols, nRows );

*rasterData = pInfo.data;
topLeftCol = pInfo.currentCol;
topLeftRow = pInfo.currentRow;

pInfo.currentCol += nCols;
if ( pInfo.currentCol == pInfo.nCols && pInfo.currentRow + nRows == pInfo.nRows ) //end of raster
{
pInfo.currentRow = pInfo.nRows;
}
else if ( pInfo.currentCol == pInfo.nCols ) //start new row
{
pInfo.currentCol = 0;
pInfo.currentRow += nRows;
}

return true;
}

void QgsRasterIterator::stopRasterRead( int bandNumber )
{
removePartInfo( bandNumber );
}

void QgsRasterIterator::removePartInfo( int bandNumber )
{
QMap<int, RasterPartInfo>::iterator partIt = mRasterPartInfos.find( bandNumber );
if ( partIt != mRasterPartInfos.end() )
{
RasterPartInfo& pInfo = partIt.value();
//CPLFree( pInfo.data );
free( pInfo.data );
delete pInfo.prj;
mRasterPartInfos.remove( bandNumber );
}
}
67 changes: 67 additions & 0 deletions src/core/raster/qgsrasteriterator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#ifndef QGSRASTERITERATOR_H
#define QGSRASTERITERATOR_H

#include "qgsrectangle.h"
#include <QMap>

class QgsMapToPixel;
class QgsRasterInterface;
class QgsRasterProjector;
class QgsRasterViewPort;

class QgsRasterIterator
{
public:
//Stores information about reading of a raster band. Columns and rows are in unsampled coordinates
struct RasterPartInfo
{
int currentCol;
int currentRow;
int nCols;
int nRows;
void* data; //data (can be in oversampled/undersampled resolution)
QgsRasterProjector* prj; //raster projector (or 0 if no reprojection is done)
};

QgsRasterIterator( QgsRasterInterface* input );
~QgsRasterIterator();

/**Start reading of raster band. Raster data can then be retrieved by calling readNextRasterPart until it returns false.
@param bandNumer number of raster band to read
@param viewPort describes raster position on screen
*/
void startRasterRead( int bandNumber, int nCols, int nRows, const QgsRectangle& extent );

/**Fetches next part of raster data
@param nCols number of columns on output device
@param nRows number of rows on output device
@param nColsRaster number of raster columns (different to nCols if oversamplingX != 1.0)
@param nRowsRaster number of raster rows (different to nRows if oversamplingY != 0)*/
bool readNextRasterPart( int bandNumber,
int& nCols, int& nRows,
void** rasterData,
int& topLeftCol, int& topLeftRow );

void stopRasterRead( int bandNumber );

const QgsRasterInterface* input() const { return mInput; }

void setMaximumTileWidth( int w ) { mMaximumTileWidth = w; }
int maximumTileWidth() const { return mMaximumTileWidth; }

void setMaximumTileHeight( int h ) { mMaximumTileHeight = h; }
int maximumTileHeight() const { return mMaximumTileHeight; }

private:
QgsRasterInterface* mInput;
QMap<int, RasterPartInfo> mRasterPartInfos;
QgsRectangle mExtent;

int mMaximumTileWidth;
int mMaximumTileHeight;

/**Remove part into and release memory*/
void removePartInfo( int bandNumber );
};

#endif // QGSRASTERITERATOR_H
132 changes: 106 additions & 26 deletions src/core/raster/qgsrasterlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,15 @@ email : tim at linfiniti.com
#include "qgssinglebandpseudocolorrenderer.h"
#include "qgssinglebandgrayrenderer.h"

#include "qgsrasterprojector.h"

#include "qgsrasteriterator.h"
#include "qgsrasterdrawer.h"

#include <cstdio>
#include <cmath>
#include <limits>
#include <typeinfo>

#include <QApplication>
#include <QCursor>
Expand Down Expand Up @@ -98,7 +104,6 @@ QgsRasterLayer::QgsRasterLayer()
, mDataProvider( 0 )
, mWidth( std::numeric_limits<int>::max() )
, mHeight( std::numeric_limits<int>::max() )
, mRenderer( 0 )
{
init();
mValid = false;
Expand All @@ -116,7 +121,6 @@ QgsRasterLayer::QgsRasterLayer(
, mDataProvider( 0 )
, mWidth( std::numeric_limits<int>::max() )
, mHeight( std::numeric_limits<int>::max() )
, mRenderer( 0 )
{
QgsDebugMsg( "Entered" );

Expand All @@ -130,8 +134,6 @@ QgsRasterLayer::QgsRasterLayer(
loadDefaultStyle( defaultLoadedFlag );
}
return;


} // QgsRasterLayer ctor

/**
Expand All @@ -153,7 +155,6 @@ QgsRasterLayer::QgsRasterLayer( const QString & uri,
, mHeight( std::numeric_limits<int>::max() )
, mModified( false )
, mProviderKey( providerKey )
, mRenderer( 0 )
{
QgsDebugMsg( "Entered" );
init();
Expand Down Expand Up @@ -187,8 +188,6 @@ QgsRasterLayer::QgsRasterLayer( const QString & uri,
QgsRasterLayer::~QgsRasterLayer()
{
mValid = false;
delete mDataProvider;
delete mRenderer;
}

//////////////////////////////////////////////////////////
Expand Down Expand Up @@ -824,12 +823,43 @@ void QgsRasterLayer::draw( QPainter * theQPainter,
// procedure to use :
//

if ( mRenderer )
QgsRasterProjector *projector = mPipe.projector();

// TODO add a method to interface to get provider and get provider
// params in QgsRasterProjector
if ( projector )
{
mRenderer->draw( theQPainter, theRasterViewPort, theQgsMapToPixel );
projector->setCRS( theRasterViewPort->mSrcCRS, theRasterViewPort->mDestCRS );
}

QgsDebugMsg( QString( "raster draw time (ms): %1" ).arg( time.elapsed() ) );
#ifdef QGISDEBUG
// Collect stats only for larger sizes to avoid confusion (small time values)
// after thumbnail render e.g. 120 is current thumbnail size
// TODO: consider another way to switch stats on/off or storing of last significant
// stats somehow
if ( theRasterViewPort->drawableAreaXDim > 120 && theRasterViewPort->drawableAreaYDim > 120 )
{
mPipe.setStatsOn( true );
}
#endif

// Drawer to pipe?
QgsRasterIterator iterator( mPipe.last() );
QgsRasterDrawer drawer( &iterator );
drawer.draw( theQPainter, theRasterViewPort, theQgsMapToPixel );

#ifdef QGISDEBUG
mPipe.setStatsOn( false );
// Print time stats
QgsDebugMsg( QString( "interface bands time" ) );
for ( int i = 0; i < mPipe.size(); i++ )
{
QgsRasterInterface * interface = mPipe.at( i );
QString name = QString( typeid( *interface ).name() ).replace( QRegExp( ".*Qgs" ), "Qgs" ).left( 30 );
QgsDebugMsg( QString( "%1 %2 %3" ).arg( name, -30 ).arg( interface->bandCount() ).arg( interface->time(), 5 ) );
}
QgsDebugMsg( QString( "total raster draw time (ms): %1" ).arg( time.elapsed(), 5 ) );
#endif
} //end of draw method

QString QgsRasterLayer::drawingStyleAsString() const
Expand Down Expand Up @@ -985,9 +1015,14 @@ QString QgsRasterLayer::lastErrorTitle()
QList< QPair< QString, QColor > > QgsRasterLayer::legendSymbologyItems() const
{
QList< QPair< QString, QColor > > symbolList;
if ( mRenderer )
//if ( mPipe.renderer() )
//{
// mPipe.renderer()->legendSymbologyItems( symbolList );
//}
QgsRasterRenderer *renderer = mPipe.renderer();
if ( renderer )
{
mRenderer->legendSymbologyItems( symbolList );
renderer->legendSymbologyItems( symbolList );
}
return symbolList;

Expand Down Expand Up @@ -1643,6 +1678,7 @@ void QgsRasterLayer::setDataProvider( QString const & provider )
{
return;
}
mPipe.set( mDataProvider );

if ( provider == "gdal" )
{
Expand Down Expand Up @@ -1722,7 +1758,8 @@ void QgsRasterLayer::setDataProvider( QString const & provider )
{
mRasterType = Multiband;
}
else if ( mDataProvider->dataType( 1 ) == QgsRasterDataProvider::ARGBDataType )
else if ( mDataProvider->dataType( 1 ) == QgsRasterDataProvider::ARGB32
|| mDataProvider->dataType( 1 ) == QgsRasterDataProvider::ARGB32_Premultiplied )
{
mRasterType = ColorLayer;
}
Expand Down Expand Up @@ -1760,6 +1797,14 @@ void QgsRasterLayer::setDataProvider( QString const & provider )
setDrawingStyle( SingleBandGray ); //sensible default
}

//resampler (must be after renderer)
QgsRasterResampleFilter * resampleFilter = new QgsRasterResampleFilter();
mPipe.set( resampleFilter );

// projector (may be anywhere in pipe)
QgsRasterProjector * projector = new QgsRasterProjector;
mPipe.set( projector );

// Store timestamp
// TODO move to provider
mLastModified = lastModified( mDataSource );
Expand All @@ -1785,7 +1830,7 @@ void QgsRasterLayer::setDataProvider( QString const & provider )
void QgsRasterLayer::closeDataProvider()
{
mValid = false;
delete mDataProvider;
mPipe.remove( mDataProvider );
mDataProvider = 0;

mRasterStatsList.clear();
Expand All @@ -1807,15 +1852,15 @@ void QgsRasterLayer::setColorShadingAlgorithm( QString )

void QgsRasterLayer::setContrastEnhancementAlgorithm( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm, bool theGenerateLookupTableFlag )
{
if ( !mRenderer || !mDataProvider )
if ( !mPipe.renderer() || !mDataProvider )
{
return;
}

QString rendererType = mRenderer->type();
QString rendererType = mPipe.renderer()->type();
if ( rendererType == "singlebandgray" )
{
QgsSingleBandGrayRenderer* gr = dynamic_cast<QgsSingleBandGrayRenderer*>( mRenderer );
QgsSingleBandGrayRenderer* gr = dynamic_cast<QgsSingleBandGrayRenderer*>( mPipe.renderer() );
if ( gr )
{
int grayBand = gr->grayBand();
Expand All @@ -1833,7 +1878,7 @@ void QgsRasterLayer::setContrastEnhancementAlgorithm( QgsContrastEnhancement::Co
}
else if ( rendererType == "multibandcolor" )
{
QgsMultiBandColorRenderer* cr = dynamic_cast<QgsMultiBandColorRenderer*>( mRenderer );
QgsMultiBandColorRenderer* cr = dynamic_cast<QgsMultiBandColorRenderer*>( mPipe.renderer() );
if ( cr )
{
//red enhancement
Expand Down Expand Up @@ -2075,12 +2120,26 @@ void QgsRasterLayer::setTransparentBandName( QString const & )
//legacy method
}

void QgsRasterLayer::setRenderer( QgsRasterRenderer* renderer )
void QgsRasterLayer::setRenderer( QgsRasterRenderer* theRenderer )
{
delete mRenderer;
mRenderer = renderer;
QgsDebugMsg( "Entered" );
if ( !theRenderer ) { return; }
mPipe.set( theRenderer );
}

// not sure if we want it
/*
void QgsRasterLayer::setResampleFilter( QgsRasterResampleFilter* resampleFilter )
{
QgsDebugMsg( "Entered" );
if ( !resampleFilter ) { return; }
if ( !mPipe.set( resampleFilter ) )
{
// TODO: somehow notify (and delete?)
QgsDebugMsg( "Cannot set resample filter." );
}
}
*/
void QgsRasterLayer::showProgress( int theValue )
{
emit progressUpdate( theValue );
Expand Down Expand Up @@ -2236,18 +2295,29 @@ bool QgsRasterLayer::readSymbology( const QDomNode& layer_node, QString& errorMe

if ( !rasterRendererElem.isNull() )
{
delete mRenderer;
mRenderer = 0;
if ( !rasterRendererElem.isNull() )
{
QString rendererType = rasterRendererElem.attribute( "type" );
QgsRasterRendererRegistryEntry rendererEntry;
if ( QgsRasterRendererRegistry::instance()->rendererData( rendererType, rendererEntry ) )
{
mRenderer = rendererEntry.rendererCreateFunction( rasterRendererElem, dataProvider() );
QgsRasterRenderer *renderer = rendererEntry.rendererCreateFunction( rasterRendererElem, dataProvider() );
mPipe.set( renderer );
}
}
}

//resampler
QgsRasterResampleFilter * resampleFilter = new QgsRasterResampleFilter();
mPipe.set( resampleFilter );

//max oversampling
QDomElement resampleElem = layer_node.firstChildElement( "rasterresampler" );
if ( !resampleElem.isNull() )
{
resampleFilter->readXML( resampleElem );
}

return true;
} //readSymbology

Expand Down Expand Up @@ -2380,9 +2450,18 @@ bool QgsRasterLayer::writeSymbology( QDomNode & layer_node, QDomDocument & docum
{
Q_UNUSED( errorMessage );
QDomElement layerElem = layer_node.toElement();
if ( mRenderer )

QgsRasterRenderer *renderer = mPipe.renderer();
if ( renderer )
{
mRenderer->writeXML( document, layerElem );
renderer->writeXML( document, layerElem );
}

QgsRasterResampleFilter *resampleFilter = mPipe.resampleFilter();
if ( resampleFilter )
{
QDomElement layerElem = layer_node.toElement();
resampleFilter->writeXML( document, layerElem );
}

return true;
Expand Down Expand Up @@ -2667,3 +2746,4 @@ bool QgsRasterLayer::readColorTable( int theBandNumber, QList<QgsColorRampShader
*theList = myColorRampItemList;
return true;
}

19 changes: 15 additions & 4 deletions src/core/raster/qgsrasterlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@
#include "qgsrastershader.h"
#include "qgscolorrampshader.h"
#include "qgsrastershaderfunction.h"
#include "qgsrasterinterface.h"
#include "qgsrasterresamplefilter.h"
#include "qgsrasterdataprovider.h"
#include "qgsrasterpipe.h"

//
// Forward declarations
Expand Down Expand Up @@ -347,9 +350,15 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
void setUserDefinedRGBMinimumMaximum( bool theBool ) { mUserDefinedRGBMinimumMaximum = theBool; }

/**Set raster renderer. Takes ownership of the renderer object*/
void setRenderer( QgsRasterRenderer* renderer );
const QgsRasterRenderer* renderer() const { return mRenderer; }
QgsRasterRenderer* renderer() { return mRenderer; }
void setRenderer( QgsRasterRenderer* theRenderer );
QgsRasterRenderer* renderer() const { return mPipe.renderer(); }

/**Set raster resample filter. Takes ownership of the resample filter object*/
//void setResampleFilter( QgsRasterResampleFilter* resampleFilter );
QgsRasterResampleFilter * resampleFilter() const { return mPipe.resampleFilter(); }

/** Get raster pipe */
QgsRasterPipe * pipe() { return &mPipe; }

/** \brief Accessor to find out how many standard deviations are being plotted */
double standardDeviations() const { return mStandardDeviations; }
Expand Down Expand Up @@ -860,7 +869,9 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
/** \brief Flag indicating if the nodatavalue is valid*/
bool mValidNoDataValue;

QgsRasterRenderer* mRenderer;
//QgsRasterRenderer* mRenderer;
//QgsRasterResampleFilter *mResampleFilter;
QgsRasterPipe mPipe;
};

#endif
Loading