QGIS API Documentation 3.39.0-Master (d85f3c2a281)
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
678 private:
679 static QImage::Format imageFormat( Qgis::DataType dataType );
680 static Qgis::DataType dataType( QImage::Format format );
681
688 static bool isNoDataValue( double value, double noDataValue )
689 {
690 // TODO: optimize no data value test by memcmp()
691 // More precise would be std::isnan(value) && std::isnan(noDataValue(bandNo)), but probably
692 // not important and slower
693 return std::isnan( value ) ||
694 qgsDoubleNear( value, noDataValue );
695 }
696
702 inline bool isNoDataValue( double value ) const;
703
708 bool createNoDataBitmap();
709
719 static void *convert( void *srcData, Qgis::DataType srcDataType, Qgis::DataType destDataType, qgssize size );
720
721 // Valid
722 bool mValid = true;
723
724 // Data type
726
727 // Data type size in bytes, to make bits() fast
728 int mTypeSize = 0;
729
730 // Width
731 int mWidth = 0;
732
733 // Height
734 int mHeight = 0;
735
736 // Has no data value
737 bool mHasNoDataValue = false;
738
739 // No data value
740 double mNoDataValue;
741
742 static const QRgb NO_DATA_COLOR;
743
744 // Data block for numerical data types, not used with image data types
745 // QByteArray does not seem to be intended for large data blocks, does it?
746 void *mData = nullptr;
747
748 // Image for image data types, not used with numerical data types
749 QImage *mImage = nullptr;
750
751 // Bitmap of no data. One bit for each pixel. Bit is 1 if a pixels is no data.
752 // Each row is represented by whole number of bytes (last bits may be unused)
753 // to make processing rows easy.
754 char *mNoDataBitmap = nullptr;
755
756 // number of bytes in mNoDataBitmap row
757 int mNoDataBitmapWidth = 0;
758
759 // total size in bytes of mNoDataBitmap
760 qgssize mNoDataBitmapSize = 0;
761
762 // Error
763 QgsError mError;
764};
765
766inline double QgsRasterBlock::readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP
767{
768 if ( !data )
769 {
770 return std::numeric_limits<double>::quiet_NaN();
771 }
772
773 switch ( type )
774 {
776 return static_cast< double >( ( static_cast< quint8 * >( data ) )[index] );
778 return static_cast< double >( ( static_cast< qint8 * >( data ) )[index] );
780 return static_cast< double >( ( static_cast< quint16 * >( data ) )[index] );
782 return static_cast< double >( ( static_cast< qint16 * >( data ) )[index] );
784 return static_cast< double >( ( static_cast< quint32 * >( data ) )[index] );
786 return static_cast< double >( ( static_cast< qint32 * >( data ) )[index] );
788 return static_cast< double >( ( static_cast< float * >( data ) )[index] );
790 return static_cast< double >( ( static_cast< double * >( data ) )[index] );
798 QgsDebugError( QStringLiteral( "Data type %1 is not supported" ).arg( qgsEnumValueToKey< Qgis::DataType >( type ) ) );
799 break;
800 }
801
802 return std::numeric_limits<double>::quiet_NaN();
803}
804
805inline void QgsRasterBlock::writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP
806{
807 if ( !data ) return;
808
809 switch ( type )
810 {
812 ( static_cast< quint8 * >( data ) )[index] = static_cast< quint8 >( value );
813 break;
815 ( static_cast< qint8 * >( data ) )[index] = static_cast< qint8 >( value );
816 break;
818 ( static_cast< quint16 * >( data ) )[index] = static_cast< quint16 >( value );
819 break;
821 ( static_cast< qint16 * >( data ) )[index] = static_cast< qint16 >( value );
822 break;
824 ( static_cast< quint32 * >( data ) )[index] = static_cast< quint32 >( value );
825 break;
827 ( static_cast< qint32 * >( data ) )[index] = static_cast< qint32 >( value );
828 break;
830 ( static_cast< float * >( data ) )[index] = static_cast< float >( value );
831 break;
833 ( static_cast< double * >( data ) )[index] = value;
834 break;
842 QgsDebugError( QStringLiteral( "Data type %1 is not supported" ).arg( qgsEnumValueToKey< Qgis::DataType >( type ) ) );
843 break;
844 }
845}
846
847inline double QgsRasterBlock::value( qgssize index ) const SIP_SKIP
848{
849 if ( !mData )
850 {
851 QgsDebugError( QStringLiteral( "Data block not allocated" ) );
852 return std::numeric_limits<double>::quiet_NaN();
853 }
854 return readValue( mData, mDataType, index );
855}
856
857inline double QgsRasterBlock::valueAndNoData( qgssize index, bool &isNoData ) const SIP_SKIP
858{
859 if ( !mData )
860 {
861 QgsDebugError( QStringLiteral( "Data block not allocated" ) );
862 isNoData = true;
863 return std::numeric_limits<double>::quiet_NaN();
864 }
865 if ( index >= static_cast< qgssize >( mWidth )*mHeight )
866 {
867 QgsDebugError( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
868 isNoData = true; // we consider no data if outside
869 return std::numeric_limits<double>::quiet_NaN();
870 }
871
872 const double val = readValue( mData, mDataType, index );
873
874 if ( !mHasNoDataValue && !mNoDataBitmap )
875 {
876 isNoData = false;
877 return val;
878 }
879
880 if ( mHasNoDataValue )
881 {
882 isNoData = isNoDataValue( val );
883 return val;
884 }
885 // use no data bitmap
886 if ( !mNoDataBitmap )
887 {
888 // no data are not defined
889 isNoData = false;
890 return val;
891 }
892
893 // no data is a bitmap
894 isNoData = QgsRasterBlock::isNoData( index );
895 return val;
896}
897
898inline bool QgsRasterBlock::isNoDataValue( double value ) const SIP_SKIP
899{
900 return std::isnan( value ) || qgsDoubleNear( value, mNoDataValue );
901}
902
903#endif
904
905
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:6405
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:5857
#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