QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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  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 
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  {
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 
222 void 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 
296 bool 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 
461 QByteArray 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 
471 void 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 
508 char *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 
562 void 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 
594 QImage QgsRasterBlock::image() const
595 {
596  if ( mImage )
597  {
598  return QImage( *mImage );
599  }
600  return QImage();
601 }
602 
603 bool 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 
618 QString 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 
657 QString 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 
678 void *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 
692 QByteArray QgsRasterBlock::valueBytes( Qgis::DataType dataType, double value )
693 {
694  const qgssize size = QgsRasterBlock::typeSize( dataType );
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 
741 bool 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 
762 QRect 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:121
@ 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 qgsFree(void *ptr)
Frees the memory space pointed to by ptr.
Definition: qgis.cpp:114
void * qgsMalloc(size_t size)
Allocates size bytes and returns a pointer to the allocated memory.
Definition: qgis.cpp:92
QString qgsEnumValueToKey(const T &value)
Returns the value for the given key of an enum.
Definition: qgis.h:1737
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:2036
bool qgsFloatNear(float a, float b, float epsilon=4 *FLT_EPSILON)
Compare two floats (but allow some difference)
Definition: qgis.h:1595
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1578
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QList< QgsRasterRange > QgsRasterRangeList