QGIS API Documentation 3.39.0-Master (47f7b3a4989)
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
162 void setNoDataValue( double noDataValue ) SIP_HOLDGIL;
163
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 QgsDebugError( 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 QgsDebugError( QStringLiteral( "Data block not allocated" ) );
363 return false;
364 }
365 if ( index >= static_cast< qgssize >( mWidth ) *mHeight )
366 {
367 QgsDebugError( 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 QgsDebugError( QStringLiteral( "Image not allocated" ) );
397 return false;
398 }
399
400 if ( index >= static_cast< qgssize >( mImage->width() ) * mImage->height() )
401 {
402 QgsDebugError( 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
489 void setIsData( int row, int column ) SIP_HOLDGIL
490 {
491 setIsData( static_cast< qgssize >( row )*mWidth + column );
492 }
493
502 {
503 if ( mHasNoDataValue )
504 {
505 //no data value set, so mNoDataBitmap is not being used
506 return;
507 }
508
509 if ( !mNoDataBitmap )
510 {
511 return;
512 }
513
514 // TODO: optimize
515 const int row = static_cast< int >( index ) / mWidth;
516 const int column = index % mWidth;
517 const qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
518 const int bit = column % 8;
519 const int nodata = 0x80 >> bit;
520 mNoDataBitmap[byte] = mNoDataBitmap[byte] & ~nodata;
521 }
522
531 QByteArray data() const;
532
541 void setData( const QByteArray &data, int offset = 0 );
542
549 char *bits( int row, int column ) SIP_SKIP;
550
558 char *bits( qgssize index ) SIP_SKIP;
559
566 char *bits() SIP_SKIP;
567
577 const char *constBits( qgssize index ) const SIP_SKIP;
578
586 const char *constBits() const SIP_SKIP;
587
595 static QString printValue( double value, bool localized = false );
596
605 static QString printValue( float value, bool localized = false ) SIP_SKIP;
606
612 bool convert( Qgis::DataType destDataType );
613
617 QImage image() const;
618
623 bool setImage( const QImage *image );
624
626 inline static double readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP;
627
629 inline static void writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP;
630
631 void applyNoDataValues( const QgsRasterRangeList &rangeList );
632
636 void applyScaleOffset( double scale, double offset );
637
639 QgsError error() const { return mError; }
640
642 void setError( const QgsError &error ) { mError = error;}
643
644 QString toString() const;
645
656 static QRect subRect( const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent );
657
662 int width() const SIP_HOLDGIL { return mWidth; }
663
668 int height() const SIP_HOLDGIL { return mHeight; }
669
670 private:
671 static QImage::Format imageFormat( Qgis::DataType dataType );
672 static Qgis::DataType dataType( QImage::Format format );
673
680 static bool isNoDataValue( double value, double noDataValue )
681 {
682 // TODO: optimize no data value test by memcmp()
683 // More precise would be std::isnan(value) && std::isnan(noDataValue(bandNo)), but probably
684 // not important and slower
685 return std::isnan( value ) ||
686 qgsDoubleNear( value, noDataValue );
687 }
688
694 inline bool isNoDataValue( double value ) const;
695
700 bool createNoDataBitmap();
701
711 static void *convert( void *srcData, Qgis::DataType srcDataType, Qgis::DataType destDataType, qgssize size );
712
713 // Valid
714 bool mValid = true;
715
716 // Data type
718
719 // Data type size in bytes, to make bits() fast
720 int mTypeSize = 0;
721
722 // Width
723 int mWidth = 0;
724
725 // Height
726 int mHeight = 0;
727
728 // Has no data value
729 bool mHasNoDataValue = false;
730
731 // No data value
732 double mNoDataValue;
733
734 static const QRgb NO_DATA_COLOR;
735
736 // Data block for numerical data types, not used with image data types
737 // QByteArray does not seem to be intended for large data blocks, does it?
738 void *mData = nullptr;
739
740 // Image for image data types, not used with numerical data types
741 QImage *mImage = nullptr;
742
743 // Bitmap of no data. One bit for each pixel. Bit is 1 if a pixels is no data.
744 // Each row is represented by whole number of bytes (last bits may be unused)
745 // to make processing rows easy.
746 char *mNoDataBitmap = nullptr;
747
748 // number of bytes in mNoDataBitmap row
749 int mNoDataBitmapWidth = 0;
750
751 // total size in bytes of mNoDataBitmap
752 qgssize mNoDataBitmapSize = 0;
753
754 // Error
755 QgsError mError;
756};
757
758inline double QgsRasterBlock::readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP
759{
760 if ( !data )
761 {
762 return std::numeric_limits<double>::quiet_NaN();
763 }
764
765 switch ( type )
766 {
768 return static_cast< double >( ( static_cast< quint8 * >( data ) )[index] );
770 return static_cast< double >( ( static_cast< qint8 * >( data ) )[index] );
772 return static_cast< double >( ( static_cast< quint16 * >( data ) )[index] );
774 return static_cast< double >( ( static_cast< qint16 * >( data ) )[index] );
776 return static_cast< double >( ( static_cast< quint32 * >( data ) )[index] );
778 return static_cast< double >( ( static_cast< qint32 * >( data ) )[index] );
780 return static_cast< double >( ( static_cast< float * >( data ) )[index] );
782 return static_cast< double >( ( static_cast< double * >( data ) )[index] );
790 QgsDebugError( QStringLiteral( "Data type %1 is not supported" ).arg( qgsEnumValueToKey< Qgis::DataType >( type ) ) );
791 break;
792 }
793
794 return std::numeric_limits<double>::quiet_NaN();
795}
796
797inline void QgsRasterBlock::writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP
798{
799 if ( !data ) return;
800
801 switch ( type )
802 {
804 ( static_cast< quint8 * >( data ) )[index] = static_cast< quint8 >( value );
805 break;
807 ( static_cast< qint8 * >( data ) )[index] = static_cast< qint8 >( value );
808 break;
810 ( static_cast< quint16 * >( data ) )[index] = static_cast< quint16 >( value );
811 break;
813 ( static_cast< qint16 * >( data ) )[index] = static_cast< qint16 >( value );
814 break;
816 ( static_cast< quint32 * >( data ) )[index] = static_cast< quint32 >( value );
817 break;
819 ( static_cast< qint32 * >( data ) )[index] = static_cast< qint32 >( value );
820 break;
822 ( static_cast< float * >( data ) )[index] = static_cast< float >( value );
823 break;
825 ( static_cast< double * >( data ) )[index] = value;
826 break;
834 QgsDebugError( QStringLiteral( "Data type %1 is not supported" ).arg( qgsEnumValueToKey< Qgis::DataType >( type ) ) );
835 break;
836 }
837}
838
839inline double QgsRasterBlock::value( qgssize index ) const SIP_SKIP
840{
841 if ( !mData )
842 {
843 QgsDebugError( QStringLiteral( "Data block not allocated" ) );
844 return std::numeric_limits<double>::quiet_NaN();
845 }
846 return readValue( mData, mDataType, index );
847}
848
849inline double QgsRasterBlock::valueAndNoData( qgssize index, bool &isNoData ) const SIP_SKIP
850{
851 if ( !mData )
852 {
853 QgsDebugError( QStringLiteral( "Data block not allocated" ) );
854 isNoData = true;
855 return std::numeric_limits<double>::quiet_NaN();
856 }
857 if ( index >= static_cast< qgssize >( mWidth )*mHeight )
858 {
859 QgsDebugError( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
860 isNoData = true; // we consider no data if outside
861 return std::numeric_limits<double>::quiet_NaN();
862 }
863
864 const double val = readValue( mData, mDataType, index );
865
866 if ( !mHasNoDataValue && !mNoDataBitmap )
867 {
868 isNoData = false;
869 return val;
870 }
871
872 if ( mHasNoDataValue )
873 {
874 isNoData = isNoDataValue( val );
875 return val;
876 }
877 // use no data bitmap
878 if ( !mNoDataBitmap )
879 {
880 // no data are not defined
881 isNoData = false;
882 return val;
883 }
884
885 // no data is a bitmap
886 isNoData = QgsRasterBlock::isNoData( index );
887 return val;
888}
889
890inline bool QgsRasterBlock::isNoDataValue( double value ) const SIP_SKIP
891{
892 return std::isnan( value ) || qgsDoubleNear( value, mNoDataValue );
893}
894
895#endif
896
897
The Qgis class provides global constants for use throughout the application.
Definition qgis.h:54
DataType
Raster data types.
Definition qgis.h:288
@ 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:6013
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:5465
#define SIP_SKIP
Definition qgis_sip.h:126
#define SIP_HOLDGIL
Definition qgis_sip.h:171
#define QgsDebugError(str)
Definition qgslogger.h:38
QList< QgsRasterRange > QgsRasterRangeList