mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -04:00
[GDAL provider] Ignore nodata value that are not representable in the data type.
This is related to commit e0d38ba3f912b7ae6b34e66a44e529ec37394458. In case we have to deal with an inconsitent raster where the nodata value is set to a value not representable in the data type, ignore it. Otherwise, a NaN value in a Byte raster would be cast as 0.
This commit is contained in:
parent
e0d38ba3f9
commit
f3b635dcbb
@ -50,6 +50,29 @@ QgsRaster::ContrastEnhancementLimits QgsRaster::contrastEnhancementLimitsFromStr
|
||||
return ContrastEnhancementNone;
|
||||
}
|
||||
|
||||
bool QgsRaster::isRepresentableValue( double value, QGis::DataType dataType )
|
||||
{
|
||||
switch ( dataType )
|
||||
{
|
||||
case QGis::Byte:
|
||||
return value >= std::numeric_limits<quint8>::min() && value <= std::numeric_limits<quint8>::max();
|
||||
case QGis::UInt16:
|
||||
return value >= std::numeric_limits<quint16>::min() && value <= std::numeric_limits<quint16>::max();
|
||||
case QGis::Int16:
|
||||
return value >= std::numeric_limits<qint16>::min() && value <= std::numeric_limits<qint16>::max();
|
||||
case QGis::UInt32:
|
||||
return value >= std::numeric_limits<quint32>::min() && value <= std::numeric_limits<quint32>::max();
|
||||
case QGis::Int32:
|
||||
return value >= std::numeric_limits<qint32>::min() && value <= std::numeric_limits<qint32>::max();
|
||||
case QGis::Float32:
|
||||
return qIsNaN( value ) || qIsInf( value ) ||
|
||||
( value >= -std::numeric_limits<float>::max() && value <= std::numeric_limits<float>::max() );
|
||||
default:
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
double QgsRaster::representableValue( double value, QGis::DataType dataType )
|
||||
{
|
||||
switch ( dataType )
|
||||
|
@ -110,8 +110,18 @@ class CORE_EXPORT QgsRaster
|
||||
static QString contrastEnhancementLimitsAsString( QgsRaster::ContrastEnhancementLimits theLimits );
|
||||
static ContrastEnhancementLimits contrastEnhancementLimitsFromString( const QString& theLimits );
|
||||
|
||||
/** Check if the specified value is representable in the given data type.
|
||||
* Supported are numerical types Byte, UInt16, Int16, UInt32, Int32, Float32, Float64.
|
||||
* @param value
|
||||
* @param dataType
|
||||
* @note added in version 2.16
|
||||
* @note not available in Python bindings */
|
||||
static bool isRepresentableValue( double value, QGis::DataType dataType );
|
||||
|
||||
/** Get value representable by given data type.
|
||||
* Supported are numerical types Byte, UInt16, Int16, UInt32, Int32, Float32, Float64.
|
||||
* This is done through C casting, so you have to be sure that the provided value is
|
||||
* representable in the output data type. This can be checked with isRepresentableValue().
|
||||
* @param value
|
||||
* @param dataType
|
||||
* @note added in version 2.1 */
|
||||
|
@ -2643,6 +2643,15 @@ void QgsGdalProvider::initBaseDataset()
|
||||
|
||||
int isValid = false;
|
||||
double myNoDataValue = GDALGetRasterNoDataValue( myGdalBand, &isValid );
|
||||
// We check that the double value we just got is representable in the
|
||||
// data type. In normal situations this should not be needed, but it happens
|
||||
// to have 8bit TIFFs with nan as the nodata value. If not checking against
|
||||
// the min/max bounds, it would be cast to 0 by representableValue().
|
||||
if ( isValid && !QgsRaster::isRepresentableValue( myNoDataValue, dataTypeFromGdal( myGdalDataType ) ) )
|
||||
{
|
||||
QgsDebugMsg( QString( "GDALGetRasterNoDataValue = %1 is not representable in data type, so ignoring it" ).arg( myNoDataValue ) );
|
||||
isValid = false;
|
||||
}
|
||||
if ( isValid )
|
||||
{
|
||||
QgsDebugMsg( QString( "GDALGetRasterNoDataValue = %1" ).arg( myNoDataValue ) );
|
||||
|
@ -12,6 +12,9 @@
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
@ -42,6 +45,9 @@ class TestQgsGdalProvider : public QObject
|
||||
|
||||
void scaleDataType(); //test resultant data types for int raster with float scale (#11573)
|
||||
void warpedVrt(); //test loading raster which requires a warped vrt
|
||||
void noData();
|
||||
void invalidNoDataInSourceIgnored();
|
||||
void isRepresentableValue();
|
||||
|
||||
private:
|
||||
QString mTestDataDir;
|
||||
@ -104,5 +110,85 @@ void TestQgsGdalProvider::warpedVrt()
|
||||
delete provider;
|
||||
}
|
||||
|
||||
void TestQgsGdalProvider::noData()
|
||||
{
|
||||
QString raster = QString( TEST_DATA_DIR ) + "/raster/band1_byte_ct_epsg4326.tif";
|
||||
QgsDataProvider* provider = QgsProviderRegistry::instance()->provider( "gdal", raster );
|
||||
QVERIFY( provider->isValid() );
|
||||
QgsRasterDataProvider* rp = dynamic_cast< QgsRasterDataProvider* >( provider );
|
||||
QVERIFY( rp );
|
||||
QCOMPARE( rp->srcNoDataValue( 1 ), static_cast<double>( 255 ) );
|
||||
delete provider;
|
||||
}
|
||||
|
||||
void TestQgsGdalProvider::invalidNoDataInSourceIgnored()
|
||||
{
|
||||
QString raster = QString( TEST_DATA_DIR ) + "/raster/byte_with_nan_nodata.tif";
|
||||
QgsDataProvider* provider = QgsProviderRegistry::instance()->provider( "gdal", raster );
|
||||
QVERIFY( provider->isValid() );
|
||||
QgsRasterDataProvider* rp = dynamic_cast< QgsRasterDataProvider* >( provider );
|
||||
QVERIFY( rp );
|
||||
QCOMPARE( rp->srcHasNoDataValue( 1 ), false );
|
||||
delete provider;
|
||||
}
|
||||
|
||||
void TestQgsGdalProvider::isRepresentableValue()
|
||||
{
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( std::numeric_limits<double>::infinity(), QGis::Byte ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( -std::numeric_limits<double>::infinity(), QGis::Byte ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( std::numeric_limits<double>::quiet_NaN(), QGis::Byte ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( -1., QGis::Byte ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( 0., QGis::Byte ), true );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( 255., QGis::Byte ), true );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( 256., QGis::Byte ), false );
|
||||
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( std::numeric_limits<double>::infinity(), QGis::UInt16 ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( -std::numeric_limits<double>::infinity(), QGis::UInt16 ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( std::numeric_limits<double>::quiet_NaN(), QGis::UInt16 ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( -1., QGis::UInt16 ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( 0., QGis::UInt16 ), true );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( 65535., QGis::UInt16 ), true );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( 65536., QGis::UInt16 ), false );
|
||||
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( std::numeric_limits<double>::infinity(), QGis::Int16 ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( -std::numeric_limits<double>::infinity(), QGis::Int16 ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( std::numeric_limits<double>::quiet_NaN(), QGis::Int16 ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( -32769., QGis::Int16 ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( -32768., QGis::Int16 ), true );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( 32767., QGis::Int16 ), true );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( 32768., QGis::Int16 ), false );
|
||||
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( std::numeric_limits<double>::infinity(), QGis::UInt32 ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( -std::numeric_limits<double>::infinity(), QGis::UInt32 ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( std::numeric_limits<double>::quiet_NaN(), QGis::UInt32 ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( -1., QGis::UInt32 ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( 0., QGis::UInt32 ), true );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( 4294967295., QGis::UInt32 ), true );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( 4294967296., QGis::UInt32 ), false );
|
||||
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( std::numeric_limits<double>::infinity(), QGis::Int32 ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( -std::numeric_limits<double>::infinity(), QGis::Int32 ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( std::numeric_limits<double>::quiet_NaN(), QGis::Int32 ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( -2147483649., QGis::Int32 ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( -2147483648., QGis::Int32 ), true );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( 2147483647., QGis::Int32 ), true );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( 2147483648., QGis::Int32 ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( 4294967296., QGis::UInt32 ), false );
|
||||
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( std::numeric_limits<double>::infinity(), QGis::Float32 ), true );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( -std::numeric_limits<double>::infinity(), QGis::Float32 ), true );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( std::numeric_limits<double>::quiet_NaN(), QGis::Float32 ), true );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( -std::numeric_limits<double>::max(), QGis::Float32 ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( std::numeric_limits<double>::max(), QGis::Float32 ), false );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( -std::numeric_limits<float>::max(), QGis::Float32 ), true );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( std::numeric_limits<float>::max(), QGis::Float32 ), true );
|
||||
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( std::numeric_limits<double>::infinity(), QGis::Float64 ), true );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( -std::numeric_limits<double>::infinity(), QGis::Float64 ), true );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( std::numeric_limits<double>::quiet_NaN(), QGis::Float64 ), true );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( -std::numeric_limits<double>::max(), QGis::Float64 ), true );
|
||||
QCOMPARE( QgsRaster::isRepresentableValue( std::numeric_limits<double>::max(), QGis::Float64 ), true );
|
||||
}
|
||||
|
||||
QTEST_MAIN( TestQgsGdalProvider )
|
||||
#include "testqgsgdalprovider.moc"
|
||||
|
BIN
tests/testdata/raster/byte_with_nan_nodata.tif
vendored
Normal file
BIN
tests/testdata/raster/byte_with_nan_nodata.tif
vendored
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user