Quantum GIS API Documentation  1.8
src/core/raster/qgsrasterlayer.cpp
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines