QGIS API Documentation  3.37.0-Master (a5b4d9743e8)
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!
28 const QRgb QgsRasterBlock::NO_DATA_COLOR = qRgba( 0, 0, 0, 0 );
29 
31  : mNoDataValue( std::numeric_limits<double>::quiet_NaN() )
32 {
33 }
34 
35 QgsRasterBlock::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 
52 bool 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 
104 QImage::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 
117 Qgis::DataType QgsRasterBlock::dataType( QImage::Format format )
118 {
119  if ( format == QImage::Format_ARGB32 )
120  {
121  return Qgis::DataType::ARGB32;
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 
231 void 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 
305 bool 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 
470 QByteArray 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 
480 void 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 
517 char *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 
571 void 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 
603 QImage QgsRasterBlock::image() const
604 {
605  if ( mImage )
606  {
607  return QImage( *mImage );
608  }
609  return QImage();
610 }
611 
612 bool 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 
627 QString 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 
666 QString 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 
687 void *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 
701 QByteArray QgsRasterBlock::valueBytes( Qgis::DataType dataType, double value )
702 {
703  const qgssize size = QgsRasterBlock::typeSize( dataType );
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 
762 bool 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 
783 QRect 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 qgsFree(void *ptr)
Frees the memory space pointed to by ptr.
Definition: qgis.cpp:115
void * qgsMalloc(size_t size)
Allocates size bytes and returns a pointer to the allocated memory.
Definition: qgis.cpp:93
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition: qgis.h:5363
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:5712
bool qgsFloatNear(float a, float b, float epsilon=4 *FLT_EPSILON)
Compare two floats (but allow some difference)
Definition: qgis.h:5183
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:5172
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugError(str)
Definition: qgslogger.h:38
QList< QgsRasterRange > QgsRasterRangeList