QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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( dataType ), 4 );
55 
56  qgsFree( mData );
57  mData = nullptr;
58  delete mImage;
59  mImage = nullptr;
60  qgsFree( mNoDataBitmap );
61  mNoDataBitmap = nullptr;
62  mDataType = Qgis::UnknownDataType;
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  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  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( 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 {
106  if ( dataType == Qgis::ARGB32 )
107  {
108  return QImage::Format_ARGB32;
109  }
110  else if ( dataType == Qgis::ARGB32_Premultiplied )
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::ARGB32;
122  }
123  else if ( format == QImage::Format_ARGB32_Premultiplied )
124  {
126  }
127  return Qgis::UnknownDataType;
128 }
129 
131 {
132  QgsDebugMsgLevel( QStringLiteral( "mWidth= %1 mHeight = %2 mDataType = %3 mData = %4 mImage = %5" ).arg( mWidth ).arg( mHeight ).arg( 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  {
143  case Qgis::Byte:
144  case Qgis::UInt16:
145  case Qgis::Int16:
146  case Qgis::UInt32:
147  case Qgis::Int32:
148  case Qgis::Float32:
149  case Qgis::CInt16:
150  case Qgis::Float64:
151  case Qgis::CInt32:
152  case Qgis::CFloat32:
153  case Qgis::CFloat64:
154  return true;
155 
157  case Qgis::ARGB32:
159  return false;
160  }
161  return false;
162 }
163 
165 {
166  switch ( dataType )
167  {
168  case Qgis::ARGB32:
170  return true;
171 
173  case Qgis::Byte:
174  case Qgis::UInt16:
175  case Qgis::Int16:
176  case Qgis::UInt32:
177  case Qgis::Int32:
178  case Qgis::Float32:
179  case Qgis::CInt16:
180  case Qgis::Float64:
181  case Qgis::CInt32:
182  case Qgis::CFloat32:
183  case Qgis::CFloat64:
184  return false;
185  }
186  return false;
187 }
188 
190 {
191  Qgis::DataType newDataType;
192 
193  switch ( dataType )
194  {
195  case Qgis::Byte:
196  *noDataValue = -32768.0;
197  newDataType = Qgis::Int16;
198  break;
199  case Qgis::Int16:
200  *noDataValue = -2147483648.0;
201  newDataType = Qgis::Int32;
202  break;
203  case Qgis::UInt16:
204  *noDataValue = -2147483648.0;
205  newDataType = Qgis::Int32;
206  break;
207  case Qgis::UInt32:
208  case Qgis::Int32:
209  case Qgis::Float32:
210  case Qgis::Float64:
211  *noDataValue = std::numeric_limits<double>::max() * -1.0;
212  newDataType = Qgis::Float64;
213  break;
214  default:
215  QgsDebugMsg( QStringLiteral( "Unknown data type %1" ).arg( dataType ) );
216  return Qgis::UnknownDataType;
217  }
218  QgsDebugMsgLevel( QStringLiteral( "newDataType = %1 noDataValue = %2" ).arg( 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  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  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  int byte = c / 8;
372  int bit = c % 8;
373  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  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  int byte = c / 8;
390  int bit = c % 8;
391  char nodata = 0x80 >> bit;
392  memset( nodataRow + byte, nodataRow[byte] | nodata, 1 );
393  }
394  for ( int r = top; r <= bottom; r++ )
395  {
396  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  QRgb nodataRgba = NO_DATA_COLOR;
428  QRgb *nodataRow = new QRgb[mWidth]; // full row of no data
429  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  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  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 #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
467  return QByteArray::fromRawData( reinterpret_cast<const char *>( mImage->constBits() ), mImage->byteCount() );
468 #else
469  return QByteArray::fromRawData( reinterpret_cast<const char *>( mImage->constBits() ), mImage->sizeInBytes() );
470 #endif
471  else
472  return QByteArray();
473 }
474 
475 void QgsRasterBlock::setData( const QByteArray &data, int offset )
476 {
477  if ( offset < 0 )
478  return; // negative offsets not allowed
479 
480  if ( mData )
481  {
482  int len = std::min( data.size(), typeSize( mDataType ) * mWidth * mHeight - offset );
483  ::memcpy( static_cast<char *>( mData ) + offset, data.constData(), len );
484  }
485  else if ( mImage && mImage->constBits() )
486  {
487 #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
488  int len = std::min( data.size(), mImage->byteCount() - offset );
489 #else
490  qsizetype len = std::min( static_cast< qsizetype >( data.size() ), mImage->sizeInBytes() - offset );
491 #endif
492  ::memcpy( mImage->bits() + offset, data.constData(), len );
493  }
494 }
495 
497 {
498  // Not testing type to avoid too much overhead because this method is called per pixel
499  if ( index >= static_cast< qgssize >( mWidth )*mHeight )
500  {
501  QgsDebugMsgLevel( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ), 4 );
502  return nullptr;
503  }
504  if ( mData )
505  {
506  return reinterpret_cast< char * >( mData ) + index * mTypeSize;
507  }
508  if ( mImage && mImage->bits() )
509  {
510  return reinterpret_cast< char * >( mImage->bits() + index * 4 );
511  }
512 
513  return nullptr;
514 }
515 
516 char *QgsRasterBlock::bits( int row, int column )
517 {
518  return bits( static_cast< qgssize >( row ) * mWidth + column );
519 }
520 
522 {
523  if ( mData )
524  {
525  return reinterpret_cast< char * >( mData );
526  }
527  if ( mImage && mImage->bits() )
528  {
529  return reinterpret_cast< char * >( mImage->bits() );
530  }
531 
532  return nullptr;
533 }
534 
536 {
537  if ( isEmpty() ) return false;
538  if ( destDataType == mDataType ) return true;
539 
540  if ( typeIsNumeric( mDataType ) && typeIsNumeric( destDataType ) )
541  {
542  void *data = convert( mData, mDataType, destDataType, static_cast< qgssize >( mWidth ) * static_cast< qgssize >( mHeight ) );
543 
544  if ( !data )
545  {
546  QgsDebugMsg( QStringLiteral( "Cannot convert raster block" ) );
547  return false;
548  }
549  qgsFree( mData );
550  mData = data;
551  mDataType = destDataType;
552  mTypeSize = typeSize( mDataType );
553  }
554  else if ( typeIsColor( mDataType ) && typeIsColor( destDataType ) )
555  {
556  QImage::Format format = imageFormat( destDataType );
557  QImage image = mImage->convertToFormat( format );
558  *mImage = image;
559  mDataType = destDataType;
560  mTypeSize = typeSize( mDataType );
561  }
562  else
563  {
564  return false;
565  }
566 
567  return true;
568 }
569 
570 void QgsRasterBlock::applyScaleOffset( double scale, double offset )
571 {
572  if ( isEmpty() ) return;
573  if ( !typeIsNumeric( mDataType ) ) return;
574  if ( scale == 1.0 && offset == 0.0 ) return;
575 
576  qgssize size = static_cast< qgssize >( mWidth ) * mHeight;
577  for ( qgssize i = 0; i < size; ++i )
578  {
579  if ( !isNoData( i ) ) setValue( i, value( i ) * scale + offset );
580  }
581 }
582 
584 {
585  if ( rangeList.isEmpty() )
586  {
587  return;
588  }
589 
590  qgssize size = static_cast< qgssize >( mWidth ) * static_cast< qgssize >( mHeight );
591  for ( qgssize i = 0; i < size; ++i )
592  {
593  double val = value( i );
594  if ( QgsRasterRange::contains( val, rangeList ) )
595  {
596  //setValue( i, mNoDataValue );
597  setIsNoData( i );
598  }
599  }
600 }
601 
602 QImage QgsRasterBlock::image() const
603 {
604  if ( mImage )
605  {
606  return QImage( *mImage );
607  }
608  return QImage();
609 }
610 
611 bool QgsRasterBlock::setImage( const QImage *image )
612 {
613  qgsFree( mData );
614  mData = nullptr;
615  delete mImage;
616  mImage = nullptr;
617  mImage = new QImage( *image );
618  mWidth = mImage->width();
619  mHeight = mImage->height();
620  mDataType = dataType( mImage->format() );
621  mTypeSize = QgsRasterBlock::typeSize( mDataType );
622  mNoDataValue = std::numeric_limits<double>::quiet_NaN();
623  return true;
624 }
625 
626 QString QgsRasterBlock::printValue( double value )
627 {
628  /*
629  * IEEE 754 double has 15-17 significant digits. It specifies:
630  *
631  * "If a decimal string with at most 15 significant decimal is converted to
632  * IEEE 754 double precision and then converted back to the same number of
633  * significant decimal, then the final string should match the original;
634  * and if an IEEE 754 double precision is converted to a decimal string with at
635  * least 17 significant decimal and then converted back to double, then the final
636  * number must match the original."
637  *
638  * If printing only 15 digits, some precision could be lost. Printing 17 digits may
639  * add some confusing digits.
640  *
641  * Default 'g' precision on linux is 6 digits, not all significant digits like
642  * some sprintf manuals say.
643  *
644  * We need to ensure that the number printed and used in QLineEdit or XML will
645  * give the same number when parsed.
646  *
647  * Is there a better solution?
648  */
649 
650  QString s;
651 
652  for ( int i = 15; i <= 17; i++ )
653  {
654  s.setNum( value, 'g', i );
655  if ( qgsDoubleNear( s.toDouble(), value ) )
656  {
657  return s;
658  }
659  }
660  // Should not happen
661  QgsDebugMsg( QStringLiteral( "Cannot correctly parse printed value" ) );
662  return s;
663 }
664 
665 QString QgsRasterBlock::printValue( float value )
666 {
667  /*
668  * IEEE 754 double has 6-9 significant digits. See printValue(double)
669  */
670 
671  QString s;
672 
673  for ( int i = 6; i <= 9; i++ )
674  {
675  s.setNum( value, 'g', i );
676  if ( qgsFloatNear( s.toFloat(), value ) )
677  {
678  return s;
679  }
680  }
681  // Should not happen
682  QgsDebugMsg( QStringLiteral( "Cannot correctly parse printed value" ) );
683  return s;
684 }
685 
686 void *QgsRasterBlock::convert( void *srcData, Qgis::DataType srcDataType, Qgis::DataType destDataType, qgssize size )
687 {
688  int destDataTypeSize = typeSize( destDataType );
689  void *destData = qgsMalloc( destDataTypeSize * size );
690  for ( qgssize i = 0; i < size; i++ )
691  {
692  double value = readValue( srcData, srcDataType, i );
693  writeValue( destData, destDataType, i, value );
694  //double newValue = readValue( destData, destDataType, i );
695  //QgsDebugMsg( QStringLiteral("convert %1 type %2 to %3: %4 -> %5").arg(i).arg(srcDataType).arg(destDataType).arg( value ).arg( newValue ) );
696  }
697  return destData;
698 }
699 
700 QByteArray QgsRasterBlock::valueBytes( Qgis::DataType dataType, double value )
701 {
703  QByteArray ba;
704  ba.resize( static_cast< int >( size ) );
705  char *data = ba.data();
706  quint8 uc;
707  quint16 us;
708  qint16 s;
709  quint32 ui;
710  qint32 i;
711  float f;
712  double d;
713  switch ( dataType )
714  {
715  case Qgis::Byte:
716  uc = static_cast< quint8 >( value );
717  memcpy( data, &uc, size );
718  break;
719  case Qgis::UInt16:
720  us = static_cast< quint16 >( value );
721  memcpy( data, &us, size );
722  break;
723  case Qgis::Int16:
724  s = static_cast< qint16 >( value );
725  memcpy( data, &s, size );
726  break;
727  case Qgis::UInt32:
728  ui = static_cast< quint32 >( value );
729  memcpy( data, &ui, size );
730  break;
731  case Qgis::Int32:
732  i = static_cast< qint32 >( value );
733  memcpy( data, &i, size );
734  break;
735  case Qgis::Float32:
736  f = static_cast< float >( value );
737  memcpy( data, &f, size );
738  break;
739  case Qgis::Float64:
740  d = static_cast< double >( value );
741  memcpy( data, &d, size );
742  break;
743  default:
744  QgsDebugMsg( QStringLiteral( "Data type is not supported" ) );
745  }
746  return ba;
747 }
748 
749 bool QgsRasterBlock::createNoDataBitmap()
750 {
751  mNoDataBitmapWidth = mWidth / 8 + 1;
752  mNoDataBitmapSize = static_cast< qgssize >( mNoDataBitmapWidth ) * mHeight;
753  QgsDebugMsgLevel( QStringLiteral( "allocate %1 bytes" ).arg( mNoDataBitmapSize ), 4 );
754  mNoDataBitmap = reinterpret_cast< char * >( qgsMalloc( mNoDataBitmapSize ) );
755  if ( !mNoDataBitmap )
756  {
757  QgsDebugMsg( QStringLiteral( "Couldn't allocate no data memory of %1 bytes" ).arg( mNoDataBitmapSize ) );
758  return false;
759  }
760  memset( mNoDataBitmap, 0, mNoDataBitmapSize );
761  return true;
762 }
763 
765 {
766  return QStringLiteral( "dataType = %1 width = %2 height = %3" )
767  .arg( mDataType ).arg( mWidth ).arg( mHeight );
768 }
769 
770 QRect QgsRasterBlock::subRect( const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent )
771 {
772  QgsDebugMsgLevel( "theExtent = " + extent.toString(), 4 );
773  QgsDebugMsgLevel( "theSubExtent = " + subExtent.toString(), 4 );
774  double xRes = extent.width() / width;
775  double yRes = extent.height() / height;
776 
777  QgsDebugMsgLevel( QStringLiteral( "theWidth = %1 height = %2 xRes = %3 yRes = %4" ).arg( width ).arg( height ).arg( xRes ).arg( yRes ), 4 );
778 
779  int top = 0;
780  int bottom = height - 1;
781  int left = 0;
782  int right = width - 1;
783 
784  if ( subExtent.yMaximum() < extent.yMaximum() )
785  {
786  top = std::round( ( extent.yMaximum() - subExtent.yMaximum() ) / yRes );
787  }
788  if ( subExtent.yMinimum() > extent.yMinimum() )
789  {
790  bottom = std::round( ( extent.yMaximum() - subExtent.yMinimum() ) / yRes ) - 1;
791  }
792 
793  if ( subExtent.xMinimum() > extent.xMinimum() )
794  {
795  left = std::round( ( subExtent.xMinimum() - extent.xMinimum() ) / xRes );
796  }
797  if ( subExtent.xMaximum() < extent.xMaximum() )
798  {
799  right = std::round( ( subExtent.xMaximum() - extent.xMinimum() ) / xRes ) - 1;
800  }
801  QRect subRect = QRect( left, top, right - left + 1, bottom - top + 1 );
802  QgsDebugMsgLevel( QStringLiteral( "subRect: %1 %2 %3 %4" ).arg( subRect.x() ).arg( subRect.y() ).arg( subRect.width() ).arg( subRect.height() ), 4 );
803  return subRect;
804 }
QgsRasterBlock::printValue
static QString printValue(double value)
Print double value with all necessary significant digits.
Definition: qgsrasterblock.cpp:626
Qgis::Float32
@ Float32
Thirty two bit floating point (float)
Definition: qgis.h:109
QgsRectangle::height
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:209
Qgis::DataType
DataType
Raster data types.
Definition: qgis.h:102
QgsRasterBlock::setIsNoData
bool setIsNoData()
Set the whole block to no data.
Definition: qgsrasterblock.cpp:234
Qgis::UInt32
@ UInt32
Thirty two bit unsigned integer (quint32)
Definition: qgis.h:107
qgsrectangle.h
QgsRasterBlock::dataType
Qgis::DataType dataType() const SIP_HOLDGIL
Returns data type.
Definition: qgsrasterblock.h:133
QgsRasterBlock::applyNoDataValues
void applyNoDataValues(const QgsRasterRangeList &rangeList)
Definition: qgsrasterblock.cpp:583
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsRasterBlock::typeIsNumeric
static bool typeIsNumeric(Qgis::DataType type)
Returns true if data type is numeric.
Definition: qgsrasterblock.cpp:139
QgsRasterBlock::resetNoDataValue
void resetNoDataValue() SIP_HOLDGIL
Reset no data value: if there was a no data value previously set, it will be discarded.
Definition: qgsrasterblock.cpp:228
QgsRasterBlock::dataTypeSize
int dataTypeSize() const SIP_HOLDGIL
Data type size in bytes.
Definition: qgsrasterblock.h:121
QgsRasterBlock::typeWithNoDataValue
static Qgis::DataType typeWithNoDataValue(Qgis::DataType dataType, double *noDataValue)
For given data type returns wider type and sets no data value.
Definition: qgsrasterblock.cpp:189
QgsRectangle::yMinimum
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
QgsRasterBlock::width
int width() const SIP_HOLDGIL
Returns the width (number of columns) of the raster block.
Definition: qgsrasterblock.h:643
qgsMalloc
void * qgsMalloc(size_t size)
Allocates size bytes and returns a pointer to the allocated memory.
Definition: qgis.cpp:86
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsRasterBlock::noDataValue
double noDataValue() const SIP_HOLDGIL
Returns no data value.
Definition: qgsrasterblock.h:177
QgsRasterBlock::readValue
static double readValue(void *data, Qgis::DataType type, qgssize index)
Definition: qgsrasterblock.h:740
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QgsRasterBlock::~QgsRasterBlock
virtual ~QgsRasterBlock()
Definition: qgsrasterblock.cpp:44
Qgis::CFloat32
@ CFloat32
Complex Float32.
Definition: qgis.h:113
QgsRasterBlock::subRect
static QRect subRect(const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent)
For extent and width, height find rectangle covered by subextent.
Definition: qgsrasterblock.cpp:770
QgsRectangle::xMaximum
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
Qgis::CFloat64
@ CFloat64
Complex Float64.
Definition: qgis.h:114
QgsRasterBlock::typeSize
static int typeSize(int dataType) SIP_HOLDGIL
Returns the size in bytes for the specified dataType.
Definition: qgsrasterblock.h:83
qgsFloatNear
bool qgsFloatNear(float a, float b, float epsilon=4 *FLT_EPSILON)
Compare two floats (but allow some difference)
Definition: qgis.h:330
QgsRasterBlock::data
QByteArray data() const
Gets access to raw data.
Definition: qgsrasterblock.cpp:461
Qgis::CInt16
@ CInt16
Complex Int16.
Definition: qgis.h:111
qgsrasterblock.h
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:315
QgsRasterBlock::setIsNoDataExcept
bool setIsNoDataExcept(QRect exceptRect)
Set the whole block to no data except specified rectangle.
Definition: qgsrasterblock.cpp:296
QgsRasterBlock::convert
bool convert(Qgis::DataType destDataType)
Convert data to different type.
Definition: qgsrasterblock.cpp:535
QgsRasterRangeList
QList< QgsRasterRange > QgsRasterRangeList
Definition: qgsrasterrange.h:26
QgsRasterBlock::reset
bool reset(Qgis::DataType dataType, int width, int height)
Reset block.
Definition: qgsrasterblock.cpp:52
QgsRasterBlock::height
int height() const SIP_HOLDGIL
Returns the height (number of rows) of the raster block.
Definition: qgsrasterblock.h:650
QgsRasterBlock::setValue
bool setValue(int row, int column, double value) SIP_HOLDGIL
Set value on position.
Definition: qgsrasterblock.h:347
QgsRectangle::xMinimum
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
QgsRasterBlock::typeIsColor
static bool typeIsColor(Qgis::DataType type)
Returns true if data type is color.
Definition: qgsrasterblock.cpp:164
QgsRasterRange::contains
bool contains(double value) const
Returns true if this range contains the specified value.
Definition: qgsrasterrange.h:114
Qgis::UInt16
@ UInt16
Sixteen bit unsigned integer (quint16)
Definition: qgis.h:105
QgsRasterBlock::isEmpty
bool isEmpty() const
Returns true if block is empty, i.e.
Definition: qgsrasterblock.cpp:130
QgsRasterBlock::value
double value(int row, int column) const SIP_HOLDGIL
Read a single value if type of block is numeric.
Definition: qgsrasterblock.h:195
QgsRectangle::toString
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
Definition: qgsrectangle.cpp:127
QgsRasterBlock::writeValue
static void writeValue(void *data, Qgis::DataType type, qgssize index, double value)
Definition: qgsrasterblock.h:771
QgsRasterBlock::valueBytes
static QByteArray valueBytes(Qgis::DataType dataType, double value)
Gets byte array representing a value.
Definition: qgsrasterblock.cpp:700
QgsRasterBlock::bits
char * bits()
Returns a pointer to block data.
Definition: qgsrasterblock.cpp:521
Qgis::ARGB32_Premultiplied
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:116
QgsRectangle::yMaximum
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
QgsRasterBlock::QgsRasterBlock
QgsRasterBlock()
Definition: qgsrasterblock.cpp:30
c
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
Definition: porting_processing.dox:1
QgsRasterBlock::setNoDataValue
void setNoDataValue(double noDataValue) SIP_HOLDGIL
Sets cell value that will be considered as "no data".
Definition: qgsrasterblock.cpp:222
QgsRectangle::width
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:202
qgsFree
void qgsFree(void *ptr)
Frees the memory space pointed to by ptr.
Definition: qgis.cpp:116
QgsRasterBlock::applyScaleOffset
void applyScaleOffset(double scale, double offset)
Apply band scale and offset to raster block values.
Definition: qgsrasterblock.cpp:570
Qgis::Int16
@ Int16
Sixteen bit signed integer (qint16)
Definition: qgis.h:106
QgsRasterBlock::setImage
bool setImage(const QImage *image)
Sets the block data via an image.
Definition: qgsrasterblock.cpp:611
Qgis::Int32
@ Int32
Thirty two bit signed integer (qint32)
Definition: qgis.h:108
Qgis::UnknownDataType
@ UnknownDataType
Unknown or unspecified type.
Definition: qgis.h:103
Qgis::CInt32
@ CInt32
Complex Int32.
Definition: qgis.h:112
Qgis::ARGB32
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:115
QgsRasterBlock::setData
void setData(const QByteArray &data, int offset=0)
Rewrite raw pixel data.
Definition: qgsrasterblock.cpp:475
qgslogger.h
QgsRasterBlock::isNoData
bool isNoData(int row, int column) const SIP_HOLDGIL
Checks if value at position is no data.
Definition: qgsrasterblock.h:286
Qgis::Byte
@ Byte
Eight bit unsigned integer (quint8)
Definition: qgis.h:104
QgsRasterBlock::toString
QString toString() const
Definition: qgsrasterblock.cpp:764
QgsRasterBlock::image
QImage image() const
Returns an image containing the block data, if the block's data type is color.
Definition: qgsrasterblock.cpp:602
qgssize
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:768
Qgis::Float64
@ Float64
Sixty four bit floating point (double)
Definition: qgis.h:110