QGIS API Documentation 3.34.0-Prizren (ffbdd678812)
Loading...
Searching...
No Matches
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 {
90 return 1;
91
94 return 2;
95
100 return 4;
101
105 return 8;
106
108 return 16;
109
112 return 4;
113
115 break;
116 }
117 return 0;
118 }
119
124 {
125 return typeSize( mDataType );
126 }
127
129 static bool typeIsNumeric( Qgis::DataType type );
130
132 static bool typeIsColor( Qgis::DataType type );
133
135 Qgis::DataType dataType() const SIP_HOLDGIL { return mDataType; }
136
138 static Qgis::DataType typeWithNoDataValue( Qgis::DataType dataType, double *noDataValue );
139
145 bool hasNoDataValue() const SIP_HOLDGIL { return mHasNoDataValue; }
146
154 {
155 return mHasNoDataValue || mNoDataBitmap;
156 }
157
163 void setNoDataValue( double noDataValue ) SIP_HOLDGIL;
164
171 void resetNoDataValue() SIP_HOLDGIL;
172
179 double noDataValue() const SIP_HOLDGIL { return mNoDataValue; }
180
187 static QByteArray valueBytes( Qgis::DataType dataType, double value );
188
197 double value( int row, int column ) const SIP_HOLDGIL
198 {
199 return value( static_cast< qgssize >( row ) * mWidth + column );
200 }
201
214 double valueAndNoData( int row, int column, bool &isNoData ) const SIP_SKIP
215 {
216 return valueAndNoData( static_cast< qgssize >( row ) * mWidth + column, isNoData );
217 }
218
226 inline double value( qgssize index ) const SIP_HOLDGIL;
227
240 inline double valueAndNoData( qgssize index, bool &isNoData ) const SIP_SKIP;
241
249 const quint8 *byteData() const SIP_SKIP
250 {
251 if ( mDataType != Qgis::DataType::Byte )
252 return nullptr;
253 return static_cast< const quint8 * >( mData );
254 }
255
262 QRgb color( int row, int column ) const SIP_HOLDGIL
263 {
264 if ( !mImage ) return NO_DATA_COLOR;
265
266 return mImage->pixel( column, row );
267 }
268
274 QRgb color( qgssize index ) const SIP_HOLDGIL
275 {
276 const int row = static_cast< int >( std::floor( static_cast< double >( index ) / mWidth ) );
277 const int column = index % mWidth;
278 return color( row, column );
279 }
280
288 bool isNoData( int row, int column ) const SIP_HOLDGIL
289 {
290 return isNoData( static_cast< qgssize >( row ) * mWidth + column );
291 }
292
300 bool isNoData( qgssize row, qgssize column ) const SIP_HOLDGIL
301 {
302 return isNoData( row * static_cast< qgssize >( mWidth ) + column );
303 }
304
311 bool isNoData( qgssize index ) const SIP_HOLDGIL
312 {
313 if ( !mHasNoDataValue && !mNoDataBitmap )
314 return false;
315 if ( index >= static_cast< qgssize >( mWidth )*mHeight )
316 {
317 QgsDebugError( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
318 return true; // we consider no data if outside
319 }
320 if ( mHasNoDataValue )
321 {
322 const double value = readValue( mData, mDataType, index );
323 return isNoDataValue( value );
324 }
325 // use no data bitmap
326 if ( !mNoDataBitmap )
327 {
328 // no data are not defined
329 return false;
330 }
331 // TODO: optimize
332 const int row = static_cast< int >( index ) / mWidth;
333 const int column = index % mWidth;
334 const qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
335 const int bit = column % 8;
336 const int mask = 0x80 >> bit;
337 //int x = mNoDataBitmap[byte] & mask;
338 //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) ) );
339 return mNoDataBitmap[byte] & mask;
340 }
341
349 bool setValue( int row, int column, double value ) SIP_HOLDGIL
350 {
351 return setValue( static_cast< qgssize >( row ) * mWidth + column, value );
352 }
353
360 bool setValue( qgssize index, double value ) SIP_HOLDGIL
361 {
362 if ( !mData )
363 {
364 QgsDebugError( QStringLiteral( "Data block not allocated" ) );
365 return false;
366 }
367 if ( index >= static_cast< qgssize >( mWidth ) *mHeight )
368 {
369 QgsDebugError( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
370 return false;
371 }
372 writeValue( mData, mDataType, index, value );
373 return true;
374 }
375
383 bool setColor( int row, int column, QRgb color ) SIP_HOLDGIL
384 {
385 return setColor( static_cast< qgssize >( row ) * mWidth + column, color );
386 }
387
394 bool setColor( qgssize index, QRgb color ) SIP_HOLDGIL
395 {
396 if ( !mImage )
397 {
398 QgsDebugError( QStringLiteral( "Image not allocated" ) );
399 return false;
400 }
401
402 if ( index >= static_cast< qgssize >( mImage->width() ) * mImage->height() )
403 {
404 QgsDebugError( QStringLiteral( "index %1 out of range" ).arg( index ) );
405 return false;
406 }
407
408 // setPixel() is slow, see Qt doc -> use direct access
409 QRgb *bits = reinterpret_cast< QRgb * >( mImage->bits() );
410 bits[index] = color;
411 return true;
412 }
413
422 {
423 if ( !mImage )
424 return nullptr;
425 return reinterpret_cast< QRgb * >( mImage->bits() );
426 }
427
434 bool setIsNoData( int row, int column ) SIP_HOLDGIL
435 {
436 return setIsNoData( static_cast< qgssize >( row ) * mWidth + column );
437 }
438
445 {
446 if ( mHasNoDataValue )
447 {
448 return setValue( index, mNoDataValue );
449 }
450 else
451 {
452 if ( !mNoDataBitmap )
453 {
454 if ( !createNoDataBitmap() )
455 {
456 return false;
457 }
458 }
459 // TODO: optimize
460 const int row = static_cast< int >( index ) / mWidth;
461 const int column = index % mWidth;
462 const qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
463 const int bit = column % 8;
464 const int nodata = 0x80 >> bit;
465 //QgsDebugMsg ( QString("set byte = %1 bit = %2 no data by %3").arg(byte).arg(bit).arg(nodata, 0,2 ) );
466 mNoDataBitmap[byte] = mNoDataBitmap[byte] | nodata;
467 return true;
468 }
469 }
470
475 bool setIsNoData();
476
481 bool setIsNoDataExcept( QRect exceptRect );
482
492 void setIsData( int row, int column ) SIP_HOLDGIL
493 {
494 setIsData( static_cast< qgssize >( row )*mWidth + column );
495 }
496
506 {
507 if ( mHasNoDataValue )
508 {
509 //no data value set, so mNoDataBitmap is not being used
510 return;
511 }
512
513 if ( !mNoDataBitmap )
514 {
515 return;
516 }
517
518 // TODO: optimize
519 const int row = static_cast< int >( index ) / mWidth;
520 const int column = index % mWidth;
521 const qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
522 const int bit = column % 8;
523 const int nodata = 0x80 >> bit;
524 mNoDataBitmap[byte] = mNoDataBitmap[byte] & ~nodata;
525 }
526
536 QByteArray data() const;
537
547 void setData( const QByteArray &data, int offset = 0 );
548
555 char *bits( int row, int column ) SIP_SKIP;
556
562 char *bits( qgssize index ) SIP_SKIP;
563
568 char *bits() SIP_SKIP;
569
576 static QString printValue( double value );
577
586 static QString printValue( float value ) SIP_SKIP;
587
593 bool convert( Qgis::DataType destDataType );
594
598 QImage image() const;
599
604 bool setImage( const QImage *image );
605
607 inline static double readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP;
608
610 inline static void writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP;
611
612 void applyNoDataValues( const QgsRasterRangeList &rangeList );
613
618 void applyScaleOffset( double scale, double offset );
619
621 QgsError error() const { return mError; }
622
624 void setError( const QgsError &error ) { mError = error;}
625
626 QString toString() const;
627
638 static QRect subRect( const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent );
639
645 int width() const SIP_HOLDGIL { return mWidth; }
646
652 int height() const SIP_HOLDGIL { return mHeight; }
653
654 private:
655 static QImage::Format imageFormat( Qgis::DataType dataType );
656 static Qgis::DataType dataType( QImage::Format format );
657
664 static bool isNoDataValue( double value, double noDataValue )
665 {
666 // TODO: optimize no data value test by memcmp()
667 // More precise would be std::isnan(value) && std::isnan(noDataValue(bandNo)), but probably
668 // not important and slower
669 return std::isnan( value ) ||
670 qgsDoubleNear( value, noDataValue );
671 }
672
678 inline bool isNoDataValue( double value ) const;
679
684 bool createNoDataBitmap();
685
695 static void *convert( void *srcData, Qgis::DataType srcDataType, Qgis::DataType destDataType, qgssize size );
696
697 // Valid
698 bool mValid = true;
699
700 // Data type
702
703 // Data type size in bytes, to make bits() fast
704 int mTypeSize = 0;
705
706 // Width
707 int mWidth = 0;
708
709 // Height
710 int mHeight = 0;
711
712 // Has no data value
713 bool mHasNoDataValue = false;
714
715 // No data value
716 double mNoDataValue;
717
718 static const QRgb NO_DATA_COLOR;
719
720 // Data block for numerical data types, not used with image data types
721 // QByteArray does not seem to be intended for large data blocks, does it?
722 void *mData = nullptr;
723
724 // Image for image data types, not used with numerical data types
725 QImage *mImage = nullptr;
726
727 // Bitmap of no data. One bit for each pixel. Bit is 1 if a pixels is no data.
728 // Each row is represented by whole number of bytes (last bits may be unused)
729 // to make processing rows easy.
730 char *mNoDataBitmap = nullptr;
731
732 // number of bytes in mNoDataBitmap row
733 int mNoDataBitmapWidth = 0;
734
735 // total size in bytes of mNoDataBitmap
736 qgssize mNoDataBitmapSize = 0;
737
738 // Error
739 QgsError mError;
740};
741
742inline double QgsRasterBlock::readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP
743{
744 if ( !data )
745 {
746 return std::numeric_limits<double>::quiet_NaN();
747 }
748
749 switch ( type )
750 {
752 return static_cast< double >( ( static_cast< quint8 * >( data ) )[index] );
754 return static_cast< double >( ( static_cast< qint8 * >( data ) )[index] );
756 return static_cast< double >( ( static_cast< quint16 * >( data ) )[index] );
758 return static_cast< double >( ( static_cast< qint16 * >( data ) )[index] );
760 return static_cast< double >( ( static_cast< quint32 * >( data ) )[index] );
762 return static_cast< double >( ( static_cast< qint32 * >( data ) )[index] );
764 return static_cast< double >( ( static_cast< float * >( data ) )[index] );
766 return static_cast< double >( ( static_cast< double * >( data ) )[index] );
774 QgsDebugError( QStringLiteral( "Data type %1 is not supported" ).arg( qgsEnumValueToKey< Qgis::DataType >( type ) ) );
775 break;
776 }
777
778 return std::numeric_limits<double>::quiet_NaN();
779}
780
781inline void QgsRasterBlock::writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP
782{
783 if ( !data ) return;
784
785 switch ( type )
786 {
788 ( static_cast< quint8 * >( data ) )[index] = static_cast< quint8 >( value );
789 break;
791 ( static_cast< qint8 * >( data ) )[index] = static_cast< qint8 >( value );
792 break;
794 ( static_cast< quint16 * >( data ) )[index] = static_cast< quint16 >( value );
795 break;
797 ( static_cast< qint16 * >( data ) )[index] = static_cast< qint16 >( value );
798 break;
800 ( static_cast< quint32 * >( data ) )[index] = static_cast< quint32 >( value );
801 break;
803 ( static_cast< qint32 * >( data ) )[index] = static_cast< qint32 >( value );
804 break;
806 ( static_cast< float * >( data ) )[index] = static_cast< float >( value );
807 break;
809 ( static_cast< double * >( data ) )[index] = value;
810 break;
818 QgsDebugError( QStringLiteral( "Data type %1 is not supported" ).arg( qgsEnumValueToKey< Qgis::DataType >( type ) ) );
819 break;
820 }
821}
822
823inline double QgsRasterBlock::value( qgssize index ) const SIP_SKIP
824{
825 if ( !mData )
826 {
827 QgsDebugError( QStringLiteral( "Data block not allocated" ) );
828 return std::numeric_limits<double>::quiet_NaN();
829 }
830 return readValue( mData, mDataType, index );
831}
832
833inline double QgsRasterBlock::valueAndNoData( qgssize index, bool &isNoData ) const SIP_SKIP
834{
835 if ( !mData )
836 {
837 QgsDebugError( QStringLiteral( "Data block not allocated" ) );
838 isNoData = true;
839 return std::numeric_limits<double>::quiet_NaN();
840 }
841 if ( index >= static_cast< qgssize >( mWidth )*mHeight )
842 {
843 QgsDebugError( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
844 isNoData = true; // we consider no data if outside
845 return std::numeric_limits<double>::quiet_NaN();
846 }
847
848 const double val = readValue( mData, mDataType, index );
849
850 if ( !mHasNoDataValue && !mNoDataBitmap )
851 {
852 isNoData = false;
853 return val;
854 }
855
856 if ( mHasNoDataValue )
857 {
858 isNoData = isNoDataValue( val );
859 return val;
860 }
861 // use no data bitmap
862 if ( !mNoDataBitmap )
863 {
864 // no data are not defined
865 isNoData = false;
866 return val;
867 }
868
869 // no data is a bitmap
870 isNoData = QgsRasterBlock::isNoData( index );
871 return val;
872}
873
874inline bool QgsRasterBlock::isNoDataValue( double value ) const SIP_SKIP
875{
876 return std::isnan( value ) || qgsDoubleNear( value, mNoDataValue );
877}
878
879#endif
880
881
The Qgis class provides global constants for use throughout the application.
Definition qgis.h:54
DataType
Raster data types.
Definition qgis.h:269
@ 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.
@ Int8
Eight bit signed integer (qint8) (added in QGIS 3.30)
@ 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.
bool isValid() const
Returns true if the block is valid (correctly filled with data).
QRgb color(int row, int column) const
Read a single color.
double value(int row, int column) const
Read a single value if type of block is numeric.
void setValid(bool valid)
Mark block as valid or invalid.
int height() const
Returns the height (number of rows) of the raster block.
bool isNoData(qgssize row, qgssize column) const
Check if value at position is no data.
bool isNoData(qgssize index) const
Check if value at position is no data.
bool setColor(qgssize index, QRgb color)
Set color on index (indexed line by line)
int dataTypeSize() const
Data type size in bytes.
bool hasNoData() const
Returns true if the block may contain no 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.
static int typeSize(Qgis::DataType dataType)
Returns the size in bytes for the specified dataType.
bool setIsNoData(qgssize index)
Set no data on pixel.
bool setValue(qgssize index, double value)
Set value on index (indexed line by line)
QRgb * colorData()
Gives direct read/write access to the raster RGB data.
void setIsData(qgssize index)
Remove no data flag on pixel.
bool setValue(int row, int column, double value)
Set value on position.
bool setColor(int row, int column, QRgb color)
Set color on position.
bool isNoData(int row, int column) const
Checks if value at position is no data.
void setIsData(int row, int column)
Remove no data flag on pixel.
Qgis::DataType dataType() const
Returns data type.
bool hasNoDataValue() const
true if the block has no data value.
const quint8 * byteData() const
Gives direct access to the raster block data.
static void writeValue(void *data, Qgis::DataType type, qgssize index, double value)
int width() const
Returns the width (number of columns) of the raster block.
void setError(const QgsError &error)
Sets the last error.
static double readValue(void *data, Qgis::DataType type, qgssize index)
bool setIsNoData(int row, int column)
Set no data on pixel.
QRgb color(qgssize index) const
Read a single value.
A rectangle specified with double values.
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:4887
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:4332
#define SIP_SKIP
Definition qgis_sip.h:126
#define SIP_HOLDGIL
Definition qgis_sip.h:166
#define QgsDebugError(str)
Definition qgslogger.h:38
QList< QgsRasterRange > QgsRasterRangeList