QGIS API Documentation  master-3f58142
src/core/raster/qgsrasterblock.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002     qgsrasterblock.cpp - Class representing a block of raster data
00003      --------------------------------------
00004     Date                 : Oct 9, 2012
00005     Copyright            : (C) 2012 by Radim Blazek
00006     email                : radim dot blazek at gmail dot com
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include <limits>
00019 
00020 #include <QByteArray>
00021 #include <QColor>
00022 
00023 #include "qgslogger.h"
00024 #include "qgsrasterblock.h"
00025 
00026 QgsRasterBlock::QgsRasterBlock()
00027     : mValid( true )
00028     , mDataType( QGis::UnknownDataType )
00029     , mTypeSize( 0 )
00030     , mWidth( 0 )
00031     , mHeight( 0 )
00032     , mHasNoDataValue( false )
00033     , mNoDataValue( std::numeric_limits<double>::quiet_NaN() )
00034     , mData( 0 )
00035     , mImage( 0 )
00036     , mNoDataBitmap( 0 )
00037     , mNoDataBitmapWidth( 0 )
00038     , mNoDataBitmapSize( 0 )
00039 {
00040 }
00041 
00042 QgsRasterBlock::QgsRasterBlock( QGis::DataType theDataType, int theWidth, int theHeight )
00043     : mValid( true )
00044     , mDataType( theDataType )
00045     , mTypeSize( 0 )
00046     , mWidth( theWidth )
00047     , mHeight( theHeight )
00048     , mHasNoDataValue( false )
00049     , mNoDataValue( std::numeric_limits<double>::quiet_NaN() )
00050     , mData( 0 )
00051     , mImage( 0 )
00052     , mNoDataBitmap( 0 )
00053     , mNoDataBitmapWidth( 0 )
00054     , mNoDataBitmapSize( 0 )
00055 {
00056   reset( mDataType, mWidth, mHeight );
00057 }
00058 
00059 QgsRasterBlock::QgsRasterBlock( QGis::DataType theDataType, int theWidth, int theHeight, double theNoDataValue )
00060     : mValid( true )
00061     , mDataType( theDataType )
00062     , mTypeSize( 0 )
00063     , mWidth( theWidth )
00064     , mHeight( theHeight )
00065     , mHasNoDataValue( true )
00066     , mNoDataValue( theNoDataValue )
00067     , mData( 0 )
00068     , mImage( 0 )
00069     , mNoDataBitmap( 0 )
00070     , mNoDataBitmapWidth( 0 )
00071     , mNoDataBitmapSize( 0 )
00072 {
00073   reset( mDataType, mWidth, mHeight, mNoDataValue );
00074 }
00075 
00076 QgsRasterBlock::~QgsRasterBlock()
00077 {
00078   QgsDebugMsg( QString( "mData = %1" ).arg(( ulong )mData ) );
00079   qgsFree( mData );
00080   delete mImage;
00081   qgsFree( mNoDataBitmap );
00082 }
00083 
00084 bool QgsRasterBlock::reset( QGis::DataType theDataType, int theWidth, int theHeight )
00085 {
00086   QgsDebugMsg( QString( "theWidth= %1 theHeight = %2 theDataType = %3" ).arg( theWidth ).arg( theHeight ).arg( theDataType ) );
00087   if ( !reset( theDataType, theWidth, theHeight, std::numeric_limits<double>::quiet_NaN() ) )
00088   {
00089     return false;
00090   }
00091   mHasNoDataValue = false;
00092   // the mNoDataBitmap is created only if necessary (usually, it is not) in setIsNoData()
00093   return true;
00094 }
00095 
00096 bool QgsRasterBlock::reset( QGis::DataType theDataType, int theWidth, int theHeight, double theNoDataValue )
00097 {
00098   QgsDebugMsg( QString( "theWidth= %1 theHeight = %2 theDataType = %3 theNoDataValue = %4" ).arg( theWidth ).arg( theHeight ).arg( theDataType ).arg( theNoDataValue ) );
00099 
00100   qgsFree( mData );
00101   mData = 0;
00102   delete mImage;
00103   mImage = 0;
00104   qgsFree( mNoDataBitmap );
00105   mNoDataBitmap = 0;
00106   mDataType = QGis::UnknownDataType;
00107   mTypeSize = 0;
00108   mWidth = 0;
00109   mHeight = 0;
00110   mHasNoDataValue = false;
00111   mNoDataValue = std::numeric_limits<double>::quiet_NaN();
00112   mValid = false;
00113 
00114   if ( typeIsNumeric( theDataType ) )
00115   {
00116     QgsDebugMsg( "Numeric type" );
00117     size_t tSize = typeSize( theDataType );
00118     QgsDebugMsg( QString( "allocate %1 bytes" ).arg( tSize * theWidth * theHeight ) );
00119     mData = qgsMalloc( tSize * theWidth * theHeight );
00120     if ( mData == 0 )
00121     {
00122       QgsDebugMsg( QString( "Couldn't allocate data memory of %1 bytes" ).arg( tSize * theWidth * theHeight ) );
00123       return false;
00124     }
00125   }
00126   else if ( typeIsColor( theDataType ) )
00127   {
00128     QgsDebugMsg( "Color type" );
00129     QImage::Format format = imageFormat( theDataType );
00130     mImage = new QImage( theWidth, theHeight, format );
00131   }
00132   else
00133   {
00134     QgsDebugMsg( "Wrong data type" );
00135     return false;
00136   }
00137 
00138   mValid = true;
00139   mDataType = theDataType;
00140   mTypeSize = QgsRasterBlock::typeSize( mDataType );
00141   mWidth = theWidth;
00142   mHeight = theHeight;
00143   mHasNoDataValue = true;
00144   mNoDataValue = theNoDataValue;
00145   QgsDebugMsg( QString( "mWidth= %1 mHeight = %2 mDataType = %3 mData = %4 mImage = %5" ).arg( mWidth ).arg( mHeight ).arg( mDataType ).arg(( ulong )mData ).arg(( ulong )mImage ) );
00146   return true;
00147 }
00148 
00149 QImage::Format QgsRasterBlock::imageFormat( QGis::DataType theDataType )
00150 {
00151   if ( theDataType == QGis::ARGB32 )
00152   {
00153     return QImage::Format_ARGB32;
00154   }
00155   else if ( theDataType == QGis::ARGB32_Premultiplied )
00156   {
00157     return QImage::Format_ARGB32_Premultiplied;
00158   }
00159   return QImage::Format_Invalid;
00160 }
00161 
00162 QGis::DataType QgsRasterBlock::dataType( QImage::Format theFormat )
00163 {
00164   if ( theFormat == QImage::Format_ARGB32 )
00165   {
00166     return QGis::ARGB32;
00167   }
00168   else if ( theFormat == QImage::Format_ARGB32_Premultiplied )
00169   {
00170     return QGis::ARGB32_Premultiplied;
00171   }
00172   return QGis::UnknownDataType;
00173 }
00174 
00175 bool QgsRasterBlock::isEmpty() const
00176 {
00177   QgsDebugMsg( QString( "mWidth= %1 mHeight = %2 mDataType = %3 mData = %4 mImage = %5" ).arg( mWidth ).arg( mHeight ).arg( mDataType ).arg(( ulong )mData ).arg(( ulong )mImage ) );
00178   if ( mWidth == 0 || mHeight == 0 ||
00179        ( typeIsNumeric( mDataType ) && mData == 0 ) ||
00180        ( typeIsColor( mDataType ) && mImage == 0 ) )
00181   {
00182     return true;
00183   }
00184   return false;
00185 }
00186 
00187 bool QgsRasterBlock::typeIsNumeric( QGis::DataType dataType )
00188 {
00189   switch ( dataType )
00190   {
00191     case QGis::Byte:
00192     case QGis::UInt16:
00193     case QGis::Int16:
00194     case QGis::UInt32:
00195     case QGis::Int32:
00196     case QGis::Float32:
00197     case QGis::CInt16:
00198     case QGis::Float64:
00199     case QGis::CInt32:
00200     case QGis::CFloat32:
00201     case QGis::CFloat64:
00202       return true;
00203 
00204     case QGis::UnknownDataType:
00205     case QGis::ARGB32:
00206     case QGis::ARGB32_Premultiplied:
00207       return false;
00208   }
00209   return false;
00210 }
00211 
00212 bool QgsRasterBlock::typeIsColor( QGis::DataType dataType )
00213 {
00214   switch ( dataType )
00215   {
00216     case QGis::ARGB32:
00217     case QGis::ARGB32_Premultiplied:
00218       return true;
00219 
00220     case QGis::UnknownDataType:
00221     case QGis::Byte:
00222     case QGis::UInt16:
00223     case QGis::Int16:
00224     case QGis::UInt32:
00225     case QGis::Int32:
00226     case QGis::Float32:
00227     case QGis::CInt16:
00228     case QGis::Float64:
00229     case QGis::CInt32:
00230     case QGis::CFloat32:
00231     case QGis::CFloat64:
00232       return false;
00233   }
00234   return false;
00235 }
00236 
00237 QGis::DataType QgsRasterBlock::typeWithNoDataValue( QGis::DataType dataType, double *noDataValue )
00238 {
00239   QGis::DataType newDataType;
00240 
00241   switch ( dataType )
00242   {
00243     case QGis::Byte:
00244       *noDataValue = -32768.0;
00245       newDataType = QGis::Int16;
00246       break;
00247     case QGis::Int16:
00248       *noDataValue = -2147483648.0;
00249       newDataType = QGis::Int32;
00250       break;
00251     case QGis::UInt16:
00252       *noDataValue = -2147483648.0;
00253       newDataType = QGis::Int32;
00254       break;
00255     case QGis::UInt32:
00256     case QGis::Int32:
00257     case QGis::Float32:
00258     case QGis::Float64:
00259       *noDataValue = std::numeric_limits<double>::max() * -1.0;
00260       newDataType = QGis::Float64;
00261     default:
00262       QgsDebugMsg( QString( "Unknow data type %1" ).arg( dataType ) );
00263       return QGis::UnknownDataType;
00264       break;
00265   }
00266   QgsDebugMsg( QString( "newDataType = %1 noDataValue = %2" ).arg( newDataType ).arg( *noDataValue ) );
00267   return newDataType;
00268 }
00269 
00270 bool QgsRasterBlock::hasNoData() const
00271 {
00272   return mHasNoDataValue || mNoDataBitmap != 0;
00273 }
00274 
00275 bool QgsRasterBlock::isNoDataValue( double value, double noDataValue )
00276 {
00277   // TODO: optimize no data value test by memcmp()
00278   // More precise would be qIsNaN(value) && qIsNaN(noDataValue(bandNo)), but probably
00279   // not important and slower
00280   if ( qIsNaN( value ) ||
00281        qgsDoubleNear( value, noDataValue ) )
00282   {
00283     return true;
00284   }
00285   return false;
00286 }
00287 
00288 double QgsRasterBlock::value( int row, int column ) const
00289 {
00290   return value(( size_t )row*mWidth + column );
00291 }
00292 
00293 QRgb QgsRasterBlock::color( size_t index ) const
00294 {
00295   int row = floor(( double )index / mWidth );
00296   int column = index % mWidth;
00297   return color( row, column );
00298 }
00299 
00300 QRgb QgsRasterBlock::color( int row, int column ) const
00301 {
00302   if ( !mImage ) return qRgba( 255, 255, 255, 0 );
00303 
00304   return mImage->pixel( column, row );
00305 }
00306 
00307 bool QgsRasterBlock::isNoData( size_t index )
00308 {
00309   if ( !mHasNoDataValue && !mNoDataBitmap ) return false;
00310   if ( index >= ( size_t )mWidth*mHeight )
00311   {
00312     QgsDebugMsg( QString( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
00313     return true; // we consider no data if outside
00314   }
00315   if ( mHasNoDataValue )
00316   {
00317     double value = readValue( mData, mDataType, index );
00318     return isNoDataValue( value );
00319   }
00320   // use no data bitmap
00321   if ( mNoDataBitmap == 0 )
00322   {
00323     // no data are not defined
00324     return false;
00325   }
00326   // TODO: optimize
00327   int row = index / mWidth;
00328   int column = index % mWidth;
00329   size_t byte = ( size_t )row * mNoDataBitmapWidth + column / 8 ;
00330   int bit = column % 8;
00331   int mask = 0x80 >> bit;
00332   //int x = mNoDataBitmap[byte] & mask;
00333   //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) ) );
00334   return mNoDataBitmap[byte] & mask;
00335 }
00336 
00337 bool QgsRasterBlock::isNoData( int row, int column )
00338 {
00339   return isNoData(( size_t )row*mWidth + column );
00340 }
00341 
00342 bool QgsRasterBlock::setValue( size_t index, double value )
00343 {
00344   if ( !mData )
00345   {
00346     QgsDebugMsg( "Data block not allocated" );
00347     return false;
00348   }
00349   if ( index >= ( size_t )mWidth*mHeight )
00350   {
00351     QgsDebugMsg( QString( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
00352     return false;
00353   }
00354   writeValue( mData, mDataType, index, value );
00355   return true;
00356 }
00357 
00358 bool QgsRasterBlock::setValue( int row, int column, double value )
00359 {
00360   return setValue(( size_t )row*mWidth + column, value );
00361 }
00362 
00363 bool QgsRasterBlock::setColor( int row, int column, QRgb color )
00364 {
00365   return setColor(( size_t )row*mWidth + column, color );
00366 }
00367 
00368 bool QgsRasterBlock::setColor( size_t index, QRgb color )
00369 {
00370   if ( !mImage )
00371   {
00372     QgsDebugMsg( "Image not allocated" );
00373     return false;
00374   }
00375 
00376   if ( index >= ( size_t )mImage->width()* mImage->height() )
00377   {
00378     QgsDebugMsg( QString( "index %1 out of range" ).arg( index ) );
00379     return false;
00380   }
00381 
00382   // setPixel() is slow, see Qt doc -> use direct access
00383   QRgb* bits = ( QRgb* )mImage->bits();
00384   bits[index] = color;
00385   return true;
00386 }
00387 
00388 bool QgsRasterBlock::setIsNoData( int row, int column )
00389 {
00390   return setIsNoData(( size_t )row*mWidth + column );
00391 }
00392 
00393 bool QgsRasterBlock::setIsNoData( size_t index )
00394 {
00395   if ( mHasNoDataValue )
00396   {
00397     return setValue( index, mNoDataValue );
00398   }
00399   else
00400   {
00401     if ( mNoDataBitmap == 0 )
00402     {
00403       if ( !createNoDataBitmap() )
00404       {
00405         return false;
00406       }
00407     }
00408     // TODO: optimize
00409     int row = index / mWidth;
00410     int column = index % mWidth;
00411     size_t byte = ( size_t )row * mNoDataBitmapWidth + column / 8;
00412     int bit = column % 8;
00413     int nodata = 0x80 >> bit;
00414     //QgsDebugMsg ( QString("set byte = %1 bit = %2 no data by %3").arg(byte).arg(bit).arg(nodata, 0,2 ) );
00415     mNoDataBitmap[byte] = mNoDataBitmap[byte] | nodata;
00416     return true;
00417   }
00418 }
00419 
00420 bool QgsRasterBlock::setIsNoData()
00421 {
00422   QgsDebugMsg( "Entered" );
00423   if ( typeIsNumeric( mDataType ) )
00424   {
00425     if ( mHasNoDataValue )
00426     {
00427       if ( !mData )
00428       {
00429         QgsDebugMsg( "Data block not allocated" );
00430         return false;
00431       }
00432 
00433       QgsDebugMsg( "set mData to mNoDataValue" );
00434       int dataTypeSize = typeSize( mDataType );
00435       QByteArray noDataByteArray = valueBytes( mDataType, mNoDataValue );
00436 
00437       char *nodata = noDataByteArray.data();
00438       for ( size_t i = 0; i < ( size_t )mWidth*mHeight; i++ )
00439       {
00440         memcpy(( char* )mData + i*dataTypeSize, nodata, dataTypeSize );
00441       }
00442     }
00443     else
00444     {
00445       // use bitmap
00446       if ( mNoDataBitmap == 0 )
00447       {
00448         if ( !createNoDataBitmap() )
00449         {
00450           return false;
00451         }
00452       }
00453       QgsDebugMsg( "set mNoDataBitmap to 1" );
00454       memset( mNoDataBitmap, 0xff, mNoDataBitmapSize );
00455     }
00456     return true;
00457   }
00458   else
00459   {
00460     // image
00461     if ( !mImage )
00462     {
00463       QgsDebugMsg( "Image not allocated" );
00464       return false;
00465     }
00466     QgsDebugMsg( "Fill image" );
00467     mImage->fill( qRgba( 0, 0, 0, 0 ) );
00468     return true;
00469   }
00470 }
00471 
00472 bool QgsRasterBlock::setIsNoDataExcept( const QRect & theExceptRect )
00473 {
00474   int top = theExceptRect.top();
00475   int bottom = theExceptRect.bottom();
00476   int left = theExceptRect.left();
00477   int right = theExceptRect.right();
00478   top = qMin( qMax( top, 0 ), mHeight - 1 );
00479   left = qMin( qMax( left, 0 ), mWidth - 1 );
00480   bottom = qMax( 0, qMin( bottom, mHeight - 1 ) );
00481   right = qMax( 0, qMin( right, mWidth - 1 ) );
00482 
00483   QgsDebugMsg( "Entered" );
00484   if ( typeIsNumeric( mDataType ) )
00485   {
00486     if ( mHasNoDataValue )
00487     {
00488       if ( !mData )
00489       {
00490         QgsDebugMsg( "Data block not allocated" );
00491         return false;
00492       }
00493 
00494       QgsDebugMsg( "set mData to mNoDataValue" );
00495       int dataTypeSize = typeSize( mDataType );
00496       QByteArray noDataByteArray = valueBytes( mDataType, mNoDataValue );
00497 
00498       char *nodata = noDataByteArray.data();
00499       char *nodataRow = new char[mWidth*dataTypeSize]; // full row of no data
00500       for ( int c = 0; c < mWidth; c++ )
00501       {
00502         memcpy( nodataRow + c*dataTypeSize, nodata, dataTypeSize );
00503       }
00504 
00505       // top and bottom
00506       for ( int r = 0; r < mHeight; r++ )
00507       {
00508         if ( r >= top && r <= bottom ) continue; // middle
00509         size_t i = ( size_t )r * mWidth;
00510         memcpy(( char* )mData + i*dataTypeSize, nodataRow, dataTypeSize*mWidth );
00511       }
00512       // middle
00513       for ( int r = top; r <= bottom; r++ )
00514       {
00515         size_t i = ( size_t )r * mWidth;
00516         // middle left
00517         memcpy(( char* )mData + i*dataTypeSize, nodataRow, dataTypeSize*left );
00518         // middle right
00519         i += right + 1;
00520         int w = mWidth - right - 1;
00521         memcpy(( char* )mData + i*dataTypeSize, nodataRow, dataTypeSize*w );
00522       }
00523       delete [] nodataRow;
00524     }
00525     else
00526     {
00527       // use bitmap
00528       if ( mNoDataBitmap == 0 )
00529       {
00530         if ( !createNoDataBitmap() )
00531         {
00532           return false;
00533         }
00534       }
00535       QgsDebugMsg( "set mNoDataBitmap to 1" );
00536 
00537       char *nodataRow = new char[mNoDataBitmapWidth]; // full row of no data
00538       memset( nodataRow, 0, mNoDataBitmapWidth );
00539       for ( int c = 0; c < mWidth; c ++ )
00540       {
00541         int byte = c / 8;
00542         int bit = c % 8;
00543         int nodata = 0x80 >> bit;
00544         memset( nodataRow + byte, nodataRow[byte] | nodata, 1 );
00545       }
00546 
00547       // top and bottom
00548       for ( int r = 0; r < mHeight; r++ )
00549       {
00550         if ( r >= top && r <= bottom ) continue; // middle
00551         size_t i = ( size_t )r * mNoDataBitmapWidth;
00552         memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
00553       }
00554       // middle
00555       memset( nodataRow, 0, mNoDataBitmapWidth );
00556       for ( int c = 0; c < mWidth; c ++ )
00557       {
00558         if ( c >= left && c <= right ) continue; // middle
00559         int byte = c / 8;
00560         int bit = c % 8;
00561         int nodata = 0x80 >> bit;
00562         memset( nodataRow + byte, nodataRow[byte] | nodata, 1 );
00563       }
00564       for ( int r = top; r <= bottom; r++ )
00565       {
00566         size_t i = ( size_t )r * mNoDataBitmapWidth;
00567         memcpy( mNoDataBitmap + i, nodataRow, mNoDataBitmapWidth );
00568       }
00569       delete [] nodataRow;
00570     }
00571     return true;
00572   }
00573   else
00574   {
00575     // image
00576     if ( !mImage )
00577     {
00578       QgsDebugMsg( "Image not allocated" );
00579       return false;
00580     }
00581     QgsDebugMsg( "Fill image" );
00582     QRgb nodataRgba = qRgba( 0, 0, 0, 0 );
00583     QRgb *nodataRow = new QRgb[mWidth]; // full row of no data
00584     int rgbSize = sizeof( QRgb );
00585     for ( int c = 0; c < mWidth; c ++ )
00586     {
00587       nodataRow[c] = nodataRgba;
00588     }
00589 
00590     // top and bottom
00591     for ( int r = 0; r < mHeight; r++ )
00592     {
00593       if ( r >= top && r <= bottom ) continue; // middle
00594       size_t i = ( size_t )r * mWidth;
00595       memcpy(( void * )( mImage->bits() + rgbSize*i ), nodataRow, rgbSize*mWidth );
00596     }
00597     // middle
00598     for ( int r = top; r <= bottom; r++ )
00599     {
00600       size_t i = r * mWidth;
00601       // middle left
00602       memcpy(( void * )( mImage->bits() + rgbSize*i ), nodataRow, rgbSize*left );
00603       // middle right
00604       i += right + 1;
00605       int w = mWidth - right;
00606       memcpy(( void * )( mImage->bits() + rgbSize*i ), nodataRow, rgbSize*w );
00607     }
00608     delete [] nodataRow;
00609     return true;
00610   }
00611 }
00612 
00613 char * QgsRasterBlock::bits( size_t index )
00614 {
00615   // Not testing type to avoid too much overhead because this method is called per pixel
00616   if ( index >= ( size_t )mWidth*mHeight )
00617   {
00618     QgsDebugMsg( QString( "Index %1 out of range (%2 x %3)" ).arg( index ).arg( mWidth ).arg( mHeight ) );
00619     return 0;
00620   }
00621   if ( mData )
00622   {
00623     return ( char* )mData + index * mTypeSize;
00624   }
00625   if ( mImage && mImage->bits() )
00626   {
00627     return ( char* )( mImage->bits() + index * 4 );
00628   }
00629 
00630   return 0;
00631 }
00632 
00633 char * QgsRasterBlock::bits( int row, int column )
00634 {
00635   return bits(( size_t )row*mWidth + column );
00636 }
00637 
00638 char * QgsRasterBlock::bits()
00639 {
00640   if ( mData )
00641   {
00642     return ( char* )mData;
00643   }
00644   if ( mImage && mImage->bits() )
00645   {
00646     return ( char* )( mImage->bits() );
00647   }
00648 
00649   return 0;
00650 }
00651 
00652 bool QgsRasterBlock::convert( QGis::DataType destDataType )
00653 {
00654   if ( isEmpty() ) return false;
00655   if ( destDataType == mDataType ) return true;
00656 
00657   if ( typeIsNumeric( mDataType ) && typeIsNumeric( destDataType ) )
00658   {
00659     void *data = convert( mData, mDataType, destDataType, mWidth * mHeight );
00660 
00661     if ( data == 0 )
00662     {
00663       QgsDebugMsg( "Cannot convert raster block" );
00664       return false;
00665     }
00666     qgsFree( mData );
00667     mData = data;
00668     mDataType = destDataType;
00669     mTypeSize = typeSize( mDataType );
00670   }
00671   else if ( typeIsColor( mDataType ) && typeIsColor( destDataType ) )
00672   {
00673     QImage::Format format = imageFormat( destDataType );
00674     QImage image = mImage->convertToFormat( format );
00675     *mImage = image;
00676     mDataType = destDataType;
00677     mTypeSize = typeSize( mDataType );
00678   }
00679   else
00680   {
00681     return false;
00682   }
00683 
00684   return true;
00685 }
00686 
00687 void QgsRasterBlock::applyNoDataValues( const QgsRasterRangeList & rangeList )
00688 {
00689   if ( rangeList.isEmpty() )
00690   {
00691     return;
00692   }
00693 
00694   size_t size = mWidth * mHeight;
00695   for ( size_t i = 0; i < size; ++i )
00696   {
00697     double val = value( i );
00698     if ( QgsRasterRange::contains( val, rangeList ) )
00699     {
00700       //setValue( i, mNoDataValue );
00701       setIsNoData( i );
00702     }
00703   }
00704 }
00705 
00706 QImage QgsRasterBlock::image() const
00707 {
00708   if ( mImage )
00709   {
00710     return QImage( *mImage );
00711   }
00712   return QImage();
00713 }
00714 
00715 bool QgsRasterBlock::setImage( const QImage * image )
00716 {
00717   qgsFree( mData );
00718   mData = 0;
00719   delete mImage;
00720   mImage = 0;
00721   mImage = new QImage( *image );
00722   mWidth = mImage->width();
00723   mHeight = mImage->height();
00724   mDataType = dataType( mImage->format() );
00725   mTypeSize = QgsRasterBlock::typeSize( mDataType );
00726   mNoDataValue = std::numeric_limits<double>::quiet_NaN();
00727   return true;
00728 }
00729 
00730 QString QgsRasterBlock::printValue( double value )
00731 {
00732   /*
00733    *  IEEE 754 double has 15-17 significant digits. It specifies:
00734    *
00735    * "If a decimal string with at most 15 significant decimal is converted to
00736    *  IEEE 754 double precision and then converted back to the same number of
00737    *  significant decimal, then the final string should match the original;
00738    *  and if an IEEE 754 double precision is converted to a decimal string with at
00739    *  least 17 significant decimal and then converted back to double, then the final
00740    *  number must match the original."
00741    *
00742    * If printing only 15 digits, some precision could be lost. Printing 17 digits may
00743    * add some confusing digits.
00744    *
00745    * Default 'g' precision on linux is 6 digits, not all significant digits like
00746    * some sprintf manuals say.
00747    *
00748    * We need to ensure that the number printed and used in QLineEdit or XML will
00749    * give the same number when parsed.
00750    *
00751    * Is there a better solution?
00752    */
00753 
00754   QString s;
00755 
00756   for ( int i = 15; i <= 17; i++ )
00757   {
00758     s.setNum( value, 'g', i );
00759     if ( s.toDouble() == value )
00760     {
00761       return s;
00762     }
00763   }
00764   // Should not happen
00765   QgsDebugMsg( "Cannot correctly parse printed value" );
00766   return s;
00767 }
00768 
00769 void * QgsRasterBlock::convert( void *srcData, QGis::DataType srcDataType, QGis::DataType destDataType, size_t size )
00770 {
00771   int destDataTypeSize = typeSize( destDataType );
00772   void *destData = qgsMalloc( destDataTypeSize * size );
00773   for ( size_t i = 0; i < size; i++ )
00774   {
00775     double value = readValue( srcData, srcDataType, i );
00776     writeValue( destData, destDataType, i, value );
00777     //double newValue = readValue( destData, destDataType, i );
00778     //QgsDebugMsg( QString("convert %1 type %2 to %3: %4 -> %5").arg(i).arg(srcDataType).arg(destDataType).arg( value ).arg( newValue ) );
00779   }
00780   return destData;
00781 }
00782 
00783 QByteArray QgsRasterBlock::valueBytes( QGis::DataType theDataType, double theValue )
00784 {
00785   size_t size = QgsRasterBlock::typeSize( theDataType );
00786   QByteArray ba;
00787   ba.resize(( int )size );
00788   char * data = ba.data();
00789   quint8 uc;
00790   quint16 us;
00791   qint16 s;
00792   quint32 ui;
00793   qint32 i;
00794   float f;
00795   double d;
00796   switch ( theDataType )
00797   {
00798     case QGis::Byte:
00799       uc = ( quint8 )theValue;
00800       memcpy( data, &uc, size );
00801       break;
00802     case QGis::UInt16:
00803       us = ( quint16 )theValue;
00804       memcpy( data, &us, size );
00805       break;
00806     case QGis::Int16:
00807       s = ( qint16 )theValue;
00808       memcpy( data, &s, size );
00809       break;
00810     case QGis::UInt32:
00811       ui = ( quint32 )theValue;
00812       memcpy( data, &ui, size );
00813       break;
00814     case QGis::Int32:
00815       i = ( qint32 )theValue;
00816       memcpy( data, &i, size );
00817       break;
00818     case QGis::Float32:
00819       f = ( float )theValue;
00820       memcpy( data, &f, size );
00821       break;
00822     case QGis::Float64:
00823       d = ( double )theValue;
00824       memcpy( data, &d, size );
00825       break;
00826     default:
00827       QgsDebugMsg( "Data type is not supported" );
00828   }
00829   return ba;
00830 }
00831 
00832 bool QgsRasterBlock::createNoDataBitmap()
00833 {
00834   mNoDataBitmapWidth = mWidth / 8 + 1;
00835   mNoDataBitmapSize = ( size_t )mNoDataBitmapWidth * mHeight;
00836   QgsDebugMsg( QString( "allocate %1 bytes" ).arg( mNoDataBitmapSize ) );
00837   mNoDataBitmap = ( char* )qgsMalloc( mNoDataBitmapSize );
00838   if ( mNoDataBitmap == 0 )
00839   {
00840     QgsDebugMsg( QString( "Couldn't allocate no data memory of %1 bytes" ).arg( mNoDataBitmapSize ) );
00841     return false;
00842   }
00843   memset( mNoDataBitmap, 0, mNoDataBitmapSize );
00844   return true;
00845 }
00846 
00847 QRect QgsRasterBlock::subRect( const QgsRectangle & theExtent, int theWidth, int theHeight, const QgsRectangle &  theSubExtent )
00848 {
00849   double xRes = theExtent.width() / theWidth;
00850   double yRes = theExtent.height() / theHeight;
00851 
00852   int top = 0;
00853   int bottom = theHeight - 1;
00854   int left = 0;
00855   int right = theWidth - 1;
00856 
00857   if ( theSubExtent.yMaximum() < theExtent.yMaximum() )
00858   {
00859     top = qRound(( theExtent.yMaximum() - theSubExtent.yMaximum() ) / yRes );
00860   }
00861   if ( theSubExtent.yMinimum() > theExtent.yMinimum() )
00862   {
00863     bottom = qRound(( theExtent.yMaximum() - theSubExtent.yMinimum() ) / yRes ) - 1;
00864   }
00865 
00866   if ( theSubExtent.xMinimum() > theExtent.xMinimum() )
00867   {
00868     left = qRound(( theSubExtent.xMinimum() - theExtent.xMinimum() ) / xRes );
00869   }
00870   if ( theSubExtent.xMaximum() < theExtent.xMaximum() )
00871   {
00872     right = qRound(( theSubExtent.xMaximum() - theExtent.xMinimum() ) / xRes ) - 1;
00873   }
00874   return QRect( left, top, right - left + 1, bottom - top + 1 );
00875 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines