QGIS API Documentation  2.3.0-Master
 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 }
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:189
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:194
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:179
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
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:199
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:184
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:204
bool isEmpty() const
Returns true if block is empty, i.e.