QGIS API Documentation  2.2.0-Valmiera
 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 
710 {
711  if ( rangeList.isEmpty() )
712  {
713  return;
714  }
715 
717  for ( qgssize i = 0; i < size; ++i )
718  {
719  double val = value( i );
720  if ( QgsRasterRange::contains( val, rangeList ) )
721  {
722  //setValue( i, mNoDataValue );
723  setIsNoData( i );
724  }
725  }
726 }
727 
728 QImage QgsRasterBlock::image() const
729 {
730  if ( mImage )
731  {
732  return QImage( *mImage );
733  }
734  return QImage();
735 }
736 
737 bool QgsRasterBlock::setImage( const QImage * image )
738 {
739  qgsFree( mData );
740  mData = 0;
741  delete mImage;
742  mImage = 0;
743  mImage = new QImage( *image );
744  mWidth = mImage->width();
745  mHeight = mImage->height();
746  mDataType = dataType( mImage->format() );
748  mNoDataValue = std::numeric_limits<double>::quiet_NaN();
749  return true;
750 }
751 
752 QString QgsRasterBlock::printValue( double value )
753 {
754  /*
755  * IEEE 754 double has 15-17 significant digits. It specifies:
756  *
757  * "If a decimal string with at most 15 significant decimal is converted to
758  * IEEE 754 double precision and then converted back to the same number of
759  * significant decimal, then the final string should match the original;
760  * and if an IEEE 754 double precision is converted to a decimal string with at
761  * least 17 significant decimal and then converted back to double, then the final
762  * number must match the original."
763  *
764  * If printing only 15 digits, some precision could be lost. Printing 17 digits may
765  * add some confusing digits.
766  *
767  * Default 'g' precision on linux is 6 digits, not all significant digits like
768  * some sprintf manuals say.
769  *
770  * We need to ensure that the number printed and used in QLineEdit or XML will
771  * give the same number when parsed.
772  *
773  * Is there a better solution?
774  */
775 
776  QString s;
777 
778  for ( int i = 15; i <= 17; i++ )
779  {
780  s.setNum( value, 'g', i );
781  if ( s.toDouble() == value )
782  {
783  return s;
784  }
785  }
786  // Should not happen
787  QgsDebugMsg( "Cannot correctly parse printed value" );
788  return s;
789 }
790 
791 void * QgsRasterBlock::convert( void *srcData, QGis::DataType srcDataType, QGis::DataType destDataType, qgssize size )
792 {
793  int destDataTypeSize = typeSize( destDataType );
794  void *destData = qgsMalloc( destDataTypeSize * size );
795  for ( qgssize i = 0; i < size; i++ )
796  {
797  double value = readValue( srcData, srcDataType, i );
798  writeValue( destData, destDataType, i, value );
799  //double newValue = readValue( destData, destDataType, i );
800  //QgsDebugMsg( QString("convert %1 type %2 to %3: %4 -> %5").arg(i).arg(srcDataType).arg(destDataType).arg( value ).arg( newValue ) );
801  }
802  return destData;
803 }
804 
805 QByteArray QgsRasterBlock::valueBytes( QGis::DataType theDataType, double theValue )
806 {
807  qgssize size = QgsRasterBlock::typeSize( theDataType );
808  QByteArray ba;
809  ba.resize(( int )size );
810  char * data = ba.data();
811  quint8 uc;
812  quint16 us;
813  qint16 s;
814  quint32 ui;
815  qint32 i;
816  float f;
817  double d;
818  switch ( theDataType )
819  {
820  case QGis::Byte:
821  uc = ( quint8 )theValue;
822  memcpy( data, &uc, size );
823  break;
824  case QGis::UInt16:
825  us = ( quint16 )theValue;
826  memcpy( data, &us, size );
827  break;
828  case QGis::Int16:
829  s = ( qint16 )theValue;
830  memcpy( data, &s, size );
831  break;
832  case QGis::UInt32:
833  ui = ( quint32 )theValue;
834  memcpy( data, &ui, size );
835  break;
836  case QGis::Int32:
837  i = ( qint32 )theValue;
838  memcpy( data, &i, size );
839  break;
840  case QGis::Float32:
841  f = ( float )theValue;
842  memcpy( data, &f, size );
843  break;
844  case QGis::Float64:
845  d = ( double )theValue;
846  memcpy( data, &d, size );
847  break;
848  default:
849  QgsDebugMsg( "Data type is not supported" );
850  }
851  return ba;
852 }
853 
855 {
856  mNoDataBitmapWidth = mWidth / 8 + 1;
858  QgsDebugMsg( QString( "allocate %1 bytes" ).arg( mNoDataBitmapSize ) );
860  if ( mNoDataBitmap == 0 )
861  {
862  QgsDebugMsg( QString( "Couldn't allocate no data memory of %1 bytes" ).arg( mNoDataBitmapSize ) );
863  return false;
864  }
865  memset( mNoDataBitmap, 0, mNoDataBitmapSize );
866  return true;
867 }
868 
869 QRect QgsRasterBlock::subRect( const QgsRectangle & theExtent, int theWidth, int theHeight, const QgsRectangle & theSubExtent )
870 {
871  QgsDebugMsg( "theExtent = " + theExtent.toString() );
872  QgsDebugMsg( "theSubExtent = " + theSubExtent.toString() );
873  double xRes = theExtent.width() / theWidth;
874  double yRes = theExtent.height() / theHeight;
875 
876  QgsDebugMsg( QString( "theWidth = %1 theHeight = %2 xRes = %3 yRes = %4" ).arg( theWidth ).arg( theHeight ).arg( xRes ).arg( yRes ) );
877 
878  int top = 0;
879  int bottom = theHeight - 1;
880  int left = 0;
881  int right = theWidth - 1;
882 
883  if ( theSubExtent.yMaximum() < theExtent.yMaximum() )
884  {
885  top = qRound(( theExtent.yMaximum() - theSubExtent.yMaximum() ) / yRes );
886  }
887  if ( theSubExtent.yMinimum() > theExtent.yMinimum() )
888  {
889  bottom = qRound(( theExtent.yMaximum() - theSubExtent.yMinimum() ) / yRes ) - 1;
890  }
891 
892  if ( theSubExtent.xMinimum() > theExtent.xMinimum() )
893  {
894  left = qRound(( theSubExtent.xMinimum() - theExtent.xMinimum() ) / xRes );
895  }
896  if ( theSubExtent.xMaximum() < theExtent.xMaximum() )
897  {
898  right = qRound(( theSubExtent.xMaximum() - theExtent.xMinimum() ) / xRes ) - 1;
899  }
900  QRect subRect = QRect( left, top, right - left + 1, bottom - top + 1 );
901  QgsDebugMsg( QString( "subRect: %1 %2 %3 %4" ).arg( subRect.x() ).arg( subRect.y() ).arg( subRect.width() ).arg( subRect.height() ) );
902  return subRect;
903 }