121 changes: 107 additions & 14 deletions src/core/raster/qgsrasterblock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,40 @@ QgsRasterBlock::QgsRasterBlock()
, mTypeSize( 0 )
, mWidth( 0 )
, mHeight( 0 )
, mHasNoDataValue( false )
, mNoDataValue( std::numeric_limits<double>::quiet_NaN() )
, mData( 0 )
, mImage( 0 )
, mNoDataBitmap( 0 )
{
}

QgsRasterBlock::QgsRasterBlock( QGis::DataType theDataType, int theWidth, int theHeight )
: mValid( true )
, mDataType( theDataType )
, mTypeSize( 0 )
, mWidth( theWidth )
, mHeight( theHeight )
, mHasNoDataValue( false )
, mNoDataValue( std::numeric_limits<double>::quiet_NaN() )
, mData( 0 )
, mImage( 0 )
, mNoDataBitmap( 0 )
{
reset( mDataType, mWidth, mHeight );
}

QgsRasterBlock::QgsRasterBlock( QGis::DataType theDataType, int theWidth, int theHeight, double theNoDataValue )
: mValid( true )
, mDataType( theDataType )
, mTypeSize( 0 )
, mWidth( theWidth )
, mHeight( theHeight )
, mHasNoDataValue( true )
, mNoDataValue( theNoDataValue )
, mData( 0 )
, mImage( 0 )
, mNoDataBitmap( 0 )
{
reset( mDataType, mWidth, mHeight, mNoDataValue );
}
Expand All @@ -55,6 +74,19 @@ QgsRasterBlock::~QgsRasterBlock()
{
QgsFree( mData );
delete mImage;
QgsFree( mNoDataBitmap );
}

bool QgsRasterBlock::reset( QGis::DataType theDataType, int theWidth, int theHeight )
{
QgsDebugMsg( QString( "theWidth= %1 theHeight = %2 theDataType = %3" ).arg( theWidth ).arg( theHeight ).arg( theDataType ) );
if ( !reset( theDataType, theWidth, theHeight, std::numeric_limits<double>::quiet_NaN() ) )
{
return false;
}
mHasNoDataValue = false;
// the mNoDataBitmap is created only if necessary (usually, it is not) in setIsNoData()
return true;
}

bool QgsRasterBlock::reset( QGis::DataType theDataType, int theWidth, int theHeight, double theNoDataValue )
Expand All @@ -65,10 +97,13 @@ bool QgsRasterBlock::reset( QGis::DataType theDataType, int theWidth, int theHei
mData = 0;
delete mImage;
mImage = 0;
QgsFree( mNoDataBitmap );
mNoDataBitmap = 0;
mDataType = QGis::UnknownDataType;
mTypeSize = 0;
mWidth = 0;
mHeight = 0;
mHasNoDataValue = false;
mNoDataValue = std::numeric_limits<double>::quiet_NaN();
mValid = false;

Expand Down Expand Up @@ -101,6 +136,7 @@ bool QgsRasterBlock::reset( QGis::DataType theDataType, int theWidth, int theHei
mTypeSize = QgsRasterBlock::typeSize( mDataType );
mWidth = theWidth;
mHeight = theHeight;
mHasNoDataValue = true;
mNoDataValue = theNoDataValue;
QgsDebugMsg( QString( "mWidth= %1 mHeight = %2 mDataType = %3 mData = %4 mImage = %5" ).arg( mWidth ).arg( mHeight ).arg( mDataType ).arg(( ulong )mData ).arg(( ulong )mImage ) );
return true;
Expand Down Expand Up @@ -265,8 +301,23 @@ bool QgsRasterBlock::isNoData( size_t index )
QgsDebugMsg( QString( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
return true; // we consider no data if outside
}
double value = readValue( mData, mDataType, index );
return isNoDataValue( value );
if ( mHasNoDataValue )
{
double value = readValue( mData, mDataType, index );
return isNoDataValue( value );
}
// use no data bitmap
if ( mNoDataBitmap == 0 )
{
// no data are not defined
return false;
}
size_t byte = index / 8;
int bit = index % 8;
int mask = 0b10000000 >> bit;
//int x = mNoDataBitmap[byte] & mask;
//QgsDebugMsg ( QString("byte = %1 bit = %2 mask = %3 nodata = %4 is nodata = %5").arg(byte).arg(bit).arg(mask, 0, 2 ).arg( x, 0, 2 ).arg( (bool)(x) ) );
return mNoDataBitmap[byte] & mask;
}

bool QgsRasterBlock::isNoData( int row, int column )
Expand Down Expand Up @@ -327,26 +378,53 @@ bool QgsRasterBlock::setIsNoData( int row, int column )

bool QgsRasterBlock::setIsNoData( size_t index )
{
return setValue( index, mNoDataValue );
if ( mHasNoDataValue )
{
return setValue( index, mNoDataValue );
}
if ( mNoDataBitmap == 0 )
{
if ( !createNoDataBitmap() )
{
return false;
}
}
size_t byte = index / 8;
int bit = index % 8;
int nodata = 0b10000000 >> bit;
//QgsDebugMsg ( QString("set byte = %1 bit = %2 no data by %3").arg(byte).arg(bit).arg(nodata, 0,2 ) );
mNoDataBitmap[byte] = mNoDataBitmap[byte] | nodata;
return true;
}

bool QgsRasterBlock::setIsNoData()
{
if ( !mData )
if ( mHasNoDataValue )
{
QgsDebugMsg( "Data block not allocated" );
return false;
}
if ( !mData )
{
QgsDebugMsg( "Data block not allocated" );
return false;
}

int dataTypeSize = typeSize( mDataType );
QByteArray noDataByteArray = valueBytes( mDataType, mNoDataValue );
int dataTypeSize = typeSize( mDataType );
QByteArray noDataByteArray = valueBytes( mDataType, mNoDataValue );

char *nodata = noDataByteArray.data();
for ( size_t i = 0; i < ( size_t )mWidth*mHeight; i++ )
char *nodata = noDataByteArray.data();
for ( size_t i = 0; i < ( size_t )mWidth*mHeight; i++ )
{
memcpy(( char* )mData + i*dataTypeSize, nodata, dataTypeSize );
}
}
// use bitmap
if ( mNoDataBitmap == 0 )
{
memcpy(( char* )mData + i*dataTypeSize, nodata, dataTypeSize );
if ( !createNoDataBitmap() )
{
return false;
}
}

memset( mNoDataBitmap, 0b11111111, sizeof( mNoDataBitmap ) );
return true;
}

Expand Down Expand Up @@ -423,7 +501,8 @@ void QgsRasterBlock::applyNodataValues( const QgsRasterRangeList & rangeList )
double val = value( i );
if ( QgsRasterRange::contains( val, rangeList ) )
{
setValue( i, mNoDataValue );
//setValue( i, mNoDataValue );
setIsNoData( i );
}
}
}
Expand Down Expand Up @@ -569,3 +648,17 @@ QByteArray QgsRasterBlock::valueBytes( QGis::DataType theDataType, double theVal
}
return ba;
}

bool QgsRasterBlock::createNoDataBitmap()
{
size_t size = mWidth * mHeight / 8 + 1;
QgsDebugMsg( QString( "allocate %1 bytes" ).arg( size ) );
mNoDataBitmap = ( char* )QgsMalloc( size );
if ( mNoDataBitmap == 0 )
{
QgsDebugMsg( QString( "Couldn't allocate no data memory of %1 bytes" ).arg( size ) );
return false;
}
memset( mNoDataBitmap, 0, size );
return true;
}
44 changes: 35 additions & 9 deletions src/core/raster/qgsrasterblock.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,39 @@ class CORE_EXPORT QgsRasterBlock
public:
QgsRasterBlock();

/** \brief Constructor which allocates data block in memory
* @param theDataType raster data type
* @param theWidth width of data matrix
* @param theHeight height of data matrix
*/
QgsRasterBlock( QGis::DataType theDataType, int theWidth, int theHeight );

/** \brief Constructor which allocates data block in memory
* @param theDataType raster data type
* @param theWidth width of data matrix
* @param theHeight height of data matrix
* @param theNoDataValue the value representing no data (NULL)
*/
QgsRasterBlock( QGis::DataType theDataType, int theWidth, int theHeight, double theNoDataValue = std::numeric_limits<double>::quiet_NaN() );
QgsRasterBlock( QGis::DataType theDataType, int theWidth, int theHeight, double theNoDataValue );

virtual ~QgsRasterBlock();

/** \brief Reset block
* @param theDataType raster data type
* @param theWidth width of data matrix
* @param theHeight height of data matrix
* @return true on success
*/
bool reset( QGis::DataType theDataType, int theWidth, int theHeight );

/** \brief Reset block
* @param theDataType raster data type
* @param theWidth width of data matrix
* @param theHeight height of data matrix
* @param theNoDataValue the value representing no data (NULL)
* @return true on success
*/
bool reset( QGis::DataType theDataType, int theWidth, int theHeight, double theNoDataValue = std::numeric_limits<double>::quiet_NaN() );
bool reset( QGis::DataType theDataType, int theWidth, int theHeight, double theNoDataValue );

// TODO: consider if use isValid() at all, isEmpty() should be sufficient
// and works also if block is valid but empty - difference between valid and empty?
Expand Down Expand Up @@ -125,26 +140,25 @@ class CORE_EXPORT QgsRasterBlock
/** For given data type returns wider type and sets no data value */
static QGis::DataType typeWithNoDataValue( QGis::DataType dataType, double *noDataValue );

/** True if the block has no data value.
* @return true if the block has no data value */
bool hasNoDataValue() const { return mHasNoDataValue; }

/** Return no data value.
* @return No data value */
double noDataValue() const { return mNoDataValue; }

/** Set no data value.
* @param noDataValue the value to be considered no data
*/
void setNoDataValue( double noDataValue ) { mNoDataValue = noDataValue; }
//void setNoDataValue( double noDataValue ) { mNoDataValue = noDataValue; }

/** Test if value is nodata comparing to noDataValue
* @param value tested value
* @param noDataValue no data value
* @return true if value is nodata */
static bool isNoDataValue( double value, double noDataValue );

/** Test if value is nodata for specific band
* @param value tested value
* @return true if value is nodata */
bool isNoDataValue( double value ) const;

// get byte array representing no data value
static QByteArray valueBytes( QGis::DataType theDataType, double theValue );

Expand Down Expand Up @@ -283,10 +297,16 @@ class CORE_EXPORT QgsRasterBlock
void setError( const QgsError & theError ) { mError = theError;}

private:

static QImage::Format imageFormat( QGis::DataType theDataType );
static QGis::DataType dataType( QImage::Format theFormat );

/** Test if value is nodata for specific band
* @param value tested value
* @return true if value is nodata */
bool isNoDataValue( double value ) const;

bool createNoDataBitmap();

// Valid
bool mValid;

Expand All @@ -302,6 +322,9 @@ class CORE_EXPORT QgsRasterBlock
// Height
int mHeight;

// Has no data value
bool mHasNoDataValue;

// No data value
double mNoDataValue;

Expand All @@ -312,6 +335,9 @@ class CORE_EXPORT QgsRasterBlock
// Image for image data types, not used with numerical data types
QImage *mImage;

// Bitmap of no data. One bit for each pixel. Bit is 1 if a pixels is no data.
char *mNoDataBitmap;

// Error
QgsError mError;
};
Expand Down
3 changes: 2 additions & 1 deletion src/core/raster/qgsrasterchecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ bool QgsRasterChecker::runTest( QString theVerifiedKey, QString theVerifiedUri,
compare( "Source data type", verifiedProvider->srcDataType( band ), expectedProvider->srcDataType( band ), mReport, typesOk );
compare( "Data type", verifiedProvider->dataType( band ), expectedProvider->dataType( band ), mReport, typesOk ) ;

compare( "No data (NULL) value", verifiedProvider->noDataValue( band ), expectedProvider->noDataValue( band ), mReport, typesOk );
// TODO: not yet sure if noDataValue() should exist at all
//compare( "No data (NULL) value", verifiedProvider->noDataValue( band ), expectedProvider->noDataValue( band ), mReport, typesOk );

bool statsOk = true;
QgsRasterBandStats verifiedStats = verifiedProvider->bandStatistics( band );
Expand Down
57 changes: 50 additions & 7 deletions src/core/raster/qgsrasterdataprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,47 @@ void QgsRasterDataProvider::setUseSrcNoDataValue( int bandNo, bool use )
mUseSrcNoDataValue[bandNo-1] = use;
}

//bool QgsRasterDataProvider::hasNoDataValue ( int theBandNo )
//{
//return ( srcHasNoDataValue(theBandNo) && useSrcNoDataValue(theBandNo) ) ||
// mHasInternalNoDataValue[bandNo-1];
//return srcHasNoDataValue(theBandNo) && useSrcNoDataValue(theBandNo);
//}

//bool QgsRasterDataProvider::noDataValue( int bandNo ) const
//{
// return mHasNoDataValue.value( bandNo - 1 );
//}

#if 0
double QgsRasterDataProvider::noDataValue( int bandNo ) const
{
if ( mSrcHasNoDataValue.value( bandNo - 1 ) && mUseSrcNoDataValue.value( bandNo - 1 ) )
{
return mSrcNoDataValue.value( bandNo -1 );
}
return mInternalNoDataValue.value( bandNo -1 );
//if ( mHasInternalNoDataValue[bandNo-1] )
//{
// return mInternalNoDataValue.value( bandNo -1 );
//}
return std::numeric_limits<double>::quiet_NaN();
}
#endif

QgsRasterBlock * QgsRasterDataProvider::block( int theBandNo, QgsRectangle const & theExtent, int theWidth, int theHeight )
{
QgsDebugMsg( QString( "theBandNo = %1 theWidth = %2 theHeight = %3" ).arg( theBandNo ).arg( theWidth ).arg( theHeight ) );
QgsDebugMsg( QString( "theExtent = %1" ).arg( theExtent.toString() ) );

QgsRasterBlock *block = new QgsRasterBlock( dataType( theBandNo ), theWidth, theHeight, noDataValue( theBandNo ) );
QgsRasterBlock *block;
if ( srcHasNoDataValue( theBandNo ) && useSrcNoDataValue( theBandNo ) )
{
block = new QgsRasterBlock( dataType( theBandNo ), theWidth, theHeight, srcNoDataValue( theBandNo ) );
}
else
{
block = new QgsRasterBlock( dataType( theBandNo ), theWidth, theHeight );
}

if ( block->isEmpty() )
{
Expand Down Expand Up @@ -142,7 +168,15 @@ QgsRasterBlock * QgsRasterDataProvider::block( int theBandNo, QgsRectangle cons

block->setIsNoData();

QgsRasterBlock *tmpBlock = new QgsRasterBlock( dataType( theBandNo ), tmpWidth, tmpHeight, noDataValue( theBandNo ) );
QgsRasterBlock *tmpBlock;
if ( srcHasNoDataValue( theBandNo ) && useSrcNoDataValue( theBandNo ) )
{
tmpBlock = new QgsRasterBlock( dataType( theBandNo ), tmpWidth, tmpHeight, srcNoDataValue( theBandNo ) );
}
else
{
tmpBlock = new QgsRasterBlock( dataType( theBandNo ), tmpWidth, tmpHeight );
}

readBlock( theBandNo, tmpExtent, tmpWidth, tmpHeight, tmpBlock->data() );

Expand Down Expand Up @@ -286,7 +320,7 @@ QgsRasterIdentifyResult QgsRasterDataProvider::identify( const QgsPoint & thePoi
// Outside the raster
for ( int bandNo = 1; bandNo <= bandCount(); bandNo++ )
{
results.insert( bandNo, noDataValue( bandNo ) );
results.insert( bandNo, QVariant() );
}
return QgsRasterIdentifyResult( QgsRasterDataProvider::IdentifyFormatValue, results );
}
Expand Down Expand Up @@ -320,14 +354,22 @@ QgsRasterIdentifyResult QgsRasterDataProvider::identify( const QgsPoint & thePoi
{
QgsRasterBlock * myBlock = block( i, pixelExtent, 1, 1 );

double value = noDataValue( i );
if ( myBlock ) value = myBlock->value( 0 );
if ( myBlock )
{
double value = myBlock->value( 0 );

results.insert( i, value );
results.insert( i, value );
delete myBlock;
}
else
{
results.insert( i, QVariant() );
}
}
return QgsRasterIdentifyResult( QgsRasterDataProvider::IdentifyFormatValue, results );
}

#if 0
QMap<QString, QString> QgsRasterDataProvider::identify( const QgsPoint & thePoint, const QgsRectangle &theExtent, int theWidth, int theHeight )
{
QMap<QString, QString> results;
Expand Down Expand Up @@ -387,6 +429,7 @@ QMap<QString, QString> QgsRasterDataProvider::identify( const QgsPoint & thePoin

return results;
}
#endif

QString QgsRasterDataProvider::lastErrorFormat()
{
Expand Down
18 changes: 15 additions & 3 deletions src/core/raster/qgsrasterdataprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
/** Value representing currentno data.
* WARNING: this value returned by this method is not constant. It may change
* for example if user disable use of source no data value. */
virtual double noDataValue( int bandNo ) const;
//virtual double noDataValue( int bandNo ) const;

/** Value representing no data value. */
virtual double srcNoDataValue( int bandNo ) const { return mSrcNoDataValue.value( bandNo -1 ); }
Expand Down Expand Up @@ -351,7 +351,7 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
virtual QgsRasterIdentifyResult identify( const QgsPoint & thePoint, IdentifyFormat theFormat, const QgsRectangle &theExtent = QgsRectangle(), int theWidth = 0, int theHeight = 0 );

// TODO: remove in 2.0
QMap<QString, QString> identify( const QgsPoint & thePoint, const QgsRectangle &theExtent = QgsRectangle(), int theWidth = 0, int theHeight = 0 );
//QMap<QString, QString> identify( const QgsPoint & thePoint, const QgsRectangle &theExtent = QgsRectangle(), int theWidth = 0, int theHeight = 0 );

/**
* \brief Returns the caption error text for the last error in this provider
Expand Down Expand Up @@ -490,24 +490,36 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
@note: this member has been added in version 1.2*/
int mDpi;

/** Source no data value is available and is set to be used or internal no data
* is available. Used internally only */
//bool hasNoDataValue ( int theBandNo );

/** \brief Cell value representing original source no data. e.g. -9999, indexed from 0 */
QList<double> mSrcNoDataValue;

/** \brief Source nodata value exist */
/** \brief Source no data value exists. */
QList<bool> mSrcHasNoDataValue;

/** \brief No data value exists. May exist even if source no data value does not
* exist, for example, if data type is wide enough a large number is used as no data. */
//QList<bool> mHasNoDataValue;

/** \brief Use source nodata value. User can disable usage of source nodata
* value as nodata. It may happen that a value is wrongly given by GDAL
* as nodata (e.g. 0) and it has to be treated as regular value. */
QList<bool> mUseSrcNoDataValue;

/** \brief Internal no data value was set and is used. */
//QList<bool> mHasInternalNoDataValue;

/** \brief Internal value representing nodata. Indexed from 0.
* This values is used to represent nodata if no source nodata is available
* or if the source nodata use was disabled.
* It would be also possible to use wider type only if nodata is really necessary
* in following interfaces, but that could make difficult to subclass
* QgsRasterInterface.
*/
// TODO: probably remove (move to providers if used)
QList<double> mInternalNoDataValue;

/** \brief Flag indicating if the nodatavalue is valid*/
Expand Down
30 changes: 13 additions & 17 deletions src/core/raster/qgsrasterinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ QgsRasterInterface::~QgsRasterInterface()
{
}

bool QgsRasterInterface::isNoDataValue( int bandNo, double value ) const
{
return QgsRasterBlock::isNoDataValue( value, noDataValue( bandNo ) );
}
//bool QgsRasterInterface::isNoDataValue( int bandNo, double value ) const
//{
// return QgsRasterBlock::isNoDataValue( value, noDataValue( bandNo ) );
//}

void QgsRasterInterface::initStatistics( QgsRasterBandStats &theStatistics,
int theBandNo,
Expand Down Expand Up @@ -200,16 +200,15 @@ QgsRasterBandStats QgsRasterInterface::bandStatistics( int theBandNo,
// Collect the histogram counts.
for ( size_t i = 0; i < (( size_t ) myBlockHeight ) * myBlockWidth; i++ )
{
//double myValue = readValue( myData, myDataType, myX + ( myY * myBlockWidth ) );
double myValue = blk->value( i );
//QgsDebugMsg ( QString ( "%1 %2 value %3" ).arg (myX).arg(myY).arg( myValue ) );

// TODO: user nodata
if ( isNoDataValue( theBandNo, myValue ) )
if ( blk->isNoData( i ) )
{
continue; // NULL
}

//double myValue = readValue( myData, myDataType, myX + ( myY * myBlockWidth ) );
double myValue = blk->value( i );
//QgsDebugMsg ( QString ( "%1 %2 value %3" ).arg (myX).arg(myY).arg( myValue ) );

myRasterBandStats.sum += myValue;
myRasterBandStats.elementCount++;

Expand Down Expand Up @@ -487,16 +486,13 @@ QgsRasterHistogram QgsRasterInterface::histogram( int theBandNo,
// Collect the histogram counts.
for ( size_t i = 0; i < (( size_t ) myBlockHeight ) * myBlockWidth; i++ )
{
//double myValue = readValue( myData, myDataType, myX + ( myY * myBlockWidth ) );
double myValue = blk->value( i );

//QgsDebugMsg ( QString ( "%1 %2 value %3" ).arg (myX).arg(myY).arg( myValue ) );

// TODO: user defined nodata values
if ( isNoDataValue( theBandNo, myValue ) )
if ( blk->isNoData( i ) )
{
continue; // NULL
}
double myValue = blk->value( i );

//QgsDebugMsg ( QString ( "%1 %2 value %3" ).arg (myX).arg(myY).arg( myValue ) );

int myBinIndex = static_cast <int>( qFloor(( myValue - myMinimum ) / myBinSize ) ) ;
//QgsDebugMsg( QString( "myValue = %1 myBinIndex = %2" ).arg( myValue ).arg( myBinIndex ) );
Expand Down
10 changes: 8 additions & 2 deletions src/core/raster/qgsrasterinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,18 +123,24 @@ class CORE_EXPORT QgsRasterInterface
return tr( "Band" ) + QString( " %1" ) .arg( theBandNumber, 1 + ( int ) log10(( float ) bandCount() ), 10, QChar( '0' ) );
}

/** True if the interface has a no data value.
* It does not change during the life of the interface.
* @param bandNo band number
* @return true if the interface has a no data value */
//virtual bool hasNoDataValue( int bandNo ) const { Q_UNUSED( bandNo ); return false; }

/** Return no data value for specific band. Each band/provider must have
* no data value, if there is no one set in original data, provider decides one
* possibly using wider data type.
* @param bandNo band number
* @return No data value */
virtual double noDataValue( int bandNo ) const { Q_UNUSED( bandNo ); return std::numeric_limits<double>::quiet_NaN(); }
//virtual double noDataValue( int bandNo ) const { Q_UNUSED( bandNo ); return std::numeric_limits<double>::quiet_NaN(); }

/** Test if value is nodata for specific band
* @param bandNo band number
* @param value tested value
* @return true if value is nodata */
virtual bool isNoDataValue( int bandNo, double value ) const;
//virtual bool isNoDataValue( int bandNo, double value ) const;

/** Read block of data using given extent and size.
* Returns pointer to data.
Expand Down
30 changes: 0 additions & 30 deletions src/core/raster/qgsrasterlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1461,36 +1461,6 @@ double QgsRasterLayer::rasterUnitsPerPixel()
return 1;
}

#if 0
void QgsRasterLayer::resetNoDataValue()
{
mNoDataValue = std::numeric_limits<int>::max();
mValidNoDataValue = false;
if ( mDataProvider != NULL && mDataProvider->bandCount() > 0 )
{
// TODO: add 'has null value' to capabilities
#if 0
int myRequestValid;
myRequestValid = 1;
double myValue = mDataProvider->noDataValue();

if ( 0 != myRequestValid )
{
setNoDataValue( myValue );
}
else
{
setNoDataValue( -9999.0 );
mValidNoDataValue = false;

}
#endif
setNoDataValue( mDataProvider->noDataValue() );
mValidNoDataValue = mDataProvider->isNoDataValueValid();
}
}
#endif

void QgsRasterLayer::init()
{
// keep this until mGeoTransform occurences are removed!
Expand Down
22 changes: 14 additions & 8 deletions src/core/raster/qgsrasterprojector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -698,17 +698,15 @@ QgsRasterBlock * QgsRasterProjector::block( int bandNo, QgsRectangle const & ex
{
QgsDebugMsg( QString( "extent:\n%1" ).arg( extent.toString() ) );
QgsDebugMsg( QString( "width = %1 height = %2" ).arg( width ).arg( height ) );
QgsRasterBlock *outputBlock = new QgsRasterBlock();
if ( !mInput )
{
QgsDebugMsg( "Input not set" );
return outputBlock;
return new QgsRasterBlock();
}

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

Expand All @@ -724,7 +722,7 @@ QgsRasterBlock * QgsRasterProjector::block( int bandNo, QgsRectangle const & ex
if ( srcRows() <= 0 || srcCols() <= 0 )
{
QgsDebugMsg( "Zero srcRows or srcCols" );
return outputBlock;
return new QgsRasterBlock();
}

//void * inputData = mInput->block( bandNo, srcExtent(), srcCols(), srcRows() );
Expand All @@ -733,18 +731,26 @@ QgsRasterBlock * QgsRasterProjector::block( int bandNo, QgsRectangle const & ex
{
QgsDebugMsg( "No raster data!" );
delete inputBlock;
return outputBlock;
return new QgsRasterBlock();
}

size_t pixelSize = QgsRasterBlock::typeSize( mInput->dataType( bandNo ) );

if ( !outputBlock->reset( mInput->dataType( bandNo ), width, height ) )
QgsRasterBlock *outputBlock;
if ( inputBlock->hasNoDataValue() )
{
outputBlock = new QgsRasterBlock( inputBlock->dataType(), width, height, inputBlock->noDataValue() );
}
else
{
outputBlock = new QgsRasterBlock( inputBlock->dataType(), width, height );
}
if ( !outputBlock->isValid() )
{
QgsDebugMsg( "Cannot reset block" );
QgsDebugMsg( "Cannot create block" );
delete inputBlock;
return outputBlock;
}
outputBlock->setNoDataValue( mInput->noDataValue( bandNo ) );

// TODO: fill by no data or transparent

Expand Down
3 changes: 2 additions & 1 deletion src/core/raster/qgsrasterrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ bool QgsRasterRenderer::usesTransparency( ) const
return true;
}
// TODO: nodata per band
return ( mAlphaBand > 0 || ( mRasterTransparency && !mRasterTransparency->isEmpty( mInput->noDataValue( 1 ) ) ) || !doubleNear( mOpacity, 1.0 ) );
//return ( mAlphaBand > 0 || ( mRasterTransparency && !mRasterTransparency->isEmpty( mInput->noDataValue( 1 ) ) ) || !doubleNear( mOpacity, 1.0 ) );
return ( mAlphaBand > 0 || ( mRasterTransparency && !mRasterTransparency->isEmpty() ) || !doubleNear( mOpacity, 1.0 ) );
}

void QgsRasterRenderer::setRasterTransparency( QgsRasterTransparency* t )
Expand Down
16 changes: 0 additions & 16 deletions src/core/raster/qgsrasterrendererregistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,27 +275,11 @@ 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.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
9 changes: 9 additions & 0 deletions src/core/raster/qgsrastertransparency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,11 @@ int QgsRasterTransparency::alphaValue( double theRedValue, double theGreenValue,
}

// TODO: nodata per band
#if 0
bool QgsRasterTransparency::isEmpty( double nodataValue ) const
{
// This was probably used when no data value was added by default to transparency list
// that is not true anamore
return (
( mTransparentSingleValuePixelList.isEmpty() ||
( mTransparentSingleValuePixelList.size() == 1 &&
Expand All @@ -194,6 +197,12 @@ bool QgsRasterTransparency::isEmpty( double nodataValue ) const
doubleNear( mTransparentThreeValuePixelList.at( 0 ).green, nodataValue ) &&
doubleNear( mTransparentThreeValuePixelList.at( 0 ).blue, nodataValue ) ) ) );
}
#endif

bool QgsRasterTransparency::isEmpty( ) const
{
return mTransparentSingleValuePixelList.isEmpty();
}

void QgsRasterTransparency::writeXML( QDomDocument& doc, QDomElement& parentElem ) const
{
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 @@ -78,7 +78,8 @@ class CORE_EXPORT QgsRasterTransparency
int alphaValue( double, double, double, int theGlobalTransparency = 255 ) const;

/**True if there are no entries in the pixel lists except the nodata value*/
bool isEmpty( double nodataValue ) const;
//bool isEmpty( double nodataValue ) const;
bool isEmpty( ) const;

void writeXML( QDomDocument& doc, QDomElement& parentElem ) const;

Expand Down
5 changes: 2 additions & 3 deletions src/core/raster/qgssinglebandgrayrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,12 @@ QgsRasterBlock* QgsSingleBandGrayRenderer::block( int bandNo, QgsRectangle cons
QRgb myDefaultColor = NODATA_COLOR;
for ( size_t i = 0; i < ( size_t )width*height; i++ )
{
double grayVal = inputBlock->value( i );

if ( inputBlock->isNoDataValue( grayVal ) )
if ( inputBlock->isNoData( i ) )
{
outputBlock->setColor( i, myDefaultColor );
continue;
}
double grayVal = inputBlock->value( i );

double currentAlpha = mOpacity;
if ( mRasterTransparency )
Expand Down
4 changes: 2 additions & 2 deletions src/core/raster/qgssinglebandpseudocolorrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,12 @@ QgsRasterBlock* QgsSingleBandPseudoColorRenderer::block( int bandNo, QgsRectangl

for ( size_t i = 0; i < ( size_t )width*height; i++ )
{
double val = inputBlock->value( i );
if ( mInput->isNoDataValue( mBand, val ) )
if ( inputBlock->isNoData( i ) )
{
outputBlock->setColor( i, myDefaultColor );
continue;
}
double val = inputBlock->value( i );
int red, green, blue;
if ( !mShader->shade( val, &red, &green, &blue ) )
{
Expand Down
4 changes: 2 additions & 2 deletions src/gui/qgsmaptoolidentify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -427,14 +427,14 @@ bool QgsMapToolIdentify::identifyRasterLayer( QList<IdentifyResult> *results, Qg
{
foreach ( int bandNo, values.keys() )
{
double value = values.value( bandNo ).toDouble();
QString valueString;
if ( dprovider->isNoDataValue( bandNo, value ) )
if ( values.value( bandNo ).isNull() )
{
valueString = tr( "no data" );
}
else
{
double value = values.value( bandNo ).toDouble();
valueString = QgsRasterBlock::printValue( value );
}
attributes.insert( dprovider->generateBandName( bandNo ), valueString );
Expand Down
17 changes: 11 additions & 6 deletions src/mapserver/qgswmsserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "qgsmaprenderer.h"
#include "qgsmaptopixel.h"
#include "qgsproject.h"
#include "qgsrasteridentifyresult.h"
#include "qgsrasterlayer.h"
#include "qgsscalecalculator.h"
#include "qgscoordinatereferencesystem.h"
Expand Down Expand Up @@ -1374,24 +1375,28 @@ int QgsWMSServer::featureInfoFromRasterLayer( QgsRasterLayer* layer,

QgsDebugMsg( QString( "infoPoint: %1 %2" ).arg( infoPoint->x() ).arg( infoPoint->y() ) );

QMap<QString, QString> attributes;
if ( !( layer->dataProvider()->capabilities() & QgsRasterDataProvider::IdentifyValue ) )
{
return 1;
}
QMap<int, QVariant> attributes;
// use context extent, width height (comes with request) to use WCS cache
// We can only use context if raster is not reprojected, otherwise it is difficult
// to guess correct source resolution
if ( mMapRenderer->hasCrsTransformEnabled() && layer->dataProvider()->crs() != mMapRenderer->destinationCrs() )
{
attributes = layer->dataProvider()->identify( *infoPoint );
attributes = layer->dataProvider()->identify( *infoPoint, QgsRasterDataProvider::IdentifyFormatValue ).results();
}
else
{
attributes = layer->dataProvider()->identify( *infoPoint, mMapRenderer->extent(), mMapRenderer->outputSize().width(), mMapRenderer->outputSize().height() );
attributes = layer->dataProvider()->identify( *infoPoint, QgsRasterDataProvider::IdentifyFormatValue, mMapRenderer->extent(), mMapRenderer->outputSize().width(), mMapRenderer->outputSize().height() ).results();
}

for ( QMap<QString, QString>::const_iterator it = attributes.constBegin(); it != attributes.constEnd(); ++it )
for ( QMap<int, QVariant>::const_iterator it = attributes.constBegin(); it != attributes.constEnd(); ++it )
{
QDomElement attributeElement = infoDocument.createElement( "Attribute" );
attributeElement.setAttribute( "name", it.key() );
attributeElement.setAttribute( "value", it.value() );
attributeElement.setAttribute( "name", layer->bandName( it.key() ) );
attributeElement.setAttribute( "value", QString::number( it.value().toDouble() ) );
layerElement.appendChild( attributeElement );
}
return 0;
Expand Down
37 changes: 32 additions & 5 deletions src/providers/gdal/qgsgdalprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -364,13 +364,26 @@ QImage* QgsGdalProvider::draw( QgsRectangle const & viewExtent, int pixelWidth,

QgsRasterBlock* QgsGdalProvider::block( int theBandNo, const QgsRectangle &theExtent, int theWidth, int theHeight )
{
QgsRasterBlock *block = new QgsRasterBlock( dataType( theBandNo ), theWidth, theHeight, noDataValue( theBandNo ) );
//QgsRasterBlock *block = new QgsRasterBlock( dataType( theBandNo ), theWidth, theHeight, noDataValue( theBandNo ) );
QgsRasterBlock *block;
if ( srcHasNoDataValue( theBandNo ) && useSrcNoDataValue( theBandNo ) )
{
block = new QgsRasterBlock( dataType( theBandNo ), theWidth, theHeight, srcNoDataValue( theBandNo ) );
}
else
{
block = new QgsRasterBlock( dataType( theBandNo ), theWidth, theHeight );
}

if ( block->isEmpty() )
{
return block;
}

if ( !mExtent.contains( theExtent ) )
{
block->setIsNoData();
}
readBlock( theBandNo, theExtent, theWidth, theHeight, block->data() );
block->applyNodataValues( userNoDataValue( theBandNo ) );
return block;
Expand Down Expand Up @@ -407,6 +420,8 @@ void QgsGdalProvider::readBlock( int theBandNo, QgsRectangle const & theExtent,

int dataSize = dataTypeSize( theBandNo );

// moved to block()
#if 0
if ( !mExtent.contains( theExtent ) )
{
// fill with null values
Expand All @@ -419,6 +434,7 @@ void QgsGdalProvider::readBlock( int theBandNo, QgsRectangle const & theExtent,
block += dataSize;
}
}
#endif

QgsRectangle myRasterExtent = theExtent.intersect( &mExtent );
if ( myRasterExtent.isEmpty() )
Expand Down Expand Up @@ -885,7 +901,7 @@ QgsRasterIdentifyResult QgsGdalProvider::identify( const QgsPoint & thePoint, Id
// Outside the raster
for ( int bandNo = 1; bandNo <= bandCount(); bandNo++ )
{
results.insert( bandNo, noDataValue( bandNo ) );
results.insert( bandNo, QVariant() ); // null QVariant represents no data
}
return QgsRasterIdentifyResult( QgsRasterDataProvider::IdentifyFormatValue, results );
}
Expand Down Expand Up @@ -955,6 +971,12 @@ QgsRasterIdentifyResult QgsGdalProvider::identify( const QgsPoint & thePoint, Id

double value = myBlock->value( r, c );

if (( srcHasNoDataValue( i ) && useSrcNoDataValue( i ) &&
( qIsNaN( value ) || doubleNear( value, srcNoDataValue( i ) ) ) ) ||
( QgsRasterRange::contains( value, userNoDataValue( i ) ) ) )
{
results.insert( i, QVariant() ); // null QVariant represents no data
}
results.insert( i, value );
}
return QgsRasterIdentifyResult( QgsRasterDataProvider::IdentifyFormatValue, results );
Expand Down Expand Up @@ -2408,6 +2430,8 @@ void QgsGdalProvider::initBaseDataset()
// disabled by user, in that case we need another value to be used for nodata
// (for reprojection for example) -> always internaly represent as wider type
// with mInternalNoDataValue in reserve.
// Not used
#if 0
int myInternalGdalDataType = myGdalDataType;
double myInternalNoDataValue = 123;
switch ( srcDataType( i ) )
Expand Down Expand Up @@ -2437,9 +2461,12 @@ void QgsGdalProvider::initBaseDataset()
// NaN should work well
myInternalNoDataValue = std::numeric_limits<double>::quiet_NaN();
}
mGdalDataType.append( myInternalGdalDataType );
mInternalNoDataValue.append( myInternalNoDataValue );
QgsDebugMsg( QString( "mInternalNoDataValue[%1] = %2" ).arg( i - 1 ).arg( mInternalNoDataValue[i-1] ) );
#endif
//mGdalDataType.append( myInternalGdalDataType );

mGdalDataType.append( myGdalDataType );
//mInternalNoDataValue.append( myInternalNoDataValue );
//QgsDebugMsg( QString( "mInternalNoDataValue[%1] = %2" ).arg( i - 1 ).arg( mInternalNoDataValue[i-1] ) );
}

mValid = true;
Expand Down
10 changes: 5 additions & 5 deletions src/providers/grass/qgsgrassgislib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -605,9 +605,9 @@ int QgsGrassGisLib::G_open_raster_new( const char *name, RASTER_MAP_TYPE wr_type
}

raster.band = 1;
double noDataValue = noDataValueForGrassType( wr_type );
QgsDebugMsg( QString( "noDataValue = %1" ).arg(( int )noDataValue ) );
raster.provider->setNoDataValue( raster.band, noDataValue );
raster.noDataValue = noDataValueForGrassType( wr_type );
QgsDebugMsg( QString( "noDataValue = %1" ).arg(( int )raster.noDataValue ) );
raster.provider->setNoDataValue( raster.band, raster.noDataValue );

raster.fd = mRasters.size();
mRasters.insert( raster.fd, raster );
Expand Down Expand Up @@ -934,8 +934,8 @@ int QgsGrassGisLib::putRasterRow( int fd, const void *buf, RASTER_MAP_TYPE data_
//QgsDebugMsg( QString("inputType = %1").arg(inputType) );
//QgsDebugMsg( QString("provider->dataType = %1").arg( rast.provider->dataType( rast.band ) ) );

double noDataValue = rast.provider->noDataValue( rast.band );
QgsRasterBlock block( inputType, mColumns, 1, noDataValue );
//double noDataValue = rast.provider->noDataValue( rast.band );
QgsRasterBlock block( inputType, mColumns, 1, rast.noDataValue );

memcpy( block.bits( 0 ), buf, QgsRasterBlock::typeSize( inputType )*mColumns );
block.convert( rast.provider->dataType( rast.band ) );
Expand Down
2 changes: 1 addition & 1 deletion src/providers/grass/qgsgrassgislib.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class GRASS_LIB_EXPORT QgsGrassGisLib
int band;
int row; // next row to be written
Raster(): provider( 0 ), projector( 0 ), input( 0 ), band( 1 ), row( 0 ) {}

double noDataValue; // output no data value
};

static QgsGrassGisLib* instance();
Expand Down
14 changes: 10 additions & 4 deletions src/providers/grass/qgsgrassrasterprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,9 @@ QgsRasterIdentifyResult QgsGrassRasterProvider::identify( const QgsPoint & thePo
Q_UNUSED( theHeight );
QgsDebugMsg( "Entered" );
QMap<int, QVariant> results;
QMap<int, QVariant> noDataResults;
noDataResults.insert( 1, QVariant() );
QgsRasterIdentifyResult noDataResult( IdentifyFormatValue, results );

if ( theFormat != IdentifyFormatValue )
{
Expand All @@ -449,8 +452,7 @@ QgsRasterIdentifyResult QgsGrassRasterProvider::identify( const QgsPoint & thePo

if ( !extent().contains( thePoint ) )
{
results.insert( 1, noDataValue( 1 ) );
return QgsRasterIdentifyResult( IdentifyFormatValue, results );
return noDataResult;
}

// TODO: use doubles instead of strings
Expand All @@ -465,13 +467,17 @@ QgsRasterIdentifyResult QgsGrassRasterProvider::identify( const QgsPoint & thePo
return QgsRasterIdentifyResult( ERROR( tr( "Cannot read data" ) ) );
}

if ( qIsNaN( value ) ) value = noDataValue( 1 );
// no data?
if ( qIsNaN( value ) || doubleNear( value, mInternalNoDataValue[0] ) )
{
return noDataResult;
}

// Apply user no data
QgsRasterRangeList myNoDataRangeList = userNoDataValue( 1 );
if ( QgsRasterRange::contains( value, myNoDataRangeList ) )
{
value = noDataValue( 1 );
return noDataResult;
}

results.insert( 1, value );
Expand Down
29 changes: 18 additions & 11 deletions src/providers/wcs/qgswcsprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,8 @@ QgsWcsProvider::QgsWcsProvider( QString const &uri )
// disabled by user, in that case we need another value to be used for nodata
// (for reprojection for example) -> always internaly represent as wider type
// with mInternalNoDataValue in reserve.
// No retyping, no internal values for now
#if 0
int myInternalGdalDataType = myGdalDataType;
double myInternalNoDataValue;
switch ( srcDataType( i ) )
Expand Down Expand Up @@ -350,12 +352,14 @@ QgsWcsProvider::QgsWcsProvider( QString const &uri )
mGdalDataType.append( myInternalGdalDataType );
mInternalNoDataValue.append( myInternalNoDataValue );
QgsDebugMsg( QString( "mInternalNoDataValue[%1] = %2" ).arg( i - 1 ).arg( mInternalNoDataValue[i-1] ) );
#endif
mGdalDataType.append( myGdalDataType );

// TODO: what to do if null values from DescribeCoverage differ?
if ( !mCoverageSummary.nullValues.contains( myNoDataValue ) )
{
QgsDebugMsg( QString( "noDataValue %1 is missing in nullValues from CoverageDescription" ).arg( myNoDataValue ) );
}
//if ( !mCoverageSummary.nullValues.contains( myNoDataValue ) )
//{
// QgsDebugMsg( QString( "noDataValue %1 is missing in nullValues from CoverageDescription" ).arg( myNoDataValue ) );
//}

QgsDebugMsg( QString( "mSrcGdalDataType[%1] = %2" ).arg( i - 1 ).arg( mSrcGdalDataType[i-1] ) );
QgsDebugMsg( QString( "mGdalDataType[%1] = %2" ).arg( i - 1 ).arg( mGdalDataType[i-1] ) );
Expand Down Expand Up @@ -1612,7 +1616,7 @@ QgsRasterIdentifyResult QgsWcsProvider::identify( const QgsPoint & thePoint, Ide
// Outside the raster
for ( int i = 1; i <= bandCount(); i++ )
{
results.insert( i, noDataValue( i ) );
results.insert( i, QVariant() );
}
return QgsRasterIdentifyResult( IdentifyFormatValue, results );
}
Expand Down Expand Up @@ -1694,14 +1698,17 @@ QgsRasterIdentifyResult QgsWcsProvider::identify( const QgsPoint & thePoint, Ide
return QgsRasterIdentifyResult( ERROR( tr( "RasterIO error: " ) + QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
}

// Apply user no data
QgsRasterRangeList myNoDataRangeList = userNoDataValue( i );
if ( QgsRasterRange::contains( value, myNoDataRangeList ) )
// Apply no data and user no data
if (( srcHasNoDataValue( i ) && useSrcNoDataValue( i ) &&
( qIsNaN( value ) || doubleNear( value, srcNoDataValue( i ) ) ) ) ||
( QgsRasterRange::contains( value, userNoDataValue( i ) ) ) )
{
value = noDataValue( i );
results.insert( i, QVariant() );
}
else
{
results.insert( i, value );
}

results.insert( i, value );
}

return QgsRasterIdentifyResult( IdentifyFormatValue, results );
Expand Down