QGIS API Documentation  3.13.0-Master (b73bd58cfb)
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 
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 
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 
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 
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 
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 
701 {
702  qgssize size = QgsRasterBlock::typeSize( dataType );
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 }
void setNoDataValue(double noDataValue)
Sets cell value that will be considered as "no data".
A rectangle specified with double values.
Definition: qgsrectangle.h:41
Thirty two bit signed integer (qint32)
Definition: qgis.h:108
bool contains(double value) const
Returns true if this range contains the specified value.
static QString printValue(double value)
Print double value with all necessary significant digits.
void * qgsMalloc(size_t size)
Allocates size bytes and returns a pointer to the allocated memory.
Definition: qgis.cpp:86
bool setIsNoData()
Set the whole block to no data.
static double readValue(void *data, Qgis::DataType type, qgssize index)
Qgis::DataType dataType() const
Returns data type.
bool qgsFloatNear(float a, float b, float epsilon=4 *FLT_EPSILON)
Compare two floats (but allow some difference)
Definition: qgis.h:330
static Qgis::DataType typeWithNoDataValue(Qgis::DataType dataType, double *noDataValue)
For given data type returns wider type and sets no data value.
static bool typeIsColor(Qgis::DataType type)
Returns true if data type is color.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
void applyNoDataValues(const QgsRasterRangeList &rangeList)
bool setValue(int row, int column, double value)
Set value on position.
bool setIsNoDataExcept(QRect exceptRect)
Set the whole block to no data except specified rectangle.
int height() const
Returns the height (number of rows) of the raster block.
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
static bool typeIsNumeric(Qgis::DataType type)
Returns true if data type is numeric.
Thirty two bit unsigned integer (quint32)
Definition: qgis.h:107
DataType
Raster data types.
Definition: qgis.h:101
Thirty two bit floating point (float)
Definition: qgis.h:109
Sixteen bit signed integer (qint16)
Definition: qgis.h:106
Complex Int16.
Definition: qgis.h:111
static QRect subRect(const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent)
For extent and width, height find rectangle covered by subextent.
Sixty four bit floating point (double)
Definition: qgis.h:110
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
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:116
virtual ~QgsRasterBlock()
bool convert(Qgis::DataType destDataType)
Convert data to different type.
bool setImage(const QImage *image)
Sets the block data via an image.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:202
Complex Float32.
Definition: qgis.h:113
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
bool reset(Qgis::DataType dataType, int width, int height)
Reset block.
char * bits()
Returns a pointer to block data.
Unknown or unspecified type.
Definition: qgis.h:103
Complex Int32.
Definition: qgis.h:112
static int typeSize(int dataType)
bool isEmpty() const
Returns true if block is empty, i.e.
Sixteen bit unsigned integer (quint16)
Definition: qgis.h:105
bool isNoData(int row, int column) const
Checks if value at position is no data.
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:703
static QByteArray valueBytes(Qgis::DataType dataType, double value)
Gets byte array representing a value.
QByteArray data() const
Gets access to raw data.
int width() const
Returns the width (number of columns) of the raster block.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
QImage image() const
Returns an image containing the block data, if the block&#39;s data type is color.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
void resetNoDataValue()
Reset no data value: if there was a no data value previously set, it will be discarded.
static void writeValue(void *data, Qgis::DataType type, qgssize index, double value)
QList< QgsRasterRange > QgsRasterRangeList
void applyScaleOffset(double scale, double offset)
Apply band scale and offset to raster block values.
double value(int row, int column) const
Read a single value if type of block is numeric.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
int dataTypeSize() const
Complex Float64.
Definition: qgis.h:114
void setData(const QByteArray &data, int offset=0)
Rewrite raw pixel data.
double noDataValue() const
Returns no data value.
void qgsFree(void *ptr)
Frees the memory space pointed to by ptr.
Definition: qgis.cpp:116
Eight bit unsigned integer (quint8)
Definition: qgis.h:104
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:115
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:209
QString toString() const