QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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  if ( mHasNoDataValue )
240  {
241  if ( !mData )
242  {
243  QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
244  return false;
245  }
246 
247  QgsDebugMsgLevel( QStringLiteral( "set mData to mNoDataValue" ), 4 );
248  int dataTypeSize = typeSize( mDataType );
249  QByteArray noDataByteArray = valueBytes( mDataType, mNoDataValue );
250 
251  char *nodata = noDataByteArray.data();
252  for ( qgssize i = 0; i < static_cast< qgssize >( mWidth )*mHeight; i++ )
253  {
254  memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodata, dataTypeSize );
255  }
256  }
257  else
258  {
259  // use bitmap
260  if ( !mNoDataBitmap )
261  {
262  if ( !createNoDataBitmap() )
263  {
264  return false;
265  }
266  }
267  QgsDebugMsgLevel( QStringLiteral( "set mNoDataBitmap to 1" ), 4 );
268  memset( mNoDataBitmap, 0xff, mNoDataBitmapSize );
269  }
270  return true;
271  }
272  else
273  {
274  // image
275  if ( !mImage )
276  {
277  QgsDebugMsg( QStringLiteral( "Image not allocated" ) );
278  return false;
279  }
280  QgsDebugMsgLevel( QStringLiteral( "Fill image" ), 4 );
281  mImage->fill( NO_DATA_COLOR );
282  return true;
283  }
284 }
285 
286 bool QgsRasterBlock::setIsNoDataExcept( QRect exceptRect )
287 {
288  int top = exceptRect.top();
289  int bottom = exceptRect.bottom();
290  int left = exceptRect.left();
291  int right = exceptRect.right();
292  top = std::min( std::max( top, 0 ), mHeight - 1 );
293  left = std::min( std::max( left, 0 ), mWidth - 1 );
294  bottom = std::max( 0, std::min( bottom, mHeight - 1 ) );
295  right = std::max( 0, std::min( right, mWidth - 1 ) );
296 
297  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
298  if ( typeIsNumeric( mDataType ) )
299  {
300  if ( mHasNoDataValue )
301  {
302  if ( !mData )
303  {
304  QgsDebugMsg( QStringLiteral( "Data block not allocated" ) );
305  return false;
306  }
307 
308  QgsDebugMsgLevel( QStringLiteral( "set mData to mNoDataValue" ), 4 );
309  int dataTypeSize = typeSize( mDataType );
310  QByteArray noDataByteArray = valueBytes( mDataType, mNoDataValue );
311 
312  char *nodata = noDataByteArray.data();
313  char *nodataRow = new char[mWidth * dataTypeSize]; // full row of no data
314  for ( int c = 0; c < mWidth; c++ )
315  {
316  memcpy( nodataRow + c * dataTypeSize, nodata, dataTypeSize );
317  }
318 
319  // top and bottom
320  for ( int r = 0; r < mHeight; r++ )
321  {
322  if ( r >= top && r <= bottom ) continue; // middle
323  qgssize i = static_cast< qgssize >( r ) * mWidth;
324  memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodataRow, dataTypeSize * static_cast< qgssize >( mWidth ) );
325  }
326  // middle
327  for ( int r = top; r <= bottom; r++ )
328  {
329  qgssize i = static_cast< qgssize >( r ) * mWidth;
330  // middle left
331  memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodataRow, dataTypeSize * static_cast< qgssize >( left ) );
332  // middle right
333  i += right + 1;
334  int w = mWidth - right - 1;
335  memcpy( reinterpret_cast< char * >( mData ) + i * dataTypeSize, nodataRow, dataTypeSize * static_cast< qgssize >( w ) );
336  }
337  delete [] nodataRow;
338  }
339  else
340  {
341  // use bitmap
342  if ( !mNoDataBitmap )
343  {
344  if ( !createNoDataBitmap() )
345  {
346  return false;
347  }
348  }
349  QgsDebugMsgLevel( QStringLiteral( "set mNoDataBitmap to 1" ), 4 );
350 
351  char *nodataRow = new char[mNoDataBitmapWidth]; // full row of no data
352  // TODO: we can simply set all bytes to 11111111 (~0) I think
353  memset( nodataRow, 0, mNoDataBitmapWidth );
354  for ( int c = 0; c < mWidth; c ++ )
355  {
356  int byte = c / 8;
357  int bit = c % 8;
358  char nodata = 0x80 >> bit;
359  memset( nodataRow + byte, nodataRow[byte] | nodata, 1 );
360  }
361 
362  // top and bottom
363  for ( int r = 0; r < mHeight; r++ )
364  {
365  if ( r >= top && r <= bottom ) continue; // middle
366  qgssize i = static_cast< qgssize >( r ) * mNoDataBitmapWidth;
367  memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
368  }
369  // middle
370  memset( nodataRow, 0, mNoDataBitmapWidth );
371  for ( int c = 0; c < mWidth; c ++ )
372  {
373  if ( c >= left && c <= right ) continue; // middle
374  int byte = c / 8;
375  int bit = c % 8;
376  char nodata = 0x80 >> bit;
377  memset( nodataRow + byte, nodataRow[byte] | nodata, 1 );
378  }
379  for ( int r = top; r <= bottom; r++ )
380  {
381  qgssize i = static_cast< qgssize >( r ) * mNoDataBitmapWidth;
382  memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
383  }
384  delete [] nodataRow;
385  }
386  return true;
387  }
388  else
389  {
390  // image
391  if ( !mImage )
392  {
393  QgsDebugMsg( QStringLiteral( "Image not allocated" ) );
394  return false;
395  }
396 
397  if ( mImage->width() != mWidth || mImage->height() != mHeight )
398  {
399  QgsDebugMsg( QStringLiteral( "Image and block size differ" ) );
400  return false;
401  }
402 
403  QgsDebugMsgLevel( QStringLiteral( "Fill image depth = %1" ).arg( mImage->depth() ), 4 );
404 
405  // TODO: support different depths
406  if ( mImage->depth() != 32 )
407  {
408  QgsDebugMsg( QStringLiteral( "Unsupported image depth" ) );
409  return false;
410  }
411 
412  QRgb nodataRgba = NO_DATA_COLOR;
413  QRgb *nodataRow = new QRgb[mWidth]; // full row of no data
414  int rgbSize = sizeof( QRgb );
415  for ( int c = 0; c < mWidth; c ++ )
416  {
417  nodataRow[c] = nodataRgba;
418  }
419 
420  // top and bottom
421  for ( int r = 0; r < mHeight; r++ )
422  {
423  if ( r >= top && r <= bottom ) continue; // middle
424  qgssize i = static_cast< qgssize >( r ) * mWidth;
425  memcpy( reinterpret_cast< void * >( mImage->bits() + rgbSize * i ), nodataRow, rgbSize * static_cast< qgssize >( mWidth ) );
426  }
427  // middle
428  for ( int r = top; r <= bottom; r++ )
429  {
430  qgssize i = static_cast< qgssize >( r ) * mWidth;
431  // middle left
432  if ( left > 0 )
433  {
434  memcpy( reinterpret_cast< void * >( mImage->bits() + rgbSize * i ), nodataRow, rgbSize * static_cast< qgssize >( left - 1 ) );
435  }
436  // middle right
437  i += right + 1;
438  int w = mWidth - right - 1;
439  memcpy( reinterpret_cast< void * >( mImage->bits() + rgbSize * i ), nodataRow, rgbSize * static_cast< qgssize >( w ) );
440  }
441  delete [] nodataRow;
442  return true;
443  }
444 }
445 
446 QByteArray QgsRasterBlock::data() const
447 {
448  if ( mData )
449  return QByteArray::fromRawData( static_cast<const char *>( mData ), typeSize( mDataType ) * mWidth * mHeight );
450  else if ( mImage && mImage->constBits() )
451  return QByteArray::fromRawData( reinterpret_cast<const char *>( mImage->constBits() ), mImage->byteCount() );
452  else
453  return QByteArray();
454 }
455 
456 void QgsRasterBlock::setData( const QByteArray &data, int offset )
457 {
458  if ( offset < 0 )
459  return; // negative offsets not allowed
460 
461  if ( mData )
462  {
463  int len = std::min( data.size(), typeSize( mDataType ) * mWidth * mHeight - offset );
464  ::memcpy( static_cast<char *>( mData ) + offset, data.constData(), len );
465  }
466  else if ( mImage && mImage->constBits() )
467  {
468  int len = std::min( data.size(), mImage->byteCount() - offset );
469  ::memcpy( mImage->bits() + offset, data.constData(), len );
470  }
471 }
472 
474 {
475  // Not testing type to avoid too much overhead because this method is called per pixel
476  if ( index >= static_cast< qgssize >( mWidth )*mHeight )
477  {
478  QgsDebugMsgLevel( QStringLiteral( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ), 4 );
479  return nullptr;
480  }
481  if ( mData )
482  {
483  return reinterpret_cast< char * >( mData ) + index * mTypeSize;
484  }
485  if ( mImage && mImage->bits() )
486  {
487  return reinterpret_cast< char * >( mImage->bits() + index * 4 );
488  }
489 
490  return nullptr;
491 }
492 
493 char *QgsRasterBlock::bits( int row, int column )
494 {
495  return bits( static_cast< qgssize >( row ) * mWidth + column );
496 }
497 
499 {
500  if ( mData )
501  {
502  return reinterpret_cast< char * >( mData );
503  }
504  if ( mImage && mImage->bits() )
505  {
506  return reinterpret_cast< char * >( mImage->bits() );
507  }
508 
509  return nullptr;
510 }
511 
513 {
514  if ( isEmpty() ) return false;
515  if ( destDataType == mDataType ) return true;
516 
517  if ( typeIsNumeric( mDataType ) && typeIsNumeric( destDataType ) )
518  {
519  void *data = convert( mData, mDataType, destDataType, static_cast< qgssize >( mWidth ) * static_cast< qgssize >( mHeight ) );
520 
521  if ( !data )
522  {
523  QgsDebugMsg( QStringLiteral( "Cannot convert raster block" ) );
524  return false;
525  }
526  qgsFree( mData );
527  mData = data;
528  mDataType = destDataType;
529  mTypeSize = typeSize( mDataType );
530  }
531  else if ( typeIsColor( mDataType ) && typeIsColor( destDataType ) )
532  {
533  QImage::Format format = imageFormat( destDataType );
534  QImage image = mImage->convertToFormat( format );
535  *mImage = image;
536  mDataType = destDataType;
537  mTypeSize = typeSize( mDataType );
538  }
539  else
540  {
541  return false;
542  }
543 
544  return true;
545 }
546 
547 void QgsRasterBlock::applyScaleOffset( double scale, double offset )
548 {
549  if ( isEmpty() ) return;
550  if ( !typeIsNumeric( mDataType ) ) return;
551  if ( scale == 1.0 && offset == 0.0 ) return;
552 
553  qgssize size = static_cast< qgssize >( mWidth ) * mHeight;
554  for ( qgssize i = 0; i < size; ++i )
555  {
556  if ( !isNoData( i ) ) setValue( i, value( i ) * scale + offset );
557  }
558 }
559 
561 {
562  if ( rangeList.isEmpty() )
563  {
564  return;
565  }
566 
567  qgssize size = static_cast< qgssize >( mWidth ) * static_cast< qgssize >( mHeight );
568  for ( qgssize i = 0; i < size; ++i )
569  {
570  double val = value( i );
571  if ( QgsRasterRange::contains( val, rangeList ) )
572  {
573  //setValue( i, mNoDataValue );
574  setIsNoData( i );
575  }
576  }
577 }
578 
579 QImage QgsRasterBlock::image() const
580 {
581  if ( mImage )
582  {
583  return QImage( *mImage );
584  }
585  return QImage();
586 }
587 
588 bool QgsRasterBlock::setImage( const QImage *image )
589 {
590  qgsFree( mData );
591  mData = nullptr;
592  delete mImage;
593  mImage = nullptr;
594  mImage = new QImage( *image );
595  mWidth = mImage->width();
596  mHeight = mImage->height();
597  mDataType = dataType( mImage->format() );
598  mTypeSize = QgsRasterBlock::typeSize( mDataType );
599  mNoDataValue = std::numeric_limits<double>::quiet_NaN();
600  return true;
601 }
602 
604 {
605  /*
606  * IEEE 754 double has 15-17 significant digits. It specifies:
607  *
608  * "If a decimal string with at most 15 significant decimal is converted to
609  * IEEE 754 double precision and then converted back to the same number of
610  * significant decimal, then the final string should match the original;
611  * and if an IEEE 754 double precision is converted to a decimal string with at
612  * least 17 significant decimal and then converted back to double, then the final
613  * number must match the original."
614  *
615  * If printing only 15 digits, some precision could be lost. Printing 17 digits may
616  * add some confusing digits.
617  *
618  * Default 'g' precision on linux is 6 digits, not all significant digits like
619  * some sprintf manuals say.
620  *
621  * We need to ensure that the number printed and used in QLineEdit or XML will
622  * give the same number when parsed.
623  *
624  * Is there a better solution?
625  */
626 
627  QString s;
628 
629  for ( int i = 15; i <= 17; i++ )
630  {
631  s.setNum( value, 'g', i );
632  if ( qgsDoubleNear( s.toDouble(), value ) )
633  {
634  return s;
635  }
636  }
637  // Should not happen
638  QgsDebugMsg( QStringLiteral( "Cannot correctly parse printed value" ) );
639  return s;
640 }
641 
643 {
644  /*
645  * IEEE 754 double has 6-9 significant digits. See printValue(double)
646  */
647 
648  QString s;
649 
650  for ( int i = 6; i <= 9; i++ )
651  {
652  s.setNum( value, 'g', i );
653  if ( qgsFloatNear( s.toFloat(), value ) )
654  {
655  return s;
656  }
657  }
658  // Should not happen
659  QgsDebugMsg( QStringLiteral( "Cannot correctly parse printed value" ) );
660  return s;
661 }
662 
663 void *QgsRasterBlock::convert( void *srcData, Qgis::DataType srcDataType, Qgis::DataType destDataType, qgssize size )
664 {
665  int destDataTypeSize = typeSize( destDataType );
666  void *destData = qgsMalloc( destDataTypeSize * size );
667  for ( qgssize i = 0; i < size; i++ )
668  {
669  double value = readValue( srcData, srcDataType, i );
670  writeValue( destData, destDataType, i, value );
671  //double newValue = readValue( destData, destDataType, i );
672  //QgsDebugMsg( QStringLiteral("convert %1 type %2 to %3: %4 -> %5").arg(i).arg(srcDataType).arg(destDataType).arg( value ).arg( newValue ) );
673  }
674  return destData;
675 }
676 
678 {
679  qgssize size = QgsRasterBlock::typeSize( dataType );
680  QByteArray ba;
681  ba.resize( static_cast< int >( size ) );
682  char *data = ba.data();
683  quint8 uc;
684  quint16 us;
685  qint16 s;
686  quint32 ui;
687  qint32 i;
688  float f;
689  double d;
690  switch ( dataType )
691  {
692  case Qgis::Byte:
693  uc = static_cast< quint8 >( value );
694  memcpy( data, &uc, size );
695  break;
696  case Qgis::UInt16:
697  us = static_cast< quint16 >( value );
698  memcpy( data, &us, size );
699  break;
700  case Qgis::Int16:
701  s = static_cast< qint16 >( value );
702  memcpy( data, &s, size );
703  break;
704  case Qgis::UInt32:
705  ui = static_cast< quint32 >( value );
706  memcpy( data, &ui, size );
707  break;
708  case Qgis::Int32:
709  i = static_cast< qint32 >( value );
710  memcpy( data, &i, size );
711  break;
712  case Qgis::Float32:
713  f = static_cast< float >( value );
714  memcpy( data, &f, size );
715  break;
716  case Qgis::Float64:
717  d = static_cast< double >( value );
718  memcpy( data, &d, size );
719  break;
720  default:
721  QgsDebugMsg( QStringLiteral( "Data type is not supported" ) );
722  }
723  return ba;
724 }
725 
726 bool QgsRasterBlock::createNoDataBitmap()
727 {
728  mNoDataBitmapWidth = mWidth / 8 + 1;
729  mNoDataBitmapSize = static_cast< qgssize >( mNoDataBitmapWidth ) * mHeight;
730  QgsDebugMsgLevel( QStringLiteral( "allocate %1 bytes" ).arg( mNoDataBitmapSize ), 4 );
731  mNoDataBitmap = reinterpret_cast< char * >( qgsMalloc( mNoDataBitmapSize ) );
732  if ( !mNoDataBitmap )
733  {
734  QgsDebugMsg( QStringLiteral( "Couldn't allocate no data memory of %1 bytes" ).arg( mNoDataBitmapSize ) );
735  return false;
736  }
737  memset( mNoDataBitmap, 0, mNoDataBitmapSize );
738  return true;
739 }
740 
742 {
743  return QStringLiteral( "dataType = %1 width = %2 height = %3" )
744  .arg( mDataType ).arg( mWidth ).arg( mHeight );
745 }
746 
747 QRect QgsRasterBlock::subRect( const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent )
748 {
749  QgsDebugMsgLevel( "theExtent = " + extent.toString(), 4 );
750  QgsDebugMsgLevel( "theSubExtent = " + subExtent.toString(), 4 );
751  double xRes = extent.width() / width;
752  double yRes = extent.height() / height;
753 
754  QgsDebugMsgLevel( QStringLiteral( "theWidth = %1 height = %2 xRes = %3 yRes = %4" ).arg( width ).arg( height ).arg( xRes ).arg( yRes ), 4 );
755 
756  int top = 0;
757  int bottom = height - 1;
758  int left = 0;
759  int right = width - 1;
760 
761  if ( subExtent.yMaximum() < extent.yMaximum() )
762  {
763  top = std::round( ( extent.yMaximum() - subExtent.yMaximum() ) / yRes );
764  }
765  if ( subExtent.yMinimum() > extent.yMinimum() )
766  {
767  bottom = std::round( ( extent.yMaximum() - subExtent.yMinimum() ) / yRes ) - 1;
768  }
769 
770  if ( subExtent.xMinimum() > extent.xMinimum() )
771  {
772  left = std::round( ( subExtent.xMinimum() - extent.xMinimum() ) / xRes );
773  }
774  if ( subExtent.xMaximum() < extent.xMaximum() )
775  {
776  right = std::round( ( subExtent.xMaximum() - extent.xMinimum() ) / xRes ) - 1;
777  }
778  QRect subRect = QRect( left, top, right - left + 1, bottom - top + 1 );
779  QgsDebugMsgLevel( QStringLiteral( "subRect: %1 %2 %3 %4" ).arg( subRect.x() ).arg( subRect.y() ).arg( subRect.width() ).arg( subRect.height() ), 4 );
780  return subRect;
781 }
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:86
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:118
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:277
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:265
static bool typeIsNumeric(Qgis::DataType type)
Returns true if data type is numeric.
Thirty two bit unsigned integer (quint32)
Definition: qgis.h:85
DataType
Raster data types.
Definition: qgis.h:79
Thirty two bit floating point (float)
Definition: qgis.h:87
Sixteen bit signed integer (qint16)
Definition: qgis.h:84
Complex Int16.
Definition: qgis.h:89
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:88
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:94
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:91
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:81
Complex Int32.
Definition: qgis.h:90
static int typeSize(int dataType)
bool isEmpty() const
Returns true if block is empty, i.e.
Sixteen bit unsigned integer (quint16)
Definition: qgis.h:83
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:596
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:92
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:148
Eight bit unsigned integer (quint8)
Definition: qgis.h:82
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:93
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:209
QString toString() const