QGIS API Documentation 3.27.0-Master (c6eca784ad)
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 {
154 return true;
155
159 return false;
160 }
161 return false;
162}
163
165{
166 switch ( dataType )
167 {
170 return true;
171
184 return false;
185 }
186 return false;
187}
188
190{
191 Qgis::DataType newDataType;
192
193 switch ( dataType )
194 {
196 *noDataValue = -32768.0;
197 newDataType = Qgis::DataType::Int16;
198 break;
200 *noDataValue = -2147483648.0;
201 newDataType = Qgis::DataType::Int32;
202 break;
204 *noDataValue = -2147483648.0;
205 newDataType = Qgis::DataType::Int32;
206 break;
211 *noDataValue = std::numeric_limits<double>::max() * -1.0;
212 newDataType = Qgis::DataType::Float64;
213 break;
214 default:
215 QgsDebugMsg( QStringLiteral( "Unknown data type %1" ).arg( static_cast< int >( dataType ) ) );
217 }
218 QgsDebugMsgLevel( QStringLiteral( "newDataType = %1 noDataValue = %2" ).arg( qgsEnumValueToKey< Qgis::DataType >( newDataType ) ).arg( *noDataValue ), 4 );
219 return newDataType;
220}
221
222void QgsRasterBlock::setNoDataValue( double noDataValue )
223{
224 mHasNoDataValue = true;
225 mNoDataValue = noDataValue;
226}
227
229{
230 mHasNoDataValue = false;
231 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
232}
233
235{
236 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
237 if ( typeIsNumeric( mDataType ) )
238 {
239 const size_t dataTypeSize = typeSize( mDataType );
240 if ( mHasNoDataValue )
241 {
242 if ( !mData )
243 {
244 QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
245 return false;
246 }
247
248 QgsDebugMsgLevel( QStringLiteral( "set mData to mNoDataValue" ), 4 );
249 QByteArray noDataByteArray = valueBytes( mDataType, mNoDataValue );
250 if ( mNoDataValue == 0 )
251 {
252 memset( mData, 0, dataTypeSize * mWidth * mHeight );
253 }
254 else
255 {
256 const char *nodata = noDataByteArray.data();
257 for ( qgssize i = 0; i < static_cast< qgssize >( mWidth )*mHeight; i++ )
258 {
259 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodata, dataTypeSize );
260 }
261 }
262 }
263 else
264 {
265 // use bitmap
266 if ( !mNoDataBitmap )
267 {
268 if ( !createNoDataBitmap() )
269 {
270 return false;
271 }
272 }
273 QgsDebugMsgLevel( QStringLiteral( "set mNoDataBitmap to 1" ), 4 );
274 memset( mNoDataBitmap, 0xff, mNoDataBitmapSize );
275 if ( mData )
276 {
277 memset( mData, 0, dataTypeSize * mWidth * mHeight );
278 }
279 }
280 return true;
281 }
282 else
283 {
284 // image
285 if ( !mImage )
286 {
287 QgsDebugMsg( QStringLiteral( "Image not allocated" ) );
288 return false;
289 }
290 QgsDebugMsgLevel( QStringLiteral( "Fill image" ), 4 );
291 mImage->fill( NO_DATA_COLOR );
292 return true;
293 }
294}
295
296bool QgsRasterBlock::setIsNoDataExcept( QRect exceptRect )
297{
298 int top = exceptRect.top();
299 int bottom = exceptRect.bottom();
300 int left = exceptRect.left();
301 int right = exceptRect.right();
302 top = std::min( std::max( top, 0 ), mHeight - 1 );
303 left = std::min( std::max( left, 0 ), mWidth - 1 );
304 bottom = std::max( 0, std::min( bottom, mHeight - 1 ) );
305 right = std::max( 0, std::min( right, mWidth - 1 ) );
306
307 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
308 if ( typeIsNumeric( mDataType ) )
309 {
310 const size_t dataTypeSize = typeSize( mDataType );
311 if ( mHasNoDataValue )
312 {
313 if ( !mData )
314 {
315 QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
316 return false;
317 }
318
319 QgsDebugMsgLevel( QStringLiteral( "set mData to mNoDataValue" ), 4 );
320 QByteArray noDataByteArray = valueBytes( mDataType, mNoDataValue );
321
322 char *nodata = noDataByteArray.data();
323 char *nodataRow = new char[mWidth * dataTypeSize]; // full row of no data
324 for ( int c = 0; c < mWidth; c++ )
325 {
326 memcpy( nodataRow + c * dataTypeSize, nodata, dataTypeSize );
327 }
328
329 // top and bottom
330 for ( int r = 0; r < mHeight; r++ )
331 {
332 if ( r >= top && r <= bottom ) continue; // middle
333 const qgssize i = static_cast< qgssize >( r ) * mWidth;
334 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodataRow, dataTypeSize * static_cast< qgssize >( mWidth ) );
335 }
336 // middle
337 for ( int r = top; r <= bottom; r++ )
338 {
339 qgssize i = static_cast< qgssize >( r ) * mWidth;
340 // middle left
341 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodataRow, dataTypeSize * static_cast< qgssize >( left ) );
342 // middle right
343 i += right + 1;
344 const int w = mWidth - right - 1;
345 memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodataRow, dataTypeSize * static_cast< qgssize >( w ) );
346 }
347 delete [] nodataRow;
348 }
349 else
350 {
351 // use bitmap
352 if ( !mNoDataBitmap )
353 {
354 if ( !createNoDataBitmap() )
355 {
356 return false;
357 }
358 }
359 QgsDebugMsgLevel( QStringLiteral( "set mNoDataBitmap to 1" ), 4 );
360
361 if ( mData )
362 {
363 memset( mData, 0, dataTypeSize * mWidth * mHeight );
364 }
365
366 char *nodataRow = new char[mNoDataBitmapWidth]; // full row of no data
367 // TODO: we can simply set all bytes to 11111111 (~0) I think
368 memset( nodataRow, 0, mNoDataBitmapWidth );
369 for ( int c = 0; c < mWidth; c ++ )
370 {
371 const int byte = c / 8;
372 const int bit = c % 8;
373 const char nodata = 0x80 >> bit;
374 memset( nodataRow + byte, nodataRow[byte] | nodata, 1 );
375 }
376
377 // top and bottom
378 for ( int r = 0; r < mHeight; r++ )
379 {
380 if ( r >= top && r <= bottom ) continue; // middle
381 const qgssize i = static_cast< qgssize >( r ) * mNoDataBitmapWidth;
382 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
383 }
384 // middle
385 memset( nodataRow, 0, mNoDataBitmapWidth );
386 for ( int c = 0; c < mWidth; c ++ )
387 {
388 if ( c >= left && c <= right ) continue; // middle
389 const int byte = c / 8;
390 const int bit = c % 8;
391 const char nodata = 0x80 >> bit;
392 memset( nodataRow + byte, nodataRow[byte] | nodata, 1 );
393 }
394 for ( int r = top; r <= bottom; r++ )
395 {
396 const qgssize i = static_cast< qgssize >( r ) * mNoDataBitmapWidth;
397 memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
398 }
399 delete [] nodataRow;
400 }
401 return true;
402 }
403 else
404 {
405 // image
406 if ( !mImage )
407 {
408 QgsDebugMsg( QStringLiteral( "Image not allocated" ) );
409 return false;
410 }
411
412 if ( mImage->width() != mWidth || mImage->height() != mHeight )
413 {
414 QgsDebugMsg( QStringLiteral( "Image and block size differ" ) );
415 return false;
416 }
417
418 QgsDebugMsgLevel( QStringLiteral( "Fill image depth = %1" ).arg( mImage->depth() ), 4 );
419
420 // TODO: support different depths
421 if ( mImage->depth() != 32 )
422 {
423 QgsDebugMsg( QStringLiteral( "Unsupported image depth" ) );
424 return false;
425 }
426
427 const QRgb nodataRgba = NO_DATA_COLOR;
428 QRgb *nodataRow = new QRgb[mWidth]; // full row of no data
429 const int rgbSize = sizeof( QRgb );
430 for ( int c = 0; c < mWidth; c ++ )
431 {
432 nodataRow[c] = nodataRgba;
433 }
434
435 // top and bottom
436 for ( int r = 0; r < mHeight; r++ )
437 {
438 if ( r >= top && r <= bottom ) continue; // middle
439 const qgssize i = static_cast< qgssize >( r ) * mWidth;
440 memcpy( reinterpret_cast< void * >( mImage->bits() + rgbSize * i ), nodataRow, rgbSize * static_cast< qgssize >( mWidth ) );
441 }
442 // middle
443 for ( int r = top; r <= bottom; r++ )
444 {
445 qgssize i = static_cast< qgssize >( r ) * mWidth;
446 // middle left
447 if ( left > 0 )
448 {
449 memcpy( reinterpret_cast< void * >( mImage->bits() + rgbSize * i ), nodataRow, rgbSize * static_cast< qgssize >( left - 1 ) );
450 }
451 // middle right
452 i += right + 1;
453 const int w = mWidth - right - 1;
454 memcpy( reinterpret_cast< void * >( mImage->bits() + rgbSize * i ), nodataRow, rgbSize * static_cast< qgssize >( w ) );
455 }
456 delete [] nodataRow;
457 return true;
458 }
459}
460
461QByteArray QgsRasterBlock::data() const
462{
463 if ( mData )
464 return QByteArray::fromRawData( static_cast<const char *>( mData ), typeSize( mDataType ) * mWidth * mHeight );
465 else if ( mImage && mImage->constBits() )
466 return QByteArray::fromRawData( reinterpret_cast<const char *>( mImage->constBits() ), mImage->sizeInBytes() );
467 else
468 return QByteArray();
469}
470
471void QgsRasterBlock::setData( const QByteArray &data, int offset )
472{
473 if ( offset < 0 )
474 return; // negative offsets not allowed
475
476 if ( mData )
477 {
478 const int len = std::min( static_cast<int>( data.size() ), typeSize( mDataType ) * mWidth * mHeight - offset );
479 ::memcpy( static_cast<char *>( mData ) + offset, data.constData(), len );
480 }
481 else if ( mImage && mImage->constBits() )
482 {
483 const qsizetype len = std::min( static_cast< qsizetype >( data.size() ), mImage->sizeInBytes() - offset );
484 ::memcpy( mImage->bits() + offset, data.constData(), len );
485 }
486}
487
489{
490 // Not testing type to avoid too much overhead because this method is called per pixel
491 if ( index >= static_cast< qgssize >( mWidth )*mHeight )
492 {
493 QgsDebugMsgLevel( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ), 4 );
494 return nullptr;
495 }
496 if ( mData )
497 {
498 return reinterpret_cast< char * >( mData ) + index * mTypeSize;
499 }
500 if ( mImage && mImage->bits() )
501 {
502 return reinterpret_cast< char * >( mImage->bits() + index * 4 );
503 }
504
505 return nullptr;
506}
507
508char *QgsRasterBlock::bits( int row, int column )
509{
510 return bits( static_cast< qgssize >( row ) * mWidth + column );
511}
512
514{
515 if ( mData )
516 {
517 return reinterpret_cast< char * >( mData );
518 }
519 if ( mImage && mImage->bits() )
520 {
521 return reinterpret_cast< char * >( mImage->bits() );
522 }
523
524 return nullptr;
525}
526
528{
529 if ( isEmpty() ) return false;
530 if ( destDataType == mDataType ) return true;
531
532 if ( typeIsNumeric( mDataType ) && typeIsNumeric( destDataType ) )
533 {
534 void *data = convert( mData, mDataType, destDataType, static_cast< qgssize >( mWidth ) * static_cast< qgssize >( mHeight ) );
535
536 if ( !data )
537 {
538 QgsDebugMsg( QStringLiteral( "Cannot convert raster block" ) );
539 return false;
540 }
541 qgsFree( mData );
542 mData = data;
543 mDataType = destDataType;
544 mTypeSize = typeSize( mDataType );
545 }
546 else if ( typeIsColor( mDataType ) && typeIsColor( destDataType ) )
547 {
548 const QImage::Format format = imageFormat( destDataType );
549 const QImage image = mImage->convertToFormat( format );
550 *mImage = image;
551 mDataType = destDataType;
552 mTypeSize = typeSize( mDataType );
553 }
554 else
555 {
556 return false;
557 }
558
559 return true;
560}
561
562void QgsRasterBlock::applyScaleOffset( double scale, double offset )
563{
564 if ( isEmpty() ) return;
565 if ( !typeIsNumeric( mDataType ) ) return;
566 if ( scale == 1.0 && offset == 0.0 ) return;
567
568 const qgssize size = static_cast< qgssize >( mWidth ) * mHeight;
569 for ( qgssize i = 0; i < size; ++i )
570 {
571 if ( !isNoData( i ) ) setValue( i, value( i ) * scale + offset );
572 }
573}
574
576{
577 if ( rangeList.isEmpty() )
578 {
579 return;
580 }
581
582 const qgssize size = static_cast< qgssize >( mWidth ) * static_cast< qgssize >( mHeight );
583 for ( qgssize i = 0; i < size; ++i )
584 {
585 const double val = value( i );
586 if ( QgsRasterRange::contains( val, rangeList ) )
587 {
588 //setValue( i, mNoDataValue );
589 setIsNoData( i );
590 }
591 }
592}
593
595{
596 if ( mImage )
597 {
598 return QImage( *mImage );
599 }
600 return QImage();
601}
602
603bool QgsRasterBlock::setImage( const QImage *image )
604{
605 qgsFree( mData );
606 mData = nullptr;
607 delete mImage;
608 mImage = nullptr;
609 mImage = new QImage( *image );
610 mWidth = mImage->width();
611 mHeight = mImage->height();
612 mDataType = dataType( mImage->format() );
613 mTypeSize = QgsRasterBlock::typeSize( mDataType );
614 mNoDataValue = std::numeric_limits<double>::quiet_NaN();
615 return true;
616}
617
618QString QgsRasterBlock::printValue( double value )
619{
620 /*
621 * IEEE 754 double has 15-17 significant digits. It specifies:
622 *
623 * "If a decimal string with at most 15 significant decimal is converted to
624 * IEEE 754 double precision and then converted back to the same number of
625 * significant decimal, then the final string should match the original;
626 * and if an IEEE 754 double precision is converted to a decimal string with at
627 * least 17 significant decimal and then converted back to double, then the final
628 * number must match the original."
629 *
630 * If printing only 15 digits, some precision could be lost. Printing 17 digits may
631 * add some confusing digits.
632 *
633 * Default 'g' precision on linux is 6 digits, not all significant digits like
634 * some sprintf manuals say.
635 *
636 * We need to ensure that the number printed and used in QLineEdit or XML will
637 * give the same number when parsed.
638 *
639 * Is there a better solution?
640 */
641
642 QString s;
643
644 for ( int i = 15; i <= 17; i++ )
645 {
646 s.setNum( value, 'g', i );
647 if ( qgsDoubleNear( s.toDouble(), value ) )
648 {
649 return s;
650 }
651 }
652 // Should not happen
653 QgsDebugMsg( QStringLiteral( "Cannot correctly parse printed value" ) );
654 return s;
655}
656
657QString QgsRasterBlock::printValue( float value )
658{
659 /*
660 * IEEE 754 double has 6-9 significant digits. See printValue(double)
661 */
662
663 QString s;
664
665 for ( int i = 6; i <= 9; i++ )
666 {
667 s.setNum( value, 'g', i );
668 if ( qgsFloatNear( s.toFloat(), value ) )
669 {
670 return s;
671 }
672 }
673 // Should not happen
674 QgsDebugMsg( QStringLiteral( "Cannot correctly parse printed value" ) );
675 return s;
676}
677
678void *QgsRasterBlock::convert( void *srcData, Qgis::DataType srcDataType, Qgis::DataType destDataType, qgssize size )
679{
680 const int destDataTypeSize = typeSize( destDataType );
681 void *destData = qgsMalloc( destDataTypeSize * size );
682 for ( qgssize i = 0; i < size; i++ )
683 {
684 const double value = readValue( srcData, srcDataType, i );
685 writeValue( destData, destDataType, i, value );
686 //double newValue = readValue( destData, destDataType, i );
687 //QgsDebugMsg( QStringLiteral("convert %1 type %2 to %3: %4 -> %5").arg(i).arg(srcDataType).arg(destDataType).arg( value ).arg( newValue ) );
688 }
689 return destData;
690}
691
692QByteArray QgsRasterBlock::valueBytes( Qgis::DataType dataType, double value )
693{
695 QByteArray ba;
696 ba.resize( static_cast< int >( size ) );
697 char *data = ba.data();
698 quint8 uc;
699 quint16 us;
700 qint16 s;
701 quint32 ui;
702 qint32 i;
703 float f;
704 double d;
705 switch ( dataType )
706 {
708 uc = static_cast< quint8 >( value );
709 memcpy( data, &uc, size );
710 break;
712 us = static_cast< quint16 >( value );
713 memcpy( data, &us, size );
714 break;
716 s = static_cast< qint16 >( value );
717 memcpy( data, &s, size );
718 break;
720 ui = static_cast< quint32 >( value );
721 memcpy( data, &ui, size );
722 break;
724 i = static_cast< qint32 >( value );
725 memcpy( data, &i, size );
726 break;
728 f = static_cast< float >( value );
729 memcpy( data, &f, size );
730 break;
732 d = static_cast< double >( value );
733 memcpy( data, &d, size );
734 break;
735 default:
736 QgsDebugMsg( QStringLiteral( "Data type is not supported" ) );
737 }
738 return ba;
739}
740
741bool QgsRasterBlock::createNoDataBitmap()
742{
743 mNoDataBitmapWidth = mWidth / 8 + 1;
744 mNoDataBitmapSize = static_cast< qgssize >( mNoDataBitmapWidth ) * mHeight;
745 QgsDebugMsgLevel( QStringLiteral( "allocate %1 bytes" ).arg( mNoDataBitmapSize ), 4 );
746 mNoDataBitmap = reinterpret_cast< char * >( qgsMalloc( mNoDataBitmapSize ) );
747 if ( !mNoDataBitmap )
748 {
749 QgsDebugMsg( QStringLiteral( "Couldn't allocate no data memory of %1 bytes" ).arg( mNoDataBitmapSize ) );
750 return false;
751 }
752 memset( mNoDataBitmap, 0, mNoDataBitmapSize );
753 return true;
754}
755
757{
758 return QStringLiteral( "dataType = %1 width = %2 height = %3" )
759 .arg( qgsEnumValueToKey< Qgis::DataType >( mDataType ) ).arg( mWidth ).arg( mHeight );
760}
761
762QRect QgsRasterBlock::subRect( const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent )
763{
764 QgsDebugMsgLevel( "theExtent = " + extent.toString(), 4 );
765 QgsDebugMsgLevel( "theSubExtent = " + subExtent.toString(), 4 );
766 const double xRes = extent.width() / width;
767 const double yRes = extent.height() / height;
768
769 QgsDebugMsgLevel( QStringLiteral( "theWidth = %1 height = %2 xRes = %3 yRes = %4" ).arg( width ).arg( height ).arg( xRes ).arg( yRes ), 4 );
770
771 int top = 0;
772 int bottom = height - 1;
773 int left = 0;
774 int right = width - 1;
775
776 if ( subExtent.yMaximum() < extent.yMaximum() )
777 {
778 top = std::round( ( extent.yMaximum() - subExtent.yMaximum() ) / yRes );
779 }
780 if ( subExtent.yMinimum() > extent.yMinimum() )
781 {
782 bottom = std::round( ( extent.yMaximum() - subExtent.yMinimum() ) / yRes ) - 1;
783 }
784
785 if ( subExtent.xMinimum() > extent.xMinimum() )
786 {
787 left = std::round( ( subExtent.xMinimum() - extent.xMinimum() ) / xRes );
788 }
789 if ( subExtent.xMaximum() < extent.xMaximum() )
790 {
791 right = std::round( ( subExtent.xMaximum() - extent.xMinimum() ) / xRes ) - 1;
792 }
793 QRect subRect = QRect( left, top, right - left + 1, bottom - top + 1 );
794 QgsDebugMsgLevel( QStringLiteral( "subRect: %1 %2 %3 %4" ).arg( subRect.x() ).arg( subRect.y() ).arg( subRect.width() ).arg( subRect.height() ), 4 );
795 return subRect;
796}
DataType
Raster data types.
Definition: qgis.h:129
@ 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.
@ 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:2661
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:3012
bool qgsFloatNear(float a, float b, float epsilon=4 *FLT_EPSILON)
Compare two floats (but allow some difference)
Definition: qgis.h:2524
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2507
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QList< QgsRasterRange > QgsRasterRangeList