Skip to content

Commit

Permalink
[Raster] Add a Qgis::DataType::Int8 signed data type
Browse files Browse the repository at this point in the history
  • Loading branch information
rouault committed Jan 27, 2023
1 parent 5259409 commit 47182b5
Show file tree
Hide file tree
Showing 20 changed files with 141 additions and 27 deletions.
5 changes: 4 additions & 1 deletion python/core/auto_additions/qgis.py
Expand Up @@ -35,6 +35,9 @@
Qgis.Byte = Qgis.DataType.Byte
Qgis.Byte.is_monkey_patched = True
Qgis.Byte.__doc__ = "Eight bit unsigned integer (quint8)"
Qgis.Int8 = Qgis.DataType.Int8
Qgis.Int8.is_monkey_patched = True
Qgis.Int8.__doc__ = "Eight bit signed integer (qint8) (added in QGIS 3.30)"
Qgis.UInt16 = Qgis.DataType.UInt16
Qgis.UInt16.is_monkey_patched = True
Qgis.UInt16.__doc__ = "Sixteen bit unsigned integer (quint16)"
Expand Down Expand Up @@ -71,7 +74,7 @@
Qgis.ARGB32_Premultiplied = Qgis.DataType.ARGB32_Premultiplied
Qgis.ARGB32_Premultiplied.is_monkey_patched = True
Qgis.ARGB32_Premultiplied.__doc__ = "Color, alpha, red, green, blue, 4 bytes the same as QImage.Format_ARGB32_Premultiplied"
Qgis.DataType.__doc__ = 'Raster data types.\nThis is modified and extended copy of GDALDataType.\n\n' + '* ``UnknownDataType``: ' + Qgis.DataType.UnknownDataType.__doc__ + '\n' + '* ``Byte``: ' + Qgis.DataType.Byte.__doc__ + '\n' + '* ``UInt16``: ' + Qgis.DataType.UInt16.__doc__ + '\n' + '* ``Int16``: ' + Qgis.DataType.Int16.__doc__ + '\n' + '* ``UInt32``: ' + Qgis.DataType.UInt32.__doc__ + '\n' + '* ``Int32``: ' + Qgis.DataType.Int32.__doc__ + '\n' + '* ``Float32``: ' + Qgis.DataType.Float32.__doc__ + '\n' + '* ``Float64``: ' + Qgis.DataType.Float64.__doc__ + '\n' + '* ``CInt16``: ' + Qgis.DataType.CInt16.__doc__ + '\n' + '* ``CInt32``: ' + Qgis.DataType.CInt32.__doc__ + '\n' + '* ``CFloat32``: ' + Qgis.DataType.CFloat32.__doc__ + '\n' + '* ``CFloat64``: ' + Qgis.DataType.CFloat64.__doc__ + '\n' + '* ``ARGB32``: ' + Qgis.DataType.ARGB32.__doc__ + '\n' + '* ``ARGB32_Premultiplied``: ' + Qgis.DataType.ARGB32_Premultiplied.__doc__
Qgis.DataType.__doc__ = 'Raster data types.\nThis is modified and extended copy of GDALDataType.\n\n' + '* ``UnknownDataType``: ' + Qgis.DataType.UnknownDataType.__doc__ + '\n' + '* ``Byte``: ' + Qgis.DataType.Byte.__doc__ + '\n' + '* ``Int8``: ' + Qgis.DataType.Int8.__doc__ + '\n' + '* ``UInt16``: ' + Qgis.DataType.UInt16.__doc__ + '\n' + '* ``Int16``: ' + Qgis.DataType.Int16.__doc__ + '\n' + '* ``UInt32``: ' + Qgis.DataType.UInt32.__doc__ + '\n' + '* ``Int32``: ' + Qgis.DataType.Int32.__doc__ + '\n' + '* ``Float32``: ' + Qgis.DataType.Float32.__doc__ + '\n' + '* ``Float64``: ' + Qgis.DataType.Float64.__doc__ + '\n' + '* ``CInt16``: ' + Qgis.DataType.CInt16.__doc__ + '\n' + '* ``CInt32``: ' + Qgis.DataType.CInt32.__doc__ + '\n' + '* ``CFloat32``: ' + Qgis.DataType.CFloat32.__doc__ + '\n' + '* ``CFloat64``: ' + Qgis.DataType.CFloat64.__doc__ + '\n' + '* ``ARGB32``: ' + Qgis.DataType.ARGB32.__doc__ + '\n' + '* ``ARGB32_Premultiplied``: ' + Qgis.DataType.ARGB32_Premultiplied.__doc__
# --
Qgis.DataType.baseClass = Qgis
# monkey patching scoped based enum
Expand Down
1 change: 1 addition & 0 deletions python/core/auto_generated/qgis.sip.in
Expand Up @@ -90,6 +90,7 @@ The development version
{
UnknownDataType,
Byte,
Int8,
UInt16,
Int16,
UInt32,
Expand Down
2 changes: 1 addition & 1 deletion python/core/auto_generated/raster/qgsraster.sip.in
Expand Up @@ -25,7 +25,7 @@ Raster namespace.
static double representableValue( double value, Qgis::DataType dataType );
%Docstring
Gets value representable by given data type.
Supported are numerical types Byte, UInt16, Int16, UInt32, Int32, Float32, Float64.
Supported are numerical types Byte, Int8, 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 :py:func:`~QgsRaster.isRepresentableValue`.

Expand Down
28 changes: 27 additions & 1 deletion src/analysis/processing/qgsalgorithmrandomraster.cpp
Expand Up @@ -111,6 +111,16 @@ QVariantMap QgsRandomRasterAlgorithmBase::processAlgorithm( const QVariantMap &p
block.setData( QByteArray( reinterpret_cast<const char *>( byteRow.data() ), QgsRasterBlock::typeSize( Qgis::DataType::Byte ) * cols ) );
break;
}
case Qgis::DataType::Int8:
{
std::vector<qint8> int8Row( cols );
for ( int col = 0; col < cols; col++ )
{
int8Row[col] = static_cast<qint8>( generateRandomLongValue( mersenneTwister ) );
}
block.setData( QByteArray( reinterpret_cast<const char *>( int8Row.data() ), QgsRasterBlock::typeSize( Qgis::DataType::Int8 ) * cols ) );
break;
}
case Qgis::DataType::Int16:
{
std::vector<qint16> int16Row( cols );
Expand Down Expand Up @@ -290,6 +300,16 @@ bool QgsRandomUniformRasterAlgorithm::prepareRandomParameters( const QVariantMap
mRandomLowerBound = std::numeric_limits<quint8>::min();
}
break;
case Qgis::DataType::Int8:
if ( mRandomLowerBound < std::numeric_limits<qint8>::min() || mRandomUpperBound > std::numeric_limits<qint8>::max() )
throw QgsProcessingException( QObject::tr( "Raster datasets of type %3 only accept positive values between %1 and %2. Please choose other bounds for random values." ).arg( std::numeric_limits<qint8>::min() ).arg( std::numeric_limits<qint8>::max() ).arg( QLatin1String( "Int8" ) ) );
if ( ( qgsDoubleNear( mRandomLowerBound, 0.0 ) && qgsDoubleNear( mRandomUpperBound, 0.0 ) ) || qgsDoubleNear( mRandomUpperBound, mRandomLowerBound ) )
{
//if parameters unset (=both are 0 or equal) --> use the whole value range
mRandomUpperBound = std::numeric_limits<qint8>::max();
mRandomLowerBound = std::numeric_limits<qint8>::min();
}
break;
case Qgis::DataType::Int16:
if ( mRandomLowerBound < std::numeric_limits<qint16>::min() || mRandomUpperBound > std::numeric_limits<qint16>::max() )
throw QgsProcessingException( QObject::tr( "Raster datasets of type %3 only accept values between %1 and %2. Please choose other bounds for random values." ).arg( std::numeric_limits<qint16>::min() ).arg( std::numeric_limits<qint16>::max() ).arg( QLatin1String( "Integer16" ) ) );
Expand Down Expand Up @@ -340,7 +360,13 @@ bool QgsRandomUniformRasterAlgorithm::prepareRandomParameters( const QVariantMap
mRandomLowerBound = std::numeric_limits<double>::min();
}
break;
default:
case Qgis::DataType::CInt16:
case Qgis::DataType::CInt32:
case Qgis::DataType::CFloat32:
case Qgis::DataType::CFloat64:
case Qgis::DataType::ARGB32:
case Qgis::DataType::ARGB32_Premultiplied:
case Qgis::DataType::UnknownDataType:
break;
}

Expand Down
11 changes: 10 additions & 1 deletion src/analysis/raster/qgsrastercalculator.cpp
Expand Up @@ -449,6 +449,9 @@ QgsRasterCalculator::Result QgsRasterCalculator::processCalculationGPU( std::uni
case Qgis::DataType::Byte:
entry.typeName = QStringLiteral( "unsigned char" );
break;
case Qgis::DataType::Int8:
entry.typeName = QStringLiteral( "signed char" );
break;
case Qgis::DataType::UInt16:
entry.typeName = QStringLiteral( "unsigned int" );
break;
Expand All @@ -470,7 +473,13 @@ QgsRasterCalculator::Result QgsRasterCalculator::processCalculationGPU( std::uni
case Qgis::DataType::Float64:
entry.typeName = QStringLiteral( "double" );
break;
default:
case Qgis::DataType::CInt16:
case Qgis::DataType::CInt32:
case Qgis::DataType::CFloat32:
case Qgis::DataType::CFloat64:
case Qgis::DataType::ARGB32:
case Qgis::DataType::ARGB32_Premultiplied:
case Qgis::DataType::UnknownDataType:
return BandError;
}
entry.bufferSize = entry.dataSize * mNumOutputColumns;
Expand Down
11 changes: 1 addition & 10 deletions src/core/providers/gdal/qgsgdalprovider.cpp
Expand Up @@ -1603,6 +1603,7 @@ Qgis::DataType QgsGdalProvider::sourceDataType( int bandNo ) const
case Qgis::DataType::ARGB32_Premultiplied:
return myDataType;
case Qgis::DataType::Byte:
case Qgis::DataType::Int8:
case Qgis::DataType::UInt16:
case Qgis::DataType::Int16:
case Qgis::DataType::UInt32:
Expand Down Expand Up @@ -3603,12 +3604,6 @@ void QgsGdalProvider::initBaseDataset()
}
}

#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
if ( myGdalDataType == GDT_Int8 )
{
myGdalDataType = GDT_Int16;
}
#endif
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,5,0)
if ( myGdalDataType == GDT_Int64 || myGdalDataType == GDT_UInt64 )
{
Expand Down Expand Up @@ -3684,10 +3679,6 @@ bool QgsGdalProvider::write( void *data, int band, int width, int height, int xO
return false;
}
GDALDataType gdalDataType = GDALGetRasterDataType( rasterBand );
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
if ( gdalDataType == GDT_Int8 )
gdalDataType = GDT_Int16;
#endif
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,5,0)
if ( gdalDataType == GDT_Int64 || gdalDataType == GDT_UInt64 )
gdalDataType = GDT_Float64;
Expand Down
3 changes: 1 addition & 2 deletions src/core/providers/gdal/qgsgdalproviderbase.cpp
Expand Up @@ -154,8 +154,7 @@ Qgis::DataType QgsGdalProviderBase::dataTypeFromGdal( const GDALDataType gdalDat
{
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
case GDT_Int8:
// Promote to Int16 due to lack of native Qgis data type for Int8
return Qgis::DataType::Int16;
return Qgis::DataType::Int8;
#endif
case GDT_Byte:
return Qgis::DataType::Byte;
Expand Down
1 change: 1 addition & 0 deletions src/core/qgis.h
Expand Up @@ -129,6 +129,7 @@ class CORE_EXPORT Qgis
{
UnknownDataType = 0, //!< Unknown or unspecified type
Byte = 1, //!< Eight bit unsigned integer (quint8)
Int8 = 14, //!< Eight bit signed integer (qint8) (added in QGIS 3.30)

This comment has been minimized.

Copy link
@agiudiceandrea

agiudiceandrea May 10, 2023

Contributor

@rouault, wouldn't it have been better to put it at the end of the enumeration list so an user can guess the corresponding number from the docs?

This comment has been minimized.

Copy link
@rouault

rouault May 10, 2023

Author Contributor

wouldn't it have been better to put it at the end of the enumeration list so an user can guess the corresponding numbe

why would a user would need to know the actual number ? The whole purpose of an enumerated data type is to use symbolic names instead of actual numbers

UInt16 = 2, //!< Sixteen bit unsigned integer (quint16)
Int16 = 3, //!< Sixteen bit signed integer (qint16)
UInt32 = 4, //!< Thirty two bit unsigned integer (quint32)
Expand Down
7 changes: 7 additions & 0 deletions src/core/qgsgdalutils.cpp
Expand Up @@ -460,6 +460,13 @@ GDALDataType QgsGdalUtils::gdalDataTypeFromQgisDataType( Qgis::DataType dataType
case Qgis::DataType::Byte:
return GDALDataType::GDT_Byte;
break;
case Qgis::DataType::Int8:
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
return GDALDataType::GDT_Int8;
#else
return GDALDataType::GDT_Unknown;
#endif
break;
case Qgis::DataType::UInt16:
return GDALDataType::GDT_UInt16;
break;
Expand Down
4 changes: 4 additions & 0 deletions src/core/raster/qgscontrastenhancement.h
Expand Up @@ -72,6 +72,8 @@ class CORE_EXPORT QgsContrastEnhancement
{
case Qgis::DataType::Byte:
return std::numeric_limits<unsigned char>::max();
case Qgis::DataType::Int8:
return std::numeric_limits<int8_t>::max();
case Qgis::DataType::UInt16:
return std::numeric_limits<unsigned short>::max();
case Qgis::DataType::Int16:
Expand Down Expand Up @@ -111,6 +113,8 @@ class CORE_EXPORT QgsContrastEnhancement
{
case Qgis::DataType::Byte:
return std::numeric_limits<unsigned char>::min();
case Qgis::DataType::Int8:
return std::numeric_limits<int8_t>::min();
case Qgis::DataType::UInt16:
return std::numeric_limits<unsigned short>::min();
case Qgis::DataType::Int16:
Expand Down
24 changes: 22 additions & 2 deletions src/core/raster/qgsraster.cpp
Expand Up @@ -25,6 +25,8 @@ bool QgsRaster::isRepresentableValue( double value, Qgis::DataType dataType )
{
case Qgis::DataType::Byte:
return value >= std::numeric_limits<quint8>::min() && value <= std::numeric_limits<quint8>::max();
case Qgis::DataType::Int8:
return value >= std::numeric_limits<qint8>::min() && value <= std::numeric_limits<qint8>::max();
case Qgis::DataType::UInt16:
return value >= std::numeric_limits<quint16>::min() && value <= std::numeric_limits<quint16>::max();
case Qgis::DataType::Int16:
Expand All @@ -36,10 +38,18 @@ bool QgsRaster::isRepresentableValue( double value, Qgis::DataType dataType )
case Qgis::DataType::Float32:
return std::isnan( value ) || std::isinf( value ) ||
( value >= -std::numeric_limits<float>::max() && value <= std::numeric_limits<float>::max() );
default:
case Qgis::DataType::Float64:
return true;
case Qgis::DataType::CInt16:
case Qgis::DataType::CInt32:
case Qgis::DataType::CFloat32:
case Qgis::DataType::CFloat64:
case Qgis::DataType::ARGB32:
case Qgis::DataType::ARGB32_Premultiplied:
case Qgis::DataType::UnknownDataType:
break;
}
return true;
}

double QgsRaster::representableValue( double value, Qgis::DataType dataType )
Expand All @@ -48,6 +58,8 @@ double QgsRaster::representableValue( double value, Qgis::DataType dataType )
{
case Qgis::DataType::Byte:
return static_cast<quint8>( value );
case Qgis::DataType::Int8:
return static_cast<qint8>( value );
case Qgis::DataType::UInt16:
return static_cast<quint16>( value );
case Qgis::DataType::Int16:
Expand All @@ -58,7 +70,15 @@ double QgsRaster::representableValue( double value, Qgis::DataType dataType )
return static_cast<qint32>( value );
case Qgis::DataType::Float32:
return static_cast<float>( value );
default:
case Qgis::DataType::Float64:
return value;
case Qgis::DataType::CInt16:
case Qgis::DataType::CInt32:
case Qgis::DataType::CFloat32:
case Qgis::DataType::CFloat64:
case Qgis::DataType::ARGB32:
case Qgis::DataType::ARGB32_Premultiplied:
case Qgis::DataType::UnknownDataType:
break;
}
return value;
Expand Down
4 changes: 2 additions & 2 deletions src/core/raster/qgsraster.h
Expand Up @@ -34,7 +34,7 @@ class CORE_EXPORT QgsRaster

/**
* Check if the specified value is representable in the given data type.
* Supported are numerical types Byte, UInt16, Int16, UInt32, Int32, Float32, Float64.
* Supported are numerical types Byte, Int8, UInt16, Int16, UInt32, Int32, Float32, Float64.
* \param value
* \param dataType
* \note not available in Python bindings
Expand All @@ -44,7 +44,7 @@ class CORE_EXPORT QgsRaster

/**
* Gets value representable by given data type.
* Supported are numerical types Byte, UInt16, Int16, UInt32, Int32, Float32, Float64.
* Supported are numerical types Byte, Int8, 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
Expand Down
25 changes: 23 additions & 2 deletions src/core/raster/qgsrasterblock.cpp
Expand Up @@ -141,6 +141,7 @@ bool QgsRasterBlock::typeIsNumeric( Qgis::DataType dataType )
switch ( dataType )
{
case Qgis::DataType::Byte:
case Qgis::DataType::Int8:
case Qgis::DataType::UInt16:
case Qgis::DataType::Int16:
case Qgis::DataType::UInt32:
Expand Down Expand Up @@ -171,6 +172,7 @@ bool QgsRasterBlock::typeIsColor( Qgis::DataType dataType )

case Qgis::DataType::UnknownDataType:
case Qgis::DataType::Byte:
case Qgis::DataType::Int8:
case Qgis::DataType::UInt16:
case Qgis::DataType::Int16:
case Qgis::DataType::UInt32:
Expand All @@ -193,6 +195,7 @@ Qgis::DataType QgsRasterBlock::typeWithNoDataValue( Qgis::DataType dataType, dou
switch ( dataType )
{
case Qgis::DataType::Byte:
case Qgis::DataType::Int8:
*noDataValue = -32768.0;
newDataType = Qgis::DataType::Int16;
break;
Expand All @@ -211,7 +214,13 @@ Qgis::DataType QgsRasterBlock::typeWithNoDataValue( Qgis::DataType dataType, dou
*noDataValue = std::numeric_limits<double>::max() * -1.0;
newDataType = Qgis::DataType::Float64;
break;
default:
case Qgis::DataType::CInt16:
case Qgis::DataType::CInt32:
case Qgis::DataType::CFloat32:
case Qgis::DataType::CFloat64:
case Qgis::DataType::ARGB32:
case Qgis::DataType::ARGB32_Premultiplied:
case Qgis::DataType::UnknownDataType:
QgsDebugMsg( QStringLiteral( "Unknown data type %1" ).arg( static_cast< int >( dataType ) ) );
return Qgis::DataType::UnknownDataType;
}
Expand Down Expand Up @@ -708,6 +717,12 @@ QByteArray QgsRasterBlock::valueBytes( Qgis::DataType dataType, double value )
uc = static_cast< quint8 >( value );
memcpy( data, &uc, size );
break;
case Qgis::DataType::Int8:
{
const qint8 myint8 = static_cast< qint8 >( value );
memcpy( data, &myint8, size );
break;
}
case Qgis::DataType::UInt16:
us = static_cast< quint16 >( value );
memcpy( data, &us, size );
Expand All @@ -732,7 +747,13 @@ QByteArray QgsRasterBlock::valueBytes( Qgis::DataType dataType, double value )
d = static_cast< double >( value );
memcpy( data, &d, size );
break;
default:
case Qgis::DataType::CInt16:
case Qgis::DataType::CInt32:
case Qgis::DataType::CFloat32:
case Qgis::DataType::CFloat64:
case Qgis::DataType::ARGB32:
case Qgis::DataType::ARGB32_Premultiplied:
case Qgis::DataType::UnknownDataType:
QgsDebugMsg( QStringLiteral( "Data type is not supported" ) );
}
return ba;
Expand Down

0 comments on commit 47182b5

Please sign in to comment.