QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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  return QByteArray::fromRawData( reinterpret_cast<const char *>( mImage->constBits() ), mImage->byteCount() );
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  int len = std::min( 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  int len = std::min( data.size(), mImage->byteCount() - 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  QImage::Format format = imageFormat( destDataType );
549  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  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  qgssize size = static_cast< qgssize >( mWidth ) * static_cast< qgssize >( mHeight );
583  for ( qgssize i = 0; i < size; ++i )
584  {
585  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 
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 
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  int destDataTypeSize = typeSize( destDataType );
681  void *destData = qgsMalloc( destDataTypeSize * size );
682  for ( qgssize i = 0; i < size; i++ )
683  {
684  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 
693 {
694  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  {
707  case Qgis::Byte:
708  uc = static_cast< quint8 >( value );
709  memcpy( data, &uc, size );
710  break;
711  case Qgis::UInt16:
712  us = static_cast< quint16 >( value );
713  memcpy( data, &us, size );
714  break;
715  case Qgis::Int16:
716  s = static_cast< qint16 >( value );
717  memcpy( data, &s, size );
718  break;
719  case Qgis::UInt32:
720  ui = static_cast< quint32 >( value );
721  memcpy( data, &ui, size );
722  break;
723  case Qgis::Int32:
724  i = static_cast< qint32 >( value );
725  memcpy( data, &i, size );
726  break;
727  case Qgis::Float32:
728  f = static_cast< float >( value );
729  memcpy( data, &f, size );
730  break;
731  case Qgis::Float64:
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( 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  double xRes = extent.width() / width;
767  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 }
void setNoDataValue(double noDataValue)
Sets cell value that will be considered as "no data".
A rectangle specified with double values.
Definition: qgsrectangle.h:40
Thirty two bit signed integer (qint32)
Definition: qgis.h:99
Qgis::DataType dataType() const
Returns data type.
int height() const
Returns the height (number of rows) of the raster block.
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:118
bool setIsNoData()
Set the whole block to no data.
static double readValue(void *data, Qgis::DataType type, qgssize index)
bool qgsFloatNear(float a, float b, float epsilon=4 *FLT_EPSILON)
Compare two floats (but allow some difference)
Definition: qgis.h:290
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.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:171
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
bool contains(double value) const
Returns true if this range contains the specified value.
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.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:278
static bool typeIsNumeric(Qgis::DataType type)
Returns true if data type is numeric.
Thirty two bit unsigned integer (quint32)
Definition: qgis.h:98
double noDataValue() const
Returns no data value.
DataType
Raster data types.
Definition: qgis.h:92
int width() const
Returns the width (number of columns) of the raster block.
Thirty two bit floating point (float)
Definition: qgis.h:100
Sixteen bit signed integer (qint16)
Definition: qgis.h:97
Complex Int16.
Definition: qgis.h:102
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:101
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:107
virtual ~QgsRasterBlock()
bool convert(Qgis::DataType destDataType)
Convert data to different type.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:176
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:161
bool setImage(const QImage *image)
Sets the block data via an image.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
double value(int row, int column) const
Read a single value if type of block is numeric.
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
Complex Float32.
Definition: qgis.h:104
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:94
Complex Int32.
Definition: qgis.h:103
static int typeSize(int dataType)
Sixteen bit unsigned integer (quint16)
Definition: qgis.h:96
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:586
static QByteArray valueBytes(Qgis::DataType dataType, double value)
Gets byte array representing a value.
QString toString() const
int dataTypeSize() const
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.
bool isNoData(int row, int column) const
Check if value at position is no data.
QImage image() const
Returns an image containing the block data, if the block&#39;s data type is color.
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:201
Complex Float64.
Definition: qgis.h:105
void setData(const QByteArray &data, int offset=0)
Rewrite raw pixel data.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:166
void qgsFree(void *ptr)
Frees the memory space pointed to by ptr.
Definition: qgis.cpp:148
Eight bit unsigned integer (quint8)
Definition: qgis.h:95
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:106
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:208
QByteArray data() const
Gets access to raw data.
bool isEmpty() const
Returns true if block is empty, i.e.