QGIS API Documentation 3.39.0-Master (47f7b3a4989)
Loading...
Searching...
No Matches
qgsrasterblock.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsrasterblock.cpp - 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#include <limits>
19
20#include <QByteArray>
21#include <QColor>
22#include <QLocale>
23
24#include "qgslogger.h"
25#include "qgsrasterblock.h"
26#include "qgsrectangle.h"
27
28// See #9101 before any change of NODATA_COLOR!
29const QRgb QgsRasterBlock::NO_DATA_COLOR = qRgba( 0, 0, 0, 0 );
30
32 : mNoDataValue( std::numeric_limits<double>::quiet_NaN() )
33{
34}
35
36QgsRasterBlock::QgsRasterBlock( Qgis::DataType dataType, int width, int height )
37 : mDataType( dataType )
38 , mWidth( width )
39 , mHeight( height )
40 , mNoDataValue( std::numeric_limits<double>::quiet_NaN() )
41{
42 ( void )reset( mDataType, mWidth, mHeight );
43}
44
46{
47 QgsDebugMsgLevel( QStringLiteral( "mData = %1" ).arg( reinterpret_cast< quint64 >( mData ) ), 4 );
48 qgsFree( mData );
49 delete mImage;
50 qgsFree( mNoDataBitmap );
51}
52
53bool QgsRasterBlock::reset( Qgis::DataType dataType, int width, int height )
54{
55 QgsDebugMsgLevel( QStringLiteral( "theWidth= %1 height = %2 dataType = %3" ).arg( width ).arg( height ).arg( qgsEnumValueToKey< Qgis::DataType >( dataType ) ), 4 );
56
57 qgsFree( mData );
58 mData = nullptr;
59 delete mImage;
60 mImage = nullptr;
61 qgsFree( mNoDataBitmap );
62 mNoDataBitmap = nullptr;
64 mTypeSize = 0;
65 mWidth = 0;
66 mHeight = 0;
67 mHasNoDataValue = false;
68 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
69 mValid = false;
70
71 if ( typeIsNumeric( dataType ) )
72 {
73 QgsDebugMsgLevel( QStringLiteral( "Numeric type" ), 4 );
74 const qgssize tSize = typeSize( dataType );
75 QgsDebugMsgLevel( QStringLiteral( "allocate %1 bytes" ).arg( tSize * width * height ), 4 );
76 mData = qgsMalloc( tSize * width * height );
77 if ( !mData )
78 {
79 QgsDebugError( QStringLiteral( "Couldn't allocate data memory of %1 bytes" ).arg( tSize * width * height ) );
80 return false;
81 }
82 }
83 else if ( typeIsColor( dataType ) )
84 {
85 QgsDebugMsgLevel( QStringLiteral( "Color type" ), 4 );
86 const QImage::Format format = imageFormat( dataType );
87 mImage = new QImage( width, height, format );
88 }
89 else
90 {
91 QgsDebugError( QStringLiteral( "Wrong data type" ) );
92 return false;
93 }
94
95 mValid = true;
96 mDataType = dataType;
97 mTypeSize = QgsRasterBlock::typeSize( mDataType );
98 mWidth = width;
99 mHeight = height;
100 QgsDebugMsgLevel( QStringLiteral( "mWidth= %1 mHeight = %2 mDataType = %3 mData = %4 mImage = %5" ).arg( mWidth ).arg( mHeight ).arg( static_cast< int>( mDataType ) )
101 .arg( reinterpret_cast< quint64 >( mData ) ).arg( reinterpret_cast< quint64 >( mImage ) ), 4 );
102 return true;
103}
104
105QImage::Format QgsRasterBlock::imageFormat( Qgis::DataType dataType )
106{
108 {
109 return QImage::Format_ARGB32;
110 }
112 {
113 return QImage::Format_ARGB32_Premultiplied;
114 }
115 return QImage::Format_Invalid;
116}
117
118Qgis::DataType QgsRasterBlock::dataType( QImage::Format format )
119{
120 if ( format == QImage::Format_ARGB32 )
121 {
123 }
124 else if ( format == QImage::Format_ARGB32_Premultiplied )
125 {
127 }
129}
130
132{
133 QgsDebugMsgLevel( QStringLiteral( "mWidth= %1 mHeight = %2 mDataType = %3 mData = %4 mImage = %5" ).arg( mWidth ).arg( mHeight ).arg( qgsEnumValueToKey( mDataType ) )
134 .arg( reinterpret_cast< quint64 >( mData ) ).arg( reinterpret_cast< quint64 >( mImage ) ), 4 );
135 return mWidth == 0 || mHeight == 0 ||
136 ( typeIsNumeric( mDataType ) && !mData ) ||
137 ( typeIsColor( mDataType ) && !mImage );
138}
139
141{
142 switch ( dataType )
143 {
156 return true;
157
161 return false;
162 }
163 return false;
164}
165
167{
168 switch ( dataType )
169 {
172 return true;
173
187 return false;
188 }
189 return false;
190}
191
193{
195
196 switch ( dataType )
197 {
200 *noDataValue = -32768.0;
201 newDataType = Qgis::DataType::Int16;
202 break;
204 *noDataValue = -2147483648.0;
205 newDataType = Qgis::DataType::Int32;
206 break;
208 *noDataValue = -2147483648.0;
209 newDataType = Qgis::DataType::Int32;
210 break;
215 *noDataValue = std::numeric_limits<double>::max() * -1.0;
216 newDataType = Qgis::DataType::Float64;
217 break;
225 QgsDebugError( QStringLiteral( "Unknown data type %1" ).arg( static_cast< int >( dataType ) ) );
227 }
228 QgsDebugMsgLevel( QStringLiteral( "newDataType = %1 noDataValue = %2" ).arg( qgsEnumValueToKey< Qgis::DataType >( newDataType ) ).arg( *noDataValue ), 4 );
229 return newDataType;
230}
231
232void QgsRasterBlock::setNoDataValue( double noDataValue )
233{
234 mHasNoDataValue = true;
235 mNoDataValue = noDataValue;
236}
237
239{
240 mHasNoDataValue = false;
241 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
242}
243
245{
246 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
247 if ( typeIsNumeric( mDataType ) )
248 {
249 const size_t dataTypeSize = typeSize( mDataType );
250 if ( mHasNoDataValue )
251 {
252 if ( !mData )
253 {
254 QgsDebugError( QStringLiteral( "Data block not allocated" ) );
255 return false;
256 }
257
258 QgsDebugMsgLevel( QStringLiteral( "set mData to mNoDataValue" ), 4 );
259 QByteArray noDataByteArray = valueBytes( mDataType, mNoDataValue );
260 if ( mNoDataValue == 0 )
261 {
262 memset( mData, 0, dataTypeSize * mWidth * mHeight );
263 }
264 else
265 {
266 const char *nodata = noDataByteArray.data();
267 for ( qgssize i = 0; i < static_cast< qgssize >( mWidth )*mHeight; i++ )
268 {
269 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodata, dataTypeSize );
270 }
271 }
272 }
273 else
274 {
275 // use bitmap
276 if ( !mNoDataBitmap )
277 {
278 if ( !createNoDataBitmap() )
279 {
280 return false;
281 }
282 }
283 QgsDebugMsgLevel( QStringLiteral( "set mNoDataBitmap to 1" ), 4 );
284 memset( mNoDataBitmap, 0xff, mNoDataBitmapSize );
285 if ( mData )
286 {
287 memset( mData, 0, dataTypeSize * mWidth * mHeight );
288 }
289 }
290 return true;
291 }
292 else
293 {
294 // image
295 if ( !mImage )
296 {
297 QgsDebugError( QStringLiteral( "Image not allocated" ) );
298 return false;
299 }
300 QgsDebugMsgLevel( QStringLiteral( "Fill image" ), 4 );
301 mImage->fill( NO_DATA_COLOR );
302 return true;
303 }
304}
305
306bool QgsRasterBlock::setIsNoDataExcept( QRect exceptRect )
307{
308 int top = exceptRect.top();
309 int bottom = exceptRect.bottom();
310 int left = exceptRect.left();
311 int right = exceptRect.right();
312 top = std::min( std::max( top, 0 ), mHeight - 1 );
313 left = std::min( std::max( left, 0 ), mWidth - 1 );
314 bottom = std::max( 0, std::min( bottom, mHeight - 1 ) );
315 right = std::max( 0, std::min( right, mWidth - 1 ) );
316
317 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
318 if ( typeIsNumeric( mDataType ) )
319 {
320 const size_t dataTypeSize = typeSize( mDataType );
321 if ( mHasNoDataValue )
322 {
323 if ( !mData )
324 {
325 QgsDebugError( QStringLiteral( "Data block not allocated" ) );
326 return false;
327 }
328
329 QgsDebugMsgLevel( QStringLiteral( "set mData to mNoDataValue" ), 4 );
330 QByteArray noDataByteArray = valueBytes( mDataType, mNoDataValue );
331
332 char *nodata = noDataByteArray.data();
333 char *nodataRow = new char[mWidth * dataTypeSize]; // full row of no data
334 for ( int c = 0; c < mWidth; c++ )
335 {
336 memcpy( nodataRow + c * dataTypeSize, nodata, dataTypeSize );
337 }
338
339 // top and bottom
340 for ( int r = 0; r < mHeight; r++ )
341 {
342 if ( r >= top && r <= bottom ) continue; // middle
343 const qgssize i = static_cast< qgssize >( r ) * mWidth;
344 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodataRow, dataTypeSize * static_cast< qgssize >( mWidth ) );
345 }
346 // middle
347 for ( int r = top; r <= bottom; r++ )
348 {
349 qgssize i = static_cast< qgssize >( r ) * mWidth;
350 // middle left
351 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodataRow, dataTypeSize * static_cast< qgssize >( left ) );
352 // middle right
353 i += right + 1;
354 const int w = mWidth - right - 1;
355 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodataRow, dataTypeSize * static_cast< qgssize >( w ) );
356 }
357 delete [] nodataRow;
358 }
359 else
360 {
361 // use bitmap
362 if ( !mNoDataBitmap )
363 {
364 if ( !createNoDataBitmap() )
365 {
366 return false;
367 }
368 }
369 QgsDebugMsgLevel( QStringLiteral( "set mNoDataBitmap to 1" ), 4 );
370
371 if ( mData )
372 {
373 memset( mData, 0, dataTypeSize * mWidth * mHeight );
374 }
375
376 char *nodataRow = new char[mNoDataBitmapWidth]; // full row of no data
377 // TODO: we can simply set all bytes to 11111111 (~0) I think
378 memset( nodataRow, 0, mNoDataBitmapWidth );
379 for ( int c = 0; c < mWidth; c ++ )
380 {
381 const int byte = c / 8;
382 const int bit = c % 8;
383 const char nodata = 0x80 >> bit;
384 memset( nodataRow + byte, nodataRow[byte] | nodata, 1 );
385 }
386
387 // top and bottom
388 for ( int r = 0; r < mHeight; r++ )
389 {
390 if ( r >= top && r <= bottom ) continue; // middle
391 const qgssize i = static_cast< qgssize >( r ) * mNoDataBitmapWidth;
392 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
393 }
394 // middle
395 memset( nodataRow, 0, mNoDataBitmapWidth );
396 for ( int c = 0; c < mWidth; c ++ )
397 {
398 if ( c >= left && c <= right ) continue; // middle
399 const int byte = c / 8;
400 const int bit = c % 8;
401 const char nodata = 0x80 >> bit;
402 memset( nodataRow + byte, nodataRow[byte] | nodata, 1 );
403 }
404 for ( int r = top; r <= bottom; r++ )
405 {
406 const qgssize i = static_cast< qgssize >( r ) * mNoDataBitmapWidth;
407 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
408 }
409 delete [] nodataRow;
410 }
411 return true;
412 }
413 else
414 {
415 // image
416 if ( !mImage )
417 {
418 QgsDebugError( QStringLiteral( "Image not allocated" ) );
419 return false;
420 }
421
422 if ( mImage->width() != mWidth || mImage->height() != mHeight )
423 {
424 QgsDebugError( QStringLiteral( "Image and block size differ" ) );
425 return false;
426 }
427
428 QgsDebugMsgLevel( QStringLiteral( "Fill image depth = %1" ).arg( mImage->depth() ), 4 );
429
430 // TODO: support different depths
431 if ( mImage->depth() != 32 )
432 {
433 QgsDebugError( QStringLiteral( "Unsupported image depth" ) );
434 return false;
435 }
436
437 const QRgb nodataRgba = NO_DATA_COLOR;
438 QRgb *nodataRow = new QRgb[mWidth]; // full row of no data
439 const int rgbSize = sizeof( QRgb );
440 for ( int c = 0; c < mWidth; c ++ )
441 {
442 nodataRow[c] = nodataRgba;
443 }
444
445 // top and bottom
446 for ( int r = 0; r < mHeight; r++ )
447 {
448 if ( r >= top && r <= bottom ) continue; // middle
449 const qgssize i = static_cast< qgssize >( r ) * mWidth;
450 memcpy( reinterpret_cast< void * >( mImage->bits() + rgbSize * i ), nodataRow, rgbSize * static_cast< qgssize >( mWidth ) );
451 }
452 // middle
453 for ( int r = top; r <= bottom; r++ )
454 {
455 qgssize i = static_cast< qgssize >( r ) * mWidth;
456 // middle left
457 if ( left > 0 )
458 {
459 memcpy( reinterpret_cast< void * >( mImage->bits() + rgbSize * i ), nodataRow, rgbSize * static_cast< qgssize >( left - 1 ) );
460 }
461 // middle right
462 i += right + 1;
463 const int w = mWidth - right - 1;
464 memcpy( reinterpret_cast< void * >( mImage->bits() + rgbSize * i ), nodataRow, rgbSize * static_cast< qgssize >( w ) );
465 }
466 delete [] nodataRow;
467 return true;
468 }
469}
470
471QByteArray QgsRasterBlock::data() const
472{
473 if ( mData )
474 return QByteArray::fromRawData( static_cast<const char *>( mData ), typeSize( mDataType ) * mWidth * mHeight );
475 else if ( mImage && mImage->constBits() )
476 return QByteArray::fromRawData( reinterpret_cast<const char *>( mImage->constBits() ), mImage->sizeInBytes() );
477 else
478 return QByteArray();
479}
480
481void QgsRasterBlock::setData( const QByteArray &data, int offset )
482{
483 if ( offset < 0 )
484 return; // negative offsets not allowed
485
486 if ( mData )
487 {
488 const int len = std::min( static_cast<int>( data.size() ), typeSize( mDataType ) * mWidth * mHeight - offset );
489 ::memcpy( static_cast<char *>( mData ) + offset, data.constData(), len );
490 }
491 else if ( mImage && mImage->constBits() )
492 {
493 const qsizetype len = std::min( static_cast< qsizetype >( data.size() ), mImage->sizeInBytes() - offset );
494 ::memcpy( mImage->bits() + offset, data.constData(), len );
495 }
496}
497
499{
500 // Not testing type to avoid too much overhead because this method is called per pixel
501 if ( index >= static_cast< qgssize >( mWidth )*mHeight )
502 {
503 QgsDebugMsgLevel( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ), 4 );
504 return nullptr;
505 }
506 if ( mData )
507 {
508 return reinterpret_cast< char * >( mData ) + index * mTypeSize;
509 }
510 if ( mImage )
511 {
512 if ( uchar *data = mImage->bits() )
513 {
514 return reinterpret_cast< char * >( data + index * 4 );
515 }
516 }
517
518 return nullptr;
519}
520
521const char *QgsRasterBlock::constBits( qgssize index ) const
522{
523 // Not testing type to avoid too much overhead because this method is called per pixel
524 if ( index >= static_cast< qgssize >( mWidth )*mHeight )
525 {
526 QgsDebugMsgLevel( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ), 4 );
527 return nullptr;
528 }
529 if ( mData )
530 {
531 return reinterpret_cast< const char * >( mData ) + index * mTypeSize;
532 }
533 if ( mImage )
534 {
535 if ( const uchar *data = mImage->constBits() )
536 {
537 return reinterpret_cast< const char * >( data + index * 4 );
538 }
539 }
540
541 return nullptr;
542}
543
544char *QgsRasterBlock::bits( int row, int column )
545{
546 return bits( static_cast< qgssize >( row ) * mWidth + column );
547}
548
550{
551 if ( mData )
552 {
553 return reinterpret_cast< char * >( mData );
554 }
555 if ( mImage )
556 {
557 if ( uchar *data = mImage->bits() )
558 {
559 return reinterpret_cast< char * >( data );
560 }
561 }
562
563 return nullptr;
564}
565
566const char *QgsRasterBlock::constBits() const
567{
568 if ( mData )
569 {
570 return reinterpret_cast< const char * >( mData );
571 }
572 if ( mImage )
573 {
574 if ( const uchar *data = mImage->constBits() )
575 {
576 return reinterpret_cast< const char * >( data );
577 }
578 }
579
580 return nullptr;
581}
582
584{
585 if ( isEmpty() ) return false;
586 if ( destDataType == mDataType ) return true;
587
588 if ( typeIsNumeric( mDataType ) && typeIsNumeric( destDataType ) )
589 {
590 void *data = convert( mData, mDataType, destDataType, static_cast< qgssize >( mWidth ) * static_cast< qgssize >( mHeight ) );
591
592 if ( !data )
593 {
594 QgsDebugError( QStringLiteral( "Cannot convert raster block" ) );
595 return false;
596 }
597 qgsFree( mData );
598 mData = data;
599 mDataType = destDataType;
600 mTypeSize = typeSize( mDataType );
601 }
602 else if ( typeIsColor( mDataType ) && typeIsColor( destDataType ) )
603 {
604 const QImage::Format format = imageFormat( destDataType );
605 const QImage image = mImage->convertToFormat( format );
606 *mImage = image;
607 mDataType = destDataType;
608 mTypeSize = typeSize( mDataType );
609 }
610 else
611 {
612 return false;
613 }
614
615 return true;
616}
617
618void QgsRasterBlock::applyScaleOffset( double scale, double offset )
619{
620 if ( isEmpty() ) return;
621 if ( !typeIsNumeric( mDataType ) ) return;
622 if ( scale == 1.0 && offset == 0.0 ) return;
623
624 const qgssize size = static_cast< qgssize >( mWidth ) * mHeight;
625 for ( qgssize i = 0; i < size; ++i )
626 {
627 if ( !isNoData( i ) ) setValue( i, value( i ) * scale + offset );
628 }
629}
630
632{
633 if ( rangeList.isEmpty() )
634 {
635 return;
636 }
637
638 const qgssize size = static_cast< qgssize >( mWidth ) * static_cast< qgssize >( mHeight );
639 for ( qgssize i = 0; i < size; ++i )
640 {
641 const double val = value( i );
642 if ( QgsRasterRange::contains( val, rangeList ) )
643 {
644 //setValue( i, mNoDataValue );
645 setIsNoData( i );
646 }
647 }
648}
649
651{
652 if ( mImage )
653 {
654 return QImage( *mImage );
655 }
656 return QImage();
657}
658
659bool QgsRasterBlock::setImage( const QImage *image )
660{
661 qgsFree( mData );
662 mData = nullptr;
663 delete mImage;
664 mImage = nullptr;
665 mImage = new QImage( *image );
666 mWidth = mImage->width();
667 mHeight = mImage->height();
668 mDataType = dataType( mImage->format() );
669 mTypeSize = QgsRasterBlock::typeSize( mDataType );
670 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
671 return true;
672}
673
674QString QgsRasterBlock::printValue( double value, bool localized )
675{
676 /*
677 * IEEE 754 double has 15-17 significant digits. It specifies:
678 *
679 * "If a decimal string with at most 15 significant decimal is converted to
680 * IEEE 754 double precision and then converted back to the same number of
681 * significant decimal, then the final string should match the original;
682 * and if an IEEE 754 double precision is converted to a decimal string with at
683 * least 17 significant decimal and then converted back to double, then the final
684 * number must match the original."
685 *
686 * If printing only 15 digits, some precision could be lost. Printing 17 digits may
687 * add some confusing digits.
688 *
689 * Default 'g' precision on linux is 6 digits, not all significant digits like
690 * some sprintf manuals say.
691 *
692 * We need to ensure that the number printed and used in QLineEdit or XML will
693 * give the same number when parsed.
694 *
695 * Is there a better solution?
696 */
697
698 QString s;
699
700 for ( int i = 15; i <= 17; i++ )
701 {
702 s.setNum( value, 'g', i );
703 const double doubleValue { s.toDouble( ) };
704 if ( qgsDoubleNear( doubleValue, value ) )
705 {
706 if ( localized )
707 {
708 return QLocale().toString( doubleValue, 'g', i );
709 }
710 return s;
711 }
712 }
713 // Should not happen
714 QgsDebugError( QStringLiteral( "Cannot correctly parse printed value" ) );
715 return s;
716}
717
718QString QgsRasterBlock::printValue( float value, bool localized )
719{
720 /*
721 * IEEE 754 double has 6-9 significant digits. See printValue(double)
722 */
723
724 QString s;
725
726 for ( int i = 6; i <= 9; i++ )
727 {
728 s.setNum( value, 'g', i );
729 const float floatValue { s.toFloat() };
730 if ( qgsFloatNear( floatValue, value ) )
731 {
732 if ( localized )
733 {
734 return QLocale().toString( floatValue, 'g', i );
735 }
736 return s;
737 }
738 }
739 // Should not happen
740 QgsDebugError( QStringLiteral( "Cannot correctly parse printed value" ) );
741 return s;
742}
743
744void *QgsRasterBlock::convert( void *srcData, Qgis::DataType srcDataType, Qgis::DataType destDataType, qgssize size )
745{
746 const int destDataTypeSize = typeSize( destDataType );
747 void *destData = qgsMalloc( destDataTypeSize * size );
748 for ( qgssize i = 0; i < size; i++ )
749 {
750 const double value = readValue( srcData, srcDataType, i );
751 writeValue( destData, destDataType, i, value );
752 //double newValue = readValue( destData, destDataType, i );
753 //QgsDebugMsgLevel( QStringLiteral("convert %1 type %2 to %3: %4 -> %5").arg(i).arg(srcDataType).arg(destDataType).arg( value ).arg( newValue ), 2 );
754 }
755 return destData;
756}
757
758QByteArray QgsRasterBlock::valueBytes( Qgis::DataType dataType, double value )
759{
761 QByteArray ba;
762 ba.resize( static_cast< int >( size ) );
763 char *data = ba.data();
764 quint8 uc;
765 quint16 us;
766 qint16 s;
767 quint32 ui;
768 qint32 i;
769 float f;
770 double d;
771 switch ( dataType )
772 {
774 uc = static_cast< quint8 >( value );
775 memcpy( data, &uc, size );
776 break;
778 {
779 const qint8 myint8 = static_cast< qint8 >( value );
780 memcpy( data, &myint8, size );
781 break;
782 }
784 us = static_cast< quint16 >( value );
785 memcpy( data, &us, size );
786 break;
788 s = static_cast< qint16 >( value );
789 memcpy( data, &s, size );
790 break;
792 ui = static_cast< quint32 >( value );
793 memcpy( data, &ui, size );
794 break;
796 i = static_cast< qint32 >( value );
797 memcpy( data, &i, size );
798 break;
800 f = static_cast< float >( value );
801 memcpy( data, &f, size );
802 break;
804 d = static_cast< double >( value );
805 memcpy( data, &d, size );
806 break;
814 QgsDebugError( QStringLiteral( "Data type is not supported" ) );
815 }
816 return ba;
817}
818
819bool QgsRasterBlock::createNoDataBitmap()
820{
821 mNoDataBitmapWidth = mWidth / 8 + 1;
822 mNoDataBitmapSize = static_cast< qgssize >( mNoDataBitmapWidth ) * mHeight;
823 QgsDebugMsgLevel( QStringLiteral( "allocate %1 bytes" ).arg( mNoDataBitmapSize ), 4 );
824 mNoDataBitmap = reinterpret_cast< char * >( qgsMalloc( mNoDataBitmapSize ) );
825 if ( !mNoDataBitmap )
826 {
827 QgsDebugError( QStringLiteral( "Couldn't allocate no data memory of %1 bytes" ).arg( mNoDataBitmapSize ) );
828 return false;
829 }
830 memset( mNoDataBitmap, 0, mNoDataBitmapSize );
831 return true;
832}
833
835{
836 return QStringLiteral( "dataType = %1 width = %2 height = %3" )
837 .arg( qgsEnumValueToKey< Qgis::DataType >( mDataType ) ).arg( mWidth ).arg( mHeight );
838}
839
840QRect QgsRasterBlock::subRect( const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent )
841{
842 QgsDebugMsgLevel( "theExtent = " + extent.toString(), 4 );
843 QgsDebugMsgLevel( "theSubExtent = " + subExtent.toString(), 4 );
844 const double xRes = extent.width() / width;
845 const double yRes = extent.height() / height;
846
847 QgsDebugMsgLevel( QStringLiteral( "theWidth = %1 height = %2 xRes = %3 yRes = %4" ).arg( width ).arg( height ).arg( xRes ).arg( yRes ), 4 );
848
849 int top = 0;
850 int bottom = height - 1;
851 int left = 0;
852 int right = width - 1;
853
854 if ( subExtent.yMaximum() < extent.yMaximum() )
855 {
856 top = std::round( ( extent.yMaximum() - subExtent.yMaximum() ) / yRes );
857 }
858 if ( subExtent.yMinimum() > extent.yMinimum() )
859 {
860 bottom = std::round( ( extent.yMaximum() - subExtent.yMinimum() ) / yRes ) - 1;
861 }
862
863 if ( subExtent.xMinimum() > extent.xMinimum() )
864 {
865 left = std::round( ( subExtent.xMinimum() - extent.xMinimum() ) / xRes );
866 }
867 if ( subExtent.xMaximum() < extent.xMaximum() )
868 {
869 right = std::round( ( subExtent.xMaximum() - extent.xMinimum() ) / xRes ) - 1;
870 }
871 QRect subRect = QRect( left, top, right - left + 1, bottom - top + 1 );
872 QgsDebugMsgLevel( QStringLiteral( "subRect: %1 %2 %3 %4" ).arg( subRect.x() ).arg( subRect.y() ).arg( subRect.width() ).arg( subRect.height() ), 4 );
873 return subRect;
874}
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)
bool isEmpty() const
Returns true if block is empty, i.e.
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 data type is numeric.
int height() const
Returns the height (number of rows) of the raster block.
bool convert(Qgis::DataType destDataType)
Convert data to different type.
bool setIsNoData()
Set the whole block to no data.
void resetNoDataValue()
Reset no data value: if there was a no data value previously set, it will be discarded.
int dataTypeSize() const
Data type size in bytes.
QString toString() const
static int typeSize(Qgis::DataType dataType)
Returns the size in bytes for the specified dataType.
bool setIsNoDataExcept(QRect exceptRect)
Set the whole block to no data except specified rectangle.
bool setImage(const QImage *image)
Sets the block data via an image.
QByteArray data() const
Gets access to raw data.
double noDataValue() const
Returns no data value.
const char * constBits() const
Returns a const pointer to block data.
void setData(const QByteArray &data, int offset=0)
Rewrite raw pixel data.
void applyNoDataValues(const QgsRasterRangeList &rangeList)
bool setValue(int row, int column, double value)
Set value on position.
bool isNoData(int row, int column) const
Checks if value at position is no data.
Qgis::DataType dataType() const
Returns data type.
char * bits()
Returns a pointer to block data.
static Qgis::DataType typeWithNoDataValue(Qgis::DataType dataType, double *noDataValue)
For given data type returns wider type and sets no data value.
QImage image() const
Returns an image containing the block data, if the block's data type is color.
void setNoDataValue(double noDataValue)
Sets cell value that will be considered as "no data".
virtual ~QgsRasterBlock()
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 applyScaleOffset(double scale, double offset)
Apply band scale and offset to raster block values.
static QString printValue(double value, bool localized=false)
Print double value with all necessary significant digits.
static QRect subRect(const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent)
For extent and width, height find rectangle covered by subextent.
static bool typeIsColor(Qgis::DataType type)
Returns true if data type is color.
static double readValue(void *data, Qgis::DataType type, qgssize index)
static QByteArray valueBytes(Qgis::DataType dataType, double value)
Gets byte array representing a value.
bool reset(Qgis::DataType dataType, int width, int height)
Reset block.
bool contains(double value) const
Returns true if this range contains the specified value.
A rectangle specified with double values.
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double width() const
Returns the width of the rectangle.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
double height() const
Returns the height of the rectangle.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
void * qgsMalloc(size_t size)
Allocates size bytes and returns a pointer to the allocated memory.
Definition qgis.cpp:93
void qgsFree(void *ptr)
Frees the memory space pointed to by ptr.
Definition qgis.cpp:115
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:5656
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 qgsFloatNear(float a, float b, float epsilon=4 *FLT_EPSILON)
Compare two floats (but allow some difference)
Definition qgis.h:5476
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 QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39
#define QgsDebugError(str)
Definition qgslogger.h:38
QList< QgsRasterRange > QgsRasterRangeList