QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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 QgsDebugError( 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 QgsDebugError( 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{
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 QgsDebugError( 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 QgsDebugError( 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 QgsDebugError( 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 QgsDebugError( 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 QgsDebugError( QStringLiteral( "Image not allocated" ) );
418 return false;
419 }
420
421 if ( mImage->width() != mWidth || mImage->height() != mHeight )
422 {
423 QgsDebugError( 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 QgsDebugError( 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 QgsDebugError( 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 QgsDebugError( 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 QgsDebugError( 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 //QgsDebugMsgLevel( QStringLiteral("convert %1 type %2 to %3: %4 -> %5").arg(i).arg(srcDataType).arg(destDataType).arg( value ).arg( newValue ), 2 );
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 QgsDebugError( 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 QgsDebugError( 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:269
@ 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.
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)
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 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.
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 xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:201
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:211
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:236
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:196
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:206
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:243
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:5398
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:5747
bool qgsFloatNear(float a, float b, float epsilon=4 *FLT_EPSILON)
Compare two floats (but allow some difference)
Definition: qgis.h:5218
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:5207
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugError(str)
Definition: qgslogger.h:38
QList< QgsRasterRange > QgsRasterRangeList