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