Skip to content
Permalink
Browse files

reimplemented user defined raster no data values

  • Loading branch information
blazek committed Sep 18, 2012
1 parent babc12a commit 3032f71666e12ac5ab6a843a5aee6627052792ef
@@ -542,9 +542,22 @@ void QgsRasterLayerProperties::sync()
}

//add current NoDataValue to NoDataValue line edit
if ( mRasterLayer->isNoDataValueValid() )
// TODO: should be per band
// TODO: no data ranges
if ( mRasterLayer->dataProvider()->srcHasNoDataValue( 1 ) )
{
lblSrcNoDataValue->setText( QgsRasterInterface::printValue( mRasterLayer->dataProvider()->noDataValue( 1 ) ) );
}
else
{
lblSrcNoDataValue->setText( tr( "not defined" ) );
}

QList<QgsRasterInterface::Range> noDataRangeList = mRasterLayer->dataProvider()->userNoDataValue( 1 );
QgsDebugMsg( QString( "noDataRangeList.size = %1" ).arg( noDataRangeList.size() ) );
if ( noDataRangeList.size() > 0 )
{
leNoDataValue->insert( QString::number( mRasterLayer->noDataValue(), 'g' ) );
leNoDataValue->insert( QgsRasterInterface::printValue( noDataRangeList.value( 0 ).min ) );
}
else
{
@@ -650,11 +663,18 @@ void QgsRasterLayerProperties::apply()
bool myDoubleOk = false;
if ( "" != leNoDataValue->text() )
{
QList<QgsRasterInterface::Range> myNoDataRangeList;
double myNoDataValue = leNoDataValue->text().toDouble( &myDoubleOk );
if ( myDoubleOk )
{
mRasterLayer->setNoDataValue( myNoDataValue );
QgsRasterInterface::Range myNoDataRange;
myNoDataRange.min = myNoDataValue;
myNoDataRange.max = myNoDataValue;

myNoDataRangeList << myNoDataRange;
}
mRasterLayer->dataProvider()->setUserNoDataValue( 1, myNoDataRangeList );
}

//set renderer from widget
@@ -1551,6 +1571,7 @@ void QgsRasterLayerProperties::on_pbnSaveStyleAs_clicked()
settings.setValue( "style/lastStyleDir", QFileInfo( outputFileName ).absolutePath() );
}

#if 0
void QgsRasterLayerProperties::on_btnResetNull_clicked( )
{
//If reset NoDataValue is checked do this first, will ignore what ever is in the LineEdit
@@ -1564,6 +1585,7 @@ void QgsRasterLayerProperties::on_btnResetNull_clicked( )
leNoDataValue->clear();
}
}
#endif

void QgsRasterLayerProperties::toggleBuildPyramidsButton()
{
@@ -76,7 +76,7 @@ class QgsRasterLayerProperties : public QDialog, private Ui::QgsRasterLayerPrope
void on_pbnRemoveSelectedRow_clicked();
/** \brief slot executed when the single band radio button is pressed. */
/** \brief slot executed when the reset null value to file default icon is selected */
void on_btnResetNull_clicked( );
//void on_btnResetNull_clicked( );

void pixelSelected( const QgsPoint& );
/** \brief slot executed when the transparency level changes. */
@@ -537,6 +537,28 @@ void QgsProjectFileTransform::transform1800to1900()
void QgsProjectFileTransform::convertRasterProperties( QDomDocument& doc, QDomNode& parentNode,
QDomElement& rasterPropertiesElem, QgsRasterLayer* rlayer )
{
//no data
//TODO: We would need to set no data on all bands, but we dont know number of bands here
QDomNode noDataNode = rasterPropertiesElem.namedItem( "mNoDataValue" );
QDomElement noDataElement = noDataNode.toElement();
if ( !noDataElement.text().isEmpty() )
{
QgsDebugMsg( "mNoDataValue = " + noDataElement.text() );
QDomElement noDataElem = doc.createElement( "noData" );

QDomElement noDataRangeList = doc.createElement( "noDataRangeList" );
noDataRangeList.setAttribute( "bandNo", 1 );

QDomElement noDataRange = doc.createElement( "noDataRange" );
noDataRange.setAttribute( "min", noDataElement.text() );
noDataRange.setAttribute( "max", noDataElement.text() );
noDataRangeList.appendChild( noDataRange );

noDataElem.appendChild( noDataRangeList );

parentNode.appendChild( noDataElem );
}

QDomElement rasterRendererElem = doc.createElement( "rasterrenderer" );
//convert general properties

@@ -106,8 +106,28 @@ void * QgsRasterDataProvider::readBlock( int bandNo, QgsRectangle const & exten
QgsDebugMsg( QString( "Couldn't allocate data memory of % bytes" ).arg( dataTypeSize( bandNo ) * width * height ) );
return 0;
}

readBlock( bandNo, extent, width, height, data );

// apply user no data values
// TODO: there are other readBlock methods where no data are not applied
QList<QgsRasterInterface::Range> myNoDataRangeList = userNoDataValue( bandNo );
if ( !myNoDataRangeList.isEmpty() )
{
QgsRasterInterface::DataType type = dataType( bandNo );
double myNoDataValue = noDataValue( bandNo );
size_t size = width * height;
for ( size_t i = 0; i < size; i++ )
{
double value = readValue( data, type, i );

if ( QgsRasterInterface::valueInRange( value, myNoDataRangeList ) )
{
writeValue( data, type, i, myNoDataValue );
}
}
}

return data;
}

@@ -1046,4 +1066,36 @@ double QgsRasterDataProvider::readValue( void *data, int type, int index )
return mValidNoDataValue ? noDataValue() : 0.0;
}

void QgsRasterDataProvider::setUserNoDataValue( int bandNo, QList<QgsRasterInterface::Range> noData )
{
//if ( bandNo > bandCount() ) return;
if ( bandNo >= mUserNoDataValue.size() )
{
for ( int i = mUserNoDataValue.size(); i < bandNo; i++ )
{
mUserNoDataValue.append( QList<QgsRasterInterface::Range>() );
}
}
QgsDebugMsg( QString( "set %1 band %1 no data ranges" ).arg( noData.size() ) );

if ( mUserNoDataValue[bandNo-1] != noData )
{
// Clear statistics
int i = 0;
while ( i < mStatistics.size() )
{
if ( mStatistics.value( i ).bandNumber == bandNo )
{
mStatistics.removeAt( i );
mHistograms.removeAt( i );
}
else
{
i++;
}
}
mUserNoDataValue[bandNo-1] = noData;
}
}

// ENDS
@@ -300,6 +300,18 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
/** value representing null data */
virtual double noDataValue() const { return 0; }

/** Value representing original source no data. This value my differ from
* if it was overwritten by user */
virtual double noDataValue( int bandNo ) const { return mNoDataValue.value( bandNo -1 ); }

/** Value representing no data value. */
//virtual double srcNoDataValue( int bandNo ) const { return mSrcNoDataValue.value(bandNo-1); }

virtual void setUserNoDataValue( int bandNo, QList<QgsRasterInterface::Range> noData );

/** Get list of user no data value ranges */
virtual QList<QgsRasterInterface::Range> userNoDataValue( int bandNo ) const { return mUserNoDataValue.value( bandNo -1 ); }

virtual double minimumValue( int bandNo ) const { Q_UNUSED( bandNo ); return 0; }
virtual double maximumValue( int bandNo ) const { Q_UNUSED( bandNo ); return 0; }

@@ -590,12 +602,25 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
@note: this member has been added in version 1.2*/
int mDpi;

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

/** \brief Cell value representing no data. e.g. -9999, indexed from 0.
* Currently the values is the same as in mSrcNoDataValue, but a possibility
* to overwrite/disable original no data value could be added (?), in that
* case this value would be different. But original source no data value
* cannot be disabled without add additional user nodata (there would not be
* any guaranteed free nodata value available (to represent nodata in
* reprojection for example) */
QList<double> mNoDataValue;

/** \brief Flag indicating if the nodatavalue is valid*/
bool mValidNoDataValue;

/** \brief List of lists of user defined additional no data values
* for each band, indexed from 0 */
QList< QList<QgsRasterInterface::Range> > mUserNoDataValue;

QgsRectangle mExtent;

/** \brief List of cached statistics, all bands mixed */
@@ -60,6 +60,16 @@ class CORE_EXPORT QgsRasterInterface
TypeCount = 14 /* maximum type # + 1 */
};

struct Range
{
double min;
double max;
inline bool operator==( const Range &o ) const
{
return min == o.min && max == o.max;
}
};

QgsRasterInterface( QgsRasterInterface * input = 0 );

virtual ~QgsRasterInterface();
@@ -220,6 +230,12 @@ class CORE_EXPORT QgsRasterInterface
inline static double readValue( void *data, QgsRasterInterface::DataType type, int index );
inline static void writeValue( void *data, QgsRasterInterface::DataType type, int index, double value );

/** \brief Test if value is within the list of ranges
* @param value value
* @param rangeList list of ranges
* @return true if value is in at least one of ranges */
inline static bool valueInRange( double value, QList<QgsRasterInterface::Range> rangeList );

private:
// Last rendering cumulative (this and all preceding interfaces) times, from index 1
QVector<double> mTime;
@@ -308,6 +324,20 @@ inline void QgsRasterInterface::writeValue( void *data, QgsRasterInterface::Data
}
}

inline bool QgsRasterInterface::valueInRange( double value, QList<QgsRasterInterface::Range> rangeList )
{
foreach ( QgsRasterInterface::Range range, rangeList )
{
if (( value >= range.min && value <= range.max ) ||
doubleNear( value, range.min ) ||
doubleNear( value, range.max ) )
{
return true;
}
}
return false;
}

#endif


@@ -1687,6 +1687,7 @@ QgsRasterDataProvider* QgsRasterLayer::loadProvider( QString theProviderKey, QSt
*/
void QgsRasterLayer::setDataProvider( QString const & provider )
{
QgsDebugMsg( "Entered" );
// XXX should I check for and possibly delete any pre-existing providers?
// XXX How often will that scenario occur?

@@ -2500,6 +2501,7 @@ bool QgsRasterLayer::readSymbology( const QDomNode& layer_node, QString& errorMe
*/
bool QgsRasterLayer::readXml( const QDomNode& layer_node )
{
QgsDebugMsg( "Entered" );
//! @note Make sure to read the file first so stats etc are initialised properly!

//process provider key
@@ -2564,6 +2566,7 @@ bool QgsRasterLayer::readXml( const QDomNode& layer_node )

setDataProvider( mProviderKey );


QString theError;
bool res = readSymbology( layer_node, theError );

@@ -2590,6 +2593,36 @@ bool QgsRasterLayer::readXml( const QDomNode& layer_node )
}
}

// Load user no data value
QDomElement noDataElement = layer_node.firstChildElement( "noData" );

QDomNodeList noDataBandList = noDataElement.elementsByTagName( "noDataRangeList" );

for ( int i = 0; i < noDataBandList.size(); ++i )
{
QDomElement bandElement = noDataBandList.at( i ).toElement();
bool ok;
int bandNo = bandElement.attribute( "bandNo" ).toInt( &ok );
QgsDebugMsg( QString( "bandNo = %1" ).arg( bandNo ) );
if ( ok && ( bandNo > 0 ) && ( bandNo <= mDataProvider->bandCount() ) )
{
QList<QgsRasterInterface::Range> myNoDataRangeList;

QDomNodeList rangeList = bandElement.elementsByTagName( "noDataRange" );

for ( int j = 0; j < rangeList.size(); ++j )
{
QDomElement rangeElement = rangeList.at( j ).toElement();
QgsRasterInterface::Range myNoDataRange;
myNoDataRange.min = rangeElement.attribute( "min" ).toDouble();
myNoDataRange.max = rangeElement.attribute( "max" ).toDouble();
QgsDebugMsg( QString( "min = %1 %2" ).arg( rangeElement.attribute( "min" ) ).arg( myNoDataRange.min ) );
myNoDataRangeList << myNoDataRange;
}
mDataProvider->setUserNoDataValue( bandNo, myNoDataRangeList );
}
}

return res;
} // QgsRasterLayer::readXml( QDomNode & layer_node )

@@ -2646,6 +2679,33 @@ bool QgsRasterLayer::writeXml( QDomNode & layer_node,
provider.appendChild( providerText );
layer_node.appendChild( provider );

// User no data
QDomElement noData = document.createElement( "noData" );

for ( int bandNo = 1; bandNo <= mDataProvider->bandCount(); bandNo++ )
{
if ( mDataProvider->userNoDataValue( bandNo ).isEmpty() ) continue;

QDomElement noDataRangeList = document.createElement( "noDataRangeList" );
noDataRangeList.setAttribute( "bandNo", bandNo );

foreach ( QgsRasterInterface::Range range, mDataProvider->userNoDataValue( bandNo ) )
{
QDomElement noDataRange = document.createElement( "noDataRange" );

noDataRange.setAttribute( "min", range.min );
noDataRange.setAttribute( "max", range.max );
noDataRangeList.appendChild( noDataRange );
}

noData.appendChild( noDataRangeList );

}
if ( noData.hasChildNodes() )
{
layer_node.appendChild( noData );
}

//write out the symbology
QString errorMsg;
return writeSymbology( layer_node, document, errorMsg );
@@ -2285,7 +2285,6 @@ void QgsGdalProvider::initBaseDataset()
{
QgsDebugMsg( QString( "GDALGetRasterNoDataValue = %1" ).arg( myNoDataValue ) ) ;
mGdalDataType.append( myGdalDataType );

}
else
{
@@ -2322,6 +2321,7 @@ void QgsGdalProvider::initBaseDataset()
mGdalDataType.append( myGdalDataType );
}
}
//mSrcNoDataValue.append( myNoDataValue );
mNoDataValue.append( myNoDataValue );
QgsDebugMsg( QString( "mNoDataValue[%1] = %2" ).arg( i - 1 ).arg( mNoDataValue[i-1] ) );
}

0 comments on commit 3032f71

Please sign in to comment.
You can’t perform that action at this time.