QGIS API Documentation 3.41.0-Master (45a0abf3bec)
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
147 bool hasNoDataValue() const SIP_HOLDGIL { return mHasNoDataValue; }
148
156 {
157 return mHasNoDataValue || mNoDataBitmap;
158 }
159
166 void setNoDataValue( double noDataValue ) SIP_HOLDGIL;
167
175 void resetNoDataValue() SIP_HOLDGIL;
176
185 double noDataValue() const SIP_HOLDGIL { return mNoDataValue; }
186
193 static QByteArray valueBytes( Qgis::DataType dataType, double value );
194
203 double value( int row, int column ) const SIP_HOLDGIL
204 {
205 return value( static_cast< qgssize >( row ) * mWidth + column );
206 }
207
220 double valueAndNoData( int row, int column, bool &isNoData ) const SIP_SKIP
221 {
222 return valueAndNoData( static_cast< qgssize >( row ) * mWidth + column, isNoData );
223 }
224
232 inline double value( qgssize index ) const SIP_HOLDGIL;
233
246 inline double valueAndNoData( qgssize index, bool &isNoData ) const SIP_SKIP;
247
255 const quint8 *byteData() const SIP_SKIP
256 {
257 if ( mDataType != Qgis::DataType::Byte )
258 return nullptr;
259 return static_cast< const quint8 * >( mData );
260 }
261
268 QRgb color( int row, int column ) const SIP_HOLDGIL
269 {
270 if ( !mImage ) return NO_DATA_COLOR;
271
272 return mImage->pixel( column, row );
273 }
274
280 QRgb color( qgssize index ) const SIP_HOLDGIL
281 {
282 const int row = static_cast< int >( std::floor( static_cast< double >( index ) / mWidth ) );
283 const int column = index % mWidth;
284 return color( row, column );
285 }
286
294 bool isNoData( int row, int column ) const SIP_HOLDGIL
295 {
296 return isNoData( static_cast< qgssize >( row ) * mWidth + column );
297 }
298
306 bool isNoData( qgssize row, qgssize column ) const SIP_HOLDGIL
307 {
308 return isNoData( row * static_cast< qgssize >( mWidth ) + column );
309 }
310
317 bool isNoData( qgssize index ) const SIP_HOLDGIL
318 {
319 if ( !mHasNoDataValue && !mNoDataBitmap )
320 return false;
321 if ( index >= static_cast< qgssize >( mWidth )*mHeight )
322 {
323 QgsDebugError( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
324 return true; // we consider no data if outside
325 }
326 if ( mHasNoDataValue )
327 {
328 const double value = readValue( mData, mDataType, index );
329 return isNoDataValue( value );
330 }
331 // use no data bitmap
332 if ( !mNoDataBitmap )
333 {
334 // no data are not defined
335 return false;
336 }
337 // TODO: optimize
338 const int row = static_cast< int >( index ) / mWidth;
339 const int column = index % mWidth;
340 const qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
341 const int bit = column % 8;
342 const int mask = 0x80 >> bit;
343 //int x = mNoDataBitmap[byte] & mask;
344 //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) ) );
345 return mNoDataBitmap[byte] & mask;
346 }
347
355 bool setValue( int row, int column, double value ) SIP_HOLDGIL
356 {
357 return setValue( static_cast< qgssize >( row ) * mWidth + column, value );
358 }
359
366 bool setValue( qgssize index, double value ) SIP_HOLDGIL
367 {
368 if ( !mData )
369 {
370 QgsDebugError( QStringLiteral( "Data block not allocated" ) );
371 return false;
372 }
373 if ( index >= static_cast< qgssize >( mWidth ) *mHeight )
374 {
375 QgsDebugError( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
376 return false;
377 }
378 writeValue( mData, mDataType, index, value );
379 return true;
380 }
381
389 bool setColor( int row, int column, QRgb color ) SIP_HOLDGIL
390 {
391 return setColor( static_cast< qgssize >( row ) * mWidth + column, color );
392 }
393
400 bool setColor( qgssize index, QRgb color ) SIP_HOLDGIL
401 {
402 if ( !mImage )
403 {
404 QgsDebugError( QStringLiteral( "Image not allocated" ) );
405 return false;
406 }
407
408 if ( index >= static_cast< qgssize >( mImage->width() ) * mImage->height() )
409 {
410 QgsDebugError( QStringLiteral( "index %1 out of range" ).arg( index ) );
411 return false;
412 }
413
414 // setPixel() is slow, see Qt doc -> use direct access
415 QRgb *bits = reinterpret_cast< QRgb * >( mImage->bits() );
416 bits[index] = color;
417 return true;
418 }
419
428 {
429 if ( !mImage )
430 return nullptr;
431 return reinterpret_cast< QRgb * >( mImage->bits() );
432 }
433
440 bool setIsNoData( int row, int column ) SIP_HOLDGIL
441 {
442 return setIsNoData( static_cast< qgssize >( row ) * mWidth + column );
443 }
444
451 {
452 if ( mHasNoDataValue )
453 {
454 return setValue( index, mNoDataValue );
455 }
456 else
457 {
458 if ( !mNoDataBitmap )
459 {
460 if ( !createNoDataBitmap() )
461 {
462 return false;
463 }
464 }
465 // TODO: optimize
466 const int row = static_cast< int >( index ) / mWidth;
467 const int column = index % mWidth;
468 const qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
469 const int bit = column % 8;
470 const int nodata = 0x80 >> bit;
471 //QgsDebugMsg ( QString("set byte = %1 bit = %2 no data by %3").arg(byte).arg(bit).arg(nodata, 0,2 ) );
472 mNoDataBitmap[byte] = mNoDataBitmap[byte] | nodata;
473 return true;
474 }
475 }
476
481 bool setIsNoData();
482
487 bool setIsNoDataExcept( QRect exceptRect );
488
497 void setIsData( int row, int column ) SIP_HOLDGIL
498 {
499 setIsData( static_cast< qgssize >( row )*mWidth + column );
500 }
501
510 {
511 if ( mHasNoDataValue )
512 {
513 //no data value set, so mNoDataBitmap is not being used
514 return;
515 }
516
517 if ( !mNoDataBitmap )
518 {
519 return;
520 }
521
522 // TODO: optimize
523 const int row = static_cast< int >( index ) / mWidth;
524 const int column = index % mWidth;
525 const qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
526 const int bit = column % 8;
527 const int nodata = 0x80 >> bit;
528 mNoDataBitmap[byte] = mNoDataBitmap[byte] & ~nodata;
529 }
530
539 QByteArray data() const;
540
549 void setData( const QByteArray &data, int offset = 0 );
550
557 char *bits( int row, int column ) SIP_SKIP;
558
566 char *bits( qgssize index ) SIP_SKIP;
567
574 char *bits() SIP_SKIP;
575
585 const char *constBits( qgssize index ) const SIP_SKIP;
586
594 const char *constBits() const SIP_SKIP;
595
603 static QString printValue( double value, bool localized = false );
604
613 static QString printValue( float value, bool localized = false ) SIP_SKIP;
614
620 bool convert( Qgis::DataType destDataType );
621
625 QImage image() const;
626
631 bool setImage( const QImage *image );
632
634 inline static double readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP;
635
637 inline static void writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP;
638
639 void applyNoDataValues( const QgsRasterRangeList &rangeList );
640
644 void applyScaleOffset( double scale, double offset );
645
647 QgsError error() const { return mError; }
648
650 void setError( const QgsError &error ) { mError = error;}
651
652 QString toString() const;
653
664 static QRect subRect( const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent );
665
670 int width() const SIP_HOLDGIL { return mWidth; }
671
676 int height() const SIP_HOLDGIL { return mHeight; }
677
695 bool minimum( double &minimum SIP_OUT, int &row SIP_OUT, int &column SIP_OUT ) const;
696
714 bool maximum( double &maximum SIP_OUT, int &row SIP_OUT, int &column SIP_OUT ) const;
715
738 bool minimumMaximum( double &minimum SIP_OUT, int &minimumRow SIP_OUT, int &minimumColumn SIP_OUT, double &maximum SIP_OUT, int &maximumRow SIP_OUT, int &maximumColumn SIP_OUT ) const;
739
740 private:
741 static QImage::Format imageFormat( Qgis::DataType dataType );
742 static Qgis::DataType dataType( QImage::Format format );
743
750 static bool isNoDataValue( double value, double noDataValue )
751 {
752 // TODO: optimize no data value test by memcmp()
753 // More precise would be std::isnan(value) && std::isnan(noDataValue(bandNo)), but probably
754 // not important and slower
755 return std::isnan( value ) ||
756 qgsDoubleNear( value, noDataValue );
757 }
758
764 inline bool isNoDataValue( double value ) const;
765
770 bool createNoDataBitmap();
771
781 static void *convert( void *srcData, Qgis::DataType srcDataType, Qgis::DataType destDataType, qgssize size );
782
783 // Valid
784 bool mValid = true;
785
786 // Data type
788
789 // Data type size in bytes, to make bits() fast
790 int mTypeSize = 0;
791
792 // Width
793 int mWidth = 0;
794
795 // Height
796 int mHeight = 0;
797
798 // Has no data value
799 bool mHasNoDataValue = false;
800
801 // No data value
802 double mNoDataValue;
803
804 static const QRgb NO_DATA_COLOR;
805
806 // Data block for numerical data types, not used with image data types
807 // QByteArray does not seem to be intended for large data blocks, does it?
808 void *mData = nullptr;
809
810 // Image for image data types, not used with numerical data types
811 QImage *mImage = nullptr;
812
813 // Bitmap of no data. One bit for each pixel. Bit is 1 if a pixels is no data.
814 // Each row is represented by whole number of bytes (last bits may be unused)
815 // to make processing rows easy.
816 char *mNoDataBitmap = nullptr;
817
818 // number of bytes in mNoDataBitmap row
819 int mNoDataBitmapWidth = 0;
820
821 // total size in bytes of mNoDataBitmap
822 qgssize mNoDataBitmapSize = 0;
823
824 // Error
825 QgsError mError;
826};
827
828inline double QgsRasterBlock::readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP
829{
830 if ( !data )
831 {
832 return std::numeric_limits<double>::quiet_NaN();
833 }
834
835 switch ( type )
836 {
838 return static_cast< double >( ( static_cast< quint8 * >( data ) )[index] );
840 return static_cast< double >( ( static_cast< qint8 * >( data ) )[index] );
842 return static_cast< double >( ( static_cast< quint16 * >( data ) )[index] );
844 return static_cast< double >( ( static_cast< qint16 * >( data ) )[index] );
846 return static_cast< double >( ( static_cast< quint32 * >( data ) )[index] );
848 return static_cast< double >( ( static_cast< qint32 * >( data ) )[index] );
850 return static_cast< double >( ( static_cast< float * >( data ) )[index] );
852 return static_cast< double >( ( static_cast< double * >( data ) )[index] );
860 QgsDebugError( QStringLiteral( "Data type %1 is not supported" ).arg( qgsEnumValueToKey< Qgis::DataType >( type ) ) );
861 break;
862 }
863
864 return std::numeric_limits<double>::quiet_NaN();
865}
866
867inline void QgsRasterBlock::writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP
868{
869 if ( !data ) return;
870
871 switch ( type )
872 {
874 ( static_cast< quint8 * >( data ) )[index] = static_cast< quint8 >( value );
875 break;
877 ( static_cast< qint8 * >( data ) )[index] = static_cast< qint8 >( value );
878 break;
880 ( static_cast< quint16 * >( data ) )[index] = static_cast< quint16 >( value );
881 break;
883 ( static_cast< qint16 * >( data ) )[index] = static_cast< qint16 >( value );
884 break;
886 ( static_cast< quint32 * >( data ) )[index] = static_cast< quint32 >( value );
887 break;
889 ( static_cast< qint32 * >( data ) )[index] = static_cast< qint32 >( value );
890 break;
892 ( static_cast< float * >( data ) )[index] = static_cast< float >( value );
893 break;
895 ( static_cast< double * >( data ) )[index] = value;
896 break;
904 QgsDebugError( QStringLiteral( "Data type %1 is not supported" ).arg( qgsEnumValueToKey< Qgis::DataType >( type ) ) );
905 break;
906 }
907}
908
909inline double QgsRasterBlock::value( qgssize index ) const SIP_SKIP
910{
911 if ( !mData )
912 {
913 QgsDebugError( QStringLiteral( "Data block not allocated" ) );
914 return std::numeric_limits<double>::quiet_NaN();
915 }
916 return readValue( mData, mDataType, index );
917}
918
919inline double QgsRasterBlock::valueAndNoData( qgssize index, bool &isNoData ) const SIP_SKIP
920{
921 if ( !mData )
922 {
923 QgsDebugError( QStringLiteral( "Data block not allocated" ) );
924 isNoData = true;
925 return std::numeric_limits<double>::quiet_NaN();
926 }
927 if ( index >= static_cast< qgssize >( mWidth )*mHeight )
928 {
929 QgsDebugError( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
930 isNoData = true; // we consider no data if outside
931 return std::numeric_limits<double>::quiet_NaN();
932 }
933
934 const double val = readValue( mData, mDataType, index );
935
936 if ( !mHasNoDataValue && !mNoDataBitmap )
937 {
938 isNoData = false;
939 return val;
940 }
941
942 if ( mHasNoDataValue )
943 {
944 isNoData = isNoDataValue( val );
945 return val;
946 }
947 // use no data bitmap
948 if ( !mNoDataBitmap )
949 {
950 // no data are not defined
951 isNoData = false;
952 return val;
953 }
954
955 // no data is a bitmap
956 isNoData = QgsRasterBlock::isNoData( index );
957 return val;
958}
959
960inline bool QgsRasterBlock::isNoDataValue( double value ) const SIP_SKIP
961{
962 return std::isnan( value ) || qgsDoubleNear( value, mNoDataValue );
963}
964
965#endif
966
967
The Qgis class provides global constants for use throughout the application.
Definition qgis.h:54
DataType
Raster data types.
Definition qgis.h:351
@ 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)
A container for error messages.
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:6506
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:5958
#define SIP_SKIP
Definition qgis_sip.h:126
#define SIP_OUT
Definition qgis_sip.h:58
#define SIP_HOLDGIL
Definition qgis_sip.h:171
#define QgsDebugError(str)
Definition qgslogger.h:38
QList< QgsRasterRange > QgsRasterRangeList