451 changes: 242 additions & 209 deletions src/app/qgsrasterlayerproperties.cpp

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions src/app/qgsrasterlayerproperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ class QgsRasterLayerProperties : public QDialog, private Ui::QgsRasterLayerPrope
/** Update items in pipe list */
void pipeItemClicked( QTreeWidgetItem * item, int column );

/** Transparency cell changed */
void transparencyCellTextEdited( const QString & text );

signals:
/** emitted when changes to layer were saved to update legend */
void refreshLegend( QString layerID, bool expandItem );
Expand Down Expand Up @@ -137,9 +140,16 @@ class QgsRasterLayerProperties : public QDialog, private Ui::QgsRasterLayerPrope

QgsRasterRendererWidget* mRendererWidget;

void setupTransparencyTable( int nBands );

/** \brief Clear the current transparency table and populate the table with the correct types for current drawing mode and data type*/
void populateTransparencyTable( QgsRasterRenderer* renderer );

void setTransparencyCell( int row, int column, double value );
void setTransparencyCellValue( int row, int column, double value );
double transparencyCellValue( int row, int column );
void setTransparencyToEdited( int row );

void setRendererWidget( const QString& rendererName );

//@TODO we should move these gradient generators somewhere more generic
Expand All @@ -162,5 +172,7 @@ class QgsRasterLayerProperties : public QDialog, private Ui::QgsRasterLayerPrope
QgsMapToolEmitPoint* mPixelSelectorTool;

QgsRasterHistogramWidget* mHistogramWidget;

QVector<bool> mTransparencyToEdited;
};
#endif
4 changes: 2 additions & 2 deletions src/core/composer/qgscomposeritem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ QgsComposerItem::QgsComposerItem( QgsComposition* composition, bool manageZValue
, QGraphicsRectItem( 0 )
, mComposition( composition )
, mBoundingResizeRectangle( 0 )
, mFrame( true )
, mFrame( false )
, mItemPositionLocked( false )
, mLastValidViewScaleFactor( -1 )
, mRotation( 0 )
Expand All @@ -55,7 +55,7 @@ QgsComposerItem::QgsComposerItem( qreal x, qreal y, qreal width, qreal height, Q
, QGraphicsRectItem( 0, 0, width, height, 0 )
, mComposition( composition )
, mBoundingResizeRectangle( 0 )
, mFrame( true )
, mFrame( false )
, mItemPositionLocked( false )
, mLastValidViewScaleFactor( -1 )
, mRotation( 0 )
Expand Down
9 changes: 4 additions & 5 deletions src/core/composer/qgscomposerscalebar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,12 +168,11 @@ void QgsComposerScaleBar::refreshSegmentMillimeters()
QRectF composerItemRect = mComposerMap->rect();

//calculate size depending on mNumUnitsPerSegment
double itemDiagonal = sqrt( composerItemRect.width() * composerItemRect.width() + composerItemRect.height() * composerItemRect.height() );
mSegmentMillimeters = itemDiagonal / mapDiagonal() * mNumUnitsPerSegment;
mSegmentMillimeters = composerItemRect.width() / mapWidth() * mNumUnitsPerSegment;
}
}

double QgsComposerScaleBar::mapDiagonal() const
double QgsComposerScaleBar::mapWidth() const
{
if ( !mComposerMap )
{
Expand All @@ -183,7 +182,7 @@ double QgsComposerScaleBar::mapDiagonal() const
QgsRectangle composerMapRect = mComposerMap->extent();
if ( mUnits == MapUnits )
{
return sqrt( composerMapRect.width() * composerMapRect.width() + composerMapRect.height() * composerMapRect.height() );
return composerMapRect.width();
}
else
{
Expand All @@ -192,7 +191,7 @@ double QgsComposerScaleBar::mapDiagonal() const
da.setSourceCrs( mComposerMap->mapRenderer()->destinationCrs().srsid() );
QSettings s;
da.setEllipsoid( s.value( "/qgis/measure/ellipsoid", "WGS84" ).toString() );
double measure = da.measureLine( QgsPoint( composerMapRect.xMinimum(), composerMapRect.yMaximum() ), QgsPoint( composerMapRect.xMaximum(), composerMapRect.yMinimum() ) );
double measure = da.measureLine( QgsPoint( composerMapRect.xMinimum(), composerMapRect.yMinimum() ), QgsPoint( composerMapRect.xMaximum(), composerMapRect.yMinimum() ) );
if ( mUnits == Feet )
{
measure /= 0.3048;
Expand Down
2 changes: 1 addition & 1 deletion src/core/composer/qgscomposerscalebar.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ class CORE_EXPORT QgsComposerScaleBar: public QgsComposerItem
void refreshSegmentMillimeters();

/**Returns diagonal of composer map in selected units (map units / meters / feet)*/
double mapDiagonal() const;
double mapWidth() const;
};

#endif //QGSCOMPOSERSCALEBAR_H
Expand Down
1 change: 0 additions & 1 deletion src/core/qgsmaprenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,6 @@ void QgsMapRenderer::render( QPainter* painter, double* forceWidthScale )
mRenderContext.painter()->scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor );
}


if ( !ml->draw( mRenderContext ) )
{
emit drawError( ml );
Expand Down
6 changes: 6 additions & 0 deletions src/core/qgsrasterdataprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,9 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
/* Read a value from a data block at a given index. */
virtual double readValue( void *data, int type, int index );

/* Return true if source band has no data value */
virtual bool srcHasNoDataValue( int bandNo ) const { Q_UNUSED( bandNo ); return false; }

/** value representing null data */
virtual double noDataValue() const { return 0; }

Expand Down Expand Up @@ -522,6 +525,9 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
return false;
}

/** Set no data value on created dataset */
virtual bool setNoDataValue( int, double ) { return false; }

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

Expand Down
6 changes: 6 additions & 0 deletions src/core/qgsrasterprojector.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ class CORE_EXPORT QgsRasterProjector : public QgsRasterInterface
/** \brief set source and destination CRS */
void setCRS( QgsCoordinateReferenceSystem theSrcCRS, QgsCoordinateReferenceSystem theDestCRS );

/** \brief Get source CRS */
QgsCoordinateReferenceSystem srcCrs() const { return mSrcCRS; }

/** \brief Get destination CRS */
QgsCoordinateReferenceSystem destCrs() const { return mDestCRS; }

/** \brief set maximum source resolution */
void setMaxSrcRes( double theMaxSrcXRes, double theMaxSrcYRes )
{
Expand Down
228 changes: 182 additions & 46 deletions src/core/raster/qgsrasterfilewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "qgsrasterinterface.h"
#include "qgsrasteriterator.h"
#include "qgsrasterlayer.h"
#include "qgsrasterprojector.h"
#include <QCoreApplication>
#include <QProgressDialog>
#include <QTextStream>
Expand All @@ -38,16 +39,20 @@ QgsRasterFileWriter::~QgsRasterFileWriter()

}

QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeRaster( QgsRasterIterator* iter, int nCols, int nRows, QgsRectangle outputExtent,
const QgsCoordinateReferenceSystem& crs, QProgressDialog* p )
//QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeRaster( QgsRasterIterator* iter, int nCols, int nRows, QgsRectangle outputExtent,
QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeRaster( const QgsRasterPipe* pipe, int nCols, int nRows, QgsRectangle outputExtent,
const QgsCoordinateReferenceSystem& crs, QProgressDialog* progressDialog )
{
QgsDebugMsg( "Entered" );
if ( !iter )

//if ( !iter )
if ( !pipe )
{
return SourceProviderError;
}

const QgsRasterInterface* iface = iter->input();
//const QgsRasterInterface* iface = iter->input();
const QgsRasterInterface* iface = pipe->last();
if ( !iface )
{
return SourceProviderError;
Expand All @@ -59,39 +64,44 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeRaster( QgsRasterIter
return SourceProviderError;
}

mProgressDialog = p;
mProgressDialog = progressDialog;

QgsRasterIterator iter( pipe->last() );

if ( iface->dataType( 1 ) == QgsRasterInterface::ARGB32 ||
iface->dataType( 1 ) == QgsRasterInterface::ARGB32_Premultiplied )
{
WriterError e = writeImageRaster( iter, nCols, nRows, outputExtent, crs, p );
WriterError e = writeImageRaster( &iter, nCols, nRows, outputExtent, crs, progressDialog );
mProgressDialog = 0;
return e;
}
else
{
mProgressDialog = 0;
WriterError e = writeDataRaster( iter, nCols, nRows, outputExtent, crs, p );
WriterError e = writeDataRaster( pipe, &iter, nCols, nRows, outputExtent, crs, progressDialog );
return e;
}
}

QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( QgsRasterIterator* iter, int nCols, int nRows, const QgsRectangle& outputExtent,
const QgsCoordinateReferenceSystem& crs, QProgressDialog* p )
QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( const QgsRasterPipe* pipe, QgsRasterIterator* iter, int nCols, int nRows, const QgsRectangle& outputExtent,
const QgsCoordinateReferenceSystem& crs, QProgressDialog* progressDialog )
{
QgsDebugMsg( "Entered" );
if ( !iter )
{
return SourceProviderError;
}

const QgsRasterInterface* iface = iter->input();
//const QgsRasterInterface* iface = iter->input();
const QgsRasterInterface* iface = pipe->last();
if ( !iface )
{
return SourceProviderError;
}

const QgsRasterDataProvider* srcProvider = dynamic_cast<const QgsRasterDataProvider*>( iface->srcInput() );
//const QgsRasterDataProvider* srcProvider = dynamic_cast<const QgsRasterDataProvider*>( iface->srcInput() );
//QgsRasterDataProvider* srcProvider = dynamic_cast<QgsRasterDataProvider*>( iface->srcInput() );
QgsRasterDataProvider* srcProvider = const_cast<QgsRasterDataProvider*>( dynamic_cast<const QgsRasterDataProvider*>( iface->srcInput() ) );
if ( !srcProvider )
{
QgsDebugMsg( "Cannot get source data provider" );
Expand All @@ -105,12 +115,6 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( QgsRaster
destDir.mkdir( mOutputUrl );
}

//Get output map units per pixel
int iterLeft = 0;
int iterTop = 0;
int iterCols = 0;
int iterRows = 0;

iter->setMaximumTileWidth( mMaxTileWidth );
iter->setMaximumTileHeight( mMaxTileHeight );

Expand All @@ -137,25 +141,159 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( QgsRaster
}
}

// Output data type - source data type is preferred but it may happen that we need
// to set 'no data' value (which was not set on source data) if output extent
// is larger than source extent (with or without reprojection) and there is no 'free'
// (not used) value available
QList<bool> destHasNoDataValueList;
QList<double> destNoDataValueList;
QList<QgsRasterInterface::DataType> destDataTypeList;
for ( int bandNo = 1; bandNo <= nBands; bandNo++ )
{

bool srcHasNoDataValue = srcProvider->srcHasNoDataValue( bandNo );
bool destHasNoDataValue = false;
double destNoDataValue;
QgsRasterInterface::DataType destDataType = srcProvider->srcDataType( bandNo );
if ( srcHasNoDataValue )
{
// If source has no data value, it is used by provider
// TODO: this is not realy source no data, we would need srcNoDataValue() but it
// can be safely used I think
destNoDataValue = srcProvider->noDataValue();
destHasNoDataValue = true;
}
#if 0
else if ( )
// TODO: see if nuller has user defined aditional values, in that case use one as no data value

}
#endif
else
{
// Verify if we realy need no data value, i.e.
QgsRectangle srcExtent = outputExtent;
QgsRasterProjector *projector = pipe->projector();
if ( projector && projector->destCrs() != projector->srcCrs() )
{
QgsCoordinateTransform ct( projector->destCrs(), projector->srcCrs() );
srcExtent = ct.transformBoundingBox( outputExtent );
}
if ( !srcProvider->extent().contains( srcExtent ) )
{
// Destination extent is larger than source extent, we need destination no data values
// Get src sample statistics (estimation from sample)
QgsRasterBandStats stats = srcProvider->bandStatistics( bandNo, QgsRasterBandStats::Min | QgsRasterBandStats::Max, srcExtent, 250000 );

// Test if we have free (not used) values
double typeMinValue = QgsContrastEnhancement::maximumValuePossible(( QgsContrastEnhancement::QgsRasterDataType )srcProvider->srcDataType( bandNo ) );
double typeMaxValue = QgsContrastEnhancement::maximumValuePossible(( QgsContrastEnhancement::QgsRasterDataType )srcProvider->srcDataType( bandNo ) );
if ( stats.minimumValue > typeMinValue )
{
destNoDataValue = typeMinValue;
}
else if ( stats.maximumValue < typeMaxValue )
{
destNoDataValue = typeMaxValue;
}
else
{
// We have to use wider type
destDataType = QgsRasterInterface::typeWithNoDataValue( destDataType, &destNoDataValue );
}
destHasNoDataValue = true;
}
}
QgsDebugMsg( QString( "bandNo = %1 destDataType = %2 destHasNoDataValue = %3 destNoDataValue = %4" ).arg( bandNo ).arg( destDataType ).arg( destHasNoDataValue ).arg( destNoDataValue ) );
destDataTypeList.append( destDataType );
destHasNoDataValueList.append( destHasNoDataValue );
destNoDataValueList.append( destNoDataValue );
}


QgsRasterInterface::DataType destDataType = destDataTypeList.value( 0 );
// Currently write API supports one output type for dataset only -> find the widest
for ( int i = 1; i < nBands; i++ )
{
if ( destDataTypeList.value( i ) > destDataType )
{
destDataType = destDataTypeList.value( i );
// no data value may be left per band (for future)
}
}

destProvider = initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType );

WriterError error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent, crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider, progressDialog );

if ( error == NoDataConflict )
{
// The value used for no data was found in source data, we must use wider data type
destProvider->remove();
delete destProvider;

// But we dont know which band -> wider all
for ( int i = 0; i < nBands; i++ )
{
double destNoDataValue;
QgsRasterInterface::DataType destDataType = QgsRasterInterface::typeWithNoDataValue( destDataTypeList.value( i ), &destNoDataValue );
destDataTypeList.replace( i, destDataType );
destNoDataValueList.replace( i, destNoDataValue );
}

// Try again
destProvider = initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType );
error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent, crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider, progressDialog );
}

return error;
}

QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(
const QgsRasterPipe* pipe,
QgsRasterIterator* iter,
int nCols, int nRows,
const QgsRectangle& outputExtent,
const QgsCoordinateReferenceSystem& crs,
QgsRasterInterface::DataType destDataType,
QList<bool> destHasNoDataValueList,
QList<double> destNoDataValueList,
QgsRasterDataProvider* destProvider,
QProgressDialog* progressDialog )
{
Q_UNUSED( pipe );
Q_UNUSED( destHasNoDataValueList );
QgsDebugMsg( "Entered" );

const QgsRasterInterface* iface = iter->input();
const QgsRasterDataProvider* srcProvider = dynamic_cast<const QgsRasterDataProvider*>( iface->srcInput() );
int nBands = iface->bandCount();

//Get output map units per pixel
int iterLeft = 0;
int iterTop = 0;
int iterCols = 0;
int iterRows = 0;

int dataTypeSize = srcProvider->typeSize( srcProvider->srcDataType( 1 ) );
QList<void*> dataList;
for ( int i = 1; i <= nBands; ++i )
{
iter->startRasterRead( i, nCols, nRows, outputExtent );
dataList.push_back( VSIMalloc( dataTypeSize * mMaxTileWidth * mMaxTileHeight ) );
destProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
}

destProvider = initOutput( nCols, nRows, crs, geoTransform, nBands, srcProvider->srcDataType( 1 ) );

int nParts = 0;
int fileIndex = 0;
if ( p )
if ( progressDialog )
{
int nPartsX = nCols / iter->maximumTileWidth() + 1;
int nPartsY = nRows / iter->maximumTileHeight() + 1;
nParts = nPartsX * nPartsY;
p->setMaximum( nParts );
p->show();
p->setLabelText( QObject::tr( "Reading raster part %1 of %2" ).arg( fileIndex + 1 ).arg( nParts ) );
progressDialog->setMaximum( nParts );
progressDialog->show();
progressDialog->setLabelText( QObject::tr( "Reading raster part %1 of %2" ).arg( fileIndex + 1 ).arg( nParts ) );
}

while ( true )
Expand All @@ -175,14 +313,15 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( QgsRaster

return NoError; //reached last tile, bail out
}
// TODO: verify if NoDataConflict happened, to do that we need the whole pipe or nuller interface
}

if ( p && fileIndex < ( nParts - 1 ) )
if ( progressDialog && fileIndex < ( nParts - 1 ) )
{
p->setValue( fileIndex + 1 );
p->setLabelText( QObject::tr( "Reading raster part %1 of %2" ).arg( fileIndex + 2 ).arg( nParts ) );
progressDialog->setValue( fileIndex + 1 );
progressDialog->setLabelText( QObject::tr( "Reading raster part %1 of %2" ).arg( fileIndex + 2 ).arg( nParts ) );
QCoreApplication::processEvents( QEventLoop::AllEvents, 1000 );
if ( p->wasCanceled() )
if ( progressDialog->wasCanceled() )
{
for ( int i = 0; i < nBands; ++i )
{
Expand All @@ -196,7 +335,7 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( QgsRaster
{
delete destProvider;
destProvider = createPartProvider( outputExtent, nCols, iterCols, iterRows,
iterLeft, iterTop, mOutputUrl, fileIndex, nBands, iface->dataType( 1 ), crs );
iterLeft, iterTop, mOutputUrl, fileIndex, nBands, destDataType, crs );

//write data to output file. todo: loop over the data list
for ( int i = 1; i <= nBands; ++i )
Expand All @@ -215,16 +354,13 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( QgsRaster
CPLFree( dataList[i - 1] );
}
}



++fileIndex;
}
return NoError;
}

QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeImageRaster( QgsRasterIterator* iter, int nCols, int nRows, const QgsRectangle& outputExtent,
const QgsCoordinateReferenceSystem& crs, QProgressDialog* p )
const QgsCoordinateReferenceSystem& crs, QProgressDialog* progressDialog )
{
QgsDebugMsg( "Entered" );
if ( !iter )
Expand Down Expand Up @@ -270,14 +406,14 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeImageRaster( QgsRaste
iter->startRasterRead( 1, nCols, nRows, outputExtent );

int nParts = 0;
if ( p )
if ( progressDialog )
{
int nPartsX = nCols / iter->maximumTileWidth() + 1;
int nPartsY = nRows / iter->maximumTileHeight() + 1;
nParts = nPartsX * nPartsY;
p->setMaximum( nParts );
p->show();
p->setLabelText( QObject::tr( "Reading raster part %1 of %2" ).arg( fileIndex + 1 ).arg( nParts ) );
progressDialog->setMaximum( nParts );
progressDialog->show();
progressDialog->setLabelText( QObject::tr( "Reading raster part %1 of %2" ).arg( fileIndex + 1 ).arg( nParts ) );
}

while ( iter->readNextRasterPart( 1, iterCols, iterRows, &data, iterLeft, iterTop ) )
Expand All @@ -288,12 +424,12 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeImageRaster( QgsRaste
continue;
}

if ( p && fileIndex < ( nParts - 1 ) )
if ( progressDialog && fileIndex < ( nParts - 1 ) )
{
p->setValue( fileIndex + 1 );
p->setLabelText( QObject::tr( "Reading raster part %1 of %2" ).arg( fileIndex + 2 ).arg( nParts ) );
progressDialog->setValue( fileIndex + 1 );
progressDialog->setLabelText( QObject::tr( "Reading raster part %1 of %2" ).arg( fileIndex + 2 ).arg( nParts ) );
QCoreApplication::processEvents( QEventLoop::AllEvents, 1000 );
if ( p->wasCanceled() )
if ( progressDialog->wasCanceled() )
{
CPLFree( data );
break;
Expand Down Expand Up @@ -349,9 +485,9 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeImageRaster( QgsRaste
delete destProvider;
CPLFree( redData ); CPLFree( greenData ); CPLFree( blueData ); CPLFree( alphaData );

if ( p )
if ( progressDialog )
{
p->setValue( p->maximum() );
progressDialog->setValue( progressDialog->maximum() );
}

if ( mTiledMode )
Expand Down Expand Up @@ -462,16 +598,16 @@ int QgsRasterFileWriter::pyramidsProgress( double dfComplete, const char *pszMes
{
Q_UNUSED( pszMessage );
GDALTermProgress( dfComplete, 0, 0 );
QProgressDialog* p = static_cast<QProgressDialog*>( pData );
if ( pData && p->wasCanceled() )
QProgressDialog* progressDialog = static_cast<QProgressDialog*>( pData );
if ( pData && progressDialog->wasCanceled() )
{
return 0;
}

if ( pData )
{
p->setRange( 0, 100 );
p->setValue( dfComplete * 100 );
progressDialog->setRange( 0, 100 );
progressDialog->setValue( dfComplete * 100 );
}
return 1;
}
Expand Down
29 changes: 23 additions & 6 deletions src/core/raster/qgsrasterfilewriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,23 @@ class CORE_EXPORT QgsRasterFileWriter
SourceProviderError = 1,
DestProviderError = 2,
CreateDatasourceError = 3,
WriteError = 4
WriteError = 4,
// Internal error if a value used for 'no data' was found in input
NoDataConflict = 5
};

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

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

void setOutputFormat( const QString& format ) { mOutputFormat = format; }
Expand All @@ -72,10 +75,24 @@ class CORE_EXPORT QgsRasterFileWriter

private:
QgsRasterFileWriter(); //forbidden
WriterError writeDataRaster( QgsRasterIterator* iter, int nCols, int nRows, const QgsRectangle& outputExtent,
const QgsCoordinateReferenceSystem& crs, QProgressDialog* p = 0 );
//WriterError writeDataRaster( QgsRasterIterator* iter, int nCols, int nRows, const QgsRectangle& outputExtent,
WriterError writeDataRaster( const QgsRasterPipe* pipe, QgsRasterIterator* iter, int nCols, int nRows, const QgsRectangle& outputExtent,
const QgsCoordinateReferenceSystem& crs, QProgressDialog* progressDialog = 0 );

// Helper method used by previous one
WriterError writeDataRaster( const QgsRasterPipe* pipe,
QgsRasterIterator* iter,
int nCols, int nRows,
const QgsRectangle& outputExtent,
const QgsCoordinateReferenceSystem& crs,
QgsRasterInterface::DataType destDataType,
QList<bool> destHasNoDataValueList,
QList<double> destNoDataValueList,
QgsRasterDataProvider* destProvider,
QProgressDialog* progressDialog );

WriterError writeImageRaster( QgsRasterIterator* iter, int nCols, int nRows, const QgsRectangle& outputExtent,
const QgsCoordinateReferenceSystem& crs, QProgressDialog* p = 0 );
const QgsCoordinateReferenceSystem& crs, QProgressDialog* progressDialog = 0 );

//initialize vrt member variables
void createVRT( int xSize, int ySize, const QgsCoordinateReferenceSystem& crs, double* geoTransform );
Expand Down
34 changes: 34 additions & 0 deletions src/core/raster/qgsrasterinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* *
***************************************************************************/

#include <limits>
#include <typeinfo>

#include <QByteArray>
Expand Down Expand Up @@ -86,6 +87,39 @@ bool QgsRasterInterface::typeIsColor( DataType dataType ) const
return false;
}

QgsRasterInterface::DataType QgsRasterInterface::typeWithNoDataValue( DataType dataType, double *noDataValue )
{
DataType newDataType;

switch ( dataType )
{
case QgsRasterInterface::Byte:
*noDataValue = -32768.0;
newDataType = QgsRasterInterface::Int16;
break;
case QgsRasterInterface::Int16:
*noDataValue = -2147483648.0;
newDataType = QgsRasterInterface::Int32;
break;
case QgsRasterInterface::UInt16:
*noDataValue = -2147483648.0;
newDataType = QgsRasterInterface::Int32;
break;
case QgsRasterInterface::UInt32:
case QgsRasterInterface::Int32:
case QgsRasterInterface::Float32:
case QgsRasterInterface::Float64:
*noDataValue = std::numeric_limits<double>::max() * -1.0;
newDataType = QgsRasterInterface::Float64;
default:
QgsDebugMsg( QString( "Unknow data type %1" ).arg( dataType ) );
return UnknownDataType;
break;
}
QgsDebugMsg( QString( "newDataType = %1 noDataValue = %2" ).arg( newDataType ).arg( *noDataValue ) );
return newDataType;
}

// 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 )
Expand Down
3 changes: 3 additions & 0 deletions src/core/raster/qgsrasterinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ class CORE_EXPORT QgsRasterInterface
return UnknownDataType;
}

/** For given data type returns wider type and sets no data value */
static DataType typeWithNoDataValue( DataType dataType, double *noDataValue );

/** Get number of bands */
virtual int bandCount() const
{
Expand Down
8 changes: 7 additions & 1 deletion src/core/raster/qgsrasterrendererregistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,21 +275,27 @@ QgsRasterRenderer* QgsRasterRendererRegistry::defaultRendererForDrawingStyle( co
if ( bandCount == 1 )
{
QList<QgsRasterTransparency::TransparentSingleValuePixel> transparentSingleList;
// No need to set no data value in transparency list, I think
#if 0
QgsRasterTransparency::TransparentSingleValuePixel singleEntry;
singleEntry.pixelValue = provider->noDataValue();
singleEntry.min = provider->noDataValue();
singleEntry.max = provider->noDataValue();
singleEntry.percentTransparent = 100;
transparentSingleList.push_back( singleEntry );
#endif
tr->setTransparentSingleValuePixelList( transparentSingleList );
}
else if ( bandCount == 3 )
{
QList<QgsRasterTransparency::TransparentThreeValuePixel> transparentThreeValueList;
#if 0
QgsRasterTransparency::TransparentThreeValuePixel threeValueEntry;
threeValueEntry.red = provider->noDataValue();
threeValueEntry.green = provider->noDataValue();
threeValueEntry.blue = provider->noDataValue();
threeValueEntry.percentTransparent = 100;
transparentThreeValueList.push_back( threeValueEntry );
#endif
tr->setTransparentThreeValuePixelList( transparentThreeValueList );
}
renderer->setRasterTransparency( tr );
Expand Down
22 changes: 17 additions & 5 deletions src/core/raster/qgsrastertransparency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ void QgsRasterTransparency::initializeTransparentPixelList( double theValue )

//add the initial value
TransparentSingleValuePixel myTransparentSingleValuePixel;
myTransparentSingleValuePixel.pixelValue = theValue;
myTransparentSingleValuePixel.min = theValue;
myTransparentSingleValuePixel.max = theValue;
myTransparentSingleValuePixel.percentTransparent = 100.0;
mTransparentSingleValuePixelList.append( myTransparentSingleValuePixel );
}
Expand Down Expand Up @@ -113,7 +114,7 @@ int QgsRasterTransparency::alphaValue( double theValue, int theGlobalTransparenc
for ( int myListRunner = 0; myListRunner < mTransparentSingleValuePixelList.count(); myListRunner++ )
{
myTransparentPixel = mTransparentSingleValuePixelList[myListRunner];
if ( myTransparentPixel.pixelValue == theValue )
if ( theValue >= myTransparentPixel.min && theValue <= myTransparentPixel.max )
{
myTransparentPixelFound = true;
break;
Expand Down Expand Up @@ -177,7 +178,7 @@ bool QgsRasterTransparency::isEmpty( double nodataValue ) const
{
return (
( mTransparentSingleValuePixelList.isEmpty() ||
( mTransparentSingleValuePixelList.size() == 1 && doubleNear( mTransparentSingleValuePixelList.at( 0 ).pixelValue, nodataValue ) ) )
( mTransparentSingleValuePixelList.size() == 1 && doubleNear( mTransparentSingleValuePixelList.at( 0 ).min, nodataValue ) && doubleNear( mTransparentSingleValuePixelList.at( 0 ).max, nodataValue ) ) )
&&
( mTransparentThreeValuePixelList.isEmpty() ||
( mTransparentThreeValuePixelList.size() < 4 && doubleNear( mTransparentThreeValuePixelList.at( 0 ).red, nodataValue ) &&
Expand All @@ -194,7 +195,9 @@ void QgsRasterTransparency::writeXML( QDomDocument& doc, QDomElement& parentElem
for ( ; it != mTransparentSingleValuePixelList.constEnd(); ++it )
{
QDomElement pixelListElement = doc.createElement( "pixelListEntry" );
pixelListElement.setAttribute( "pixelValue", QString::number( it->pixelValue, 'f' ) );
//pixelListElement.setAttribute( "pixelValue", QString::number( it->pixelValue, 'f' ) );
pixelListElement.setAttribute( "min", QString::number( it->min, 'f' ) );
pixelListElement.setAttribute( "max", QString::number( it->max, 'f' ) );
pixelListElement.setAttribute( "percentTransparent", QString::number( it->percentTransparent ) );
singleValuePixelListElement.appendChild( pixelListElement );
}
Expand Down Expand Up @@ -239,7 +242,16 @@ void QgsRasterTransparency::readXML( const QDomElement& elem )
{
currentEntryElem = entryList.at( i ).toElement();
sp.percentTransparent = currentEntryElem.attribute( "percentTransparent" ).toDouble();
sp.pixelValue = currentEntryElem.attribute( "pixelValue" ).toDouble();
// Backward compoatibility < 1.9 : pixelValue (before ranges)
if ( currentEntryElem.hasAttribute( "pixelValue" ) )
{
sp.min = sp.max = currentEntryElem.attribute( "pixelValue" ).toDouble();
}
else
{
sp.min = currentEntryElem.attribute( "min" ).toDouble();
sp.max = currentEntryElem.attribute( "max" ).toDouble();
}
mTransparentSingleValuePixelList.append( sp );
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/core/raster/qgsrastertransparency.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ class CORE_EXPORT QgsRasterTransparency

struct TransparentSingleValuePixel
{
double pixelValue;
double min;
double max;
double percentTransparent;
};

Expand Down
2 changes: 1 addition & 1 deletion src/gui/qgsmapcanvasmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ void QgsMapCanvasMap::render()

paint.end();

// convert QImage to QPixmap to acheive faster drawing on screen
// convert QImage to QPixmap to achieve faster drawing on screen
mPixmap = QPixmap::fromImage( mImage );
}
else
Expand Down
1 change: 1 addition & 0 deletions src/gui/qgsmessagelogviewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ void QgsMessageLogViewer::logMessage( QString message, QString tag, int level )
w->verticalHeader()->setVisible( false );
w->setGridStyle( Qt::DotLine );
w->setEditTriggers( QAbstractItemView::NoEditTriggers );
w->setHorizontalScrollMode( QAbstractItemView::ScrollPerPixel );
w->setHorizontalHeaderLabels( QStringList() << tr( "Timestamp" ) << tr( "Message" ) << tr( "Level" ) );
tabWidget->addTab( w, tag );

Expand Down
14 changes: 7 additions & 7 deletions src/gui/qgsowssourceselect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ void QgsOWSSourceSelect::populateFormats()
formatsMap.insert( "jpg", "jpeg" );
formatsMap.insert( "png", "png" );

int prefered = -1;
int preferred = -1;
int firstEnabled = -1;
QStringList layersFormats = selectedLayersFormats();
for ( int i = 0; i < layersFormats.size(); i++ )
Expand Down Expand Up @@ -213,9 +213,9 @@ void QgsOWSSourceSelect::populateFormats()
if ( firstEnabled < 0 ) { firstEnabled = i; }
if ( simpleFormat.contains( "tif" ) ) // prefer *tif*
{
if ( prefered < 0 || simpleFormat.startsWith( "g" ) ) // prefere geotiff
if ( preferred < 0 || simpleFormat.startsWith( "g" ) ) // prefer geotiff
{
prefered = i;
preferred = i;
}
}
}
Expand All @@ -230,12 +230,12 @@ void QgsOWSSourceSelect::populateFormats()
btn->setText( label );
btn->setToolTip( tip );
}
// Set prefered
// Set preferred
// TODO: all enabled for now, see above
prefered = prefered >= 0 ? prefered : firstEnabled;
if ( prefered >= 0 )
preferred = preferred >= 0 ? preferred : firstEnabled;
if ( preferred >= 0 )
{
mImageFormatGroup->button( prefered )->setChecked( true );
mImageFormatGroup->button( preferred )->setChecked( true );
}

mImageFormatsGroupBox->setEnabled( true );
Expand Down
7 changes: 7 additions & 0 deletions src/gui/qgsrasterlayersaveasdialog.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "qgsapplication.h"
#include "qgslogger.h"
#include "qgscoordinatetransform.h"
#include "qgsrasterlayersaveasdialog.h"
Expand All @@ -21,6 +22,12 @@ QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterDataProvider* s
, mResolutionState( OriginalResolution )
{
setupUi( this );
mAddNoDataManuallyToolButton->setIcon( QgsApplication::getThemeIcon( "/mActionNewAttribute.png" ) );
mLoadTransparentNoDataToolButton->setIcon( QgsApplication::getThemeIcon( "/mActionCopySelected.png" ) );
mRemoveSelectedNoDataToolButton->setIcon( QgsApplication::getThemeIcon( "/mActionDeleteAttribute.png" ) );
mRemoveAllNoDataToolButton->setIcon( QgsApplication::getThemeIcon( "/mActionRemove.png" ) );
mNoDataGroupBox->setEnabled( false ); // not yet implemented

setValidators();
// Translated labels + EPSG are updated later
mCrsComboBox->addItem( "Layer", OriginalCrs );
Expand Down
127 changes: 70 additions & 57 deletions src/providers/gdal/qgsgdalprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,21 @@ void QgsGdalProvider::readBlock( int theBandNo, QgsRectangle const & theExtent,
}
#endif

bool QgsGdalProvider::srcHasNoDataValue( int bandNo ) const
{
if ( mGdalDataset )
{
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, bandNo );
if ( myGdalBand )
{
int ok;
GDALGetRasterNoDataValue( myGdalBand, &ok );
return ok;
}
}
return false;
}

double QgsGdalProvider::noDataValue() const
{
if ( mNoDataValue.size() > 0 )
Expand Down Expand Up @@ -829,15 +844,31 @@ bool QgsGdalProvider::identify( const QgsPoint & point, QMap<int, QString>& resu
for ( int i = 1; i <= GDALGetRasterCount( mGdalDataset ); i++ )
{
GDALRasterBandH gdalBand = GDALGetRasterBand( mGdalDataset, i );
double value;
double data[4];

// GDAL ECW driver reads whole row if single pixel (nYSize == 1) is requested
// and it makes identify very slow -> use 2x2 matrix
int r = 0;
int c = 0;
if ( col == mWidth - 1 && mWidth > 1 )
{
col--;
c++;
}
if ( row == mHeight - 1 && mHeight > 1 )
{
row--;
r++;
}

CPLErr err = GDALRasterIO( gdalBand, GF_Read, col, row, 1, 1,
&value, 1, 1, GDT_Float64, 0, 0 );
CPLErr err = GDALRasterIO( gdalBand, GF_Read, col, row, 2, 2,
data, 2, 2, GDT_Float64, 0, 0 );

if ( err != CPLE_None )
{
QgsLogger::warning( "RasterIO error: " + QString::fromUtf8( CPLGetLastErrorMsg() ) );
}
double value = data[r*2+c];

//double value = readValue( data, type, 0 );
// QgsDebugMsg( QString( "value=%1" ).arg( value ) );
Expand All @@ -863,62 +894,12 @@ bool QgsGdalProvider::identify( const QgsPoint & point, QMap<int, QString>& resu

bool QgsGdalProvider::identify( const QgsPoint& thePoint, QMap<QString, QString>& theResults )
{
// QgsDebugMsg( "Entered" );
if ( !mExtent.contains( thePoint ) )
QMap<int, QString> results;
identify( thePoint, results );
for ( int i = 1; i <= GDALGetRasterCount( mGdalDataset ); i++ )
{
// Outside the raster
for ( int i = 1; i <= GDALGetRasterCount( mGdalDataset ); i++ )
{
theResults[ generateBandName( i )] = tr( "out of extent" );
}
theResults[ generateBandName( i )] = results.value( i );
}
else
{
double x = thePoint.x();
double y = thePoint.y();

// Calculate the row / column where the point falls
double xres = ( mExtent.xMaximum() - mExtent.xMinimum() ) / mWidth;
double yres = ( mExtent.yMaximum() - mExtent.yMinimum() ) / mHeight;

// Offset, not the cell index -> flor
int col = ( int ) floor(( x - mExtent.xMinimum() ) / xres );
int row = ( int ) floor(( mExtent.yMaximum() - y ) / yres );

// QgsDebugMsg( "row = " + QString::number( row ) + " col = " + QString::number( col ) );

for ( int i = 1; i <= GDALGetRasterCount( mGdalDataset ); i++ )
{
GDALRasterBandH gdalBand = GDALGetRasterBand( mGdalDataset, i );
double value;

CPLErr err = GDALRasterIO( gdalBand, GF_Read, col, row, 1, 1,
&value, 1, 1, GDT_Float64, 0, 0 );

if ( err != CPLE_None )
{
QgsLogger::warning( "RasterIO error: " + QString::fromUtf8( CPLGetLastErrorMsg() ) );
}

//double value = readValue( data, type, 0 );
// QgsDebugMsg( QString( "value=%1" ).arg( value ) );
QString v;

if ( mValidNoDataValue && ( fabs( value - mNoDataValue[i-1] ) <= TINY_VALUE || value != value ) )
{
v = tr( "null (no data)" );
}
else
{
v.setNum( value );
}

theResults[ generateBandName( i )] = v;

//CPLFree( data );
}
}

return true;
}

Expand Down Expand Up @@ -2274,13 +2255,45 @@ bool QgsGdalProvider::write( void* data, int band, int width, int height, int xO
return ( GDALRasterIO( rasterBand, GF_Write, xOffset, yOffset, width, height, data, width, height, GDALGetRasterDataType( rasterBand ), 0, 0 ) == CE_None );
}

bool QgsGdalProvider::setNoDataValue( int bandNo, double noDataValue )
{
if ( !mGdalDataset ) return false;

GDALRasterBandH rasterBand = GDALGetRasterBand( mGdalDataset, bandNo );
CPLErrorReset();
CPLErr err = GDALSetRasterNoDataValue( rasterBand, noDataValue );
if ( err != CPLE_None )
{
QgsDebugMsg( "Cannot set no data value" );
return false;
}
return true;
}

QStringList QgsGdalProvider::createFormats() const
{
return QStringList();
}

bool QgsGdalProvider::remove()
{
if ( mGdalDataset )
{
GDALDriverH driver = GDALGetDatasetDriver( mGdalDataset );
GDALClose( mGdalDataset );
mGdalDataset = 0;

CPLErrorReset();
CPLErr err = GDALDeleteDataset( driver, TO8F( dataSourceUri() ) );
if ( err != CPLE_None )
{
QgsLogger::warning( "RasterIO error: " + QString::fromUtf8( CPLGetLastErrorMsg() ) );
QgsDebugMsg( "RasterIO error: " + QString::fromUtf8( CPLGetLastErrorMsg() ) );
return false;
}
QgsDebugMsg( "Raster dataset dataSourceUri() successfully deleted" );
return true;
}
return false;
}

Expand Down
3 changes: 3 additions & 0 deletions src/providers/gdal/qgsgdalprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase

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

bool srcHasNoDataValue( int bandNo ) const;
double noDataValue() const;
void computeMinMax( int bandNo );
double minimumValue( int bandNo ) const;
Expand Down Expand Up @@ -273,6 +274,8 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase
/**Writes into the provider datasource*/
bool write( void* data, int band, int width, int height, int xOffset, int yOffset );

bool setNoDataValue( int bandNo, double noDataValue );

/**Returns the formats supported by create()*/
QStringList createFormats() const;

Expand Down
Empty file modified src/providers/postgres/qgspgsourceselect.cpp
100755 → 100644
Empty file.
Empty file modified src/providers/postgres/qgspostgresconn.cpp
100755 → 100644
Empty file.
76 changes: 50 additions & 26 deletions src/ui/qgsrasterlayerpropertiesbase.ui

Large diffs are not rendered by default.

84 changes: 81 additions & 3 deletions src/ui/qgsrasterlayersaveasdialogbase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>510</width>
<height>543</height>
<y>-118</y>
<width>492</width>
<height>661</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
Expand Down Expand Up @@ -362,6 +362,84 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="mNoDataGroupBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Additional no data values. The specified values will be set to no data in output raster.</string>
</property>
<property name="title">
<string>No data values (not yet implemented)</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QTableWidget" name="mNoDataTableWidget"/>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QToolButton" name="mAddNoDataManuallyToolButton">
<property name="toolTip">
<string>Add values manually</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset>
<normaloff>../../images/themes/default/mActionNewAttribute.png</normaloff>../../images/themes/default/mActionNewAttribute.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="mLoadTransparentNoDataToolButton">
<property name="toolTip">
<string>Load user defined fully transparent (100%) values </string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset>
<normaloff>../../images/themes/default/mActionCopySelected.png</normaloff>../../images/themes/default/mActionCopySelected.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="mRemoveSelectedNoDataToolButton">
<property name="toolTip">
<string>Remove selected row</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset>
<normaloff>../../images/themes/default/mActionDeleteAttribute.png</normaloff>../../images/themes/default/mActionDeleteAttribute.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="mRemoveAllNoDataToolButton">
<property name="toolTip">
<string>Clear all</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset>
<normaloff>../../images/themes/default/mActionRemove.png</normaloff>../../images/themes/default/mActionRemove.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
Expand Down