QGIS API Documentation  3.6.0-Noosa (5873452)
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 
146  bool hasNoData() const
147  {
148  return mHasNoDataValue || mNoDataBitmap;
149  }
150 
156  void setNoDataValue( double noDataValue );
157 
164  void resetNoDataValue();
165 
172  double noDataValue() const { return mNoDataValue; }
173 
179  static QByteArray valueBytes( Qgis::DataType dataType, double value );
180 
189  double value( int row, int column ) const
190  {
191  return value( static_cast< qgssize >( row ) * mWidth + column );
192  }
193 
206  double valueAndNoData( int row, int column, bool &isNoData ) const SIP_SKIP
207  {
208  return valueAndNoData( static_cast< qgssize >( row ) * mWidth + column, isNoData );
209  }
210 
218  double value( qgssize index ) const;
219 
232  double valueAndNoData( qgssize index, bool &isNoData ) const SIP_SKIP;
233 
241  const quint8 *byteData() const SIP_SKIP
242  {
243  if ( mDataType != Qgis::Byte )
244  return nullptr;
245  return static_cast< const quint8 * >( mData );
246  }
247 
253  QRgb color( int row, int column ) const
254  {
255  if ( !mImage ) return NO_DATA_COLOR;
256 
257  return mImage->pixel( column, row );
258  }
259 
264  QRgb color( qgssize index ) const
265  {
266  int row = static_cast< int >( std::floor( static_cast< double >( index ) / mWidth ) );
267  int column = index % mWidth;
268  return color( row, column );
269  }
270 
278  bool isNoData( int row, int column ) const
279  {
280  return isNoData( static_cast< qgssize >( row ) * mWidth + column );
281  }
282 
290  bool isNoData( qgssize row, qgssize column ) const
291  {
292  return isNoData( row * static_cast< qgssize >( mWidth ) + column );
293  }
294 
301  bool isNoData( qgssize index ) const
302  {
303  if ( !mHasNoDataValue && !mNoDataBitmap )
304  return false;
305  if ( index >= static_cast< qgssize >( mWidth )*mHeight )
306  {
307  QgsDebugMsg( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
308  return true; // we consider no data if outside
309  }
310  if ( mHasNoDataValue )
311  {
312  double value = readValue( mData, mDataType, index );
313  return isNoDataValue( value );
314  }
315  // use no data bitmap
316  if ( !mNoDataBitmap )
317  {
318  // no data are not defined
319  return false;
320  }
321  // TODO: optimize
322  int row = static_cast< int >( index ) / mWidth;
323  int column = index % mWidth;
324  qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
325  int bit = column % 8;
326  int mask = 0x80 >> bit;
327  //int x = mNoDataBitmap[byte] & mask;
328  //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) ) );
329  return mNoDataBitmap[byte] & mask;
330  }
331 
338  bool setValue( int row, int column, double value )
339  {
340  return setValue( static_cast< qgssize >( row ) * mWidth + column, value );
341  }
342 
348  bool setValue( qgssize index, double value )
349  {
350  if ( !mData )
351  {
352  QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
353  return false;
354  }
355  if ( index >= static_cast< qgssize >( mWidth ) *mHeight )
356  {
357  QgsDebugMsg( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
358  return false;
359  }
360  writeValue( mData, mDataType, index, value );
361  return true;
362  }
363 
370  bool setColor( int row, int column, QRgb color )
371  {
372  return setColor( static_cast< qgssize >( row ) * mWidth + column, color );
373  }
374 
380  bool setColor( qgssize index, QRgb color )
381  {
382  if ( !mImage )
383  {
384  QgsDebugMsg( QStringLiteral( "Image not allocated" ) );
385  return false;
386  }
387 
388  if ( index >= static_cast< qgssize >( mImage->width() ) * mImage->height() )
389  {
390  QgsDebugMsg( QStringLiteral( "index %1 out of range" ).arg( index ) );
391  return false;
392  }
393 
394  // setPixel() is slow, see Qt doc -> use direct access
395  QRgb *bits = reinterpret_cast< QRgb * >( mImage->bits() );
396  bits[index] = color;
397  return true;
398  }
399 
407  QRgb *colorData() SIP_SKIP
408  {
409  if ( !mImage )
410  return nullptr;
411  return reinterpret_cast< QRgb * >( mImage->bits() );
412  }
413 
419  bool setIsNoData( int row, int column )
420  {
421  return setIsNoData( static_cast< qgssize >( row ) * mWidth + column );
422  }
423 
428  bool setIsNoData( qgssize index )
429  {
430  if ( mHasNoDataValue )
431  {
432  return setValue( index, mNoDataValue );
433  }
434  else
435  {
436  if ( !mNoDataBitmap )
437  {
438  if ( !createNoDataBitmap() )
439  {
440  return false;
441  }
442  }
443  // TODO: optimize
444  int row = static_cast< int >( index ) / mWidth;
445  int column = index % mWidth;
446  qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
447  int bit = column % 8;
448  int nodata = 0x80 >> bit;
449  //QgsDebugMsg ( QString("set byte = %1 bit = %2 no data by %3").arg(byte).arg(bit).arg(nodata, 0,2 ) );
450  mNoDataBitmap[byte] = mNoDataBitmap[byte] | nodata;
451  return true;
452  }
453  }
454 
458  bool setIsNoData();
459 
463  bool setIsNoDataExcept( QRect exceptRect );
464 
473  void setIsData( int row, int column )
474  {
475  setIsData( static_cast< qgssize >( row )*mWidth + column );
476  }
477 
485  void setIsData( qgssize index )
486  {
487  if ( mHasNoDataValue )
488  {
489  //no data value set, so mNoDataBitmap is not being used
490  return;
491  }
492 
493  if ( !mNoDataBitmap )
494  {
495  return;
496  }
497 
498  // TODO: optimize
499  int row = static_cast< int >( index ) / mWidth;
500  int column = index % mWidth;
501  qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
502  int bit = column % 8;
503  int nodata = 0x80 >> bit;
504  mNoDataBitmap[byte] = mNoDataBitmap[byte] & ~nodata;
505  }
506 
516  QByteArray data() const;
517 
527  void setData( const QByteArray &data, int offset = 0 );
528 
535  char *bits( int row, int column ) SIP_SKIP;
536 
542  char *bits( qgssize index ) SIP_SKIP;
543 
548  char *bits() SIP_SKIP;
549 
555  static QString printValue( double value );
556 
565  static QString printValue( float value ) SIP_SKIP;
566 
571  bool convert( Qgis::DataType destDataType );
572 
576  QImage image() const;
577 
582  bool setImage( const QImage *image );
583 
585  inline static double readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP;
586 
588  inline static void writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP;
589 
590  void applyNoDataValues( const QgsRasterRangeList &rangeList );
591 
596  void applyScaleOffset( double scale, double offset );
597 
599  QgsError error() const { return mError; }
600 
602  void setError( const QgsError &error ) { mError = error;}
603 
604  QString toString() const;
605 
616  static QRect subRect( const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent );
617 
623  int width() const { return mWidth; }
624 
630  int height() const { return mHeight; }
631 
632  private:
633  static QImage::Format imageFormat( Qgis::DataType dataType );
634  static Qgis::DataType dataType( QImage::Format format );
635 
641  static bool isNoDataValue( double value, double noDataValue )
642  {
643  // TODO: optimize no data value test by memcmp()
644  // More precise would be std::isnan(value) && std::isnan(noDataValue(bandNo)), but probably
645  // not important and slower
646  return std::isnan( value ) ||
647  qgsDoubleNear( value, noDataValue );
648  }
649 
654  bool isNoDataValue( double value ) const;
655 
659  bool createNoDataBitmap();
660 
669  static void *convert( void *srcData, Qgis::DataType srcDataType, Qgis::DataType destDataType, qgssize size );
670 
671  // Valid
672  bool mValid = true;
673 
674  // Data type
676 
677  // Data type size in bytes, to make bits() fast
678  int mTypeSize = 0;
679 
680  // Width
681  int mWidth = 0;
682 
683  // Height
684  int mHeight = 0;
685 
686  // Has no data value
687  bool mHasNoDataValue = false;
688 
689  // No data value
690  double mNoDataValue;
691 
692  static const QRgb NO_DATA_COLOR;
693 
694  // Data block for numerical data types, not used with image data types
695  // QByteArray does not seem to be intended for large data blocks, does it?
696  void *mData = nullptr;
697 
698  // Image for image data types, not used with numerical data types
699  QImage *mImage = nullptr;
700 
701  // Bitmap of no data. One bit for each pixel. Bit is 1 if a pixels is no data.
702  // Each row is represented by whole number of bytes (last bits may be unused)
703  // to make processing rows easy.
704  char *mNoDataBitmap = nullptr;
705 
706  // number of bytes in mNoDataBitmap row
707  int mNoDataBitmapWidth = 0;
708 
709  // total size in bytes of mNoDataBitmap
710  qgssize mNoDataBitmapSize = 0;
711 
712  // Error
713  QgsError mError;
714 };
715 
716 inline double QgsRasterBlock::readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP
717 {
718  if ( !data )
719  {
720  return std::numeric_limits<double>::quiet_NaN();
721  }
722 
723  switch ( type )
724  {
725  case Qgis::Byte:
726  return static_cast< double >( ( static_cast< quint8 * >( data ) )[index] );
727  case Qgis::UInt16:
728  return static_cast< double >( ( static_cast< quint16 * >( data ) )[index] );
729  case Qgis::Int16:
730  return static_cast< double >( ( static_cast< qint16 * >( data ) )[index] );
731  case Qgis::UInt32:
732  return static_cast< double >( ( static_cast< quint32 * >( data ) )[index] );
733  case Qgis::Int32:
734  return static_cast< double >( ( static_cast< qint32 * >( data ) )[index] );
735  case Qgis::Float32:
736  return static_cast< double >( ( static_cast< float * >( data ) )[index] );
737  case Qgis::Float64:
738  return static_cast< double >( ( static_cast< double * >( data ) )[index] );
739  default:
740  QgsDebugMsg( QStringLiteral( "Data type %1 is not supported" ).arg( type ) );
741  break;
742  }
743 
744  return std::numeric_limits<double>::quiet_NaN();
745 }
746 
747 inline void QgsRasterBlock::writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP
748 {
749  if ( !data ) return;
750 
751  switch ( type )
752  {
753  case Qgis::Byte:
754  ( static_cast< quint8 * >( data ) )[index] = static_cast< quint8 >( value );
755  break;
756  case Qgis::UInt16:
757  ( static_cast< quint16 * >( data ) )[index] = static_cast< quint16 >( value );
758  break;
759  case Qgis::Int16:
760  ( static_cast< qint16 * >( data ) )[index] = static_cast< qint16 >( value );
761  break;
762  case Qgis::UInt32:
763  ( static_cast< quint32 * >( data ) )[index] = static_cast< quint32 >( value );
764  break;
765  case Qgis::Int32:
766  ( static_cast< qint32 * >( data ) )[index] = static_cast< qint32 >( value );
767  break;
768  case Qgis::Float32:
769  ( static_cast< float * >( data ) )[index] = static_cast< float >( value );
770  break;
771  case Qgis::Float64:
772  ( static_cast< double * >( data ) )[index] = value;
773  break;
774  default:
775  QgsDebugMsg( QStringLiteral( "Data type %1 is not supported" ).arg( type ) );
776  break;
777  }
778 }
779 
780 inline double QgsRasterBlock::value( qgssize index ) const SIP_SKIP
781 {
782  if ( !mData )
783  {
784  QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
785  return std::numeric_limits<double>::quiet_NaN();
786  }
787  return readValue( mData, mDataType, index );
788 }
789 
790 inline double QgsRasterBlock::valueAndNoData( qgssize index, bool &isNoData ) const SIP_SKIP
791 {
792  if ( !mData )
793  {
794  QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
795  isNoData = true;
796  return std::numeric_limits<double>::quiet_NaN();
797  }
798  if ( index >= static_cast< qgssize >( mWidth )*mHeight )
799  {
800  QgsDebugMsg( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
801  isNoData = true; // we consider no data if outside
802  return std::numeric_limits<double>::quiet_NaN();
803  }
804 
805  const double val = readValue( mData, mDataType, index );
806 
807  if ( !mHasNoDataValue && !mNoDataBitmap )
808  {
809  isNoData = false;
810  return val;
811  }
812 
813  if ( mHasNoDataValue )
814  {
815  isNoData = isNoDataValue( val );
816  return val;
817  }
818  // use no data bitmap
819  if ( !mNoDataBitmap )
820  {
821  // no data are not defined
822  isNoData = false;
823  return val;
824  }
825 
826  // no data is a bitmap
827  isNoData = QgsRasterBlock::isNoData( index );
828  return val;
829 }
830 
831 inline bool QgsRasterBlock::isNoDataValue( double value ) const SIP_SKIP
832 {
833  return std::isnan( value ) || qgsDoubleNear( value, mNoDataValue );
834 }
835 
836 #endif
837 
838 
A rectangle specified with double values.
Definition: qgsrectangle.h:41
bool isNoData(qgssize row, qgssize column) const
Check if value at position is no data.
Thirty two bit signed integer (qint32)
Definition: qgis.h:86
bool isValid() const
Returns true if the block is valid (correctly filled with data).
static double readValue(void *data, Qgis::DataType type, qgssize index)
Qgis::DataType dataType() const
Returns data type.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
bool setValue(int row, int column, double value)
Set value on position.
int height() const
Returns the height (number of rows) of the raster block.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:265
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.
Thirty two bit unsigned integer (quint32)
Definition: qgis.h:85
QRgb * colorData()
Gives direct read/write access to the raster RGB data.
DataType
Raster data types.
Definition: qgis.h:79
bool setColor(qgssize index, QRgb color)
Set color on index (indexed line by line)
Thirty two bit floating point (float)
Definition: qgis.h:87
bool isNoData(qgssize index) const
Check if value at position is no data.
Sixteen bit signed integer (qint16)
Definition: qgis.h:84
Complex Int16.
Definition: qgis.h:89
Sixty four bit floating point (double)
Definition: qgis.h:88
QgsError error() const
Returns the last error.
bool setIsNoData(int row, int column)
Set no data on pixel.
bool setColor(int row, int column, QRgb color)
Set color on position.
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:94
Raster data container.
void setIsData(qgssize index)
Remove no data flag on pixel.
const quint8 * byteData() const
Gives direct access to the raster block data.
#define SIP_SKIP
Definition: qgis_sip.h:119
void setError(const QgsError &error)
Sets the last error.
Complex Float32.
Definition: qgis.h:91
bool setIsNoData(qgssize index)
Set no data on pixel.
QRgb color(int row, int column) const
Read a single color.
void setIsData(int row, int column)
Remove no data flag on pixel.
Unknown or unspecified type.
Definition: qgis.h:81
Complex Int32.
Definition: qgis.h:90
static int typeSize(int dataType)
Sixteen bit unsigned integer (quint16)
Definition: qgis.h:83
bool isNoData(int row, int column) const
Checks if value at position is no data.
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:596
int width() const
Returns the width (number of columns) of the raster block.
void setValid(bool valid)
Mark block as valid or invalid.
QRgb color(qgssize index) const
Read a single value.
static void writeValue(void *data, Qgis::DataType type, qgssize index, double value)
QList< QgsRasterRange > QgsRasterRangeList
bool setValue(qgssize index, double value)
Set value on index (indexed line by line)
QgsError is container for error messages (report).
Definition: qgserror.h:80
double value(int row, int column) const
Read a single value if type of block is numeric.
bool hasNoDataValue() const
True if the block has no data value.
int dataTypeSize() const
Complex Float64.
Definition: qgis.h:92
bool hasNoData() const
Returns true if the block may contain no data.
double noDataValue() const
Returns no data value.
Eight bit unsigned integer (quint8)
Definition: qgis.h:82
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:93