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