QGIS API Documentation 3.99.0-Master (2fe06baccd8)
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 <limits>
22
23#include "qgis.h"
24#include "qgis_core.h"
25#include "qgis_sip.h"
26#include "qgserror.h"
27#include "qgslogger.h"
28#include "qgsrasterrange.h"
29
30#include <QImage>
31
32class QgsRectangle;
33
38class CORE_EXPORT QgsRasterBlock
39{
40 public:
42
50
51 virtual ~QgsRasterBlock();
52
60 bool reset( Qgis::DataType dataType, int width, int height );
61
62 // TODO: consider if use isValid() at all, isEmpty() should be sufficient
63 // and works also if block is valid but empty - difference between valid and empty?
64
70 bool isValid() const SIP_HOLDGIL { return mValid; }
71
73 void setValid( bool valid ) SIP_HOLDGIL { mValid = valid; }
74
80 bool isEmpty() const;
81
86 {
87 // Modified and extended copy from GDAL
88 switch ( dataType )
89 {
92 return 1;
93
96 return 2;
97
102 return 4;
103
107 return 8;
108
110 return 16;
111
114 return 4;
115
117 break;
118 }
119 return 0;
120 }
121
126 {
127 return typeSize( mDataType );
128 }
129
136 static bool typeIsNumeric( Qgis::DataType type );
137
145 static bool typeIsComplex( Qgis::DataType type );
146
153 static bool typeIsColor( Qgis::DataType type );
154
156 Qgis::DataType dataType() const SIP_HOLDGIL { return mDataType; }
157
159 static Qgis::DataType typeWithNoDataValue( Qgis::DataType dataType, double *noDataValue );
160
168 bool hasNoDataValue() const SIP_HOLDGIL { return mHasNoDataValue; }
169
177 {
178 return mHasNoDataValue || mNoDataBitmap;
179 }
180
187 void setNoDataValue( double noDataValue ) SIP_HOLDGIL;
188
196 void resetNoDataValue() SIP_HOLDGIL;
197
206 double noDataValue() const SIP_HOLDGIL { return mNoDataValue; }
207
214 static QByteArray valueBytes( Qgis::DataType dataType, double value );
215
224 double value( int row, int column ) const SIP_HOLDGIL
225 {
226 return value( static_cast< qgssize >( row ) * mWidth + column );
227 }
228
241 double valueAndNoData( int row, int column, bool &isNoData ) const SIP_SKIP
242 {
243 return valueAndNoData( static_cast< qgssize >( row ) * mWidth + column, isNoData );
244 }
245
253 inline double value( qgssize index ) const SIP_HOLDGIL;
254
267 inline double valueAndNoData( qgssize index, bool &isNoData ) const SIP_SKIP;
268
276 const quint8 *byteData() const SIP_SKIP
277 {
278 if ( mDataType != Qgis::DataType::Byte )
279 return nullptr;
280 return static_cast< const quint8 * >( mData );
281 }
282
289 QRgb color( int row, int column ) const SIP_HOLDGIL
290 {
291 if ( !mImage ) return NO_DATA_COLOR;
292
293 return mImage->pixel( column, row );
294 }
295
301 QRgb color( qgssize index ) const SIP_HOLDGIL
302 {
303 const int row = static_cast< int >( std::floor( static_cast< double >( index ) / mWidth ) );
304 const int column = index % mWidth;
305 return color( row, column );
306 }
307
315 bool isNoData( int row, int column ) const SIP_HOLDGIL
316 {
317 return isNoData( static_cast< qgssize >( row ) * mWidth + column );
318 }
319
327 bool isNoData( qgssize row, qgssize column ) const SIP_HOLDGIL
328 {
329 return isNoData( row * static_cast< qgssize >( mWidth ) + column );
330 }
331
338 bool isNoData( qgssize index ) const SIP_HOLDGIL
339 {
340 if ( !mHasNoDataValue && !mNoDataBitmap )
341 return false;
342 if ( index >= static_cast< qgssize >( mWidth )*mHeight )
343 {
344 QgsDebugError( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
345 return true; // we consider no data if outside
346 }
347 if ( mHasNoDataValue )
348 {
349 const double value = readValue( mData, mDataType, index );
350 return isNoDataValue( value );
351 }
352 // use no data bitmap
353 if ( !mNoDataBitmap )
354 {
355 // no data are not defined
356 return false;
357 }
358 // TODO: optimize
359 const int row = static_cast< int >( index ) / mWidth;
360 const int column = index % mWidth;
361 const qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
362 const int bit = column % 8;
363 const int mask = 0x80 >> bit;
364 //int x = mNoDataBitmap[byte] & mask;
365 //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) ) );
366 return mNoDataBitmap[byte] & mask;
367 }
368
376 bool setValue( int row, int column, double value ) SIP_HOLDGIL
377 {
378 return setValue( static_cast< qgssize >( row ) * mWidth + column, value );
379 }
380
387 bool setValue( qgssize index, double value ) SIP_HOLDGIL
388 {
389 if ( !mData )
390 {
391 QgsDebugError( QStringLiteral( "Data block not allocated" ) );
392 return false;
393 }
394 if ( index >= static_cast< qgssize >( mWidth ) *mHeight )
395 {
396 QgsDebugError( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
397 return false;
398 }
399 writeValue( mData, mDataType, index, value );
400 return true;
401 }
402
410 bool setColor( int row, int column, QRgb color ) SIP_HOLDGIL
411 {
412 return setColor( static_cast< qgssize >( row ) * mWidth + column, color );
413 }
414
421 bool setColor( qgssize index, QRgb color ) SIP_HOLDGIL
422 {
423 if ( !mImage )
424 {
425 QgsDebugError( QStringLiteral( "Image not allocated" ) );
426 return false;
427 }
428
429 if ( index >= static_cast< qgssize >( mImage->width() ) * mImage->height() )
430 {
431 QgsDebugError( QStringLiteral( "index %1 out of range" ).arg( index ) );
432 return false;
433 }
434
435 // setPixel() is slow, see Qt doc -> use direct access
436 QRgb *bits = reinterpret_cast< QRgb * >( mImage->bits() );
437 bits[index] = color;
438 return true;
439 }
440
449 {
450 if ( !mImage )
451 return nullptr;
452 return reinterpret_cast< QRgb * >( mImage->bits() );
453 }
454
461 bool setIsNoData( int row, int column ) SIP_HOLDGIL
462 {
463 return setIsNoData( static_cast< qgssize >( row ) * mWidth + column );
464 }
465
472 {
473 if ( mHasNoDataValue )
474 {
475 return setValue( index, mNoDataValue );
476 }
477 else
478 {
479 if ( !mNoDataBitmap )
480 {
481 if ( !createNoDataBitmap() )
482 {
483 return false;
484 }
485 }
486 // TODO: optimize
487 const int row = static_cast< int >( index ) / mWidth;
488 const int column = index % mWidth;
489 const qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
490 const int bit = column % 8;
491 const int nodata = 0x80 >> bit;
492 //QgsDebugMsg ( QString("set byte = %1 bit = %2 no data by %3").arg(byte).arg(bit).arg(nodata, 0,2 ) );
493 mNoDataBitmap[byte] = mNoDataBitmap[byte] | nodata;
494 return true;
495 }
496 }
497
502 bool setIsNoData();
503
508 bool setIsNoDataExcept( QRect exceptRect );
509
518 void setIsData( int row, int column ) SIP_HOLDGIL
519 {
520 setIsData( static_cast< qgssize >( row )*mWidth + column );
521 }
522
531 {
532 if ( mHasNoDataValue )
533 {
534 //no data value set, so mNoDataBitmap is not being used
535 return;
536 }
537
538 if ( !mNoDataBitmap )
539 {
540 return;
541 }
542
543 // TODO: optimize
544 const int row = static_cast< int >( index ) / mWidth;
545 const int column = index % mWidth;
546 const qgssize byte = static_cast< qgssize >( row ) * mNoDataBitmapWidth + column / 8;
547 const int bit = column % 8;
548 const int nodata = 0x80 >> bit;
549 mNoDataBitmap[byte] = mNoDataBitmap[byte] & ~nodata;
550 }
551
552#ifndef SIP_RUN
561 bool fill( double value );
562#else
563
572 void fill( double value );
573 % MethodCode
574 if ( !QgsRasterBlock::typeIsNumeric( sipCpp->dataType() ) )
575 {
576 PyErr_SetString( PyExc_ValueError, QStringLiteral( "Cannot fill a block with %1 data type" ).arg( qgsEnumValueToKey( sipCpp->dataType() ) ).toUtf8().constData() );
577 sipIsErr = 1;
578 }
579 else if ( QgsRasterBlock::typeIsComplex( sipCpp->dataType() ) )
580 {
581 PyErr_SetString( PyExc_ValueError, QStringLiteral( "Cannot fill a block with %1 complex data type" ).arg( qgsEnumValueToKey( sipCpp->dataType() ) ).toUtf8().constData() );
582 sipIsErr = 1;
583 }
584 else if ( sipCpp->isEmpty() )
585 {
586 PyErr_SetString( PyExc_ValueError, QStringLiteral( "Cannot fill an empty block" ).toUtf8().constData() );
587 sipIsErr = 1;
588 }
589 else
590 {
591 sipCpp->fill( a0 );
592 }
593 % End
594#endif
595
604 QByteArray data() const;
605
614 void setData( const QByteArray &data, int offset = 0 );
615
622 char *bits( int row, int column ) SIP_SKIP;
623
631 char *bits( qgssize index ) SIP_SKIP;
632
639 char *bits() SIP_SKIP;
640
650 const char *constBits( qgssize index ) const SIP_SKIP;
651
659 const char *constBits() const SIP_SKIP;
660
668 static QString printValue( double value, bool localized = false );
669
678 static QString printValue( float value, bool localized = false ) SIP_SKIP;
679
685 bool convert( Qgis::DataType destDataType );
686
690 QImage image() const;
691
696 bool setImage( const QImage *image );
697
699 inline static double readValue( void *data, Qgis::DataType type, qgssize index ) SIP_SKIP;
700
702 inline static void writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP;
703
704 void applyNoDataValues( const QgsRasterRangeList &rangeList );
705
709 void applyScaleOffset( double scale, double offset );
710
712 QgsError error() const { return mError; }
713
715 void setError( const QgsError &error ) { mError = error;}
716
717 QString toString() const;
718
729 static QRect subRect( const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent );
730
735 int width() const SIP_HOLDGIL { return mWidth; }
736
741 int height() const SIP_HOLDGIL { return mHeight; }
742
760 bool minimum( double &minimum SIP_OUT, int &row SIP_OUT, int &column SIP_OUT ) const;
761
779 bool maximum( double &maximum SIP_OUT, int &row SIP_OUT, int &column SIP_OUT ) const;
780
803 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;
804
805 private:
806 static QImage::Format imageFormat( Qgis::DataType dataType );
807 static Qgis::DataType dataType( QImage::Format format );
808
815 static bool isNoDataValue( double value, double noDataValue )
816 {
817 // TODO: optimize no data value test by memcmp()
818 // More precise would be std::isnan(value) && std::isnan(noDataValue(bandNo)), but probably
819 // not important and slower
820 return std::isnan( value ) ||
821 qgsDoubleNear( value, noDataValue );
822 }
823
829 inline bool isNoDataValue( double value ) const;
830
835 bool createNoDataBitmap();
836
846 static void *convert( void *srcData, Qgis::DataType srcDataType, Qgis::DataType destDataType, qgssize size );
847
848 // Valid
849 bool mValid = true;
850
851 // Data type
853
854 // Data type size in bytes, to make bits() fast
855 int mTypeSize = 0;
856
857 // Width
858 int mWidth = 0;
859
860 // Height
861 int mHeight = 0;
862
863 // Has no data value
864 bool mHasNoDataValue = false;
865
866 // No data value
867 double mNoDataValue;
868
869 static const QRgb NO_DATA_COLOR;
870
871 // Data block for numerical data types, not used with image data types
872 // QByteArray does not seem to be intended for large data blocks, does it?
873 void *mData = nullptr;
874
875 // Image for image data types, not used with numerical data types
876 QImage *mImage = nullptr;
877
878 // Bitmap of no data. One bit for each pixel. Bit is 1 if a pixels is no data.
879 // Each row is represented by whole number of bytes (last bits may be unused)
880 // to make processing rows easy.
881 char *mNoDataBitmap = nullptr;
882
883 // number of bytes in mNoDataBitmap row
884 int mNoDataBitmapWidth = 0;
885
886 // total size in bytes of mNoDataBitmap
887 qgssize mNoDataBitmapSize = 0;
888
889 // Error
890 QgsError mError;
891};
892
894{
895 if ( !data )
896 {
897 return std::numeric_limits<double>::quiet_NaN();
898 }
899
900 switch ( type )
901 {
903 return static_cast< double >( ( static_cast< quint8 * >( data ) )[index] );
905 return static_cast< double >( ( static_cast< qint8 * >( data ) )[index] );
907 return static_cast< double >( ( static_cast< quint16 * >( data ) )[index] );
909 return static_cast< double >( ( static_cast< qint16 * >( data ) )[index] );
911 return static_cast< double >( ( static_cast< quint32 * >( data ) )[index] );
913 return static_cast< double >( ( static_cast< qint32 * >( data ) )[index] );
915 return static_cast< double >( ( static_cast< float * >( data ) )[index] );
917 return static_cast< double >( ( static_cast< double * >( data ) )[index] );
925 QgsDebugError( QStringLiteral( "Data type %1 is not supported" ).arg( qgsEnumValueToKey< Qgis::DataType >( type ) ) );
926 break;
927 }
928
929 return std::numeric_limits<double>::quiet_NaN();
930}
931
932inline void QgsRasterBlock::writeValue( void *data, Qgis::DataType type, qgssize index, double value ) SIP_SKIP
933{
934 if ( !data ) return;
935
936 switch ( type )
937 {
939 ( static_cast< quint8 * >( data ) )[index] = static_cast< quint8 >( value );
940 break;
942 ( static_cast< qint8 * >( data ) )[index] = static_cast< qint8 >( value );
943 break;
945 ( static_cast< quint16 * >( data ) )[index] = static_cast< quint16 >( value );
946 break;
948 ( static_cast< qint16 * >( data ) )[index] = static_cast< qint16 >( value );
949 break;
951 ( static_cast< quint32 * >( data ) )[index] = static_cast< quint32 >( value );
952 break;
954 ( static_cast< qint32 * >( data ) )[index] = static_cast< qint32 >( value );
955 break;
957 ( static_cast< float * >( data ) )[index] = static_cast< float >( value );
958 break;
960 ( static_cast< double * >( data ) )[index] = value;
961 break;
969 QgsDebugError( QStringLiteral( "Data type %1 is not supported" ).arg( qgsEnumValueToKey< Qgis::DataType >( type ) ) );
970 break;
971 }
972}
973
974inline double QgsRasterBlock::value( qgssize index ) const SIP_SKIP
975{
976 if ( !mData )
977 {
978 QgsDebugError( QStringLiteral( "Data block not allocated" ) );
979 return std::numeric_limits<double>::quiet_NaN();
980 }
981 return readValue( mData, mDataType, index );
982}
983
984inline double QgsRasterBlock::valueAndNoData( qgssize index, bool &isNoData ) const SIP_SKIP
985{
986 if ( !mData )
987 {
988 QgsDebugError( QStringLiteral( "Data block not allocated" ) );
989 isNoData = true;
990 return std::numeric_limits<double>::quiet_NaN();
991 }
992 if ( index >= static_cast< qgssize >( mWidth )*mHeight )
993 {
994 QgsDebugError( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
995 isNoData = true; // we consider no data if outside
996 return std::numeric_limits<double>::quiet_NaN();
997 }
998
999 const double val = readValue( mData, mDataType, index );
1000
1001 if ( !mHasNoDataValue && !mNoDataBitmap )
1002 {
1003 isNoData = false;
1004 return val;
1005 }
1006
1007 if ( mHasNoDataValue )
1008 {
1009 isNoData = isNoDataValue( val );
1010 return val;
1011 }
1012 // use no data bitmap
1013 if ( !mNoDataBitmap )
1014 {
1015 // no data are not defined
1016 isNoData = false;
1017 return val;
1018 }
1019
1020 // no data is a bitmap
1022 return val;
1023}
1024
1025inline bool QgsRasterBlock::isNoDataValue( double value ) const SIP_SKIP
1026{
1027 return std::isnan( value ) || qgsDoubleNear( value, mNoDataValue );
1028}
1029
1030#endif
1031
1032
DataType
Raster data types.
Definition qgis.h:372
@ CInt32
Complex Int32.
Definition qgis.h:383
@ Float32
Thirty two bit floating point (float).
Definition qgis.h:380
@ CFloat64
Complex Float64.
Definition qgis.h:385
@ Int16
Sixteen bit signed integer (qint16).
Definition qgis.h:377
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition qgis.h:387
@ Int8
Eight bit signed integer (qint8) (added in QGIS 3.30).
Definition qgis.h:375
@ UInt16
Sixteen bit unsigned integer (quint16).
Definition qgis.h:376
@ Byte
Eight bit unsigned integer (quint8).
Definition qgis.h:374
@ UnknownDataType
Unknown or unspecified type.
Definition qgis.h:373
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition qgis.h:386
@ Int32
Thirty two bit signed integer (qint32).
Definition qgis.h:379
@ Float64
Sixty four bit floating point (double).
Definition qgis.h:381
@ CFloat32
Complex Float32.
Definition qgis.h:384
@ CInt16
Complex Int16.
Definition qgis.h:382
@ UInt32
Thirty two bit unsigned integer (quint32).
Definition qgis.h:378
A container for error messages.
Definition qgserror.h:81
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.
static bool typeIsNumeric(Qgis::DataType type)
Returns true if a data type 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.
char * bits(int row, int column)
Returns a pointer to block 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.
QByteArray data() const
Gets access to raw data.
bool setIsNoData(qgssize index)
Set no data on pixel.
bool setValue(qgssize index, double value)
Set value on index (indexed line by line).
double noDataValue() const
Returns no data value.
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.
static bool typeIsComplex(Qgis::DataType type)
Returns true if a data type is a complex number type.
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.
QgsError error() const
Returns the last error.
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.
bool reset(Qgis::DataType dataType, int width, int height)
Reset block.
A rectangle specified with double values.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:6798
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:7142
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6607
#define SIP_SKIP
Definition qgis_sip.h:134
#define SIP_OUT
Definition qgis_sip.h:58
#define SIP_HOLDGIL
Definition qgis_sip.h:179
#define QgsDebugError(str)
Definition qgslogger.h:57
QList< QgsRasterRange > QgsRasterRangeList