QGIS API Documentation  3.2.0-Bonn (bc43194)
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 
204  QRgb color( int row, int column ) const
205  {
206  if ( !mImage ) return NO_DATA_COLOR;
207 
208  return mImage->pixel( column, row );
209  }
210 
215  QRgb color( qgssize index ) const
216  {
217  int row = static_cast< int >( std::floor( static_cast< double >( index ) / mWidth ) );
218  int column = index % mWidth;
219  return color( row, column );
220  }
221 
227  bool isNoData( int row, int column )
228  {
229  return isNoData( static_cast< qgssize >( row ) * mWidth + column );
230  }
231 
236  bool isNoData( qgssize index )
237  {
238  if ( !mHasNoDataValue && !mNoDataBitmap )
239  return false;
240  if ( index >= static_cast< qgssize >( mWidth )*mHeight )
241  {
242  QgsDebugMsg( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
243  return true; // we consider no data if outside
244  }
245  if ( mHasNoDataValue )
246  {
247  double value = readValue( mData, mDataType, index );
248  return isNoDataValue( value );
249  }
250  // use no data bitmap
251  if ( !mNoDataBitmap )
252  {
253  // no data are not defined
254  return false;
255  }
256  // TODO: optimize
257  int row = static_cast< int >( index ) / mWidth;
258  int column = index % mWidth;
259  qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
260  int bit = column % 8;
261  int mask = 0x80 >> bit;
262  //int x = mNoDataBitmap[byte] & mask;
263  //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) ) );
264  return mNoDataBitmap[byte] & mask;
265  }
266 
273  bool setValue( int row, int column, double value )
274  {
275  return setValue( static_cast< qgssize >( row ) * mWidth + column, value );
276  }
277 
283  bool setValue( qgssize index, double value )
284  {
285  if ( !mData )
286  {
287  QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
288  return false;
289  }
290  if ( index >= static_cast< qgssize >( mWidth ) *mHeight )
291  {
292  QgsDebugMsg( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
293  return false;
294  }
295  writeValue( mData, mDataType, index, value );
296  return true;
297  }
298 
305  bool setColor( int row, int column, QRgb color )
306  {
307  return setColor( static_cast< qgssize >( row ) * mWidth + column, color );
308  }
309 
315  bool setColor( qgssize index, QRgb color )
316  {
317  if ( !mImage )
318  {
319  QgsDebugMsg( QStringLiteral( "Image not allocated" ) );
320  return false;
321  }
322 
323  if ( index >= static_cast< qgssize >( mImage->width() ) * mImage->height() )
324  {
325  QgsDebugMsg( QStringLiteral( "index %1 out of range" ).arg( index ) );
326  return false;
327  }
328 
329  // setPixel() is slow, see Qt doc -> use direct access
330  QRgb *bits = reinterpret_cast< QRgb * >( mImage->bits() );
331  bits[index] = color;
332  return true;
333  }
334 
340  bool setIsNoData( int row, int column )
341  {
342  return setIsNoData( static_cast< qgssize >( row ) * mWidth + column );
343  }
344 
349  bool setIsNoData( qgssize index )
350  {
351  if ( mHasNoDataValue )
352  {
353  return setValue( index, mNoDataValue );
354  }
355  else
356  {
357  if ( !mNoDataBitmap )
358  {
359  if ( !createNoDataBitmap() )
360  {
361  return false;
362  }
363  }
364  // TODO: optimize
365  int row = static_cast< int >( index ) / mWidth;
366  int column = index % mWidth;
367  qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
368  int bit = column % 8;
369  int nodata = 0x80 >> bit;
370  //QgsDebugMsg ( QString("set byte = %1 bit = %2 no data by %3").arg(byte).arg(bit).arg(nodata, 0,2 ) );
371  mNoDataBitmap[byte] = mNoDataBitmap[byte] | nodata;
372  return true;
373  }
374  }
375 
379  bool setIsNoData();
380 
384  bool setIsNoDataExcept( QRect exceptRect );
385 
394  void setIsData( int row, int column )
395  {
396  setIsData( static_cast< qgssize >( row )*mWidth + column );
397  }
398 
406  void setIsData( qgssize index )
407  {
408  if ( mHasNoDataValue )
409  {
410  //no data value set, so mNoDataBitmap is not being used
411  return;
412  }
413 
414  if ( !mNoDataBitmap )
415  {
416  return;
417  }
418 
419  // TODO: optimize
420  int row = static_cast< int >( index ) / mWidth;
421  int column = index % mWidth;
422  qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
423  int bit = column % 8;
424  int nodata = 0x80 >> bit;
425  mNoDataBitmap[byte] = mNoDataBitmap[byte] & ~nodata;
426  }
427 
437  QByteArray data() const;
438 
448  void setData( const QByteArray &data, int offset = 0 );
449 
456  char *bits( int row, int column ) SIP_SKIP;
457 
463  char *bits( qgssize index ) SIP_SKIP;
464 
469  char *bits() SIP_SKIP;
470 
476  static QString printValue( double value );
477 
486  static QString printValue( float value ) SIP_SKIP;
487 
492  bool convert( Qgis::DataType destDataType );
493 
497  QImage image() const;
498 
503  bool setImage( const QImage *image );
504 
506  inline static double readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP;
507 
509  inline static void writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP;
510 
511  void applyNoDataValues( const QgsRasterRangeList &rangeList );
512 
517  void applyScaleOffset( double scale, double offset );
518 
520  QgsError error() const { return mError; }
521 
523  void setError( const QgsError &error ) { mError = error;}
524 
525  QString toString() const;
526 
537  static QRect subRect( const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent );
538 
544  int width() const { return mWidth; }
545 
551  int height() const { return mHeight; }
552 
553  private:
554  static QImage::Format imageFormat( Qgis::DataType dataType );
555  static Qgis::DataType dataType( QImage::Format format );
556 
562  static bool isNoDataValue( double value, double noDataValue )
563  {
564  // TODO: optimize no data value test by memcmp()
565  // More precise would be std::isnan(value) && std::isnan(noDataValue(bandNo)), but probably
566  // not important and slower
567  return std::isnan( value ) ||
568  qgsDoubleNear( value, noDataValue );
569  }
570 
575  bool isNoDataValue( double value ) const;
576 
580  bool createNoDataBitmap();
581 
590  static void *convert( void *srcData, Qgis::DataType srcDataType, Qgis::DataType destDataType, qgssize size );
591 
592  // Valid
593  bool mValid = true;
594 
595  // Data type
597 
598  // Data type size in bytes, to make bits() fast
599  int mTypeSize = 0;
600 
601  // Width
602  int mWidth = 0;
603 
604  // Height
605  int mHeight = 0;
606 
607  // Has no data value
608  bool mHasNoDataValue = false;
609 
610  // No data value
611  double mNoDataValue;
612 
613  static const QRgb NO_DATA_COLOR;
614 
615  // Data block for numerical data types, not used with image data types
616  // QByteArray does not seem to be intended for large data blocks, does it?
617  void *mData = nullptr;
618 
619  // Image for image data types, not used with numerical data types
620  QImage *mImage = nullptr;
621 
622  // Bitmap of no data. One bit for each pixel. Bit is 1 if a pixels is no data.
623  // Each row is represented by whole number of bytes (last bits may be unused)
624  // to make processing rows easy.
625  char *mNoDataBitmap = nullptr;
626 
627  // number of bytes in mNoDataBitmap row
628  int mNoDataBitmapWidth = 0;
629 
630  // total size in bytes of mNoDataBitmap
631  qgssize mNoDataBitmapSize = 0;
632 
633  // Error
634  QgsError mError;
635 };
636 
637 inline double QgsRasterBlock::readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP
638 {
639  if ( !data )
640  {
641  return std::numeric_limits<double>::quiet_NaN();
642  }
643 
644  switch ( type )
645  {
646  case Qgis::Byte:
647  return static_cast< double >( ( static_cast< quint8 * >( data ) )[index] );
648  break;
649  case Qgis::UInt16:
650  return static_cast< double >( ( static_cast< quint16 * >( data ) )[index] );
651  break;
652  case Qgis::Int16:
653  return static_cast< double >( ( static_cast< qint16 * >( data ) )[index] );
654  break;
655  case Qgis::UInt32:
656  return static_cast< double >( ( static_cast< quint32 * >( data ) )[index] );
657  break;
658  case Qgis::Int32:
659  return static_cast< double >( ( static_cast< qint32 * >( data ) )[index] );
660  break;
661  case Qgis::Float32:
662  return static_cast< double >( ( static_cast< float * >( data ) )[index] );
663  break;
664  case Qgis::Float64:
665  return static_cast< double >( ( static_cast< double * >( data ) )[index] );
666  break;
667  default:
668  QgsDebugMsg( QString( "Data type %1 is not supported" ).arg( type ) );
669  break;
670  }
671 
672  return std::numeric_limits<double>::quiet_NaN();
673 }
674 
675 inline void QgsRasterBlock::writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP
676 {
677  if ( !data ) return;
678 
679  switch ( type )
680  {
681  case Qgis::Byte:
682  ( static_cast< quint8 * >( data ) )[index] = static_cast< quint8 >( value );
683  break;
684  case Qgis::UInt16:
685  ( static_cast< quint16 * >( data ) )[index] = static_cast< quint16 >( value );
686  break;
687  case Qgis::Int16:
688  ( static_cast< qint16 * >( data ) )[index] = static_cast< qint16 >( value );
689  break;
690  case Qgis::UInt32:
691  ( static_cast< quint32 * >( data ) )[index] = static_cast< quint32 >( value );
692  break;
693  case Qgis::Int32:
694  ( static_cast< qint32 * >( data ) )[index] = static_cast< qint32 >( value );
695  break;
696  case Qgis::Float32:
697  ( static_cast< float * >( data ) )[index] = static_cast< float >( value );
698  break;
699  case Qgis::Float64:
700  ( static_cast< double * >( data ) )[index] = value;
701  break;
702  default:
703  QgsDebugMsg( QString( "Data type %1 is not supported" ).arg( type ) );
704  break;
705  }
706 }
707 
708 inline double QgsRasterBlock::value( qgssize index ) const SIP_SKIP
709 {
710  if ( !mData )
711  {
712  QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
713  return std::numeric_limits<double>::quiet_NaN();
714  }
715  return readValue( mData, mDataType, index );
716 }
717 
718 inline bool QgsRasterBlock::isNoDataValue( double value ) const SIP_SKIP
719 {
720  return std::isnan( value ) || qgsDoubleNear( value, mNoDataValue );
721 }
722 
723 #endif
724 
725 
A rectangle specified with double values.
Definition: qgsrectangle.h:40
Thirty two bit signed integer (qint32)
Definition: qgis.h:98
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:251
Thirty two bit unsigned integer (quint32)
Definition: qgis.h:97
DataType
Raster data types.
Definition: qgis.h:91
bool setColor(qgssize index, QRgb color)
Set color on index (indexed line by line)
Thirty two bit floating point (float)
Definition: qgis.h:99
Sixteen bit signed integer (qint16)
Definition: qgis.h:96
bool isNoData(int row, int column)
Check if value at position is no data.
Complex Int16.
Definition: qgis.h:101
Sixty four bit floating point (double)
Definition: qgis.h:100
QgsError error() const
Returns the last error.
bool isNoData(qgssize index)
Check if value at position is no data.
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:106
Raster data container.
void setIsData(qgssize index)
Remove no data flag on pixel.
#define SIP_SKIP
Definition: qgis_sip.h:119
void setError(const QgsError &error)
Sets the last error.
Complex Float32.
Definition: qgis.h:103
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:93
Complex Int32.
Definition: qgis.h:102
static int typeSize(int dataType)
Sixteen bit unsigned integer (quint16)
Definition: qgis.h:95
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:510
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:104
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:94
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:105