|
QGIS API Documentation
master-3f58142
|
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 }