QGIS API Documentation  2.12.0-Lyon
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 
26 // See #9101 before any change of NODATA_COLOR!
27 const QRgb QgsRasterBlock::mNoDataColor = qRgba( 0, 0, 0, 0 );
28 
30  : mValid( true )
31  , mDataType( QGis::UnknownDataType )
32  , mTypeSize( 0 )
33  , mWidth( 0 )
34  , mHeight( 0 )
35  , mHasNoDataValue( false )
36  , mNoDataValue( std::numeric_limits<double>::quiet_NaN() )
37  , mData( 0 )
38  , mImage( 0 )
39  , mNoDataBitmap( 0 )
40  , mNoDataBitmapWidth( 0 )
41  , mNoDataBitmapSize( 0 )
42 {
43 }
44 
45 QgsRasterBlock::QgsRasterBlock( QGis::DataType theDataType, int theWidth, int theHeight )
46  : mValid( true )
47  , mDataType( theDataType )
48  , mTypeSize( 0 )
49  , mWidth( theWidth )
50  , mHeight( theHeight )
51  , mHasNoDataValue( false )
52  , mNoDataValue( std::numeric_limits<double>::quiet_NaN() )
53  , mData( 0 )
54  , mImage( 0 )
55  , mNoDataBitmap( 0 )
56  , mNoDataBitmapWidth( 0 )
57  , mNoDataBitmapSize( 0 )
58 {
59  ( void )reset( mDataType, mWidth, mHeight );
60 }
61 
62 QgsRasterBlock::QgsRasterBlock( QGis::DataType theDataType, int theWidth, int theHeight, double theNoDataValue )
63  : mValid( true )
64  , mDataType( theDataType )
65  , mTypeSize( 0 )
66  , mWidth( theWidth )
67  , mHeight( theHeight )
68  , mHasNoDataValue( true )
69  , mNoDataValue( theNoDataValue )
70  , mData( 0 )
71  , mImage( 0 )
72  , mNoDataBitmap( 0 )
73  , mNoDataBitmapWidth( 0 )
74  , mNoDataBitmapSize( 0 )
75 {
76  ( void )reset( mDataType, mWidth, mHeight, mNoDataValue );
77 }
78 
80 {
81  QgsDebugMsg( QString( "mData = %1" ).arg(( ulong )mData ) );
82  qgsFree( mData );
83  delete mImage;
84  qgsFree( mNoDataBitmap );
85 }
86 
87 bool QgsRasterBlock::reset( QGis::DataType theDataType, int theWidth, int theHeight )
88 {
89  QgsDebugMsg( QString( "theWidth= %1 theHeight = %2 theDataType = %3" ).arg( theWidth ).arg( theHeight ).arg( theDataType ) );
90  if ( !reset( theDataType, theWidth, theHeight, std::numeric_limits<double>::quiet_NaN() ) )
91  {
92  return false;
93  }
94  mHasNoDataValue = false;
95  // the mNoDataBitmap is created only if necessary (usually, it is not) in setIsNoData()
96  return true;
97 }
98 
99 bool QgsRasterBlock::reset( QGis::DataType theDataType, int theWidth, int theHeight, double theNoDataValue )
100 {
101  QgsDebugMsg( QString( "theWidth= %1 theHeight = %2 theDataType = %3 theNoDataValue = %4" ).arg( theWidth ).arg( theHeight ).arg( theDataType ).arg( theNoDataValue ) );
102 
103  qgsFree( mData );
104  mData = 0;
105  delete mImage;
106  mImage = 0;
107  qgsFree( mNoDataBitmap );
108  mNoDataBitmap = 0;
109  mDataType = QGis::UnknownDataType;
110  mTypeSize = 0;
111  mWidth = 0;
112  mHeight = 0;
113  mHasNoDataValue = false;
114  mNoDataValue = std::numeric_limits<double>::quiet_NaN();
115  mValid = false;
116 
117  if ( typeIsNumeric( theDataType ) )
118  {
119  QgsDebugMsg( "Numeric type" );
120  qgssize tSize = typeSize( theDataType );
121  QgsDebugMsg( QString( "allocate %1 bytes" ).arg( tSize * theWidth * theHeight ) );
122  mData = qgsMalloc( tSize * theWidth * theHeight );
123  if ( mData == 0 )
124  {
125  QgsDebugMsg( QString( "Couldn't allocate data memory of %1 bytes" ).arg( tSize * theWidth * theHeight ) );
126  return false;
127  }
128  }
129  else if ( typeIsColor( theDataType ) )
130  {
131  QgsDebugMsg( "Color type" );
132  QImage::Format format = imageFormat( theDataType );
133  mImage = new QImage( theWidth, theHeight, format );
134  }
135  else
136  {
137  QgsDebugMsg( "Wrong data type" );
138  return false;
139  }
140 
141  mValid = true;
142  mDataType = theDataType;
143  mTypeSize = QgsRasterBlock::typeSize( mDataType );
144  mWidth = theWidth;
145  mHeight = theHeight;
146  mHasNoDataValue = true;
147  mNoDataValue = theNoDataValue;
148  QgsDebugMsg( QString( "mWidth= %1 mHeight = %2 mDataType = %3 mData = %4 mImage = %5" ).arg( mWidth ).arg( mHeight ).arg( mDataType ).arg(( ulong )mData ).arg(( ulong )mImage ) );
149  return true;
150 }
151 
152 QImage::Format QgsRasterBlock::imageFormat( QGis::DataType theDataType )
153 {
154  if ( theDataType == QGis::ARGB32 )
155  {
156  return QImage::Format_ARGB32;
157  }
158  else if ( theDataType == QGis::ARGB32_Premultiplied )
159  {
160  return QImage::Format_ARGB32_Premultiplied;
161  }
162  return QImage::Format_Invalid;
163 }
164 
165 QGis::DataType QgsRasterBlock::dataType( QImage::Format theFormat )
166 {
167  if ( theFormat == QImage::Format_ARGB32 )
168  {
169  return QGis::ARGB32;
170  }
171  else if ( theFormat == QImage::Format_ARGB32_Premultiplied )
172  {
174  }
175  return QGis::UnknownDataType;
176 }
177 
179 {
180  QgsDebugMsg( QString( "mWidth= %1 mHeight = %2 mDataType = %3 mData = %4 mImage = %5" ).arg( mWidth ).arg( mHeight ).arg( mDataType ).arg(( ulong )mData ).arg(( ulong )mImage ) );
181  if ( mWidth == 0 || mHeight == 0 ||
182  ( typeIsNumeric( mDataType ) && mData == 0 ) ||
183  ( typeIsColor( mDataType ) && mImage == 0 ) )
184  {
185  return true;
186  }
187  return false;
188 }
189 
191 {
192  switch ( dataType )
193  {
194  case QGis::Byte:
195  case QGis::UInt16:
196  case QGis::Int16:
197  case QGis::UInt32:
198  case QGis::Int32:
199  case QGis::Float32:
200  case QGis::CInt16:
201  case QGis::Float64:
202  case QGis::CInt32:
203  case QGis::CFloat32:
204  case QGis::CFloat64:
205  return true;
206 
208  case QGis::ARGB32:
210  return false;
211  }
212  return false;
213 }
214 
216 {
217  switch ( dataType )
218  {
219  case QGis::ARGB32:
221  return true;
222 
224  case QGis::Byte:
225  case QGis::UInt16:
226  case QGis::Int16:
227  case QGis::UInt32:
228  case QGis::Int32:
229  case QGis::Float32:
230  case QGis::CInt16:
231  case QGis::Float64:
232  case QGis::CInt32:
233  case QGis::CFloat32:
234  case QGis::CFloat64:
235  return false;
236  }
237  return false;
238 }
239 
241 {
242  QGis::DataType newDataType;
243 
244  switch ( dataType )
245  {
246  case QGis::Byte:
247  *noDataValue = -32768.0;
248  newDataType = QGis::Int16;
249  break;
250  case QGis::Int16:
251  *noDataValue = -2147483648.0;
252  newDataType = QGis::Int32;
253  break;
254  case QGis::UInt16:
255  *noDataValue = -2147483648.0;
256  newDataType = QGis::Int32;
257  break;
258  case QGis::UInt32:
259  case QGis::Int32:
260  case QGis::Float32:
261  case QGis::Float64:
262  *noDataValue = std::numeric_limits<double>::max() * -1.0;
263  newDataType = QGis::Float64;
264  break;
265  default:
266  QgsDebugMsg( QString( "Unknow data type %1" ).arg( dataType ) );
267  return QGis::UnknownDataType;
268  break;
269  }
270  QgsDebugMsg( QString( "newDataType = %1 noDataValue = %2" ).arg( newDataType ).arg( *noDataValue ) );
271  return newDataType;
272 }
273 
275 {
276  return mHasNoDataValue || mNoDataBitmap != 0;
277 }
278 
279 bool QgsRasterBlock::isNoDataValue( double value, double noDataValue )
280 {
281  // TODO: optimize no data value test by memcmp()
282  // More precise would be qIsNaN(value) && qIsNaN(noDataValue(bandNo)), but probably
283  // not important and slower
284  if ( qIsNaN( value ) ||
285  qgsDoubleNear( value, noDataValue ) )
286  {
287  return true;
288  }
289  return false;
290 }
291 
292 double QgsRasterBlock::value( int row, int column ) const
293 {
294  return value(( qgssize )row*mWidth + column );
295 }
296 
298 {
299  int row = floor(( double )index / mWidth );
300  int column = index % mWidth;
301  return color( row, column );
302 }
303 
304 QRgb QgsRasterBlock::color( int row, int column ) const
305 {
306  if ( !mImage ) return mNoDataColor;
307 
308  return mImage->pixel( column, row );
309 }
310 
312 {
313  if ( !mHasNoDataValue && !mNoDataBitmap ) return false;
314  if ( index >= ( qgssize )mWidth*mHeight )
315  {
316  QgsDebugMsg( QString( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
317  return true; // we consider no data if outside
318  }
319  if ( mHasNoDataValue )
320  {
321  double value = readValue( mData, mDataType, index );
322  return isNoDataValue( value );
323  }
324  // use no data bitmap
325  if ( mNoDataBitmap == 0 )
326  {
327  // no data are not defined
328  return false;
329  }
330  // TODO: optimize
331  int row = ( int ) index / mWidth;
332  int column = index % mWidth;
333  qgssize byte = ( qgssize )row * mNoDataBitmapWidth + column / 8;
334  int bit = column % 8;
335  int mask = 0x80 >> bit;
336  //int x = mNoDataBitmap[byte] & mask;
337  //QgsDebugMsg ( QString("byte = %1 bit = %2 mask = %3 nodata = %4 is nodata = %5").arg(byte).arg(bit).arg(mask, 0, 2 ).arg( x, 0, 2 ).arg( (bool)(x) ) );
338  return mNoDataBitmap[byte] & mask;
339 }
340 
341 bool QgsRasterBlock::isNoData( int row, int column )
342 {
343  return isNoData(( qgssize )row*mWidth + column );
344 }
345 
347 {
348  if ( !mData )
349  {
350  QgsDebugMsg( "Data block not allocated" );
351  return false;
352  }
353  if ( index >= ( qgssize )mWidth*mHeight )
354  {
355  QgsDebugMsg( QString( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
356  return false;
357  }
358  writeValue( mData, mDataType, index, value );
359  return true;
360 }
361 
362 bool QgsRasterBlock::setValue( int row, int column, double value )
363 {
364  return setValue(( qgssize )row*mWidth + column, value );
365 }
366 
367 bool QgsRasterBlock::setColor( int row, int column, QRgb color )
368 {
369  return setColor(( qgssize )row*mWidth + column, color );
370 }
371 
373 {
374  if ( !mImage )
375  {
376  QgsDebugMsg( "Image not allocated" );
377  return false;
378  }
379 
380  if ( index >= ( qgssize )mImage->width()* mImage->height() )
381  {
382  QgsDebugMsg( QString( "index %1 out of range" ).arg( index ) );
383  return false;
384  }
385 
386  // setPixel() is slow, see Qt doc -> use direct access
387  QRgb* bits = ( QRgb* )mImage->bits();
388  bits[index] = color;
389  return true;
390 }
391 
392 bool QgsRasterBlock::setIsNoData( int row, int column )
393 {
394  return setIsNoData(( qgssize )row*mWidth + column );
395 }
396 
398 {
399  if ( mHasNoDataValue )
400  {
401  return setValue( index, mNoDataValue );
402  }
403  else
404  {
405  if ( mNoDataBitmap == 0 )
406  {
407  if ( !createNoDataBitmap() )
408  {
409  return false;
410  }
411  }
412  // TODO: optimize
413  int row = ( int ) index / mWidth;
414  int column = index % mWidth;
415  qgssize byte = ( qgssize )row * mNoDataBitmapWidth + column / 8;
416  int bit = column % 8;
417  int nodata = 0x80 >> bit;
418  //QgsDebugMsg ( QString("set byte = %1 bit = %2 no data by %3").arg(byte).arg(bit).arg(nodata, 0,2 ) );
419  mNoDataBitmap[byte] = mNoDataBitmap[byte] | nodata;
420  return true;
421  }
422 }
423 
425 {
426  QgsDebugMsg( "Entered" );
427  if ( typeIsNumeric( mDataType ) )
428  {
429  if ( mHasNoDataValue )
430  {
431  if ( !mData )
432  {
433  QgsDebugMsg( "Data block not allocated" );
434  return false;
435  }
436 
437  QgsDebugMsg( "set mData to mNoDataValue" );
438  int dataTypeSize = typeSize( mDataType );
439  QByteArray noDataByteArray = valueBytes( mDataType, mNoDataValue );
440 
441  char *nodata = noDataByteArray.data();
442  for ( qgssize i = 0; i < ( qgssize )mWidth*mHeight; i++ )
443  {
444  memcpy(( char* )mData + i*dataTypeSize, nodata, dataTypeSize );
445  }
446  }
447  else
448  {
449  // use bitmap
450  if ( mNoDataBitmap == 0 )
451  {
452  if ( !createNoDataBitmap() )
453  {
454  return false;
455  }
456  }
457  QgsDebugMsg( "set mNoDataBitmap to 1" );
458  memset( mNoDataBitmap, 0xff, mNoDataBitmapSize );
459  }
460  return true;
461  }
462  else
463  {
464  // image
465  if ( !mImage )
466  {
467  QgsDebugMsg( "Image not allocated" );
468  return false;
469  }
470  QgsDebugMsg( "Fill image" );
471  mImage->fill( mNoDataColor );
472  return true;
473  }
474 }
475 
476 bool QgsRasterBlock::setIsNoDataExcept( const QRect & theExceptRect )
477 {
478  int top = theExceptRect.top();
479  int bottom = theExceptRect.bottom();
480  int left = theExceptRect.left();
481  int right = theExceptRect.right();
482  top = qMin( qMax( top, 0 ), mHeight - 1 );
483  left = qMin( qMax( left, 0 ), mWidth - 1 );
484  bottom = qMax( 0, qMin( bottom, mHeight - 1 ) );
485  right = qMax( 0, qMin( right, mWidth - 1 ) );
486 
487  QgsDebugMsg( "Entered" );
488  if ( typeIsNumeric( mDataType ) )
489  {
490  if ( mHasNoDataValue )
491  {
492  if ( !mData )
493  {
494  QgsDebugMsg( "Data block not allocated" );
495  return false;
496  }
497 
498  QgsDebugMsg( "set mData to mNoDataValue" );
499  int dataTypeSize = typeSize( mDataType );
500  QByteArray noDataByteArray = valueBytes( mDataType, mNoDataValue );
501 
502  char *nodata = noDataByteArray.data();
503  char *nodataRow = new char[mWidth*dataTypeSize]; // full row of no data
504  for ( int c = 0; c < mWidth; c++ )
505  {
506  memcpy( nodataRow + c*dataTypeSize, nodata, dataTypeSize );
507  }
508 
509  // top and bottom
510  for ( int r = 0; r < mHeight; r++ )
511  {
512  if ( r >= top && r <= bottom ) continue; // middle
513  qgssize i = ( qgssize )r * mWidth;
514  memcpy(( char* )mData + i*dataTypeSize, nodataRow, dataTypeSize*mWidth );
515  }
516  // middle
517  for ( int r = top; r <= bottom; r++ )
518  {
519  qgssize i = ( qgssize )r * mWidth;
520  // middle left
521  memcpy(( char* )mData + i*dataTypeSize, nodataRow, dataTypeSize*left );
522  // middle right
523  i += right + 1;
524  int w = mWidth - right - 1;
525  memcpy(( char* )mData + i*dataTypeSize, nodataRow, dataTypeSize*w );
526  }
527  delete [] nodataRow;
528  }
529  else
530  {
531  // use bitmap
532  if ( mNoDataBitmap == 0 )
533  {
534  if ( !createNoDataBitmap() )
535  {
536  return false;
537  }
538  }
539  QgsDebugMsg( "set mNoDataBitmap to 1" );
540 
541  char *nodataRow = new char[mNoDataBitmapWidth]; // full row of no data
542  // TODO: we can simply set all bytes to 11111111 (~0) I think
543  memset( nodataRow, 0, mNoDataBitmapWidth );
544  for ( int c = 0; c < mWidth; c ++ )
545  {
546  int byte = c / 8;
547  int bit = c % 8;
548  char nodata = 0x80 >> bit;
549  memset( nodataRow + byte, nodataRow[byte] | nodata, 1 );
550  }
551 
552  // top and bottom
553  for ( int r = 0; r < mHeight; r++ )
554  {
555  if ( r >= top && r <= bottom ) continue; // middle
556  qgssize i = ( qgssize )r * mNoDataBitmapWidth;
557  memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
558  }
559  // middle
560  memset( nodataRow, 0, mNoDataBitmapWidth );
561  for ( int c = 0; c < mWidth; c ++ )
562  {
563  if ( c >= left && c <= right ) continue; // middle
564  int byte = c / 8;
565  int bit = c % 8;
566  char nodata = 0x80 >> bit;
567  memset( nodataRow + byte, nodataRow[byte] | nodata, 1 );
568  }
569  for ( int r = top; r <= bottom; r++ )
570  {
571  qgssize i = ( qgssize )r * mNoDataBitmapWidth;
572  memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
573  }
574  delete [] nodataRow;
575  }
576  return true;
577  }
578  else
579  {
580  // image
581  if ( !mImage )
582  {
583  QgsDebugMsg( "Image not allocated" );
584  return false;
585  }
586 
587  if ( mImage->width() != mWidth || mImage->height() != mHeight )
588  {
589  QgsDebugMsg( "Image and block size differ" );
590  return false;
591  }
592 
593  QgsDebugMsg( QString( "Fill image depth = %1" ).arg( mImage->depth() ) );
594 
595  // TODO: support different depths
596  if ( mImage->depth() != 32 )
597  {
598  QgsDebugMsg( "Unsupported image depth" );
599  return false;
600  }
601 
602  QRgb nodataRgba = mNoDataColor;
603  QRgb *nodataRow = new QRgb[mWidth]; // full row of no data
604  int rgbSize = sizeof( QRgb );
605  for ( int c = 0; c < mWidth; c ++ )
606  {
607  nodataRow[c] = nodataRgba;
608  }
609 
610  // top and bottom
611  for ( int r = 0; r < mHeight; r++ )
612  {
613  if ( r >= top && r <= bottom ) continue; // middle
614  qgssize i = ( qgssize )r * mWidth;
615  memcpy(( void * )( mImage->bits() + rgbSize*i ), nodataRow, rgbSize*mWidth );
616  }
617  // middle
618  for ( int r = top; r <= bottom; r++ )
619  {
620  qgssize i = ( qgssize )r * mWidth;
621  // middle left
622  if ( left > 0 )
623  {
624  memcpy(( void * )( mImage->bits() + rgbSize*i ), nodataRow, rgbSize*( left - 1 ) );
625  }
626  // middle right
627  i += right + 1;
628  int w = mWidth - right - 1;
629  memcpy(( void * )( mImage->bits() + rgbSize*i ), nodataRow, rgbSize*w );
630  }
631  delete [] nodataRow;
632  return true;
633  }
634 }
635 
636 void QgsRasterBlock::setIsData( int row, int column )
637 {
638  setIsData(( qgssize )row*mWidth + column );
639 }
640 
642 {
643  if ( mHasNoDataValue )
644  {
645  //no data value set, so mNoDataBitmap is not being used
646  return;
647  }
648 
649  if ( mNoDataBitmap == 0 )
650  {
651  return;
652  }
653 
654  // TODO: optimize
655  int row = ( int ) index / mWidth;
656  int column = index % mWidth;
657  qgssize byte = ( qgssize )row * mNoDataBitmapWidth + column / 8;
658  int bit = column % 8;
659  int nodata = 0x80 >> bit;
660  mNoDataBitmap[byte] = mNoDataBitmap[byte] & ~nodata;
661 }
662 
664 {
665  // Not testing type to avoid too much overhead because this method is called per pixel
666  if ( index >= ( qgssize )mWidth*mHeight )
667  {
668  QgsDebugMsg( QString( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
669  return 0;
670  }
671  if ( mData )
672  {
673  return ( char* )mData + index * mTypeSize;
674  }
675  if ( mImage && mImage->bits() )
676  {
677  return ( char* )( mImage->bits() + index * 4 );
678  }
679 
680  return 0;
681 }
682 
683 char * QgsRasterBlock::bits( int row, int column )
684 {
685  return bits(( qgssize )row*mWidth + column );
686 }
687 
689 {
690  if ( mData )
691  {
692  return ( char* )mData;
693  }
694  if ( mImage && mImage->bits() )
695  {
696  return ( char* )( mImage->bits() );
697  }
698 
699  return 0;
700 }
701 
703 {
704  if ( isEmpty() ) return false;
705  if ( destDataType == mDataType ) return true;
706 
707  if ( typeIsNumeric( mDataType ) && typeIsNumeric( destDataType ) )
708  {
709  void *data = convert( mData, mDataType, destDataType, ( qgssize )mWidth * ( qgssize )mHeight );
710 
711  if ( data == 0 )
712  {
713  QgsDebugMsg( "Cannot convert raster block" );
714  return false;
715  }
716  qgsFree( mData );
717  mData = data;
718  mDataType = destDataType;
719  mTypeSize = typeSize( mDataType );
720  }
721  else if ( typeIsColor( mDataType ) && typeIsColor( destDataType ) )
722  {
723  QImage::Format format = imageFormat( destDataType );
724  QImage image = mImage->convertToFormat( format );
725  *mImage = image;
726  mDataType = destDataType;
727  mTypeSize = typeSize( mDataType );
728  }
729  else
730  {
731  return false;
732  }
733 
734  return true;
735 }
736 
737 void QgsRasterBlock::applyScaleOffset( double scale, double offset )
738 {
739  if ( isEmpty() ) return;
740  if ( !typeIsNumeric( mDataType ) ) return;
741  if ( scale == 1.0 && offset == 0.0 ) return;
742 
743  qgssize size = ( qgssize ) mWidth * mHeight;
744  for ( qgssize i = 0; i < size; ++i )
745  {
746  if ( !isNoData( i ) ) setValue( i, value( i ) * scale + offset );
747  }
748  return;
749 }
750 
752 {
753  if ( rangeList.isEmpty() )
754  {
755  return;
756  }
757 
758  qgssize size = ( qgssize )mWidth * ( qgssize )mHeight;
759  for ( qgssize i = 0; i < size; ++i )
760  {
761  double val = value( i );
762  if ( QgsRasterRange::contains( val, rangeList ) )
763  {
764  //setValue( i, mNoDataValue );
765  setIsNoData( i );
766  }
767  }
768 }
769 
771 {
772  if ( mImage )
773  {
774  return QImage( *mImage );
775  }
776  return QImage();
777 }
778 
779 bool QgsRasterBlock::setImage( const QImage * image )
780 {
781  qgsFree( mData );
782  mData = 0;
783  delete mImage;
784  mImage = 0;
785  mImage = new QImage( *image );
786  mWidth = mImage->width();
787  mHeight = mImage->height();
788  mDataType = dataType( mImage->format() );
789  mTypeSize = QgsRasterBlock::typeSize( mDataType );
790  mNoDataValue = std::numeric_limits<double>::quiet_NaN();
791  return true;
792 }
793 
795 {
796  /*
797  * IEEE 754 double has 15-17 significant digits. It specifies:
798  *
799  * "If a decimal string with at most 15 significant decimal is converted to
800  * IEEE 754 double precision and then converted back to the same number of
801  * significant decimal, then the final string should match the original;
802  * and if an IEEE 754 double precision is converted to a decimal string with at
803  * least 17 significant decimal and then converted back to double, then the final
804  * number must match the original."
805  *
806  * If printing only 15 digits, some precision could be lost. Printing 17 digits may
807  * add some confusing digits.
808  *
809  * Default 'g' precision on linux is 6 digits, not all significant digits like
810  * some sprintf manuals say.
811  *
812  * We need to ensure that the number printed and used in QLineEdit or XML will
813  * give the same number when parsed.
814  *
815  * Is there a better solution?
816  */
817 
818  QString s;
819 
820  for ( int i = 15; i <= 17; i++ )
821  {
822  s.setNum( value, 'g', i );
823  if ( s.toDouble() == value )
824  {
825  return s;
826  }
827  }
828  // Should not happen
829  QgsDebugMsg( "Cannot correctly parse printed value" );
830  return s;
831 }
832 
833 void * QgsRasterBlock::convert( void *srcData, QGis::DataType srcDataType, QGis::DataType destDataType, qgssize size )
834 {
835  int destDataTypeSize = typeSize( destDataType );
836  void *destData = qgsMalloc( destDataTypeSize * size );
837  for ( qgssize i = 0; i < size; i++ )
838  {
839  double value = readValue( srcData, srcDataType, i );
840  writeValue( destData, destDataType, i, value );
841  //double newValue = readValue( destData, destDataType, i );
842  //QgsDebugMsg( QString("convert %1 type %2 to %3: %4 -> %5").arg(i).arg(srcDataType).arg(destDataType).arg( value ).arg( newValue ) );
843  }
844  return destData;
845 }
846 
847 QByteArray QgsRasterBlock::valueBytes( QGis::DataType theDataType, double theValue )
848 {
849  qgssize size = QgsRasterBlock::typeSize( theDataType );
850  QByteArray ba;
851  ba.resize(( int )size );
852  char * data = ba.data();
853  quint8 uc;
854  quint16 us;
855  qint16 s;
856  quint32 ui;
857  qint32 i;
858  float f;
859  double d;
860  switch ( theDataType )
861  {
862  case QGis::Byte:
863  uc = ( quint8 )theValue;
864  memcpy( data, &uc, size );
865  break;
866  case QGis::UInt16:
867  us = ( quint16 )theValue;
868  memcpy( data, &us, size );
869  break;
870  case QGis::Int16:
871  s = ( qint16 )theValue;
872  memcpy( data, &s, size );
873  break;
874  case QGis::UInt32:
875  ui = ( quint32 )theValue;
876  memcpy( data, &ui, size );
877  break;
878  case QGis::Int32:
879  i = ( qint32 )theValue;
880  memcpy( data, &i, size );
881  break;
882  case QGis::Float32:
883  f = ( float )theValue;
884  memcpy( data, &f, size );
885  break;
886  case QGis::Float64:
887  d = ( double )theValue;
888  memcpy( data, &d, size );
889  break;
890  default:
891  QgsDebugMsg( "Data type is not supported" );
892  }
893  return ba;
894 }
895 
896 bool QgsRasterBlock::createNoDataBitmap()
897 {
898  mNoDataBitmapWidth = mWidth / 8 + 1;
899  mNoDataBitmapSize = ( qgssize )mNoDataBitmapWidth * mHeight;
900  QgsDebugMsg( QString( "allocate %1 bytes" ).arg( mNoDataBitmapSize ) );
901  mNoDataBitmap = ( char* )qgsMalloc( mNoDataBitmapSize );
902  if ( mNoDataBitmap == 0 )
903  {
904  QgsDebugMsg( QString( "Couldn't allocate no data memory of %1 bytes" ).arg( mNoDataBitmapSize ) );
905  return false;
906  }
907  memset( mNoDataBitmap, 0, mNoDataBitmapSize );
908  return true;
909 }
910 
912 {
913  return QString( "dataType = %1 width = %2 height = %3" )
914  .arg( mDataType ).arg( mWidth ).arg( mHeight );
915 }
916 
917 QRect QgsRasterBlock::subRect( const QgsRectangle & theExtent, int theWidth, int theHeight, const QgsRectangle & theSubExtent )
918 {
919  QgsDebugMsg( "theExtent = " + theExtent.toString() );
920  QgsDebugMsg( "theSubExtent = " + theSubExtent.toString() );
921  double xRes = theExtent.width() / theWidth;
922  double yRes = theExtent.height() / theHeight;
923 
924  QgsDebugMsg( QString( "theWidth = %1 theHeight = %2 xRes = %3 yRes = %4" ).arg( theWidth ).arg( theHeight ).arg( xRes ).arg( yRes ) );
925 
926  int top = 0;
927  int bottom = theHeight - 1;
928  int left = 0;
929  int right = theWidth - 1;
930 
931  if ( theSubExtent.yMaximum() < theExtent.yMaximum() )
932  {
933  top = qRound(( theExtent.yMaximum() - theSubExtent.yMaximum() ) / yRes );
934  }
935  if ( theSubExtent.yMinimum() > theExtent.yMinimum() )
936  {
937  bottom = qRound(( theExtent.yMaximum() - theSubExtent.yMinimum() ) / yRes ) - 1;
938  }
939 
940  if ( theSubExtent.xMinimum() > theExtent.xMinimum() )
941  {
942  left = qRound(( theSubExtent.xMinimum() - theExtent.xMinimum() ) / xRes );
943  }
944  if ( theSubExtent.xMaximum() < theExtent.xMaximum() )
945  {
946  right = qRound(( theSubExtent.xMaximum() - theExtent.xMinimum() ) / xRes ) - 1;
947  }
948  QRect subRect = QRect( left, top, right - left + 1, bottom - top + 1 );
949  QgsDebugMsg( QString( "subRect: %1 %2 %3 %4" ).arg( subRect.x() ).arg( subRect.y() ).arg( subRect.width() ).arg( subRect.height() ) );
950  return subRect;
951 }
Sixty four bit floating point (double)
Definition: qgis.h:131
QImage convertToFormat(Format format, QFlags< Qt::ImageConversionFlag > flags) const
Sixteen bit signed integer (qint16)
Definition: qgis.h:127
static unsigned index
A rectangle specified with double values.
Definition: qgsrectangle.h:35
Complex Float64.
Definition: qgis.h:135
bool convert(QGis::DataType destDataType)
Convert data to different type.
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:253
bool setIsNoData()
Set the whole block to no data.
static bool contains(double value, const QgsRasterRangeList &rangeList)
Test if value is within the list of ranges.
int right() const
Eight bit unsigned integer (quint8)
Definition: qgis.h:125
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:196
Sixteen bit unsigned integer (quint16)
Definition: qgis.h:126
static bool typeIsNumeric(QGis::DataType type)
Returns true if data type is numeric.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void applyNoDataValues(const QgsRasterRangeList &rangeList)
bool setValue(int row, int column, double value)
Set value on position.
int depth() const
QGis::DataType dataType() const
Returns data type.
int height() const
int x() const
int y() const
The QGis class provides global constants for use throughout the application.
Definition: qgis.h:36
double toDouble(bool *ok) const
bool isNoData(int row, int column)
Check if value at position is no data.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:268
void resize(int size)
double ANALYSIS_EXPORT max(double x, double y)
Returns the maximum of two doubles or the first argument if both are equal.
bool setColor(int row, int column, QRgb color)
Set color on position.
virtual ~QgsRasterBlock()
static QGis::DataType typeWithNoDataValue(QGis::DataType dataType, double *noDataValue)
For given data type returns wider type and sets no data value.
QRgb pixel(int x, int y) const
bool setIsNoDataExcept(const QRect &theExceptRect)
Set the whole block to no data except specified rectangle.
Thirty two bit floating point (float)
Definition: qgis.h:130
bool hasNoData() const
Returns true if the block may contain no data.
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:201
void fill(uint pixelValue)
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:186
bool setImage(const QImage *image)
set image.
int top() const
double value(int row, int column) const
Read a single value if type of block is numeric.
int width() const
int left() const
bool isEmpty() const
static bool typeIsColor(QGis::DataType type)
Returns true if data type is color.
void setIsData(int row, int column)
Remove no data flag on pixel.
char * bits()
Get pointer to data.
static int typeSize(int dataType)
DataType
Raster data types.
Definition: qgis.h:122
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:375
bool reset(QGis::DataType theDataType, int theWidth, int theHeight)
Reset block.
QString toString() const
int dataTypeSize() const
Complex Int16.
Definition: qgis.h:132
static void writeValue(void *data, QGis::DataType type, qgssize index, double value)
Thirty two bit signed integer (qint32)
Definition: qgis.h:129
int width() const
void applyScaleOffset(double scale, double offset)
Apply band scale and offset to raster block values @note added in 2.3.
Unknown or unspecified type.
Definition: qgis.h:124
QString & setNum(short n, int base)
static QByteArray valueBytes(QGis::DataType theDataType, double theValue)
Get byte array representing a value.
int bottom() const
char * data()
uchar * bits()
QImage image() const
Get image if type is color.
int height() const
Complex Int32.
Definition: qgis.h:133
QRgb color(int row, int column) const
Read a single color.
static double readValue(void *data, QGis::DataType type, qgssize index)
static QRect subRect(const QgsRectangle &theExtent, int theWidth, int theHeight, const QgsRectangle &theSubExtent)
For theExtent and theWidht, theHeight find rectangle covered by subextent.
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:137
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:206
QString toString(bool automaticPrecision=false) const
returns string representation of form xmin,ymin xmax,ymax
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:139
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:191
void qgsFree(void *ptr)
Frees the memory space pointed to by ptr.
Definition: qgis.cpp:283
Format format() const
Thirty two bit unsigned integer (quint32)
Definition: qgis.h:128
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:211
Complex Float32.
Definition: qgis.h:134
bool isEmpty() const
Returns true if block is empty, i.e.