QGIS API Documentation 3.27.0-Master (9c08adf5ef)
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
30class QgsRectangle;
31
36class 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 SIP_HOLDGIL { return mValid; }
69
71 void setValid( bool valid ) SIP_HOLDGIL { mValid = valid; }
72
78 bool isEmpty() const;
79
83 static int typeSize( Qgis::DataType dataType ) SIP_HOLDGIL
84 {
85 // Modified and extended copy from GDAL
86 switch ( dataType )
87 {
89 return 1;
90
93 return 2;
94
99 return 4;
100
104 return 8;
105
107 return 16;
108
111 return 4;
112
113 default:
114 return 0;
115 }
116 }
117
122 {
123 return typeSize( mDataType );
124 }
125
127 static bool typeIsNumeric( Qgis::DataType type );
128
130 static bool typeIsColor( Qgis::DataType type );
131
133 Qgis::DataType dataType() const SIP_HOLDGIL { return mDataType; }
134
136 static Qgis::DataType typeWithNoDataValue( Qgis::DataType dataType, double *noDataValue );
137
143 bool hasNoDataValue() const SIP_HOLDGIL { return mHasNoDataValue; }
144
152 {
153 return mHasNoDataValue || mNoDataBitmap;
154 }
155
161 void setNoDataValue( double noDataValue ) SIP_HOLDGIL;
162
169 void resetNoDataValue() SIP_HOLDGIL;
170
177 double noDataValue() const SIP_HOLDGIL { return mNoDataValue; }
178
185 static QByteArray valueBytes( Qgis::DataType dataType, double value );
186
195 double value( int row, int column ) const SIP_HOLDGIL
196 {
197 return value( static_cast< qgssize >( row ) * mWidth + column );
198 }
199
212 double valueAndNoData( int row, int column, bool &isNoData ) const SIP_SKIP
213 {
214 return valueAndNoData( static_cast< qgssize >( row ) * mWidth + column, isNoData );
215 }
216
224 inline double value( qgssize index ) const SIP_HOLDGIL;
225
238 inline double valueAndNoData( qgssize index, bool &isNoData ) const SIP_SKIP;
239
247 const quint8 *byteData() const SIP_SKIP
248 {
249 if ( mDataType != Qgis::DataType::Byte )
250 return nullptr;
251 return static_cast< const quint8 * >( mData );
252 }
253
260 QRgb color( int row, int column ) const SIP_HOLDGIL
261 {
262 if ( !mImage ) return NO_DATA_COLOR;
263
264 return mImage->pixel( column, row );
265 }
266
272 QRgb color( qgssize index ) const SIP_HOLDGIL
273 {
274 const int row = static_cast< int >( std::floor( static_cast< double >( index ) / mWidth ) );
275 const int column = index % mWidth;
276 return color( row, column );
277 }
278
286 bool isNoData( int row, int column ) const SIP_HOLDGIL
287 {
288 return isNoData( static_cast< qgssize >( row ) * mWidth + column );
289 }
290
298 bool isNoData( qgssize row, qgssize column ) const SIP_HOLDGIL
299 {
300 return isNoData( row * static_cast< qgssize >( mWidth ) + column );
301 }
302
309 bool isNoData( qgssize index ) const SIP_HOLDGIL
310 {
311 if ( !mHasNoDataValue && !mNoDataBitmap )
312 return false;
313 if ( index >= static_cast< qgssize >( mWidth )*mHeight )
314 {
315 QgsDebugMsg( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
316 return true; // we consider no data if outside
317 }
318 if ( mHasNoDataValue )
319 {
320 const double value = readValue( mData, mDataType, index );
321 return isNoDataValue( value );
322 }
323 // use no data bitmap
324 if ( !mNoDataBitmap )
325 {
326 // no data are not defined
327 return false;
328 }
329 // TODO: optimize
330 const int row = static_cast< int >( index ) / mWidth;
331 const int column = index % mWidth;
332 const qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
333 const int bit = column % 8;
334 const 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 return mNoDataBitmap[byte] & mask;
338 }
339
347 bool setValue( int row, int column, double value ) SIP_HOLDGIL
348 {
349 return setValue( static_cast< qgssize >( row ) * mWidth + column, value );
350 }
351
358 bool setValue( qgssize index, double value ) SIP_HOLDGIL
359 {
360 if ( !mData )
361 {
362 QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
363 return false;
364 }
365 if ( index >= static_cast< qgssize >( mWidth ) *mHeight )
366 {
367 QgsDebugMsg( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
368 return false;
369 }
370 writeValue( mData, mDataType, index, value );
371 return true;
372 }
373
381 bool setColor( int row, int column, QRgb color ) SIP_HOLDGIL
382 {
383 return setColor( static_cast< qgssize >( row ) * mWidth + column, color );
384 }
385
392 bool setColor( qgssize index, QRgb color ) SIP_HOLDGIL
393 {
394 if ( !mImage )
395 {
396 QgsDebugMsg( QStringLiteral( "Image not allocated" ) );
397 return false;
398 }
399
400 if ( index >= static_cast< qgssize >( mImage->width() ) * mImage->height() )
401 {
402 QgsDebugMsg( QStringLiteral( "index %1 out of range" ).arg( index ) );
403 return false;
404 }
405
406 // setPixel() is slow, see Qt doc -> use direct access
407 QRgb *bits = reinterpret_cast< QRgb * >( mImage->bits() );
408 bits[index] = color;
409 return true;
410 }
411
420 {
421 if ( !mImage )
422 return nullptr;
423 return reinterpret_cast< QRgb * >( mImage->bits() );
424 }
425
432 bool setIsNoData( int row, int column ) SIP_HOLDGIL
433 {
434 return setIsNoData( static_cast< qgssize >( row ) * mWidth + column );
435 }
436
443 {
444 if ( mHasNoDataValue )
445 {
446 return setValue( index, mNoDataValue );
447 }
448 else
449 {
450 if ( !mNoDataBitmap )
451 {
452 if ( !createNoDataBitmap() )
453 {
454 return false;
455 }
456 }
457 // TODO: optimize
458 const int row = static_cast< int >( index ) / mWidth;
459 const int column = index % mWidth;
460 const qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
461 const int bit = column % 8;
462 const 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 mNoDataBitmap[byte] = mNoDataBitmap[byte] | nodata;
465 return true;
466 }
467 }
468
473 bool setIsNoData();
474
479 bool setIsNoDataExcept( QRect exceptRect );
480
490 void setIsData( int row, int column ) SIP_HOLDGIL
491 {
492 setIsData( static_cast< qgssize >( row )*mWidth + column );
493 }
494
504 {
505 if ( mHasNoDataValue )
506 {
507 //no data value set, so mNoDataBitmap is not being used
508 return;
509 }
510
511 if ( !mNoDataBitmap )
512 {
513 return;
514 }
515
516 // TODO: optimize
517 const int row = static_cast< int >( index ) / mWidth;
518 const int column = index % mWidth;
519 const qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
520 const int bit = column % 8;
521 const int nodata = 0x80 >> bit;
522 mNoDataBitmap[byte] = mNoDataBitmap[byte] & ~nodata;
523 }
524
534 QByteArray data() const;
535
545 void setData( const QByteArray &data, int offset = 0 );
546
553 char *bits( int row, int column ) SIP_SKIP;
554
560 char *bits( qgssize index ) SIP_SKIP;
561
566 char *bits() SIP_SKIP;
567
574 static QString printValue( double value );
575
584 static QString printValue( float value ) SIP_SKIP;
585
591 bool convert( Qgis::DataType destDataType );
592
596 QImage image() const;
597
602 bool setImage( const QImage *image );
603
605 inline static double readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP;
606
608 inline static void writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP;
609
610 void applyNoDataValues( const QgsRasterRangeList &rangeList );
611
616 void applyScaleOffset( double scale, double offset );
617
619 QgsError error() const { return mError; }
620
622 void setError( const QgsError &error ) { mError = error;}
623
624 QString toString() const;
625
636 static QRect subRect( const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent );
637
643 int width() const SIP_HOLDGIL { return mWidth; }
644
650 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
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
676 inline bool isNoDataValue( double value ) const;
677
682 bool createNoDataBitmap();
683
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
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
740inline double QgsRasterBlock::readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP
741{
742 if ( !data )
743 {
744 return std::numeric_limits<double>::quiet_NaN();
745 }
746
747 switch ( type )
748 {
750 return static_cast< double >( ( static_cast< quint8 * >( data ) )[index] );
752 return static_cast< double >( ( static_cast< quint16 * >( data ) )[index] );
754 return static_cast< double >( ( static_cast< qint16 * >( data ) )[index] );
756 return static_cast< double >( ( static_cast< quint32 * >( data ) )[index] );
758 return static_cast< double >( ( static_cast< qint32 * >( data ) )[index] );
760 return static_cast< double >( ( static_cast< float * >( data ) )[index] );
762 return static_cast< double >( ( static_cast< double * >( data ) )[index] );
763 default:
764 QgsDebugMsg( QStringLiteral( "Data type %1 is not supported" ).arg( qgsEnumValueToKey< Qgis::DataType >( type ) ) );
765 break;
766 }
767
768 return std::numeric_limits<double>::quiet_NaN();
769}
770
771inline void QgsRasterBlock::writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP
772{
773 if ( !data ) return;
774
775 switch ( type )
776 {
778 ( static_cast< quint8 * >( data ) )[index] = static_cast< quint8 >( value );
779 break;
781 ( static_cast< quint16 * >( data ) )[index] = static_cast< quint16 >( value );
782 break;
784 ( static_cast< qint16 * >( data ) )[index] = static_cast< qint16 >( value );
785 break;
787 ( static_cast< quint32 * >( data ) )[index] = static_cast< quint32 >( value );
788 break;
790 ( static_cast< qint32 * >( data ) )[index] = static_cast< qint32 >( value );
791 break;
793 ( static_cast< float * >( data ) )[index] = static_cast< float >( value );
794 break;
796 ( static_cast< double * >( data ) )[index] = value;
797 break;
798 default:
799 QgsDebugMsg( QStringLiteral( "Data type %1 is not supported" ).arg( qgsEnumValueToKey< Qgis::DataType >( type ) ) );
800 break;
801 }
802}
803
804inline double QgsRasterBlock::value( qgssize index ) const SIP_SKIP
805{
806 if ( !mData )
807 {
808 QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
809 return std::numeric_limits<double>::quiet_NaN();
810 }
811 return readValue( mData, mDataType, index );
812}
813
814inline double QgsRasterBlock::valueAndNoData( qgssize index, bool &isNoData ) const SIP_SKIP
815{
816 if ( !mData )
817 {
818 QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
819 isNoData = true;
820 return std::numeric_limits<double>::quiet_NaN();
821 }
822 if ( index >= static_cast< qgssize >( mWidth )*mHeight )
823 {
824 QgsDebugMsg( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
825 isNoData = true; // we consider no data if outside
826 return std::numeric_limits<double>::quiet_NaN();
827 }
828
829 const double val = readValue( mData, mDataType, index );
830
831 if ( !mHasNoDataValue && !mNoDataBitmap )
832 {
833 isNoData = false;
834 return val;
835 }
836
837 if ( mHasNoDataValue )
838 {
839 isNoData = isNoDataValue( val );
840 return val;
841 }
842 // use no data bitmap
843 if ( !mNoDataBitmap )
844 {
845 // no data are not defined
846 isNoData = false;
847 return val;
848 }
849
850 // no data is a bitmap
851 isNoData = QgsRasterBlock::isNoData( index );
852 return val;
853}
854
855inline bool QgsRasterBlock::isNoDataValue( double value ) const SIP_SKIP
856{
857 return std::isnan( value ) || qgsDoubleNear( value, mNoDataValue );
858}
859
860#endif
861
862
The Qgis class provides global constants for use throughout the application.
Definition: qgis.h:72
DataType
Raster data types.
Definition: qgis.h:129
@ CInt32
Complex Int32.
@ Float32
Thirty two bit floating point (float)
@ CFloat64
Complex Float64.
@ Int16
Sixteen bit signed integer (qint16)
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
@ UInt16
Sixteen bit unsigned integer (quint16)
@ Byte
Eight bit unsigned integer (quint8)
@ UnknownDataType
Unknown or unspecified type.
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
@ Int32
Thirty two bit signed integer (qint32)
@ Float64
Sixty four bit floating point (double)
@ CFloat32
Complex Float32.
@ CInt16
Complex Int16.
@ UInt32
Thirty two bit unsigned integer (quint32)
QgsError is container for error messages (report).
Definition: qgserror.h:81
Raster data container.
void setIsData(qgssize index) SIP_HOLDGIL
Remove no data flag on pixel.
bool setValue(qgssize index, double value) SIP_HOLDGIL
Set value on index (indexed line by line)
void setValid(bool valid) SIP_HOLDGIL
Mark block as valid or invalid.
int width() const SIP_HOLDGIL
Returns the width (number of columns) of the raster block.
static int typeSize(Qgis::DataType dataType) SIP_HOLDGIL
Returns the size in bytes for the specified dataType.
bool isValid() const SIP_HOLDGIL
Returns true if the block is valid (correctly filled with data).
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.
Qgis::DataType dataType() const SIP_HOLDGIL
Returns data type.
bool isNoData(qgssize row, qgssize column) const SIP_HOLDGIL
Check if value at position is no data.
QRgb * colorData()
Gives direct read/write access to the raster RGB data.
double value(int row, int column) const SIP_HOLDGIL
Read a single value if type of block is numeric.
QRgb color(int row, int column) const SIP_HOLDGIL
Read a single color.
int dataTypeSize() const SIP_HOLDGIL
Data type size in bytes.
bool hasNoDataValue() const SIP_HOLDGIL
true if the block has no data value.
const quint8 * byteData() const
Gives direct access to the raster block data.
bool setColor(qgssize index, QRgb color) SIP_HOLDGIL
Set color on index (indexed line by line)
bool setColor(int row, int column, QRgb color) SIP_HOLDGIL
Set color on position.
static void writeValue(void *data, Qgis::DataType type, qgssize index, double value)
bool setIsNoData(qgssize index) SIP_HOLDGIL
Set no data on pixel.
bool isNoData(int row, int column) const SIP_HOLDGIL
Checks if value at position is no data.
bool isNoData(qgssize index) const SIP_HOLDGIL
Check if value at position is no data.
bool hasNoData() const SIP_HOLDGIL
Returns true if the block may contain no data.
bool setValue(int row, int column, double value) SIP_HOLDGIL
Set value on position.
void setError(const QgsError &error)
Sets the last error.
int height() const SIP_HOLDGIL
Returns the height (number of rows) of the raster block.
static double readValue(void *data, Qgis::DataType type, qgssize index)
bool setIsNoData(int row, int column) SIP_HOLDGIL
Set no data on pixel.
QRgb color(qgssize index) const SIP_HOLDGIL
Read a single value.
void setIsData(int row, int column) SIP_HOLDGIL
Remove no data flag on pixel.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
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:2930
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2404
#define SIP_SKIP
Definition: qgis_sip.h:126
#define SIP_HOLDGIL
Definition: qgis_sip.h:166
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QList< QgsRasterRange > QgsRasterRangeList