QGIS API Documentation  3.14.0-Pi (9f7028fd23)
qgsrasterblock.h
Go to the documentation of this file.
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 
36 class CORE_EXPORT QgsRasterBlock
37 {
38  public:
40 
47  QgsRasterBlock( Qgis::DataType dataType, int width, int height );
48 
49  virtual ~QgsRasterBlock();
50 
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 
68  bool isValid() const { return mValid; }
69 
71  void setValid( bool valid ) { mValid = valid; }
72 
78  bool isEmpty() const;
79 
80  // Return data type size in bytes
81  static int typeSize( int dataType )
82  {
83  // Modified and extended copy from GDAL
84  switch ( dataType )
85  {
86  case Qgis::Byte:
87  return 1;
88 
89  case Qgis::UInt16:
90  case Qgis::Int16:
91  return 2;
92 
93  case Qgis::UInt32:
94  case Qgis::Int32:
95  case Qgis::Float32:
96  case Qgis::CInt16:
97  return 4;
98 
99  case Qgis::Float64:
100  case Qgis::CInt32:
101  case Qgis::CFloat32:
102  return 8;
103 
104  case Qgis::CFloat64:
105  return 16;
106 
107  case Qgis::ARGB32:
109  return 4;
110 
111  default:
112  return 0;
113  }
114  }
115 
116  // Data type in bytes
117  int dataTypeSize() const
118  {
119  return typeSize( mDataType );
120  }
121 
123  static bool typeIsNumeric( Qgis::DataType type );
124 
126  static bool typeIsColor( Qgis::DataType type );
127 
129  Qgis::DataType dataType() const { return mDataType; }
130 
132  static Qgis::DataType typeWithNoDataValue( Qgis::DataType dataType, double *noDataValue );
133 
139  bool hasNoDataValue() const { return mHasNoDataValue; }
140 
147  bool hasNoData() const
148  {
149  return mHasNoDataValue || mNoDataBitmap;
150  }
151 
157  void setNoDataValue( double noDataValue );
158 
165  void resetNoDataValue();
166 
173  double noDataValue() const { return mNoDataValue; }
174 
181  static QByteArray valueBytes( Qgis::DataType dataType, double value );
182 
191  double value( int row, int column ) const
192  {
193  return value( static_cast< qgssize >( row ) * mWidth + column );
194  }
195 
208  double valueAndNoData( int row, int column, bool &isNoData ) const SIP_SKIP
209  {
210  return valueAndNoData( static_cast< qgssize >( row ) * mWidth + column, isNoData );
211  }
212 
220  inline double value( qgssize index ) const;
221 
234  inline double valueAndNoData( qgssize index, bool &isNoData ) const SIP_SKIP;
235 
243  const quint8 *byteData() const SIP_SKIP
244  {
245  if ( mDataType != Qgis::Byte )
246  return nullptr;
247  return static_cast< const quint8 * >( mData );
248  }
249 
256  QRgb color( int row, int column ) const
257  {
258  if ( !mImage ) return NO_DATA_COLOR;
259 
260  return mImage->pixel( column, row );
261  }
262 
268  QRgb color( qgssize index ) const
269  {
270  int row = static_cast< int >( std::floor( static_cast< double >( index ) / mWidth ) );
271  int column = index % mWidth;
272  return color( row, column );
273  }
274 
282  bool isNoData( int row, int column ) const
283  {
284  return isNoData( static_cast< qgssize >( row ) * mWidth + column );
285  }
286 
294  bool isNoData( qgssize row, qgssize column ) const
295  {
296  return isNoData( row * static_cast< qgssize >( mWidth ) + column );
297  }
298 
305  bool isNoData( qgssize index ) const
306  {
307  if ( !mHasNoDataValue && !mNoDataBitmap )
308  return false;
309  if ( index >= static_cast< qgssize >( mWidth )*mHeight )
310  {
311  QgsDebugMsg( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
312  return true; // we consider no data if outside
313  }
314  if ( mHasNoDataValue )
315  {
316  double value = readValue( mData, mDataType, index );
317  return isNoDataValue( value );
318  }
319  // use no data bitmap
320  if ( !mNoDataBitmap )
321  {
322  // no data are not defined
323  return false;
324  }
325  // TODO: optimize
326  int row = static_cast< int >( index ) / mWidth;
327  int column = index % mWidth;
328  qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
329  int bit = column % 8;
330  int mask = 0x80 >> bit;
331  //int x = mNoDataBitmap[byte] & mask;
332  //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) ) );
333  return mNoDataBitmap[byte] & mask;
334  }
335 
343  bool setValue( int row, int column, double value )
344  {
345  return setValue( static_cast< qgssize >( row ) * mWidth + column, value );
346  }
347 
354  bool setValue( qgssize index, double value )
355  {
356  if ( !mData )
357  {
358  QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
359  return false;
360  }
361  if ( index >= static_cast< qgssize >( mWidth ) *mHeight )
362  {
363  QgsDebugMsg( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
364  return false;
365  }
366  writeValue( mData, mDataType, index, value );
367  return true;
368  }
369 
377  bool setColor( int row, int column, QRgb color )
378  {
379  return setColor( static_cast< qgssize >( row ) * mWidth + column, color );
380  }
381 
388  bool setColor( qgssize index, QRgb color )
389  {
390  if ( !mImage )
391  {
392  QgsDebugMsg( QStringLiteral( "Image not allocated" ) );
393  return false;
394  }
395 
396  if ( index >= static_cast< qgssize >( mImage->width() ) * mImage->height() )
397  {
398  QgsDebugMsg( QStringLiteral( "index %1 out of range" ).arg( index ) );
399  return false;
400  }
401 
402  // setPixel() is slow, see Qt doc -> use direct access
403  QRgb *bits = reinterpret_cast< QRgb * >( mImage->bits() );
404  bits[index] = color;
405  return true;
406  }
407 
416  {
417  if ( !mImage )
418  return nullptr;
419  return reinterpret_cast< QRgb * >( mImage->bits() );
420  }
421 
428  bool setIsNoData( int row, int column )
429  {
430  return setIsNoData( static_cast< qgssize >( row ) * mWidth + column );
431  }
432 
438  bool setIsNoData( qgssize index )
439  {
440  if ( mHasNoDataValue )
441  {
442  return setValue( index, mNoDataValue );
443  }
444  else
445  {
446  if ( !mNoDataBitmap )
447  {
448  if ( !createNoDataBitmap() )
449  {
450  return false;
451  }
452  }
453  // TODO: optimize
454  int row = static_cast< int >( index ) / mWidth;
455  int column = index % mWidth;
456  qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
457  int bit = column % 8;
458  int nodata = 0x80 >> bit;
459  //QgsDebugMsg ( QString("set byte = %1 bit = %2 no data by %3").arg(byte).arg(bit).arg(nodata, 0,2 ) );
460  mNoDataBitmap[byte] = mNoDataBitmap[byte] | nodata;
461  return true;
462  }
463  }
464 
469  bool setIsNoData();
470 
475  bool setIsNoDataExcept( QRect exceptRect );
476 
486  void setIsData( int row, int column )
487  {
488  setIsData( static_cast< qgssize >( row )*mWidth + column );
489  }
490 
499  void setIsData( qgssize index )
500  {
501  if ( mHasNoDataValue )
502  {
503  //no data value set, so mNoDataBitmap is not being used
504  return;
505  }
506 
507  if ( !mNoDataBitmap )
508  {
509  return;
510  }
511 
512  // TODO: optimize
513  int row = static_cast< int >( index ) / mWidth;
514  int column = index % mWidth;
515  qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
516  int bit = column % 8;
517  int nodata = 0x80 >> bit;
518  mNoDataBitmap[byte] = mNoDataBitmap[byte] & ~nodata;
519  }
520 
530  QByteArray data() const;
531 
541  void setData( const QByteArray &data, int offset = 0 );
542 
549  char *bits( int row, int column ) SIP_SKIP;
550 
556  char *bits( qgssize index ) SIP_SKIP;
557 
562  char *bits() SIP_SKIP;
563 
569  static QString printValue( double value );
570 
579  static QString printValue( float value ) SIP_SKIP;
580 
586  bool convert( Qgis::DataType destDataType );
587 
591  QImage image() const;
592 
597  bool setImage( const QImage *image );
598 
600  inline static double readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP;
601 
603  inline static void writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP;
604 
605  void applyNoDataValues( const QgsRasterRangeList &rangeList );
606 
611  void applyScaleOffset( double scale, double offset );
612 
614  QgsError error() const { return mError; }
615 
617  void setError( const QgsError &error ) { mError = error;}
618 
619  QString toString() const;
620 
631  static QRect subRect( const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent );
632 
638  int width() const { return mWidth; }
639 
645  int height() const { return mHeight; }
646 
647  private:
648  static QImage::Format imageFormat( Qgis::DataType dataType );
649  static Qgis::DataType dataType( QImage::Format format );
650 
657  static bool isNoDataValue( double value, double noDataValue )
658  {
659  // TODO: optimize no data value test by memcmp()
660  // More precise would be std::isnan(value) && std::isnan(noDataValue(bandNo)), but probably
661  // not important and slower
662  return std::isnan( value ) ||
663  qgsDoubleNear( value, noDataValue );
664  }
665 
671  inline bool isNoDataValue( double value ) const;
672 
677  bool createNoDataBitmap();
678 
688  static void *convert( void *srcData, Qgis::DataType srcDataType, Qgis::DataType destDataType, qgssize size );
689 
690  // Valid
691  bool mValid = true;
692 
693  // Data type
695 
696  // Data type size in bytes, to make bits() fast
697  int mTypeSize = 0;
698 
699  // Width
700  int mWidth = 0;
701 
702  // Height
703  int mHeight = 0;
704 
705  // Has no data value
706  bool mHasNoDataValue = false;
707 
708  // No data value
709  double mNoDataValue;
710 
711  static const QRgb NO_DATA_COLOR;
712 
713  // Data block for numerical data types, not used with image data types
714  // QByteArray does not seem to be intended for large data blocks, does it?
715  void *mData = nullptr;
716 
717  // Image for image data types, not used with numerical data types
718  QImage *mImage = nullptr;
719 
720  // Bitmap of no data. One bit for each pixel. Bit is 1 if a pixels is no data.
721  // Each row is represented by whole number of bytes (last bits may be unused)
722  // to make processing rows easy.
723  char *mNoDataBitmap = nullptr;
724 
725  // number of bytes in mNoDataBitmap row
726  int mNoDataBitmapWidth = 0;
727 
728  // total size in bytes of mNoDataBitmap
729  qgssize mNoDataBitmapSize = 0;
730 
731  // Error
732  QgsError mError;
733 };
734 
735 inline double QgsRasterBlock::readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP
736 {
737  if ( !data )
738  {
739  return std::numeric_limits<double>::quiet_NaN();
740  }
741 
742  switch ( type )
743  {
744  case Qgis::Byte:
745  return static_cast< double >( ( static_cast< quint8 * >( data ) )[index] );
746  case Qgis::UInt16:
747  return static_cast< double >( ( static_cast< quint16 * >( data ) )[index] );
748  case Qgis::Int16:
749  return static_cast< double >( ( static_cast< qint16 * >( data ) )[index] );
750  case Qgis::UInt32:
751  return static_cast< double >( ( static_cast< quint32 * >( data ) )[index] );
752  case Qgis::Int32:
753  return static_cast< double >( ( static_cast< qint32 * >( data ) )[index] );
754  case Qgis::Float32:
755  return static_cast< double >( ( static_cast< float * >( data ) )[index] );
756  case Qgis::Float64:
757  return static_cast< double >( ( static_cast< double * >( data ) )[index] );
758  default:
759  QgsDebugMsg( QStringLiteral( "Data type %1 is not supported" ).arg( type ) );
760  break;
761  }
762 
763  return std::numeric_limits<double>::quiet_NaN();
764 }
765 
766 inline void QgsRasterBlock::writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP
767 {
768  if ( !data ) return;
769 
770  switch ( type )
771  {
772  case Qgis::Byte:
773  ( static_cast< quint8 * >( data ) )[index] = static_cast< quint8 >( value );
774  break;
775  case Qgis::UInt16:
776  ( static_cast< quint16 * >( data ) )[index] = static_cast< quint16 >( value );
777  break;
778  case Qgis::Int16:
779  ( static_cast< qint16 * >( data ) )[index] = static_cast< qint16 >( value );
780  break;
781  case Qgis::UInt32:
782  ( static_cast< quint32 * >( data ) )[index] = static_cast< quint32 >( value );
783  break;
784  case Qgis::Int32:
785  ( static_cast< qint32 * >( data ) )[index] = static_cast< qint32 >( value );
786  break;
787  case Qgis::Float32:
788  ( static_cast< float * >( data ) )[index] = static_cast< float >( value );
789  break;
790  case Qgis::Float64:
791  ( static_cast< double * >( data ) )[index] = value;
792  break;
793  default:
794  QgsDebugMsg( QStringLiteral( "Data type %1 is not supported" ).arg( type ) );
795  break;
796  }
797 }
798 
799 inline double QgsRasterBlock::value( qgssize index ) const SIP_SKIP
800 {
801  if ( !mData )
802  {
803  QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
804  return std::numeric_limits<double>::quiet_NaN();
805  }
806  return readValue( mData, mDataType, index );
807 }
808 
809 inline double QgsRasterBlock::valueAndNoData( qgssize index, bool &isNoData ) const SIP_SKIP
810 {
811  if ( !mData )
812  {
813  QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
814  isNoData = true;
815  return std::numeric_limits<double>::quiet_NaN();
816  }
817  if ( index >= static_cast< qgssize >( mWidth )*mHeight )
818  {
819  QgsDebugMsg( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
820  isNoData = true; // we consider no data if outside
821  return std::numeric_limits<double>::quiet_NaN();
822  }
823 
824  const double val = readValue( mData, mDataType, index );
825 
826  if ( !mHasNoDataValue && !mNoDataBitmap )
827  {
828  isNoData = false;
829  return val;
830  }
831 
832  if ( mHasNoDataValue )
833  {
834  isNoData = isNoDataValue( val );
835  return val;
836  }
837  // use no data bitmap
838  if ( !mNoDataBitmap )
839  {
840  // no data are not defined
841  isNoData = false;
842  return val;
843  }
844 
845  // no data is a bitmap
846  isNoData = QgsRasterBlock::isNoData( index );
847  return val;
848 }
849 
850 inline bool QgsRasterBlock::isNoDataValue( double value ) const SIP_SKIP
851 {
852  return std::isnan( value ) || qgsDoubleNear( value, mNoDataValue );
853 }
854 
855 #endif
856 
857 
QgsRasterBlock::color
QRgb color(qgssize index) const
Read a single value.
Definition: qgsrasterblock.h:268
QgsRasterBlock::dataTypeSize
int dataTypeSize() const
Definition: qgsrasterblock.h:117
Qgis::Float32
@ Float32
Thirty two bit floating point (float)
Definition: qgis.h:122
Qgis::DataType
DataType
Raster data types.
Definition: qgis.h:114
Qgis::UInt32
@ UInt32
Thirty two bit unsigned integer (quint32)
Definition: qgis.h:120
QgsRasterBlock::isNoData
bool isNoData(qgssize row, qgssize column) const
Check if value at position is no data.
Definition: qgsrasterblock.h:294
QgsRasterBlock::color
QRgb color(int row, int column) const
Read a single color.
Definition: qgsrasterblock.h:256
QgsError
Definition: qgserror.h:80
qgis.h
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsRasterBlock::readValue
static double readValue(void *data, Qgis::DataType type, qgssize index)
Definition: qgsrasterblock.h:735
QgsRectangle
Definition: qgsrectangle.h:41
Qgis::CFloat32
@ CFloat32
Complex Float32.
Definition: qgis.h:126
QgsRasterBlock::setColor
bool setColor(qgssize index, QRgb color)
Set color on index (indexed line by line)
Definition: qgsrasterblock.h:388
QgsRasterBlock::setIsData
void setIsData(int row, int column)
Remove no data flag on pixel.
Definition: qgsrasterblock.h:486
QgsRasterBlock::isNoData
bool isNoData(qgssize index) const
Check if value at position is no data.
Definition: qgsrasterblock.h:305
QgsRasterBlock::setValid
void setValid(bool valid)
Mark block as valid or invalid.
Definition: qgsrasterblock.h:71
QgsRasterBlock::setIsData
void setIsData(qgssize index)
Remove no data flag on pixel.
Definition: qgsrasterblock.h:499
QgsRasterBlock::valueAndNoData
double valueAndNoData(int row, int column, bool &isNoData) const
Reads a single value from the pixel at row and column, if type of block is numeric.
Definition: qgsrasterblock.h:208
QgsRasterBlock::setIsNoData
bool setIsNoData(int row, int column)
Set no data on pixel.
Definition: qgsrasterblock.h:428
Qgis::CFloat64
@ CFloat64
Complex Float64.
Definition: qgis.h:127
QgsRasterBlock::isValid
bool isValid() const
Returns true if the block is valid (correctly filled with data).
Definition: qgsrasterblock.h:68
SIP_SKIP
#define SIP_SKIP
Definition: qgis_sip.h:126
QgsRasterBlock::setColor
bool setColor(int row, int column, QRgb color)
Set color on position.
Definition: qgsrasterblock.h:377
qgserror.h
QgsRasterBlock::setIsNoData
bool setIsNoData(qgssize index)
Set no data on pixel.
Definition: qgsrasterblock.h:438
QgsRasterBlock::value
double value(int row, int column) const
Read a single value if type of block is numeric.
Definition: qgsrasterblock.h:191
QgsRasterBlock::hasNoDataValue
bool hasNoDataValue() const
true if the block has no data value.
Definition: qgsrasterblock.h:139
Qgis::CInt16
@ CInt16
Complex Int16.
Definition: qgis.h:124
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:315
qgis_sip.h
QgsRasterBlock::byteData
const quint8 * byteData() const
Gives direct access to the raster block data.
Definition: qgsrasterblock.h:243
QgsRasterBlock::setError
void setError(const QgsError &error)
Sets the last error.
Definition: qgsrasterblock.h:617
QgsRasterRangeList
QList< QgsRasterRange > QgsRasterRangeList
Definition: qgsrasterrange.h:26
Qgis::UInt16
@ UInt16
Sixteen bit unsigned integer (quint16)
Definition: qgis.h:118
QgsRasterBlock::isNoData
bool isNoData(int row, int column) const
Checks if value at position is no data.
Definition: qgsrasterblock.h:282
QgsRasterBlock::writeValue
static void writeValue(void *data, Qgis::DataType type, qgssize index, double value)
Definition: qgsrasterblock.h:766
QgsRasterBlock::dataType
Qgis::DataType dataType() const
Returns data type.
Definition: qgsrasterblock.h:129
QgsRasterBlock::width
int width() const
Returns the width (number of columns) of the raster block.
Definition: qgsrasterblock.h:638
Qgis::ARGB32_Premultiplied
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:129
QgsRasterBlock::typeSize
static int typeSize(int dataType)
Definition: qgsrasterblock.h:81
Qgis::Int16
@ Int16
Sixteen bit signed integer (qint16)
Definition: qgis.h:119
Qgis::Int32
@ Int32
Thirty two bit signed integer (qint32)
Definition: qgis.h:121
QgsRasterBlock::setValue
bool setValue(qgssize index, double value)
Set value on index (indexed line by line)
Definition: qgsrasterblock.h:354
QgsRasterBlock::height
int height() const
Returns the height (number of rows) of the raster block.
Definition: qgsrasterblock.h:645
Qgis
Definition: qgis.h:45
Qgis::UnknownDataType
@ UnknownDataType
Unknown or unspecified type.
Definition: qgis.h:116
Qgis::CInt32
@ CInt32
Complex Int32.
Definition: qgis.h:125
QgsRasterBlock::noDataValue
double noDataValue() const
Returns no data value.
Definition: qgsrasterblock.h:173
qgsrasterrange.h
Qgis::ARGB32
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:128
qgslogger.h
QgsRasterBlock::colorData
QRgb * colorData()
Gives direct read/write access to the raster RGB data.
Definition: qgsrasterblock.h:415
Qgis::Byte
@ Byte
Eight bit unsigned integer (quint8)
Definition: qgis.h:117
QgsRasterBlock
Definition: qgsrasterblock.h:36
QgsRasterBlock::hasNoData
bool hasNoData() const
Returns true if the block may contain no data.
Definition: qgsrasterblock.h:147
QgsRasterBlock::setValue
bool setValue(int row, int column, double value)
Set value on position.
Definition: qgsrasterblock.h:343
qgssize
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
Definition: qgis.h:723
Qgis::Float64
@ Float64
Sixty four bit floating point (double)
Definition: qgis.h:123