QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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 
187  double value( int row, int column ) const
188  {
189  return value( static_cast< qgssize >( row ) * mWidth + column );
190  }
191 
197  double value( qgssize index ) const;
198 
206  const quint8 *byteData() const SIP_SKIP
207  {
208  if ( mDataType != Qgis::Byte )
209  return nullptr;
210  return static_cast< const quint8 * >( mData );
211  }
212 
218  QRgb color( int row, int column ) const
219  {
220  if ( !mImage ) return NO_DATA_COLOR;
221 
222  return mImage->pixel( column, row );
223  }
224 
229  QRgb color( qgssize index ) const
230  {
231  int row = static_cast< int >( std::floor( static_cast< double >( index ) / mWidth ) );
232  int column = index % mWidth;
233  return color( row, column );
234  }
235 
241  bool isNoData( int row, int column ) const
242  {
243  return isNoData( static_cast< qgssize >( row ) * mWidth + column );
244  }
245 
251  bool isNoData( qgssize row, qgssize column ) const
252  {
253  return isNoData( row * static_cast< qgssize >( mWidth ) + column );
254  }
255 
260  bool isNoData( qgssize index ) const
261  {
262  if ( !mHasNoDataValue && !mNoDataBitmap )
263  return false;
264  if ( index >= static_cast< qgssize >( mWidth )*mHeight )
265  {
266  QgsDebugMsg( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
267  return true; // we consider no data if outside
268  }
269  if ( mHasNoDataValue )
270  {
271  double value = readValue( mData, mDataType, index );
272  return isNoDataValue( value );
273  }
274  // use no data bitmap
275  if ( !mNoDataBitmap )
276  {
277  // no data are not defined
278  return false;
279  }
280  // TODO: optimize
281  int row = static_cast< int >( index ) / mWidth;
282  int column = index % mWidth;
283  qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
284  int bit = column % 8;
285  int mask = 0x80 >> bit;
286  //int x = mNoDataBitmap[byte] & mask;
287  //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) ) );
288  return mNoDataBitmap[byte] & mask;
289  }
290 
297  bool setValue( int row, int column, double value )
298  {
299  return setValue( static_cast< qgssize >( row ) * mWidth + column, value );
300  }
301 
307  bool setValue( qgssize index, double value )
308  {
309  if ( !mData )
310  {
311  QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
312  return false;
313  }
314  if ( index >= static_cast< qgssize >( mWidth ) *mHeight )
315  {
316  QgsDebugMsg( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
317  return false;
318  }
319  writeValue( mData, mDataType, index, value );
320  return true;
321  }
322 
329  bool setColor( int row, int column, QRgb color )
330  {
331  return setColor( static_cast< qgssize >( row ) * mWidth + column, color );
332  }
333 
339  bool setColor( qgssize index, QRgb color )
340  {
341  if ( !mImage )
342  {
343  QgsDebugMsg( QStringLiteral( "Image not allocated" ) );
344  return false;
345  }
346 
347  if ( index >= static_cast< qgssize >( mImage->width() ) * mImage->height() )
348  {
349  QgsDebugMsg( QStringLiteral( "index %1 out of range" ).arg( index ) );
350  return false;
351  }
352 
353  // setPixel() is slow, see Qt doc -> use direct access
354  QRgb *bits = reinterpret_cast< QRgb * >( mImage->bits() );
355  bits[index] = color;
356  return true;
357  }
358 
367  {
368  if ( !mImage )
369  return nullptr;
370  return reinterpret_cast< QRgb * >( mImage->bits() );
371  }
372 
378  bool setIsNoData( int row, int column )
379  {
380  return setIsNoData( static_cast< qgssize >( row ) * mWidth + column );
381  }
382 
387  bool setIsNoData( qgssize index )
388  {
389  if ( mHasNoDataValue )
390  {
391  return setValue( index, mNoDataValue );
392  }
393  else
394  {
395  if ( !mNoDataBitmap )
396  {
397  if ( !createNoDataBitmap() )
398  {
399  return false;
400  }
401  }
402  // TODO: optimize
403  int row = static_cast< int >( index ) / mWidth;
404  int column = index % mWidth;
405  qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
406  int bit = column % 8;
407  int nodata = 0x80 >> bit;
408  //QgsDebugMsg ( QString("set byte = %1 bit = %2 no data by %3").arg(byte).arg(bit).arg(nodata, 0,2 ) );
409  mNoDataBitmap[byte] = mNoDataBitmap[byte] | nodata;
410  return true;
411  }
412  }
413 
417  bool setIsNoData();
418 
422  bool setIsNoDataExcept( QRect exceptRect );
423 
432  void setIsData( int row, int column )
433  {
434  setIsData( static_cast< qgssize >( row )*mWidth + column );
435  }
436 
444  void setIsData( qgssize index )
445  {
446  if ( mHasNoDataValue )
447  {
448  //no data value set, so mNoDataBitmap is not being used
449  return;
450  }
451 
452  if ( !mNoDataBitmap )
453  {
454  return;
455  }
456 
457  // TODO: optimize
458  int row = static_cast< int >( index ) / mWidth;
459  int column = index % mWidth;
460  qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
461  int bit = column % 8;
462  int nodata = 0x80 >> bit;
463  mNoDataBitmap[byte] = mNoDataBitmap[byte] & ~nodata;
464  }
465 
475  QByteArray data() const;
476 
486  void setData( const QByteArray &data, int offset = 0 );
487 
494  char *bits( int row, int column ) SIP_SKIP;
495 
501  char *bits( qgssize index ) SIP_SKIP;
502 
507  char *bits() SIP_SKIP;
508 
514  static QString printValue( double value );
515 
524  static QString printValue( float value ) SIP_SKIP;
525 
530  bool convert( Qgis::DataType destDataType );
531 
535  QImage image() const;
536 
541  bool setImage( const QImage *image );
542 
544  inline static double readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP;
545 
547  inline static void writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP;
548 
549  void applyNoDataValues( const QgsRasterRangeList &rangeList );
550 
555  void applyScaleOffset( double scale, double offset );
556 
558  QgsError error() const { return mError; }
559 
561  void setError( const QgsError &error ) { mError = error;}
562 
563  QString toString() const;
564 
575  static QRect subRect( const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent );
576 
582  int width() const { return mWidth; }
583 
589  int height() const { return mHeight; }
590 
591  private:
592  static QImage::Format imageFormat( Qgis::DataType dataType );
593  static Qgis::DataType dataType( QImage::Format format );
594 
600  static bool isNoDataValue( double value, double noDataValue )
601  {
602  // TODO: optimize no data value test by memcmp()
603  // More precise would be std::isnan(value) && std::isnan(noDataValue(bandNo)), but probably
604  // not important and slower
605  return std::isnan( value ) ||
606  qgsDoubleNear( value, noDataValue );
607  }
608 
613  bool isNoDataValue( double value ) const;
614 
618  bool createNoDataBitmap();
619 
628  static void *convert( void *srcData, Qgis::DataType srcDataType, Qgis::DataType destDataType, qgssize size );
629 
630  // Valid
631  bool mValid = true;
632 
633  // Data type
635 
636  // Data type size in bytes, to make bits() fast
637  int mTypeSize = 0;
638 
639  // Width
640  int mWidth = 0;
641 
642  // Height
643  int mHeight = 0;
644 
645  // Has no data value
646  bool mHasNoDataValue = false;
647 
648  // No data value
649  double mNoDataValue;
650 
651  static const QRgb NO_DATA_COLOR;
652 
653  // Data block for numerical data types, not used with image data types
654  // QByteArray does not seem to be intended for large data blocks, does it?
655  void *mData = nullptr;
656 
657  // Image for image data types, not used with numerical data types
658  QImage *mImage = nullptr;
659 
660  // Bitmap of no data. One bit for each pixel. Bit is 1 if a pixels is no data.
661  // Each row is represented by whole number of bytes (last bits may be unused)
662  // to make processing rows easy.
663  char *mNoDataBitmap = nullptr;
664 
665  // number of bytes in mNoDataBitmap row
666  int mNoDataBitmapWidth = 0;
667 
668  // total size in bytes of mNoDataBitmap
669  qgssize mNoDataBitmapSize = 0;
670 
671  // Error
672  QgsError mError;
673 };
674 
675 inline double QgsRasterBlock::readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP
676 {
677  if ( !data )
678  {
679  return std::numeric_limits<double>::quiet_NaN();
680  }
681 
682  switch ( type )
683  {
684  case Qgis::Byte:
685  return static_cast< double >( ( static_cast< quint8 * >( data ) )[index] );
686  break;
687  case Qgis::UInt16:
688  return static_cast< double >( ( static_cast< quint16 * >( data ) )[index] );
689  break;
690  case Qgis::Int16:
691  return static_cast< double >( ( static_cast< qint16 * >( data ) )[index] );
692  break;
693  case Qgis::UInt32:
694  return static_cast< double >( ( static_cast< quint32 * >( data ) )[index] );
695  break;
696  case Qgis::Int32:
697  return static_cast< double >( ( static_cast< qint32 * >( data ) )[index] );
698  break;
699  case Qgis::Float32:
700  return static_cast< double >( ( static_cast< float * >( data ) )[index] );
701  break;
702  case Qgis::Float64:
703  return static_cast< double >( ( static_cast< double * >( data ) )[index] );
704  break;
705  default:
706  QgsDebugMsg( QStringLiteral( "Data type %1 is not supported" ).arg( type ) );
707  break;
708  }
709 
710  return std::numeric_limits<double>::quiet_NaN();
711 }
712 
713 inline void QgsRasterBlock::writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP
714 {
715  if ( !data ) return;
716 
717  switch ( type )
718  {
719  case Qgis::Byte:
720  ( static_cast< quint8 * >( data ) )[index] = static_cast< quint8 >( value );
721  break;
722  case Qgis::UInt16:
723  ( static_cast< quint16 * >( data ) )[index] = static_cast< quint16 >( value );
724  break;
725  case Qgis::Int16:
726  ( static_cast< qint16 * >( data ) )[index] = static_cast< qint16 >( value );
727  break;
728  case Qgis::UInt32:
729  ( static_cast< quint32 * >( data ) )[index] = static_cast< quint32 >( value );
730  break;
731  case Qgis::Int32:
732  ( static_cast< qint32 * >( data ) )[index] = static_cast< qint32 >( value );
733  break;
734  case Qgis::Float32:
735  ( static_cast< float * >( data ) )[index] = static_cast< float >( value );
736  break;
737  case Qgis::Float64:
738  ( static_cast< double * >( data ) )[index] = value;
739  break;
740  default:
741  QgsDebugMsg( QStringLiteral( "Data type %1 is not supported" ).arg( type ) );
742  break;
743  }
744 }
745 
746 inline double QgsRasterBlock::value( qgssize index ) const SIP_SKIP
747 {
748  if ( !mData )
749  {
750  QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
751  return std::numeric_limits<double>::quiet_NaN();
752  }
753  return readValue( mData, mDataType, index );
754 }
755 
756 inline bool QgsRasterBlock::isNoDataValue( double value ) const SIP_SKIP
757 {
758  return std::isnan( value ) || qgsDoubleNear( value, mNoDataValue );
759 }
760 
761 #endif
762 
763 
A rectangle specified with double values.
Definition: qgsrectangle.h:40
Thirty two bit signed integer (qint32)
Definition: qgis.h:99
Qgis::DataType dataType() const
Returns data type.
int height() const
Returns the height (number of rows) of the raster block.
bool isValid() const
Returns true if the block is valid (correctly filled with data).
static double readValue(void *data, Qgis::DataType type, qgssize index)
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
bool setValue(int row, int column, double value)
Set value on position.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:278
Thirty two bit unsigned integer (quint32)
Definition: qgis.h:98
QRgb * colorData()
Gives direct read/write access to the raster RGB data.
double noDataValue() const
Returns no data value.
DataType
Raster data types.
Definition: qgis.h:92
int width() const
Returns the width (number of columns) of the raster block.
bool setColor(qgssize index, QRgb color)
Set color on index (indexed line by line)
Thirty two bit floating point (float)
Definition: qgis.h:100
Sixteen bit signed integer (qint16)
Definition: qgis.h:97
Complex Int16.
Definition: qgis.h:102
Sixty four bit floating point (double)
Definition: qgis.h:101
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:107
bool hasNoData() const
Returns true if the block may contain no data.
Raster data container.
void setIsData(qgssize index)
Remove no data flag on pixel.
#define SIP_SKIP
Definition: qgis_sip.h:119
double value(int row, int column) const
Read a single value if type of block is numeric.
void setError(const QgsError &error)
Sets the last error.
Complex Float32.
Definition: qgis.h:104
bool setIsNoData(qgssize index)
Set no data on pixel.
void setIsData(int row, int column)
Remove no data flag on pixel.
const quint8 * byteData() const
Gives direct access to the raster block data.
Unknown or unspecified type.
Definition: qgis.h:94
Complex Int32.
Definition: qgis.h:103
static int typeSize(int dataType)
Sixteen bit unsigned integer (quint16)
Definition: qgis.h:96
bool isNoData(qgssize index) const
Check 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:586
int dataTypeSize() const
void setValid(bool valid)
Mark block as valid or invalid.
bool hasNoDataValue() const
True if the block has no data 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
bool isNoData(int row, int column) const
Check if value at position is no data.
QRgb color(int row, int column) const
Read a single color.
Complex Float64.
Definition: qgis.h:105
QgsError error() const
Returns the last error.
bool isNoData(qgssize row, qgssize column) const
Check if value at position is no data.
QRgb color(qgssize index) const
Read a single value.
Eight bit unsigned integer (quint8)
Definition: qgis.h:95
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:106