LCOV - code coverage report
Current view: top level - core/raster - qgsrasterblock.h (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 186 0.0 %
Date: 2021-04-10 08:29:14 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :     qgsrasterblock.h - Class representing a block of raster data
       3                 :            :      --------------------------------------
       4                 :            :     Date                 : Oct 9, 2012
       5                 :            :     Copyright            : (C) 2012 by Radim Blazek
       6                 :            :     email                : radim dot blazek at gmail dot com
       7                 :            :  ***************************************************************************/
       8                 :            : 
       9                 :            : /***************************************************************************
      10                 :            :  *                                                                         *
      11                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      12                 :            :  *   it under the terms of the GNU General Public License as published by  *
      13                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      14                 :            :  *   (at your option) any later version.                                   *
      15                 :            :  *                                                                         *
      16                 :            :  ***************************************************************************/
      17                 :            : 
      18                 :            : #ifndef QGSRASTERBLOCK_H
      19                 :            : #define QGSRASTERBLOCK_H
      20                 :            : 
      21                 :            : #include "qgis_core.h"
      22                 :            : #include "qgis_sip.h"
      23                 :            : #include <limits>
      24                 :            : #include <QImage>
      25                 :            : #include "qgis.h"
      26                 :            : #include "qgserror.h"
      27                 :            : #include "qgslogger.h"
      28                 :            : #include "qgsrasterrange.h"
      29                 :            : 
      30                 :            : class QgsRectangle;
      31                 :            : 
      32                 :            : /**
      33                 :            :  * \ingroup core
      34                 :            :  * \brief Raster data container.
      35                 :            :  */
      36                 :            : class CORE_EXPORT QgsRasterBlock
      37                 :            : {
      38                 :            :   public:
      39                 :            :     QgsRasterBlock();
      40                 :            : 
      41                 :            :     /**
      42                 :            :      * \brief Constructor which allocates data block in memory
      43                 :            :      *  \param dataType raster data type
      44                 :            :      *  \param width width of data matrix
      45                 :            :      *  \param height height of data matrix
      46                 :            :      */
      47                 :            :     QgsRasterBlock( Qgis::DataType dataType, int width, int height );
      48                 :            : 
      49                 :            :     virtual ~QgsRasterBlock();
      50                 :            : 
      51                 :            :     /**
      52                 :            :      * \brief Reset block
      53                 :            :      *  \param dataType raster data type
      54                 :            :      *  \param width width of data matrix
      55                 :            :      *  \param height height of data matrix
      56                 :            :      *  \returns TRUE on success
      57                 :            :      */
      58                 :            :     bool reset( Qgis::DataType dataType, int width, int height );
      59                 :            : 
      60                 :            :     // TODO: consider if use isValid() at all, isEmpty() should be sufficient
      61                 :            :     // and works also if block is valid but empty - difference between valid and empty?
      62                 :            : 
      63                 :            :     /**
      64                 :            :      * \brief Returns TRUE if the block is valid (correctly filled with data).
      65                 :            :      *  An empty block may still be valid (if zero size block was requested).
      66                 :            :      *  If the block is not valid, error may be retrieved by error() method.
      67                 :            :      */
      68                 :          0 :     bool isValid() const SIP_HOLDGIL { return mValid; }
      69                 :            : 
      70                 :            :     //! \brief Mark block as valid or invalid
      71                 :          0 :     void setValid( bool valid ) SIP_HOLDGIL { mValid = valid; }
      72                 :            : 
      73                 :            :     /**
      74                 :            :      * Returns TRUE if block is empty, i.e. its size is 0 (zero rows or cols).
      75                 :            :      *  This method does not return TRUE if size is not zero and all values are
      76                 :            :      *  'no data' (null).
      77                 :            :      */
      78                 :            :     bool isEmpty() const;
      79                 :            : 
      80                 :            :     /**
      81                 :            :      * Returns the size in bytes for the specified \a dataType.
      82                 :            :      */
      83                 :          0 :     static int typeSize( int dataType ) SIP_HOLDGIL
      84                 :            :     {
      85                 :            :       // Modified and extended copy from GDAL
      86                 :          0 :       switch ( dataType )
      87                 :            :       {
      88                 :            :         case Qgis::Byte:
      89                 :          0 :           return 1;
      90                 :            : 
      91                 :            :         case Qgis::UInt16:
      92                 :            :         case Qgis::Int16:
      93                 :          0 :           return 2;
      94                 :            : 
      95                 :            :         case Qgis::UInt32:
      96                 :            :         case Qgis::Int32:
      97                 :            :         case Qgis::Float32:
      98                 :            :         case Qgis::CInt16:
      99                 :          0 :           return 4;
     100                 :            : 
     101                 :            :         case Qgis::Float64:
     102                 :            :         case Qgis::CInt32:
     103                 :            :         case Qgis::CFloat32:
     104                 :          0 :           return 8;
     105                 :            : 
     106                 :            :         case Qgis::CFloat64:
     107                 :          0 :           return 16;
     108                 :            : 
     109                 :            :         case Qgis::ARGB32:
     110                 :            :         case Qgis::ARGB32_Premultiplied:
     111                 :          0 :           return 4;
     112                 :            : 
     113                 :            :         default:
     114                 :          0 :           return 0;
     115                 :            :       }
     116                 :          0 :     }
     117                 :            : 
     118                 :            :     /**
     119                 :            :      * Data type size in bytes.
     120                 :            :      */
     121                 :            :     int dataTypeSize() const SIP_HOLDGIL
     122                 :            :     {
     123                 :            :       return typeSize( mDataType );
     124                 :            :     }
     125                 :            : 
     126                 :            :     //! Returns TRUE if data type is numeric
     127                 :            :     static bool typeIsNumeric( Qgis::DataType type );
     128                 :            : 
     129                 :            :     //! Returns TRUE if data type is color
     130                 :            :     static bool typeIsColor( Qgis::DataType type );
     131                 :            : 
     132                 :            :     //! Returns data type
     133                 :          0 :     Qgis::DataType dataType() const  SIP_HOLDGIL { return mDataType; }
     134                 :            : 
     135                 :            :     //! For given data type returns wider type and sets no data value
     136                 :            :     static Qgis::DataType typeWithNoDataValue( Qgis::DataType dataType, double *noDataValue );
     137                 :            : 
     138                 :            :     /**
     139                 :            :      * TRUE if the block has no data value.
     140                 :            :      * \returns TRUE if the block has no data value
     141                 :            :      * \see noDataValue(), setNoDataValue(), resetNoDataValue()
     142                 :            :      */
     143                 :          0 :     bool hasNoDataValue() const SIP_HOLDGIL { return mHasNoDataValue; }
     144                 :            : 
     145                 :            :     /**
     146                 :            :      * Returns TRUE if the block may contain no data. It does not guarantee
     147                 :            :      * that it really contains any no data. It can be used to speed up processing.
     148                 :            :      * Not the difference between this method and hasNoDataValue().
     149                 :            :      * \returns TRUE if the block may contain no data
     150                 :            :     */
     151                 :          0 :     bool hasNoData() const SIP_HOLDGIL
     152                 :            :     {
     153                 :          0 :       return mHasNoDataValue || mNoDataBitmap;
     154                 :            :     }
     155                 :            : 
     156                 :            :     /**
     157                 :            :      * Sets cell value that will be considered as "no data".
     158                 :            :      * \see noDataValue(), hasNoDataValue(), resetNoDataValue()
     159                 :            :      * \since QGIS 3.0
     160                 :            :      */
     161                 :            :     void setNoDataValue( double noDataValue ) SIP_HOLDGIL;
     162                 :            : 
     163                 :            :     /**
     164                 :            :      * Reset no data value: if there was a no data value previously set,
     165                 :            :      * it will be discarded.
     166                 :            :      * \see noDataValue(), hasNoDataValue(), setNoDataValue()
     167                 :            :      * \since QGIS 3.0
     168                 :            :      */
     169                 :            :     void resetNoDataValue() SIP_HOLDGIL;
     170                 :            : 
     171                 :            :     /**
     172                 :            :      * Returns no data value. If the block does not have a no data value the
     173                 :            :      *  returned value is undefined.
     174                 :            :      * \returns No data value
     175                 :            :      * \see hasNoDataValue(), setNoDataValue(), resetNoDataValue()
     176                 :            :      */
     177                 :          0 :     double noDataValue() const SIP_HOLDGIL { return mNoDataValue; }
     178                 :            : 
     179                 :            :     /**
     180                 :            :      * Gets byte array representing a value.
     181                 :            :      * \param dataType data type
     182                 :            :      * \param value value
     183                 :            :      * \returns byte array representing the value
     184                 :            :     */
     185                 :            :     static QByteArray valueBytes( Qgis::DataType dataType, double value );
     186                 :            : 
     187                 :            :     /**
     188                 :            :      * Read a single value if type of block is numeric. If type is color,
     189                 :            :      * returned value is undefined.
     190                 :            :      * \param row row index
     191                 :            :      * \param column column index
     192                 :            :      * \returns value
     193                 :            :      * \see valueAndNoData()
     194                 :            :     */
     195                 :          0 :     double value( int row, int column ) const SIP_HOLDGIL
     196                 :            :     {
     197                 :          0 :       return value( static_cast< qgssize >( row ) * mWidth + column );
     198                 :            :     }
     199                 :            : 
     200                 :            :     /**
     201                 :            :      * Reads a single value from the pixel at \a row and \a column, if type of block is numeric. If type is color,
     202                 :            :      * returned value is undefined.
     203                 :            :      *
     204                 :            :      * Additionally, the \a isNoData argument will be set to TRUE if the pixel represents a nodata value. This method
     205                 :            :      * is more efficient then calling isNoData() and value() separately.
     206                 :            :      *
     207                 :            :      * \note Not available in Python bindings
     208                 :            :      * \see value()
     209                 :            :      * \see isNoData()
     210                 :            :      * \since QGIS 3.6
     211                 :            :      */
     212                 :          0 :     double valueAndNoData( int row, int column, bool &isNoData ) const SIP_SKIP
     213                 :            :     {
     214                 :          0 :       return valueAndNoData( static_cast< qgssize >( row ) * mWidth + column, isNoData );
     215                 :            :     }
     216                 :            : 
     217                 :            :     /**
     218                 :            :      * Reads a single value if type of block is numeric. If type is color,
     219                 :            :      * returned value is undefined.
     220                 :            :      * \param index data matrix index (long type in Python)
     221                 :            :      * \returns value
     222                 :            :      * \see valueAndNoData()
     223                 :            :     */
     224                 :            :     inline double value( qgssize index ) const SIP_HOLDGIL;
     225                 :            : 
     226                 :            :     /**
     227                 :            :      * Reads a single value from the pixel at the specified data matrix \a index, if type of block is numeric. If type is color,
     228                 :            :      * returned value is undefined.
     229                 :            :      *
     230                 :            :      * Additionally, the \a isNoData argument will be set to TRUE if the pixel represents a nodata value. This method
     231                 :            :      * is more efficient then calling isNoData() and value() separately.
     232                 :            :      *
     233                 :            :      * \note Not available in Python bindings
     234                 :            :      * \see value()
     235                 :            :      * \see isNoData()
     236                 :            :      * \since QGIS 3.6
     237                 :            :      */
     238                 :            :     inline double valueAndNoData( qgssize index, bool &isNoData ) const SIP_SKIP;
     239                 :            : 
     240                 :            :     /**
     241                 :            :      * Gives direct access to the raster block data.
     242                 :            :      * The data type of the block must be Qgis::Byte otherwise it returns NULLPTR.
     243                 :            :      * Useful for most efficient read access.
     244                 :            :      * \note not available in Python bindings
     245                 :            :      * \since QGIS 3.4
     246                 :            :      */
     247                 :          0 :     const quint8 *byteData() const SIP_SKIP
     248                 :            :     {
     249                 :          0 :       if ( mDataType != Qgis::Byte )
     250                 :          0 :         return nullptr;
     251                 :          0 :       return static_cast< const quint8 * >( mData );
     252                 :          0 :     }
     253                 :            : 
     254                 :            :     /**
     255                 :            :      * \brief Read a single color
     256                 :            :      *  \param row row index
     257                 :            :      *  \param column column index
     258                 :            :      *  \returns color
     259                 :            :     */
     260                 :          0 :     QRgb color( int row, int column ) const SIP_HOLDGIL
     261                 :            :     {
     262                 :          0 :       if ( !mImage ) return NO_DATA_COLOR;
     263                 :            : 
     264                 :          0 :       return mImage->pixel( column, row );
     265                 :          0 :     }
     266                 :            : 
     267                 :            :     /**
     268                 :            :      * \brief Read a single value
     269                 :            :      *  \param index data matrix index (long type in Python)
     270                 :            :      *  \returns color
     271                 :            :     */
     272                 :          0 :     QRgb color( qgssize index ) const SIP_HOLDGIL
     273                 :            :     {
     274                 :          0 :       int row = static_cast< int >( std::floor( static_cast< double >( index ) / mWidth ) );
     275                 :          0 :       int column = index % mWidth;
     276                 :          0 :       return color( row, column );
     277                 :            :     }
     278                 :            : 
     279                 :            :     /**
     280                 :            :      * Checks if value at position is no data
     281                 :            :      * \param row row index
     282                 :            :      * \param column column index
     283                 :            :      * \returns TRUE if value is no data
     284                 :            :      * \see valueAndNoData()
     285                 :            :     */
     286                 :          0 :     bool isNoData( int row, int column ) const SIP_HOLDGIL
     287                 :            :     {
     288                 :          0 :       return isNoData( static_cast< qgssize >( row ) * mWidth + column );
     289                 :            :     }
     290                 :            : 
     291                 :            :     /**
     292                 :            :      * Check if value at position is no data
     293                 :            :      * \param row row index
     294                 :            :      * \param column column index
     295                 :            :      * \returns TRUE if value is no data
     296                 :            :      * \see valueAndNoData()
     297                 :            :     */
     298                 :          0 :     bool isNoData( qgssize row, qgssize column ) const SIP_HOLDGIL
     299                 :            :     {
     300                 :          0 :       return isNoData( row * static_cast< qgssize >( mWidth ) + column );
     301                 :            :     }
     302                 :            : 
     303                 :            :     /**
     304                 :            :      * Check if value at position is no data
     305                 :            :      * \param index data matrix index (long type in Python)
     306                 :            :      * \returns TRUE if value is no data
     307                 :            :      * \see valueAndNoData()
     308                 :            :     */
     309                 :          0 :     bool isNoData( qgssize index ) const SIP_HOLDGIL
     310                 :            :     {
     311                 :          0 :       if ( !mHasNoDataValue && !mNoDataBitmap )
     312                 :          0 :         return false;
     313                 :          0 :       if ( index >= static_cast< qgssize >( mWidth )*mHeight )
     314                 :            :       {
     315                 :          0 :         QgsDebugMsg( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
     316                 :          0 :         return true; // we consider no data if outside
     317                 :            :       }
     318                 :          0 :       if ( mHasNoDataValue )
     319                 :            :       {
     320                 :          0 :         double value = readValue( mData, mDataType, index );
     321                 :          0 :         return isNoDataValue( value );
     322                 :            :       }
     323                 :            :       // use no data bitmap
     324                 :          0 :       if ( !mNoDataBitmap )
     325                 :            :       {
     326                 :            :         // no data are not defined
     327                 :          0 :         return false;
     328                 :            :       }
     329                 :            :       // TODO: optimize
     330                 :          0 :       int row = static_cast< int >( index ) / mWidth;
     331                 :          0 :       int column = index % mWidth;
     332                 :          0 :       qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
     333                 :          0 :       int bit = column % 8;
     334                 :          0 :       int mask = 0x80 >> bit;
     335                 :            :       //int x = mNoDataBitmap[byte] & mask;
     336                 :            :       //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) ) );
     337                 :          0 :       return mNoDataBitmap[byte] & mask;
     338                 :          0 :     }
     339                 :            : 
     340                 :            :     /**
     341                 :            :      * \brief Set value on position
     342                 :            :      *  \param row row index
     343                 :            :      *  \param column column index
     344                 :            :      *  \param value the value to be set
     345                 :            :      *  \returns TRUE on success
     346                 :            :     */
     347                 :          0 :     bool setValue( int row, int column, double value ) SIP_HOLDGIL
     348                 :            :     {
     349                 :          0 :       return setValue( static_cast< qgssize >( row ) * mWidth + column, value );
     350                 :            :     }
     351                 :            : 
     352                 :            :     /**
     353                 :            :      * \brief Set value on index (indexed line by line)
     354                 :            :      *  \param index data matrix index (long type in Python)
     355                 :            :      *  \param value the value to be set
     356                 :            :      *  \returns TRUE on success
     357                 :            :     */
     358                 :          0 :     bool setValue( qgssize index, double value ) SIP_HOLDGIL
     359                 :            :     {
     360                 :          0 :       if ( !mData )
     361                 :            :       {
     362                 :          0 :         QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
     363                 :          0 :         return false;
     364                 :            :       }
     365                 :          0 :       if ( index >= static_cast< qgssize >( mWidth ) *mHeight )
     366                 :            :       {
     367                 :          0 :         QgsDebugMsg( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
     368                 :          0 :         return false;
     369                 :            :       }
     370                 :          0 :       writeValue( mData, mDataType, index, value );
     371                 :          0 :       return true;
     372                 :          0 :     }
     373                 :            : 
     374                 :            :     /**
     375                 :            :      * \brief Set color on position
     376                 :            :      *  \param row row index
     377                 :            :      *  \param column column index
     378                 :            :      *  \param color the color to be set, QRgb value
     379                 :            :      *  \returns TRUE on success
     380                 :            :     */
     381                 :          0 :     bool setColor( int row, int column, QRgb color ) SIP_HOLDGIL
     382                 :            :     {
     383                 :          0 :       return setColor( static_cast< qgssize >( row ) * mWidth + column, color );
     384                 :            :     }
     385                 :            : 
     386                 :            :     /**
     387                 :            :      * \brief Set color on index (indexed line by line)
     388                 :            :      *  \param index data matrix index (long type in Python)
     389                 :            :      *  \param color the color to be set, QRgb value
     390                 :            :      *  \returns TRUE on success
     391                 :            :     */
     392                 :          0 :     bool setColor( qgssize index, QRgb color ) SIP_HOLDGIL
     393                 :            :     {
     394                 :          0 :       if ( !mImage )
     395                 :            :       {
     396                 :          0 :         QgsDebugMsg( QStringLiteral( "Image not allocated" ) );
     397                 :          0 :         return false;
     398                 :            :       }
     399                 :            : 
     400                 :          0 :       if ( index >= static_cast< qgssize >( mImage->width() ) * mImage->height() )
     401                 :            :       {
     402                 :          0 :         QgsDebugMsg( QStringLiteral( "index %1 out of range" ).arg( index ) );
     403                 :          0 :         return false;
     404                 :            :       }
     405                 :            : 
     406                 :            :       // setPixel() is slow, see Qt doc -> use direct access
     407                 :          0 :       QRgb *bits = reinterpret_cast< QRgb * >( mImage->bits() );
     408                 :          0 :       bits[index] = color;
     409                 :          0 :       return true;
     410                 :          0 :     }
     411                 :            : 
     412                 :            :     /**
     413                 :            :      * Gives direct read/write access to the raster RGB data.
     414                 :            :      * The data type of the block must be Qgis::ARGB32 or Qgis::ARGB32_Premultiplied otherwise it returns NULLPTR.
     415                 :            :      * Useful for most efficient read/write access to RGB blocks.
     416                 :            :      * \note not available in Python bindings
     417                 :            :      * \since QGIS 3.4
     418                 :            :      */
     419                 :          0 :     QRgb *colorData() SIP_SKIP
     420                 :            :     {
     421                 :          0 :       if ( !mImage )
     422                 :          0 :         return nullptr;
     423                 :          0 :       return reinterpret_cast< QRgb * >( mImage->bits() );
     424                 :          0 :     }
     425                 :            : 
     426                 :            :     /**
     427                 :            :      * \brief Set no data on pixel
     428                 :            :      *  \param row row index
     429                 :            :      *  \param column column index
     430                 :            :      *  \returns TRUE on success
     431                 :            :     */
     432                 :          0 :     bool setIsNoData( int row, int column ) SIP_HOLDGIL
     433                 :            :     {
     434                 :          0 :       return setIsNoData( static_cast< qgssize >( row ) * mWidth + column );
     435                 :            :     }
     436                 :            : 
     437                 :            :     /**
     438                 :            :      * \brief Set no data on pixel
     439                 :            :      *  \param index data matrix index (long type in Python)
     440                 :            :      *  \returns TRUE on success
     441                 :            :     */
     442                 :          0 :     bool setIsNoData( qgssize index ) SIP_HOLDGIL
     443                 :            :     {
     444                 :          0 :       if ( mHasNoDataValue )
     445                 :            :       {
     446                 :          0 :         return setValue( index, mNoDataValue );
     447                 :            :       }
     448                 :            :       else
     449                 :            :       {
     450                 :          0 :         if ( !mNoDataBitmap )
     451                 :            :         {
     452                 :          0 :           if ( !createNoDataBitmap() )
     453                 :            :           {
     454                 :          0 :             return false;
     455                 :            :           }
     456                 :          0 :         }
     457                 :            :         // TODO: optimize
     458                 :          0 :         int row = static_cast< int >( index ) / mWidth;
     459                 :          0 :         int column = index % mWidth;
     460                 :          0 :         qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
     461                 :          0 :         int bit = column % 8;
     462                 :          0 :         int nodata = 0x80 >> bit;
     463                 :            :         //QgsDebugMsg ( QString("set byte = %1 bit = %2 no data by %3").arg(byte).arg(bit).arg(nodata, 0,2 ) );
     464                 :          0 :         mNoDataBitmap[byte] = mNoDataBitmap[byte] | nodata;
     465                 :          0 :         return true;
     466                 :            :       }
     467                 :          0 :     }
     468                 :            : 
     469                 :            :     /**
     470                 :            :      * \brief Set the whole block to no data
     471                 :            :      *  \returns TRUE on success
     472                 :            :     */
     473                 :            :     bool setIsNoData();
     474                 :            : 
     475                 :            :     /**
     476                 :            :      * \brief Set the whole block to no data except specified rectangle
     477                 :            :      *  \returns TRUE on success
     478                 :            :     */
     479                 :            :     bool setIsNoDataExcept( QRect exceptRect );
     480                 :            : 
     481                 :            :     /**
     482                 :            :      * \brief Remove no data flag on pixel. If the raster block does not have an explicit
     483                 :            :      * no data value set then an internal map of no data pixels is maintained for the block.
     484                 :            :      * In this case it is possible to reset a pixel to flag it as having valid data using this
     485                 :            :      * method. This method has no effect for raster blocks with an explicit no data value set.
     486                 :            :      *  \param row row index
     487                 :            :      *  \param column column index
     488                 :            :      *  \since QGIS 2.10
     489                 :            :     */
     490                 :          0 :     void setIsData( int row, int column ) SIP_HOLDGIL
     491                 :            :     {
     492                 :          0 :       setIsData( static_cast< qgssize >( row )*mWidth + column );
     493                 :          0 :     }
     494                 :            : 
     495                 :            :     /**
     496                 :            :      * \brief Remove no data flag on pixel. If the raster block does not have an explicit
     497                 :            :      * no data value set then an internal map of no data pixels is maintained for the block.
     498                 :            :      * In this case it is possible to reset a pixel to flag it as having valid data using this
     499                 :            :      * method. This method has no effect for raster blocks with an explicit no data value set.
     500                 :            :      *  \param index data matrix index (long type in Python)
     501                 :            :      *  \since QGIS 2.10
     502                 :            :     */
     503                 :          0 :     void setIsData( qgssize index ) SIP_HOLDGIL
     504                 :            :     {
     505                 :          0 :       if ( mHasNoDataValue )
     506                 :            :       {
     507                 :            :         //no data value set, so mNoDataBitmap is not being used
     508                 :          0 :         return;
     509                 :            :       }
     510                 :            : 
     511                 :          0 :       if ( !mNoDataBitmap )
     512                 :            :       {
     513                 :          0 :         return;
     514                 :            :       }
     515                 :            : 
     516                 :            :       // TODO: optimize
     517                 :          0 :       int row = static_cast< int >( index ) / mWidth;
     518                 :          0 :       int column = index % mWidth;
     519                 :          0 :       qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
     520                 :          0 :       int bit = column % 8;
     521                 :          0 :       int nodata = 0x80 >> bit;
     522                 :          0 :       mNoDataBitmap[byte] = mNoDataBitmap[byte] & ~nodata;
     523                 :          0 :     }
     524                 :            : 
     525                 :            :     /**
     526                 :            :      * Gets access to raw data.
     527                 :            :      * The returned QByteArray instance is not a copy of the data: it only refers to the array
     528                 :            :      * owned by the QgsRasterBlock, therefore it is only valid while the QgsRasterBlock object
     529                 :            :      * still exists. Writing to the returned QByteArray will not affect the original data:
     530                 :            :      * a deep copy of the data will be made and only the local copy will be modified.
     531                 :            :      * \note in Python the method returns ordinary bytes object as the
     532                 :            :      * \since QGIS 3.0
     533                 :            :      */
     534                 :            :     QByteArray data() const;
     535                 :            : 
     536                 :            :     /**
     537                 :            :      * Rewrite raw pixel data.
     538                 :            :      * If the data array is shorter than the internal array within the raster block object,
     539                 :            :      * pixels at the end will stay untouched. If the data array is longer than the internal
     540                 :            :      * array, only the initial data from the input array will be used.
     541                 :            :      * Optionally it is possible to set non-zero offset (in bytes) if the input data should
     542                 :            :      * overwrite data somewhere in the middle of the internal buffer.
     543                 :            :      * \since QGIS 3.0
     544                 :            :      */
     545                 :            :     void setData( const QByteArray &data, int offset = 0 );
     546                 :            : 
     547                 :            :     /**
     548                 :            :      * Returns a pointer to block data.
     549                 :            :      * \param row row index
     550                 :            :      * \param column column index
     551                 :            :      * \note not available in Python bindings
     552                 :            :      */
     553                 :            :     char *bits( int row, int column ) SIP_SKIP;
     554                 :            : 
     555                 :            :     /**
     556                 :            :      * Returns a pointer to block data.
     557                 :            :      * \param index data matrix index (long type in Python)
     558                 :            :      * \note not available in Python bindings
     559                 :            :      */
     560                 :            :     char *bits( qgssize index ) SIP_SKIP;
     561                 :            : 
     562                 :            :     /**
     563                 :            :      * Returns a pointer to block data.
     564                 :            :      * \note not available in Python bindings
     565                 :            :      */
     566                 :            :     char *bits() SIP_SKIP;
     567                 :            : 
     568                 :            :     /**
     569                 :            :      * \brief Print double value with all necessary significant digits.
     570                 :            :      *         It is ensured that conversion back to double gives the same number.
     571                 :            :      *  \param value the value to be printed
     572                 :            :      *  \returns string representing the value
     573                 :            :      */
     574                 :            :     static QString printValue( double value );
     575                 :            : 
     576                 :            :     /**
     577                 :            :      * \brief Print float value with all necessary significant digits.
     578                 :            :      *         It is ensured that conversion back to float gives the same number.
     579                 :            :      *  \param value the value to be printed
     580                 :            :      *  \returns string representing the value
     581                 :            :      * \note not available in Python bindings
     582                 :            :      * \since QGIS 2.16
     583                 :            :      */
     584                 :            :     static QString printValue( float value ) SIP_SKIP;
     585                 :            : 
     586                 :            :     /**
     587                 :            :      * \brief Convert data to different type.
     588                 :            :      *  \param destDataType dest data type
     589                 :            :      *  \returns TRUE on success
     590                 :            :     */
     591                 :            :     bool convert( Qgis::DataType destDataType );
     592                 :            : 
     593                 :            :     /**
     594                 :            :      * Returns an image containing the block data, if the block's data type is color.
     595                 :            :      */
     596                 :            :     QImage image() const;
     597                 :            : 
     598                 :            :     /**
     599                 :            :      * Sets the block data via an \a image.
     600                 :            :      * \returns TRUE on success
     601                 :            :     */
     602                 :            :     bool setImage( const QImage *image );
     603                 :            : 
     604                 :            :     //! \note not available in Python bindings
     605                 :            :     inline static double readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP;
     606                 :            : 
     607                 :            :     //! \note not available in Python bindings
     608                 :            :     inline static void writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP;
     609                 :            : 
     610                 :            :     void applyNoDataValues( const QgsRasterRangeList &rangeList );
     611                 :            : 
     612                 :            :     /**
     613                 :            :      * Apply band scale and offset to raster block values
     614                 :            :      * \since QGIS 2.3
     615                 :            :     */
     616                 :            :     void applyScaleOffset( double scale, double offset );
     617                 :            : 
     618                 :            :     //! Returns the last error
     619                 :            :     QgsError error() const { return mError; }
     620                 :            : 
     621                 :            :     //! Sets the last error
     622                 :          0 :     void setError( const QgsError &error ) { mError = error;}
     623                 :            : 
     624                 :            :     QString toString() const;
     625                 :            : 
     626                 :            :     /**
     627                 :            :      * \brief For extent and width, height find rectangle covered by subextent.
     628                 :            :      * The output rect has x oriented from left to right and y from top to bottom
     629                 :            :      * (upper-left to lower-right orientation).
     630                 :            :      * \param extent extent, usually the larger
     631                 :            :      * \param width numbers of columns in theExtent
     632                 :            :      * \param height numbers of rows in theExtent
     633                 :            :      * \param subExtent extent, usually smaller than theExtent
     634                 :            :      * \returns the rectangle covered by sub extent
     635                 :            :      */
     636                 :            :     static QRect subRect( const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent );
     637                 :            : 
     638                 :            :     /**
     639                 :            :      * Returns the width (number of columns) of the raster block.
     640                 :            :      * \see height
     641                 :            :      * \since QGIS 2.10
     642                 :            :      */
     643                 :          0 :     int width() const SIP_HOLDGIL { return mWidth; }
     644                 :            : 
     645                 :            :     /**
     646                 :            :      * Returns the height (number of rows) of the raster block.
     647                 :            :      * \see width
     648                 :            :      * \since QGIS 2.10
     649                 :            :      */
     650                 :          0 :     int height() const SIP_HOLDGIL { return mHeight; }
     651                 :            : 
     652                 :            :   private:
     653                 :            :     static QImage::Format imageFormat( Qgis::DataType dataType );
     654                 :            :     static Qgis::DataType dataType( QImage::Format format );
     655                 :            : 
     656                 :            :     /**
     657                 :            :      * Test if value is nodata comparing to noDataValue
     658                 :            :      * \param value tested value
     659                 :            :      * \param noDataValue no data value
     660                 :            :      * \returns TRUE if value is nodata
     661                 :            :     */
     662                 :            :     static bool isNoDataValue( double value, double noDataValue )
     663                 :            :     {
     664                 :            :       // TODO: optimize no data value test by memcmp()
     665                 :            :       // More precise would be std::isnan(value) && std::isnan(noDataValue(bandNo)), but probably
     666                 :            :       // not important and slower
     667                 :            :       return std::isnan( value ) ||
     668                 :            :              qgsDoubleNear( value, noDataValue );
     669                 :            :     }
     670                 :            : 
     671                 :            :     /**
     672                 :            :      * Test if value is nodata for specific band
     673                 :            :      * \param value tested value
     674                 :            :      * \returns TRUE if value is nodata
     675                 :            :     */
     676                 :            :     inline bool isNoDataValue( double value ) const;
     677                 :            : 
     678                 :            :     /**
     679                 :            :      * Allocate no data bitmap
     680                 :            :      *  \returns TRUE on success
     681                 :            :     */
     682                 :            :     bool createNoDataBitmap();
     683                 :            : 
     684                 :            :     /**
     685                 :            :      * \brief Convert block of data from one type to another. Original block memory
     686                 :            :      *         is not release.
     687                 :            :      *  \param srcData source data
     688                 :            :      *  \param srcDataType source data type
     689                 :            :      *  \param destDataType dest data type
     690                 :            :      *  \param size block size (width * height)
     691                 :            :      *  \returns block of data in destDataType
     692                 :            :     */
     693                 :            :     static void *convert( void *srcData, Qgis::DataType srcDataType, Qgis::DataType destDataType, qgssize size );
     694                 :            : 
     695                 :            :     // Valid
     696                 :            :     bool mValid = true;
     697                 :            : 
     698                 :            :     // Data type
     699                 :            :     Qgis::DataType mDataType = Qgis::UnknownDataType;
     700                 :            : 
     701                 :            :     // Data type size in bytes, to make bits() fast
     702                 :            :     int mTypeSize = 0;
     703                 :            : 
     704                 :            :     // Width
     705                 :            :     int mWidth = 0;
     706                 :            : 
     707                 :            :     // Height
     708                 :            :     int mHeight = 0;
     709                 :            : 
     710                 :            :     // Has no data value
     711                 :            :     bool mHasNoDataValue = false;
     712                 :            : 
     713                 :            :     // No data value
     714                 :            :     double mNoDataValue;
     715                 :            : 
     716                 :            :     static const QRgb NO_DATA_COLOR;
     717                 :            : 
     718                 :            :     // Data block for numerical data types, not used with image data types
     719                 :            :     // QByteArray does not seem to be intended for large data blocks, does it?
     720                 :            :     void *mData = nullptr;
     721                 :            : 
     722                 :            :     // Image for image data types, not used with numerical data types
     723                 :            :     QImage *mImage = nullptr;
     724                 :            : 
     725                 :            :     // Bitmap of no data. One bit for each pixel. Bit is 1 if a pixels is no data.
     726                 :            :     // Each row is represented by whole number of bytes (last bits may be unused)
     727                 :            :     // to make processing rows easy.
     728                 :            :     char *mNoDataBitmap = nullptr;
     729                 :            : 
     730                 :            :     // number of bytes in mNoDataBitmap row
     731                 :            :     int mNoDataBitmapWidth = 0;
     732                 :            : 
     733                 :            :     // total size in bytes of mNoDataBitmap
     734                 :            :     qgssize mNoDataBitmapSize = 0;
     735                 :            : 
     736                 :            :     // Error
     737                 :            :     QgsError mError;
     738                 :            : };
     739                 :            : 
     740                 :          0 : inline double QgsRasterBlock::readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP
     741                 :            : {
     742                 :          0 :   if ( !data )
     743                 :            :   {
     744                 :          0 :     return std::numeric_limits<double>::quiet_NaN();
     745                 :            :   }
     746                 :            : 
     747                 :          0 :   switch ( type )
     748                 :            :   {
     749                 :            :     case Qgis::Byte:
     750                 :          0 :       return static_cast< double >( ( static_cast< quint8 * >( data ) )[index] );
     751                 :            :     case Qgis::UInt16:
     752                 :          0 :       return static_cast< double >( ( static_cast< quint16 * >( data ) )[index] );
     753                 :            :     case Qgis::Int16:
     754                 :          0 :       return static_cast< double >( ( static_cast< qint16 * >( data ) )[index] );
     755                 :            :     case Qgis::UInt32:
     756                 :          0 :       return static_cast< double >( ( static_cast< quint32 * >( data ) )[index] );
     757                 :            :     case Qgis::Int32:
     758                 :          0 :       return static_cast< double >( ( static_cast< qint32 * >( data ) )[index] );
     759                 :            :     case Qgis::Float32:
     760                 :          0 :       return static_cast< double >( ( static_cast< float * >( data ) )[index] );
     761                 :            :     case Qgis::Float64:
     762                 :          0 :       return static_cast< double >( ( static_cast< double * >( data ) )[index] );
     763                 :            :     default:
     764                 :          0 :       QgsDebugMsg( QStringLiteral( "Data type %1 is not supported" ).arg( type ) );
     765                 :          0 :       break;
     766                 :            :   }
     767                 :            : 
     768                 :          0 :   return std::numeric_limits<double>::quiet_NaN();
     769                 :          0 : }
     770                 :            : 
     771                 :          0 : inline void QgsRasterBlock::writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP
     772                 :            : {
     773                 :          0 :   if ( !data ) return;
     774                 :            : 
     775                 :          0 :   switch ( type )
     776                 :            :   {
     777                 :            :     case Qgis::Byte:
     778                 :          0 :       ( static_cast< quint8 * >( data ) )[index] = static_cast< quint8 >( value );
     779                 :          0 :       break;
     780                 :            :     case Qgis::UInt16:
     781                 :          0 :       ( static_cast< quint16 * >( data ) )[index] = static_cast< quint16 >( value );
     782                 :          0 :       break;
     783                 :            :     case Qgis::Int16:
     784                 :          0 :       ( static_cast< qint16 * >( data ) )[index] = static_cast< qint16 >( value );
     785                 :          0 :       break;
     786                 :            :     case Qgis::UInt32:
     787                 :          0 :       ( static_cast< quint32 * >( data ) )[index] = static_cast< quint32 >( value );
     788                 :          0 :       break;
     789                 :            :     case Qgis::Int32:
     790                 :          0 :       ( static_cast< qint32 * >( data ) )[index] = static_cast< qint32 >( value );
     791                 :          0 :       break;
     792                 :            :     case Qgis::Float32:
     793                 :          0 :       ( static_cast< float * >( data ) )[index] = static_cast< float >( value );
     794                 :          0 :       break;
     795                 :            :     case Qgis::Float64:
     796                 :          0 :       ( static_cast< double * >( data ) )[index] = value;
     797                 :          0 :       break;
     798                 :            :     default:
     799                 :          0 :       QgsDebugMsg( QStringLiteral( "Data type %1 is not supported" ).arg( type ) );
     800                 :          0 :       break;
     801                 :            :   }
     802                 :          0 : }
     803                 :            : 
     804                 :          0 : inline double QgsRasterBlock::value( qgssize index ) const SIP_SKIP
     805                 :            : {
     806                 :          0 :   if ( !mData )
     807                 :            :   {
     808                 :          0 :     QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
     809                 :          0 :     return std::numeric_limits<double>::quiet_NaN();
     810                 :            :   }
     811                 :          0 :   return readValue( mData, mDataType, index );
     812                 :          0 : }
     813                 :            : 
     814                 :          0 : inline double QgsRasterBlock::valueAndNoData( qgssize index, bool &isNoData ) const SIP_SKIP
     815                 :            : {
     816                 :          0 :   if ( !mData )
     817                 :            :   {
     818                 :          0 :     QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
     819                 :          0 :     isNoData = true;
     820                 :          0 :     return std::numeric_limits<double>::quiet_NaN();
     821                 :            :   }
     822                 :          0 :   if ( index >= static_cast< qgssize >( mWidth )*mHeight )
     823                 :            :   {
     824                 :          0 :     QgsDebugMsg( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
     825                 :          0 :     isNoData = true; // we consider no data if outside
     826                 :          0 :     return std::numeric_limits<double>::quiet_NaN();
     827                 :            :   }
     828                 :            : 
     829                 :          0 :   const double val = readValue( mData, mDataType, index );
     830                 :            : 
     831                 :          0 :   if ( !mHasNoDataValue && !mNoDataBitmap )
     832                 :            :   {
     833                 :          0 :     isNoData = false;
     834                 :          0 :     return val;
     835                 :            :   }
     836                 :            : 
     837                 :          0 :   if ( mHasNoDataValue )
     838                 :            :   {
     839                 :          0 :     isNoData = isNoDataValue( val );
     840                 :          0 :     return val;
     841                 :            :   }
     842                 :            :   // use no data bitmap
     843                 :          0 :   if ( !mNoDataBitmap )
     844                 :            :   {
     845                 :            :     // no data are not defined
     846                 :          0 :     isNoData = false;
     847                 :          0 :     return val;
     848                 :            :   }
     849                 :            : 
     850                 :            :   // no data is a bitmap
     851                 :          0 :   isNoData = QgsRasterBlock::isNoData( index );
     852                 :          0 :   return val;
     853                 :          0 : }
     854                 :            : 
     855                 :          0 : inline bool QgsRasterBlock::isNoDataValue( double value ) const SIP_SKIP
     856                 :            : {
     857                 :          0 :   return std::isnan( value ) || qgsDoubleNear( value, mNoDataValue );
     858                 :            : }
     859                 :            : 
     860                 :            : #endif
     861                 :            : 
     862                 :            : 

Generated by: LCOV version 1.14