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