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 }
static QImage::Format imageFormat(QGis::DataType theDataType)
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:111
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:185
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.
static void writeValue(void *data, QGis::DataType type, size_t index, double value)
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:258
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:190
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:175
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)
size_t mNoDataBitmapSize
static double readValue(void *data, QGis::DataType type, size_t index)
bool reset(QGis::DataType theDataType, int theWidth, int theHeight)
Reset block.
int dataTypeSize() const
QList< QgsRasterRange > QgsRasterRangeList
static QByteArray valueBytes(QGis::DataType theDataType, double theValue)
Get byte array representing a value.
DataType
Raster data types.
Definition: qgis.h:163
QGis::DataType mDataType
QImage image() const
Get image if type is color.
QRgb color(int row, int column) const
Read a single color.
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:195
double size
Definition: qgssvgcache.cpp:75
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:180
void qgsFree(void *ptr)
Frees the memory space pointed to by ptr.
Definition: qgis.cpp:141
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:200
bool isEmpty() const
Returns true if block is empty, i.e.