QGIS API Documentation 3.28.14-Firenze (exported)
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
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.
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.
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: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:2681
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:3032
bool qgsFloatNear(float a, float b, float epsilon=4 *FLT_EPSILON)
Compare two floats (but allow some difference)
Definition qgis.h:2544
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:2527
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39
#define QgsDebugMsg(str)
Definition qgslogger.h:38
QList< QgsRasterRange > QgsRasterRangeList