Quantum GIS API Documentation
1.8
|
00001 /*************************************************************************** 00002 qgsrasterlayer.cpp - description 00003 ------------------- 00004 begin : Sat Jun 22 2002 00005 copyright : (C) 2003 by Tim Sutton, Steve Halasz and Gary E.Sherman 00006 email : tim at linfiniti.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 "qgsapplication.h" 00019 #include "qgslogger.h" 00020 #include "qgsmessagelog.h" 00021 #include "qgsmaplayerregistry.h" 00022 #include "qgsmaptopixel.h" 00023 #include "qgsproviderregistry.h" 00024 #include "qgsrasterbandstats.h" 00025 #include "qgsrasterlayer.h" 00026 #include "qgsrasterpyramid.h" 00027 #include "qgsrectangle.h" 00028 #include "qgsrendercontext.h" 00029 #include "qgscoordinatereferencesystem.h" 00030 #include "qgscoordinatetransform.h" 00031 00032 #include "gdalwarper.h" 00033 #include "cpl_conv.h" 00034 00035 #include "qgspseudocolorshader.h" 00036 #include "qgsfreakoutshader.h" 00037 #include "qgscolorrampshader.h" 00038 00039 #include <cstdio> 00040 #include <cmath> 00041 #include <limits> 00042 00043 #include <QApplication> 00044 #include <QCursor> 00045 #include <QDomElement> 00046 #include <QDomNode> 00047 #include <QFile> 00048 #include <QFileInfo> 00049 #include <QFont> 00050 #include <QFontMetrics> 00051 #include <QFrame> 00052 #include <QImage> 00053 #include <QLabel> 00054 #include <QList> 00055 #include <QMatrix> 00056 #include <QMessageBox> 00057 #include <QLibrary> 00058 #include <QPainter> 00059 #include <QPixmap> 00060 #include <QRegExp> 00061 #include <QSlider> 00062 #include <QSettings> 00063 #include <QTime> 00064 00065 // typedefs for provider plugin functions of interest 00066 typedef void buildsupportedrasterfilefilter_t( QString & theFileFiltersString ); 00067 typedef bool isvalidrasterfilename_t( QString const & theFileNameQString, QString & retErrMsg ); 00068 00069 // workaround for MSVC compiler which already has defined macro max 00070 // that interferes with calling std::numeric_limits<int>::max 00071 #ifdef _MSC_VER 00072 # ifdef max 00073 # undef max 00074 # endif 00075 #endif 00076 00077 // Comparison value for equality; i.e., we shouldn't directly compare two 00078 // floats so it's better to take their difference and see if they're within 00079 // a certain range -- in this case twenty times the smallest value that 00080 // doubles can take for the current system. (Yes, 20 was arbitrary.) 00081 #define TINY_VALUE std::numeric_limits<double>::epsilon() * 20 00082 00083 00084 QgsRasterLayer::QgsRasterLayer( 00085 QString const & path, 00086 QString const & baseName, 00087 bool loadDefaultStyleFlag ) 00088 : QgsMapLayer( RasterLayer, baseName, path ) 00089 // Constant that signals property not used. 00090 , QSTRING_NOT_SET( "Not Set" ) 00091 , TRSTRING_NOT_SET( tr( "Not Set" ) ) 00092 , mStandardDeviations( 0 ) 00093 , mDataProvider( 0 ) 00094 , mWidth( std::numeric_limits<int>::max() ) 00095 , mHeight( std::numeric_limits<int>::max() ) 00096 , mInvertColor( false ) 00097 { 00098 QgsDebugMsg( "Entered" ); 00099 00100 // TODO, call constructor with provider key for now 00101 init(); 00102 setDataProvider( "gdal", QStringList(), QStringList(), QString(), QString(), loadDefaultStyleFlag ); 00103 00104 if ( mValid && loadDefaultStyleFlag ) 00105 { 00106 bool defaultLoadedFlag = false; 00107 loadDefaultStyle( defaultLoadedFlag ); 00108 // I'm no sure if this should be used somehow, in pre raster-providers there was 00109 // only mLastViewPort init after this block, nothing to do with style 00110 //if ( defaultLoadedFlag ) 00111 //{ 00112 //return; 00113 //} 00114 } 00115 return; 00116 00117 00118 } // QgsRasterLayer ctor 00119 00124 QgsRasterLayer::QgsRasterLayer( int dummy, 00125 QString const & rasterLayerPath, 00126 QString const & baseName, 00127 QString const & providerKey, 00128 QStringList const & layers, 00129 QStringList const & styles, 00130 QString const & format, 00131 QString const & crs ) 00132 : QgsMapLayer( RasterLayer, baseName, rasterLayerPath ) 00133 , mStandardDeviations( 0 ) 00134 , mDataProvider( 0 ) 00135 , mEditable( false ) 00136 , mWidth( std::numeric_limits<int>::max() ) 00137 , mHeight( std::numeric_limits<int>::max() ) 00138 , mInvertColor( false ) 00139 , mModified( false ) 00140 , mProviderKey( providerKey ) 00141 , mLayers( layers ) 00142 , mStyles( styles ) 00143 , mFormat( format ) 00144 , mCrs( crs ) 00145 { 00146 Q_UNUSED( dummy ); 00147 00148 QgsDebugMsg( "(8 arguments) starting. with layer list of " + 00149 layers.join( ", " ) + " and style list of " + styles.join( ", " ) + " and format of " + 00150 format + " and CRS of " + crs ); 00151 00152 00153 init(); 00154 // if we're given a provider type, try to create and bind one to this layer 00155 bool loadDefaultStyleFlag = false ; // ??? 00156 setDataProvider( providerKey, layers, styles, format, crs, loadDefaultStyleFlag ); 00157 00158 // load default style if provider is gdal and if no style was given 00159 // this should be an argument like in the other constructor 00160 if ( mValid && providerKey == "gdal" && layers.isEmpty() && styles.isEmpty() ) 00161 { 00162 bool defaultLoadedFlag = false; 00163 loadDefaultStyle( defaultLoadedFlag ); 00164 } 00165 00166 // Default for the popup menu 00167 // TODO: popMenu = 0; 00168 00169 // Get the update threshold from user settings. We 00170 // do this only on construction to avoid the penality of 00171 // fetching this each time the layer is drawn. If the user 00172 // changes the threshold from the preferences dialog, it will 00173 // have no effect on existing layers 00174 // TODO: QSettings settings; 00175 // updateThreshold = settings.readNumEntry("Map/updateThreshold", 1000); 00176 00177 00178 // TODO: Connect signals from the dataprovider to the qgisapp 00179 00180 QgsDebugMsg( "(8 arguments) exiting." ); 00181 00182 emit statusChanged( tr( "QgsRasterLayer created" ) ); 00183 } // QgsRasterLayer ctor 00184 00185 QgsRasterLayer::~QgsRasterLayer() 00186 { 00187 mValid = false; 00188 delete mRasterShader; 00189 delete mDataProvider; 00190 } 00191 00193 // 00194 // Static Methods and members 00195 // 00197 00205 void QgsRasterLayer::buildSupportedRasterFileFilter( QString & theFileFiltersString ) 00206 { 00207 QgsDebugMsg( "Entered" ); 00208 QLibrary* myLib = QgsRasterLayer::loadProviderLibrary( "gdal" ); 00209 if ( !myLib ) 00210 { 00211 QgsDebugMsg( "Could not load gdal provider library" ); 00212 return; 00213 } 00214 buildsupportedrasterfilefilter_t *pBuild = ( buildsupportedrasterfilefilter_t * ) cast_to_fptr( myLib->resolve( "buildSupportedRasterFileFilter" ) ); 00215 if ( ! pBuild ) 00216 { 00217 QgsDebugMsg( "Could not resolve buildSupportedRasterFileFilter in gdal provider library" ); 00218 return; 00219 } 00220 00221 pBuild( theFileFiltersString ); 00222 delete myLib; 00223 } 00224 00228 bool QgsRasterLayer::isValidRasterFileName( QString const & theFileNameQString, QString & retErrMsg ) 00229 { 00230 00231 QLibrary* myLib = QgsRasterLayer::loadProviderLibrary( "gdal" ); 00232 if ( !myLib ) 00233 { 00234 QgsDebugMsg( "Could not load gdal provider library" ); 00235 return false; 00236 } 00237 isvalidrasterfilename_t *pValid = ( isvalidrasterfilename_t * ) cast_to_fptr( myLib->resolve( "isValidRasterFileName" ) ); 00238 if ( ! pValid ) 00239 { 00240 QgsDebugMsg( "Could not resolve isValidRasterFileName in gdal provider library" ); 00241 return false; 00242 } 00243 00244 bool myIsValid = pValid( theFileNameQString, retErrMsg ); 00245 delete myLib; 00246 return myIsValid; 00247 } 00248 00249 bool QgsRasterLayer::isValidRasterFileName( QString const & theFileNameQString ) 00250 { 00251 QString retErrMsg; 00252 return isValidRasterFileName( theFileNameQString, retErrMsg ); 00253 } 00254 00255 QDateTime QgsRasterLayer::lastModified( QString const & name ) 00256 { 00257 QgsDebugMsg( "name=" + name ); 00258 QDateTime t; 00259 00260 QFileInfo fi( name ); 00261 00262 // Is it file? 00263 if ( !fi.exists() ) 00264 return t; 00265 00266 t = fi.lastModified(); 00267 00268 QgsDebugMsg( "last modified = " + t.toString() ); 00269 00270 return t; 00271 } 00272 00273 // typedef for the QgsDataProvider class factory 00274 typedef QgsDataProvider * classFactoryFunction_t( const QString * ); 00275 00277 // 00278 // Non Static Public methods 00279 // 00281 00282 unsigned int QgsRasterLayer::bandCount() const 00283 { 00284 return mBandCount; 00285 } 00286 00287 const QString QgsRasterLayer::bandName( int theBandNo ) 00288 { 00289 if ( theBandNo <= mRasterStatsList.size() && theBandNo > 0 ) 00290 { 00291 //vector starts at base 0, band counts at base1! 00292 return mRasterStatsList[theBandNo - 1].bandName; 00293 } 00294 else 00295 { 00296 return QString( "" ); 00297 } 00298 } 00299 00300 int QgsRasterLayer::bandNumber( QString const & theBandName ) const 00301 { 00302 for ( int myIterator = 0; myIterator < mRasterStatsList.size(); ++myIterator ) 00303 { 00304 //find out the name of this band 00305 QgsRasterBandStats myRasterBandStats = mRasterStatsList[myIterator]; 00306 QgsDebugMsg( "myRasterBandStats.bandName: " + myRasterBandStats.bandName + " :: theBandName: " 00307 + theBandName ); 00308 00309 if ( myRasterBandStats.bandName == theBandName ) 00310 { 00311 QgsDebugMsg( "********** band " + QString::number( myRasterBandStats.bandNumber ) + 00312 " was found in bandNumber " + theBandName ); 00313 00314 return myRasterBandStats.bandNumber; 00315 } 00316 } 00317 QgsDebugMsg( "********** no band was found in bandNumber " + theBandName ); 00318 00319 return 0; //no band was found 00320 } 00321 00341 const QgsRasterBandStats QgsRasterLayer::bandStatistics( int theBandNo ) 00342 { 00343 QgsDebugMsg( "theBandNo = " + QString::number( theBandNo ) ); 00344 QgsDebugMsg( "mRasterType = " + QString::number( mRasterType ) ); 00345 if ( mRasterType == ColorLayer ) 00346 { 00347 // Statistics have no sense for ColorLayer 00348 QgsRasterBandStats myNullReturnStats; 00349 return myNullReturnStats; 00350 } 00351 // check if we have received a valid band number 00352 if (( mDataProvider->bandCount() < theBandNo ) && mRasterType != Palette ) 00353 { 00354 // invalid band id, return nothing 00355 QgsRasterBandStats myNullReturnStats; 00356 return myNullReturnStats; 00357 } 00358 if ( mRasterType == Palette && ( theBandNo > 3 ) ) 00359 { 00360 // invalid band id, return nothing 00361 QgsRasterBandStats myNullReturnStats; 00362 return myNullReturnStats; 00363 } 00364 // check if we have previously gathered stats for this band... 00365 if ( theBandNo < 1 || theBandNo > mRasterStatsList.size() ) 00366 { 00367 // invalid band id, return nothing 00368 QgsRasterBandStats myNullReturnStats; 00369 return myNullReturnStats; 00370 } 00371 00372 QgsRasterBandStats myRasterBandStats = mRasterStatsList[theBandNo - 1]; 00373 myRasterBandStats.bandNumber = theBandNo; 00374 00375 // don't bother with this if we already have stats 00376 if ( myRasterBandStats.statsGathered ) 00377 { 00378 return myRasterBandStats; 00379 } 00380 00381 myRasterBandStats = mDataProvider->bandStatistics( theBandNo ); 00382 QgsDebugMsg( "adding stats to stats collection at position " + QString::number( theBandNo - 1 ) ); 00383 //add this band to the class stats map 00384 mRasterStatsList[theBandNo - 1] = myRasterBandStats; 00385 emit drawingProgress( mHeight, mHeight ); //reset progress 00386 QgsDebugMsg( "Stats collection completed returning" ); 00387 return myRasterBandStats; 00388 } // QgsRasterLayer::bandStatistics 00389 00390 const QgsRasterBandStats QgsRasterLayer::bandStatistics( QString const & theBandName ) 00391 { 00392 // only print message if we are actually gathering the stats 00393 emit statusChanged( tr( "Retrieving stats for %1" ).arg( name() ) ); 00394 qApp->processEvents(); 00395 //reset the main app progress bar 00396 emit drawingProgress( 0, 0 ); 00397 //we cant use a vector iterator because the iterator is astruct not a class 00398 //and the qvector model does not like this. 00399 for ( int i = 1; i <= mDataProvider->bandCount(); i++ ) 00400 { 00401 QgsRasterBandStats myRasterBandStats = bandStatistics( i ); 00402 if ( myRasterBandStats.bandName == theBandName ) 00403 { 00404 return myRasterBandStats; 00405 } 00406 } 00407 00408 return QgsRasterBandStats(); // return a null one 00409 } 00410 00411 00412 QString QgsRasterLayer::buildPyramids( RasterPyramidList const & theRasterPyramidList, 00413 QString const & theResamplingMethod, bool theTryInternalFlag ) 00414 { 00415 return mDataProvider->buildPyramids( theRasterPyramidList, theResamplingMethod, theTryInternalFlag ); 00416 } 00417 00418 00419 QgsRasterLayer::RasterPyramidList QgsRasterLayer::buildPyramidList() 00420 { 00421 return mDataProvider->buildPyramidList(); 00422 } 00423 00424 QString QgsRasterLayer::colorShadingAlgorithmAsString() const 00425 { 00426 switch ( mColorShadingAlgorithm ) 00427 { 00428 case PseudoColorShader: 00429 return QString( "PseudoColorShader" ); 00430 break; 00431 case FreakOutShader: 00432 return QString( "FreakOutShader" ); 00433 break; 00434 case ColorRampShader: 00435 return QString( "ColorRampShader" ); 00436 break; 00437 case UserDefinedShader: 00438 return QString( "UserDefinedShader" ); 00439 break; 00440 default: 00441 break; 00442 } 00443 00444 return QString( "UndefinedShader" ); 00445 } 00446 00451 void QgsRasterLayer::computeMinimumMaximumEstimates( int theBand, double* theMinMax ) 00452 { 00453 if ( !theMinMax ) 00454 return; 00455 00456 if ( 0 < theBand && theBand <= ( int ) bandCount() ) 00457 { 00458 theMinMax[0] = mDataProvider->minimumValue( theBand ); 00459 theMinMax[1] = mDataProvider->maximumValue( theBand ); 00460 } 00461 } 00462 00467 void QgsRasterLayer::computeMinimumMaximumEstimates( QString theBand, double* theMinMax ) 00468 { 00469 computeMinimumMaximumEstimates( bandNumber( theBand ), theMinMax ); 00470 } 00471 00472 void QgsRasterLayer::computeMinimumMaximumEstimates( int theBand, double& theMin, double& theMax ) 00473 { 00474 double theMinMax[2]; 00475 computeMinimumMaximumEstimates( theBand, theMinMax ); 00476 theMin = theMinMax[0]; 00477 theMax = theMinMax[1]; 00478 } 00479 00484 void QgsRasterLayer::computeMinimumMaximumFromLastExtent( int theBand, double* theMinMax ) 00485 { 00486 if ( !theMinMax ) 00487 return; 00488 00489 int myDataType = mDataProvider->dataType( theBand ); 00490 void* myScanData = readData( theBand, &mLastViewPort ); 00491 00492 /* Check for out of memory error */ 00493 if ( myScanData == NULL ) 00494 { 00495 return; 00496 } 00497 00498 if ( 0 < theBand && theBand <= ( int ) bandCount() ) 00499 { 00500 // Was there any reason to use float for myMin, myMax, myValue? 00501 // It was breaking Float64 data obviously, especially if an extreme value 00502 // was used for NoDataValue. 00503 double myMin = std::numeric_limits<double>::max(); 00504 double myMax = -1 * std::numeric_limits<double>::max(); 00505 double myValue = 0.0; 00506 for ( int myRow = 0; myRow < mLastViewPort.drawableAreaYDim; ++myRow ) 00507 { 00508 for ( int myColumn = 0; myColumn < mLastViewPort.drawableAreaXDim; ++myColumn ) 00509 { 00510 myValue = readValue( myScanData, myDataType, myRow * mLastViewPort.drawableAreaXDim + myColumn ); 00511 if ( mValidNoDataValue && ( qAbs( myValue - mNoDataValue ) <= TINY_VALUE || myValue != myValue ) ) 00512 { 00513 continue; 00514 } 00515 myMin = qMin( myMin, myValue ); 00516 myMax = qMax( myMax, myValue ); 00517 } 00518 } 00519 theMinMax[0] = myMin; 00520 theMinMax[1] = myMax; 00521 } 00522 } 00523 00528 void QgsRasterLayer::computeMinimumMaximumFromLastExtent( QString theBand, double* theMinMax ) 00529 { 00530 computeMinimumMaximumFromLastExtent( bandNumber( theBand ), theMinMax ); 00531 } 00532 00533 void QgsRasterLayer::computeMinimumMaximumFromLastExtent( int theBand, double& theMin, double& theMax ) 00534 { 00535 double theMinMax[2]; 00536 computeMinimumMaximumFromLastExtent( theBand, theMinMax ); 00537 theMin = theMinMax[0]; 00538 theMax = theMinMax[1]; 00539 } 00540 00545 QgsContrastEnhancement* QgsRasterLayer::contrastEnhancement( unsigned int theBand ) 00546 { 00547 if ( 0 < theBand && theBand <= bandCount() ) 00548 { 00549 return &mContrastEnhancementList[theBand - 1]; 00550 } 00551 00552 return 0; 00553 } 00554 00555 const QgsContrastEnhancement* QgsRasterLayer::constContrastEnhancement( unsigned int theBand ) const 00556 { 00557 if ( 0 < theBand && theBand <= bandCount() ) 00558 { 00559 return &mContrastEnhancementList[theBand - 1]; 00560 } 00561 00562 return 0; 00563 } 00564 00565 QString QgsRasterLayer::contrastEnhancementAlgorithmAsString() const 00566 { 00567 switch ( mContrastEnhancementAlgorithm ) 00568 { 00569 case QgsContrastEnhancement::NoEnhancement: 00570 return QString( "NoEnhancement" ); 00571 break; 00572 case QgsContrastEnhancement::StretchToMinimumMaximum: 00573 return QString( "StretchToMinimumMaximum" ); 00574 break; 00575 case QgsContrastEnhancement::StretchAndClipToMinimumMaximum: 00576 return QString( "StretchAndClipToMinimumMaximum" ); 00577 break; 00578 case QgsContrastEnhancement::ClipToMinimumMaximum: 00579 return QString( "ClipToMinimumMaximum" ); 00580 break; 00581 case QgsContrastEnhancement::UserDefinedEnhancement: 00582 return QString( "UserDefined" ); 00583 break; 00584 } 00585 00586 return QString( "NoEnhancement" ); 00587 } 00588 00593 bool QgsRasterLayer::copySymbologySettings( const QgsMapLayer& theOther ) 00594 { 00595 //prevent warnings 00596 if ( theOther.type() < 0 ) 00597 { 00598 return false; 00599 } 00600 return false; 00601 } //todo 00602 00607 QList<QgsColorRampShader::ColorRampItem>* QgsRasterLayer::colorTable( int theBandNo ) 00608 { 00609 return &( mRasterStatsList[theBandNo-1].colorTable ); 00610 } 00611 00615 QgsRasterDataProvider* QgsRasterLayer::dataProvider() 00616 { 00617 return mDataProvider; 00618 } 00619 00623 const QgsRasterDataProvider* QgsRasterLayer::dataProvider() const 00624 { 00625 return mDataProvider; 00626 } 00627 00628 void QgsRasterLayer::reload() 00629 { 00630 if ( mDataProvider ) 00631 { 00632 mDataProvider->reloadData(); 00633 } 00634 } 00635 00636 bool QgsRasterLayer::draw( QgsRenderContext& rendererContext ) 00637 { 00638 QgsDebugMsg( "entered. (renderContext)" ); 00639 00640 // Don't waste time drawing if transparency is at 0 (completely transparent) 00641 if ( mTransparencyLevel == 0 ) 00642 return true; 00643 00644 QgsDebugMsg( "checking timestamp." ); 00645 00646 // Check timestamp 00647 if ( !update() ) 00648 { 00649 return false; 00650 } 00651 00652 const QgsMapToPixel& theQgsMapToPixel = rendererContext.mapToPixel(); 00653 00654 QgsRectangle myProjectedViewExtent; 00655 QgsRectangle myProjectedLayerExtent; 00656 00657 if ( rendererContext.coordinateTransform() ) 00658 { 00659 QgsDebugMsg( "coordinateTransform set -> project extents." ); 00660 try 00661 { 00662 myProjectedViewExtent = rendererContext.coordinateTransform()->transformBoundingBox( rendererContext.extent() ); 00663 } 00664 catch ( QgsCsException &cs ) 00665 { 00666 QgsMessageLog::logMessage( tr( "Could not reproject view extent: %1" ).arg( cs.what() ), tr( "Raster" ) ); 00667 myProjectedViewExtent.setMinimal(); 00668 } 00669 00670 try 00671 { 00672 myProjectedLayerExtent = rendererContext.coordinateTransform()->transformBoundingBox( mLayerExtent ); 00673 } 00674 catch ( QgsCsException &cs ) 00675 { 00676 QgsMessageLog::logMessage( tr( "Could not reproject layer extent: %1" ).arg( cs.what() ), tr( "Raster" ) ); 00677 myProjectedViewExtent.setMinimal(); 00678 } 00679 } 00680 else 00681 { 00682 QgsDebugMsg( "coordinateTransform not set" ); 00683 myProjectedViewExtent = rendererContext.extent(); 00684 myProjectedLayerExtent = mLayerExtent; 00685 } 00686 00687 QPainter* theQPainter = rendererContext.painter(); 00688 00689 if ( !theQPainter ) 00690 { 00691 return false; 00692 } 00693 00694 // clip raster extent to view extent 00695 //QgsRectangle myRasterExtent = theViewExtent.intersect( &mLayerExtent ); 00696 QgsRectangle myRasterExtent = myProjectedViewExtent.intersect( &myProjectedLayerExtent ); 00697 if ( myRasterExtent.isEmpty() ) 00698 { 00699 QgsDebugMsg( "draw request outside view extent." ); 00700 // nothing to do 00701 return true; 00702 } 00703 00704 QgsDebugMsg( "theViewExtent is " + rendererContext.extent().toString() ); 00705 QgsDebugMsg( "myProjectedViewExtent is " + myProjectedViewExtent.toString() ); 00706 QgsDebugMsg( "myProjectedLayerExtent is " + myProjectedLayerExtent.toString() ); 00707 QgsDebugMsg( "myRasterExtent is " + myRasterExtent.toString() ); 00708 00709 // 00710 // The first thing we do is set up the QgsRasterViewPort. This struct stores all the settings 00711 // relating to the size (in pixels and coordinate system units) of the raster part that is 00712 // in view in the map window. It also stores the origin. 00713 // 00714 //this is not a class level member because every time the user pans or zooms 00715 //the contents of the rasterViewPort will change 00716 QgsRasterViewPort *myRasterViewPort = new QgsRasterViewPort(); 00717 00718 myRasterViewPort->mDrawnExtent = myRasterExtent; 00719 if ( rendererContext.coordinateTransform() ) 00720 { 00721 myRasterViewPort->mSrcCRS = crs(); 00722 myRasterViewPort->mDestCRS = rendererContext.coordinateTransform()->destCRS(); 00723 } 00724 else 00725 { 00726 myRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid 00727 myRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid 00728 } 00729 00730 // get dimensions of clipped raster image in device coordinate space (this is the size of the viewport) 00731 myRasterViewPort->topLeftPoint = theQgsMapToPixel.transform( myRasterExtent.xMinimum(), myRasterExtent.yMaximum() ); 00732 myRasterViewPort->bottomRightPoint = theQgsMapToPixel.transform( myRasterExtent.xMaximum(), myRasterExtent.yMinimum() ); 00733 00734 // align to output device grid, i.e. floor/ceil to integers 00735 // TODO: this should only be done if paint device is raster - screen, image 00736 // for other devices (pdf) it can have floating point origin 00737 // we could use floating point for raster devices as well, but respecting the 00738 // output device grid should make it more effective as the resampling is done in 00739 // the provider anyway 00740 if ( true ) 00741 { 00742 myRasterViewPort->topLeftPoint.setX( floor( myRasterViewPort->topLeftPoint.x() ) ); 00743 myRasterViewPort->topLeftPoint.setY( floor( myRasterViewPort->topLeftPoint.y() ) ); 00744 myRasterViewPort->bottomRightPoint.setX( ceil( myRasterViewPort->bottomRightPoint.x() ) ); 00745 myRasterViewPort->bottomRightPoint.setY( ceil( myRasterViewPort->bottomRightPoint.y() ) ); 00746 // recalc myRasterExtent to aligned values 00747 myRasterExtent.set( 00748 theQgsMapToPixel.toMapCoordinatesF( myRasterViewPort->topLeftPoint.x(), 00749 myRasterViewPort->bottomRightPoint.y() ), 00750 theQgsMapToPixel.toMapCoordinatesF( myRasterViewPort->bottomRightPoint.x(), 00751 myRasterViewPort->topLeftPoint.y() ) 00752 ); 00753 00754 } 00755 00756 myRasterViewPort->drawableAreaXDim = static_cast<int>( qAbs(( myRasterExtent.width() / theQgsMapToPixel.mapUnitsPerPixel() ) ) ); 00757 myRasterViewPort->drawableAreaYDim = static_cast<int>( qAbs(( myRasterExtent.height() / theQgsMapToPixel.mapUnitsPerPixel() ) ) ); 00758 00759 //the drawable area can start to get very very large when you get down displaying 2x2 or smaller, this is becasue 00760 //theQgsMapToPixel.mapUnitsPerPixel() is less then 1, 00761 //so we will just get the pixel data and then render these special cases differently in paintImageToCanvas() 00762 #if 0 00763 if ( 2 >= myRasterViewPort->clippedWidth && 2 >= myRasterViewPort->clippedHeight ) 00764 { 00765 myRasterViewPort->drawableAreaXDim = myRasterViewPort->clippedWidth; 00766 myRasterViewPort->drawableAreaYDim = myRasterViewPort->clippedHeight; 00767 } 00768 #endif 00769 00770 QgsDebugMsgLevel( QString( "mapUnitsPerPixel = %1" ).arg( theQgsMapToPixel.mapUnitsPerPixel() ), 3 ); 00771 QgsDebugMsgLevel( QString( "mWidth = %1" ).arg( mWidth ), 3 ); 00772 QgsDebugMsgLevel( QString( "mHeight = %1" ).arg( mHeight ), 3 ); 00773 QgsDebugMsgLevel( QString( "myRasterExtent.xMinimum() = %1" ).arg( myRasterExtent.xMinimum() ), 3 ); 00774 QgsDebugMsgLevel( QString( "myRasterExtent.xMaximum() = %1" ).arg( myRasterExtent.xMaximum() ), 3 ); 00775 QgsDebugMsgLevel( QString( "myRasterExtent.yMinimum() = %1" ).arg( myRasterExtent.yMinimum() ), 3 ); 00776 QgsDebugMsgLevel( QString( "myRasterExtent.yMaximum() = %1" ).arg( myRasterExtent.yMaximum() ), 3 ); 00777 00778 QgsDebugMsgLevel( QString( "topLeftPoint.x() = %1" ).arg( myRasterViewPort->topLeftPoint.x() ), 3 ); 00779 QgsDebugMsgLevel( QString( "bottomRightPoint.x() = %1" ).arg( myRasterViewPort->bottomRightPoint.x() ), 3 ); 00780 QgsDebugMsgLevel( QString( "topLeftPoint.y() = %1" ).arg( myRasterViewPort->topLeftPoint.y() ), 3 ); 00781 QgsDebugMsgLevel( QString( "bottomRightPoint.y() = %1" ).arg( myRasterViewPort->bottomRightPoint.y() ), 3 ); 00782 00783 QgsDebugMsgLevel( QString( "drawableAreaXDim = %1" ).arg( myRasterViewPort->drawableAreaXDim ), 3 ); 00784 QgsDebugMsgLevel( QString( "drawableAreaYDim = %1" ).arg( myRasterViewPort->drawableAreaYDim ), 3 ); 00785 00786 QgsDebugMsgLevel( "ReadXml: gray band name : " + mGrayBandName, 3 ); 00787 QgsDebugMsgLevel( "ReadXml: red band name : " + mRedBandName, 3 ); 00788 QgsDebugMsgLevel( "ReadXml: green band name : " + mGreenBandName, 3 ); 00789 QgsDebugMsgLevel( "ReadXml: blue band name : " + mBlueBandName, 3 ); 00790 00791 // /\/\/\ - added to handle zoomed-in rasters 00792 00793 mLastViewPort = *myRasterViewPort; 00794 00795 // Provider mode: See if a provider key is specified, and if so use the provider instead 00796 00797 mDataProvider->setDpi( rendererContext.rasterScaleFactor() * 25.4 * rendererContext.scaleFactor() ); 00798 00799 draw( theQPainter, myRasterViewPort, &theQgsMapToPixel ); 00800 00801 delete myRasterViewPort; 00802 QgsDebugMsg( "exiting." ); 00803 00804 return true; 00805 00806 } 00807 00808 void QgsRasterLayer::draw( QPainter * theQPainter, 00809 QgsRasterViewPort * theRasterViewPort, 00810 const QgsMapToPixel* theQgsMapToPixel ) 00811 { 00812 QgsDebugMsg( " 3 arguments" ); 00813 QTime time; 00814 time.start(); 00815 // 00816 // 00817 // The goal here is to make as many decisions as possible early on (outside of the rendering loop) 00818 // so that we can maximise performance of the rendering process. So now we check which drawing 00819 // procedure to use : 00820 // 00821 00822 QgsDebugMsg( "mDrawingStyle = " + QString::number( mDrawingStyle ) ); 00823 switch ( mDrawingStyle ) 00824 { 00825 // a "Gray" or "Undefined" layer drawn as a range of gray colors 00826 case SingleBandGray: 00827 //check the band is set! 00828 if ( mGrayBandName == TRSTRING_NOT_SET ) 00829 { 00830 break; 00831 } 00832 else 00833 { 00834 drawSingleBandGray( theQPainter, theRasterViewPort, 00835 theQgsMapToPixel, bandNumber( mGrayBandName ) ); 00836 break; 00837 } 00838 // a "Gray" or "Undefined" layer drawn using a pseudocolor algorithm 00839 case SingleBandPseudoColor: 00840 //check the band is set! 00841 if ( mGrayBandName == TRSTRING_NOT_SET ) 00842 { 00843 break; 00844 } 00845 else 00846 { 00847 drawSingleBandPseudoColor( theQPainter, theRasterViewPort, 00848 theQgsMapToPixel, bandNumber( mGrayBandName ) ); 00849 break; 00850 } 00851 // a single band with a color map 00852 case PalettedColor: 00853 //check the band is set! 00854 if ( mGrayBandName == TRSTRING_NOT_SET ) 00855 { 00856 break; 00857 } 00858 else 00859 { 00860 QgsDebugMsg( "PalettedColor drawing type detected..." ); 00861 00862 drawPalettedSingleBandColor( theQPainter, theRasterViewPort, 00863 theQgsMapToPixel, bandNumber( mGrayBandName ) ); 00864 break; 00865 } 00866 // a "Palette" layer drawn in gray scale (using only one of the color components) 00867 case PalettedSingleBandGray: 00868 //check the band is set! 00869 if ( mGrayBandName == TRSTRING_NOT_SET ) 00870 { 00871 break; 00872 } 00873 else 00874 { 00875 QgsDebugMsg( "PalettedSingleBandGray drawing type detected..." ); 00876 00877 int myBandNo = 1; 00878 drawPalettedSingleBandGray( theQPainter, theRasterViewPort, 00879 theQgsMapToPixel, myBandNo ); 00880 00881 break; 00882 } 00883 // a "Palette" layer having only one of its color components rendered as psuedo color 00884 case PalettedSingleBandPseudoColor: 00885 //check the band is set! 00886 if ( mGrayBandName == TRSTRING_NOT_SET ) 00887 { 00888 break; 00889 } 00890 else 00891 { 00892 00893 int myBandNo = 1; 00894 drawPalettedSingleBandPseudoColor( theQPainter, theRasterViewPort, 00895 theQgsMapToPixel, myBandNo ); 00896 break; 00897 } 00898 //a "Palette" image where the bands contains 24bit color info and 8 bits is pulled out per color 00899 case PalettedMultiBandColor: 00900 drawPalettedMultiBandColor( theQPainter, theRasterViewPort, 00901 theQgsMapToPixel, 1 ); 00902 break; 00903 // a layer containing 2 or more bands, but using only one band to produce a grayscale image 00904 case MultiBandSingleBandGray: 00905 QgsDebugMsg( "MultiBandSingleBandGray drawing type detected..." ); 00906 //check the band is set! 00907 if ( mGrayBandName == TRSTRING_NOT_SET ) 00908 { 00909 QgsDebugMsg( "MultiBandSingleBandGray Not Set detected..." + mGrayBandName ); 00910 break; 00911 } 00912 else 00913 { 00914 00915 //get the band number for the mapped gray band 00916 drawMultiBandSingleBandGray( theQPainter, theRasterViewPort, 00917 theQgsMapToPixel, bandNumber( mGrayBandName ) ); 00918 break; 00919 } 00920 //a layer containing 2 or more bands, but using only one band to produce a pseudocolor image 00921 case MultiBandSingleBandPseudoColor: 00922 //check the band is set! 00923 if ( mGrayBandName == TRSTRING_NOT_SET ) 00924 { 00925 break; 00926 } 00927 else 00928 { 00929 00930 drawMultiBandSingleBandPseudoColor( theQPainter, theRasterViewPort, 00931 theQgsMapToPixel, bandNumber( mGrayBandName ) ); 00932 break; 00933 } 00934 //a layer containing 2 or more bands, mapped to the three RGBcolors. 00935 //In the case of a multiband with only two bands, 00936 //one band will have to be mapped to more than one color 00937 case MultiBandColor: 00938 if ( mRedBandName == TRSTRING_NOT_SET || 00939 mGreenBandName == TRSTRING_NOT_SET || 00940 mBlueBandName == TRSTRING_NOT_SET ) 00941 { 00942 break; 00943 } 00944 else 00945 { 00946 drawMultiBandColor( theQPainter, theRasterViewPort, 00947 theQgsMapToPixel ); 00948 } 00949 break; 00950 case SingleBandColorDataStyle: 00951 //check the band is set! 00952 if ( mGrayBandName == TRSTRING_NOT_SET ) 00953 { 00954 break; 00955 } 00956 else 00957 { 00958 drawSingleBandColorData( theQPainter, theRasterViewPort, 00959 theQgsMapToPixel, bandNumber( mGrayBandName ) ); 00960 break; 00961 } 00962 00963 default: 00964 break; 00965 00966 } 00967 QgsDebugMsg( QString( "raster draw time (ms): %1" ).arg( time.elapsed() ) ); 00968 } //end of draw method 00969 00970 QString QgsRasterLayer::drawingStyleAsString() const 00971 { 00972 switch ( mDrawingStyle ) 00973 { 00974 case SingleBandGray: 00975 return QString( "SingleBandGray" ); //no need to tr() this its not shown in ui 00976 break; 00977 case SingleBandPseudoColor: 00978 return QString( "SingleBandPseudoColor" );//no need to tr() this its not shown in ui 00979 break; 00980 case PalettedColor: 00981 return QString( "PalettedColor" );//no need to tr() this its not shown in ui 00982 break; 00983 case PalettedSingleBandGray: 00984 return QString( "PalettedSingleBandGray" );//no need to tr() this its not shown in ui 00985 break; 00986 case PalettedSingleBandPseudoColor: 00987 return QString( "PalettedSingleBandPseudoColor" );//no need to tr() this its not shown in ui 00988 break; 00989 case PalettedMultiBandColor: 00990 return QString( "PalettedMultiBandColor" );//no need to tr() this its not shown in ui 00991 break; 00992 case MultiBandSingleBandGray: 00993 return QString( "MultiBandSingleBandGray" );//no need to tr() this its not shown in ui 00994 break; 00995 case MultiBandSingleBandPseudoColor: 00996 return QString( "MultiBandSingleBandPseudoColor" );//no need to tr() this its not shown in ui 00997 break; 00998 case MultiBandColor: 00999 return QString( "MultiBandColor" );//no need to tr() this its not shown in ui 01000 break; 01001 case SingleBandColorDataStyle: 01002 return QString( "SingleBandColorDataStyle" );//no need to tr() this its not shown in ui 01003 break; 01004 default: 01005 break; 01006 } 01007 01008 return QString( "UndefinedDrawingStyle" ); 01009 01010 } 01011 01016 bool QgsRasterLayer::hasCompatibleSymbology( const QgsMapLayer& theOther ) const 01017 { 01018 //prevent warnings 01019 if ( theOther.type() < 0 ) 01020 { 01021 return false; 01022 } 01023 return false; 01024 } //todo 01025 01030 bool QgsRasterLayer::hasStatistics( int theBandNo ) 01031 { 01032 if ( theBandNo <= mRasterStatsList.size() && theBandNo > 0 ) 01033 { 01034 //vector starts at base 0, band counts at base1! 01035 return mRasterStatsList[theBandNo - 1].statsGathered; 01036 } 01037 else 01038 { 01039 return false; 01040 } 01041 } 01042 01048 bool QgsRasterLayer::identify( const QgsPoint& thePoint, QMap<QString, QString>& theResults ) 01049 { 01050 theResults.clear(); 01051 01052 QgsDebugMsg( "identify provider : " + mProviderKey ) ; 01053 return ( mDataProvider->identify( thePoint, theResults ) ); 01054 } 01055 01062 QString QgsRasterLayer::identifyAsText( const QgsPoint& thePoint ) 01063 { 01064 if ( mProviderKey != "wms" ) 01065 { 01066 // Currently no meaning for anything other than OGC WMS layers 01067 return QString(); 01068 } 01069 01070 return mDataProvider->identifyAsText( thePoint ); 01071 } 01072 01079 QString QgsRasterLayer::identifyAsHtml( const QgsPoint& thePoint ) 01080 { 01081 if ( mProviderKey != "wms" ) 01082 { 01083 // Currently no meaning for anything other than OGC WMS layers 01084 return QString(); 01085 } 01086 01087 return mDataProvider->identifyAsHtml( thePoint ); 01088 } 01089 01094 bool QgsRasterLayer::isEditable() const 01095 { 01096 return false; 01097 } 01098 01099 QString QgsRasterLayer::lastError() 01100 { 01101 return mError; 01102 } 01103 01104 QString QgsRasterLayer::lastErrorTitle() 01105 { 01106 return mErrorCaption; 01107 } 01108 01109 QList< QPair< QString, QColor > > QgsRasterLayer::legendSymbologyItems() const 01110 { 01111 QList< QPair< QString, QColor > > symbolList; 01112 if ( mDrawingStyle == SingleBandGray || mDrawingStyle == PalettedSingleBandGray || mDrawingStyle == MultiBandSingleBandGray ) 01113 { 01114 //add min/max from contrast enhancement 01115 QString grayBand = grayBandName(); 01116 if ( !grayBand.isEmpty() ) 01117 { 01118 int grayBandNr = bandNumber( grayBand ); 01119 const QgsContrastEnhancement* ceh = constContrastEnhancement( grayBandNr ); 01120 if ( ceh ) 01121 { 01122 QgsContrastEnhancement::ContrastEnhancementAlgorithm alg = ceh->contrastEnhancementAlgorithm(); 01123 if ( alg == QgsContrastEnhancement::NoEnhancement 01124 || alg == QgsContrastEnhancement::ClipToMinimumMaximum ) 01125 { 01126 //diffcult to display a meaningful item 01127 symbolList.push_back( qMakePair( QString::number( ceh->minimumValue() ) + "-" + QString::number( ceh->maximumValue() ), QColor( 125, 125, 125 ) ) ); 01128 } 01129 else 01130 { 01131 symbolList.push_back( qMakePair( QString::number( ceh->minimumValue() ), QColor( 0, 0, 0 ) ) ); 01132 symbolList.push_back( qMakePair( QString::number( ceh->maximumValue() ), QColor( 255, 255, 255 ) ) ); 01133 } 01134 } 01135 } 01136 } 01137 else 01138 { 01139 switch ( mColorShadingAlgorithm ) 01140 { 01141 case ColorRampShader: 01142 { 01143 const QgsColorRampShader* crShader = dynamic_cast<QgsColorRampShader*>( mRasterShader->rasterShaderFunction() ); 01144 if ( crShader ) 01145 { 01146 QList<QgsColorRampShader::ColorRampItem> shaderItems = crShader->colorRampItemList(); 01147 QList<QgsColorRampShader::ColorRampItem>::const_iterator itemIt = shaderItems.constBegin(); 01148 for ( ; itemIt != shaderItems.constEnd(); ++itemIt ) 01149 { 01150 symbolList.push_back( qMakePair( itemIt->label, itemIt->color ) ); 01151 } 01152 } 01153 break; 01154 } 01155 case PseudoColorShader: 01156 { 01157 //class breaks have fixed color for the pseudo color shader 01158 const QgsPseudoColorShader* pcShader = dynamic_cast<QgsPseudoColorShader*>( mRasterShader->rasterShaderFunction() ); 01159 if ( pcShader ) 01160 { 01161 symbolList.push_back( qMakePair( QString::number( pcShader->classBreakMin1() ), QColor( 0, 0, 255 ) ) ); 01162 symbolList.push_back( qMakePair( QString::number( pcShader->classBreakMax1() ), QColor( 0, 255, 255 ) ) ); 01163 symbolList.push_back( qMakePair( QString::number( pcShader->classBreakMax2() ), QColor( 255, 255, 0 ) ) ); 01164 symbolList.push_back( qMakePair( QString::number( pcShader->maximumValue() ), QColor( 255, 0, 0 ) ) ); 01165 } 01166 break; 01167 } 01168 case FreakOutShader: 01169 { 01170 const QgsFreakOutShader* foShader = dynamic_cast<QgsFreakOutShader*>( mRasterShader->rasterShaderFunction() ); 01171 if ( foShader ) 01172 { 01173 symbolList.push_back( qMakePair( QString::number( foShader->classBreakMin1() ), QColor( 255, 0, 255 ) ) ); 01174 symbolList.push_back( qMakePair( QString::number( foShader->classBreakMax1() ), QColor( 0, 255, 255 ) ) ); 01175 symbolList.push_back( qMakePair( QString::number( foShader->classBreakMax2() ), QColor( 255, 0, 0 ) ) ); 01176 symbolList.push_back( qMakePair( QString::number( foShader->maximumValue() ), QColor( 0, 255, 0 ) ) ); 01177 } 01178 break; 01179 } 01180 default: 01181 { 01182 break; 01183 } 01184 } 01185 } 01186 return symbolList; 01187 } 01188 01193 QPixmap QgsRasterLayer::legendAsPixmap() 01194 { 01195 return legendAsPixmap( false ); 01196 } 01197 01202 QPixmap QgsRasterLayer::legendAsPixmap( bool theWithNameFlag ) 01203 { 01204 QgsDebugMsg( "called (" + drawingStyleAsString() + ")" ); 01205 01206 QPixmap myLegendQPixmap; //will be initialised once we know what drawing style is active 01207 QPainter myQPainter; 01208 01209 01210 if ( !mProviderKey.isEmpty() ) 01211 { 01212 QgsDebugMsg( "provider Key (" + mProviderKey + ")" ); 01213 myLegendQPixmap = QPixmap( 3, 1 ); 01214 myQPainter.begin( &myLegendQPixmap ); 01215 //draw legend red part 01216 myQPainter.setPen( QPen( QColor( 255, 0, 0 ), 0 ) ); 01217 myQPainter.drawPoint( 0, 0 ); 01218 //draw legend green part 01219 myQPainter.setPen( QPen( QColor( 0, 255, 0 ), 0 ) ); 01220 myQPainter.drawPoint( 1, 0 ); 01221 //draw legend blue part 01222 myQPainter.setPen( QPen( QColor( 0, 0, 255 ), 0 ) ); 01223 myQPainter.drawPoint( 2, 0 ); 01224 01225 } 01226 else 01227 { 01228 // Legacy GDAL (non-provider) 01229 01230 // 01231 // Get the adjusted matrix stats 01232 // 01233 QString myColorerpretation = mDataProvider->colorInterpretationName( 1 ); 01234 01235 // 01236 // Create the legend pixmap - note it is generated on the preadjusted stats 01237 // 01238 if ( mDrawingStyle == MultiBandSingleBandGray || mDrawingStyle == PalettedSingleBandGray || mDrawingStyle == SingleBandGray ) 01239 { 01240 01241 myLegendQPixmap = QPixmap( 100, 1 ); 01242 myQPainter.begin( &myLegendQPixmap ); 01243 int myPos = 0; 01244 for ( double my = 0; my < 255; my += 2.55 ) 01245 { 01246 if ( !mInvertColor ) //histogram is not inverted 01247 { 01248 //draw legend as grayscale 01249 int myGray = static_cast < int >( my ); 01250 myQPainter.setPen( QPen( QColor( myGray, myGray, myGray ), 0 ) ); 01251 } 01252 else //histogram is inverted 01253 { 01254 //draw legend as inverted grayscale 01255 int myGray = 255 - static_cast < int >( my ); 01256 myQPainter.setPen( QPen( QColor( myGray, myGray, myGray ), 0 ) ); 01257 } //end of invert histogram check 01258 myQPainter.drawPoint( myPos++, 0 ); 01259 } 01260 } //end of gray check 01261 else if ( mDrawingStyle == MultiBandSingleBandPseudoColor || 01262 mDrawingStyle == PalettedSingleBandPseudoColor || mDrawingStyle == SingleBandPseudoColor ) 01263 { 01264 01265 //set up the three class breaks for pseudocolor mapping 01266 double myRangeSize = 90; //hard coded for now 01267 double myBreakSize = myRangeSize / 3; 01268 double myClassBreakMin1 = 0; 01269 double myClassBreakMax1 = myClassBreakMin1 + myBreakSize; 01270 double myClassBreakMin2 = myClassBreakMax1; 01271 double myClassBreakMax2 = myClassBreakMin2 + myBreakSize; 01272 double myClassBreakMin3 = myClassBreakMax2; 01273 01274 // 01275 // Create the legend pixmap - note it is generated on the preadjusted stats 01276 // 01277 myLegendQPixmap = QPixmap( 100, 1 ); 01278 myQPainter.begin( &myLegendQPixmap ); 01279 int myPos = 0; 01280 for ( double my = 0; my < myRangeSize; my += myRangeSize / 100.0 ) 01281 { 01282 //draw pseudocolor legend 01283 if ( !mInvertColor ) 01284 { 01285 //check if we are in the first class break 01286 if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) ) 01287 { 01288 int myRed = 0; 01289 int myBlue = 255; 01290 int myGreen = static_cast < int >((( 255 / myRangeSize ) * ( my - myClassBreakMin1 ) ) * 3 ); 01291 // testing this stuff still ... 01292 if ( mColorShadingAlgorithm == FreakOutShader ) 01293 { 01294 myRed = 255 - myGreen; 01295 } 01296 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01297 } 01298 //check if we are in the second class break 01299 else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) ) 01300 { 01301 int myRed = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ); 01302 int myBlue = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ) ); 01303 int myGreen = 255; 01304 // testing this stuff still ... 01305 if ( mColorShadingAlgorithm == FreakOutShader ) 01306 { 01307 myGreen = myBlue; 01308 } 01309 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01310 } 01311 //otherwise we must be in the third classbreak 01312 else 01313 { 01314 int myRed = 255; 01315 int myBlue = 0; 01316 int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin3 ) / 1 ) * 3 ) ) ); 01317 // testing this stuff still ... 01318 if ( mColorShadingAlgorithm == FreakOutShader ) 01319 { 01320 myRed = myGreen; 01321 myGreen = 255 - myGreen; 01322 } 01323 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01324 } 01325 } //end of invert !histogram false check 01326 else //invert histogram toggle is off 01327 { 01328 //check if we are in the first class break 01329 if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) ) 01330 { 01331 int myRed = 255; 01332 int myBlue = 0; 01333 int myGreen = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin1 ) / 1 ) * 3 ) ); 01334 // testing this stuff still ... 01335 if ( mColorShadingAlgorithm == FreakOutShader ) 01336 { 01337 myRed = 255 - myGreen; 01338 } 01339 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01340 } 01341 //check if we are in the second class break 01342 else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) ) 01343 { 01344 int myRed = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ) ); 01345 int myBlue = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ); 01346 int myGreen = 255; 01347 // testing this stuff still ... 01348 if ( mColorShadingAlgorithm == FreakOutShader ) 01349 { 01350 myGreen = myBlue; 01351 } 01352 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01353 } 01354 //otherwise we must be in the third classbreak 01355 else 01356 { 01357 int myRed = 0; 01358 int myBlue = 255; 01359 int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * ( my - myClassBreakMin3 ) ) * 3 ) ); 01360 // testing this stuff still ... 01361 if ( mColorShadingAlgorithm == FreakOutShader ) 01362 { 01363 myRed = 255 - myGreen; 01364 } 01365 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01366 } 01367 01368 } //end of invert histogram check 01369 myQPainter.drawPoint( myPos++, 0 ); 01370 } 01371 01372 } //end of pseudocolor check 01373 else if ( mDrawingStyle == PalettedMultiBandColor || mDrawingStyle == MultiBandColor || mDrawingStyle == PalettedColor ) 01374 { 01375 // 01376 // Create the legend pixmap showing red green and blue band mappings 01377 // 01378 // TODO update this so it actually shows the mappings for paletted images 01379 myLegendQPixmap = QPixmap( 3, 1 ); 01380 myQPainter.begin( &myLegendQPixmap ); 01381 //draw legend red part 01382 myQPainter.setPen( QPen( QColor( 224, 103, 103 ), 0 ) ); 01383 myQPainter.drawPoint( 0, 0 ); 01384 //draw legend green part 01385 myQPainter.setPen( QPen( QColor( 132, 224, 127 ), 0 ) ); 01386 myQPainter.drawPoint( 1, 0 ); 01387 //draw legend blue part 01388 myQPainter.setPen( QPen( QColor( 127, 160, 224 ), 0 ) ); 01389 myQPainter.drawPoint( 2, 0 ); 01390 } 01391 } 01392 01393 myQPainter.end(); 01394 01395 01396 // see if the caller wants the name of the layer in the pixmap (used for legend bar) 01397 if ( theWithNameFlag ) 01398 { 01399 QFont myQFont( "arial", 10, QFont::Normal ); 01400 QFontMetrics myQFontMetrics( myQFont ); 01401 01402 int myHeight = ( myQFontMetrics.height() + 10 > 35 ) ? myQFontMetrics.height() + 10 : 35; 01403 01404 //create a matrix to 01405 QMatrix myQWMatrix; 01406 //scale the raster legend up a bit bigger to the legend item size 01407 //note that scaling parameters are factors, not absolute values, 01408 // so scale (0.25,1) scales the painter to a quarter of its size in the x direction 01409 //TODO We need to decide how much to scale by later especially for rgb images which are only 3x1 pix 01410 //hard coding thes values for now. 01411 if ( myLegendQPixmap.width() == 3 ) 01412 { 01413 //scale width by factor of 50 (=150px wide) 01414 myQWMatrix.scale( 60, myHeight ); 01415 } 01416 else 01417 { 01418 //assume 100px so scale by factor of 1.5 (=150px wide) 01419 myQWMatrix.scale( 1.8, myHeight ); 01420 } 01421 //apply the matrix 01422 QPixmap myQPixmap2 = myLegendQPixmap.transformed( myQWMatrix ); 01423 QPainter myQPainter( &myQPixmap2 ); 01424 01425 //load up the pyramid icons 01426 QString myThemePath = QgsApplication::activeThemePath(); 01427 QPixmap myPyramidPixmap( myThemePath + "/mIconPyramid.png" ); 01428 QPixmap myNoPyramidPixmap( myThemePath + "/mIconNoPyramid.png" ); 01429 01430 // 01431 // Overlay a pyramid icon 01432 // 01433 if ( mHasPyramids ) 01434 { 01435 myQPainter.drawPixmap( 0, myHeight - myPyramidPixmap.height(), myPyramidPixmap ); 01436 } 01437 else 01438 { 01439 myQPainter.drawPixmap( 0, myHeight - myNoPyramidPixmap.height(), myNoPyramidPixmap ); 01440 } 01441 // 01442 // Overlay the layer name 01443 // 01444 if ( mDrawingStyle == MultiBandSingleBandGray || mDrawingStyle == PalettedSingleBandGray || mDrawingStyle == SingleBandGray ) 01445 { 01446 myQPainter.setPen( Qt::white ); 01447 } 01448 else 01449 { 01450 myQPainter.setPen( Qt::black ); 01451 } 01452 myQPainter.setFont( myQFont ); 01453 myQPainter.drawText( 25, myHeight - 10, name() ); 01454 // 01455 // finish up 01456 // 01457 myLegendQPixmap = myQPixmap2; 01458 myQPainter.end(); 01459 } 01460 //finish up 01461 01462 return myLegendQPixmap; 01463 01464 } //end of legendAsPixmap function 01465 01470 QPixmap QgsRasterLayer::legendAsPixmap( int theLabelCount ) 01471 { 01472 QgsDebugMsg( "entered." ); 01473 QFont myQFont( "arial", 10, QFont::Normal ); 01474 QFontMetrics myQFontMetrics( myQFont ); 01475 01476 int myFontHeight = ( myQFontMetrics.height() ); 01477 const int myerLabelSpacing = 5; 01478 int myImageHeight = (( myFontHeight + ( myerLabelSpacing * 2 ) ) * theLabelCount ); 01479 //these next two vars are not used anywhere so commented out for now 01480 //int myLongestLabelWidth = myQFontMetrics.width(name()); 01481 //const int myHorizontalLabelSpacing = 5; 01482 const int myColorBarWidth = 10; 01483 // 01484 // Get the adjusted matrix stats 01485 // 01486 QString myColorerpretation = mDataProvider->colorInterpretationName( 1 ); 01487 QPixmap myLegendQPixmap; //will be initialised once we know what drawing style is active 01488 QPainter myQPainter; 01489 // 01490 // Create the legend pixmap - note it is generated on the preadjusted stats 01491 // 01492 if ( mDrawingStyle == MultiBandSingleBandGray || mDrawingStyle == PalettedSingleBandGray || mDrawingStyle == SingleBandGray ) 01493 { 01494 01495 myLegendQPixmap = QPixmap( 1, myImageHeight ); 01496 const double myIncrement = static_cast<double>( myImageHeight ) / 255.0; 01497 myQPainter.begin( &myLegendQPixmap ); 01498 int myPos = 0; 01499 for ( double my = 0; my < 255; my += myIncrement ) 01500 { 01501 if ( !mInvertColor ) //histogram is not inverted 01502 { 01503 //draw legend as grayscale 01504 int myGray = static_cast < int >( my ); 01505 myQPainter.setPen( QPen( QColor( myGray, myGray, myGray ), 0 ) ); 01506 } 01507 else //histogram is inverted 01508 { 01509 //draw legend as inverted grayscale 01510 int myGray = 255 - static_cast < int >( my ); 01511 myQPainter.setPen( QPen( QColor( myGray, myGray, myGray ), 0 ) ); 01512 } //end of invert histogram check 01513 myQPainter.drawPoint( 0, myPos++ ); 01514 } 01515 } //end of gray check 01516 else if ( mDrawingStyle == MultiBandSingleBandPseudoColor || 01517 mDrawingStyle == PalettedSingleBandPseudoColor || mDrawingStyle == SingleBandPseudoColor ) 01518 { 01519 01520 //set up the three class breaks for pseudocolor mapping 01521 double myRangeSize = 90; //hard coded for now 01522 double myBreakSize = myRangeSize / 3; 01523 double myClassBreakMin1 = 0; 01524 double myClassBreakMax1 = myClassBreakMin1 + myBreakSize; 01525 double myClassBreakMin2 = myClassBreakMax1; 01526 double myClassBreakMax2 = myClassBreakMin2 + myBreakSize; 01527 double myClassBreakMin3 = myClassBreakMax2; 01528 01529 // 01530 // Create the legend pixmap - note it is generated on the preadjusted stats 01531 // 01532 myLegendQPixmap = QPixmap( 1, myImageHeight ); 01533 const double myIncrement = myImageHeight / myRangeSize; 01534 myQPainter.begin( &myLegendQPixmap ); 01535 int myPos = 0; 01536 for ( double my = 0; my < 255; my += myIncrement ) 01537 for ( double my = 0; my < myRangeSize; my += myIncrement ) 01538 { 01539 //draw pseudocolor legend 01540 if ( !mInvertColor ) 01541 { 01542 //check if we are in the first class break 01543 if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) ) 01544 { 01545 int myRed = 0; 01546 int myBlue = 255; 01547 int myGreen = static_cast < int >((( 255 / myRangeSize ) * ( my - myClassBreakMin1 ) ) * 3 ); 01548 // testing this stuff still ... 01549 if ( mColorShadingAlgorithm == FreakOutShader ) 01550 { 01551 myRed = 255 - myGreen; 01552 } 01553 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01554 } 01555 //check if we are in the second class break 01556 else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) ) 01557 { 01558 int myRed = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ); 01559 int myBlue = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ) ); 01560 int myGreen = 255; 01561 // testing this stuff still ... 01562 if ( mColorShadingAlgorithm == FreakOutShader ) 01563 { 01564 myGreen = myBlue; 01565 } 01566 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01567 } 01568 //otherwise we must be in the third classbreak 01569 else 01570 { 01571 int myRed = 255; 01572 int myBlue = 0; 01573 int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin3 ) / 1 ) * 3 ) ) ); 01574 // testing this stuff still ... 01575 if ( mColorShadingAlgorithm == FreakOutShader ) 01576 { 01577 myRed = myGreen; 01578 myGreen = 255 - myGreen; 01579 } 01580 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01581 } 01582 } //end of invert !histogram check 01583 else //invert histogram toggle is off 01584 { 01585 //check if we are in the first class break 01586 if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) ) 01587 { 01588 int myRed = 255; 01589 int myBlue = 0; 01590 int myGreen = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin1 ) / 1 ) * 3 ) ); 01591 // testing this stuff still ... 01592 if ( mColorShadingAlgorithm == FreakOutShader ) 01593 { 01594 myRed = 255 - myGreen; 01595 } 01596 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01597 } 01598 //check if we are in the second class break 01599 else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) ) 01600 { 01601 int myRed = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ) ); 01602 int myBlue = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ); 01603 int myGreen = 255; 01604 // testing this stuff still ... 01605 if ( mColorShadingAlgorithm == FreakOutShader ) 01606 { 01607 myGreen = myBlue; 01608 } 01609 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01610 } 01611 //otherwise we must be in the third classbreak 01612 else 01613 { 01614 int myRed = 0; 01615 int myBlue = 255; 01616 int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * ( my - myClassBreakMin3 ) ) * 3 ) ); 01617 // testing this stuff still ... 01618 if ( mColorShadingAlgorithm == FreakOutShader ) 01619 { 01620 myRed = 255 - myGreen; 01621 } 01622 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01623 } 01624 01625 } //end of invert histogram check 01626 myQPainter.drawPoint( 0, myPos++ ); 01627 } 01628 01629 } //end of pseudocolor check 01630 else if ( mDrawingStyle == PalettedMultiBandColor || mDrawingStyle == MultiBandColor ) 01631 { 01632 // 01633 // Create the legend pixmap showing red green and blue band mappings 01634 // 01635 // TODO update this so it actually shows the mappings for paletted images 01636 myLegendQPixmap = QPixmap( 1, 3 ); 01637 myQPainter.begin( &myLegendQPixmap ); 01638 //draw legend red part 01639 myQPainter.setPen( QPen( QColor( 224, 103, 103 ), 0 ) ); 01640 myQPainter.drawPoint( 0, 0 ); 01641 //draw legend green part 01642 myQPainter.setPen( QPen( QColor( 132, 224, 127 ), 0 ) ); 01643 myQPainter.drawPoint( 0, 1 ); 01644 //draw legend blue part 01645 myQPainter.setPen( QPen( QColor( 127, 160, 224 ), 0 ) ); 01646 myQPainter.drawPoint( 0, 2 ); 01647 } 01648 01649 01650 myQPainter.end(); 01651 01652 01653 01654 //create a matrix to 01655 QMatrix myQWMatrix; 01656 //scale the raster legend up a bit bigger to the legend item size 01657 //note that scaling parameters are factors, not absolute values, 01658 // so scale (0.25,1) scales the painter to a quarter of its size in the x direction 01659 //TODO We need to decide how much to scale by later especially for rgb images which are only 3x1 pix 01660 //hard coding thes values for now. 01661 if ( myLegendQPixmap.height() == 3 ) 01662 { 01663 myQWMatrix.scale( myColorBarWidth, 2 ); 01664 } 01665 else 01666 { 01667 myQWMatrix.scale( myColorBarWidth, 2 ); 01668 } 01669 //apply the matrix 01670 QPixmap myQPixmap2 = myLegendQPixmap.transformed( myQWMatrix ); 01671 QPainter myQPainter2( &myQPixmap2 ); 01672 // 01673 // Overlay the layer name 01674 // 01675 if ( mDrawingStyle == MultiBandSingleBandGray || mDrawingStyle == PalettedSingleBandGray || mDrawingStyle == SingleBandGray ) 01676 { 01677 myQPainter2.setPen( Qt::white ); 01678 } 01679 else 01680 { 01681 myQPainter2.setPen( Qt::black ); 01682 } 01683 myQPainter2.setFont( myQFont ); 01684 myQPainter2.drawText( 25, myImageHeight - 10, name() ); 01685 // 01686 // finish up 01687 // 01688 myLegendQPixmap = myQPixmap2; 01689 myQPainter2.end(); 01690 //finish up 01691 01692 return myLegendQPixmap; 01693 01694 }//end of getDetailedLegend 01695 01700 double QgsRasterLayer::maximumValue( unsigned int theBand ) 01701 { 01702 if ( 0 < theBand && theBand <= bandCount() ) 01703 { 01704 return mContrastEnhancementList[theBand - 1].maximumValue(); 01705 } 01706 01707 return 0.0; 01708 } 01709 01714 double QgsRasterLayer::maximumValue( QString theBand ) 01715 { 01716 if ( theBand != tr( "Not Set" ) ) 01717 { 01718 return maximumValue( bandNumber( theBand ) ); 01719 } 01720 01721 return 0.0; 01722 } 01723 01724 01725 QString QgsRasterLayer::metadata() 01726 { 01727 QString myMetadata ; 01728 myMetadata += "<p class=\"glossy\">" + tr( "Driver:" ) + "</p>\n"; 01729 myMetadata += "<p>"; 01730 myMetadata += mDataProvider->description(); 01731 myMetadata += "</p>\n"; 01732 01733 // Insert provider-specific (e.g. WMS-specific) metadata 01734 // crashing 01735 //QString s = mDataProvider->metadata(); 01736 //QgsDebugMsg( s ); 01737 myMetadata += mDataProvider->metadata(); 01738 01739 myMetadata += "<p class=\"glossy\">"; 01740 myMetadata += tr( "No Data Value" ); 01741 myMetadata += "</p>\n"; 01742 myMetadata += "<p>"; 01743 if ( mValidNoDataValue ) 01744 { 01745 myMetadata += QString::number( mNoDataValue ); 01746 } 01747 else 01748 { 01749 myMetadata += "*" + tr( "NoDataValue not set" ) + "*"; 01750 } 01751 myMetadata += "</p>\n"; 01752 01753 myMetadata += "</p>\n"; 01754 myMetadata += "<p class=\"glossy\">"; 01755 myMetadata += tr( "Data Type:" ); 01756 myMetadata += "</p>\n"; 01757 myMetadata += "<p>"; 01758 //just use the first band 01759 switch ( mDataProvider->srcDataType( 1 ) ) 01760 { 01761 case GDT_Byte: 01762 myMetadata += tr( "GDT_Byte - Eight bit unsigned integer" ); 01763 break; 01764 case GDT_UInt16: 01765 myMetadata += tr( "GDT_UInt16 - Sixteen bit unsigned integer " ); 01766 break; 01767 case GDT_Int16: 01768 myMetadata += tr( "GDT_Int16 - Sixteen bit signed integer " ); 01769 break; 01770 case GDT_UInt32: 01771 myMetadata += tr( "GDT_UInt32 - Thirty two bit unsigned integer " ); 01772 break; 01773 case GDT_Int32: 01774 myMetadata += tr( "GDT_Int32 - Thirty two bit signed integer " ); 01775 break; 01776 case GDT_Float32: 01777 myMetadata += tr( "GDT_Float32 - Thirty two bit floating point " ); 01778 break; 01779 case GDT_Float64: 01780 myMetadata += tr( "GDT_Float64 - Sixty four bit floating point " ); 01781 break; 01782 case GDT_CInt16: 01783 myMetadata += tr( "GDT_CInt16 - Complex Int16 " ); 01784 break; 01785 case GDT_CInt32: 01786 myMetadata += tr( "GDT_CInt32 - Complex Int32 " ); 01787 break; 01788 case GDT_CFloat32: 01789 myMetadata += tr( "GDT_CFloat32 - Complex Float32 " ); 01790 break; 01791 case GDT_CFloat64: 01792 myMetadata += tr( "GDT_CFloat64 - Complex Float64 " ); 01793 break; 01794 default: 01795 myMetadata += tr( "Could not determine raster data type." ); 01796 } 01797 myMetadata += "</p>\n"; 01798 01799 myMetadata += "<p class=\"glossy\">"; 01800 myMetadata += tr( "Pyramid overviews:" ); 01801 myMetadata += "</p>\n"; 01802 myMetadata += "<p>"; 01803 01804 myMetadata += "<p class=\"glossy\">"; 01805 myMetadata += tr( "Layer Spatial Reference System: " ); 01806 myMetadata += "</p>\n"; 01807 myMetadata += "<p>"; 01808 myMetadata += crs().toProj4(); 01809 myMetadata += "</p>\n"; 01810 01811 myMetadata += "<p class=\"glossy\">"; 01812 myMetadata += tr( "Layer Extent (layer original source projection): " ); 01813 myMetadata += "</p>\n"; 01814 myMetadata += "<p>"; 01815 myMetadata += mDataProvider->extent().toString(); 01816 myMetadata += "</p>\n"; 01817 01818 // output coordinate system 01819 // TODO: this is not related to layer, to be removed? [MD] 01820 #if 0 01821 myMetadata += "<tr><td class=\"glossy\">"; 01822 myMetadata += tr( "Project Spatial Reference System: " ); 01823 myMetadata += "</p>\n"; 01824 myMetadata += "<p>"; 01825 myMetadata += mCoordinateTransform->destCRS().toProj4(); 01826 myMetadata += "</p>\n"; 01827 #endif 01828 01829 // 01830 // Add the stats for each band to the output table 01831 // 01832 int myBandCountInt = bandCount(); 01833 for ( int myIteratorInt = 1; myIteratorInt <= myBandCountInt; ++myIteratorInt ) 01834 { 01835 QgsDebugMsg( "Raster properties : checking if band " + QString::number( myIteratorInt ) + " has stats? " ); 01836 //band name 01837 myMetadata += "<p class=\"glossy\">\n"; 01838 myMetadata += tr( "Band" ); 01839 myMetadata += "</p>\n"; 01840 myMetadata += "<p>"; 01841 myMetadata += bandName( myIteratorInt ); 01842 myMetadata += "</p>\n"; 01843 //band number 01844 myMetadata += "<p>"; 01845 myMetadata += tr( "Band No" ); 01846 myMetadata += "</p>\n"; 01847 myMetadata += "<p>\n"; 01848 myMetadata += QString::number( myIteratorInt ); 01849 myMetadata += "</p>\n"; 01850 01851 //check if full stats for this layer have already been collected 01852 if ( !hasStatistics( myIteratorInt ) ) //not collected 01853 { 01854 QgsDebugMsg( ".....no" ); 01855 01856 myMetadata += "<p>"; 01857 myMetadata += tr( "No Stats" ); 01858 myMetadata += "</p>\n"; 01859 myMetadata += "<p>\n"; 01860 myMetadata += tr( "No stats collected yet" ); 01861 myMetadata += "</p>\n"; 01862 } 01863 else // collected - show full detail 01864 { 01865 QgsDebugMsg( ".....yes" ); 01866 01867 QgsRasterBandStats myRasterBandStats = bandStatistics( myIteratorInt ); 01868 //Min Val 01869 myMetadata += "<p>"; 01870 myMetadata += tr( "Min Val" ); 01871 myMetadata += "</p>\n"; 01872 myMetadata += "<p>\n"; 01873 myMetadata += QString::number( myRasterBandStats.minimumValue, 'f', 10 ); 01874 myMetadata += "</p>\n"; 01875 01876 // Max Val 01877 myMetadata += "<p>"; 01878 myMetadata += tr( "Max Val" ); 01879 myMetadata += "</p>\n"; 01880 myMetadata += "<p>\n"; 01881 myMetadata += QString::number( myRasterBandStats.maximumValue, 'f', 10 ); 01882 myMetadata += "</p>\n"; 01883 01884 // Range 01885 myMetadata += "<p>"; 01886 myMetadata += tr( "Range" ); 01887 myMetadata += "</p>\n"; 01888 myMetadata += "<p>\n"; 01889 myMetadata += QString::number( myRasterBandStats.range, 'f', 10 ); 01890 myMetadata += "</p>\n"; 01891 01892 // Mean 01893 myMetadata += "<p>"; 01894 myMetadata += tr( "Mean" ); 01895 myMetadata += "</p>\n"; 01896 myMetadata += "<p>\n"; 01897 myMetadata += QString::number( myRasterBandStats.mean, 'f', 10 ); 01898 myMetadata += "</p>\n"; 01899 01900 //sum of squares 01901 myMetadata += "<p>"; 01902 myMetadata += tr( "Sum of squares" ); 01903 myMetadata += "</p>\n"; 01904 myMetadata += "<p>\n"; 01905 myMetadata += QString::number( myRasterBandStats.sumOfSquares, 'f', 10 ); 01906 myMetadata += "</p>\n"; 01907 01908 //standard deviation 01909 myMetadata += "<p>"; 01910 myMetadata += tr( "Standard Deviation" ); 01911 myMetadata += "</p>\n"; 01912 myMetadata += "<p>\n"; 01913 myMetadata += QString::number( myRasterBandStats.stdDev, 'f', 10 ); 01914 myMetadata += "</p>\n"; 01915 01916 //sum of all cells 01917 myMetadata += "<p>"; 01918 myMetadata += tr( "Sum of all cells" ); 01919 myMetadata += "</p>\n"; 01920 myMetadata += "<p>\n"; 01921 myMetadata += QString::number( myRasterBandStats.sum, 'f', 10 ); 01922 myMetadata += "</p>\n"; 01923 01924 //number of cells 01925 myMetadata += "<p>"; 01926 myMetadata += tr( "Cell Count" ); 01927 myMetadata += "</p>\n"; 01928 myMetadata += "<p>\n"; 01929 myMetadata += QString::number( myRasterBandStats.elementCount ); 01930 myMetadata += "</p>\n"; 01931 } 01932 } 01933 01934 QgsDebugMsg( myMetadata ); 01935 return myMetadata; 01936 } 01937 01942 double QgsRasterLayer::minimumValue( unsigned int theBand ) 01943 { 01944 if ( 0 < theBand && theBand <= bandCount() ) 01945 { 01946 return mContrastEnhancementList[theBand - 1].minimumValue(); 01947 } 01948 01949 return 0.0; 01950 } 01951 01956 double QgsRasterLayer::minimumValue( QString theBand ) 01957 { 01958 return minimumValue( bandNumber( theBand ) ); 01959 } 01960 01965 QPixmap QgsRasterLayer::paletteAsPixmap( int theBandNumber ) 01966 { 01967 //TODO: This function should take dimensions 01968 QgsDebugMsg( "entered." ); 01969 01970 // Only do this for the non-provider (hard-coded GDAL) scenario... 01971 // Maybe WMS can do this differently using QImage::numColors and QImage::color() 01972 if ( mProviderKey.isEmpty() && hasBand( "Palette" ) && theBandNumber > 0 ) //don't tr() this its a gdal word! 01973 { 01974 QgsDebugMsg( "....found paletted image" ); 01975 QgsColorRampShader myShader; 01976 //QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = myShader.colorRampItemList(); 01977 01978 //if ( readColorTable( 1, &myColorRampItemList ) ) 01979 QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = mDataProvider->colorTable( 1 ); 01980 // TODO: add CT capability? It can depends on band (?) 01981 if ( myColorRampItemList.size() > 0 ) 01982 { 01983 QgsDebugMsg( "....got color ramp item list" ); 01984 myShader.setColorRampItemList( myColorRampItemList ); 01985 myShader.setColorRampType( QgsColorRampShader::DISCRETE ); 01986 // Draw image 01987 int mySize = 100; 01988 QPixmap myPalettePixmap( mySize, mySize ); 01989 QPainter myQPainter( &myPalettePixmap ); 01990 01991 QImage myQImage = QImage( mySize, mySize, QImage::Format_RGB32 ); 01992 myQImage.fill( 0 ); 01993 myPalettePixmap.fill(); 01994 01995 double myStep = (( double )myColorRampItemList.size() - 1 ) / ( double )( mySize * mySize ); 01996 double myValue = 0.0; 01997 for ( int myRow = 0; myRow < mySize; myRow++ ) 01998 { 01999 QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow ); 02000 for ( int myCol = 0; myCol < mySize; myCol++ ) 02001 { 02002 myValue = myStep * ( double )( myCol + myRow * mySize ); 02003 int c1, c2, c3; 02004 myShader.shade( myValue, &c1, &c2, &c3 ); 02005 myLineBuffer[ myCol ] = qRgb( c1, c2, c3 ); 02006 } 02007 } 02008 02009 myQPainter.drawImage( 0, 0, myQImage ); 02010 return myPalettePixmap; 02011 } 02012 QPixmap myNullPixmap; 02013 return myNullPixmap; 02014 } 02015 else 02016 { 02017 //invalid layer was requested 02018 QPixmap myNullPixmap; 02019 return myNullPixmap; 02020 } 02021 } 02022 02023 /* 02024 * @param theBandNoInt - which band to compute the histogram for 02025 * @param theBinCountInt - how many 'bins' to categorise the data into 02026 * @param theIgnoreOutOfRangeFlag - whether to ignore values that are out of range (default=true) 02027 * @param theThoroughBandScanFlag - whether to visit each cell when computing the histogram (default=false) 02028 */ 02029 void QgsRasterLayer::populateHistogram( int theBandNo, int theBinCount, bool theIgnoreOutOfRangeFlag, bool theHistogramEstimatedFlag ) 02030 { 02031 QgsRasterBandStats myRasterBandStats = bandStatistics( theBandNo ); 02032 mDataProvider->populateHistogram( theBandNo, myRasterBandStats, theBinCount, theIgnoreOutOfRangeFlag, theHistogramEstimatedFlag ); 02033 } 02034 02035 QString QgsRasterLayer::providerType() const 02036 { 02037 if ( mProviderKey.isEmpty() ) 02038 { 02039 return QString(); 02040 } 02041 else 02042 { 02043 return mProviderKey; 02044 } 02045 } 02046 02050 double QgsRasterLayer::rasterUnitsPerPixel() 02051 { 02052 // We return one raster pixel per map unit pixel 02053 // One raster pixel can have several raster units... 02054 02055 // We can only use one of the mGeoTransform[], so go with the 02056 // horisontal one. 02057 02058 //return qAbs( mGeoTransform[1] ); 02059 if ( mDataProvider->capabilities() & QgsRasterDataProvider::ExactResolution && mDataProvider->xSize() > 0 ) 02060 { 02061 return mDataProvider->extent().width() / mDataProvider->xSize(); 02062 } 02063 return 1; 02064 } 02065 02066 02067 void QgsRasterLayer::resetNoDataValue() 02068 { 02069 mNoDataValue = std::numeric_limits<int>::max(); 02070 mValidNoDataValue = false; 02071 if ( mDataProvider != NULL && mDataProvider->bandCount() > 0 ) 02072 { 02073 // TODO: add 'has null value' to capabilities 02074 #if 0 02075 int myRequestValid; 02076 myRequestValid = 1; 02077 double myValue = mDataProvider->noDataValue(); 02078 02079 if ( 0 != myRequestValid ) 02080 { 02081 setNoDataValue( myValue ); 02082 } 02083 else 02084 { 02085 setNoDataValue( -9999.0 ); 02086 mValidNoDataValue = false; 02087 02088 } 02089 #endif 02090 setNoDataValue( mDataProvider->noDataValue() ); 02091 mValidNoDataValue = mDataProvider->isNoDataValueValid(); 02092 } 02093 } 02094 02095 02096 void QgsRasterLayer::setBlueBandName( QString const & theBandName ) 02097 { 02098 mBlueBandName = validateBandName( theBandName ); 02099 } 02100 02101 void QgsRasterLayer::init() 02102 { 02103 // keep this until mGeoTransform occurences are removed! 02104 mGeoTransform[0] = 0; 02105 mGeoTransform[1] = 1; 02106 mGeoTransform[2] = 0; 02107 mGeoTransform[3] = 0; 02108 mGeoTransform[4] = 0; 02109 mGeoTransform[5] = -1; 02110 02111 02112 mRasterType = QgsRasterLayer::GrayOrUndefined; 02113 02114 mRedBandName = TRSTRING_NOT_SET; 02115 mGreenBandName = TRSTRING_NOT_SET; 02116 mBlueBandName = TRSTRING_NOT_SET; 02117 mGrayBandName = TRSTRING_NOT_SET; 02118 mTransparencyBandName = TRSTRING_NOT_SET; 02119 02120 02121 mUserDefinedRGBMinimumMaximum = false; //defaults needed to bypass enhanceContrast 02122 mUserDefinedGrayMinimumMaximum = false; 02123 mRGBMinimumMaximumEstimated = true; 02124 mGrayMinimumMaximumEstimated = true; 02125 02126 mDrawingStyle = QgsRasterLayer::UndefinedDrawingStyle; 02127 mContrastEnhancementAlgorithm = QgsContrastEnhancement::NoEnhancement; 02128 mColorShadingAlgorithm = QgsRasterLayer::UndefinedShader; 02129 mRasterShader = new QgsRasterShader(); 02130 02131 mBandCount = 0; 02132 mHasPyramids = false; 02133 mNoDataValue = -9999.0; 02134 mValidNoDataValue = false; 02135 02136 //Initialize the last view port structure, should really be a class 02137 mLastViewPort.drawableAreaXDim = 0; 02138 mLastViewPort.drawableAreaYDim = 0; 02139 } 02140 02141 QLibrary* QgsRasterLayer::loadProviderLibrary( QString theProviderKey ) 02142 { 02143 QgsDebugMsg( "theProviderKey = " + theProviderKey ); 02144 // load the plugin 02145 QgsProviderRegistry * pReg = QgsProviderRegistry::instance(); 02146 QString myLibPath = pReg->library( theProviderKey ); 02147 QgsDebugMsg( "myLibPath = " + myLibPath ); 02148 02149 #ifdef TESTPROVIDERLIB 02150 const char *cOgrLib = ( const char * ) myLibPath; 02151 // test code to help debug provider loading problems 02152 // void *handle = dlopen(cOgrLib, RTLD_LAZY); 02153 void *handle = dlopen( cOgrLib, RTLD_LAZY | RTLD_GLOBAL ); 02154 if ( !handle ) 02155 { 02156 QgsLogger::warning( "Error in dlopen: " ); 02157 } 02158 else 02159 { 02160 QgsDebugMsg( "dlopen suceeded" ); 02161 dlclose( handle ); 02162 } 02163 02164 #endif 02165 02166 // load the data provider 02167 QLibrary* myLib = new QLibrary( myLibPath ); 02168 02169 QgsDebugMsg( "Library name is " + myLib->fileName() ); 02170 bool loaded = myLib->load(); 02171 02172 if ( !loaded ) 02173 { 02174 QgsMessageLog::logMessage( tr( "Failed to load provider %1 (Reason: %2)" ).arg( myLib->fileName() ).arg( myLib->errorString() ), tr( "Raster" ) ); 02175 return NULL; 02176 } 02177 QgsDebugMsg( "Loaded data provider library" ); 02178 return myLib; 02179 } 02180 02181 // This code should be shared also by vector layer -> move it to QgsMapLayer 02182 QgsRasterDataProvider* QgsRasterLayer::loadProvider( QString theProviderKey, QString theDataSource ) 02183 { 02184 QgsDebugMsg( "Entered" ); 02185 QLibrary* myLib = QgsRasterLayer::loadProviderLibrary( theProviderKey ); 02186 QgsDebugMsg( "Library loaded" ); 02187 if ( !myLib ) 02188 { 02189 QgsDebugMsg( "myLib is NULL" ); 02190 return NULL; 02191 } 02192 02193 QgsDebugMsg( "Attempting to resolve the classFactory function" ); 02194 classFactoryFunction_t * classFactory = ( classFactoryFunction_t * ) cast_to_fptr( myLib->resolve( "classFactory" ) ); 02195 02196 if ( !classFactory ) 02197 { 02198 QgsMessageLog::logMessage( tr( "Cannot resolve the classFactory function" ), tr( "Raster" ) ); 02199 return NULL; 02200 } 02201 QgsDebugMsg( "Getting pointer to a mDataProvider object from the library" ); 02202 //XXX - This was a dynamic cast but that kills the Windows 02203 // version big-time with an abnormal termination error 02204 // mDataProvider = (QgsRasterDataProvider*)(classFactory((const 02205 // char*)(dataSource.utf8()))); 02206 02207 // Copied from qgsproviderregistry in preference to the above. 02208 QgsRasterDataProvider* myDataProvider = ( QgsRasterDataProvider* )( *classFactory )( &theDataSource ); 02209 02210 if ( !myDataProvider ) 02211 { 02212 QgsMessageLog::logMessage( tr( "Cannot instantiate the data provider" ), tr( "Raster" ) ); 02213 return NULL; 02214 } 02215 QgsDebugMsg( "Data driver created" ); 02216 return myDataProvider; 02217 } 02218 02219 void QgsRasterLayer::setDataProvider( QString const & provider, 02220 QStringList const & layers, 02221 QStringList const & styles, 02222 QString const & format, 02223 QString const & crs ) 02224 { 02225 setDataProvider( provider, layers, styles, format, crs, false ); 02226 } 02227 02231 void QgsRasterLayer::setDataProvider( QString const & provider, 02232 QStringList const & layers, 02233 QStringList const & styles, 02234 QString const & format, 02235 QString const & theCrs, 02236 bool loadDefaultStyleFlag ) 02237 { 02238 Q_UNUSED( loadDefaultStyleFlag ); 02239 // XXX should I check for and possibly delete any pre-existing providers? 02240 // XXX How often will that scenario occur? 02241 02242 mProviderKey = provider; 02243 mValid = false; // assume the layer is invalid until we determine otherwise 02244 02245 // set the layer name (uppercase first character) 02246 02247 if ( ! mLayerName.isEmpty() ) // XXX shouldn't this happen in parent? 02248 { 02249 setLayerName( mLayerName ); 02250 } 02251 02252 mBandCount = 0; 02253 mRasterShader = new QgsRasterShader(); 02254 02255 mDataProvider = QgsRasterLayer::loadProvider( mProviderKey, mDataSource ); 02256 if ( !mDataProvider ) 02257 { 02258 return; 02259 } 02260 02261 02262 QgsDebugMsg( QString( "Instantiated the data provider plugin with layer list of %1 and style list of %2 and format of %3 and CRS of %4" ) 02263 .arg( layers.join( ", " ) ) 02264 .arg( styles.join( ", " ) ) 02265 .arg( format ) 02266 .arg( theCrs ) 02267 ); 02268 if ( !mDataProvider->isValid() ) 02269 { 02270 if ( provider != "gdal" || !layers.isEmpty() || !styles.isEmpty() || !format.isNull() || !theCrs.isNull() ) 02271 { 02272 QgsMessageLog::logMessage( tr( "Data provider is invalid (layers: %1, styles: %2, formats: %3)" ) 02273 .arg( layers.join( ", " ) ) 02274 .arg( styles.join( ", " ) ) 02275 .arg( format ), 02276 tr( "Raster" ) ); 02277 } 02278 return; 02279 } 02280 02281 if ( provider == "gdal" ) 02282 { 02283 // make sure that the /vsigzip or /vsizip is added to uri, if applicable 02284 mDataSource = mDataProvider->dataSourceUri(); 02285 } 02286 02287 mDataProvider->addLayers( layers, styles ); 02288 mDataProvider->setImageEncoding( format ); 02289 mDataProvider->setImageCrs( theCrs ); 02290 02291 setNoDataValue( mDataProvider->noDataValue() ); 02292 02293 // get the extent 02294 QgsRectangle mbr = mDataProvider->extent(); 02295 02296 // show the extent 02297 QString s = mbr.toString(); 02298 QgsDebugMsg( "Extent of layer: " + s ); 02299 // store the extent 02300 mLayerExtent.setXMaximum( mbr.xMaximum() ); 02301 mLayerExtent.setXMinimum( mbr.xMinimum() ); 02302 mLayerExtent.setYMaximum( mbr.yMaximum() ); 02303 mLayerExtent.setYMinimum( mbr.yMinimum() ); 02304 02305 mWidth = mDataProvider->xSize(); 02306 mHeight = mDataProvider->ySize(); 02307 02308 02309 // upper case the first letter of the layer name 02310 QgsDebugMsg( "mLayerName: " + name() ); 02311 02312 // set up the raster drawing style 02313 mDrawingStyle = MultiBandColor; //sensible default 02314 02315 // Setup source CRS 02316 if ( mProviderKey == "wms" ) 02317 { 02318 QgsCoordinateReferenceSystem crs; 02319 crs.createFromOgcWmsCrs( theCrs ); 02320 setCrs( crs ); 02321 } 02322 else 02323 { 02324 setCrs( QgsCoordinateReferenceSystem( mDataProvider->crs() ) ); 02325 } 02326 02327 QString mySourceWkt = crs().toWkt(); 02328 02329 QgsDebugMsg( "using wkt:\n" + mySourceWkt ); 02330 02331 mBandCount = mDataProvider->bandCount( ); 02332 for ( int i = 1; i <= mBandCount; i++ ) 02333 { 02334 QgsRasterBandStats myRasterBandStats; 02335 myRasterBandStats.bandName = mDataProvider->generateBandName( i ); 02336 myRasterBandStats.bandNumber = i; 02337 myRasterBandStats.statsGathered = false; 02338 myRasterBandStats.histogramVector->clear(); 02339 //Store the default color table 02340 //readColorTable( i, &myRasterBandStats.colorTable ); 02341 QList<QgsColorRampShader::ColorRampItem> ct; 02342 ct = mDataProvider->colorTable( i ); 02343 myRasterBandStats.colorTable = ct; 02344 02345 mRasterStatsList.push_back( myRasterBandStats ); 02346 02347 //Build a new contrast enhancement for the band and store in list 02348 //QgsContrastEnhancement myContrastEnhancement(( QgsContrastEnhancement::QgsRasterDataType )mDataProvider->dataType( i ) ); 02349 QgsContrastEnhancement myContrastEnhancement(( QgsContrastEnhancement::QgsRasterDataType )mDataProvider->srcDataType( i ) ); 02350 mContrastEnhancementList.append( myContrastEnhancement ); 02351 } 02352 02353 //defaults - Needs to be set after the Contrast list has been build 02354 //Try to read the default contrast enhancement from the config file 02355 02356 QSettings myQSettings; 02357 setContrastEnhancementAlgorithm( myQSettings.value( "/Raster/defaultContrastEnhancementAlgorithm", "NoEnhancement" ).toString() ); 02358 02359 //decide what type of layer this is... 02360 //TODO Change this to look at the color interp and palette interp to decide which type of layer it is 02361 QgsDebugMsg( "bandCount = " + QString::number( mDataProvider->bandCount() ) ); 02362 QgsDebugMsg( "dataType = " + QString::number( mDataProvider->dataType( 1 ) ) ); 02363 if (( mDataProvider->bandCount() > 1 ) ) 02364 { 02365 mRasterType = Multiband; 02366 } 02367 else if ( mDataProvider->dataType( 1 ) == QgsRasterDataProvider::ARGBDataType ) 02368 { 02369 mRasterType = ColorLayer; 02370 } 02371 //TODO hasBand is really obsolete and only used in the Palette instance, change to new function hasPalette(int) 02372 //else if ( hasBand( "Palette" ) ) //don't tr() this its a gdal word! 02373 // not sure if is worth to add colorTable capability - CT can be empty in any case 02374 // Calc bandStatistics is very slow!!! 02375 //else if ( bandStatistics(1).colorTable.count() > 0 ) 02376 else if ( mDataProvider->colorInterpretation( 1 ) == QgsRasterDataProvider::PaletteIndex ) 02377 { 02378 mRasterType = Palette; 02379 } 02380 else 02381 { 02382 mRasterType = GrayOrUndefined; 02383 } 02384 02385 // Set min/max values for single band if we have them ready (no need to calculate which is slow) 02386 // don't set min/max on multiband even if available because it would cause stretch of bands and thus colors distortion 02387 if ( mDataProvider->bandCount() == 1 && ( mDataProvider->capabilities() & QgsRasterDataProvider::ExactMinimumMaximum ) ) 02388 { 02389 setMinimumValue( 1, mDataProvider->minimumValue( 1 ) ); 02390 setMaximumValue( 1, mDataProvider->maximumValue( 1 ) ); 02391 } 02392 02393 QgsDebugMsg( "mRasterType = " + QString::number( mRasterType ) ); 02394 if ( mRasterType == ColorLayer ) 02395 { 02396 QgsDebugMsg( "Setting mDrawingStyle to SingleBandColorDataStyle " + QString::number( SingleBandColorDataStyle ) ); 02397 mDrawingStyle = SingleBandColorDataStyle; 02398 mGrayBandName = bandName( 1 ); //sensible default 02399 } 02400 else if ( mRasterType == Palette ) 02401 { 02402 mRedBandName = TRSTRING_NOT_SET; // sensible default 02403 mGreenBandName = TRSTRING_NOT_SET; // sensible default 02404 mBlueBandName = TRSTRING_NOT_SET;// sensible default 02405 mTransparencyBandName = TRSTRING_NOT_SET; // sensible default 02406 mGrayBandName = bandName( 1 ); //sensible default 02407 QgsDebugMsg( mGrayBandName ); 02408 02409 mDrawingStyle = PalettedColor; //sensible default 02410 02411 //Set up a new color ramp shader 02412 setColorShadingAlgorithm( ColorRampShader ); 02413 QgsColorRampShader* myColorRampShader = ( QgsColorRampShader* ) mRasterShader->rasterShaderFunction(); 02414 //TODO: Make sure the set algorithm and cast was successful, 02415 //e.g., if ( 0 != myColorRampShader && myColorRampShader->shaderTypeAsString == "ColorRampShader" ) 02416 myColorRampShader->setColorRampType( QgsColorRampShader::INTERPOLATED ); 02417 myColorRampShader->setColorRampItemList( *colorTable( 1 ) ); 02418 } 02419 else if ( mRasterType == Multiband ) 02420 { 02421 //we know we have at least 2 layers... 02422 mRedBandName = bandName( myQSettings.value( "/Raster/defaultRedBand", 1 ).toInt() ); // sensible default 02423 mGreenBandName = bandName( myQSettings.value( "/Raster/defaultGreenBand", 2 ).toInt() ); // sensible default 02424 02425 //Check to make sure preferred bands combinations are valid 02426 if ( mRedBandName.isEmpty() ) 02427 { 02428 mRedBandName = bandName( 1 ); 02429 } 02430 02431 if ( mGreenBandName.isEmpty() ) 02432 { 02433 mGreenBandName = bandName( 2 ); 02434 } 02435 02436 //for the third band we cant be sure so.. 02437 if (( mDataProvider->bandCount() > 2 ) ) 02438 { 02439 mBlueBandName = bandName( myQSettings.value( "/Raster/defaultBlueBand", 3 ).toInt() ); // sensible default 02440 if ( mBlueBandName.isEmpty() ) 02441 { 02442 mBlueBandName = bandName( 3 ); 02443 } 02444 } 02445 else 02446 { 02447 mBlueBandName = bandName( myQSettings.value( "/Raster/defaultBlueBand", 2 ).toInt() ); // sensible default 02448 if ( mBlueBandName.isEmpty() ) 02449 { 02450 mBlueBandName = bandName( 2 ); 02451 } 02452 } 02453 02454 02455 mTransparencyBandName = TRSTRING_NOT_SET; 02456 mGrayBandName = TRSTRING_NOT_SET; //sensible default 02457 mDrawingStyle = MultiBandColor; //sensible default 02458 02459 // read standard deviations 02460 if ( mContrastEnhancementAlgorithm == QgsContrastEnhancement::StretchToMinimumMaximum && 02461 myQSettings.value( "/Raster/useStandardDeviation", false ).toBool() ) 02462 { 02463 setStandardDeviations( myQSettings.value( "/Raster/defaultStandardDeviation", 2.0 ).toDouble() ); 02464 } 02465 } 02466 else //GrayOrUndefined 02467 { 02468 mRedBandName = TRSTRING_NOT_SET; //sensible default 02469 mGreenBandName = TRSTRING_NOT_SET; //sensible default 02470 mBlueBandName = TRSTRING_NOT_SET; //sensible default 02471 mTransparencyBandName = TRSTRING_NOT_SET; //sensible default 02472 mDrawingStyle = SingleBandGray; //sensible default 02473 mGrayBandName = bandName( 1 ); 02474 02475 // If we have min/max available (without calculation), it is better to use StretchToMinimumMaximum 02476 // TODO: in GUI there is 'Contrast enhancement - Default' which is overwritten here 02477 // and that is confusing 02478 if ( mDataProvider->capabilities() & QgsRasterDataProvider::ExactMinimumMaximum ) 02479 { 02480 setContrastEnhancementAlgorithm( QgsContrastEnhancement::StretchToMinimumMaximum ); 02481 } 02482 02483 // read standard deviations 02484 if ( mContrastEnhancementAlgorithm == QgsContrastEnhancement::StretchToMinimumMaximum && 02485 myQSettings.value( "/Raster/useStandardDeviation", false ).toBool() ) 02486 { 02487 setStandardDeviations( myQSettings.value( "/Raster/defaultStandardDeviation", 2.0 ).toDouble() ); 02488 } 02489 } 02490 // Debug 02491 //mDrawingStyle = SingleBandPseudoColor; 02492 02493 // Store timestamp 02494 // TODO move to provider 02495 mLastModified = lastModified( mDataSource ); 02496 02497 mValidNoDataValue = mDataProvider->isNoDataValueValid(); 02498 if ( mValidNoDataValue ) 02499 { 02500 mRasterTransparency.initializeTransparentPixelList( mNoDataValue, mNoDataValue, mNoDataValue ); 02501 mRasterTransparency.initializeTransparentPixelList( mNoDataValue ); 02502 } 02503 02504 // Connect provider signals 02505 connect( 02506 mDataProvider, SIGNAL( progress( int, double, QString ) ), 02507 this, SLOT( onProgress( int, double, QString ) ) 02508 ); 02509 02510 // Do a passthrough for the status bar text 02511 connect( 02512 mDataProvider, SIGNAL( statusChanged( QString ) ), 02513 this, SIGNAL( statusChanged( QString ) ) 02514 ); 02515 02516 //mark the layer as valid 02517 mValid = true; 02518 02519 QgsDebugMsg( "exiting." ); 02520 } // QgsRasterLayer::setDataProvider 02521 02522 void QgsRasterLayer::closeDataProvider() 02523 { 02524 mValid = false; 02525 delete mRasterShader; 02526 mRasterShader = 0; 02527 delete mDataProvider; 02528 mDataProvider = 0; 02529 02530 mRasterStatsList.clear(); 02531 mContrastEnhancementList.clear(); 02532 02533 mHasPyramids = false; 02534 mPyramidList.clear(); 02535 } 02536 02537 void QgsRasterLayer::setColorShadingAlgorithm( ColorShadingAlgorithm theShadingAlgorithm ) 02538 { 02539 QgsDebugMsg( "called with [" + QString::number( theShadingAlgorithm ) + "]" ); 02540 if ( mColorShadingAlgorithm != theShadingAlgorithm ) 02541 { 02542 if ( !mRasterShader ) 02543 { 02544 mRasterShader = new QgsRasterShader(); 02545 } 02546 02547 switch ( theShadingAlgorithm ) 02548 { 02549 case PseudoColorShader: 02550 mRasterShader->setRasterShaderFunction( new QgsPseudoColorShader() ); 02551 break; 02552 case FreakOutShader: 02553 mRasterShader->setRasterShaderFunction( new QgsFreakOutShader() ); 02554 break; 02555 case ColorRampShader: 02556 mRasterShader->setRasterShaderFunction( new QgsColorRampShader() ); 02557 break; 02558 case UserDefinedShader: 02559 //do nothing 02560 break; 02561 default: 02562 mRasterShader->setRasterShaderFunction( new QgsRasterShaderFunction() ); 02563 break; 02564 } 02565 02566 //Set the class variable after the call to setRasterShader(), so memory recovery can happen 02567 mColorShadingAlgorithm = theShadingAlgorithm; 02568 } 02569 QgsDebugMsg( "mColorShadingAlgorithm = " + QString::number( theShadingAlgorithm ) ); 02570 } 02571 02572 void QgsRasterLayer::setColorShadingAlgorithm( QString theShaderAlgorithm ) 02573 { 02574 QgsDebugMsg( "called with [" + theShaderAlgorithm + "]" ); 02575 02576 if ( theShaderAlgorithm == "PseudoColorShader" ) 02577 setColorShadingAlgorithm( PseudoColorShader ); 02578 else if ( theShaderAlgorithm == "FreakOutShader" ) 02579 setColorShadingAlgorithm( FreakOutShader ); 02580 else if ( theShaderAlgorithm == "ColorRampShader" ) 02581 setColorShadingAlgorithm( ColorRampShader ); 02582 else if ( theShaderAlgorithm == "UserDefinedShader" ) 02583 setColorShadingAlgorithm( UserDefinedShader ); 02584 else 02585 setColorShadingAlgorithm( UndefinedShader ); 02586 } 02587 02588 void QgsRasterLayer::setContrastEnhancementAlgorithm( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm, bool theGenerateLookupTableFlag ) 02589 { 02590 QList<QgsContrastEnhancement>::iterator myIterator = mContrastEnhancementList.begin(); 02591 while ( myIterator != mContrastEnhancementList.end() ) 02592 { 02593 ( *myIterator ).setContrastEnhancementAlgorithm( theAlgorithm, theGenerateLookupTableFlag ); 02594 ++myIterator; 02595 } 02596 mContrastEnhancementAlgorithm = theAlgorithm; 02597 } 02598 02599 void QgsRasterLayer::setContrastEnhancementAlgorithm( QString theAlgorithm, bool theGenerateLookupTableFlag ) 02600 { 02601 QgsDebugMsg( "called with [" + theAlgorithm + "] and flag=" + QString::number(( int )theGenerateLookupTableFlag ) ); 02602 02603 if ( theAlgorithm == "NoEnhancement" ) 02604 { 02605 setContrastEnhancementAlgorithm( QgsContrastEnhancement::NoEnhancement, theGenerateLookupTableFlag ); 02606 } 02607 else if ( theAlgorithm == "StretchToMinimumMaximum" ) 02608 { 02609 setContrastEnhancementAlgorithm( QgsContrastEnhancement::StretchToMinimumMaximum, theGenerateLookupTableFlag ); 02610 } 02611 else if ( theAlgorithm == "StretchAndClipToMinimumMaximum" ) 02612 { 02613 setContrastEnhancementAlgorithm( QgsContrastEnhancement::StretchAndClipToMinimumMaximum, theGenerateLookupTableFlag ); 02614 } 02615 else if ( theAlgorithm == "ClipToMinimumMaximum" ) 02616 { 02617 setContrastEnhancementAlgorithm( QgsContrastEnhancement::ClipToMinimumMaximum, theGenerateLookupTableFlag ); 02618 } 02619 else if ( theAlgorithm == "UserDefined" ) 02620 { 02621 setContrastEnhancementAlgorithm( QgsContrastEnhancement::UserDefinedEnhancement, theGenerateLookupTableFlag ); 02622 } 02623 else 02624 { 02625 setContrastEnhancementAlgorithm( QgsContrastEnhancement::NoEnhancement, theGenerateLookupTableFlag ); 02626 } 02627 } 02628 02629 void QgsRasterLayer::setContrastEnhancementFunction( QgsContrastEnhancementFunction* theFunction ) 02630 { 02631 if ( theFunction ) 02632 { 02633 QList<QgsContrastEnhancement>::iterator myIterator = mContrastEnhancementList.begin(); 02634 while ( myIterator != mContrastEnhancementList.end() ) 02635 { 02636 ( *myIterator ).setContrastEnhancementFunction( theFunction ); 02637 ++myIterator; 02638 } 02639 } 02640 } 02641 02647 void QgsRasterLayer::setDrawingStyle( QString const & theDrawingStyleQString ) 02648 { 02649 QgsDebugMsg( "DrawingStyle = " + theDrawingStyleQString ); 02650 if ( theDrawingStyleQString == "SingleBandGray" )//no need to tr() this its not shown in ui 02651 { 02652 mDrawingStyle = SingleBandGray; 02653 } 02654 else if ( theDrawingStyleQString == "SingleBandPseudoColor" )//no need to tr() this its not shown in ui 02655 { 02656 mDrawingStyle = SingleBandPseudoColor; 02657 } 02658 else if ( theDrawingStyleQString == "PalettedColor" )//no need to tr() this its not shown in ui 02659 { 02660 mDrawingStyle = PalettedColor; 02661 } 02662 else if ( theDrawingStyleQString == "PalettedSingleBandGray" )//no need to tr() this its not shown in ui 02663 { 02664 mDrawingStyle = PalettedSingleBandGray; 02665 } 02666 else if ( theDrawingStyleQString == "PalettedSingleBandPseudoColor" )//no need to tr() this its not shown in ui 02667 { 02668 mDrawingStyle = PalettedSingleBandPseudoColor; 02669 } 02670 else if ( theDrawingStyleQString == "PalettedMultiBandColor" )//no need to tr() this its not shown in ui 02671 { 02672 mDrawingStyle = PalettedMultiBandColor; 02673 } 02674 else if ( theDrawingStyleQString == "MultiBandSingleBandGray" )//no need to tr() this its not shown in ui 02675 { 02676 mDrawingStyle = MultiBandSingleBandGray; 02677 } 02678 else if ( theDrawingStyleQString == "MultiBandSingleBandPseudoColor" )//no need to tr() this its not shown in ui 02679 { 02680 mDrawingStyle = MultiBandSingleBandPseudoColor; 02681 } 02682 else if ( theDrawingStyleQString == "MultiBandColor" )//no need to tr() this its not shown in ui 02683 { 02684 mDrawingStyle = MultiBandColor; 02685 } 02686 else if ( theDrawingStyleQString == "SingleBandColorDataStyle" )//no need to tr() this its not shown in ui 02687 { 02688 QgsDebugMsg( "Setting mDrawingStyle to SingleBandColorDataStyle " + QString::number( SingleBandColorDataStyle ) ); 02689 mDrawingStyle = SingleBandColorDataStyle; 02690 QgsDebugMsg( "Setted mDrawingStyle to " + QString::number( mDrawingStyle ) ); 02691 } 02692 else 02693 { 02694 mDrawingStyle = UndefinedDrawingStyle; 02695 } 02696 } 02697 02698 void QgsRasterLayer::setGrayBandName( QString const & theBandName ) 02699 { 02700 mGrayBandName = validateBandName( theBandName ); 02701 } 02702 02703 void QgsRasterLayer::setGreenBandName( QString const & theBandName ) 02704 { 02705 mGreenBandName = validateBandName( theBandName ); 02706 } 02707 02708 void QgsRasterLayer::setLayerOrder( QStringList const & layers ) 02709 { 02710 QgsDebugMsg( "entered." ); 02711 02712 if ( mDataProvider ) 02713 { 02714 QgsDebugMsg( "About to mDataProvider->setLayerOrder(layers)." ); 02715 mDataProvider->setLayerOrder( layers ); 02716 } 02717 02718 } 02719 02720 void QgsRasterLayer::setMaximumValue( unsigned int theBand, double theValue, bool theGenerateLookupTableFlag ) 02721 { 02722 QgsDebugMsg( "setMaximumValue theValue = " + QString::number( theValue ) ); 02723 if ( 0 < theBand && theBand <= bandCount() ) 02724 { 02725 mContrastEnhancementList[theBand - 1].setMaximumValue( theValue, theGenerateLookupTableFlag ); 02726 } 02727 } 02728 02729 void QgsRasterLayer::setMaximumValue( QString theBand, double theValue, bool theGenerateLookupTableFlag ) 02730 { 02731 if ( theBand != tr( "Not Set" ) ) 02732 { 02733 setMaximumValue( bandNumber( theBand ), theValue, theGenerateLookupTableFlag ); 02734 } 02735 } 02736 02737 void QgsRasterLayer::setMinimumMaximumUsingLastExtent() 02738 { 02739 double myMinMax[2]; 02740 if ( rasterType() == QgsRasterLayer::GrayOrUndefined || drawingStyle() == QgsRasterLayer::SingleBandGray || drawingStyle() == QgsRasterLayer::MultiBandSingleBandGray ) 02741 { 02742 computeMinimumMaximumFromLastExtent( grayBandName(), myMinMax ); 02743 setMinimumValue( grayBandName(), myMinMax[0] ); 02744 setMaximumValue( grayBandName(), myMinMax[1] ); 02745 02746 setUserDefinedGrayMinimumMaximum( true ); 02747 } 02748 else if ( rasterType() == QgsRasterLayer::Multiband ) 02749 { 02750 computeMinimumMaximumFromLastExtent( redBandName(), myMinMax ); 02751 setMinimumValue( redBandName(), myMinMax[0], false ); 02752 setMaximumValue( redBandName(), myMinMax[1], false ); 02753 02754 computeMinimumMaximumFromLastExtent( greenBandName(), myMinMax ); 02755 setMinimumValue( greenBandName(), myMinMax[0], false ); 02756 setMaximumValue( greenBandName(), myMinMax[1], false ); 02757 02758 computeMinimumMaximumFromLastExtent( blueBandName(), myMinMax ); 02759 setMinimumValue( blueBandName(), myMinMax[0], false ); 02760 setMaximumValue( blueBandName(), myMinMax[1], false ); 02761 02762 setUserDefinedRGBMinimumMaximum( true ); 02763 } 02764 } 02765 02766 void QgsRasterLayer::setMinimumMaximumUsingDataset() 02767 { 02768 if ( rasterType() == QgsRasterLayer::GrayOrUndefined || drawingStyle() == QgsRasterLayer::SingleBandGray || drawingStyle() == QgsRasterLayer::MultiBandSingleBandGray ) 02769 { 02770 QgsRasterBandStats myRasterBandStats = bandStatistics( bandNumber( mGrayBandName ) ); 02771 double myMin = myRasterBandStats.minimumValue; 02772 double myMax = myRasterBandStats.maximumValue; 02773 setMinimumValue( grayBandName(), myMin ); 02774 setMaximumValue( grayBandName(), myMax ); 02775 setUserDefinedGrayMinimumMaximum( false ); 02776 } 02777 else if ( rasterType() == QgsRasterLayer::Multiband ) 02778 { 02779 QgsRasterBandStats myRasterBandStats = bandStatistics( bandNumber( mRedBandName ) ); 02780 double myMin = myRasterBandStats.minimumValue; 02781 double myMax = myRasterBandStats.maximumValue; 02782 setMinimumValue( redBandName(), myMin ); 02783 setMaximumValue( redBandName(), myMax ); 02784 02785 myRasterBandStats = bandStatistics( bandNumber( mGreenBandName ) ); 02786 myMin = myRasterBandStats.minimumValue; 02787 myMax = myRasterBandStats.maximumValue; 02788 setMinimumValue( greenBandName(), myMin ); 02789 setMaximumValue( greenBandName(), myMax ); 02790 02791 myRasterBandStats = bandStatistics( bandNumber( mGreenBandName ) ); 02792 myMin = myRasterBandStats.minimumValue; 02793 myMax = myRasterBandStats.maximumValue; 02794 setMinimumValue( greenBandName(), myMin ); 02795 setMaximumValue( greenBandName(), myMax ); 02796 02797 setUserDefinedRGBMinimumMaximum( false ); 02798 } 02799 } 02800 02801 void QgsRasterLayer::setMinimumValue( unsigned int theBand, double theValue, bool theGenerateLookupTableFlag ) 02802 { 02803 QgsDebugMsg( "setMinimumValue theValue = " + QString::number( theValue ) ); 02804 if ( 0 < theBand && theBand <= bandCount() ) 02805 { 02806 mContrastEnhancementList[theBand - 1].setMinimumValue( theValue, theGenerateLookupTableFlag ); 02807 } 02808 } 02809 02810 void QgsRasterLayer::setMinimumValue( QString theBand, double theValue, bool theGenerateLookupTableFlag ) 02811 { 02812 if ( theBand != tr( "Not Set" ) ) 02813 { 02814 setMinimumValue( bandNumber( theBand ), theValue, theGenerateLookupTableFlag ); 02815 } 02816 02817 } 02818 02819 void QgsRasterLayer::setNoDataValue( double theNoDataValue ) 02820 { 02821 if ( theNoDataValue != mNoDataValue ) 02822 { 02823 mNoDataValue = theNoDataValue; 02824 mValidNoDataValue = true; 02825 //Basically set the raster stats as invalid 02826 QList<QgsRasterBandStats>::iterator myIterator = mRasterStatsList.begin(); 02827 while ( myIterator != mRasterStatsList.end() ) 02828 { 02829 ( *myIterator ).statsGathered = false; 02830 ++myIterator; 02831 } 02832 } 02833 } 02834 02835 void QgsRasterLayer::setRasterShaderFunction( QgsRasterShaderFunction* theFunction ) 02836 { 02837 if ( theFunction ) 02838 { 02839 mRasterShader->setRasterShaderFunction( theFunction ); 02840 mColorShadingAlgorithm = QgsRasterLayer::UserDefinedShader; 02841 } 02842 else 02843 { 02844 //If NULL as passed in, set a default shader function to prevent segfaults 02845 mRasterShader->setRasterShaderFunction( new QgsRasterShaderFunction() ); 02846 mColorShadingAlgorithm = QgsRasterLayer::UndefinedShader; 02847 } 02848 } 02849 02850 void QgsRasterLayer::setRedBandName( QString const & theBandName ) 02851 { 02852 QgsDebugMsg( "setRedBandName : " + theBandName ); 02853 mRedBandName = validateBandName( theBandName ); 02854 } 02855 02856 void QgsRasterLayer::setSubLayerVisibility( QString name, bool vis ) 02857 { 02858 02859 if ( mDataProvider ) 02860 { 02861 QgsDebugMsg( "About to mDataProvider->setSubLayerVisibility(name, vis)." ); 02862 mDataProvider->setSubLayerVisibility( name, vis ); 02863 } 02864 02865 } 02866 02867 void QgsRasterLayer::setTransparentBandName( QString const & theBandName ) 02868 { 02869 mTransparencyBandName = validateBandName( theBandName ); 02870 } 02871 02872 void QgsRasterLayer::showProgress( int theValue ) 02873 { 02874 emit progressUpdate( theValue ); 02875 } 02876 02877 02878 void QgsRasterLayer::showStatusMessage( QString const & theMessage ) 02879 { 02880 // QgsDebugMsg(QString("entered with '%1'.").arg(theMessage)); 02881 02882 // Pass-through 02883 // TODO: See if we can connect signal-to-signal. This is a kludge according to the Qt doc. 02884 emit statusChanged( theMessage ); 02885 } 02886 02887 02888 QStringList QgsRasterLayer::subLayers() const 02889 { 02890 return mDataProvider->subLayers(); 02891 } 02892 02893 02894 void QgsRasterLayer::thumbnailAsPixmap( QPixmap * theQPixmap ) 02895 { 02896 //TODO: This should be depreciated and a new function written that just returns a new QPixmap, it will be safer 02897 if ( !theQPixmap ) 02898 return; 02899 02900 theQPixmap->fill( ); //defaults to white 02901 02902 QgsRasterViewPort *myRasterViewPort = new QgsRasterViewPort(); 02903 02904 double myMapUnitsPerPixel; 02905 double myX = 0.0; 02906 double myY = 0.0; 02907 QgsRectangle myExtent = mDataProvider->extent(); 02908 if ( myExtent.width() / myExtent.height() >= theQPixmap->width() / theQPixmap->height() ) 02909 { 02910 myMapUnitsPerPixel = myExtent.width() / theQPixmap->width(); 02911 myY = ( theQPixmap->height() - myExtent.height() / myMapUnitsPerPixel ) / 2; 02912 } 02913 else 02914 { 02915 myMapUnitsPerPixel = myExtent.height() / theQPixmap->height(); 02916 myX = ( theQPixmap->width() - myExtent.width() / myMapUnitsPerPixel ) / 2; 02917 } 02918 02919 double myPixelWidth = myExtent.width() / myMapUnitsPerPixel; 02920 double myPixelHeight = myExtent.height() / myMapUnitsPerPixel; 02921 02922 //myRasterViewPort->topLeftPoint = QgsPoint( 0, 0 ); 02923 myRasterViewPort->topLeftPoint = QgsPoint( myX, myY ); 02924 02925 //myRasterViewPort->bottomRightPoint = QgsPoint( theQPixmap->width(), theQPixmap->height() ); 02926 02927 myRasterViewPort->bottomRightPoint = QgsPoint( myPixelWidth, myPixelHeight ); 02928 myRasterViewPort->drawableAreaXDim = theQPixmap->width(); 02929 myRasterViewPort->drawableAreaYDim = theQPixmap->height(); 02930 //myRasterViewPort->drawableAreaXDim = myPixelWidth; 02931 //myRasterViewPort->drawableAreaYDim = myPixelHeight; 02932 02933 myRasterViewPort->mDrawnExtent = myExtent; 02934 myRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid 02935 myRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid 02936 02937 QgsMapToPixel *myMapToPixel = new QgsMapToPixel( myMapUnitsPerPixel ); 02938 02939 QPainter * myQPainter = new QPainter( theQPixmap ); 02940 draw( myQPainter, myRasterViewPort, myMapToPixel ); 02941 delete myRasterViewPort; 02942 delete myMapToPixel; 02943 myQPainter->end(); 02944 delete myQPainter; 02945 } 02946 02947 void QgsRasterLayer::thumbnailAsImage( QImage * thepImage ) 02948 { 02949 //TODO: This should be depreciated and a new function written that just returns a new QImage, it will be safer 02950 if ( !thepImage ) 02951 return; 02952 02953 02954 thepImage->fill( Qt::white ); //defaults to white 02955 02956 // Raster providers are disabled (for the moment) 02957 if ( mProviderKey.isEmpty() ) 02958 { 02959 QgsRasterViewPort *myRasterViewPort = new QgsRasterViewPort(); 02960 myRasterViewPort->topLeftPoint = QgsPoint( 0, 0 ); 02961 myRasterViewPort->bottomRightPoint = QgsPoint( thepImage->width(), thepImage->height() ); 02962 myRasterViewPort->drawableAreaXDim = thepImage->width(); 02963 myRasterViewPort->drawableAreaYDim = thepImage->height(); 02964 02965 QPainter * myQPainter = new QPainter( thepImage ); 02966 draw( myQPainter, myRasterViewPort ); 02967 delete myRasterViewPort; 02968 myQPainter->end(); 02969 delete myQPainter; 02970 } 02971 02972 } 02973 02974 void QgsRasterLayer::triggerRepaint() 02975 { 02976 emit repaintRequested(); 02977 } 02978 02979 void QgsRasterLayer::updateProgress( int theProgress, int theMax ) 02980 { 02981 //simply propogate it on! 02982 emit drawingProgress( theProgress, theMax ); 02983 } 02984 02985 void QgsRasterLayer::onProgress( int theType, double theProgress, QString theMessage ) 02986 { 02987 Q_UNUSED( theType ); 02988 Q_UNUSED( theMessage ); 02989 QgsDebugMsg( QString( "theProgress = %1" ).arg( theProgress ) ); 02990 emit progressUpdate(( int )theProgress ); 02991 } 02992 02994 // 02995 // Protected methods 02996 // 02998 /* 02999 * @param QDomNode node that will contain the symbology definition for this layer. 03000 * @param errorMessage reference to string that will be updated with any error messages 03001 * @return true in case of success. 03002 */ 03003 bool QgsRasterLayer::readSymbology( const QDomNode& layer_node, QString& errorMessage ) 03004 { 03005 Q_UNUSED( errorMessage ); 03006 QDomNode mnl = layer_node.namedItem( "rasterproperties" ); 03007 QDomNode snode = mnl.namedItem( "mDrawingStyle" ); 03008 QDomElement myElement = snode.toElement(); 03009 setDrawingStyle( myElement.text() ); 03010 03011 snode = mnl.namedItem( "mColorShadingAlgorithm" ); 03012 myElement = snode.toElement(); 03013 setColorShadingAlgorithm( myElement.text() ); 03014 03015 snode = mnl.namedItem( "mInvertColor" ); 03016 myElement = snode.toElement(); 03017 QVariant myVariant = ( QVariant ) myElement.attribute( "boolean" ); 03018 setInvertHistogram( myVariant.toBool() ); 03019 03020 snode = mnl.namedItem( "mRedBandName" ); 03021 myElement = snode.toElement(); 03022 setRedBandName( myElement.text() ); 03023 03024 snode = mnl.namedItem( "mGreenBandName" ); 03025 myElement = snode.toElement(); 03026 setGreenBandName( myElement.text() ); 03027 03028 snode = mnl.namedItem( "mBlueBandName" ); 03029 myElement = snode.toElement(); 03030 setBlueBandName( myElement.text() ); 03031 03032 snode = mnl.namedItem( "mGrayBandName" ); 03033 myElement = snode.toElement(); 03034 QgsDebugMsg( QString( " Setting gray band to : " ) + myElement.text() ); 03035 setGrayBandName( myElement.text() ); 03036 03037 snode = mnl.namedItem( "mStandardDeviations" ); 03038 myElement = snode.toElement(); 03039 setStandardDeviations( myElement.text().toDouble() ); 03040 03041 snode = mnl.namedItem( "mUserDefinedRGBMinimumMaximum" ); 03042 myElement = snode.toElement(); 03043 myVariant = ( QVariant ) myElement.attribute( "boolean" ); 03044 setUserDefinedRGBMinimumMaximum( myVariant.toBool() ); 03045 03046 snode = mnl.namedItem( "mRGBMinimumMaximumEstimated" ); 03047 myElement = snode.toElement(); 03048 myVariant = ( QVariant ) myElement.attribute( "boolean" ); 03049 setRGBMinimumMaximumEstimated( myVariant.toBool() ); 03050 03051 snode = mnl.namedItem( "mUserDefinedGrayMinimumMaximum" ); 03052 myElement = snode.toElement(); 03053 myVariant = ( QVariant ) myElement.attribute( "boolean" ); 03054 setUserDefinedGrayMinimumMaximum( myVariant.toBool() ); 03055 03056 snode = mnl.namedItem( "mGrayMinimumMaximumEstimated" ); 03057 myElement = snode.toElement(); 03058 myVariant = ( QVariant ) myElement.attribute( "boolean" ); 03059 setGrayMinimumMaximumEstimated( myVariant.toBool() ); 03060 03061 snode = mnl.namedItem( "mContrastEnhancementAlgorithm" ); 03062 myElement = snode.toElement(); 03063 setContrastEnhancementAlgorithm( myElement.text(), false ); 03064 03065 QDomNode contrastEnhancementMinMaxValues = mnl.namedItem( "contrastEnhancementMinMaxValues" ); 03066 QDomNodeList minMaxValueList = contrastEnhancementMinMaxValues.toElement().elementsByTagName( "minMaxEntry" ); 03067 for ( int i = 0; i < minMaxValueList.size(); ++i ) 03068 { 03069 QDomNode minMaxEntry = minMaxValueList.at( i ).toElement(); 03070 if ( minMaxEntry.isNull() ) 03071 { 03072 continue; 03073 } 03074 QDomNode minEntry = minMaxEntry.namedItem( "min" ); 03075 QDomNode maxEntry = minMaxEntry.namedItem( "max" ); 03076 03077 setMinimumValue( i + 1, minEntry.toElement().text().toDouble(), false ); 03078 setMaximumValue( i + 1, maxEntry.toElement().text().toDouble(), false ); 03079 } 03080 03081 QgsDebugMsg( "ReadXml: gray band name " + mGrayBandName ); 03082 QgsDebugMsg( "ReadXml: red band name " + mRedBandName ); 03083 QgsDebugMsg( "ReadXml: green band name " + mGreenBandName ); 03084 QgsDebugMsg( "Drawing style " + drawingStyleAsString() ); 03085 03086 /* 03087 * Transparency tab 03088 */ 03089 snode = mnl.namedItem( "mNoDataValue" ); 03090 myElement = snode.toElement(); 03091 QgsDebugMsg( "ReadXml: mNoDataValue = " + myElement.text() ); 03092 setNoDataValue( myElement.text().toDouble() ); 03093 QgsDebugMsg( "ReadXml: mNoDataValue = " + QString::number( mNoDataValue ) ); 03094 if ( myElement.attribute( "mValidNoDataValue", "false" ).compare( "true" ) ) 03095 { 03096 // If flag element is not true, set to false. 03097 mValidNoDataValue = false; 03098 } 03099 03100 QDomNode singleValuePixelListNode = mnl.namedItem( "singleValuePixelList" ); 03101 if ( !singleValuePixelListNode.isNull() ) 03102 { 03103 QList<QgsRasterTransparency::TransparentSingleValuePixel> newSingleValuePixelList; 03104 03105 //entries 03106 QDomNodeList singleValuePixelList = singleValuePixelListNode.toElement().elementsByTagName( "pixelListEntry" ); 03107 for ( int i = 0; i < singleValuePixelList.size(); ++i ) 03108 { 03109 QgsRasterTransparency::TransparentSingleValuePixel myNewItem; 03110 QDomElement singleValuePixelListElement = singleValuePixelList.at( i ).toElement(); 03111 if ( singleValuePixelListElement.isNull() ) 03112 { 03113 continue; 03114 } 03115 03116 myNewItem.pixelValue = singleValuePixelListElement.attribute( "pixelValue" ).toDouble(); 03117 myNewItem.percentTransparent = singleValuePixelListElement.attribute( "percentTransparent" ).toDouble(); 03118 03119 newSingleValuePixelList.push_back( myNewItem ); 03120 } 03121 mRasterTransparency.setTransparentSingleValuePixelList( newSingleValuePixelList ); 03122 } 03123 03124 QDomNode threeValuePixelListNode = mnl.namedItem( "threeValuePixelList" ); 03125 if ( !threeValuePixelListNode.isNull() ) 03126 { 03127 QList<QgsRasterTransparency::TransparentThreeValuePixel> newThreeValuePixelList; 03128 03129 //entries 03130 QDomNodeList threeValuePixelList = threeValuePixelListNode.toElement().elementsByTagName( "pixelListEntry" ); 03131 for ( int i = 0; i < threeValuePixelList.size(); ++i ) 03132 { 03133 QgsRasterTransparency::TransparentThreeValuePixel myNewItem; 03134 QDomElement threeValuePixelListElement = threeValuePixelList.at( i ).toElement(); 03135 if ( threeValuePixelListElement.isNull() ) 03136 { 03137 continue; 03138 } 03139 03140 myNewItem.red = threeValuePixelListElement.attribute( "red" ).toDouble(); 03141 myNewItem.green = threeValuePixelListElement.attribute( "green" ).toDouble(); 03142 myNewItem.blue = threeValuePixelListElement.attribute( "blue" ).toDouble(); 03143 myNewItem.percentTransparent = threeValuePixelListElement.attribute( "percentTransparent" ).toDouble(); 03144 03145 newThreeValuePixelList.push_back( myNewItem ); 03146 } 03147 mRasterTransparency.setTransparentThreeValuePixelList( newThreeValuePixelList ); 03148 } 03149 03150 /* 03151 * Color Ramp tab 03152 */ 03153 //restore custom color ramp settings 03154 QDomNode customColorRampNode = mnl.namedItem( "customColorRamp" ); 03155 if ( !customColorRampNode.isNull() ) 03156 { 03157 QgsColorRampShader* myColorRampShader = ( QgsColorRampShader* ) mRasterShader->rasterShaderFunction(); 03158 03159 //TODO: Remove the customColorRampType check and following if() in v2.0, added for compatibility with older ( bugged ) project files 03160 QDomNode customColorRampTypeNode = customColorRampNode.namedItem( "customColorRampType" ); 03161 QDomNode colorRampTypeNode = customColorRampNode.namedItem( "colorRampType" ); 03162 QString myRampType = ""; 03163 if ( "" == customColorRampTypeNode.toElement().text() ) 03164 { 03165 myRampType = colorRampTypeNode.toElement().text(); 03166 } 03167 else 03168 { 03169 myRampType = customColorRampTypeNode.toElement().text(); 03170 } 03171 myColorRampShader->setColorRampType( myRampType ); 03172 03173 03174 //entries 03175 QList<QgsColorRampShader::ColorRampItem> myColorRampItemList; 03176 QDomNodeList colorRampEntryList = customColorRampNode.toElement().elementsByTagName( "colorRampEntry" ); 03177 for ( int i = 0; i < colorRampEntryList.size(); ++i ) 03178 { 03179 QgsColorRampShader::ColorRampItem myNewItem; 03180 QDomElement colorRampEntryElement = colorRampEntryList.at( i ).toElement(); 03181 if ( colorRampEntryElement.isNull() ) 03182 { 03183 continue; 03184 } 03185 03186 myNewItem.color = QColor( colorRampEntryElement.attribute( "red" ).toInt(), colorRampEntryElement.attribute( "green" ).toInt(), colorRampEntryElement.attribute( "blue" ).toInt() ); 03187 myNewItem.label = colorRampEntryElement.attribute( "label" ); 03188 myNewItem.value = colorRampEntryElement.attribute( "value" ).toDouble(); 03189 03190 myColorRampItemList.push_back( myNewItem ); 03191 } 03192 myColorRampShader->setColorRampItemList( myColorRampItemList ); 03193 } 03194 return true; 03195 } //readSymbology 03196 03221 bool QgsRasterLayer::readXml( const QDomNode& layer_node ) 03222 { 03224 03225 //process provider key 03226 QDomNode pkeyNode = layer_node.namedItem( "provider" ); 03227 03228 if ( pkeyNode.isNull() ) 03229 { 03230 mProviderKey = "gdal"; 03231 } 03232 else 03233 { 03234 QDomElement pkeyElt = pkeyNode.toElement(); 03235 mProviderKey = pkeyElt.text(); 03236 if ( mProviderKey.isEmpty() ) 03237 { 03238 mProviderKey = "gdal"; 03239 } 03240 } 03241 03242 // Open the raster source based on provider and datasource 03243 03244 // Go down the raster-data-provider paradigm 03245 03246 // Collect provider-specific information 03247 03248 QDomNode rpNode = layer_node.namedItem( "rasterproperties" ); 03249 03250 // Collect sublayer names and styles 03251 mLayers.clear(); 03252 mStyles.clear(); 03253 03254 if ( mProviderKey == "wms" ) 03255 { 03256 QDomElement layerElement = rpNode.firstChildElement( "wmsSublayer" ); 03257 while ( !layerElement.isNull() ) 03258 { 03259 // TODO: sublayer visibility - post-0.8 release timeframe 03260 03261 // collect name for the sublayer 03262 mLayers += layerElement.namedItem( "name" ).toElement().text(); 03263 03264 // collect style for the sublayer 03265 mStyles += layerElement.namedItem( "style" ).toElement().text(); 03266 03267 layerElement = layerElement.nextSiblingElement( "wmsSublayer" ); 03268 } 03269 03270 // Collect format 03271 mFormat = rpNode.namedItem( "wmsFormat" ).toElement().text(); 03272 } 03273 03274 mCrs = crs().authid(); 03275 // Collect CRS 03276 setDataProvider( mProviderKey, mLayers, mStyles, mFormat, mCrs ); 03277 03278 QString theError; 03279 bool res = readSymbology( layer_node, theError ); 03280 03281 // old wms settings we need to correct 03282 if ( res && 03283 mProviderKey == "wms" && 03284 mDrawingStyle == MultiBandColor && 03285 mRedBandName == TRSTRING_NOT_SET && 03286 mGreenBandName == TRSTRING_NOT_SET && 03287 mBlueBandName == TRSTRING_NOT_SET ) 03288 { 03289 mDrawingStyle = SingleBandColorDataStyle; 03290 mGrayBandName = bandName( 1 ); 03291 } 03292 03293 // Check timestamp 03294 QDomNode stampNode = layer_node.namedItem( "timestamp" ); 03295 if ( !stampNode.isNull() ) 03296 { 03297 QDateTime stamp = QDateTime::fromString( stampNode.toElement().text(), Qt::ISODate ); 03298 // TODO: very bad, we have to load twice!!! Make QgsDataProvider::timestamp() static? 03299 if ( stamp < mDataProvider->dataTimestamp() ) 03300 { 03301 QgsDebugMsg( "data changed, reload provider" ); 03302 closeDataProvider(); 03303 init(); 03304 setDataProvider( mProviderKey, mLayers, mStyles, mFormat, mCrs ); 03305 } 03306 } 03307 03308 return res; 03309 } // QgsRasterLayer::readXml( QDomNode & layer_node ) 03310 03311 /* 03312 * @param QDomNode the node that will have the style element added to it. 03313 * @param QDomDocument the document that will have the QDomNode added. 03314 * @param errorMessage reference to string that will be updated with any error messages 03315 * @return true in case of success. 03316 */ 03317 bool QgsRasterLayer::writeSymbology( QDomNode & layer_node, QDomDocument & document, QString& errorMessage ) const 03318 { 03319 Q_UNUSED( errorMessage ); 03320 // <rasterproperties> 03321 QDomElement rasterPropertiesElement = document.createElement( "rasterproperties" ); 03322 layer_node.appendChild( rasterPropertiesElement ); 03323 03324 QStringList sl = subLayers(); 03325 QStringList sls = mDataProvider->subLayerStyles(); 03326 03327 QStringList::const_iterator layerStyle = sls.begin(); 03328 03329 if ( mProviderKey == "wms" ) 03330 { 03331 // <rasterproperties><wmsSublayer> 03332 for ( QStringList::const_iterator layerName = sl.begin(); 03333 layerName != sl.end(); 03334 ++layerName ) 03335 { 03336 03337 QgsDebugMsg( QString( "<rasterproperties><wmsSublayer> %1" ).arg( layerName->toLocal8Bit().data() ) ); 03338 03339 QDomElement sublayerElement = document.createElement( "wmsSublayer" ); 03340 03341 // TODO: sublayer visibility - post-0.8 release timeframe 03342 03343 // <rasterproperties><wmsSublayer><name> 03344 QDomElement sublayerNameElement = document.createElement( "name" ); 03345 QDomText sublayerNameText = document.createTextNode( *layerName ); 03346 sublayerNameElement.appendChild( sublayerNameText ); 03347 sublayerElement.appendChild( sublayerNameElement ); 03348 03349 // <rasterproperties><wmsSublayer><style> 03350 QDomElement sublayerStyleElement = document.createElement( "style" ); 03351 QDomText sublayerStyleText = document.createTextNode( *layerStyle ); 03352 sublayerStyleElement.appendChild( sublayerStyleText ); 03353 sublayerElement.appendChild( sublayerStyleElement ); 03354 03355 rasterPropertiesElement.appendChild( sublayerElement ); 03356 03357 // This assumes there are exactly the same number of "layerName"s as there are "layerStyle"s 03358 ++layerStyle; 03359 } 03360 03361 // <rasterproperties><wmsFormat> 03362 QDomElement formatElement = document.createElement( "wmsFormat" ); 03363 QDomText formatText = 03364 document.createTextNode( mDataProvider->imageEncoding() ); 03365 formatElement.appendChild( formatText ); 03366 rasterPropertiesElement.appendChild( formatElement ); 03367 } 03368 03369 // <mDrawingStyle> 03370 QDomElement drawStyleElement = document.createElement( "mDrawingStyle" ); 03371 QDomText drawStyleText = document.createTextNode( drawingStyleAsString() ); 03372 03373 drawStyleElement.appendChild( drawStyleText ); 03374 03375 rasterPropertiesElement.appendChild( drawStyleElement ); 03376 03377 // <colorShadingAlgorithm> 03378 QDomElement colorShadingAlgorithmElement = document.createElement( "mColorShadingAlgorithm" ); 03379 QDomText colorShadingAlgorithmText = document.createTextNode( colorShadingAlgorithmAsString() ); 03380 03381 colorShadingAlgorithmElement.appendChild( colorShadingAlgorithmText ); 03382 03383 rasterPropertiesElement.appendChild( colorShadingAlgorithmElement ); 03384 03385 // <mInvertColor> 03386 QDomElement mInvertColorElement = document.createElement( "mInvertColor" ); 03387 03388 if ( invertHistogram() ) 03389 { 03390 mInvertColorElement.setAttribute( "boolean", "true" ); 03391 } 03392 else 03393 { 03394 mInvertColorElement.setAttribute( "boolean", "false" ); 03395 } 03396 03397 rasterPropertiesElement.appendChild( mInvertColorElement ); 03398 03399 // <mRedBandName> 03400 QDomElement mRedBandNameElement = document.createElement( "mRedBandName" ); 03401 QString writtenRedBandName = redBandName(); 03402 if ( writtenRedBandName == TRSTRING_NOT_SET ) 03403 { 03404 // Write english "not set" only. 03405 writtenRedBandName = QSTRING_NOT_SET; 03406 } 03407 QDomText mRedBandNameText = document.createTextNode( writtenRedBandName ); 03408 03409 mRedBandNameElement.appendChild( mRedBandNameText ); 03410 03411 rasterPropertiesElement.appendChild( mRedBandNameElement ); 03412 03413 03414 // <mGreenBandName> 03415 QDomElement mGreenBandNameElement = document.createElement( "mGreenBandName" ); 03416 QString writtenGreenBandName = greenBandName(); 03417 if ( writtenGreenBandName == TRSTRING_NOT_SET ) 03418 { 03419 // Write english "not set" only. 03420 writtenGreenBandName = QSTRING_NOT_SET; 03421 } 03422 QDomText mGreenBandNameText = document.createTextNode( writtenGreenBandName ); 03423 03424 mGreenBandNameElement.appendChild( mGreenBandNameText ); 03425 03426 rasterPropertiesElement.appendChild( mGreenBandNameElement ); 03427 03428 // <mBlueBandName> 03429 QDomElement mBlueBandNameElement = document.createElement( "mBlueBandName" ); 03430 QString writtenBlueBandName = blueBandName(); 03431 if ( writtenBlueBandName == TRSTRING_NOT_SET ) 03432 { 03433 // Write english "not set" only. 03434 writtenBlueBandName = QSTRING_NOT_SET; 03435 } 03436 QDomText mBlueBandNameText = document.createTextNode( writtenBlueBandName ); 03437 03438 mBlueBandNameElement.appendChild( mBlueBandNameText ); 03439 03440 rasterPropertiesElement.appendChild( mBlueBandNameElement ); 03441 03442 // <mGrayBandName> 03443 QDomElement mGrayBandNameElement = document.createElement( "mGrayBandName" ); 03444 QString writtenGrayBandName = grayBandName(); 03445 if ( writtenGrayBandName == TRSTRING_NOT_SET ) 03446 { 03447 // Write english "not set" only. 03448 writtenGrayBandName = QSTRING_NOT_SET; 03449 } 03450 QDomText mGrayBandNameText = document.createTextNode( writtenGrayBandName ); 03451 03452 mGrayBandNameElement.appendChild( mGrayBandNameText ); 03453 rasterPropertiesElement.appendChild( mGrayBandNameElement ); 03454 03455 // <mStandardDeviations> 03456 QDomElement mStandardDeviationsElement = document.createElement( "mStandardDeviations" ); 03457 QDomText mStandardDeviationsText = document.createTextNode( QString::number( standardDeviations() ) ); 03458 03459 mStandardDeviationsElement.appendChild( mStandardDeviationsText ); 03460 03461 rasterPropertiesElement.appendChild( mStandardDeviationsElement ); 03462 03463 // <mUserDefinedRGBMinimumMaximum> 03464 QDomElement userDefinedRGBMinMaxFlag = document.createElement( "mUserDefinedRGBMinimumMaximum" ); 03465 03466 if ( hasUserDefinedRGBMinimumMaximum() ) 03467 { 03468 userDefinedRGBMinMaxFlag.setAttribute( "boolean", "true" ); 03469 } 03470 else 03471 { 03472 userDefinedRGBMinMaxFlag.setAttribute( "boolean", "false" ); 03473 } 03474 03475 rasterPropertiesElement.appendChild( userDefinedRGBMinMaxFlag ); 03476 03477 // <mRGBMinimumMaximumEstimated> 03478 QDomElement RGBMinimumMaximumEstimated = document.createElement( "mRGBMinimumMaximumEstimated" ); 03479 03480 if ( isRGBMinimumMaximumEstimated() ) 03481 { 03482 RGBMinimumMaximumEstimated.setAttribute( "boolean", "true" ); 03483 } 03484 else 03485 { 03486 RGBMinimumMaximumEstimated.setAttribute( "boolean", "false" ); 03487 } 03488 03489 rasterPropertiesElement.appendChild( RGBMinimumMaximumEstimated ); 03490 03491 // <mUserDefinedGrayMinimumMaximum> 03492 QDomElement userDefinedGrayMinMaxFlag = document.createElement( "mUserDefinedGrayMinimumMaximum" ); 03493 03494 if ( hasUserDefinedGrayMinimumMaximum() ) 03495 { 03496 userDefinedGrayMinMaxFlag.setAttribute( "boolean", "true" ); 03497 } 03498 else 03499 { 03500 userDefinedGrayMinMaxFlag.setAttribute( "boolean", "false" ); 03501 } 03502 03503 rasterPropertiesElement.appendChild( userDefinedGrayMinMaxFlag ); 03504 03505 // <mGrayMinimumMaximumEstimated> 03506 QDomElement GrayMinimumMaximumEstimated = document.createElement( "mGrayMinimumMaximumEstimated" ); 03507 03508 if ( isGrayMinimumMaximumEstimated() ) 03509 { 03510 GrayMinimumMaximumEstimated.setAttribute( "boolean", "true" ); 03511 } 03512 else 03513 { 03514 GrayMinimumMaximumEstimated.setAttribute( "boolean", "false" ); 03515 } 03516 03517 rasterPropertiesElement.appendChild( GrayMinimumMaximumEstimated ); 03518 03519 // <contrastEnhancementAlgorithm> 03520 QDomElement contrastEnhancementAlgorithmElement = document.createElement( "mContrastEnhancementAlgorithm" ); 03521 QDomText contrastEnhancementAlgorithmText = document.createTextNode( contrastEnhancementAlgorithmAsString() ); 03522 03523 contrastEnhancementAlgorithmElement.appendChild( contrastEnhancementAlgorithmText ); 03524 03525 rasterPropertiesElement.appendChild( contrastEnhancementAlgorithmElement ); 03526 03527 // <minMaxValues> 03528 QList<QgsContrastEnhancement>::const_iterator it; 03529 QDomElement contrastEnhancementMinMaxValuesElement = document.createElement( "contrastEnhancementMinMaxValues" ); 03530 for ( it = mContrastEnhancementList.constBegin(); it != mContrastEnhancementList.constEnd(); ++it ) 03531 { 03532 QDomElement minMaxEntry = document.createElement( "minMaxEntry" ); 03533 QDomElement minEntry = document.createElement( "min" ); 03534 QDomElement maxEntry = document.createElement( "max" ); 03535 03536 QDomText minEntryText = document.createTextNode( QString::number( it->minimumValue() ) ); 03537 minEntry.appendChild( minEntryText ); 03538 03539 QDomText maxEntryText = document.createTextNode( QString::number( it->maximumValue() ) ); 03540 maxEntry.appendChild( maxEntryText ); 03541 03542 minMaxEntry.appendChild( minEntry ); 03543 minMaxEntry.appendChild( maxEntry ); 03544 03545 contrastEnhancementMinMaxValuesElement.appendChild( minMaxEntry ); 03546 } 03547 03548 rasterPropertiesElement.appendChild( contrastEnhancementMinMaxValuesElement ); 03549 03550 /* 03551 * Transparency tab 03552 */ 03553 // <mNodataValue> 03554 QDomElement mNoDataValueElement = document.createElement( "mNoDataValue" ); 03555 QDomText mNoDataValueText = document.createTextNode( QString::number( mNoDataValue, 'f' ) ); 03556 if ( mValidNoDataValue ) 03557 { 03558 mNoDataValueElement.setAttribute( "mValidNoDataValue", "true" ); 03559 } 03560 else 03561 { 03562 mNoDataValueElement.setAttribute( "mValidNoDataValue", "false" ); 03563 } 03564 03565 mNoDataValueElement.appendChild( mNoDataValueText ); 03566 03567 rasterPropertiesElement.appendChild( mNoDataValueElement ); 03568 03569 03570 if ( mRasterTransparency.transparentSingleValuePixelList().count() > 0 ) 03571 { 03572 QDomElement singleValuePixelListElement = document.createElement( "singleValuePixelList" ); 03573 03574 QList<QgsRasterTransparency::TransparentSingleValuePixel> myPixelList = mRasterTransparency.transparentSingleValuePixelList(); 03575 QList<QgsRasterTransparency::TransparentSingleValuePixel>::iterator it; 03576 for ( it = myPixelList.begin(); it != myPixelList.end(); ++it ) 03577 { 03578 QDomElement pixelListElement = document.createElement( "pixelListEntry" ); 03579 pixelListElement.setAttribute( "pixelValue", QString::number( it->pixelValue, 'f' ) ); 03580 pixelListElement.setAttribute( "percentTransparent", QString::number( it->percentTransparent ) ); 03581 03582 singleValuePixelListElement.appendChild( pixelListElement ); 03583 } 03584 03585 rasterPropertiesElement.appendChild( singleValuePixelListElement ); 03586 } 03587 03588 if ( mRasterTransparency.transparentThreeValuePixelList().count() > 0 ) 03589 { 03590 QDomElement threeValuePixelListElement = document.createElement( "threeValuePixelList" ); 03591 03592 QList<QgsRasterTransparency::TransparentThreeValuePixel> myPixelList = mRasterTransparency.transparentThreeValuePixelList(); 03593 QList<QgsRasterTransparency::TransparentThreeValuePixel>::iterator it; 03594 for ( it = myPixelList.begin(); it != myPixelList.end(); ++it ) 03595 { 03596 QDomElement pixelListElement = document.createElement( "pixelListEntry" ); 03597 pixelListElement.setAttribute( "red", QString::number( it->red, 'f' ) ); 03598 pixelListElement.setAttribute( "green", QString::number( it->green, 'f' ) ); 03599 pixelListElement.setAttribute( "blue", QString::number( it->blue, 'f' ) ); 03600 pixelListElement.setAttribute( "percentTransparent", QString::number( it->percentTransparent ) ); 03601 03602 threeValuePixelListElement.appendChild( pixelListElement ); 03603 } 03604 03605 rasterPropertiesElement.appendChild( threeValuePixelListElement ); 03606 } 03607 03608 /* 03609 * Color Ramp tab 03610 */ 03611 if ( QgsRasterLayer::ColorRampShader == colorShadingAlgorithm() ) 03612 { 03613 QDomElement customColorRampElement = document.createElement( "customColorRamp" ); 03614 03615 QDomElement customColorRampType = document.createElement( "colorRampType" ); 03616 QDomText customColorRampTypeText = document.createTextNode((( QgsColorRampShader* )mRasterShader->rasterShaderFunction() )->colorRampTypeAsQString() ); 03617 customColorRampType.appendChild( customColorRampTypeText ); 03618 customColorRampElement.appendChild( customColorRampType ); 03619 03620 QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = (( QgsColorRampShader* )mRasterShader->rasterShaderFunction() )->colorRampItemList(); 03621 QList<QgsColorRampShader::ColorRampItem>::iterator it; 03622 for ( it = myColorRampItemList.begin(); it != myColorRampItemList.end(); ++it ) 03623 { 03624 QDomElement colorRampEntryElement = document.createElement( "colorRampEntry" ); 03625 colorRampEntryElement.setAttribute( "red", QString::number( it->color.red() ) ); 03626 colorRampEntryElement.setAttribute( "green", QString::number( it->color.green() ) ); 03627 colorRampEntryElement.setAttribute( "blue", QString::number( it->color.blue() ) ); 03628 colorRampEntryElement.setAttribute( "value", QString::number( it->value, 'f' ) ); 03629 colorRampEntryElement.setAttribute( "label", it->label ); 03630 03631 customColorRampElement.appendChild( colorRampEntryElement ); 03632 } 03633 03634 rasterPropertiesElement.appendChild( customColorRampElement ); 03635 } 03636 03637 return true; 03638 } // bool QgsRasterLayer::writeSymbology 03639 03640 /* 03641 * virtual 03642 * @note Called by QgsMapLayer::writeXML(). 03643 */ 03644 bool QgsRasterLayer::writeXml( QDomNode & layer_node, 03645 QDomDocument & document ) 03646 { 03647 // first get the layer element so that we can append the type attribute 03648 03649 QDomElement mapLayerNode = layer_node.toElement(); 03650 03651 if ( mapLayerNode.isNull() || "maplayer" != mapLayerNode.nodeName() ) 03652 { 03653 QgsMessageLog::logMessage( tr( "<maplayer> not found." ), tr( "Raster" ) ); 03654 return false; 03655 } 03656 03657 mapLayerNode.setAttribute( "type", "raster" ); 03658 03659 // add provider node 03660 03661 QDomElement provider = document.createElement( "provider" ); 03662 QDomText providerText = document.createTextNode( mProviderKey ); 03663 provider.appendChild( providerText ); 03664 layer_node.appendChild( provider ); 03665 03666 //write out the symbology 03667 QString errorMsg; 03668 return writeSymbology( layer_node, document, errorMsg ); 03669 } 03670 03672 // 03673 // Private methods 03674 // 03676 void QgsRasterLayer::drawSingleBandColorData( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 03677 const QgsMapToPixel* theQgsMapToPixel, int theBandNo ) 03678 { 03679 QgsDebugMsg( "entered." ); 03680 03681 QgsRasterImageBuffer imageBuffer( mDataProvider, theBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 03682 imageBuffer.reset(); 03683 03684 QRgb* imageScanLine = 0; 03685 void* rasterScanLine = 0; 03686 03687 while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine ) ) 03688 { 03689 if ( mTransparencyLevel == 255 ) 03690 { 03691 int size = theRasterViewPort->drawableAreaXDim * 4; 03692 memcpy( imageScanLine, rasterScanLine, size ); 03693 } 03694 else 03695 { 03696 uint *p = ( uint* ) rasterScanLine; 03697 for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i ) 03698 { 03699 QRgb c( *p++ ); 03700 03701 imageScanLine[ i ] = qRgba( qRed( c ), qGreen( c ), qBlue( c ), qAlpha( c ) * mTransparencyLevel / 255 ); 03702 } 03703 } 03704 } 03705 } 03706 03707 void QgsRasterLayer::drawMultiBandColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 03708 const QgsMapToPixel* theQgsMapToPixel ) 03709 { 03710 QgsDebugMsg( "entered." ); 03711 int myRedBandNo = bandNumber( mRedBandName ); 03712 //Invalid band number, segfault prevention 03713 if ( 0 >= myRedBandNo ) 03714 { 03715 return; 03716 } 03717 03718 int myGreenBandNo = bandNumber( mGreenBandName ); 03719 //Invalid band number, segfault prevention 03720 if ( 0 >= myGreenBandNo ) 03721 { 03722 return; 03723 } 03724 03725 int myBlueBandNo = bandNumber( mBlueBandName ); 03726 //Invalid band number, segfault prevention 03727 if ( 0 >= myBlueBandNo ) 03728 { 03729 return; 03730 } 03731 03732 int myTransparencyBandNo = bandNumber( mTransparencyBandName ); 03733 bool hasTransparencyBand = 0 < myTransparencyBandNo; 03734 03735 int myRedType = mDataProvider->dataType( myRedBandNo ); 03736 int myGreenType = mDataProvider->dataType( myGreenBandNo ); 03737 int myBlueType = mDataProvider->dataType( myBlueBandNo ); 03738 int myTransparencyType = hasTransparencyBand ? mDataProvider->dataType( myTransparencyBandNo ) : 0; 03739 03740 QRgb* redImageScanLine = 0; 03741 void* redRasterScanLine = 0; 03742 QRgb* greenImageScanLine = 0; 03743 void* greenRasterScanLine = 0; 03744 QRgb* blueImageScanLine = 0; 03745 void* blueRasterScanLine = 0; 03746 QRgb* transparencyImageScanLine = 0; 03747 void* transparencyRasterScanLine = 0; 03748 03749 QRgb myDefaultColor = qRgba( 255, 255, 255, 0 ); 03750 03751 QgsRasterBandStats myRedBandStats; 03752 QgsRasterBandStats myGreenBandStats; 03753 QgsRasterBandStats myBlueBandStats; 03754 03755 /* 03756 * If a stetch is requested and there are no user defined Min Max values 03757 * we need to get these values from the bands themselves. 03758 * 03759 */ 03760 if ( QgsContrastEnhancement::NoEnhancement != contrastEnhancementAlgorithm() && !mUserDefinedRGBMinimumMaximum && mStandardDeviations > 0 ) 03761 { 03762 myRedBandStats = bandStatistics( myRedBandNo ); 03763 myGreenBandStats = bandStatistics( myGreenBandNo ); 03764 myBlueBandStats = bandStatistics( myBlueBandNo ); 03765 mRGBMinimumMaximumEstimated = false; 03766 setMaximumValue( myRedBandNo, myRedBandStats.mean + ( mStandardDeviations * myRedBandStats.stdDev ) ); 03767 setMinimumValue( myRedBandNo, myRedBandStats.mean - ( mStandardDeviations * myRedBandStats.stdDev ) ); 03768 setMaximumValue( myGreenBandNo, myGreenBandStats.mean + ( mStandardDeviations * myGreenBandStats.stdDev ) ); 03769 setMinimumValue( myGreenBandNo, myGreenBandStats.mean - ( mStandardDeviations * myGreenBandStats.stdDev ) ); 03770 setMaximumValue( myBlueBandNo, myBlueBandStats.mean + ( mStandardDeviations * myBlueBandStats.stdDev ) ); 03771 setMinimumValue( myBlueBandNo, myBlueBandStats.mean - ( mStandardDeviations * myBlueBandStats.stdDev ) ); 03772 } 03773 else if ( QgsContrastEnhancement::NoEnhancement != contrastEnhancementAlgorithm() && !mUserDefinedRGBMinimumMaximum ) 03774 { 03775 //This case will be true the first time the image is loaded, so just approimate the min max to keep 03776 //from calling generate raster band stats 03777 mRGBMinimumMaximumEstimated = true; 03778 03779 setMinimumValue( myRedBandNo, mDataProvider->minimumValue( myRedBandNo ) ); 03780 setMaximumValue( myRedBandNo, mDataProvider->maximumValue( myRedBandNo ) ); 03781 03782 setMinimumValue( myGreenBandNo, mDataProvider->minimumValue( myGreenBandNo ) ); 03783 setMaximumValue( myGreenBandNo, mDataProvider->maximumValue( myGreenBandNo ) ); 03784 03785 setMinimumValue( myBlueBandNo, mDataProvider->minimumValue( myBlueBandNo ) ); 03786 setMaximumValue( myBlueBandNo, mDataProvider->maximumValue( myBlueBandNo ) ); 03787 } 03788 03789 //Read and display pixels 03790 double myRedValue = 0.0; 03791 double myGreenValue = 0.0; 03792 double myBlueValue = 0.0; 03793 int myTransparencyValue = 0; 03794 03795 int myStretchedRedValue = 0; 03796 int myStretchedGreenValue = 0; 03797 int myStretchedBlueValue = 0; 03798 int myAlphaValue = 0; 03799 QgsContrastEnhancement* myRedContrastEnhancement = contrastEnhancement( myRedBandNo ); 03800 QgsContrastEnhancement* myGreenContrastEnhancement = contrastEnhancement( myGreenBandNo ); 03801 QgsContrastEnhancement* myBlueContrastEnhancement = contrastEnhancement( myBlueBandNo ); 03802 03803 QgsRasterImageBuffer redImageBuffer( mDataProvider, myRedBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 03804 redImageBuffer.reset(); 03805 QgsRasterImageBuffer greenImageBuffer( mDataProvider, myGreenBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 03806 greenImageBuffer.setWritingEnabled( false ); //only draw to redImageBuffer 03807 greenImageBuffer.reset(); 03808 QgsRasterImageBuffer blueImageBuffer( mDataProvider, myBlueBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 03809 blueImageBuffer.setWritingEnabled( false ); //only draw to redImageBuffer 03810 blueImageBuffer.reset(); 03811 03812 QgsRasterImageBuffer *transparencyImageBuffer = 0; 03813 if ( hasTransparencyBand ) 03814 { 03815 transparencyImageBuffer = new QgsRasterImageBuffer( mDataProvider, myTransparencyBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 03816 transparencyImageBuffer->setWritingEnabled( false ); //only draw to redImageBuffer 03817 transparencyImageBuffer->reset(); 03818 } 03819 03820 while ( redImageBuffer.nextScanLine( &redImageScanLine, &redRasterScanLine ) 03821 && greenImageBuffer.nextScanLine( &greenImageScanLine, &greenRasterScanLine ) 03822 && blueImageBuffer.nextScanLine( &blueImageScanLine, &blueRasterScanLine ) 03823 && ( !transparencyImageBuffer || transparencyImageBuffer->nextScanLine( &transparencyImageScanLine, &transparencyRasterScanLine ) ) ) 03824 { 03825 for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i ) 03826 { 03827 if ( transparencyImageBuffer ) 03828 { 03829 myTransparencyValue = readValue( transparencyRasterScanLine, myTransparencyType, i ); 03830 if ( 0 == myTransparencyValue ) 03831 { 03832 redImageScanLine[ i ] = myDefaultColor; 03833 continue; 03834 } 03835 } 03836 03837 myRedValue = readValue( redRasterScanLine, myRedType, i ); 03838 myGreenValue = readValue( greenRasterScanLine, myGreenType, i ); 03839 myBlueValue = readValue( blueRasterScanLine, myBlueType, i ); 03840 03841 if ( mValidNoDataValue && 03842 ( 03843 ( qAbs( myRedValue - mNoDataValue ) <= TINY_VALUE || myRedValue != myRedValue ) || 03844 ( qAbs( myGreenValue - mNoDataValue ) <= TINY_VALUE || myGreenValue != myGreenValue ) || 03845 ( qAbs( myBlueValue - mNoDataValue ) <= TINY_VALUE || myBlueValue != myBlueValue ) 03846 ) 03847 ) 03848 { 03849 redImageScanLine[ i ] = myDefaultColor; 03850 continue; 03851 } 03852 03853 if ( QgsContrastEnhancement::NoEnhancement != contrastEnhancementAlgorithm() && 03854 ( !myRedContrastEnhancement->isValueInDisplayableRange( myRedValue ) || 03855 !myGreenContrastEnhancement->isValueInDisplayableRange( myGreenValue ) || 03856 !myBlueContrastEnhancement->isValueInDisplayableRange( myBlueValue ) ) ) 03857 { 03858 redImageScanLine[ i ] = myDefaultColor; 03859 continue; 03860 } 03861 03862 myAlphaValue = mRasterTransparency.alphaValue( myRedValue, myGreenValue, myBlueValue, mTransparencyLevel ); 03863 if ( 0 == myAlphaValue ) 03864 { 03865 redImageScanLine[ i ] = myDefaultColor; 03866 continue; 03867 } 03868 03869 if ( QgsContrastEnhancement::NoEnhancement == contrastEnhancementAlgorithm() ) 03870 { 03871 myStretchedRedValue = myRedValue; 03872 myStretchedGreenValue = myGreenValue; 03873 myStretchedBlueValue = myBlueValue; 03874 } 03875 else 03876 { 03877 myStretchedRedValue = myRedContrastEnhancement->enhanceContrast( myRedValue ); 03878 myStretchedGreenValue = myGreenContrastEnhancement->enhanceContrast( myGreenValue ); 03879 myStretchedBlueValue = myBlueContrastEnhancement->enhanceContrast( myBlueValue ); 03880 } 03881 03882 if ( mInvertColor ) 03883 { 03884 myStretchedRedValue = 255 - myStretchedRedValue; 03885 myStretchedGreenValue = 255 - myStretchedGreenValue; 03886 myStretchedBlueValue = 255 - myStretchedBlueValue; 03887 } 03888 03889 if ( myTransparencyValue ) 03890 myAlphaValue *= myTransparencyValue / 255.0; 03891 03892 redImageScanLine[ i ] = qRgba( myStretchedRedValue, myStretchedGreenValue, myStretchedBlueValue, myAlphaValue ); 03893 } 03894 } 03895 03896 if ( transparencyImageBuffer ) 03897 delete transparencyImageBuffer; 03898 } 03899 03900 void QgsRasterLayer::drawMultiBandSingleBandGray( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 03901 const QgsMapToPixel* theQgsMapToPixel, int theBandNo ) 03902 { 03903 //delegate to drawSingleBandGray! 03904 drawSingleBandGray( theQPainter, theRasterViewPort, theQgsMapToPixel, theBandNo ); 03905 } 03906 03907 void QgsRasterLayer::drawMultiBandSingleBandPseudoColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 03908 const QgsMapToPixel* theQgsMapToPixel, int theBandNo ) 03909 { 03910 //delegate to drawSinglePseudocolor! 03911 drawSingleBandPseudoColor( theQPainter, theRasterViewPort, theQgsMapToPixel, theBandNo ); 03912 } 03913 03921 void QgsRasterLayer::drawPalettedSingleBandColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 03922 const QgsMapToPixel* theQgsMapToPixel, int theBandNo ) 03923 { 03924 QgsDebugMsg( "entered." ); 03925 //Invalid band number, segfault prevention 03926 if ( 0 >= theBandNo ) 03927 { 03928 return; 03929 } 03930 03931 int myTransparencyBandNo = bandNumber( mTransparencyBandName ); 03932 bool hasTransparencyBand = 0 < myTransparencyBandNo; 03933 03934 if ( NULL == mRasterShader ) 03935 { 03936 return; 03937 } 03938 03939 int myDataType = mDataProvider->dataType( theBandNo ); 03940 int myTransparencyType = hasTransparencyBand ? mDataProvider->dataType( myTransparencyBandNo ) : 0; 03941 03942 QgsRasterImageBuffer imageBuffer( mDataProvider, theBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 03943 imageBuffer.reset(); 03944 03945 QgsRasterImageBuffer *transparencyImageBuffer = 0; 03946 if ( hasTransparencyBand ) 03947 { 03948 transparencyImageBuffer = new QgsRasterImageBuffer( mDataProvider, myTransparencyBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 03949 transparencyImageBuffer->setWritingEnabled( false ); //only draw to imageBuffer 03950 transparencyImageBuffer->reset(); 03951 } 03952 03953 QRgb* imageScanLine = 0; 03954 void* rasterScanLine = 0; 03955 QRgb* transparencyImageScanLine = 0; 03956 void* transparencyRasterScanLine = 0; 03957 03958 QRgb myDefaultColor = qRgba( 255, 255, 255, 0 ); 03959 double myPixelValue = 0.0; 03960 int myRedValue = 0; 03961 int myGreenValue = 0; 03962 int myBlueValue = 0; 03963 int myTransparencyValue = 0; 03964 int myAlphaValue = 0; 03965 03966 while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine ) 03967 && ( !transparencyImageBuffer || transparencyImageBuffer->nextScanLine( &transparencyImageScanLine, &transparencyRasterScanLine ) ) ) 03968 { 03969 for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i ) 03970 { 03971 if ( transparencyImageBuffer ) 03972 { 03973 myTransparencyValue = readValue( transparencyRasterScanLine, myTransparencyType, i ); 03974 if ( 0 == myTransparencyValue ) 03975 { 03976 imageScanLine[ i ] = myDefaultColor; 03977 continue; 03978 } 03979 } 03980 03981 myRedValue = 0; 03982 myGreenValue = 0; 03983 myBlueValue = 0; 03984 //myPixelValue = readValue( rasterScanLine, ( GDALDataType )myDataType, i ); 03985 myPixelValue = readValue( rasterScanLine, myDataType, i ); 03986 03987 if ( mValidNoDataValue && ( qAbs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) ) 03988 { 03989 imageScanLine[ i ] = myDefaultColor; 03990 continue; 03991 } 03992 03993 myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel ); 03994 if ( 0 == myAlphaValue ) 03995 { 03996 imageScanLine[ i ] = myDefaultColor; 03997 continue; 03998 } 03999 04000 if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) ) 04001 { 04002 imageScanLine[ i ] = myDefaultColor; 04003 continue; 04004 } 04005 04006 if ( myTransparencyValue ) 04007 myAlphaValue *= myTransparencyValue / 255.0; 04008 04009 if ( mInvertColor ) 04010 { 04011 //Invert flag, flip blue and red 04012 imageScanLine[ i ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue ); 04013 } 04014 else 04015 { 04016 //Normal 04017 imageScanLine[ i ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue ); 04018 } 04019 } 04020 } 04021 04022 if ( transparencyImageBuffer ) 04023 delete transparencyImageBuffer; 04024 } 04025 04033 void QgsRasterLayer::drawPalettedSingleBandGray( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 04034 const QgsMapToPixel* theQgsMapToPixel, int theBandNo ) 04035 { 04036 QgsDebugMsg( "entered." ); 04037 //Invalid band number, segfault prevention 04038 if ( 0 >= theBandNo ) 04039 { 04040 return; 04041 } 04042 04043 int myTransparencyBandNo = bandNumber( mTransparencyBandName ); 04044 bool hasTransparencyBand = 0 < myTransparencyBandNo; 04045 04046 if ( NULL == mRasterShader ) 04047 { 04048 return; 04049 } 04050 04051 int myDataType = mDataProvider->dataType( theBandNo ); 04052 int myTransparencyType = hasTransparencyBand ? mDataProvider->dataType( myTransparencyBandNo ) : 0; 04053 04054 QgsRasterImageBuffer imageBuffer( mDataProvider, theBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 04055 imageBuffer.reset(); 04056 04057 QgsRasterImageBuffer *transparencyImageBuffer = 0; 04058 if ( hasTransparencyBand ) 04059 { 04060 transparencyImageBuffer = new QgsRasterImageBuffer( mDataProvider, myTransparencyBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 04061 transparencyImageBuffer->setWritingEnabled( false ); //only draw to redImageBuffer 04062 transparencyImageBuffer->reset(); 04063 } 04064 04065 QRgb* imageScanLine = 0; 04066 void* rasterScanLine = 0; 04067 QRgb* transparencyImageScanLine = 0; 04068 void* transparencyRasterScanLine = 0; 04069 04070 QRgb myDefaultColor = qRgba( 255, 255, 255, 0 ); 04071 double myPixelValue = 0.0; 04072 int myRedValue = 0; 04073 int myGreenValue = 0; 04074 int myBlueValue = 0; 04075 int myTransparencyValue = 0; 04076 int myAlphaValue = 0; 04077 04078 while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine ) 04079 && ( !transparencyImageBuffer || transparencyImageBuffer->nextScanLine( &transparencyImageScanLine, &transparencyRasterScanLine ) ) ) 04080 { 04081 for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i ) 04082 { 04083 if ( transparencyImageBuffer ) 04084 { 04085 myTransparencyValue = readValue( transparencyRasterScanLine, myTransparencyType, i ); 04086 if ( 0 == myTransparencyValue ) 04087 { 04088 imageScanLine[ i ] = myDefaultColor; 04089 continue; 04090 } 04091 } 04092 04093 myRedValue = 0; 04094 myGreenValue = 0; 04095 myBlueValue = 0; 04096 //myPixelValue = readValue( rasterScanLine, ( GDALDataType )myDataType, i ); 04097 myPixelValue = readValue( rasterScanLine, myDataType, i ); 04098 04099 if ( mValidNoDataValue && ( qAbs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) ) 04100 { 04101 imageScanLine[ i ] = myDefaultColor; 04102 continue; 04103 } 04104 04105 myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel ); 04106 if ( 0 == myAlphaValue ) 04107 { 04108 imageScanLine[ i ] = myDefaultColor; 04109 continue; 04110 } 04111 04112 if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) ) 04113 { 04114 imageScanLine[ i ] = myDefaultColor; 04115 continue; 04116 } 04117 04118 if ( myTransparencyValue ) 04119 myAlphaValue *= myTransparencyValue / 255.0; 04120 04121 if ( mInvertColor ) 04122 { 04123 //Invert flag, flip blue and red 04124 double myGrayValue = ( 0.3 * ( double )myRedValue ) + ( 0.59 * ( double )myGreenValue ) + ( 0.11 * ( double )myBlueValue ); 04125 imageScanLine[ i ] = qRgba(( int )myGrayValue, ( int )myGrayValue, ( int )myGrayValue, myAlphaValue ); 04126 } 04127 else 04128 { 04129 //Normal 04130 double myGrayValue = ( 0.3 * ( double )myBlueValue ) + ( 0.59 * ( double )myGreenValue ) + ( 0.11 * ( double )myRedValue ); 04131 imageScanLine[ i ] = qRgba(( int )myGrayValue, ( int )myGrayValue, ( int )myGrayValue, myAlphaValue ); 04132 } 04133 } 04134 } 04135 04136 if ( transparencyImageBuffer ) 04137 delete transparencyImageBuffer; 04138 } 04139 04148 void QgsRasterLayer::drawPalettedSingleBandPseudoColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 04149 const QgsMapToPixel* theQgsMapToPixel, int theBandNo ) 04150 { 04151 QgsDebugMsg( "entered." ); 04152 //Invalid band number, segfault prevention 04153 if ( 0 >= theBandNo ) 04154 { 04155 return; 04156 } 04157 04158 int myTransparencyBandNo = bandNumber( mTransparencyBandName ); 04159 bool hasTransparencyBand = 0 < myTransparencyBandNo; 04160 04161 if ( NULL == mRasterShader ) 04162 { 04163 return; 04164 } 04165 04166 QgsRasterBandStats myRasterBandStats = bandStatistics( theBandNo ); 04167 int myDataType = mDataProvider->dataType( theBandNo ); 04168 int myTransparencyType = hasTransparencyBand ? mDataProvider->dataType( myTransparencyBandNo ) : 0; 04169 04170 QgsRasterImageBuffer imageBuffer( mDataProvider, theBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 04171 imageBuffer.reset(); 04172 04173 QgsRasterImageBuffer *transparencyImageBuffer = 0; 04174 if ( hasTransparencyBand ) 04175 { 04176 transparencyImageBuffer = new QgsRasterImageBuffer( mDataProvider, myTransparencyBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 04177 transparencyImageBuffer->setWritingEnabled( false ); //only draw to imageBuffer 04178 transparencyImageBuffer->reset(); 04179 } 04180 04181 QRgb* imageScanLine = 0; 04182 void* rasterScanLine = 0; 04183 QRgb* transparencyImageScanLine = 0; 04184 void* transparencyRasterScanLine = 0; 04185 04186 QRgb myDefaultColor = qRgba( 255, 255, 255, 0 ); 04187 double myMinimumValue = 0.0; 04188 double myMaximumValue = 0.0; 04189 //Use standard deviations if set, otherwise, use min max of band 04190 if ( mStandardDeviations > 0 ) 04191 { 04192 myMinimumValue = ( myRasterBandStats.mean - ( mStandardDeviations * myRasterBandStats.stdDev ) ); 04193 myMaximumValue = ( myRasterBandStats.mean + ( mStandardDeviations * myRasterBandStats.stdDev ) ); 04194 } 04195 else 04196 { 04197 myMinimumValue = myRasterBandStats.minimumValue; 04198 myMaximumValue = myRasterBandStats.maximumValue; 04199 } 04200 04201 mRasterShader->setMinimumValue( myMinimumValue ); 04202 mRasterShader->setMaximumValue( myMaximumValue ); 04203 04204 double myPixelValue = 0.0; 04205 int myRedValue = 0; 04206 int myGreenValue = 0; 04207 int myBlueValue = 0; 04208 int myTransparencyValue = 0; 04209 int myAlphaValue = 0; 04210 04211 while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine ) 04212 && ( !transparencyImageBuffer || transparencyImageBuffer->nextScanLine( &transparencyImageScanLine, &transparencyRasterScanLine ) ) ) 04213 { 04214 for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i ) 04215 { 04216 if ( transparencyImageBuffer ) 04217 { 04218 myTransparencyValue = readValue( transparencyRasterScanLine, myTransparencyType, i ); 04219 if ( 0 == myTransparencyValue ) 04220 { 04221 imageScanLine[ i ] = myDefaultColor; 04222 continue; 04223 } 04224 } 04225 04226 myPixelValue = readValue( rasterScanLine, myDataType, i ); 04227 04228 if ( mValidNoDataValue && ( qAbs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) ) 04229 { 04230 imageScanLine[ i ] = myDefaultColor; 04231 continue; 04232 } 04233 04234 myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel ); 04235 if ( 0 == myAlphaValue ) 04236 { 04237 imageScanLine[ i ] = myDefaultColor; 04238 continue; 04239 } 04240 04241 if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) ) 04242 { 04243 imageScanLine[ i ] = myDefaultColor; 04244 continue; 04245 } 04246 04247 if ( myTransparencyValue ) 04248 myAlphaValue *= myTransparencyValue / 255.0; 04249 04250 if ( mInvertColor ) 04251 { 04252 //Invert flag, flip blue and red 04253 imageScanLine[ i ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue ); 04254 } 04255 else 04256 { 04257 //Normal 04258 imageScanLine[ i ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue ); 04259 } 04260 } 04261 } 04262 04263 if ( transparencyImageBuffer ) 04264 delete transparencyImageBuffer; 04265 } 04266 04275 void QgsRasterLayer::drawPalettedMultiBandColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 04276 const QgsMapToPixel* theQgsMapToPixel, int theBandNo ) 04277 { 04278 Q_UNUSED( theQPainter ); 04279 Q_UNUSED( theRasterViewPort ); 04280 Q_UNUSED( theQgsMapToPixel ); 04281 Q_UNUSED( theBandNo ); 04282 QgsDebugMsg( "Not supported at this time" ); 04283 } 04284 04285 void QgsRasterLayer::drawSingleBandGray( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 04286 const QgsMapToPixel* theQgsMapToPixel, int theBandNo ) 04287 { 04288 QgsDebugMsg( "layer=" + QString::number( theBandNo ) ); 04289 //Invalid band number, segfault prevention 04290 if ( 0 >= theBandNo ) 04291 { 04292 return; 04293 } 04294 04295 int myTransparencyBandNo = bandNumber( mTransparencyBandName ); 04296 bool hasTransparencyBand = 0 < myTransparencyBandNo; 04297 04298 int myDataType = mDataProvider->dataType( theBandNo ); 04299 QgsDebugMsg( "myDataType = " + QString::number( myDataType ) ); 04300 int myTransparencyType = hasTransparencyBand ? mDataProvider->dataType( myTransparencyBandNo ) : 0; 04301 04302 QgsRasterImageBuffer imageBuffer( mDataProvider, theBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 04303 imageBuffer.reset(); 04304 04305 QgsRasterImageBuffer *transparencyImageBuffer = 0; 04306 if ( hasTransparencyBand ) 04307 { 04308 transparencyImageBuffer = new QgsRasterImageBuffer( mDataProvider, myTransparencyBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 04309 transparencyImageBuffer->setWritingEnabled( false ); //only draw to imageBuffer 04310 transparencyImageBuffer->reset(); 04311 } 04312 04313 QRgb* imageScanLine = 0; 04314 void* rasterScanLine = 0; 04315 QRgb* transparencyImageScanLine = 0; 04316 void* transparencyRasterScanLine = 0; 04317 04318 QRgb myDefaultColor = qRgba( 255, 255, 255, 0 ); 04319 double myGrayValue = 0.0; 04320 int myGrayVal = 0; 04321 int myTransparencyValue = 0; 04322 int myAlphaValue = 0; 04323 QgsContrastEnhancement* myContrastEnhancement = contrastEnhancement( theBandNo ); 04324 04325 QgsRasterBandStats myGrayBandStats; 04326 //myGrayBandStats = bandStatistics( theBandNo ); // debug 04327 if ( QgsContrastEnhancement::NoEnhancement != contrastEnhancementAlgorithm() && !mUserDefinedGrayMinimumMaximum && mStandardDeviations > 0 ) 04328 { 04329 mGrayMinimumMaximumEstimated = false; 04330 myGrayBandStats = bandStatistics( theBandNo ); 04331 setMaximumValue( theBandNo, myGrayBandStats.mean + ( mStandardDeviations * myGrayBandStats.stdDev ) ); 04332 setMinimumValue( theBandNo, myGrayBandStats.mean - ( mStandardDeviations * myGrayBandStats.stdDev ) ); 04333 } 04334 else if ( QgsContrastEnhancement::NoEnhancement != contrastEnhancementAlgorithm() && !mUserDefinedGrayMinimumMaximum ) 04335 { 04336 //This case will be true the first time the image is loaded, so just approimate the min max to keep 04337 //from calling generate raster band stats 04338 mGrayMinimumMaximumEstimated = true; 04339 setMaximumValue( theBandNo, mDataProvider->maximumValue( theBandNo ) ); 04340 setMinimumValue( theBandNo, mDataProvider->minimumValue( theBandNo ) ); 04341 } 04342 04343 QgsDebugMsg( " -> imageBuffer.nextScanLine" ); 04344 while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine ) 04345 && ( !transparencyImageBuffer || transparencyImageBuffer->nextScanLine( &transparencyImageScanLine, &transparencyRasterScanLine ) ) ) 04346 { 04347 //QgsDebugMsg( " rendering line"); 04348 for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i ) 04349 { 04350 if ( transparencyImageBuffer ) 04351 { 04352 myTransparencyValue = readValue( transparencyRasterScanLine, myTransparencyType, i ); 04353 if ( 0 == myTransparencyValue ) 04354 { 04355 imageScanLine[ i ] = myDefaultColor; 04356 continue; 04357 } 04358 } 04359 04360 myGrayValue = readValue( rasterScanLine, myDataType, i ); 04361 //QgsDebugMsg( QString( "i = %1 myGrayValue = %2 ").arg(i).arg( myGrayValue ) ); 04362 //if ( myGrayValue != -2147483647 ) { 04363 //QgsDebugMsg( "myGrayValue = " + QString::number( myGrayValue ) ); 04364 //} 04365 04366 if ( mValidNoDataValue && ( qAbs( myGrayValue - mNoDataValue ) <= TINY_VALUE || myGrayValue != myGrayValue ) ) 04367 { 04368 imageScanLine[ i ] = myDefaultColor; 04369 continue; 04370 } 04371 04372 if ( !myContrastEnhancement->isValueInDisplayableRange( myGrayValue ) ) 04373 { 04374 imageScanLine[ i ] = myDefaultColor; 04375 continue; 04376 } 04377 04378 myAlphaValue = mRasterTransparency.alphaValue( myGrayValue, mTransparencyLevel ); 04379 if ( 0 == myAlphaValue ) 04380 { 04381 imageScanLine[ i ] = myDefaultColor; 04382 continue; 04383 } 04384 04385 04386 myGrayVal = myContrastEnhancement->enhanceContrast( myGrayValue ); 04387 04388 if ( mInvertColor ) 04389 { 04390 myGrayVal = 255 - myGrayVal; 04391 } 04392 04393 if ( myTransparencyValue ) 04394 myAlphaValue *= myTransparencyValue / 255.0; 04395 04396 //QgsDebugMsg( QString( "i = %1 myGrayValue = %2 myGrayVal = %3 myAlphaValue = %4").arg(i).arg( myGrayValue ).arg(myGrayVal).arg(myAlphaValue) ); 04397 imageScanLine[ i ] = qRgba( myGrayVal, myGrayVal, myGrayVal, myAlphaValue ); 04398 } 04399 } 04400 04401 if ( transparencyImageBuffer ) 04402 delete transparencyImageBuffer; 04403 } // QgsRasterLayer::drawSingleBandGray 04404 04405 void QgsRasterLayer::drawSingleBandPseudoColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 04406 const QgsMapToPixel* theQgsMapToPixel, int theBandNo ) 04407 { 04408 QgsDebugMsg( "entered." ); 04409 //Invalid band number, segfault prevention 04410 if ( 0 >= theBandNo ) 04411 { 04412 return; 04413 } 04414 04415 int myTransparencyBandNo = bandNumber( mTransparencyBandName ); 04416 bool hasTransparencyBand = 0 < myTransparencyBandNo; 04417 04418 if ( NULL == mRasterShader ) 04419 { 04420 return; 04421 } 04422 04423 QgsRasterBandStats myRasterBandStats = bandStatistics( theBandNo ); 04424 int myDataType = mDataProvider->dataType( theBandNo ); 04425 int myTransparencyType = hasTransparencyBand ? mDataProvider->dataType( myTransparencyBandNo ) : 0; 04426 04427 QgsRasterImageBuffer imageBuffer( mDataProvider, theBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 04428 imageBuffer.reset(); 04429 04430 QgsRasterImageBuffer *transparencyImageBuffer = 0; 04431 if ( hasTransparencyBand ) 04432 { 04433 transparencyImageBuffer = new QgsRasterImageBuffer( mDataProvider, myTransparencyBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 04434 transparencyImageBuffer->setWritingEnabled( false ); //only draw to imageBuffer 04435 transparencyImageBuffer->reset(); 04436 } 04437 04438 QRgb* imageScanLine = 0; 04439 void* rasterScanLine = 0; 04440 QRgb* transparencyImageScanLine = 0; 04441 void* transparencyRasterScanLine = 0; 04442 04443 QRgb myDefaultColor = qRgba( 255, 255, 255, 0 ); 04444 04445 double myMinimumValue = 0.0; 04446 double myMaximumValue = 0.0; 04447 //Use standard deviations if set, otherwise, use min max of band 04448 if ( mStandardDeviations > 0 ) 04449 { 04450 myMinimumValue = ( myRasterBandStats.mean - ( mStandardDeviations * myRasterBandStats.stdDev ) ); 04451 myMaximumValue = ( myRasterBandStats.mean + ( mStandardDeviations * myRasterBandStats.stdDev ) ); 04452 } 04453 else 04454 { 04455 myMinimumValue = myRasterBandStats.minimumValue; 04456 myMaximumValue = myRasterBandStats.maximumValue; 04457 } 04458 04459 mRasterShader->setMinimumValue( myMinimumValue ); 04460 mRasterShader->setMaximumValue( myMaximumValue ); 04461 04462 int myRedValue = 255; 04463 int myGreenValue = 255; 04464 int myBlueValue = 255; 04465 int myTransparencyValue = 0; 04466 04467 double myPixelValue = 0.0; 04468 int myAlphaValue = 0; 04469 04470 while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine ) 04471 && ( !transparencyImageBuffer || transparencyImageBuffer->nextScanLine( &transparencyImageScanLine, &transparencyRasterScanLine ) ) ) 04472 { 04473 for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i ) 04474 { 04475 if ( transparencyImageBuffer ) 04476 { 04477 myTransparencyValue = readValue( transparencyRasterScanLine, myTransparencyType, i ); 04478 if ( 0 == myTransparencyValue ) 04479 { 04480 imageScanLine[ i ] = myDefaultColor; 04481 continue; 04482 } 04483 } 04484 04485 myPixelValue = readValue( rasterScanLine, myDataType, i ); 04486 04487 if ( mValidNoDataValue && ( qAbs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) ) 04488 { 04489 imageScanLine[ i ] = myDefaultColor; 04490 continue; 04491 } 04492 04493 myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel ); 04494 if ( 0 == myAlphaValue ) 04495 { 04496 imageScanLine[ i ] = myDefaultColor; 04497 continue; 04498 } 04499 04500 if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) ) 04501 { 04502 imageScanLine[ i ] = myDefaultColor; 04503 continue; 04504 } 04505 04506 if ( myTransparencyValue ) 04507 myAlphaValue *= myTransparencyValue / 255.0; 04508 04509 if ( mInvertColor ) 04510 { 04511 //Invert flag, flip blue and red 04512 imageScanLine[ i ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue ); 04513 } 04514 else 04515 { 04516 //Normal 04517 imageScanLine[ i ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue ); 04518 //QgsDebugMsg ( QString ( "%1 value : %2 rgba : %3 %4 %5 %6" ).arg (i).arg( myPixelValue ).arg(myRedValue).arg(myGreenValue).arg(myBlueValue).arg(myAlphaValue) ); 04519 } 04520 } 04521 } 04522 04523 if ( transparencyImageBuffer ) 04524 delete transparencyImageBuffer; 04525 } 04526 04527 #if 0 04528 QString QgsRasterLayer::generateBandName( int theBandNumber ) 04529 { 04530 return tr( "Band" ) + QString( " %1" ) .arg( theBandNumber, 1 + ( int ) log10(( float ) bandCount() ), 10, QChar( '0' ) ); 04531 } 04532 #endif 04533 04538 bool QgsRasterLayer::hasBand( QString const & theBandName ) 04539 { 04540 //TODO: This function is no longer really needed and about be removed -- it is only used to see if "Palette" exists which is not the correct way to see if a band is paletted or not 04541 QgsDebugMsg( "Looking for band : " + theBandName ); 04542 04543 for ( int i = 1; i <= mDataProvider->bandCount(); i++ ) 04544 { 04545 QString myColorQString = mDataProvider->colorInterpretationName( i ); 04546 QgsDebugMsgLevel( QString( "band%1" ).arg( i ), 2 ); 04547 04548 if ( myColorQString == theBandName ) 04549 { 04550 QgsDebugMsgLevel( QString( "band%1" ).arg( i ), 2 ); 04551 QgsDebugMsgLevel( "Found band : " + theBandName, 2 ); 04552 04553 return true; 04554 } 04555 QgsDebugMsgLevel( "Found unmatched band : " + QString::number( i ) + " " + myColorQString, 2 ); 04556 } 04557 return false; 04558 } 04559 04560 QString QgsRasterLayer::projectionWkt() 04561 { 04562 // TODO: where is it used? It would be better to use crs. 04563 return mDataProvider->crs().toWkt(); 04564 } 04565 04566 /* 04567 *data type is the same as raster band. The memory must be released later! 04568 * \return pointer to the memory 04569 */ 04570 void *QgsRasterLayer::readData( int bandNo, QgsRasterViewPort *viewPort ) 04571 { 04572 int size = mDataProvider->dataTypeSize( bandNo ) / 8; 04573 04574 #if 0 04575 QgsDebugMsg( "calling RasterIO with " + 04576 QString( ", source NW corner: " ) + QString::number( viewPort->rectXOffset ) + 04577 ", " + QString::number( viewPort->rectYOffset ) + 04578 ", source size: " + QString::number( viewPort->clippedWidth ) + 04579 ", " + QString::number( viewPort->clippedHeight ) + 04580 ", dest size: " + QString::number( viewPort->drawableAreaXDim ) + 04581 ", " + QString::number( viewPort->drawableAreaYDim ) ); 04582 #endif 04583 void *data = VSIMalloc( size * viewPort->drawableAreaXDim * viewPort->drawableAreaYDim ); 04584 04585 /* Abort if out of memory */ 04586 if ( data == NULL ) 04587 { 04588 QgsDebugMsg( "Layer " + name() + " couldn't allocate enough memory. Ignoring" ); 04589 } 04590 else 04591 { 04592 // TODO: check extent 04593 QgsRectangle partExtent( 04594 viewPort->mDrawnExtent.xMinimum(), 04595 viewPort->mDrawnExtent.yMinimum(), 04596 viewPort->mDrawnExtent.xMaximum(), 04597 viewPort->mDrawnExtent.yMaximum() 04598 ); 04599 mDataProvider->readBlock( bandNo, partExtent, 04600 viewPort->drawableAreaXDim, 04601 viewPort->drawableAreaYDim, 04602 viewPort->mSrcCRS, 04603 viewPort->mDestCRS, data ); 04604 } 04605 return data; 04606 } 04607 04608 /* 04609 * @note Called from ctor if a raster image given there 04610 * 04611 * @param theFilename absolute path and filename of the raster to be loaded 04612 * @returns true if successfully read file 04613 */ 04614 bool QgsRasterLayer::readFile( QString const &theFilename ) 04615 { 04616 Q_UNUSED( theFilename ); 04617 mValid = false; 04618 return true; 04619 } // QgsRasterLayer::readFile 04620 04621 /* 04622 * @param index index in memory block 04623 */ 04624 double QgsRasterLayer::readValue( void *data, int type, int index ) 04625 { 04626 if ( !data ) 04627 return mValidNoDataValue ? mNoDataValue : 0.0; 04628 04629 switch ( type ) 04630 { 04631 case QgsRasterDataProvider::Byte: 04632 return ( double )(( GByte * )data )[index]; 04633 break; 04634 case QgsRasterDataProvider::UInt16: 04635 return ( double )(( GUInt16 * )data )[index]; 04636 break; 04637 case QgsRasterDataProvider::Int16: 04638 return ( double )(( GInt16 * )data )[index]; 04639 break; 04640 case QgsRasterDataProvider::UInt32: 04641 return ( double )(( GUInt32 * )data )[index]; 04642 break; 04643 case QgsRasterDataProvider::Int32: 04644 return ( double )(( GInt32 * )data )[index]; 04645 break; 04646 case QgsRasterDataProvider::Float32: 04647 return ( double )(( float * )data )[index]; 04648 break; 04649 case QgsRasterDataProvider::Float64: 04650 return ( double )(( double * )data )[index]; 04651 break; 04652 default: 04653 QgsMessageLog::logMessage( tr( "GDAL data type %1 is not supported" ).arg( type ), tr( "Raster" ) ); 04654 break; 04655 } 04656 04657 return mValidNoDataValue ? mNoDataValue : 0.0; 04658 } 04659 04660 bool QgsRasterLayer::update() 04661 { 04662 QgsDebugMsg( "entered." ); 04663 // Check if data changed 04664 if ( mDataProvider->dataTimestamp() > mDataProvider->timestamp() ) 04665 { 04666 QgsDebugMsg( "reload data" ); 04667 closeDataProvider(); 04668 init(); 04669 setDataProvider( mProviderKey, mLayers, mStyles, mFormat, mCrs ); 04670 emit dataChanged(); 04671 } 04672 return mValid; 04673 } 04674 04675 bool QgsRasterLayer::usesProvider() 04676 { 04677 return !mProviderKey.isEmpty(); 04678 } 04679 04680 QString QgsRasterLayer::validateBandName( QString const & theBandName ) 04681 { 04682 QgsDebugMsg( "Checking..." ); 04683 //check if the band is unset 04684 if ( theBandName == TRSTRING_NOT_SET || theBandName == QSTRING_NOT_SET ) 04685 { 04686 QgsDebugMsg( "Band name is '" + QSTRING_NOT_SET + "'. Nothing to do." ); 04687 // Use translated name internally 04688 return TRSTRING_NOT_SET; 04689 } 04690 04691 //check that a valid band name was passed 04692 QgsDebugMsg( "Looking through raster band stats for matching band name" ); 04693 for ( int myIterator = 0; myIterator < mRasterStatsList.size(); ++myIterator ) 04694 { 04695 //find out the name of this band 04696 if ( mRasterStatsList[myIterator].bandName == theBandName ) 04697 { 04698 QgsDebugMsg( "Matching band name found" ); 04699 return theBandName; 04700 } 04701 } 04702 QgsDebugMsg( "No matching band name found in raster band stats" ); 04703 04704 QgsDebugMsg( "Testing for non zero-buffered names" ); 04705 //TODO Remove test in v2.0 or earlier 04706 QStringList myBandNameComponents = theBandName.split( " " ); 04707 if ( myBandNameComponents.size() == 2 ) 04708 { 04709 int myBandNumber = myBandNameComponents.at( 1 ).toInt(); 04710 if ( myBandNumber > 0 ) 04711 { 04712 QString myBandName = mDataProvider->generateBandName( myBandNumber ); 04713 for ( int myIterator = 0; myIterator < mRasterStatsList.size(); ++myIterator ) 04714 { 04715 //find out the name of this band 04716 if ( mRasterStatsList[myIterator].bandName == myBandName ) 04717 { 04718 QgsDebugMsg( "Matching band name found" ); 04719 return myBandName; 04720 } 04721 } 04722 } 04723 } 04724 04725 QgsDebugMsg( "Testing older naming format" ); 04726 //See of the band in an older format #:something. 04727 //TODO Remove test in v2.0 or earlier 04728 myBandNameComponents.clear(); 04729 if ( theBandName.contains( ':' ) ) 04730 { 04731 myBandNameComponents = theBandName.split( ":" ); 04732 if ( myBandNameComponents.size() == 2 ) 04733 { 04734 int myBandNumber = myBandNameComponents.at( 0 ).toInt(); 04735 if ( myBandNumber > 0 ) 04736 { 04737 QgsDebugMsg( "Transformed older name format to current format" ); 04738 return "Band " + QString::number( myBandNumber ); 04739 } 04740 } 04741 } 04742 04743 //if no matches were found default to not set 04744 QgsDebugMsg( "All checks failed, returning '" + QSTRING_NOT_SET + "'" ); 04745 return TRSTRING_NOT_SET; 04746 } 04747 04748 QgsRasterImageBuffer::QgsRasterImageBuffer( QgsRasterDataProvider *dataProvider, int bandNo, QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* mapToPixel, double* geoTransform ): 04749 mDataProvider( dataProvider ), mBandNo( bandNo ), mPainter( p ), mViewPort( viewPort ), mMapToPixel( mapToPixel ), mGeoTransform( geoTransform ), mValid( false ), mWritingEnabled( true ), mDrawPixelRect( false ), mCurrentImage( 0 ), mCurrentGDALData( 0 ) 04750 { 04751 04752 } 04753 04754 QgsRasterImageBuffer::~QgsRasterImageBuffer() 04755 { 04756 delete mCurrentImage; 04757 CPLFree( mCurrentGDALData ); 04758 } 04759 04760 void QgsRasterImageBuffer::reset( int maxPixelsInVirtualMemory ) 04761 { 04762 QgsDebugMsg( "Start" ); 04763 //if ( !mRasterBand || !mPainter || !mViewPort ) 04764 if ( !mDataProvider || mBandNo <= 0 || !mPainter || !mViewPort ) 04765 { 04766 mValid = false; 04767 return; 04768 } 04769 04770 mValid = true; 04771 04772 //decide on the partition of the image 04773 04774 int pixels = mViewPort->drawableAreaXDim * mViewPort->drawableAreaYDim; 04775 int mNumPartImages = pixels / maxPixelsInVirtualMemory + 1.0; 04776 mNumRasterRowsPerPart = ( double )mViewPort->drawableAreaYDim / ( double )mNumPartImages + 0.5; 04777 04778 mCurrentPartRasterMin = -1; 04779 mCurrentPartRasterMax = -1; 04780 mCurrentPartImageRow = 0; 04781 mNumCurrentImageRows = 0; 04782 04783 mCurrentPart = 0; 04784 04785 createNextPartImage(); 04786 04787 // TODO 04788 //if ( 2 >= mViewPort->clippedWidth && 2 >= mViewPort->clippedHeight ) 04789 if ( false ) 04790 { 04791 //use Peter's fix for zoomed in rasters 04792 mDrawPixelRect = true; 04793 } 04794 } 04795 04796 bool QgsRasterImageBuffer::nextScanLine( QRgb** imageScanLine, void** rasterScanLine ) 04797 { 04798 //QgsDebugMsg( "mCurrentRow = " + QString::number( mCurrentRow ) ); 04799 if ( !mValid ) 04800 return false; 04801 04802 if ( !mCurrentImage && !mCurrentGDALData ) 04803 { 04804 return false; 04805 } 04806 04807 if ( mCurrentPartImageRow >= mNumCurrentImageRows ) 04808 { 04809 if ( !createNextPartImage() ) 04810 { 04811 return false; 04812 } 04813 } 04814 04815 if ( mWritingEnabled ) 04816 { 04817 *imageScanLine = ( QRgb* ) mCurrentImage->scanLine( mCurrentPartImageRow ); 04818 } 04819 else 04820 { 04821 *imageScanLine = 0; 04822 } 04823 int size = mDataProvider->dataTypeSize( mBandNo ) / 8; 04824 *rasterScanLine = ( unsigned char * )mCurrentGDALData + mCurrentPartImageRow * mViewPort->drawableAreaXDim * size; 04825 04826 ++mCurrentPartImageRow; 04827 ++mCurrentRow; 04828 return !mWritingEnabled || *imageScanLine; 04829 } 04830 04831 bool QgsRasterImageBuffer::createNextPartImage() 04832 { 04833 QgsDebugMsg( "Entered" ); 04834 //draw the last image if mCurrentImage exists 04835 if ( mCurrentImage ) 04836 { 04837 if ( mWritingEnabled ) 04838 { 04839 // TODO: consider similar system with raster providers, see the comment 04840 // in QgsRasterImageBuffer::drawPixelRectangle() 04841 // e.g request the block with raster resolution and draw pixels as rectangles 04842 //if ( 2 >= mViewPort->clippedWidth && 2 >= mViewPort->clippedHeight ) 04843 if ( false ) 04844 { 04845 drawPixelRectangle(); 04846 } 04847 else 04848 { 04849 //int paintXoffset = 0; 04850 //int paintYoffset = 0; 04851 double imageX = 0; 04852 double imageY = 0; 04853 04854 if ( mMapToPixel ) 04855 { 04856 imageX = mViewPort->topLeftPoint.x(); 04857 imageY = mViewPort->topLeftPoint.y() + mCurrentPartRasterMin; 04858 } 04859 04860 QgsDebugMsg( QString( "mCurrentPartRasterMin = %1" ).arg( mCurrentPartRasterMin ) ); 04861 QgsDebugMsg( QString( "imageX = %1 imageY = %2" ).arg( imageX ).arg( imageY ) ); 04862 mPainter->drawImage( QPointF( imageX, imageY ), //the top-left point in the paint device 04863 *mCurrentImage ); 04864 } 04865 } 04866 } 04867 04868 delete mCurrentImage; mCurrentImage = 0; 04869 CPLFree( mCurrentGDALData ); mCurrentGDALData = 0; 04870 04871 mCurrentPart++; // NEW 04872 QgsDebugMsg( QString( "mCurrentPartRasterMax = %1 mViewPort->drawableAreaYDim = %2" ).arg( mCurrentPartRasterMax ).arg( mViewPort->drawableAreaYDim ) ); 04873 if ( mCurrentPartRasterMax >= mViewPort->drawableAreaYDim ) 04874 { 04875 return false; //already at the end... 04876 } 04877 04878 mCurrentPartRasterMin = mCurrentPartRasterMax + 1; 04879 mCurrentPartRasterMax = mCurrentPartRasterMin + mNumRasterRowsPerPart; 04880 if ( mCurrentPartRasterMax > mViewPort->drawableAreaYDim ) 04881 { 04882 mCurrentPartRasterMax = mViewPort->drawableAreaYDim; 04883 } 04884 mCurrentRow = mCurrentPartRasterMin; 04885 mCurrentPartImageRow = 0; 04886 04887 //read GDAL image data 04888 int size = mDataProvider->dataTypeSize( mBandNo ) / 8 ; 04889 int xSize = mViewPort->drawableAreaXDim; 04890 int ySize = mViewPort->drawableAreaYDim; 04891 04892 //make the raster tiles overlap at least 2 pixels to avoid white stripes 04893 int overlapRows = 0; 04894 if ( mMapToPixel ) 04895 { 04896 // TODO: do we still need overlaps? 04897 overlapRows = mMapToPixel->mapUnitsPerPixel() / qAbs( mGeoTransform[5] ) + 2; 04898 } 04899 //if ( mCurrentPartRasterMax + overlapRows >= mViewPort->clippedHeight ) 04900 if ( mCurrentPartRasterMax + overlapRows >= mViewPort->drawableAreaYDim ) 04901 { 04902 overlapRows = 0; 04903 } 04904 int rasterYSize = mCurrentPartRasterMax - mCurrentPartRasterMin + overlapRows; 04905 QgsDebugMsg( "rasterYSize = " + QString::number( rasterYSize ) ); 04906 04907 // TODO: consider something like this 04908 //if ( 2 >= mViewPort->clippedWidth && 2 >= mViewPort->clippedHeight ) //for zoomed in rasters 04909 if ( false ) 04910 { 04911 //rasterYSize = mViewPort->clippedHeight; 04912 //ySize = mViewPort->drawableAreaYDim; 04913 } 04914 else //normal mode 04915 { 04916 if ( mMapToPixel ) 04917 { 04918 // makes no more sense 04919 //ySize = qAbs((( rasterYSize ) / mMapToPixel->mapUnitsPerPixel() * mGeoTransform[5] ) ) + 0.5; 04920 } 04921 } 04922 QgsDebugMsg( QString( "xSize = %1 ySize = %2" ).arg( xSize ).arg( ySize ) ); 04923 if ( ySize < 1 || xSize < 1 ) 04924 { 04925 return false; 04926 } 04927 mNumCurrentImageRows = rasterYSize; 04928 QgsDebugMsg( "alloc " + QString::number( size * xSize * rasterYSize ) ); 04929 mCurrentGDALData = VSIMalloc( size * xSize * rasterYSize ); 04930 04931 double yMax = mViewPort->mDrawnExtent.yMaximum() - mCurrentRow * mMapToPixel->mapUnitsPerPixel(); 04932 double yMin = yMax - rasterYSize * mMapToPixel->mapUnitsPerPixel(); 04933 04934 QgsDebugMsg( QString( "mCurrentRow = %1 yMaximum = %2 ySize = %3 mapUnitsPerPixel = %4" ).arg( mCurrentRow ).arg( mViewPort->mDrawnExtent.yMaximum() ).arg( ySize ).arg( mMapToPixel->mapUnitsPerPixel() ) ); 04935 QgsRectangle myPartExtent( mViewPort->mDrawnExtent.xMinimum(), yMin, 04936 mViewPort->mDrawnExtent.xMaximum(), yMax ); 04937 QgsDebugMsg( "myPartExtent is " + myPartExtent.toString() ); 04938 mDataProvider->readBlock( mBandNo, myPartExtent, xSize, rasterYSize , mViewPort->mSrcCRS, mViewPort->mDestCRS, mCurrentGDALData ); 04939 04940 //create the QImage 04941 if ( mWritingEnabled ) 04942 { 04943 mCurrentImage = new QImage( xSize, rasterYSize, QImage::Format_ARGB32 ); 04944 mCurrentImage->fill( qRgba( 255, 255, 255, 0 ) ); 04945 } 04946 else 04947 { 04948 mCurrentImage = 0; 04949 } 04950 return true; 04951 } 04952 04953 void QgsRasterImageBuffer::drawPixelRectangle() 04954 { 04955 // TODO: consider using similar with raster providers, originaly it was used only with 04956 // 2 >= mViewPort->clippedWidth && 2 >= mViewPort->clippedHeight 04957 // but why? but I believe that it should be used always if the ration of original 04958 // raster resolution and device resolution is under certain limit 04959 #if 0 04960 // Set up the initial offset into the myQImage we want to copy to the map canvas 04961 // This is useful when the source image pixels are larger than the screen image. 04962 int paintXoffset = 0; 04963 int paintYoffset = 0; 04964 04965 if ( mMapToPixel ) 04966 { 04967 paintXoffset = static_cast<int>( 04968 ( mViewPort->rectXOffsetFloat - 04969 mViewPort->rectXOffset ) 04970 / mMapToPixel->mapUnitsPerPixel() 04971 * qAbs( mGeoTransform[1] ) 04972 ); 04973 04974 paintYoffset = static_cast<int>( 04975 ( mViewPort->rectYOffsetFloat - 04976 mViewPort->rectYOffset ) 04977 / mMapToPixel->mapUnitsPerPixel() 04978 * qAbs( mGeoTransform[5] ) 04979 ); 04980 04981 04982 } 04983 04984 //fix for zoomed in rasters 04985 //Catch special rendering cases 04986 //INSTANCE: 1x1 04987 if ( 1 == mViewPort->clippedWidth && 1 == mViewPort->clippedHeight ) 04988 { 04989 QColor myColor( mCurrentImage->pixel( 0, 0 ) ); 04990 myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 0 ) ) ); 04991 mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ), 04992 static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ), 04993 static_cast<int>( mViewPort->bottomRightPoint.x() ), 04994 static_cast<int>( mViewPort->bottomRightPoint.y() ), 04995 QBrush( myColor ) ); 04996 } 04997 //1x2, 2x1 or 2x2 04998 else if ( 2 >= mViewPort->clippedWidth && 2 >= mViewPort->clippedHeight ) 04999 { 05000 int myPixelBoundaryX = 0; 05001 int myPixelBoundaryY = 0; 05002 if ( mMapToPixel ) 05003 { 05004 myPixelBoundaryX = static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ) + static_cast<int>( qAbs( mGeoTransform[1] / mMapToPixel->mapUnitsPerPixel() ) ) - paintXoffset; 05005 myPixelBoundaryY = static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ) + static_cast<int>( qAbs( mGeoTransform[5] / mMapToPixel->mapUnitsPerPixel() ) ) - paintYoffset; 05006 } 05007 05008 //INSTANCE: 1x2 05009 if ( 1 == mViewPort->clippedWidth ) 05010 { 05011 QColor myColor( mCurrentImage->pixel( 0, 0 ) ); 05012 myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 0 ) ) ); 05013 mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ), 05014 static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ), 05015 static_cast<int>( mViewPort->bottomRightPoint.x() ), 05016 static_cast<int>( myPixelBoundaryY ), 05017 QBrush( myColor ) ); 05018 myColor = QColor( mCurrentImage->pixel( 0, 1 ) ); 05019 myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 1 ) ) ); 05020 mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ), 05021 static_cast<int>( myPixelBoundaryY ), 05022 static_cast<int>( mViewPort->bottomRightPoint.x() ), 05023 static_cast<int>( mViewPort->bottomRightPoint.y() ), 05024 QBrush( myColor ) ); 05025 } 05026 else 05027 { 05028 //INSTANCE: 2x1 05029 if ( 1 == mViewPort->clippedHeight ) 05030 { 05031 QColor myColor( mCurrentImage->pixel( 0, 0 ) ); 05032 myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 0 ) ) ); 05033 mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ), 05034 static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ), 05035 static_cast<int>( myPixelBoundaryX ), 05036 static_cast<int>( mViewPort->bottomRightPoint.y() ), 05037 QBrush( myColor ) ); 05038 myColor = QColor( mCurrentImage->pixel( 1, 0 ) ); 05039 myColor.setAlpha( qAlpha( mCurrentImage->pixel( 1, 0 ) ) ); 05040 mPainter->fillRect( static_cast<int>( myPixelBoundaryX ), 05041 static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ), 05042 static_cast<int>( mViewPort->bottomRightPoint.x() ), 05043 static_cast<int>( mViewPort->bottomRightPoint.y() ), 05044 QBrush( myColor ) ); 05045 } 05046 //INSTANCE: 2x2 05047 else 05048 { 05049 QColor myColor( mCurrentImage->pixel( 0, 0 ) ); 05050 myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 0 ) ) ); 05051 mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ), 05052 static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ), 05053 static_cast<int>( myPixelBoundaryX ), 05054 static_cast<int>( myPixelBoundaryY ), 05055 QBrush( myColor ) ); 05056 myColor = QColor( mCurrentImage->pixel( 1, 0 ) ); 05057 myColor.setAlpha( qAlpha( mCurrentImage->pixel( 1, 0 ) ) ); 05058 mPainter->fillRect( static_cast<int>( myPixelBoundaryX ), 05059 static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ), 05060 static_cast<int>( mViewPort->bottomRightPoint.x() ), 05061 static_cast<int>( myPixelBoundaryY ), 05062 QBrush( myColor ) ); 05063 myColor = QColor( mCurrentImage->pixel( 0, 1 ) ); 05064 myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 1 ) ) ); 05065 mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ), 05066 static_cast<int>( myPixelBoundaryY ), 05067 static_cast<int>( myPixelBoundaryX ), 05068 static_cast<int>( mViewPort->bottomRightPoint.y() ), 05069 QBrush( myColor ) ); 05070 myColor = QColor( mCurrentImage->pixel( 1, 1 ) ); 05071 myColor.setAlpha( qAlpha( mCurrentImage->pixel( 1, 1 ) ) ); 05072 mPainter->fillRect( static_cast<int>( myPixelBoundaryX ), 05073 static_cast<int>( myPixelBoundaryY ), 05074 static_cast<int>( mViewPort->bottomRightPoint.x() ), 05075 static_cast<int>( mViewPort->bottomRightPoint.y() ), 05076 QBrush( myColor ) ); 05077 } 05078 } 05079 } 05080 #endif 05081 } 05082 05083 // Keep this for now, it is used by Python interface!!! 05084 void QgsRasterLayer::registerGdalDrivers() 05085 { 05086 if ( GDALGetDriverCount() == 0 ) 05087 GDALAllRegister(); 05088 } 05089 05090 // Keep this for QgsRasterLayerProperties 05091 bool QgsRasterLayer::readColorTable( int theBandNumber, QList<QgsColorRampShader::ColorRampItem>* theList ) 05092 { 05093 // TODO : check if exists - returned vale? 05094 QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = mDataProvider->colorTable( theBandNumber ); 05095 if ( myColorRampItemList.size() == 0 ) 05096 { 05097 return false; 05098 } 05099 *theList = myColorRampItemList; 05100 return true; 05101 } 05102