QGIS API Documentation  2.4.0-Chugiak
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 {
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 {
77 }
78 
80 {
81  QgsDebugMsg( QString( "mData = %1" ).arg(( ulong )mData ) );
82  qgsFree( mData );
83  delete mImage;
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;
108  mNoDataBitmap = 0;
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;
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  default:
265  QgsDebugMsg( QString( "Unknow data type %1" ).arg( dataType ) );
266  return QGis::UnknownDataType;
267  break;
268  }
269  QgsDebugMsg( QString( "newDataType = %1 noDataValue = %2" ).arg( newDataType ).arg( *noDataValue ) );
270  return newDataType;
271 }
272 
274 {
275  return mHasNoDataValue || mNoDataBitmap != 0;
276 }
277 
278 bool QgsRasterBlock::isNoDataValue( double value, double noDataValue )
279 {
280  // TODO: optimize no data value test by memcmp()
281  // More precise would be qIsNaN(value) && qIsNaN(noDataValue(bandNo)), but probably
282  // not important and slower
283  if ( qIsNaN( value ) ||
284  qgsDoubleNear( value, noDataValue ) )
285  {
286  return true;
287  }
288  return false;
289 }
290 
291 double QgsRasterBlock::value( int row, int column ) const
292 {
293  return value(( qgssize )row*mWidth + column );
294 }
295 
297 {
298  int row = floor(( double )index / mWidth );
299  int column = index % mWidth;
300  return color( row, column );
301 }
302 
303 QRgb QgsRasterBlock::color( int row, int column ) const
304 {
305  if ( !mImage ) return mNoDataColor;
306 
307  return mImage->pixel( column, row );
308 }
309 
311 {
312  if ( !mHasNoDataValue && !mNoDataBitmap ) return false;
313  if ( index >= ( qgssize )mWidth*mHeight )
314  {
315  QgsDebugMsg( QString( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
316  return true; // we consider no data if outside
317  }
318  if ( mHasNoDataValue )
319  {
320  double value = readValue( mData, mDataType, index );
321  return isNoDataValue( value );
322  }
323  // use no data bitmap
324  if ( mNoDataBitmap == 0 )
325  {
326  // no data are not defined
327  return false;
328  }
329  // TODO: optimize
330  int row = ( int ) index / mWidth;
331  int column = index % mWidth;
332  qgssize byte = ( qgssize )row * mNoDataBitmapWidth + column / 8 ;
333  int bit = column % 8;
334  int mask = 0x80 >> bit;
335  //int x = mNoDataBitmap[byte] & mask;
336  //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) ) );
337  return mNoDataBitmap[byte] & mask;
338 }
339 
340 bool QgsRasterBlock::isNoData( int row, int column )
341 {
342  return isNoData(( qgssize )row*mWidth + column );
343 }
344 
346 {
347  if ( !mData )
348  {
349  QgsDebugMsg( "Data block not allocated" );
350  return false;
351  }
352  if ( index >= ( qgssize )mWidth*mHeight )
353  {
354  QgsDebugMsg( QString( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
355  return false;
356  }
357  writeValue( mData, mDataType, index, value );
358  return true;
359 }
360 
361 bool QgsRasterBlock::setValue( int row, int column, double value )
362 {
363  return setValue(( qgssize )row*mWidth + column, value );
364 }
365 
366 bool QgsRasterBlock::setColor( int row, int column, QRgb color )
367 {
368  return setColor(( qgssize )row*mWidth + column, color );
369 }
370 
372 {
373  if ( !mImage )
374  {
375  QgsDebugMsg( "Image not allocated" );
376  return false;
377  }
378 
379  if ( index >= ( qgssize )mImage->width()* mImage->height() )
380  {
381  QgsDebugMsg( QString( "index %1 out of range" ).arg( index ) );
382  return false;
383  }
384 
385  // setPixel() is slow, see Qt doc -> use direct access
386  QRgb* bits = ( QRgb* )mImage->bits();
387  bits[index] = color;
388  return true;
389 }
390 
391 bool QgsRasterBlock::setIsNoData( int row, int column )
392 {
393  return setIsNoData(( qgssize )row*mWidth + column );
394 }
395 
397 {
398  if ( mHasNoDataValue )
399  {
400  return setValue( index, mNoDataValue );
401  }
402  else
403  {
404  if ( mNoDataBitmap == 0 )
405  {
406  if ( !createNoDataBitmap() )
407  {
408  return false;
409  }
410  }
411  // TODO: optimize
412  int row = ( int ) index / mWidth;
413  int column = index % mWidth;
414  qgssize byte = ( qgssize )row * mNoDataBitmapWidth + column / 8;
415  int bit = column % 8;
416  int nodata = 0x80 >> bit;
417  //QgsDebugMsg ( QString("set byte = %1 bit = %2 no data by %3").arg(byte).arg(bit).arg(nodata, 0,2 ) );
418  mNoDataBitmap[byte] = mNoDataBitmap[byte] | nodata;
419  return true;
420  }
421 }
422 
424 {
425  QgsDebugMsg( "Entered" );
426  if ( typeIsNumeric( mDataType ) )
427  {
428  if ( mHasNoDataValue )
429  {
430  if ( !mData )
431  {
432  QgsDebugMsg( "Data block not allocated" );
433  return false;
434  }
435 
436  QgsDebugMsg( "set mData to mNoDataValue" );
438  QByteArray noDataByteArray = valueBytes( mDataType, mNoDataValue );
439 
440  char *nodata = noDataByteArray.data();
441  for ( qgssize i = 0; i < ( qgssize )mWidth*mHeight; i++ )
442  {
443  memcpy(( char* )mData + i*dataTypeSize, nodata, dataTypeSize );
444  }
445  }
446  else
447  {
448  // use bitmap
449  if ( mNoDataBitmap == 0 )
450  {
451  if ( !createNoDataBitmap() )
452  {
453  return false;
454  }
455  }
456  QgsDebugMsg( "set mNoDataBitmap to 1" );
457  memset( mNoDataBitmap, 0xff, mNoDataBitmapSize );
458  }
459  return true;
460  }
461  else
462  {
463  // image
464  if ( !mImage )
465  {
466  QgsDebugMsg( "Image not allocated" );
467  return false;
468  }
469  QgsDebugMsg( "Fill image" );
470  mImage->fill( mNoDataColor );
471  return true;
472  }
473 }
474 
475 bool QgsRasterBlock::setIsNoDataExcept( const QRect & theExceptRect )
476 {
477  int top = theExceptRect.top();
478  int bottom = theExceptRect.bottom();
479  int left = theExceptRect.left();
480  int right = theExceptRect.right();
481  top = qMin( qMax( top, 0 ), mHeight - 1 );
482  left = qMin( qMax( left, 0 ), mWidth - 1 );
483  bottom = qMax( 0, qMin( bottom, mHeight - 1 ) );
484  right = qMax( 0, qMin( right, mWidth - 1 ) );
485 
486  QgsDebugMsg( "Entered" );
487  if ( typeIsNumeric( mDataType ) )
488  {
489  if ( mHasNoDataValue )
490  {
491  if ( !mData )
492  {
493  QgsDebugMsg( "Data block not allocated" );
494  return false;
495  }
496 
497  QgsDebugMsg( "set mData to mNoDataValue" );
499  QByteArray noDataByteArray = valueBytes( mDataType, mNoDataValue );
500 
501  char *nodata = noDataByteArray.data();
502  char *nodataRow = new char[mWidth*dataTypeSize]; // full row of no data
503  for ( int c = 0; c < mWidth; c++ )
504  {
505  memcpy( nodataRow + c*dataTypeSize, nodata, dataTypeSize );
506  }
507 
508  // top and bottom
509  for ( int r = 0; r < mHeight; r++ )
510  {
511  if ( r >= top && r <= bottom ) continue; // middle
512  qgssize i = ( qgssize )r * mWidth;
513  memcpy(( char* )mData + i*dataTypeSize, nodataRow, dataTypeSize*mWidth );
514  }
515  // middle
516  for ( int r = top; r <= bottom; r++ )
517  {
518  qgssize i = ( qgssize )r * mWidth;
519  // middle left
520  memcpy(( char* )mData + i*dataTypeSize, nodataRow, dataTypeSize*left );
521  // middle right
522  i += right + 1;
523  int w = mWidth - right - 1;
524  memcpy(( char* )mData + i*dataTypeSize, nodataRow, dataTypeSize*w );
525  }
526  delete [] nodataRow;
527  }
528  else
529  {
530  // use bitmap
531  if ( mNoDataBitmap == 0 )
532  {
533  if ( !createNoDataBitmap() )
534  {
535  return false;
536  }
537  }
538  QgsDebugMsg( "set mNoDataBitmap to 1" );
539 
540  char *nodataRow = new char[mNoDataBitmapWidth]; // full row of no data
541  // TODO: we can simply set all bytes to 11111111 (~0) I think
542  memset( nodataRow, 0, mNoDataBitmapWidth );
543  for ( int c = 0; c < mWidth; c ++ )
544  {
545  int byte = c / 8;
546  int bit = c % 8;
547  char nodata = 0x80 >> bit;
548  memset( nodataRow + byte, nodataRow[byte] | nodata, 1 );
549  }
550 
551  // top and bottom
552  for ( int r = 0; r < mHeight; r++ )
553  {
554  if ( r >= top && r <= bottom ) continue; // middle
556  memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
557  }
558  // middle
559  memset( nodataRow, 0, mNoDataBitmapWidth );
560  for ( int c = 0; c < mWidth; c ++ )
561  {
562  if ( c >= left && c <= right ) continue; // middle
563  int byte = c / 8;
564  int bit = c % 8;
565  char nodata = 0x80 >> bit;
566  memset( nodataRow + byte, nodataRow[byte] | nodata, 1 );
567  }
568  for ( int r = top; r <= bottom; r++ )
569  {
571  memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
572  }
573  delete [] nodataRow;
574  }
575  return true;
576  }
577  else
578  {
579  // image
580  if ( !mImage )
581  {
582  QgsDebugMsg( "Image not allocated" );
583  return false;
584  }
585 
586  if ( mImage->width() != mWidth || mImage->height() != mHeight )
587  {
588  QgsDebugMsg( "Image and block size differ" );
589  return false;
590  }
591 
592  QgsDebugMsg( QString( "Fill image depth = %1" ).arg( mImage->depth() ) );
593 
594  // TODO: support different depths
595  if ( mImage->depth() != 32 )
596  {
597  QgsDebugMsg( "Unsupported image depth" );
598  return false;
599  }
600 
601  QRgb nodataRgba = mNoDataColor;
602  QRgb *nodataRow = new QRgb[mWidth]; // full row of no data
603  int rgbSize = sizeof( QRgb );
604  for ( int c = 0; c < mWidth; c ++ )
605  {
606  nodataRow[c] = nodataRgba;
607  }
608 
609  // top and bottom
610  for ( int r = 0; r < mHeight; r++ )
611  {
612  if ( r >= top && r <= bottom ) continue; // middle
613  qgssize i = ( qgssize )r * mWidth;
614  memcpy(( void * )( mImage->bits() + rgbSize*i ), nodataRow, rgbSize*mWidth );
615  }
616  // middle
617  for ( int r = top; r <= bottom; r++ )
618  {
619  qgssize i = ( qgssize )r * mWidth;
620  // middle left
621  if ( left > 0 )
622  {
623  memcpy(( void * )( mImage->bits() + rgbSize*i ), nodataRow, rgbSize*( left - 1 ) );
624  }
625  // middle right
626  i += right + 1;
627  int w = mWidth - right - 1;
628  memcpy(( void * )( mImage->bits() + rgbSize*i ), nodataRow, rgbSize*w );
629  }
630  delete [] nodataRow;
631  return true;
632  }
633 }
634 
636 {
637  // Not testing type to avoid too much overhead because this method is called per pixel
638  if ( index >= ( qgssize )mWidth*mHeight )
639  {
640  QgsDebugMsg( QString( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
641  return 0;
642  }
643  if ( mData )
644  {
645  return ( char* )mData + index * mTypeSize;
646  }
647  if ( mImage && mImage->bits() )
648  {
649  return ( char* )( mImage->bits() + index * 4 );
650  }
651 
652  return 0;
653 }
654 
655 char * QgsRasterBlock::bits( int row, int column )
656 {
657  return bits(( qgssize )row*mWidth + column );
658 }
659 
661 {
662  if ( mData )
663  {
664  return ( char* )mData;
665  }
666  if ( mImage && mImage->bits() )
667  {
668  return ( char* )( mImage->bits() );
669  }
670 
671  return 0;
672 }
673 
675 {
676  if ( isEmpty() ) return false;
677  if ( destDataType == mDataType ) return true;
678 
679  if ( typeIsNumeric( mDataType ) && typeIsNumeric( destDataType ) )
680  {
681  void *data = convert( mData, mDataType, destDataType, mWidth * mHeight );
682 
683  if ( data == 0 )
684  {
685  QgsDebugMsg( "Cannot convert raster block" );
686  return false;
687  }
688  qgsFree( mData );
689  mData = data;
690  mDataType = destDataType;
692  }
693  else if ( typeIsColor( mDataType ) && typeIsColor( destDataType ) )
694  {
695  QImage::Format format = imageFormat( destDataType );
696  QImage image = mImage->convertToFormat( format );
697  *mImage = image;
698  mDataType = destDataType;
700  }
701  else
702  {
703  return false;
704  }
705 
706  return true;
707 }
708 
709 void QgsRasterBlock::applyScaleOffset( double scale, double offset )
710 {
711  if ( isEmpty() ) return;
712  if ( !typeIsNumeric( mDataType ) ) return;
713  if ( scale == 1.0 && offset == 0.0 ) return;
714 
716  for ( qgssize i = 0; i < size; ++i )
717  {
718  if ( !isNoData( i ) ) setValue( i, value( i ) * scale + offset );
719  }
720  return;
721 }
722 
724 {
725  if ( rangeList.isEmpty() )
726  {
727  return;
728  }
729 
731  for ( qgssize i = 0; i < size; ++i )
732  {
733  double val = value( i );
734  if ( QgsRasterRange::contains( val, rangeList ) )
735  {
736  //setValue( i, mNoDataValue );
737  setIsNoData( i );
738  }
739  }
740 }
741 
742 QImage QgsRasterBlock::image() const
743 {
744  if ( mImage )
745  {
746  return QImage( *mImage );
747  }
748  return QImage();
749 }
750 
751 bool QgsRasterBlock::setImage( const QImage * image )
752 {
753  qgsFree( mData );
754  mData = 0;
755  delete mImage;
756  mImage = 0;
757  mImage = new QImage( *image );
758  mWidth = mImage->width();
759  mHeight = mImage->height();
760  mDataType = dataType( mImage->format() );
762  mNoDataValue = std::numeric_limits<double>::quiet_NaN();
763  return true;
764 }
765 
766 QString QgsRasterBlock::printValue( double value )
767 {
768  /*
769  * IEEE 754 double has 15-17 significant digits. It specifies:
770  *
771  * "If a decimal string with at most 15 significant decimal is converted to
772  * IEEE 754 double precision and then converted back to the same number of
773  * significant decimal, then the final string should match the original;
774  * and if an IEEE 754 double precision is converted to a decimal string with at
775  * least 17 significant decimal and then converted back to double, then the final
776  * number must match the original."
777  *
778  * If printing only 15 digits, some precision could be lost. Printing 17 digits may
779  * add some confusing digits.
780  *
781  * Default 'g' precision on linux is 6 digits, not all significant digits like
782  * some sprintf manuals say.
783  *
784  * We need to ensure that the number printed and used in QLineEdit or XML will
785  * give the same number when parsed.
786  *
787  * Is there a better solution?
788  */
789 
790  QString s;
791 
792  for ( int i = 15; i <= 17; i++ )
793  {
794  s.setNum( value, 'g', i );
795  if ( s.toDouble() == value )
796  {
797  return s;
798  }
799  }
800  // Should not happen
801  QgsDebugMsg( "Cannot correctly parse printed value" );
802  return s;
803 }
804 
805 void * QgsRasterBlock::convert( void *srcData, QGis::DataType srcDataType, QGis::DataType destDataType, qgssize size )
806 {
807  int destDataTypeSize = typeSize( destDataType );
808  void *destData = qgsMalloc( destDataTypeSize * size );
809  for ( qgssize i = 0; i < size; i++ )
810  {
811  double value = readValue( srcData, srcDataType, i );
812  writeValue( destData, destDataType, i, value );
813  //double newValue = readValue( destData, destDataType, i );
814  //QgsDebugMsg( QString("convert %1 type %2 to %3: %4 -> %5").arg(i).arg(srcDataType).arg(destDataType).arg( value ).arg( newValue ) );
815  }
816  return destData;
817 }
818 
819 QByteArray QgsRasterBlock::valueBytes( QGis::DataType theDataType, double theValue )
820 {
821  qgssize size = QgsRasterBlock::typeSize( theDataType );
822  QByteArray ba;
823  ba.resize(( int )size );
824  char * data = ba.data();
825  quint8 uc;
826  quint16 us;
827  qint16 s;
828  quint32 ui;
829  qint32 i;
830  float f;
831  double d;
832  switch ( theDataType )
833  {
834  case QGis::Byte:
835  uc = ( quint8 )theValue;
836  memcpy( data, &uc, size );
837  break;
838  case QGis::UInt16:
839  us = ( quint16 )theValue;
840  memcpy( data, &us, size );
841  break;
842  case QGis::Int16:
843  s = ( qint16 )theValue;
844  memcpy( data, &s, size );
845  break;
846  case QGis::UInt32:
847  ui = ( quint32 )theValue;
848  memcpy( data, &ui, size );
849  break;
850  case QGis::Int32:
851  i = ( qint32 )theValue;
852  memcpy( data, &i, size );
853  break;
854  case QGis::Float32:
855  f = ( float )theValue;
856  memcpy( data, &f, size );
857  break;
858  case QGis::Float64:
859  d = ( double )theValue;
860  memcpy( data, &d, size );
861  break;
862  default:
863  QgsDebugMsg( "Data type is not supported" );
864  }
865  return ba;
866 }
867 
869 {
870  mNoDataBitmapWidth = mWidth / 8 + 1;
872  QgsDebugMsg( QString( "allocate %1 bytes" ).arg( mNoDataBitmapSize ) );
874  if ( mNoDataBitmap == 0 )
875  {
876  QgsDebugMsg( QString( "Couldn't allocate no data memory of %1 bytes" ).arg( mNoDataBitmapSize ) );
877  return false;
878  }
879  memset( mNoDataBitmap, 0, mNoDataBitmapSize );
880  return true;
881 }
882 
883 QRect QgsRasterBlock::subRect( const QgsRectangle & theExtent, int theWidth, int theHeight, const QgsRectangle & theSubExtent )
884 {
885  QgsDebugMsg( "theExtent = " + theExtent.toString() );
886  QgsDebugMsg( "theSubExtent = " + theSubExtent.toString() );
887  double xRes = theExtent.width() / theWidth;
888  double yRes = theExtent.height() / theHeight;
889 
890  QgsDebugMsg( QString( "theWidth = %1 theHeight = %2 xRes = %3 yRes = %4" ).arg( theWidth ).arg( theHeight ).arg( xRes ).arg( yRes ) );
891 
892  int top = 0;
893  int bottom = theHeight - 1;
894  int left = 0;
895  int right = theWidth - 1;
896 
897  if ( theSubExtent.yMaximum() < theExtent.yMaximum() )
898  {
899  top = qRound(( theExtent.yMaximum() - theSubExtent.yMaximum() ) / yRes );
900  }
901  if ( theSubExtent.yMinimum() > theExtent.yMinimum() )
902  {
903  bottom = qRound(( theExtent.yMaximum() - theSubExtent.yMinimum() ) / yRes ) - 1;
904  }
905 
906  if ( theSubExtent.xMinimum() > theExtent.xMinimum() )
907  {
908  left = qRound(( theSubExtent.xMinimum() - theExtent.xMinimum() ) / xRes );
909  }
910  if ( theSubExtent.xMaximum() < theExtent.xMaximum() )
911  {
912  right = qRound(( theSubExtent.xMaximum() - theExtent.xMinimum() ) / xRes ) - 1;
913  }
914  QRect subRect = QRect( left, top, right - left + 1, bottom - top + 1 );
915  QgsDebugMsg( QString( "subRect: %1 %2 %3 %4" ).arg( subRect.x() ).arg( subRect.y() ).arg( subRect.width() ).arg( subRect.height() ) );
916  return subRect;
917 }
static QImage::Format imageFormat(QGis::DataType theDataType)
static const QRgb mNoDataColor
static unsigned index
A rectangle specified with double values.
Definition: qgsrectangle.h:35
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:175
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.
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:194
static bool typeIsNumeric(QGis::DataType type)
Returns true if data type is numeric.
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
void applyNoDataValues(const QgsRasterRangeList &rangeList)
bool setValue(int row, int column, double value)
Set value on position.
QGis::DataType dataType() const
Returns data type.
The QGis class provides global constants for use throughout the application.
Definition: qgis.h:34
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:324
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.
bool setIsNoDataExcept(const QRect &theExceptRect)
Set the whole block to no data except specified rectangle.
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:199
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:184
bool setImage(const QImage *image)
set image.
double value(int row, int column) const
Read a single value if type of block is numeric.
static bool isNoDataValue(double value, double noDataValue)
Test if value is nodata comparing to noDataValue.
static bool typeIsColor(QGis::DataType type)
Returns true if data type is color.
char * bits()
Get pointer to data.
static int typeSize(int dataType)
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:424
bool reset(QGis::DataType theDataType, int theWidth, int theHeight)
Reset block.
int dataTypeSize() const
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 @note added in 2.3
static QByteArray valueBytes(QGis::DataType theDataType, double theValue)
Get byte array representing a value.
DataType
Raster data types.
Definition: qgis.h:204
QGis::DataType mDataType
QImage image() const
Get image if type is color.
qgssize mNoDataBitmapSize
QRgb color(int row, int column) const
Read a single color.
static double readValue(void *data, QGis::DataType type, qgssize index)
bool createNoDataBitmap()
Allocate no data bitmap.
static QRect subRect(const QgsRectangle &theExtent, int theWidth, int theHeight, const QgsRectangle &theSubExtent)
For theExtent and theWidht, theHeight find rectangle covered by subextent.
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:204
double size
Definition: qgssvgcache.cpp:77
QString toString(bool automaticPrecision=false) const
returns string representation of form xmin,ymin xmax,ymax
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:189
void qgsFree(void *ptr)
Frees the memory space pointed to by ptr.
Definition: qgis.cpp:205
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:209
bool isEmpty() const
Returns true if block is empty, i.e.