Quantum GIS API Documentation  1.7.5-Wroclaw
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
qgsrasterlayer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrasterlayer.cpp - description
3  -------------------
4 begin : Sat Jun 22 2002
5 copyright : (C) 2003 by Tim Sutton, Steve Halasz and Gary E.Sherman
6 email : tim at linfiniti.com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 /* $Id$ */
18 
19 #include "qgsapplication.h"
20 #include "qgslogger.h"
21 #include "qgsmaplayerregistry.h"
22 #include "qgsmaptopixel.h"
23 #include "qgsproviderregistry.h"
24 #include "qgsrasterbandstats.h"
25 #include "qgsrasterlayer.h"
26 #include "qgsrasterpyramid.h"
27 #include "qgsrectangle.h"
28 #include "qgsrendercontext.h"
30 #include "qgscoordinatetransform.h"
31 
32 #include "gdalwarper.h"
33 #include "cpl_conv.h"
34 
35 #include "qgspseudocolorshader.h"
36 #include "qgsfreakoutshader.h"
37 #include "qgscolorrampshader.h"
38 
39 #include <cstdio>
40 #include <cmath>
41 #include <limits>
42 
43 #include <QApplication>
44 #include <QCursor>
45 #include <QDomElement>
46 #include <QDomNode>
47 #include <QFile>
48 #include <QFileInfo>
49 #include <QFont>
50 #include <QFontMetrics>
51 #include <QFrame>
52 #include <QImage>
53 #include <QLabel>
54 #include <QList>
55 #include <QMatrix>
56 #include <QMessageBox>
57 #include <QLibrary>
58 #include <QPainter>
59 #include <QPixmap>
60 #include <QRegExp>
61 #include <QSlider>
62 #include <QSettings>
63 #include <QTime>
64 
65 // typedefs for provider plugin functions of interest
66 typedef void buildsupportedrasterfilefilter_t( QString & theFileFiltersString );
67 typedef bool isvalidrasterfilename_t( QString const & theFileNameQString, QString & retErrMsg );
68 
69 // workaround for MSVC compiler which already has defined macro max
70 // that interferes with calling std::numeric_limits<int>::max
71 #ifdef _MSC_VER
72 # ifdef max
73 # undef max
74 # endif
75 #endif
76 
77 // Comparison value for equality; i.e., we shouldn't directly compare two
78 // floats so it's better to take their difference and see if they're within
79 // a certain range -- in this case twenty times the smallest value that
80 // doubles can take for the current system. (Yes, 20 was arbitrary.)
81 #define TINY_VALUE std::numeric_limits<double>::epsilon() * 20
82 
83 
85  QString const & path,
86  QString const & baseName,
87  bool loadDefaultStyleFlag )
88  : QgsMapLayer( RasterLayer, baseName, path )
89  // Constant that signals property not used.
90  , QSTRING_NOT_SET( "Not Set" )
91  , TRSTRING_NOT_SET( tr( "Not Set" ) )
92  , mStandardDeviations( 0 )
93  , mDataProvider( 0 )
94  , mWidth( std::numeric_limits<int>::max() )
95  , mHeight( std::numeric_limits<int>::max() )
96  , mInvertColor( false )
97 {
98  QgsDebugMsg( "Entered" );
99 
100  // TODO, call constructor with provider key for now
101  init();
102  setDataProvider( "gdal", QStringList(), QStringList(), QString(), QString(), loadDefaultStyleFlag );
103 
104  if ( mValid && loadDefaultStyleFlag )
105  {
106  bool defaultLoadedFlag = false;
107  loadDefaultStyle( defaultLoadedFlag );
108  // I'm no sure if this should be used somehow, in pre raster-providers there was
109  // only mLastViewPort init after this block, nothing to do with style
110  //if ( defaultLoadedFlag )
111  //{
112  //return;
113  //}
114  }
115  return;
116 
117 
118 } // QgsRasterLayer ctor
119 
125  QString const & rasterLayerPath,
126  QString const & baseName,
127  QString const & providerKey,
128  QStringList const & layers,
129  QStringList const & styles,
130  QString const & format,
131  QString const & crs )
132  : QgsMapLayer( RasterLayer, baseName, rasterLayerPath )
133  , mStandardDeviations( 0 )
134  , mDataProvider( 0 )
135  , mEditable( false )
136  , mWidth( std::numeric_limits<int>::max() )
137  , mHeight( std::numeric_limits<int>::max() )
138  , mInvertColor( false )
139  , mModified( false )
140  , mProviderKey( providerKey )
141  , mLayers( layers )
142  , mStyles( styles )
143  , mFormat( format )
144  , mCrs( crs )
145 {
146  QgsDebugMsg( "(8 arguments) starting. with layer list of " +
147  layers.join( ", " ) + " and style list of " + styles.join( ", " ) + " and format of " +
148  format + " and CRS of " + crs );
149 
150 
151  init();
152  // if we're given a provider type, try to create and bind one to this layer
153  bool loadDefaultStyleFlag = false ; // ???
154  setDataProvider( providerKey, layers, styles, format, crs, loadDefaultStyleFlag );
155 
156  // Default for the popup menu
157  // TODO: popMenu = 0;
158 
159  // Get the update threshold from user settings. We
160  // do this only on construction to avoid the penality of
161  // fetching this each time the layer is drawn. If the user
162  // changes the threshold from the preferences dialog, it will
163  // have no effect on existing layers
164  // TODO: QSettings settings;
165  // updateThreshold = settings.readNumEntry("Map/updateThreshold", 1000);
166 
167 
168  // TODO: Connect signals from the dataprovider to the qgisapp
169 
170  QgsDebugMsg( "(8 arguments) exiting." );
171 
172  emit statusChanged( tr( "QgsRasterLayer created" ) );
173 } // QgsRasterLayer ctor
174 
176 {
177  mValid = false;
178  delete mRasterShader;
179  delete mDataProvider;
180 }
181 
183 //
184 // Static Methods and members
185 //
187 
195 void QgsRasterLayer::buildSupportedRasterFileFilter( QString & theFileFiltersString )
196 {
197  QgsDebugMsg( "Entered" );
198  QLibrary* myLib = QgsRasterLayer::loadProviderLibrary( "gdal" );
199  if ( !myLib )
200  {
201  QgsDebugMsg( "Could not load gdal provider library" );
202  return;
203  }
204  buildsupportedrasterfilefilter_t *pBuild = ( buildsupportedrasterfilefilter_t * ) cast_to_fptr( myLib->resolve( "buildSupportedRasterFileFilter" ) );
205  if ( ! pBuild )
206  {
207  QgsDebugMsg( "Could not resolve buildSupportedRasterFileFilter in gdal provider library" );
208  return;
209  }
210 
211  pBuild( theFileFiltersString );
212  delete myLib;
213 }
214 
218 bool QgsRasterLayer::isValidRasterFileName( QString const & theFileNameQString, QString & retErrMsg )
219 {
220 
221  QLibrary* myLib = QgsRasterLayer::loadProviderLibrary( "gdal" );
222  if ( !myLib )
223  {
224  QgsDebugMsg( "Could not load gdal provider library" );
225  return false;
226  }
227  isvalidrasterfilename_t *pValid = ( isvalidrasterfilename_t * ) cast_to_fptr( myLib->resolve( "isValidRasterFileName" ) );
228  if ( ! pValid )
229  {
230  QgsDebugMsg( "Could not resolve isValidRasterFileName in gdal provider library" );
231  return false;
232  }
233 
234  bool myIsValid = pValid( theFileNameQString, retErrMsg );
235  delete myLib;
236  return myIsValid;
237 }
238 
239 bool QgsRasterLayer::isValidRasterFileName( QString const & theFileNameQString )
240 {
241  QString retErrMsg;
242  return isValidRasterFileName( theFileNameQString, retErrMsg );
243 }
244 
245 QDateTime QgsRasterLayer::lastModified( QString const & name )
246 {
247  QgsDebugMsg( "name=" + name );
248  QDateTime t;
249 
250  QFileInfo fi( name );
251 
252  // Is it file?
253  if ( !fi.exists() ) return t;
254 
255  t = fi.lastModified();
256 
257  QgsDebugMsg( "last modified = " + t.toString() );
258 
259  return t;
260 }
261 
262 // typedef for the QgsDataProvider class factory
263 typedef QgsDataProvider * classFactoryFunction_t( const QString * );
264 
266 //
267 // Non Static Public methods
268 //
270 
272 {
273  return mBandCount;
274 }
275 
276 const QString QgsRasterLayer::bandName( int theBandNo )
277 {
278  if ( theBandNo <= mRasterStatsList.size() && theBandNo > 0 )
279  {
280  //vector starts at base 0, band counts at base1!
281  return mRasterStatsList[theBandNo - 1].bandName;
282  }
283  else
284  {
285  return QString( "" );
286  }
287 }
288 
289 int QgsRasterLayer::bandNumber( QString const & theBandName )
290 {
291  for ( int myIterator = 0; myIterator < mRasterStatsList.size(); ++myIterator )
292  {
293  //find out the name of this band
294  QgsRasterBandStats myRasterBandStats = mRasterStatsList[myIterator];
295  QgsDebugMsg( "myRasterBandStats.bandName: " + myRasterBandStats.bandName + " :: theBandName: "
296  + theBandName );
297 
298  if ( myRasterBandStats.bandName == theBandName )
299  {
300  QgsDebugMsg( "********** band " + QString::number( myRasterBandStats.bandNumber ) +
301  " was found in bandNumber " + theBandName );
302 
303  return myRasterBandStats.bandNumber;
304  }
305  }
306  QgsDebugMsg( "********** no band was found in bandNumber " + theBandName );
307 
308  return 0; //no band was found
309 }
310 
331 {
332  QgsDebugMsg( "theBandNo = " + QString::number( theBandNo ) );
333  QgsDebugMsg( "mRasterType = " + QString::number( mRasterType ) );
334  if ( mRasterType == ColorLayer )
335  {
336  // Statistics have no sense for ColorLayer
337  QgsRasterBandStats myNullReturnStats;
338  return myNullReturnStats;
339  }
340  // check if we have received a valid band number
341  if (( mDataProvider->bandCount() < theBandNo ) && mRasterType != Palette )
342  {
343  // invalid band id, return nothing
344  QgsRasterBandStats myNullReturnStats;
345  return myNullReturnStats;
346  }
347  if ( mRasterType == Palette && ( theBandNo > 3 ) )
348  {
349  // invalid band id, return nothing
350  QgsRasterBandStats myNullReturnStats;
351  return myNullReturnStats;
352  }
353  // check if we have previously gathered stats for this band...
354  if ( theBandNo < 1 || theBandNo > mRasterStatsList.size() )
355  {
356  // invalid band id, return nothing
357  QgsRasterBandStats myNullReturnStats;
358  return myNullReturnStats;
359  }
360 
361  QgsRasterBandStats myRasterBandStats = mRasterStatsList[theBandNo - 1];
362  myRasterBandStats.bandNumber = theBandNo;
363 
364  // don't bother with this if we already have stats
365  if ( myRasterBandStats.statsGathered )
366  {
367  return myRasterBandStats;
368  }
369 
370  myRasterBandStats = mDataProvider->bandStatistics( theBandNo );
371  QgsDebugMsg( "adding stats to stats collection at position " + QString::number( theBandNo - 1 ) );
372  //add this band to the class stats map
373  mRasterStatsList[theBandNo - 1] = myRasterBandStats;
374  emit drawingProgress( mHeight, mHeight ); //reset progress
375  QgsDebugMsg( "Stats collection completed returning" );
376  return myRasterBandStats;
377 } // QgsRasterLayer::bandStatistics
378 
379 const QgsRasterBandStats QgsRasterLayer::bandStatistics( QString const & theBandName )
380 {
381  // only print message if we are actually gathering the stats
382  emit statusChanged( tr( "Retrieving stats for %1" ).arg( name() ) );
383  qApp->processEvents();
384  //reset the main app progress bar
385  emit drawingProgress( 0, 0 );
386  //we cant use a vector iterator because the iterator is astruct not a class
387  //and the qvector model does not like this.
388  for ( int i = 1; i <= mDataProvider->bandCount(); i++ )
389  {
390  QgsRasterBandStats myRasterBandStats = bandStatistics( i );
391  if ( myRasterBandStats.bandName == theBandName )
392  {
393  return myRasterBandStats;
394  }
395  }
396 
397  return QgsRasterBandStats(); // return a null one
398 }
399 
400 
401 QString QgsRasterLayer::buildPyramids( RasterPyramidList const & theRasterPyramidList,
402  QString const & theResamplingMethod, bool theTryInternalFlag )
403 {
404  return mDataProvider->buildPyramids( theRasterPyramidList, theResamplingMethod, theTryInternalFlag );
405 }
406 
407 
409 {
411 }
412 
414 {
415  switch ( mColorShadingAlgorithm )
416  {
417  case PseudoColorShader:
418  return QString( "PseudoColorShader" );
419  break;
420  case FreakOutShader:
421  return QString( "FreakOutShader" );
422  break;
423  case ColorRampShader:
424  return QString( "ColorRampShader" );
425  break;
426  case UserDefinedShader:
427  return QString( "UserDefinedShader" );
428  break;
429  default:
430  break;
431  }
432 
433  return QString( "UndefinedShader" );
434 }
435 
440 void QgsRasterLayer::computeMinimumMaximumEstimates( int theBand, double* theMinMax )
441 {
442  if ( 0 == theMinMax ) { return; }
443 
444  if ( 0 < theBand && theBand <= ( int ) bandCount() )
445  {
446  theMinMax[0] = mDataProvider->minimumValue( theBand );
447  theMinMax[1] = mDataProvider->maximumValue( theBand );
448  }
449 }
450 
455 void QgsRasterLayer::computeMinimumMaximumEstimates( QString theBand, double* theMinMax )
456 {
457  computeMinimumMaximumEstimates( bandNumber( theBand ), theMinMax );
458 }
459 
460 void QgsRasterLayer::computeMinimumMaximumEstimates( int theBand, double& theMin, double& theMax )
461 {
462  double theMinMax[2];
463  computeMinimumMaximumEstimates( theBand, theMinMax );
464  theMin = theMinMax[0];
465  theMax = theMinMax[1];
466 }
467 
472 void QgsRasterLayer::computeMinimumMaximumFromLastExtent( int theBand, double* theMinMax )
473 {
474  if ( 0 == theMinMax ) { return; }
475 
476  int myDataType = mDataProvider->dataType( theBand );
477  void* myScanData = readData( theBand, &mLastViewPort );
478 
479  /* Check for out of memory error */
480  if ( myScanData == NULL )
481  {
482  return;
483  }
484 
485  if ( 0 < theBand && theBand <= ( int ) bandCount() )
486  {
487  // Was there any reason to use float for myMin, myMax, myValue?
488  // It was breaking Float64 data obviously, especially if an extreme value
489  // was used for NoDataValue.
490  double myMin = std::numeric_limits<double>::max();
491  double myMax = -1 * std::numeric_limits<double>::max();
492  double myValue = 0.0;
493  for ( int myRow = 0; myRow < mLastViewPort.drawableAreaYDim; ++myRow )
494  {
495  for ( int myColumn = 0; myColumn < mLastViewPort.drawableAreaXDim; ++myColumn )
496  {
497  myValue = readValue( myScanData, myDataType, myRow * mLastViewPort.drawableAreaXDim + myColumn );
498  if ( mValidNoDataValue && ( qAbs( myValue - mNoDataValue ) <= TINY_VALUE || myValue != myValue ) )
499  {
500  continue;
501  }
502  myMin = qMin( myMin, myValue );
503  myMax = qMax( myMax, myValue );
504  }
505  }
506  theMinMax[0] = myMin;
507  theMinMax[1] = myMax;
508  }
509 }
510 
515 void QgsRasterLayer::computeMinimumMaximumFromLastExtent( QString theBand, double* theMinMax )
516 {
517  computeMinimumMaximumFromLastExtent( bandNumber( theBand ), theMinMax );
518 }
519 
520 void QgsRasterLayer::computeMinimumMaximumFromLastExtent( int theBand, double& theMin, double& theMax )
521 {
522  double theMinMax[2];
523  computeMinimumMaximumFromLastExtent( theBand, theMinMax );
524  theMin = theMinMax[0];
525  theMax = theMinMax[1];
526 }
527 
533 {
534  if ( 0 < theBand && theBand <= bandCount() )
535  {
536  return &mContrastEnhancementList[theBand - 1];
537  }
538 
539  return 0;
540 }
541 
543 {
545  {
547  return QString( "NoEnhancement" );
548  break;
550  return QString( "StretchToMinimumMaximum" );
551  break;
553  return QString( "StretchAndClipToMinimumMaximum" );
554  break;
556  return QString( "ClipToMinimumMaximum" );
557  break;
559  return QString( "UserDefined" );
560  break;
561  }
562 
563  return QString( "NoEnhancement" );
564 }
565 
571 {
572  //preventwarnings
573  if ( theOther.type() < 0 )
574  {
575  return false;
576  }
577  return false;
578 } //todo
579 
584 QList<QgsColorRampShader::ColorRampItem>* QgsRasterLayer::colorTable( int theBandNo )
585 {
586  return &( mRasterStatsList[theBandNo-1].colorTable );
587 }
588 
593 {
594  return mDataProvider;
595 }
596 
601 {
602  return mDataProvider;
603 }
604 
606 {
607  if ( mDataProvider )
608  {
610  }
611 }
612 
613 bool QgsRasterLayer::draw( QgsRenderContext& rendererContext )
614 {
615  QgsDebugMsg( "entered. (renderContext)" );
616 
617  // Don't waste time drawing if transparency is at 0 (completely transparent)
618  if ( mTransparencyLevel == 0 )
619  return true;
620 
621  QgsDebugMsg( "checking timestamp." );
622 
623  // Check timestamp
624  if ( !update() )
625  {
626  return false;
627  }
628 
629  const QgsMapToPixel& theQgsMapToPixel = rendererContext.mapToPixel();
630 
631  QgsRectangle myProjectedViewExtent;
632  QgsRectangle myProjectedLayerExtent;
633 
634  if ( rendererContext.coordinateTransform() )
635  {
636  QgsDebugMsg( "coordinateTransform set -> project extents." );
637  myProjectedViewExtent = rendererContext.coordinateTransform()->transformBoundingBox(
638  rendererContext.extent() );
639  myProjectedLayerExtent = rendererContext.coordinateTransform()->transformBoundingBox(
640  mLayerExtent );
641  }
642  else
643  {
644  QgsDebugMsg( "coordinateTransform not set" );
645  myProjectedViewExtent = rendererContext.extent();
646  myProjectedLayerExtent = mLayerExtent;
647  }
648 
649  QPainter* theQPainter = rendererContext.painter();
650 
651  if ( !theQPainter )
652  {
653  return false;
654  }
655 
656  // clip raster extent to view extent
657  //QgsRectangle myRasterExtent = theViewExtent.intersect( &mLayerExtent );
658  QgsRectangle myRasterExtent = myProjectedViewExtent.intersect( &myProjectedLayerExtent );
659  if ( myRasterExtent.isEmpty() )
660  {
661  QgsDebugMsg( "draw request outside view extent." );
662  // nothing to do
663  return true;
664  }
665 
666  QgsDebugMsg( "theViewExtent is " + rendererContext.extent().toString() );
667  QgsDebugMsg( "myProjectedViewExtent is " + myProjectedViewExtent.toString() );
668  QgsDebugMsg( "myProjectedLayerExtent is " + myProjectedLayerExtent.toString() );
669  QgsDebugMsg( "myRasterExtent is " + myRasterExtent.toString() );
670 
671  //
672  // The first thing we do is set up the QgsRasterViewPort. This struct stores all the settings
673  // relating to the size (in pixels and coordinate system units) of the raster part that is
674  // in view in the map window. It also stores the origin.
675  //
676  //this is not a class level member because every time the user pans or zooms
677  //the contents of the rasterViewPort will change
678  QgsRasterViewPort *myRasterViewPort = new QgsRasterViewPort();
679 
680  myRasterViewPort->mDrawnExtent = myRasterExtent;
681  if ( rendererContext.coordinateTransform() )
682  {
683  myRasterViewPort->mSrcCRS = crs();
684  myRasterViewPort->mDestCRS = rendererContext.coordinateTransform()->destCRS();
685  }
686  else
687  {
688  myRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid
689  myRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid
690  }
691 
692  // get dimensions of clipped raster image in device coordinate space (this is the size of the viewport)
693  myRasterViewPort->topLeftPoint = theQgsMapToPixel.transform( myRasterExtent.xMinimum(), myRasterExtent.yMaximum() );
694  myRasterViewPort->bottomRightPoint = theQgsMapToPixel.transform( myRasterExtent.xMaximum(), myRasterExtent.yMinimum() );
695 
696  // align to output device grid, i.e. floor/ceil to integers
697  // TODO: this should only be done if paint device is raster - screen, image
698  // for other devices (pdf) it can have floating point origin
699  // we could use floating point for raster devices as well, but respecting the
700  // output device grid should make it more effective as the resampling is done in
701  // the provider anyway
702  if ( true )
703  {
704  myRasterViewPort->topLeftPoint.setX( floor( myRasterViewPort->topLeftPoint.x() ) );
705  myRasterViewPort->topLeftPoint.setY( floor( myRasterViewPort->topLeftPoint.y() ) );
706  myRasterViewPort->bottomRightPoint.setX( ceil( myRasterViewPort->bottomRightPoint.x() ) );
707  myRasterViewPort->bottomRightPoint.setY( ceil( myRasterViewPort->bottomRightPoint.y() ) );
708  // recalc myRasterExtent to aligned values
709  myRasterExtent.set(
710  theQgsMapToPixel.toMapCoordinatesF( myRasterViewPort->topLeftPoint.x(),
711  myRasterViewPort->bottomRightPoint.y() ),
712  theQgsMapToPixel.toMapCoordinatesF( myRasterViewPort->bottomRightPoint.x(),
713  myRasterViewPort->topLeftPoint.y() )
714  );
715 
716  }
717 
718  myRasterViewPort->drawableAreaXDim = static_cast<int>( qAbs(( myRasterExtent.width() / theQgsMapToPixel.mapUnitsPerPixel() ) ) );
719  myRasterViewPort->drawableAreaYDim = static_cast<int>( qAbs(( myRasterExtent.height() / theQgsMapToPixel.mapUnitsPerPixel() ) ) );
720 
721  //the drawable area can start to get very very large when you get down displaying 2x2 or smaller, this is becasue
722  //theQgsMapToPixel.mapUnitsPerPixel() is less then 1,
723  //so we will just get the pixel data and then render these special cases differently in paintImageToCanvas()
724 #if 0
725  if ( 2 >= myRasterViewPort->clippedWidth && 2 >= myRasterViewPort->clippedHeight )
726  {
727  myRasterViewPort->drawableAreaXDim = myRasterViewPort->clippedWidth;
728  myRasterViewPort->drawableAreaYDim = myRasterViewPort->clippedHeight;
729  }
730 #endif
731 
732  QgsDebugMsgLevel( QString( "mapUnitsPerPixel = %1" ).arg( theQgsMapToPixel.mapUnitsPerPixel() ), 3 );
733  QgsDebugMsgLevel( QString( "mWidth = %1" ).arg( mWidth ), 3 );
734  QgsDebugMsgLevel( QString( "mHeight = %1" ).arg( mHeight ), 3 );
735  QgsDebugMsgLevel( QString( "myRasterExtent.xMinimum() = %1" ).arg( myRasterExtent.xMinimum() ), 3 );
736  QgsDebugMsgLevel( QString( "myRasterExtent.xMaximum() = %1" ).arg( myRasterExtent.xMaximum() ), 3 );
737  QgsDebugMsgLevel( QString( "myRasterExtent.yMinimum() = %1" ).arg( myRasterExtent.yMinimum() ), 3 );
738  QgsDebugMsgLevel( QString( "myRasterExtent.yMaximum() = %1" ).arg( myRasterExtent.yMaximum() ), 3 );
739 
740  QgsDebugMsgLevel( QString( "topLeftPoint.x() = %1" ).arg( myRasterViewPort->topLeftPoint.x() ), 3 );
741  QgsDebugMsgLevel( QString( "bottomRightPoint.x() = %1" ).arg( myRasterViewPort->bottomRightPoint.x() ), 3 );
742  QgsDebugMsgLevel( QString( "topLeftPoint.y() = %1" ).arg( myRasterViewPort->topLeftPoint.y() ), 3 );
743  QgsDebugMsgLevel( QString( "bottomRightPoint.y() = %1" ).arg( myRasterViewPort->bottomRightPoint.y() ), 3 );
744 
745  QgsDebugMsgLevel( QString( "drawableAreaXDim = %1" ).arg( myRasterViewPort->drawableAreaXDim ), 3 );
746  QgsDebugMsgLevel( QString( "drawableAreaYDim = %1" ).arg( myRasterViewPort->drawableAreaYDim ), 3 );
747 
748  QgsDebugMsgLevel( "ReadXml: gray band name : " + mGrayBandName, 3 );
749  QgsDebugMsgLevel( "ReadXml: red band name : " + mRedBandName, 3 );
750  QgsDebugMsgLevel( "ReadXml: green band name : " + mGreenBandName, 3 );
751  QgsDebugMsgLevel( "ReadXml: blue band name : " + mBlueBandName, 3 );
752 
753  // /\/\/\ - added to handle zoomed-in rasters
754 
755  mLastViewPort = *myRasterViewPort;
756 
757  // Provider mode: See if a provider key is specified, and if so use the provider instead
758 
759  mDataProvider->setDpi( rendererContext.rasterScaleFactor() * 25.4 * rendererContext.scaleFactor() );
760 
761  draw( theQPainter, myRasterViewPort, &theQgsMapToPixel );
762 
763  delete myRasterViewPort;
764  QgsDebugMsg( "exiting." );
765 
766  return true;
767 
768 }
769 
770 void QgsRasterLayer::draw( QPainter * theQPainter,
771  QgsRasterViewPort * theRasterViewPort,
772  const QgsMapToPixel* theQgsMapToPixel )
773 {
774  QgsDebugMsg( " 3 arguments" );
775  QTime time;
776  time.start();
777  //
778  //
779  // The goal here is to make as many decisions as possible early on (outside of the rendering loop)
780  // so that we can maximise performance of the rendering process. So now we check which drawing
781  // procedure to use :
782  //
783 
784  QgsDebugMsg( "mDrawingStyle = " + QString::number( mDrawingStyle ) );
785  switch ( mDrawingStyle )
786  {
787  // a "Gray" or "Undefined" layer drawn as a range of gray colors
788  case SingleBandGray:
789  //check the band is set!
791  {
792  break;
793  }
794  else
795  {
796  drawSingleBandGray( theQPainter, theRasterViewPort,
797  theQgsMapToPixel, bandNumber( mGrayBandName ) );
798  break;
799  }
800  // a "Gray" or "Undefined" layer drawn using a pseudocolor algorithm
802  //check the band is set!
804  {
805  break;
806  }
807  else
808  {
809  drawSingleBandPseudoColor( theQPainter, theRasterViewPort,
810  theQgsMapToPixel, bandNumber( mGrayBandName ) );
811  break;
812  }
813  // a single band with a color map
814  case PalettedColor:
815  //check the band is set!
817  {
818  break;
819  }
820  else
821  {
822  QgsDebugMsg( "PalettedColor drawing type detected..." );
823 
824  drawPalettedSingleBandColor( theQPainter, theRasterViewPort,
825  theQgsMapToPixel, bandNumber( mGrayBandName ) );
826  break;
827  }
828  // a "Palette" layer drawn in gray scale (using only one of the color components)
830  //check the band is set!
832  {
833  break;
834  }
835  else
836  {
837  QgsDebugMsg( "PalettedSingleBandGray drawing type detected..." );
838 
839  int myBandNo = 1;
840  drawPalettedSingleBandGray( theQPainter, theRasterViewPort,
841  theQgsMapToPixel, myBandNo );
842 
843  break;
844  }
845  // a "Palette" layer having only one of its color components rendered as psuedo color
847  //check the band is set!
849  {
850  break;
851  }
852  else
853  {
854 
855  int myBandNo = 1;
856  drawPalettedSingleBandPseudoColor( theQPainter, theRasterViewPort,
857  theQgsMapToPixel, myBandNo );
858  break;
859  }
860  //a "Palette" image where the bands contains 24bit color info and 8 bits is pulled out per color
862  drawPalettedMultiBandColor( theQPainter, theRasterViewPort,
863  theQgsMapToPixel, 1 );
864  break;
865  // a layer containing 2 or more bands, but using only one band to produce a grayscale image
867  QgsDebugMsg( "MultiBandSingleBandGray drawing type detected..." );
868  //check the band is set!
870  {
871  QgsDebugMsg( "MultiBandSingleBandGray Not Set detected..." + mGrayBandName );
872  break;
873  }
874  else
875  {
876 
877  //get the band number for the mapped gray band
878  drawMultiBandSingleBandGray( theQPainter, theRasterViewPort,
879  theQgsMapToPixel, bandNumber( mGrayBandName ) );
880  break;
881  }
882  //a layer containing 2 or more bands, but using only one band to produce a pseudocolor image
884  //check the band is set!
886  {
887  break;
888  }
889  else
890  {
891 
892  drawMultiBandSingleBandPseudoColor( theQPainter, theRasterViewPort,
893  theQgsMapToPixel, bandNumber( mGrayBandName ) );
894  break;
895  }
896  //a layer containing 2 or more bands, mapped to the three RGBcolors.
897  //In the case of a multiband with only two bands,
898  //one band will have to be mapped to more than one color
899  case MultiBandColor:
900  if ( mRedBandName == TRSTRING_NOT_SET ||
903  {
904  break;
905  }
906  else
907  {
908  drawMultiBandColor( theQPainter, theRasterViewPort,
909  theQgsMapToPixel );
910  }
911  break;
913  //check the band is set!
915  {
916  break;
917  }
918  else
919  {
920  drawSingleBandColorData( theQPainter, theRasterViewPort,
921  theQgsMapToPixel, bandNumber( mGrayBandName ) );
922  break;
923  }
924 
925  default:
926  break;
927 
928  }
929  QgsDebugMsg( QString( "raster draw time (ms): %1" ).arg( time.elapsed() ) );
930 } //end of draw method
931 
933 {
934  switch ( mDrawingStyle )
935  {
936  case SingleBandGray:
937  return QString( "SingleBandGray" ); //no need to tr() this its not shown in ui
938  break;
940  return QString( "SingleBandPseudoColor" );//no need to tr() this its not shown in ui
941  break;
942  case PalettedColor:
943  return QString( "PalettedColor" );//no need to tr() this its not shown in ui
944  break;
946  return QString( "PalettedSingleBandGray" );//no need to tr() this its not shown in ui
947  break;
949  return QString( "PalettedSingleBandPseudoColor" );//no need to tr() this its not shown in ui
950  break;
952  return QString( "PalettedMultiBandColor" );//no need to tr() this its not shown in ui
953  break;
955  return QString( "MultiBandSingleBandGray" );//no need to tr() this its not shown in ui
956  break;
958  return QString( "MultiBandSingleBandPseudoColor" );//no need to tr() this its not shown in ui
959  break;
960  case MultiBandColor:
961  return QString( "MultiBandColor" );//no need to tr() this its not shown in ui
962  break;
964  return QString( "SingleBandColorDataStyle" );//no need to tr() this its not shown in ui
965  break;
966  default:
967  break;
968  }
969 
970  return QString( "UndefinedDrawingStyle" );
971 
972 }
973 
979 {
980  //preventwarnings
981  if ( theOther.type() < 0 )
982  {
983  return false;
984  }
985  return false;
986 } //todo
987 
992 bool QgsRasterLayer::hasStatistics( int theBandNo )
993 {
994  if ( theBandNo <= mRasterStatsList.size() && theBandNo > 0 )
995  {
996  //vector starts at base 0, band counts at base1!
997  return mRasterStatsList[theBandNo - 1].statsGathered;
998  }
999  else
1000  {
1001  return false;
1002  }
1003 }
1004 
1010 bool QgsRasterLayer::identify( const QgsPoint& thePoint, QMap<QString, QString>& theResults )
1011 {
1012  theResults.clear();
1013 
1014  QgsDebugMsg( "identify provider : " + mProviderKey ) ;
1015  return ( mDataProvider->identify( thePoint, theResults ) );
1016 }
1017 
1024 QString QgsRasterLayer::identifyAsText( const QgsPoint& thePoint )
1025 {
1026  if ( mProviderKey != "wms" )
1027  {
1028  // Currently no meaning for anything other than OGC WMS layers
1029  return QString();
1030  }
1031 
1032  return mDataProvider->identifyAsText( thePoint );
1033 }
1034 
1041 QString QgsRasterLayer::identifyAsHtml( const QgsPoint& thePoint )
1042 {
1043  if ( mProviderKey != "wms" )
1044  {
1045  // Currently no meaning for anything other than OGC WMS layers
1046  return QString();
1047  }
1048 
1049  return mDataProvider->identifyAsHtml( thePoint );
1050 }
1051 
1057 {
1058  return false;
1059 }
1060 
1062 {
1063  return mError;
1064 }
1065 
1067 {
1068  return mErrorCaption;
1069 }
1070 
1076 {
1077  return legendAsPixmap( false );
1078 }
1079 
1084 QPixmap QgsRasterLayer::legendAsPixmap( bool theWithNameFlag )
1085 {
1086  QgsDebugMsg( "called (" + drawingStyleAsString() + ")" );
1087 
1088  QPixmap myLegendQPixmap; //will be initialised once we know what drawing style is active
1089  QPainter myQPainter;
1090 
1091 
1092  if ( !mProviderKey.isEmpty() )
1093  {
1094  QgsDebugMsg( "provider Key (" + mProviderKey + ")" );
1095  myLegendQPixmap = QPixmap( 3, 1 );
1096  myQPainter.begin( &myLegendQPixmap );
1097  //draw legend red part
1098  myQPainter.setPen( QPen( QColor( 255, 0, 0 ), 0 ) );
1099  myQPainter.drawPoint( 0, 0 );
1100  //draw legend green part
1101  myQPainter.setPen( QPen( QColor( 0, 255, 0 ), 0 ) );
1102  myQPainter.drawPoint( 1, 0 );
1103  //draw legend blue part
1104  myQPainter.setPen( QPen( QColor( 0, 0, 255 ), 0 ) );
1105  myQPainter.drawPoint( 2, 0 );
1106 
1107  }
1108  else
1109  {
1110  // Legacy GDAL (non-provider)
1111 
1112  //
1113  // Get the adjusted matrix stats
1114  //
1115  QString myColorerpretation = mDataProvider->colorInterpretationName( 1 );
1116 
1117  //
1118  // Create the legend pixmap - note it is generated on the preadjusted stats
1119  //
1121  {
1122 
1123  myLegendQPixmap = QPixmap( 100, 1 );
1124  myQPainter.begin( &myLegendQPixmap );
1125  int myPos = 0;
1126  for ( double my = 0; my < 255; my += 2.55 )
1127  {
1128  if ( !mInvertColor ) //histogram is not inverted
1129  {
1130  //draw legend as grayscale
1131  int myGray = static_cast < int >( my );
1132  myQPainter.setPen( QPen( QColor( myGray, myGray, myGray ), 0 ) );
1133  }
1134  else //histogram is inverted
1135  {
1136  //draw legend as inverted grayscale
1137  int myGray = 255 - static_cast < int >( my );
1138  myQPainter.setPen( QPen( QColor( myGray, myGray, myGray ), 0 ) );
1139  } //end of invert histogram check
1140  myQPainter.drawPoint( myPos++, 0 );
1141  }
1142  } //end of gray check
1145  {
1146 
1147  //set up the three class breaks for pseudocolor mapping
1148  double myRangeSize = 90; //hard coded for now
1149  double myBreakSize = myRangeSize / 3;
1150  double myClassBreakMin1 = 0;
1151  double myClassBreakMax1 = myClassBreakMin1 + myBreakSize;
1152  double myClassBreakMin2 = myClassBreakMax1;
1153  double myClassBreakMax2 = myClassBreakMin2 + myBreakSize;
1154  double myClassBreakMin3 = myClassBreakMax2;
1155 
1156  //
1157  // Create the legend pixmap - note it is generated on the preadjusted stats
1158  //
1159  myLegendQPixmap = QPixmap( 100, 1 );
1160  myQPainter.begin( &myLegendQPixmap );
1161  int myPos = 0;
1162  for ( double my = 0; my < myRangeSize; my += myRangeSize / 100.0 )
1163  {
1164  //draw pseudocolor legend
1165  if ( !mInvertColor )
1166  {
1167  //check if we are in the first class break
1168  if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) )
1169  {
1170  int myRed = 0;
1171  int myBlue = 255;
1172  int myGreen = static_cast < int >((( 255 / myRangeSize ) * ( my - myClassBreakMin1 ) ) * 3 );
1173  // testing this stuff still ...
1175  {
1176  myRed = 255 - myGreen;
1177  }
1178  myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
1179  }
1180  //check if we are in the second class break
1181  else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) )
1182  {
1183  int myRed = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 );
1184  int myBlue = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ) );
1185  int myGreen = 255;
1186  // testing this stuff still ...
1188  {
1189  myGreen = myBlue;
1190  }
1191  myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
1192  }
1193  //otherwise we must be in the third classbreak
1194  else
1195  {
1196  int myRed = 255;
1197  int myBlue = 0;
1198  int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin3 ) / 1 ) * 3 ) ) );
1199  // testing this stuff still ...
1201  {
1202  myRed = myGreen;
1203  myGreen = 255 - myGreen;
1204  }
1205  myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
1206  }
1207  } //end of invert !histogram false check
1208  else //invert histogram toggle is off
1209  {
1210  //check if we are in the first class break
1211  if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) )
1212  {
1213  int myRed = 255;
1214  int myBlue = 0;
1215  int myGreen = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin1 ) / 1 ) * 3 ) );
1216  // testing this stuff still ...
1218  {
1219  myRed = 255 - myGreen;
1220  }
1221  myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
1222  }
1223  //check if we are in the second class break
1224  else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) )
1225  {
1226  int myRed = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ) );
1227  int myBlue = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 );
1228  int myGreen = 255;
1229  // testing this stuff still ...
1231  {
1232  myGreen = myBlue;
1233  }
1234  myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
1235  }
1236  //otherwise we must be in the third classbreak
1237  else
1238  {
1239  int myRed = 0;
1240  int myBlue = 255;
1241  int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * ( my - myClassBreakMin3 ) ) * 3 ) );
1242  // testing this stuff still ...
1244  {
1245  myRed = 255 - myGreen;
1246  }
1247  myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
1248  }
1249 
1250  } //end of invert histogram check
1251  myQPainter.drawPoint( myPos++, 0 );
1252  }
1253 
1254  } //end of pseudocolor check
1256  {
1257  //
1258  // Create the legend pixmap showing red green and blue band mappings
1259  //
1260  // TODO update this so it actually shows the mappings for paletted images
1261  myLegendQPixmap = QPixmap( 3, 1 );
1262  myQPainter.begin( &myLegendQPixmap );
1263  //draw legend red part
1264  myQPainter.setPen( QPen( QColor( 224, 103, 103 ), 0 ) );
1265  myQPainter.drawPoint( 0, 0 );
1266  //draw legend green part
1267  myQPainter.setPen( QPen( QColor( 132, 224, 127 ), 0 ) );
1268  myQPainter.drawPoint( 1, 0 );
1269  //draw legend blue part
1270  myQPainter.setPen( QPen( QColor( 127, 160, 224 ), 0 ) );
1271  myQPainter.drawPoint( 2, 0 );
1272  }
1273  }
1274 
1275  myQPainter.end();
1276 
1277 
1278  // see if the caller wants the name of the layer in the pixmap (used for legend bar)
1279  if ( theWithNameFlag )
1280  {
1281  QFont myQFont( "arial", 10, QFont::Normal );
1282  QFontMetrics myQFontMetrics( myQFont );
1283 
1284  int myHeight = ( myQFontMetrics.height() + 10 > 35 ) ? myQFontMetrics.height() + 10 : 35;
1285 
1286  //create a matrix to
1287  QMatrix myQWMatrix;
1288  //scale the raster legend up a bit bigger to the legend item size
1289  //note that scaling parameters are factors, not absolute values,
1290  // so scale (0.25,1) scales the painter to a quarter of its size in the x direction
1291  //TODO We need to decide how much to scale by later especially for rgb images which are only 3x1 pix
1292  //hard coding thes values for now.
1293  if ( myLegendQPixmap.width() == 3 )
1294  {
1295  //scale width by factor of 50 (=150px wide)
1296  myQWMatrix.scale( 60, myHeight );
1297  }
1298  else
1299  {
1300  //assume 100px so scale by factor of 1.5 (=150px wide)
1301  myQWMatrix.scale( 1.8, myHeight );
1302  }
1303  //apply the matrix
1304  QPixmap myQPixmap2 = myLegendQPixmap.transformed( myQWMatrix );
1305  QPainter myQPainter( &myQPixmap2 );
1306 
1307  //load up the pyramid icons
1308  QString myThemePath = QgsApplication::activeThemePath();
1309  QPixmap myPyramidPixmap( myThemePath + "/mIconPyramid.png" );
1310  QPixmap myNoPyramidPixmap( myThemePath + "/mIconNoPyramid.png" );
1311 
1312  //
1313  // Overlay a pyramid icon
1314  //
1315  if ( mHasPyramids )
1316  {
1317  myQPainter.drawPixmap( 0, myHeight - myPyramidPixmap.height(), myPyramidPixmap );
1318  }
1319  else
1320  {
1321  myQPainter.drawPixmap( 0, myHeight - myNoPyramidPixmap.height(), myNoPyramidPixmap );
1322  }
1323  //
1324  // Overlay the layer name
1325  //
1327  {
1328  myQPainter.setPen( Qt::white );
1329  }
1330  else
1331  {
1332  myQPainter.setPen( Qt::black );
1333  }
1334  myQPainter.setFont( myQFont );
1335  myQPainter.drawText( 25, myHeight - 10, name() );
1336  //
1337  // finish up
1338  //
1339  myLegendQPixmap = myQPixmap2;
1340  myQPainter.end();
1341  }
1342  //finish up
1343 
1344  return myLegendQPixmap;
1345 
1346 } //end of legendAsPixmap function
1347 
1352 QPixmap QgsRasterLayer::legendAsPixmap( int theLabelCount )
1353 {
1354  QgsDebugMsg( "entered." );
1355  QFont myQFont( "arial", 10, QFont::Normal );
1356  QFontMetrics myQFontMetrics( myQFont );
1357 
1358  int myFontHeight = ( myQFontMetrics.height() );
1359  const int myerLabelSpacing = 5;
1360  int myImageHeight = (( myFontHeight + ( myerLabelSpacing * 2 ) ) * theLabelCount );
1361  //these next two vars are not used anywhere so commented out for now
1362  //int myLongestLabelWidth = myQFontMetrics.width(name());
1363  //const int myHorizontalLabelSpacing = 5;
1364  const int myColorBarWidth = 10;
1365  //
1366  // Get the adjusted matrix stats
1367  //
1368  QString myColorerpretation = mDataProvider->colorInterpretationName( 1 );
1369  QPixmap myLegendQPixmap; //will be initialised once we know what drawing style is active
1370  QPainter myQPainter;
1371  //
1372  // Create the legend pixmap - note it is generated on the preadjusted stats
1373  //
1375  {
1376 
1377  myLegendQPixmap = QPixmap( 1, myImageHeight );
1378  const double myIncrement = static_cast<double>( myImageHeight ) / 255.0;
1379  myQPainter.begin( &myLegendQPixmap );
1380  int myPos = 0;
1381  for ( double my = 0; my < 255; my += myIncrement )
1382  {
1383  if ( !mInvertColor ) //histogram is not inverted
1384  {
1385  //draw legend as grayscale
1386  int myGray = static_cast < int >( my );
1387  myQPainter.setPen( QPen( QColor( myGray, myGray, myGray ), 0 ) );
1388  }
1389  else //histogram is inverted
1390  {
1391  //draw legend as inverted grayscale
1392  int myGray = 255 - static_cast < int >( my );
1393  myQPainter.setPen( QPen( QColor( myGray, myGray, myGray ), 0 ) );
1394  } //end of invert histogram check
1395  myQPainter.drawPoint( 0, myPos++ );
1396  }
1397  } //end of gray check
1400  {
1401 
1402  //set up the three class breaks for pseudocolor mapping
1403  double myRangeSize = 90; //hard coded for now
1404  double myBreakSize = myRangeSize / 3;
1405  double myClassBreakMin1 = 0;
1406  double myClassBreakMax1 = myClassBreakMin1 + myBreakSize;
1407  double myClassBreakMin2 = myClassBreakMax1;
1408  double myClassBreakMax2 = myClassBreakMin2 + myBreakSize;
1409  double myClassBreakMin3 = myClassBreakMax2;
1410 
1411  //
1412  // Create the legend pixmap - note it is generated on the preadjusted stats
1413  //
1414  myLegendQPixmap = QPixmap( 1, myImageHeight );
1415  const double myIncrement = myImageHeight / myRangeSize;
1416  myQPainter.begin( &myLegendQPixmap );
1417  int myPos = 0;
1418  for ( double my = 0; my < 255; my += myIncrement )
1419  for ( double my = 0; my < myRangeSize; my += myIncrement )
1420  {
1421  //draw pseudocolor legend
1422  if ( !mInvertColor )
1423  {
1424  //check if we are in the first class break
1425  if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) )
1426  {
1427  int myRed = 0;
1428  int myBlue = 255;
1429  int myGreen = static_cast < int >((( 255 / myRangeSize ) * ( my - myClassBreakMin1 ) ) * 3 );
1430  // testing this stuff still ...
1432  {
1433  myRed = 255 - myGreen;
1434  }
1435  myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
1436  }
1437  //check if we are in the second class break
1438  else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) )
1439  {
1440  int myRed = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 );
1441  int myBlue = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ) );
1442  int myGreen = 255;
1443  // testing this stuff still ...
1445  {
1446  myGreen = myBlue;
1447  }
1448  myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
1449  }
1450  //otherwise we must be in the third classbreak
1451  else
1452  {
1453  int myRed = 255;
1454  int myBlue = 0;
1455  int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin3 ) / 1 ) * 3 ) ) );
1456  // testing this stuff still ...
1458  {
1459  myRed = myGreen;
1460  myGreen = 255 - myGreen;
1461  }
1462  myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
1463  }
1464  } //end of invert !histogram check
1465  else //invert histogram toggle is off
1466  {
1467  //check if we are in the first class break
1468  if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) )
1469  {
1470  int myRed = 255;
1471  int myBlue = 0;
1472  int myGreen = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin1 ) / 1 ) * 3 ) );
1473  // testing this stuff still ...
1475  {
1476  myRed = 255 - myGreen;
1477  }
1478  myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
1479  }
1480  //check if we are in the second class break
1481  else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) )
1482  {
1483  int myRed = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ) );
1484  int myBlue = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 );
1485  int myGreen = 255;
1486  // testing this stuff still ...
1488  {
1489  myGreen = myBlue;
1490  }
1491  myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
1492  }
1493  //otherwise we must be in the third classbreak
1494  else
1495  {
1496  int myRed = 0;
1497  int myBlue = 255;
1498  int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * ( my - myClassBreakMin3 ) ) * 3 ) );
1499  // testing this stuff still ...
1501  {
1502  myRed = 255 - myGreen;
1503  }
1504  myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
1505  }
1506 
1507  } //end of invert histogram check
1508  myQPainter.drawPoint( 0, myPos++ );
1509  }
1510 
1511  } //end of pseudocolor check
1513  {
1514  //
1515  // Create the legend pixmap showing red green and blue band mappings
1516  //
1517  // TODO update this so it actually shows the mappings for paletted images
1518  myLegendQPixmap = QPixmap( 1, 3 );
1519  myQPainter.begin( &myLegendQPixmap );
1520  //draw legend red part
1521  myQPainter.setPen( QPen( QColor( 224, 103, 103 ), 0 ) );
1522  myQPainter.drawPoint( 0, 0 );
1523  //draw legend green part
1524  myQPainter.setPen( QPen( QColor( 132, 224, 127 ), 0 ) );
1525  myQPainter.drawPoint( 0, 1 );
1526  //draw legend blue part
1527  myQPainter.setPen( QPen( QColor( 127, 160, 224 ), 0 ) );
1528  myQPainter.drawPoint( 0, 2 );
1529  }
1530 
1531 
1532  myQPainter.end();
1533 
1534 
1535 
1536  //create a matrix to
1537  QMatrix myQWMatrix;
1538  //scale the raster legend up a bit bigger to the legend item size
1539  //note that scaling parameters are factors, not absolute values,
1540  // so scale (0.25,1) scales the painter to a quarter of its size in the x direction
1541  //TODO We need to decide how much to scale by later especially for rgb images which are only 3x1 pix
1542  //hard coding thes values for now.
1543  if ( myLegendQPixmap.height() == 3 )
1544  {
1545  myQWMatrix.scale( myColorBarWidth, 2 );
1546  }
1547  else
1548  {
1549  myQWMatrix.scale( myColorBarWidth, 2 );
1550  }
1551  //apply the matrix
1552  QPixmap myQPixmap2 = myLegendQPixmap.transformed( myQWMatrix );
1553  QPainter myQPainter2( &myQPixmap2 );
1554  //
1555  // Overlay the layer name
1556  //
1558  {
1559  myQPainter2.setPen( Qt::white );
1560  }
1561  else
1562  {
1563  myQPainter2.setPen( Qt::black );
1564  }
1565  myQPainter2.setFont( myQFont );
1566  myQPainter2.drawText( 25, myImageHeight - 10, name() );
1567  //
1568  // finish up
1569  //
1570  myLegendQPixmap = myQPixmap2;
1571  myQPainter2.end();
1572  //finish up
1573 
1574  return myLegendQPixmap;
1575 
1576 }//end of getDetailedLegend
1577 
1582 double QgsRasterLayer::maximumValue( unsigned int theBand )
1583 {
1584  if ( 0 < theBand && theBand <= bandCount() )
1585  {
1586  return mContrastEnhancementList[theBand - 1].maximumValue();
1587  }
1588 
1589  return 0.0;
1590 }
1591 
1596 double QgsRasterLayer::maximumValue( QString theBand )
1597 {
1598  if ( theBand != tr( "Not Set" ) )
1599  {
1600  return maximumValue( bandNumber( theBand ) );
1601  }
1602 
1603  return 0.0;
1604 }
1605 
1606 
1608 {
1609  QString myMetadata ;
1610  myMetadata += "<p class=\"glossy\">" + tr( "Driver:" ) + "</p>\n";
1611  myMetadata += "<p>";
1612  myMetadata += mDataProvider->description();
1613  myMetadata += "</p>\n";
1614 
1615  // Insert provider-specific (e.g. WMS-specific) metadata
1616  // crashing
1617  //QString s = mDataProvider->metadata();
1618  //QgsDebugMsg( s );
1619  myMetadata += mDataProvider->metadata();
1620 
1621  myMetadata += "<p class=\"glossy\">";
1622  myMetadata += tr( "No Data Value" );
1623  myMetadata += "</p>\n";
1624  myMetadata += "<p>";
1625  if ( mValidNoDataValue )
1626  {
1627  myMetadata += QString::number( mNoDataValue );
1628  }
1629  else
1630  {
1631  myMetadata += "*" + tr( "NoDataValue not set" ) + "*";
1632  }
1633  myMetadata += "</p>\n";
1634 
1635  myMetadata += "</p>\n";
1636  myMetadata += "<p class=\"glossy\">";
1637  myMetadata += tr( "Data Type:" );
1638  myMetadata += "</p>\n";
1639  myMetadata += "<p>";
1640  //just use the first band
1641  switch ( mDataProvider->dataType( 1 ) )
1642  {
1643  case GDT_Byte:
1644  myMetadata += tr( "GDT_Byte - Eight bit unsigned integer" );
1645  break;
1646  case GDT_UInt16:
1647  myMetadata += tr( "GDT_UInt16 - Sixteen bit unsigned integer " );
1648  break;
1649  case GDT_Int16:
1650  myMetadata += tr( "GDT_Int16 - Sixteen bit signed integer " );
1651  break;
1652  case GDT_UInt32:
1653  myMetadata += tr( "GDT_UInt32 - Thirty two bit unsigned integer " );
1654  break;
1655  case GDT_Int32:
1656  myMetadata += tr( "GDT_Int32 - Thirty two bit signed integer " );
1657  break;
1658  case GDT_Float32:
1659  myMetadata += tr( "GDT_Float32 - Thirty two bit floating point " );
1660  break;
1661  case GDT_Float64:
1662  myMetadata += tr( "GDT_Float64 - Sixty four bit floating point " );
1663  break;
1664  case GDT_CInt16:
1665  myMetadata += tr( "GDT_CInt16 - Complex Int16 " );
1666  break;
1667  case GDT_CInt32:
1668  myMetadata += tr( "GDT_CInt32 - Complex Int32 " );
1669  break;
1670  case GDT_CFloat32:
1671  myMetadata += tr( "GDT_CFloat32 - Complex Float32 " );
1672  break;
1673  case GDT_CFloat64:
1674  myMetadata += tr( "GDT_CFloat64 - Complex Float64 " );
1675  break;
1676  default:
1677  myMetadata += tr( "Could not determine raster data type." );
1678  }
1679  myMetadata += "</p>\n";
1680 
1681  myMetadata += "<p class=\"glossy\">";
1682  myMetadata += tr( "Pyramid overviews:" );
1683  myMetadata += "</p>\n";
1684  myMetadata += "<p>";
1685 
1686  myMetadata += "<p class=\"glossy\">";
1687  myMetadata += tr( "Layer Spatial Reference System: " );
1688  myMetadata += "</p>\n";
1689  myMetadata += "<p>";
1690  myMetadata += mCRS->toProj4();
1691  myMetadata += "</p>\n";
1692 
1693  myMetadata += "<p class=\"glossy\">";
1694  myMetadata += tr( "Layer Extent (layer original source projection): " );
1695  myMetadata += "</p>\n";
1696  myMetadata += "<p>";
1697  myMetadata += mDataProvider->extent().toString();
1698  myMetadata += "</p>\n";
1699 
1700  // output coordinate system
1701  // TODO: this is not related to layer, to be removed? [MD]
1702 #if 0
1703  myMetadata += "<tr><td class=\"glossy\">";
1704  myMetadata += tr( "Project Spatial Reference System: " );
1705  myMetadata += "</p>\n";
1706  myMetadata += "<p>";
1707  myMetadata += mCoordinateTransform->destCRS().toProj4();
1708  myMetadata += "</p>\n";
1709 #endif
1710 
1711  //
1712  // Add the stats for each band to the output table
1713  //
1714  int myBandCountInt = bandCount();
1715  for ( int myIteratorInt = 1; myIteratorInt <= myBandCountInt; ++myIteratorInt )
1716  {
1717  QgsDebugMsg( "Raster properties : checking if band " + QString::number( myIteratorInt ) + " has stats? " );
1718  //band name
1719  myMetadata += "<p class=\"glossy\">\n";
1720  myMetadata += tr( "Band" );
1721  myMetadata += "</p>\n";
1722  myMetadata += "<p>";
1723  myMetadata += bandName( myIteratorInt );
1724  myMetadata += "</p>\n";
1725  //band number
1726  myMetadata += "<p>";
1727  myMetadata += tr( "Band No" );
1728  myMetadata += "</p>\n";
1729  myMetadata += "<p>\n";
1730  myMetadata += QString::number( myIteratorInt );
1731  myMetadata += "</p>\n";
1732 
1733  //check if full stats for this layer have already been collected
1734  if ( !hasStatistics( myIteratorInt ) ) //not collected
1735  {
1736  QgsDebugMsg( ".....no" );
1737 
1738  myMetadata += "<p>";
1739  myMetadata += tr( "No Stats" );
1740  myMetadata += "</p>\n";
1741  myMetadata += "<p>\n";
1742  myMetadata += tr( "No stats collected yet" );
1743  myMetadata += "</p>\n";
1744  }
1745  else // collected - show full detail
1746  {
1747  QgsDebugMsg( ".....yes" );
1748 
1749  QgsRasterBandStats myRasterBandStats = bandStatistics( myIteratorInt );
1750  //Min Val
1751  myMetadata += "<p>";
1752  myMetadata += tr( "Min Val" );
1753  myMetadata += "</p>\n";
1754  myMetadata += "<p>\n";
1755  myMetadata += QString::number( myRasterBandStats.minimumValue, 'f', 10 );
1756  myMetadata += "</p>\n";
1757 
1758  // Max Val
1759  myMetadata += "<p>";
1760  myMetadata += tr( "Max Val" );
1761  myMetadata += "</p>\n";
1762  myMetadata += "<p>\n";
1763  myMetadata += QString::number( myRasterBandStats.maximumValue, 'f', 10 );
1764  myMetadata += "</p>\n";
1765 
1766  // Range
1767  myMetadata += "<p>";
1768  myMetadata += tr( "Range" );
1769  myMetadata += "</p>\n";
1770  myMetadata += "<p>\n";
1771  myMetadata += QString::number( myRasterBandStats.range, 'f', 10 );
1772  myMetadata += "</p>\n";
1773 
1774  // Mean
1775  myMetadata += "<p>";
1776  myMetadata += tr( "Mean" );
1777  myMetadata += "</p>\n";
1778  myMetadata += "<p>\n";
1779  myMetadata += QString::number( myRasterBandStats.mean, 'f', 10 );
1780  myMetadata += "</p>\n";
1781 
1782  //sum of squares
1783  myMetadata += "<p>";
1784  myMetadata += tr( "Sum of squares" );
1785  myMetadata += "</p>\n";
1786  myMetadata += "<p>\n";
1787  myMetadata += QString::number( myRasterBandStats.sumOfSquares, 'f', 10 );
1788  myMetadata += "</p>\n";
1789 
1790  //standard deviation
1791  myMetadata += "<p>";
1792  myMetadata += tr( "Standard Deviation" );
1793  myMetadata += "</p>\n";
1794  myMetadata += "<p>\n";
1795  myMetadata += QString::number( myRasterBandStats.stdDev, 'f', 10 );
1796  myMetadata += "</p>\n";
1797 
1798  //sum of all cells
1799  myMetadata += "<p>";
1800  myMetadata += tr( "Sum of all cells" );
1801  myMetadata += "</p>\n";
1802  myMetadata += "<p>\n";
1803  myMetadata += QString::number( myRasterBandStats.sum, 'f', 10 );
1804  myMetadata += "</p>\n";
1805 
1806  //number of cells
1807  myMetadata += "<p>";
1808  myMetadata += tr( "Cell Count" );
1809  myMetadata += "</p>\n";
1810  myMetadata += "<p>\n";
1811  myMetadata += QString::number( myRasterBandStats.elementCount );
1812  myMetadata += "</p>\n";
1813  }
1814  }
1815 
1816  QgsDebugMsg( myMetadata );
1817  return myMetadata;
1818 }
1819 
1824 double QgsRasterLayer::minimumValue( unsigned int theBand )
1825 {
1826  if ( 0 < theBand && theBand <= bandCount() )
1827  {
1828  return mContrastEnhancementList[theBand - 1].minimumValue();
1829  }
1830 
1831  return 0.0;
1832 }
1833 
1838 double QgsRasterLayer::minimumValue( QString theBand )
1839 {
1840  return minimumValue( bandNumber( theBand ) );
1841 }
1842 
1847 QPixmap QgsRasterLayer::paletteAsPixmap( int theBandNumber )
1848 {
1849  //TODO: This function should take dimensions
1850  QgsDebugMsg( "entered." );
1851 
1852  // Only do this for the non-provider (hard-coded GDAL) scenario...
1853  // Maybe WMS can do this differently using QImage::numColors and QImage::color()
1854  if ( mProviderKey.isEmpty() && hasBand( "Palette" ) && theBandNumber > 0 ) //don't tr() this its a gdal word!
1855  {
1856  QgsDebugMsg( "....found paletted image" );
1857  QgsColorRampShader myShader;
1858  //QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = myShader.colorRampItemList();
1859 
1860  //if ( readColorTable( 1, &myColorRampItemList ) )
1861  QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = mDataProvider->colorTable( 1 );
1862  // TODO: add CT capability? It can depends on band (?)
1863  if ( myColorRampItemList.size() > 0 )
1864  {
1865  QgsDebugMsg( "....got color ramp item list" );
1866  myShader.setColorRampItemList( myColorRampItemList );
1868  // Draw image
1869  int mySize = 100;
1870  QPixmap myPalettePixmap( mySize, mySize );
1871  QPainter myQPainter( &myPalettePixmap );
1872 
1873  QImage myQImage = QImage( mySize, mySize, QImage::Format_RGB32 );
1874  myQImage.fill( 0 );
1875  myPalettePixmap.fill();
1876 
1877  double myStep = (( double )myColorRampItemList.size() - 1 ) / ( double )( mySize * mySize );
1878  double myValue = 0.0;
1879  for ( int myRow = 0; myRow < mySize; myRow++ )
1880  {
1881  QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
1882  for ( int myCol = 0; myCol < mySize; myCol++ )
1883  {
1884  myValue = myStep * ( double )( myCol + myRow * mySize );
1885  int c1, c2, c3;
1886  myShader.shade( myValue, &c1, &c2, &c3 );
1887  myLineBuffer[ myCol ] = qRgb( c1, c2, c3 );
1888  }
1889  }
1890 
1891  myQPainter.drawImage( 0, 0, myQImage );
1892  return myPalettePixmap;
1893  }
1894  QPixmap myNullPixmap;
1895  return myNullPixmap;
1896  }
1897  else
1898  {
1899  //invalid layer was requested
1900  QPixmap myNullPixmap;
1901  return myNullPixmap;
1902  }
1903 }
1904 
1905 /*
1906  * @param theBandNoInt - which band to compute the histogram for
1907  * @param theBinCountInt - how many 'bins' to categorise the data into
1908  * @param theIgnoreOutOfRangeFlag - whether to ignore values that are out of range (default=true)
1909  * @param theThoroughBandScanFlag - whether to visit each cell when computing the histogram (default=false)
1910  */
1911 void QgsRasterLayer::populateHistogram( int theBandNo, int theBinCount, bool theIgnoreOutOfRangeFlag, bool theHistogramEstimatedFlag )
1912 {
1913  QgsRasterBandStats myRasterBandStats = bandStatistics( theBandNo );
1914  mDataProvider->populateHistogram( theBandNo, myRasterBandStats, theBinCount, theIgnoreOutOfRangeFlag, theHistogramEstimatedFlag );
1915 }
1916 
1918 {
1919  if ( mProviderKey.isEmpty() )
1920  {
1921  return QString();
1922  }
1923  else
1924  {
1925  return mProviderKey;
1926  }
1927 }
1928 
1933 {
1934 // We return one raster pixel per map unit pixel
1935 // One raster pixel can have several raster units...
1936 
1937 // We can only use one of the mGeoTransform[], so go with the
1938 // horisontal one.
1939 
1940  //return qAbs( mGeoTransform[1] );
1942  {
1943  return mDataProvider->extent().width() / mDataProvider->xSize();
1944  }
1945  return 1;
1946 }
1947 
1948 
1950 {
1952  mValidNoDataValue = false;
1953  if ( mDataProvider != NULL && mDataProvider->bandCount() > 0 )
1954  {
1955  // TODO: add 'has null value' to capabilities
1956 #if 0
1957  int myRequestValid;
1958  myRequestValid = 1;
1959  double myValue = mDataProvider->noDataValue();
1960 
1961  if ( 0 != myRequestValid )
1962  {
1963  setNoDataValue( myValue );
1964  }
1965  else
1966  {
1967  setNoDataValue( -9999.0 );
1968  mValidNoDataValue = false;
1969 
1970  }
1971 #endif
1974  }
1975 }
1976 
1977 
1978 void QgsRasterLayer::setBlueBandName( QString const & theBandName )
1979 {
1980  mBlueBandName = validateBandName( theBandName );
1981 }
1982 
1984 {
1985  // keep this until mGeoTransform occurences are removed!
1986  mGeoTransform[0] = 0;
1987  mGeoTransform[1] = 1;
1988  mGeoTransform[2] = 0;
1989  mGeoTransform[3] = 0;
1990  mGeoTransform[4] = 0;
1991  mGeoTransform[5] = -1;
1992 
1993 
1995 
2001 
2002 
2003  mUserDefinedRGBMinimumMaximum = false; //defaults needed to bypass enhanceContrast
2007 
2012 
2013  mBandCount = 0;
2014  mHasPyramids = false;
2015  mNoDataValue = -9999.0;
2016  mValidNoDataValue = false;
2017 
2018  //Initialize the last view port structure, should really be a class
2021 }
2022 
2023 QLibrary* QgsRasterLayer::loadProviderLibrary( QString theProviderKey )
2024 {
2025  QgsDebugMsg( "theProviderKey = " + theProviderKey );
2026  // load the plugin
2028  QString myLibPath = pReg->library( theProviderKey );
2029  QgsDebugMsg( "myLibPath = " + myLibPath );
2030 
2031 #ifdef TESTPROVIDERLIB
2032  const char *cOgrLib = ( const char * ) myLibPath;
2033  // test code to help debug provider loading problems
2034  // void *handle = dlopen(cOgrLib, RTLD_LAZY);
2035  void *handle = dlopen( cOgrLib, RTLD_LAZY | RTLD_GLOBAL );
2036  if ( !handle )
2037  {
2038  QgsLogger::warning( "Error in dlopen: " );
2039  }
2040  else
2041  {
2042  QgsDebugMsg( "dlopen suceeded" );
2043  dlclose( handle );
2044  }
2045 
2046 #endif
2047 
2048  // load the data provider
2049  QLibrary* myLib = new QLibrary( myLibPath );
2050 
2051  QgsDebugMsg( "Library name is " + myLib->fileName() );
2052  bool loaded = myLib->load();
2053 
2054  if ( !loaded )
2055  {
2056  QgsLogger::warning( "QgsRasterLayer::loadProviderLibrary: Failed to load " );
2057  return NULL;
2058  }
2059  QgsDebugMsg( "Loaded data provider library" );
2060  return myLib;
2061 }
2062 
2063 // This code should be shared also by vector layer -> move it to QgsMapLayer
2064 QgsRasterDataProvider* QgsRasterLayer::loadProvider( QString theProviderKey, QString theDataSource )
2065 {
2066  QgsDebugMsg( "Entered" );
2067  QLibrary* myLib = QgsRasterLayer::loadProviderLibrary( theProviderKey );
2068  QgsDebugMsg( "Library loaded" );
2069  if ( !myLib )
2070  {
2071  QgsDebugMsg( "myLib is NULL" );
2072  return NULL;
2073  }
2074 
2075  QgsDebugMsg( "Attempting to resolve the classFactory function" );
2076  classFactoryFunction_t * classFactory = ( classFactoryFunction_t * ) cast_to_fptr( myLib->resolve( "classFactory" ) );
2077 
2078  if ( !classFactory )
2079  {
2080  QgsLogger::warning( "QgsRasterLayer::loadProvider: Cannot resolve the classFactory function" );
2081  return NULL;
2082  }
2083  QgsDebugMsg( "Getting pointer to a mDataProvider object from the library" );
2084  //XXX - This was a dynamic cast but that kills the Windows
2085  // version big-time with an abnormal termination error
2086  // mDataProvider = (QgsRasterDataProvider*)(classFactory((const
2087  // char*)(dataSource.utf8())));
2088 
2089  // Copied from qgsproviderregistry in preference to the above.
2090  QgsRasterDataProvider* myDataProvider = ( QgsRasterDataProvider* )( *classFactory )( &theDataSource );
2091 
2092  if ( !myDataProvider )
2093  {
2094  QgsLogger::warning( "QgsRasterLayer::loadProvider: Unable to instantiate the data provider plugin" );
2095  return NULL;
2096  }
2097  QgsDebugMsg( "Data driver created" );
2098  return myDataProvider;
2099 }
2100 
2101 void QgsRasterLayer::setDataProvider( QString const & provider,
2102  QStringList const & layers,
2103  QStringList const & styles,
2104  QString const & format,
2105  QString const & crs )
2106 {
2107  setDataProvider( provider, layers, styles, format, crs, false );
2108 }
2109 
2113 void QgsRasterLayer::setDataProvider( QString const & provider,
2114  QStringList const & layers,
2115  QStringList const & styles,
2116  QString const & format,
2117  QString const & crs,
2118  bool loadDefaultStyleFlag )
2119 {
2120  // XXX should I check for and possibly delete any pre-existing providers?
2121  // XXX How often will that scenario occur?
2122 
2123  mProviderKey = provider;
2124  mValid = false; // assume the layer is invalid until we determine otherwise
2125 
2126  // set the layer name (uppercase first character)
2127 
2128  if ( ! mLayerName.isEmpty() ) // XXX shouldn't this happen in parent?
2129  {
2131  }
2132 
2133  mBandCount = 0;
2135 
2137  if ( !mDataProvider )
2138  {
2139  return;
2140  }
2141 
2142 
2143  QgsDebugMsg( "Instantiated the data provider plugin"
2144  + QString( " with layer list of " ) + layers.join( ", " )
2145  + " and style list of " + styles.join( ", " )
2146  + " and format of " + format + " and CRS of " + crs );
2147  if ( ! mDataProvider->isValid() )
2148  {
2149  QgsLogger::warning( "QgsRasterLayer::setDataProvider: Data provider is invalid." );
2150  return;
2151  }
2152 
2153  mDataProvider->addLayers( layers, styles );
2154  mDataProvider->setImageEncoding( format );
2155  mDataProvider->setImageCrs( crs );
2156 
2158 
2159  // get the extent
2161 
2162  // show the extent
2163  QString s = mbr.toString();
2164  QgsDebugMsg( "Extent of layer: " + s );
2165  // store the extent
2166  mLayerExtent.setXMaximum( mbr.xMaximum() );
2167  mLayerExtent.setXMinimum( mbr.xMinimum() );
2168  mLayerExtent.setYMaximum( mbr.yMaximum() );
2169  mLayerExtent.setYMinimum( mbr.yMinimum() );
2170 
2171  mWidth = mDataProvider->xSize();
2173 
2174 
2175  // upper case the first letter of the layer name
2176  QgsDebugMsg( "mLayerName: " + name() );
2177 
2178  // set up the raster drawing style
2179  mDrawingStyle = MultiBandColor; //sensible default
2180 
2181  // Setup source CRS
2182  if ( mProviderKey == "wms" )
2183  {
2185  mCRS->createFromOgcWmsCrs( crs );
2186  }
2187  else
2188  {
2190  }
2191  //get the project projection, defaulting to this layer's projection
2192  //if none exists....
2193  if ( !mCRS->isValid() )
2194  {
2195  mCRS->setValidationHint( tr( "Specify CRS for layer %1" ).arg( name() ) );
2196  mCRS->validate();
2197  }
2198  QString mySourceWkt = mCRS->toWkt();
2199 
2200  QgsDebugMsg( "using wkt:\n" + mySourceWkt );
2201 
2203  for ( int i = 1; i <= mBandCount; i++ )
2204  {
2205  QgsRasterBandStats myRasterBandStats;
2206  myRasterBandStats.bandName = mDataProvider->generateBandName( i );
2207  myRasterBandStats.bandNumber = i;
2208  myRasterBandStats.statsGathered = false;
2209  myRasterBandStats.histogramVector->clear();
2210  //Store the default color table
2211  //readColorTable( i, &myRasterBandStats.colorTable );
2212  QList<QgsColorRampShader::ColorRampItem> ct;
2213  ct = mDataProvider->colorTable( i );
2214  myRasterBandStats.colorTable = ct;
2215 
2216  mRasterStatsList.push_back( myRasterBandStats );
2217 
2218  //Build a new contrast enhancement for the band and store in list
2219  //QgsContrastEnhancement myContrastEnhancement(( QgsContrastEnhancement::QgsRasterDataType )mDataProvider->dataType( i ) );
2221  mContrastEnhancementList.append( myContrastEnhancement );
2222  }
2223 
2224  //defaults - Needs to be set after the Contrast list has been build
2225  //Try to read the default contrast enhancement from the config file
2226 
2227  QSettings myQSettings;
2228  setContrastEnhancementAlgorithm( myQSettings.value( "/Raster/defaultContrastEnhancementAlgorithm", "NoEnhancement" ).toString() );
2229 
2230  //decide what type of layer this is...
2231  //TODO Change this to look at the color interp and palette interp to decide which type of layer it is
2232  QgsDebugMsg( "bandCount = " + QString::number( mDataProvider->bandCount() ) );
2233  QgsDebugMsg( "dataType = " + QString::number( mDataProvider->dataType( 1 ) ) );
2234  if (( mDataProvider->bandCount() > 1 ) )
2235  {
2237  }
2239  {
2241  }
2242  //TODO hasBand is really obsolete and only used in the Palette instance, change to new function hasPalette(int)
2243  //else if ( hasBand( "Palette" ) ) //don't tr() this its a gdal word!
2244  // not sure if is worth to add colorTable capability - CT can be empty in any case
2245  // Calc bandStatistics is very slow!!!
2246  //else if ( bandStatistics(1).colorTable.count() > 0 )
2248  {
2249  mRasterType = Palette;
2250  }
2251  else
2252  {
2254  }
2255 
2256  // Set min/max values for single band if we have them ready (no need to calculate which is slow)
2257  // don't set min/max on multiband even if available because it would cause stretch of bands and thus colors distortion
2259  {
2262  }
2263 
2264  QgsDebugMsg( "mRasterType = " + QString::number( mRasterType ) );
2265  if ( mRasterType == ColorLayer )
2266  {
2267  QgsDebugMsg( "Setting mDrawingStyle to SingleBandColorDataStyle " + QString::number( SingleBandColorDataStyle ) );
2269  mGrayBandName = bandName( 1 ); //sensible default
2270  }
2271  else if ( mRasterType == Palette )
2272  {
2273  mRedBandName = TRSTRING_NOT_SET; // sensible default
2274  mGreenBandName = TRSTRING_NOT_SET; // sensible default
2275  mBlueBandName = TRSTRING_NOT_SET;// sensible default
2276  mTransparencyBandName = TRSTRING_NOT_SET; // sensible default
2277  mGrayBandName = bandName( 1 ); //sensible default
2279 
2280  mDrawingStyle = PalettedColor; //sensible default
2281 
2282  //Set up a new color ramp shader
2285  //TODO: Make sure the set algorithm and cast was successful,
2286  //e.g., if ( 0 != myColorRampShader && myColorRampShader->shaderTypeAsString == "ColorRampShader" )
2287  myColorRampShader->setColorRampType( QgsColorRampShader::INTERPOLATED );
2288  myColorRampShader->setColorRampItemList( *colorTable( 1 ) );
2289  }
2290  else if ( mRasterType == Multiband )
2291  {
2292  //we know we have at least 2 layers...
2293  mRedBandName = bandName( myQSettings.value( "/Raster/defaultRedBand", 1 ).toInt() ); // sensible default
2294  mGreenBandName = bandName( myQSettings.value( "/Raster/defaultGreenBand", 2 ).toInt() ); // sensible default
2295 
2296  //Check to make sure preferred bands combinations are valid
2297  if ( mRedBandName.isEmpty() )
2298  {
2299  mRedBandName = bandName( 1 );
2300  }
2301 
2302  if ( mGreenBandName.isEmpty() )
2303  {
2304  mGreenBandName = bandName( 2 );
2305  }
2306 
2307  //for the third band we cant be sure so..
2308  if (( mDataProvider->bandCount() > 2 ) )
2309  {
2310  mBlueBandName = bandName( myQSettings.value( "/Raster/defaultBlueBand", 3 ).toInt() ); // sensible default
2311  if ( mBlueBandName.isEmpty() )
2312  {
2313  mBlueBandName = bandName( 3 );
2314  }
2315  }
2316  else
2317  {
2318  mBlueBandName = bandName( myQSettings.value( "/Raster/defaultBlueBand", 2 ).toInt() ); // sensible default
2319  if ( mBlueBandName.isEmpty() )
2320  {
2321  mBlueBandName = bandName( 2 );
2322  }
2323  }
2324 
2325 
2327  mGrayBandName = TRSTRING_NOT_SET; //sensible default
2328  mDrawingStyle = MultiBandColor; //sensible default
2329 
2330  // read standard deviations
2332  {
2333  setStandardDeviations( myQSettings.value( "/Raster/defaultStandardDeviation", 2.0 ).toInt() );
2334  }
2335  }
2336  else //GrayOrUndefined
2337  {
2338  mRedBandName = TRSTRING_NOT_SET; //sensible default
2339  mGreenBandName = TRSTRING_NOT_SET; //sensible default
2340  mBlueBandName = TRSTRING_NOT_SET; //sensible default
2341  mTransparencyBandName = TRSTRING_NOT_SET; //sensible default
2342  mDrawingStyle = SingleBandGray; //sensible default
2343  mGrayBandName = bandName( 1 );
2344 
2345  // If we have min/max available (without calculation), it is better to use StretchToMinimumMaximum
2346  // TODO: in GUI there is 'Contrast enhancement - Default' which is overwritten here
2347  // and that is confusing
2349  {
2351  }
2352 
2353  // read standard deviations
2355  {
2356  setStandardDeviations( myQSettings.value( "/Raster/defaultStandardDeviation", 2.0 ).toInt() );
2357  }
2358  }
2359  // Debug
2360  //mDrawingStyle = SingleBandPseudoColor;
2361 
2362  // Store timestamp
2363  // TODO move to provider
2365 
2367  if ( mValidNoDataValue )
2368  {
2371  }
2372 
2373  // Connect provider signals
2374  connect(
2375  mDataProvider, SIGNAL( progress( int, double, QString ) ),
2376  this, SLOT( onProgress( int, double, QString ) )
2377  );
2378 
2379  // Do a passthrough for the status bar text
2380  connect(
2381  mDataProvider, SIGNAL( statusChanged( QString ) ),
2382  this, SIGNAL( statusChanged( QString ) )
2383  );
2384 
2385  //mark the layer as valid
2386  mValid = true;
2387 
2388  QgsDebugMsg( "exiting." );
2389 } // QgsRasterLayer::setDataProvider
2390 
2392 {
2393  mValid = false;
2394  delete mRasterShader;
2395  mRasterShader = 0;
2396  delete mDataProvider;
2397  mDataProvider = 0;
2398 
2399  mRasterStatsList.clear();
2400  mContrastEnhancementList.clear();
2401 
2402  mHasPyramids = false;
2403  mPyramidList.clear();
2404 }
2405 
2407 {
2408  QgsDebugMsg( "called with [" + QString::number( theShadingAlgorithm ) + "]" );
2409  if ( mColorShadingAlgorithm != theShadingAlgorithm )
2410  {
2411  if ( 0 == mRasterShader )
2412  {
2414  }
2415 
2416  switch ( theShadingAlgorithm )
2417  {
2418  case PseudoColorShader:
2420  break;
2421  case FreakOutShader:
2423  break;
2424  case ColorRampShader:
2426  break;
2427  case UserDefinedShader:
2428  //do nothing
2429  break;
2430  default:
2432  break;
2433  }
2434 
2435  //Set the class variable after the call to setRasterShader(), so memory recovery can happen
2436  mColorShadingAlgorithm = theShadingAlgorithm;
2437  }
2438  QgsDebugMsg( "mColorShadingAlgorithm = " + QString::number( theShadingAlgorithm ) );
2439 }
2440 
2441 void QgsRasterLayer::setColorShadingAlgorithm( QString theShaderAlgorithm )
2442 {
2443  QgsDebugMsg( "called with [" + theShaderAlgorithm + "]" );
2444 
2445  if ( theShaderAlgorithm == "PseudoColorShader" )
2447  else if ( theShaderAlgorithm == "FreakOutShader" )
2449  else if ( theShaderAlgorithm == "ColorRampShader" )
2451  else if ( theShaderAlgorithm == "UserDefinedShader" )
2453  else
2455 }
2456 
2458 {
2459  QList<QgsContrastEnhancement>::iterator myIterator = mContrastEnhancementList.begin();
2460  while ( myIterator != mContrastEnhancementList.end() )
2461  {
2462  ( *myIterator ).setContrastEnhancementAlgorithm( theAlgorithm, theGenerateLookupTableFlag );
2463  ++myIterator;
2464  }
2465  mContrastEnhancementAlgorithm = theAlgorithm;
2466 }
2467 
2468 void QgsRasterLayer::setContrastEnhancementAlgorithm( QString theAlgorithm, bool theGenerateLookupTableFlag )
2469 {
2470  QgsDebugMsg( "called with [" + theAlgorithm + "] and flag=" + QString::number(( int )theGenerateLookupTableFlag ) );
2471 
2472  if ( theAlgorithm == "NoEnhancement" )
2473  {
2475  }
2476  else if ( theAlgorithm == "StretchToMinimumMaximum" )
2477  {
2479  }
2480  else if ( theAlgorithm == "StretchAndClipToMinimumMaximum" )
2481  {
2483  }
2484  else if ( theAlgorithm == "ClipToMinimumMaximum" )
2485  {
2487  }
2488  else if ( theAlgorithm == "UserDefined" )
2489  {
2491  }
2492  else
2493  {
2495  }
2496 }
2497 
2499 {
2500  if ( theFunction )
2501  {
2502  QList<QgsContrastEnhancement>::iterator myIterator = mContrastEnhancementList.begin();
2503  while ( myIterator != mContrastEnhancementList.end() )
2504  {
2505  ( *myIterator ).setContrastEnhancementFunction( theFunction );
2506  ++myIterator;
2507  }
2508  }
2509 }
2510 
2516 void QgsRasterLayer::setDrawingStyle( QString const & theDrawingStyleQString )
2517 {
2518  QgsDebugMsg( "DrawingStyle = " + theDrawingStyleQString );
2519  if ( theDrawingStyleQString == "SingleBandGray" )//no need to tr() this its not shown in ui
2520  {
2522  }
2523  else if ( theDrawingStyleQString == "SingleBandPseudoColor" )//no need to tr() this its not shown in ui
2524  {
2526  }
2527  else if ( theDrawingStyleQString == "PalettedColor" )//no need to tr() this its not shown in ui
2528  {
2530  }
2531  else if ( theDrawingStyleQString == "PalettedSingleBandGray" )//no need to tr() this its not shown in ui
2532  {
2534  }
2535  else if ( theDrawingStyleQString == "PalettedSingleBandPseudoColor" )//no need to tr() this its not shown in ui
2536  {
2538  }
2539  else if ( theDrawingStyleQString == "PalettedMultiBandColor" )//no need to tr() this its not shown in ui
2540  {
2542  }
2543  else if ( theDrawingStyleQString == "MultiBandSingleBandGray" )//no need to tr() this its not shown in ui
2544  {
2546  }
2547  else if ( theDrawingStyleQString == "MultiBandSingleBandPseudoColor" )//no need to tr() this its not shown in ui
2548  {
2550  }
2551  else if ( theDrawingStyleQString == "MultiBandColor" )//no need to tr() this its not shown in ui
2552  {
2554  }
2555  else if ( theDrawingStyleQString == "SingleBandColorDataStyle" )//no need to tr() this its not shown in ui
2556  {
2557  QgsDebugMsg( "Setting mDrawingStyle to SingleBandColorDataStyle " + QString::number( SingleBandColorDataStyle ) );
2559  QgsDebugMsg( "Setted mDrawingStyle to " + QString::number( mDrawingStyle ) );
2560  }
2561  else
2562  {
2564  }
2565 }
2566 
2567 void QgsRasterLayer::setGrayBandName( QString const & theBandName )
2568 {
2569  mGrayBandName = validateBandName( theBandName );
2570 }
2571 
2572 void QgsRasterLayer::setGreenBandName( QString const & theBandName )
2573 {
2574  mGreenBandName = validateBandName( theBandName );
2575 }
2576 
2577 void QgsRasterLayer::setLayerOrder( QStringList const & layers )
2578 {
2579  QgsDebugMsg( "entered." );
2580 
2581  if ( mDataProvider )
2582  {
2583  QgsDebugMsg( "About to mDataProvider->setLayerOrder(layers)." );
2584  mDataProvider->setLayerOrder( layers );
2585  }
2586 
2587 }
2588 
2589 void QgsRasterLayer::setMaximumValue( unsigned int theBand, double theValue, bool theGenerateLookupTableFlag )
2590 {
2591  QgsDebugMsg( "setMaximumValue theValue = " + QString::number( theValue ) );
2592  if ( 0 < theBand && theBand <= bandCount() )
2593  {
2594  mContrastEnhancementList[theBand - 1].setMaximumValue( theValue, theGenerateLookupTableFlag );
2595  }
2596 }
2597 
2598 void QgsRasterLayer::setMaximumValue( QString theBand, double theValue, bool theGenerateLookupTableFlag )
2599 {
2600  if ( theBand != tr( "Not Set" ) )
2601  {
2602  setMaximumValue( bandNumber( theBand ), theValue, theGenerateLookupTableFlag );
2603  }
2604 }
2605 
2607 {
2608  double myMinMax[2];
2610  {
2612  setMinimumValue( grayBandName(), myMinMax[0] );
2613  setMaximumValue( grayBandName(), myMinMax[1] );
2614 
2616  }
2617  else if ( rasterType() == QgsRasterLayer::Multiband )
2618  {
2620  setMinimumValue( redBandName(), myMinMax[0], false );
2621  setMaximumValue( redBandName(), myMinMax[1], false );
2622 
2624  setMinimumValue( greenBandName(), myMinMax[0], false );
2625  setMaximumValue( greenBandName(), myMinMax[1], false );
2626 
2628  setMinimumValue( blueBandName(), myMinMax[0], false );
2629  setMaximumValue( blueBandName(), myMinMax[1], false );
2630 
2632  }
2633 }
2634 
2636 {
2638  {
2639  QgsRasterBandStats myRasterBandStats = bandStatistics( bandNumber( mGrayBandName ) );
2640  double myMin = myRasterBandStats.minimumValue;
2641  double myMax = myRasterBandStats.maximumValue;
2642  setMinimumValue( grayBandName(), myMin );
2643  setMaximumValue( grayBandName(), myMax );
2645  }
2646  else if ( rasterType() == QgsRasterLayer::Multiband )
2647  {
2648  QgsRasterBandStats myRasterBandStats = bandStatistics( bandNumber( mRedBandName ) );
2649  double myMin = myRasterBandStats.minimumValue;
2650  double myMax = myRasterBandStats.maximumValue;
2651  setMinimumValue( redBandName(), myMin );
2652  setMaximumValue( redBandName(), myMax );
2653 
2654  myRasterBandStats = bandStatistics( bandNumber( mGreenBandName ) );
2655  myMin = myRasterBandStats.minimumValue;
2656  myMax = myRasterBandStats.maximumValue;
2657  setMinimumValue( greenBandName(), myMin );
2658  setMaximumValue( greenBandName(), myMax );
2659 
2660  myRasterBandStats = bandStatistics( bandNumber( mGreenBandName ) );
2661  myMin = myRasterBandStats.minimumValue;
2662  myMax = myRasterBandStats.maximumValue;
2663  setMinimumValue( greenBandName(), myMin );
2664  setMaximumValue( greenBandName(), myMax );
2665 
2667  }
2668 }
2669 
2670 void QgsRasterLayer::setMinimumValue( unsigned int theBand, double theValue, bool theGenerateLookupTableFlag )
2671 {
2672  QgsDebugMsg( "setMinimumValue theValue = " + QString::number( theValue ) );
2673  if ( 0 < theBand && theBand <= bandCount() )
2674  {
2675  mContrastEnhancementList[theBand - 1].setMinimumValue( theValue, theGenerateLookupTableFlag );
2676  }
2677 }
2678 
2679 void QgsRasterLayer::setMinimumValue( QString theBand, double theValue, bool theGenerateLookupTableFlag )
2680 {
2681  if ( theBand != tr( "Not Set" ) )
2682  {
2683  setMinimumValue( bandNumber( theBand ), theValue, theGenerateLookupTableFlag );
2684  }
2685 
2686 }
2687 
2688 void QgsRasterLayer::setNoDataValue( double theNoDataValue )
2689 {
2690  if ( theNoDataValue != mNoDataValue )
2691  {
2692  mNoDataValue = theNoDataValue;
2693  mValidNoDataValue = true;
2694  //Basically set the raster stats as invalid
2695  QList<QgsRasterBandStats>::iterator myIterator = mRasterStatsList.begin();
2696  while ( myIterator != mRasterStatsList.end() )
2697  {
2698  ( *myIterator ).statsGathered = false;
2699  ++myIterator;
2700  }
2701  }
2702 }
2703 
2705 {
2706  if ( theFunction )
2707  {
2708  mRasterShader->setRasterShaderFunction( theFunction );
2710  }
2711  else
2712  {
2713  //If NULL as passed in, set a default shader function to prevent segfaults
2716  }
2717 }
2718 
2719 void QgsRasterLayer::setRedBandName( QString const & theBandName )
2720 {
2721  QgsDebugMsg( "setRedBandName : " + theBandName );
2722  mRedBandName = validateBandName( theBandName );
2723 }
2724 
2725 void QgsRasterLayer::setSubLayerVisibility( QString const & name, bool vis )
2726 {
2727 
2728  if ( mDataProvider )
2729  {
2730  QgsDebugMsg( "About to mDataProvider->setSubLayerVisibility(name, vis)." );
2731  mDataProvider->setSubLayerVisibility( name, vis );
2732  }
2733 
2734 }
2735 
2736 void QgsRasterLayer::setTransparentBandName( QString const & theBandName )
2737 {
2738  mTransparencyBandName = validateBandName( theBandName );
2739 }
2740 
2741 void QgsRasterLayer::showProgress( int theValue )
2742 {
2743  emit progressUpdate( theValue );
2744 }
2745 
2746 
2747 void QgsRasterLayer::showStatusMessage( QString const & theMessage )
2748 {
2749  // QgsDebugMsg(QString("entered with '%1'.").arg(theMessage));
2750 
2751  // Pass-through
2752  // TODO: See if we can connect signal-to-signal. This is a kludge according to the Qt doc.
2753  emit statusChanged( theMessage );
2754 }
2755 
2756 
2757 QStringList QgsRasterLayer::subLayers() const
2758 {
2759  return mDataProvider->subLayers();
2760 }
2761 
2762 
2763 void QgsRasterLayer::thumbnailAsPixmap( QPixmap * theQPixmap )
2764 {
2765  //TODO: This should be depreciated and a new function written that just returns a new QPixmap, it will be safer
2766  if ( 0 == theQPixmap ) { return; }
2767 
2768  theQPixmap->fill( ); //defaults to white
2769 
2770  QgsRasterViewPort *myRasterViewPort = new QgsRasterViewPort();
2771 
2772  double myMapUnitsPerPixel;
2773  double myX = 0.0;
2774  double myY = 0.0;
2775  QgsRectangle myExtent = mDataProvider->extent();
2776  if ( myExtent.width() / myExtent.height() >= theQPixmap->width() / theQPixmap->height() )
2777  {
2778  myMapUnitsPerPixel = myExtent.width() / theQPixmap->width();
2779  myY = ( theQPixmap->height() - myExtent.height() / myMapUnitsPerPixel ) / 2;
2780  }
2781  else
2782  {
2783  myMapUnitsPerPixel = myExtent.height() / theQPixmap->height();
2784  myX = ( theQPixmap->width() - myExtent.width() / myMapUnitsPerPixel ) / 2;
2785  }
2786 
2787  double myPixelWidth = myExtent.width() / myMapUnitsPerPixel;
2788  double myPixelHeight = myExtent.height() / myMapUnitsPerPixel;
2789 
2790  //myRasterViewPort->topLeftPoint = QgsPoint( 0, 0 );
2791  myRasterViewPort->topLeftPoint = QgsPoint( myX, myY );
2792 
2793  //myRasterViewPort->bottomRightPoint = QgsPoint( theQPixmap->width(), theQPixmap->height() );
2794 
2795  myRasterViewPort->bottomRightPoint = QgsPoint( myPixelWidth, myPixelHeight );
2796  myRasterViewPort->drawableAreaXDim = theQPixmap->width();
2797  myRasterViewPort->drawableAreaYDim = theQPixmap->height();
2798  //myRasterViewPort->drawableAreaXDim = myPixelWidth;
2799  //myRasterViewPort->drawableAreaYDim = myPixelHeight;
2800 
2801  myRasterViewPort->mDrawnExtent = myExtent;
2802  myRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid
2803  myRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid
2804 
2805  QgsMapToPixel *myMapToPixel = new QgsMapToPixel( myMapUnitsPerPixel );
2806 
2807  QPainter * myQPainter = new QPainter( theQPixmap );
2808  draw( myQPainter, myRasterViewPort, myMapToPixel );
2809  delete myRasterViewPort;
2810  delete myMapToPixel;
2811  myQPainter->end();
2812  delete myQPainter;
2813 }
2814 
2815 void QgsRasterLayer::thumbnailAsImage( QImage * thepImage )
2816 {
2817  //TODO: This should be depreciated and a new function written that just returns a new QImage, it will be safer
2818  if ( 0 == thepImage ) { return; }
2819 
2820  thepImage->fill( Qt::white ); //defaults to white
2821 
2822  // Raster providers are disabled (for the moment)
2823  if ( mProviderKey.isEmpty() )
2824  {
2825  QgsRasterViewPort *myRasterViewPort = new QgsRasterViewPort();
2826  myRasterViewPort->topLeftPoint = QgsPoint( 0, 0 );
2827  myRasterViewPort->bottomRightPoint = QgsPoint( thepImage->width(), thepImage->height() );
2828  myRasterViewPort->drawableAreaXDim = thepImage->width();
2829  myRasterViewPort->drawableAreaYDim = thepImage->height();
2830 
2831  QPainter * myQPainter = new QPainter( thepImage );
2832  draw( myQPainter, myRasterViewPort );
2833  delete myRasterViewPort;
2834  myQPainter->end();
2835  delete myQPainter;
2836  }
2837 
2838 }
2839 
2841 {
2842  emit repaintRequested();
2843 }
2844 
2845 void QgsRasterLayer::updateProgress( int theProgress, int theMax )
2846 {
2847  //simply propogate it on!
2848  emit drawingProgress( theProgress, theMax );
2849 }
2850 
2851 void QgsRasterLayer::onProgress( int theType, double theProgress, QString theMesssage )
2852 {
2853  QgsDebugMsg( QString( "theProgress = %1" ).arg( theProgress ) );
2854  emit progressUpdate(( int )theProgress );
2855 }
2856 
2858 //
2859 // Protected methods
2860 //
2862 /*
2863  * @param QDomNode node that will contain the symbology definition for this layer.
2864  * @param errorMessage reference to string that will be updated with any error messages
2865  * @return true in case of success.
2866  */
2867 bool QgsRasterLayer::readSymbology( const QDomNode& layer_node, QString& errorMessage )
2868 {
2869  QDomNode mnl = layer_node.namedItem( "rasterproperties" );
2870  QDomNode snode = mnl.namedItem( "mDrawingStyle" );
2871  QDomElement myElement = snode.toElement();
2872  setDrawingStyle( myElement.text() );
2873 
2874  snode = mnl.namedItem( "mColorShadingAlgorithm" );
2875  myElement = snode.toElement();
2876  setColorShadingAlgorithm( myElement.text() );
2877 
2878  snode = mnl.namedItem( "mInvertColor" );
2879  myElement = snode.toElement();
2880  QVariant myVariant = ( QVariant ) myElement.attribute( "boolean" );
2881  setInvertHistogram( myVariant.toBool() );
2882 
2883  snode = mnl.namedItem( "mRedBandName" );
2884  myElement = snode.toElement();
2885  setRedBandName( myElement.text() );
2886 
2887  snode = mnl.namedItem( "mGreenBandName" );
2888  myElement = snode.toElement();
2889  setGreenBandName( myElement.text() );
2890 
2891  snode = mnl.namedItem( "mBlueBandName" );
2892  myElement = snode.toElement();
2893  setBlueBandName( myElement.text() );
2894 
2895  snode = mnl.namedItem( "mGrayBandName" );
2896  myElement = snode.toElement();
2897  QgsDebugMsg( QString( " Setting gray band to : " ) + myElement.text() );
2898  setGrayBandName( myElement.text() );
2899 
2900  snode = mnl.namedItem( "mStandardDeviations" );
2901  myElement = snode.toElement();
2902  setStandardDeviations( myElement.text().toDouble() );
2903 
2904  snode = mnl.namedItem( "mUserDefinedRGBMinimumMaximum" );
2905  myElement = snode.toElement();
2906  myVariant = ( QVariant ) myElement.attribute( "boolean" );
2907  setUserDefinedRGBMinimumMaximum( myVariant.toBool() );
2908 
2909  snode = mnl.namedItem( "mRGBMinimumMaximumEstimated" );
2910  myElement = snode.toElement();
2911  myVariant = ( QVariant ) myElement.attribute( "boolean" );
2912  setRGBMinimumMaximumEstimated( myVariant.toBool() );
2913 
2914  snode = mnl.namedItem( "mUserDefinedGrayMinimumMaximum" );
2915  myElement = snode.toElement();
2916  myVariant = ( QVariant ) myElement.attribute( "boolean" );
2917  setUserDefinedGrayMinimumMaximum( myVariant.toBool() );
2918 
2919  snode = mnl.namedItem( "mGrayMinimumMaximumEstimated" );
2920  myElement = snode.toElement();
2921  myVariant = ( QVariant ) myElement.attribute( "boolean" );
2922  setGrayMinimumMaximumEstimated( myVariant.toBool() );
2923 
2924  snode = mnl.namedItem( "mContrastEnhancementAlgorithm" );
2925  myElement = snode.toElement();
2926  setContrastEnhancementAlgorithm( myElement.text(), false );
2927 
2928  QDomNode contrastEnhancementMinMaxValues = mnl.namedItem( "contrastEnhancementMinMaxValues" );
2929  QDomNodeList minMaxValueList = contrastEnhancementMinMaxValues.toElement().elementsByTagName( "minMaxEntry" );
2930  for ( int i = 0; i < minMaxValueList.size(); ++i )
2931  {
2932  QDomNode minMaxEntry = minMaxValueList.at( i ).toElement();
2933  if ( minMaxEntry.isNull() )
2934  {
2935  continue;
2936  }
2937  QDomNode minEntry = minMaxEntry.namedItem( "min" );
2938  QDomNode maxEntry = minMaxEntry.namedItem( "max" );
2939 
2940  setMinimumValue( i + 1, minEntry.toElement().text().toDouble(), false );
2941  setMaximumValue( i + 1, maxEntry.toElement().text().toDouble(), false );
2942  }
2943 
2944  QgsDebugMsg( "ReadXml: gray band name " + mGrayBandName );
2945  QgsDebugMsg( "ReadXml: red band name " + mRedBandName );
2946  QgsDebugMsg( "ReadXml: green band name " + mGreenBandName );
2947  QgsDebugMsg( "Drawing style " + drawingStyleAsString() );
2948 
2949  /*
2950  * Transparency tab
2951  */
2952  snode = mnl.namedItem( "mNoDataValue" );
2953  myElement = snode.toElement();
2954  QgsDebugMsg( "ReadXml: mNoDataValue = " + myElement.text() );
2955  setNoDataValue( myElement.text().toDouble() );
2956  QgsDebugMsg( "ReadXml: mNoDataValue = " + QString::number( mNoDataValue ) );
2957  if ( myElement.attribute( "mValidNoDataValue", "false" ).compare( "true" ) )
2958  {
2959  // If flag element is not true, set to false.
2960  mValidNoDataValue = false;
2961  }
2962 
2963  QDomNode singleValuePixelListNode = mnl.namedItem( "singleValuePixelList" );
2964  if ( !singleValuePixelListNode.isNull() )
2965  {
2966  QList<QgsRasterTransparency::TransparentSingleValuePixel> newSingleValuePixelList;
2967 
2968  //entries
2969  QDomNodeList singleValuePixelList = singleValuePixelListNode.toElement().elementsByTagName( "pixelListEntry" );
2970  for ( int i = 0; i < singleValuePixelList.size(); ++i )
2971  {
2973  QDomElement singleValuePixelListElement = singleValuePixelList.at( i ).toElement();
2974  if ( singleValuePixelListElement.isNull() )
2975  {
2976  continue;
2977  }
2978 
2979  myNewItem.pixelValue = singleValuePixelListElement.attribute( "pixelValue" ).toDouble();
2980  myNewItem.percentTransparent = singleValuePixelListElement.attribute( "percentTransparent" ).toDouble();
2981 
2982  newSingleValuePixelList.push_back( myNewItem );
2983  }
2984  mRasterTransparency.setTransparentSingleValuePixelList( newSingleValuePixelList );
2985  }
2986 
2987  QDomNode threeValuePixelListNode = mnl.namedItem( "threeValuePixelList" );
2988  if ( !threeValuePixelListNode.isNull() )
2989  {
2990  QList<QgsRasterTransparency::TransparentThreeValuePixel> newThreeValuePixelList;
2991 
2992  //entries
2993  QDomNodeList threeValuePixelList = threeValuePixelListNode.toElement().elementsByTagName( "pixelListEntry" );
2994  for ( int i = 0; i < threeValuePixelList.size(); ++i )
2995  {
2997  QDomElement threeValuePixelListElement = threeValuePixelList.at( i ).toElement();
2998  if ( threeValuePixelListElement.isNull() )
2999  {
3000  continue;
3001  }
3002 
3003  myNewItem.red = threeValuePixelListElement.attribute( "red" ).toDouble();
3004  myNewItem.green = threeValuePixelListElement.attribute( "green" ).toDouble();
3005  myNewItem.blue = threeValuePixelListElement.attribute( "blue" ).toDouble();
3006  myNewItem.percentTransparent = threeValuePixelListElement.attribute( "percentTransparent" ).toDouble();
3007 
3008  newThreeValuePixelList.push_back( myNewItem );
3009  }
3010  mRasterTransparency.setTransparentThreeValuePixelList( newThreeValuePixelList );
3011  }
3012 
3013  /*
3014  * Color Ramp tab
3015  */
3016  //restore custom color ramp settings
3017  QDomNode customColorRampNode = mnl.namedItem( "customColorRamp" );
3018  if ( !customColorRampNode.isNull() )
3019  {
3021 
3022  //TODO: Remove the customColorRampType check and following if() in v2.0, added for compatibility with older ( bugged ) project files
3023  QDomNode customColorRampTypeNode = customColorRampNode.namedItem( "customColorRampType" );
3024  QDomNode colorRampTypeNode = customColorRampNode.namedItem( "colorRampType" );
3025  QString myRampType = "";
3026  if ( "" == customColorRampTypeNode.toElement().text() )
3027  {
3028  myRampType = colorRampTypeNode.toElement().text();
3029  }
3030  else
3031  {
3032  myRampType = customColorRampTypeNode.toElement().text();
3033  }
3034  myColorRampShader->setColorRampType( myRampType );
3035 
3036 
3037  //entries
3038  QList<QgsColorRampShader::ColorRampItem> myColorRampItemList;
3039  QDomNodeList colorRampEntryList = customColorRampNode.toElement().elementsByTagName( "colorRampEntry" );
3040  for ( int i = 0; i < colorRampEntryList.size(); ++i )
3041  {
3043  QDomElement colorRampEntryElement = colorRampEntryList.at( i ).toElement();
3044  if ( colorRampEntryElement.isNull() )
3045  {
3046  continue;
3047  }
3048 
3049  myNewItem.color = QColor( colorRampEntryElement.attribute( "red" ).toInt(), colorRampEntryElement.attribute( "green" ).toInt(), colorRampEntryElement.attribute( "blue" ).toInt() );
3050  myNewItem.label = colorRampEntryElement.attribute( "label" );
3051  myNewItem.value = colorRampEntryElement.attribute( "value" ).toDouble();
3052 
3053  myColorRampItemList.push_back( myNewItem );
3054  }
3055  myColorRampShader->setColorRampItemList( myColorRampItemList );
3056  }
3057  return true;
3058 } //readSymbology
3059 
3084 bool QgsRasterLayer::readXml( QDomNode & layer_node )
3085 {
3087 
3088  //process provider key
3089  QDomNode pkeyNode = layer_node.namedItem( "provider" );
3090 
3091  if ( pkeyNode.isNull() )
3092  {
3093  mProviderKey = "gdal";
3094  }
3095  else
3096  {
3097  QDomElement pkeyElt = pkeyNode.toElement();
3098  mProviderKey = pkeyElt.text();
3099  if ( mProviderKey.isEmpty() )
3100  {
3101  mProviderKey = "gdal";
3102  }
3103  }
3104 
3105  // Open the raster source based on provider and datasource
3106 
3107  // Go down the raster-data-provider paradigm
3108 
3109  // Collect provider-specific information
3110 
3111  QDomNode rpNode = layer_node.namedItem( "rasterproperties" );
3112 
3113  // Collect sublayer names and styles
3114  mLayers.clear();
3115  mStyles.clear();
3116 
3117  if ( mProviderKey == "wms" )
3118  {
3119  QDomElement layerElement = rpNode.firstChildElement( "wmsSublayer" );
3120  while ( !layerElement.isNull() )
3121  {
3122  // TODO: sublayer visibility - post-0.8 release timeframe
3123 
3124  // collect name for the sublayer
3125  mLayers += layerElement.namedItem( "name" ).toElement().text();
3126 
3127  // collect style for the sublayer
3128  mStyles += layerElement.namedItem( "style" ).toElement().text();
3129 
3130  layerElement = layerElement.nextSiblingElement( "wmsSublayer" );
3131  }
3132 
3133  // Collect format
3134  mFormat = rpNode.namedItem( "wmsFormat" ).toElement().text();
3135  }
3136 
3137  mCrs = crs().authid();
3138  // Collect CRS
3140 
3141  QString theError;
3142  bool res = readSymbology( layer_node, theError );
3143 
3144  // old wms settings we need to correct
3145  if ( res &&
3146  mProviderKey == "wms" &&
3151  {
3153  mGrayBandName = bandName( 1 );
3154  }
3155 
3156  // Check timestamp
3157  QDomNode stampNode = layer_node.namedItem( "timestamp" );
3158  if ( !stampNode.isNull() )
3159  {
3160  QDateTime stamp = QDateTime::fromString( stampNode.toElement().text(), Qt::ISODate );
3161  // TODO: very bad, we have to load twice!!! Make QgsDataProvider::timestamp() static?
3162  if ( stamp < mDataProvider->dataTimestamp() )
3163  {
3164  QgsDebugMsg( "data changed, reload provider" );
3166  init();
3168  }
3169  }
3170 
3171  return res;
3172 } // QgsRasterLayer::readXml( QDomNode & layer_node )
3173 
3174 /*
3175  * @param QDomNode the node that will have the style element added to it.
3176  * @param QDomDocument the document that will have the QDomNode added.
3177  * @param errorMessage reference to string that will be updated with any error messages
3178  * @return true in case of success.
3179  */
3180 bool QgsRasterLayer::writeSymbology( QDomNode & layer_node, QDomDocument & document, QString& errorMessage ) const
3181 {
3182  // <rasterproperties>
3183  QDomElement rasterPropertiesElement = document.createElement( "rasterproperties" );
3184  layer_node.appendChild( rasterPropertiesElement );
3185 
3186  QStringList sl = subLayers();
3187  QStringList sls = mDataProvider->subLayerStyles();
3188 
3189  QStringList::const_iterator layerStyle = sls.begin();
3190 
3191  if ( mProviderKey == "wms" )
3192  {
3193  // <rasterproperties><wmsSublayer>
3194  for ( QStringList::const_iterator layerName = sl.begin();
3195  layerName != sl.end();
3196  ++layerName )
3197  {
3198 
3199  QgsDebugMsg( QString( "<rasterproperties><wmsSublayer> %1" ).arg( layerName->toLocal8Bit().data() ) );
3200 
3201  QDomElement sublayerElement = document.createElement( "wmsSublayer" );
3202 
3203  // TODO: sublayer visibility - post-0.8 release timeframe
3204 
3205  // <rasterproperties><wmsSublayer><name>
3206  QDomElement sublayerNameElement = document.createElement( "name" );
3207  QDomText sublayerNameText = document.createTextNode( *layerName );
3208  sublayerNameElement.appendChild( sublayerNameText );
3209  sublayerElement.appendChild( sublayerNameElement );
3210 
3211  // <rasterproperties><wmsSublayer><style>
3212  QDomElement sublayerStyleElement = document.createElement( "style" );
3213  QDomText sublayerStyleText = document.createTextNode( *layerStyle );
3214  sublayerStyleElement.appendChild( sublayerStyleText );
3215  sublayerElement.appendChild( sublayerStyleElement );
3216 
3217  rasterPropertiesElement.appendChild( sublayerElement );
3218 
3219  // This assumes there are exactly the same number of "layerName"s as there are "layerStyle"s
3220  ++layerStyle;
3221  }
3222 
3223  // <rasterproperties><wmsFormat>
3224  QDomElement formatElement = document.createElement( "wmsFormat" );
3225  QDomText formatText =
3226  document.createTextNode( mDataProvider->imageEncoding() );
3227  formatElement.appendChild( formatText );
3228  rasterPropertiesElement.appendChild( formatElement );
3229  }
3230 
3231  // <mDrawingStyle>
3232  QDomElement drawStyleElement = document.createElement( "mDrawingStyle" );
3233  QDomText drawStyleText = document.createTextNode( drawingStyleAsString() );
3234 
3235  drawStyleElement.appendChild( drawStyleText );
3236 
3237  rasterPropertiesElement.appendChild( drawStyleElement );
3238 
3239  // <colorShadingAlgorithm>
3240  QDomElement colorShadingAlgorithmElement = document.createElement( "mColorShadingAlgorithm" );
3241  QDomText colorShadingAlgorithmText = document.createTextNode( colorShadingAlgorithmAsString() );
3242 
3243  colorShadingAlgorithmElement.appendChild( colorShadingAlgorithmText );
3244 
3245  rasterPropertiesElement.appendChild( colorShadingAlgorithmElement );
3246 
3247  // <mInvertColor>
3248  QDomElement mInvertColorElement = document.createElement( "mInvertColor" );
3249 
3250  if ( invertHistogram() )
3251  {
3252  mInvertColorElement.setAttribute( "boolean", "true" );
3253  }
3254  else
3255  {
3256  mInvertColorElement.setAttribute( "boolean", "false" );
3257  }
3258 
3259  rasterPropertiesElement.appendChild( mInvertColorElement );
3260 
3261  // <mRedBandName>
3262  QDomElement mRedBandNameElement = document.createElement( "mRedBandName" );
3263  QString writtenRedBandName = redBandName();
3264  if ( writtenRedBandName == TRSTRING_NOT_SET )
3265  {
3266  // Write english "not set" only.
3267  writtenRedBandName = QSTRING_NOT_SET;
3268  }
3269  QDomText mRedBandNameText = document.createTextNode( writtenRedBandName );
3270 
3271  mRedBandNameElement.appendChild( mRedBandNameText );
3272 
3273  rasterPropertiesElement.appendChild( mRedBandNameElement );
3274 
3275 
3276  // <mGreenBandName>
3277  QDomElement mGreenBandNameElement = document.createElement( "mGreenBandName" );
3278  QString writtenGreenBandName = greenBandName();
3279  if ( writtenGreenBandName == TRSTRING_NOT_SET )
3280  {
3281  // Write english "not set" only.
3282  writtenGreenBandName = QSTRING_NOT_SET;
3283  }
3284  QDomText mGreenBandNameText = document.createTextNode( writtenGreenBandName );
3285 
3286  mGreenBandNameElement.appendChild( mGreenBandNameText );
3287 
3288  rasterPropertiesElement.appendChild( mGreenBandNameElement );
3289 
3290  // <mBlueBandName>
3291  QDomElement mBlueBandNameElement = document.createElement( "mBlueBandName" );
3292  QString writtenBlueBandName = blueBandName();
3293  if ( writtenBlueBandName == TRSTRING_NOT_SET )
3294  {
3295  // Write english "not set" only.
3296  writtenBlueBandName = QSTRING_NOT_SET;
3297  }
3298  QDomText mBlueBandNameText = document.createTextNode( writtenBlueBandName );
3299 
3300  mBlueBandNameElement.appendChild( mBlueBandNameText );
3301 
3302  rasterPropertiesElement.appendChild( mBlueBandNameElement );
3303 
3304  // <mGrayBandName>
3305  QDomElement mGrayBandNameElement = document.createElement( "mGrayBandName" );
3306  QString writtenGrayBandName = grayBandName();
3307  if ( writtenGrayBandName == TRSTRING_NOT_SET )
3308  {
3309  // Write english "not set" only.
3310  writtenGrayBandName = QSTRING_NOT_SET;
3311  }
3312  QDomText mGrayBandNameText = document.createTextNode( writtenGrayBandName );
3313 
3314  mGrayBandNameElement.appendChild( mGrayBandNameText );
3315  rasterPropertiesElement.appendChild( mGrayBandNameElement );
3316 
3317  // <mStandardDeviations>
3318  QDomElement mStandardDeviationsElement = document.createElement( "mStandardDeviations" );
3319  QDomText mStandardDeviationsText = document.createTextNode( QString::number( standardDeviations() ) );
3320 
3321  mStandardDeviationsElement.appendChild( mStandardDeviationsText );
3322 
3323  rasterPropertiesElement.appendChild( mStandardDeviationsElement );
3324 
3325  // <mUserDefinedRGBMinimumMaximum>
3326  QDomElement userDefinedRGBMinMaxFlag = document.createElement( "mUserDefinedRGBMinimumMaximum" );
3327 
3329  {
3330  userDefinedRGBMinMaxFlag.setAttribute( "boolean", "true" );
3331  }
3332  else
3333  {
3334  userDefinedRGBMinMaxFlag.setAttribute( "boolean", "false" );
3335  }
3336 
3337  rasterPropertiesElement.appendChild( userDefinedRGBMinMaxFlag );
3338 
3339  // <mRGBMinimumMaximumEstimated>
3340  QDomElement RGBMinimumMaximumEstimated = document.createElement( "mRGBMinimumMaximumEstimated" );
3341 
3343  {
3344  RGBMinimumMaximumEstimated.setAttribute( "boolean", "true" );
3345  }
3346  else
3347  {
3348  RGBMinimumMaximumEstimated.setAttribute( "boolean", "false" );
3349  }
3350 
3351  rasterPropertiesElement.appendChild( RGBMinimumMaximumEstimated );
3352 
3353  // <mUserDefinedGrayMinimumMaximum>
3354  QDomElement userDefinedGrayMinMaxFlag = document.createElement( "mUserDefinedGrayMinimumMaximum" );
3355 
3357  {
3358  userDefinedGrayMinMaxFlag.setAttribute( "boolean", "true" );
3359  }
3360  else
3361  {
3362  userDefinedGrayMinMaxFlag.setAttribute( "boolean", "false" );
3363  }
3364 
3365  rasterPropertiesElement.appendChild( userDefinedGrayMinMaxFlag );
3366 
3367  // <mGrayMinimumMaximumEstimated>
3368  QDomElement GrayMinimumMaximumEstimated = document.createElement( "mGrayMinimumMaximumEstimated" );
3369 
3371  {
3372  GrayMinimumMaximumEstimated.setAttribute( "boolean", "true" );
3373  }
3374  else
3375  {
3376  GrayMinimumMaximumEstimated.setAttribute( "boolean", "false" );
3377  }
3378 
3379  rasterPropertiesElement.appendChild( GrayMinimumMaximumEstimated );
3380 
3381  // <contrastEnhancementAlgorithm>
3382  QDomElement contrastEnhancementAlgorithmElement = document.createElement( "mContrastEnhancementAlgorithm" );
3383  QDomText contrastEnhancementAlgorithmText = document.createTextNode( contrastEnhancementAlgorithmAsString() );
3384 
3385  contrastEnhancementAlgorithmElement.appendChild( contrastEnhancementAlgorithmText );
3386 
3387  rasterPropertiesElement.appendChild( contrastEnhancementAlgorithmElement );
3388 
3389  // <minMaxValues>
3390  QList<QgsContrastEnhancement>::const_iterator it;
3391  QDomElement contrastEnhancementMinMaxValuesElement = document.createElement( "contrastEnhancementMinMaxValues" );
3392  for ( it = mContrastEnhancementList.constBegin(); it != mContrastEnhancementList.constEnd(); ++it )
3393  {
3394  QDomElement minMaxEntry = document.createElement( "minMaxEntry" );
3395  QDomElement minEntry = document.createElement( "min" );
3396  QDomElement maxEntry = document.createElement( "max" );
3397 
3398  QDomText minEntryText = document.createTextNode( QString::number( it->minimumValue() ) );
3399  minEntry.appendChild( minEntryText );
3400 
3401  QDomText maxEntryText = document.createTextNode( QString::number( it->maximumValue() ) );
3402  maxEntry.appendChild( maxEntryText );
3403 
3404  minMaxEntry.appendChild( minEntry );
3405  minMaxEntry.appendChild( maxEntry );
3406 
3407  contrastEnhancementMinMaxValuesElement.appendChild( minMaxEntry );
3408  }
3409 
3410  rasterPropertiesElement.appendChild( contrastEnhancementMinMaxValuesElement );
3411 
3412  /*
3413  * Transparency tab
3414  */
3415  // <mNodataValue>
3416  QDomElement mNoDataValueElement = document.createElement( "mNoDataValue" );
3417  QDomText mNoDataValueText = document.createTextNode( QString::number( mNoDataValue, 'f' ) );
3418  if ( mValidNoDataValue )
3419  {
3420  mNoDataValueElement.setAttribute( "mValidNoDataValue", "true" );
3421  }
3422  else
3423  {
3424  mNoDataValueElement.setAttribute( "mValidNoDataValue", "false" );
3425  }
3426 
3427  mNoDataValueElement.appendChild( mNoDataValueText );
3428 
3429  rasterPropertiesElement.appendChild( mNoDataValueElement );
3430 
3431 
3433  {
3434  QDomElement singleValuePixelListElement = document.createElement( "singleValuePixelList" );
3435 
3436  QList<QgsRasterTransparency::TransparentSingleValuePixel> myPixelList = mRasterTransparency.transparentSingleValuePixelList();
3437  QList<QgsRasterTransparency::TransparentSingleValuePixel>::iterator it;
3438  for ( it = myPixelList.begin(); it != myPixelList.end(); ++it )
3439  {
3440  QDomElement pixelListElement = document.createElement( "pixelListEntry" );
3441  pixelListElement.setAttribute( "pixelValue", QString::number( it->pixelValue, 'f' ) );
3442  pixelListElement.setAttribute( "percentTransparent", QString::number( it->percentTransparent ) );
3443 
3444  singleValuePixelListElement.appendChild( pixelListElement );
3445  }
3446 
3447  rasterPropertiesElement.appendChild( singleValuePixelListElement );
3448  }
3449 
3451  {
3452  QDomElement threeValuePixelListElement = document.createElement( "threeValuePixelList" );
3453 
3454  QList<QgsRasterTransparency::TransparentThreeValuePixel> myPixelList = mRasterTransparency.transparentThreeValuePixelList();
3455  QList<QgsRasterTransparency::TransparentThreeValuePixel>::iterator it;
3456  for ( it = myPixelList.begin(); it != myPixelList.end(); ++it )
3457  {
3458  QDomElement pixelListElement = document.createElement( "pixelListEntry" );
3459  pixelListElement.setAttribute( "red", QString::number( it->red, 'f' ) );
3460  pixelListElement.setAttribute( "green", QString::number( it->green, 'f' ) );
3461  pixelListElement.setAttribute( "blue", QString::number( it->blue, 'f' ) );
3462  pixelListElement.setAttribute( "percentTransparent", QString::number( it->percentTransparent ) );
3463 
3464  threeValuePixelListElement.appendChild( pixelListElement );
3465  }
3466 
3467  rasterPropertiesElement.appendChild( threeValuePixelListElement );
3468  }
3469 
3470  /*
3471  * Color Ramp tab
3472  */
3474  {
3475  QDomElement customColorRampElement = document.createElement( "customColorRamp" );
3476 
3477  QDomElement customColorRampType = document.createElement( "colorRampType" );
3478  QDomText customColorRampTypeText = document.createTextNode((( QgsColorRampShader* )mRasterShader->rasterShaderFunction() )->colorRampTypeAsQString() );
3479  customColorRampType.appendChild( customColorRampTypeText );
3480  customColorRampElement.appendChild( customColorRampType );
3481 
3482  QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = (( QgsColorRampShader* )mRasterShader->rasterShaderFunction() )->colorRampItemList();
3483  QList<QgsColorRampShader::ColorRampItem>::iterator it;
3484  for ( it = myColorRampItemList.begin(); it != myColorRampItemList.end(); ++it )
3485  {
3486  QDomElement colorRampEntryElement = document.createElement( "colorRampEntry" );
3487  colorRampEntryElement.setAttribute( "red", QString::number( it->color.red() ) );
3488  colorRampEntryElement.setAttribute( "green", QString::number( it->color.green() ) );
3489  colorRampEntryElement.setAttribute( "blue", QString::number( it->color.blue() ) );
3490  colorRampEntryElement.setAttribute( "value", QString::number( it->value, 'f' ) );
3491  colorRampEntryElement.setAttribute( "label", it->label );
3492 
3493  customColorRampElement.appendChild( colorRampEntryElement );
3494  }
3495 
3496  rasterPropertiesElement.appendChild( customColorRampElement );
3497  }
3498 
3499  return true;
3500 } // bool QgsRasterLayer::writeSymbology
3501 
3502 /*
3503  * virtual
3504  * @note Called by QgsMapLayer::writeXML().
3505  */
3506 bool QgsRasterLayer::writeXml( QDomNode & layer_node,
3507  QDomDocument & document )
3508 {
3509  // first get the layer element so that we can append the type attribute
3510 
3511  QDomElement mapLayerNode = layer_node.toElement();
3512 
3513  if ( mapLayerNode.isNull() || ( "maplayer" != mapLayerNode.nodeName() ) )
3514  {
3515  QgsLogger::warning( "QgsRasterLayer::writeXML() can't find <maplayer>" );
3516  return false;
3517  }
3518 
3519  mapLayerNode.setAttribute( "type", "raster" );
3520 
3521  // add provider node
3522 
3523  QDomElement provider = document.createElement( "provider" );
3524  QDomText providerText = document.createTextNode( mProviderKey );
3525  provider.appendChild( providerText );
3526  layer_node.appendChild( provider );
3527 
3528  //write out the symbology
3529  QString errorMsg;
3530  return writeSymbology( layer_node, document, errorMsg );
3531 }
3532 
3534 //
3535 // Private methods
3536 //
3538 void QgsRasterLayer::drawSingleBandColorData( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
3539  const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
3540 {
3541  QgsDebugMsg( "entered." );
3542 
3543  QgsRasterImageBuffer imageBuffer( mDataProvider, theBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
3544  imageBuffer.reset();
3545 
3546  QRgb* imageScanLine = 0;
3547  void* rasterScanLine = 0;
3548 
3549  while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine ) )
3550  {
3551  if ( mTransparencyLevel == 255 )
3552  {
3553  int size = theRasterViewPort->drawableAreaXDim * 4;
3554  memcpy( imageScanLine, rasterScanLine, size );
3555  }
3556  else
3557  {
3558  uint *p = ( uint* ) rasterScanLine;
3559  for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i )
3560  {
3561  QRgb c( *p++ );
3562 
3563  imageScanLine[ i ] = qRgba( qRed( c ), qGreen( c ), qBlue( c ), qAlpha( c ) * mTransparencyLevel / 255 );
3564  }
3565  }
3566  }
3567 }
3568 
3569 void QgsRasterLayer::drawMultiBandColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
3570  const QgsMapToPixel* theQgsMapToPixel )
3571 {
3572  QgsDebugMsg( "entered." );
3573  int myRedBandNo = bandNumber( mRedBandName );
3574  //Invalid band number, segfault prevention
3575  if ( 0 >= myRedBandNo )
3576  {
3577  return;
3578  }
3579 
3580  int myGreenBandNo = bandNumber( mGreenBandName );
3581  //Invalid band number, segfault prevention
3582  if ( 0 >= myGreenBandNo )
3583  {
3584  return;
3585  }
3586 
3587  int myBlueBandNo = bandNumber( mBlueBandName );
3588  //Invalid band number, segfault prevention
3589  if ( 0 >= myBlueBandNo )
3590  {
3591  return;
3592  }
3593 
3594  int myTransparencyBandNo = bandNumber( mTransparencyBandName );
3595  bool hasTransparencyBand = 0 < myTransparencyBandNo;
3596 
3597  int myRedType = mDataProvider->dataType( myRedBandNo );
3598  int myGreenType = mDataProvider->dataType( myGreenBandNo );
3599  int myBlueType = mDataProvider->dataType( myBlueBandNo );
3600  int myTransparencyType = hasTransparencyBand ? mDataProvider->dataType( myTransparencyBandNo ) : 0;
3601 
3602  QRgb* redImageScanLine = 0;
3603  void* redRasterScanLine = 0;
3604  QRgb* greenImageScanLine = 0;
3605  void* greenRasterScanLine = 0;
3606  QRgb* blueImageScanLine = 0;
3607  void* blueRasterScanLine = 0;
3608  QRgb* transparencyImageScanLine = 0;
3609  void* transparencyRasterScanLine = 0;
3610 
3611  QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
3612 
3613  QgsRasterBandStats myRedBandStats;
3614  QgsRasterBandStats myGreenBandStats;
3615  QgsRasterBandStats myBlueBandStats;
3616 
3617  /*
3618  * If a stetch is requested and there are no user defined Min Max values
3619  * we need to get these values from the bands themselves.
3620  *
3621  */
3623  {
3624  myRedBandStats = bandStatistics( myRedBandNo );
3625  myGreenBandStats = bandStatistics( myGreenBandNo );
3626  myBlueBandStats = bandStatistics( myBlueBandNo );
3628  setMaximumValue( myRedBandNo, myRedBandStats.mean + ( mStandardDeviations * myRedBandStats.stdDev ) );
3629  setMinimumValue( myRedBandNo, myRedBandStats.mean - ( mStandardDeviations * myRedBandStats.stdDev ) );
3630  setMaximumValue( myGreenBandNo, myGreenBandStats.mean + ( mStandardDeviations * myGreenBandStats.stdDev ) );
3631  setMinimumValue( myGreenBandNo, myGreenBandStats.mean - ( mStandardDeviations * myGreenBandStats.stdDev ) );
3632  setMaximumValue( myBlueBandNo, myBlueBandStats.mean + ( mStandardDeviations * myBlueBandStats.stdDev ) );
3633  setMinimumValue( myBlueBandNo, myBlueBandStats.mean - ( mStandardDeviations * myBlueBandStats.stdDev ) );
3634  }
3636  {
3637  //This case will be true the first time the image is loaded, so just approimate the min max to keep
3638  //from calling generate raster band stats
3640 
3641  setMinimumValue( myRedBandNo, mDataProvider->minimumValue( myRedBandNo ) );
3642  setMaximumValue( myRedBandNo, mDataProvider->maximumValue( myRedBandNo ) );
3643 
3644  setMinimumValue( myGreenBandNo, mDataProvider->minimumValue( myGreenBandNo ) );
3645  setMaximumValue( myGreenBandNo, mDataProvider->maximumValue( myGreenBandNo ) );
3646 
3647  setMinimumValue( myBlueBandNo, mDataProvider->minimumValue( myBlueBandNo ) );
3648  setMaximumValue( myBlueBandNo, mDataProvider->maximumValue( myBlueBandNo ) );
3649  }
3650 
3651  //Read and display pixels
3652  double myRedValue = 0.0;
3653  double myGreenValue = 0.0;
3654  double myBlueValue = 0.0;
3655  int myTransparencyValue = 0;
3656 
3657  int myStretchedRedValue = 0;
3658  int myStretchedGreenValue = 0;
3659  int myStretchedBlueValue = 0;
3660  int myAlphaValue = 0;
3661  QgsContrastEnhancement* myRedContrastEnhancement = contrastEnhancement( myRedBandNo );
3662  QgsContrastEnhancement* myGreenContrastEnhancement = contrastEnhancement( myGreenBandNo );
3663  QgsContrastEnhancement* myBlueContrastEnhancement = contrastEnhancement( myBlueBandNo );
3664 
3665  QgsRasterImageBuffer redImageBuffer( mDataProvider, myRedBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
3666  redImageBuffer.reset();
3667  QgsRasterImageBuffer greenImageBuffer( mDataProvider, myGreenBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
3668  greenImageBuffer.setWritingEnabled( false ); //only draw to redImageBuffer
3669  greenImageBuffer.reset();
3670  QgsRasterImageBuffer blueImageBuffer( mDataProvider, myBlueBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
3671  blueImageBuffer.setWritingEnabled( false ); //only draw to redImageBuffer
3672  blueImageBuffer.reset();
3673 
3674  QgsRasterImageBuffer *transparencyImageBuffer = 0;
3675  if ( hasTransparencyBand )
3676  {
3677  transparencyImageBuffer = new QgsRasterImageBuffer( mDataProvider, myTransparencyBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
3678  transparencyImageBuffer->setWritingEnabled( false ); //only draw to redImageBuffer
3679  transparencyImageBuffer->reset();
3680  }
3681 
3682  while ( redImageBuffer.nextScanLine( &redImageScanLine, &redRasterScanLine )
3683  && greenImageBuffer.nextScanLine( &greenImageScanLine, &greenRasterScanLine )
3684  && blueImageBuffer.nextScanLine( &blueImageScanLine, &blueRasterScanLine )
3685  && ( !transparencyImageBuffer || transparencyImageBuffer->nextScanLine( &transparencyImageScanLine, &transparencyRasterScanLine ) ) )
3686  {
3687  for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i )
3688  {
3689  if ( transparencyImageBuffer )
3690  {
3691  myTransparencyValue = readValue( transparencyRasterScanLine, myTransparencyType, i );
3692  if ( 0 == myTransparencyValue )
3693  {
3694  redImageScanLine[ i ] = myDefaultColor;
3695  continue;
3696  }
3697  }
3698 
3699  myRedValue = readValue( redRasterScanLine, myRedType, i );
3700  myGreenValue = readValue( greenRasterScanLine, myGreenType, i );
3701  myBlueValue = readValue( blueRasterScanLine, myBlueType, i );
3702 
3703  if ( mValidNoDataValue &&
3704  (
3705  ( qAbs( myRedValue - mNoDataValue ) <= TINY_VALUE || myRedValue != myRedValue ) ||
3706  ( qAbs( myGreenValue - mNoDataValue ) <= TINY_VALUE || myGreenValue != myGreenValue ) ||
3707  ( qAbs( myBlueValue - mNoDataValue ) <= TINY_VALUE || myBlueValue != myBlueValue )
3708  )
3709  )
3710  {
3711  redImageScanLine[ i ] = myDefaultColor;
3712  continue;
3713  }
3714 
3716  ( !myRedContrastEnhancement->isValueInDisplayableRange( myRedValue ) ||
3717  !myGreenContrastEnhancement->isValueInDisplayableRange( myGreenValue ) ||
3718  !myBlueContrastEnhancement->isValueInDisplayableRange( myBlueValue ) ) )
3719  {
3720  redImageScanLine[ i ] = myDefaultColor;
3721  continue;
3722  }
3723 
3724  myAlphaValue = mRasterTransparency.alphaValue( myRedValue, myGreenValue, myBlueValue, mTransparencyLevel );
3725  if ( 0 == myAlphaValue )
3726  {
3727  redImageScanLine[ i ] = myDefaultColor;
3728  continue;
3729  }
3730 
3732  {
3733  myStretchedRedValue = myRedValue;
3734  myStretchedGreenValue = myGreenValue;
3735  myStretchedBlueValue = myBlueValue;
3736  }
3737  else
3738  {
3739  myStretchedRedValue = myRedContrastEnhancement->enhanceContrast( myRedValue );
3740  myStretchedGreenValue = myGreenContrastEnhancement->enhanceContrast( myGreenValue );
3741  myStretchedBlueValue = myBlueContrastEnhancement->enhanceContrast( myBlueValue );
3742  }
3743 
3744  if ( mInvertColor )
3745  {
3746  myStretchedRedValue = 255 - myStretchedRedValue;
3747  myStretchedGreenValue = 255 - myStretchedGreenValue;
3748  myStretchedBlueValue = 255 - myStretchedBlueValue;
3749  }
3750 
3751  if ( myTransparencyValue )
3752  myAlphaValue *= myTransparencyValue / 255.0;
3753 
3754  redImageScanLine[ i ] = qRgba( myStretchedRedValue, myStretchedGreenValue, myStretchedBlueValue, myAlphaValue );
3755  }
3756  }
3757 
3758  if ( transparencyImageBuffer )
3759  delete transparencyImageBuffer;
3760 }
3761 
3762 void QgsRasterLayer::drawMultiBandSingleBandGray( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
3763  const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
3764 {
3765  //delegate to drawSingleBandGray!
3766  drawSingleBandGray( theQPainter, theRasterViewPort, theQgsMapToPixel, theBandNo );
3767 }
3768 
3769 void QgsRasterLayer::drawMultiBandSingleBandPseudoColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
3770  const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
3771 {
3772  //delegate to drawSinglePseudocolor!
3773  drawSingleBandPseudoColor( theQPainter, theRasterViewPort, theQgsMapToPixel, theBandNo );
3774 }
3775 
3783 void QgsRasterLayer::drawPalettedSingleBandColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
3784  const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
3785 {
3786  QgsDebugMsg( "entered." );
3787  //Invalid band number, segfault prevention
3788  if ( 0 >= theBandNo )
3789  {
3790  return;
3791  }
3792 
3793  int myTransparencyBandNo = bandNumber( mTransparencyBandName );
3794  bool hasTransparencyBand = 0 < myTransparencyBandNo;
3795 
3796  if ( NULL == mRasterShader )
3797  {
3798  return;
3799  }
3800 
3801  int myDataType = mDataProvider->dataType( theBandNo );
3802  int myTransparencyType = hasTransparencyBand ? mDataProvider->dataType( myTransparencyBandNo ) : 0;
3803 
3804  QgsRasterImageBuffer imageBuffer( mDataProvider, theBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
3805  imageBuffer.reset();
3806 
3807  QgsRasterImageBuffer *transparencyImageBuffer = 0;
3808  if ( hasTransparencyBand )
3809  {
3810  transparencyImageBuffer = new QgsRasterImageBuffer( mDataProvider, myTransparencyBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
3811  transparencyImageBuffer->setWritingEnabled( false ); //only draw to imageBuffer
3812  transparencyImageBuffer->reset();
3813  }
3814 
3815  QRgb* imageScanLine = 0;
3816  void* rasterScanLine = 0;
3817  QRgb* transparencyImageScanLine = 0;
3818  void* transparencyRasterScanLine = 0;
3819 
3820  QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
3821  double myPixelValue = 0.0;
3822  int myRedValue = 0;
3823  int myGreenValue = 0;
3824  int myBlueValue = 0;
3825  int myTransparencyValue = 0;
3826  int myAlphaValue = 0;
3827 
3828  while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine )
3829  && ( !transparencyImageBuffer || transparencyImageBuffer->nextScanLine( &transparencyImageScanLine, &transparencyRasterScanLine ) ) )
3830  {
3831  for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i )
3832  {
3833  if ( transparencyImageBuffer )
3834  {
3835  myTransparencyValue = readValue( transparencyRasterScanLine, myTransparencyType, i );
3836  if ( 0 == myTransparencyValue )
3837  {
3838  imageScanLine[ i ] = myDefaultColor;
3839  continue;
3840  }
3841  }
3842 
3843  myRedValue = 0;
3844  myGreenValue = 0;
3845  myBlueValue = 0;
3846  //myPixelValue = readValue( rasterScanLine, ( GDALDataType )myDataType, i );
3847  myPixelValue = readValue( rasterScanLine, myDataType, i );
3848 
3849  if ( mValidNoDataValue && ( qAbs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) )
3850  {
3851  imageScanLine[ i ] = myDefaultColor;
3852  continue;
3853  }
3854 
3855  myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel );
3856  if ( 0 == myAlphaValue )
3857  {
3858  imageScanLine[ i ] = myDefaultColor;
3859  continue;
3860  }
3861 
3862  if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) )
3863  {
3864  imageScanLine[ i ] = myDefaultColor;
3865  continue;
3866  }
3867 
3868  if ( myTransparencyValue )
3869  myAlphaValue *= myTransparencyValue / 255.0;
3870 
3871  if ( mInvertColor )
3872  {
3873  //Invert flag, flip blue and red
3874  imageScanLine[ i ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue );
3875  }
3876  else
3877  {
3878  //Normal
3879  imageScanLine[ i ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue );
3880  }
3881  }
3882  }
3883 
3884  if ( transparencyImageBuffer )
3885  delete transparencyImageBuffer;
3886 }
3887 
3895 void QgsRasterLayer::drawPalettedSingleBandGray( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
3896  const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
3897 {
3898  QgsDebugMsg( "entered." );
3899  //Invalid band number, segfault prevention
3900  if ( 0 >= theBandNo )
3901  {
3902  return;
3903  }
3904 
3905  int myTransparencyBandNo = bandNumber( mTransparencyBandName );
3906  bool hasTransparencyBand = 0 < myTransparencyBandNo;
3907 
3908  if ( NULL == mRasterShader )
3909  {
3910  return;
3911  }
3912 
3913  int myDataType = mDataProvider->dataType( theBandNo );
3914  int myTransparencyType = hasTransparencyBand ? mDataProvider->dataType( myTransparencyBandNo ) : 0;
3915 
3916  QgsRasterImageBuffer imageBuffer( mDataProvider, theBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
3917  imageBuffer.reset();
3918 
3919  QgsRasterImageBuffer *transparencyImageBuffer = 0;
3920  if ( hasTransparencyBand )
3921  {
3922  transparencyImageBuffer = new QgsRasterImageBuffer( mDataProvider, myTransparencyBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
3923  transparencyImageBuffer->setWritingEnabled( false ); //only draw to redImageBuffer
3924  transparencyImageBuffer->reset();
3925  }
3926 
3927  QRgb* imageScanLine = 0;
3928  void* rasterScanLine = 0;
3929  QRgb* transparencyImageScanLine = 0;
3930  void* transparencyRasterScanLine = 0;
3931 
3932  QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
3933  double myPixelValue = 0.0;
3934  int myRedValue = 0;
3935  int myGreenValue = 0;
3936  int myBlueValue = 0;
3937  int myTransparencyValue = 0;
3938  int myAlphaValue = 0;
3939 
3940  while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine )
3941  && ( !transparencyImageBuffer || transparencyImageBuffer->nextScanLine( &transparencyImageScanLine, &transparencyRasterScanLine ) ) )
3942  {
3943  for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i )
3944  {
3945  if ( transparencyImageBuffer )
3946  {
3947  myTransparencyValue = readValue( transparencyRasterScanLine, myTransparencyType, i );
3948  if ( 0 == myTransparencyValue )
3949  {
3950  imageScanLine[ i ] = myDefaultColor;
3951  continue;
3952  }
3953  }
3954 
3955  myRedValue = 0;
3956  myGreenValue = 0;
3957  myBlueValue = 0;
3958  //myPixelValue = readValue( rasterScanLine, ( GDALDataType )myDataType, i );
3959  myPixelValue = readValue( rasterScanLine, myDataType, i );
3960 
3961  if ( mValidNoDataValue && ( qAbs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) )
3962  {
3963  imageScanLine[ i ] = myDefaultColor;
3964  continue;
3965  }
3966 
3967  myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel );
3968  if ( 0 == myAlphaValue )
3969  {
3970  imageScanLine[ i ] = myDefaultColor;
3971  continue;
3972  }
3973 
3974  if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) )
3975  {
3976  imageScanLine[ i ] = myDefaultColor;
3977  continue;
3978  }
3979 
3980  if ( myTransparencyValue )
3981  myAlphaValue *= myTransparencyValue / 255.0;
3982 
3983  if ( mInvertColor )
3984  {
3985  //Invert flag, flip blue and red
3986  double myGrayValue = ( 0.3 * ( double )myRedValue ) + ( 0.59 * ( double )myGreenValue ) + ( 0.11 * ( double )myBlueValue );
3987  imageScanLine[ i ] = qRgba(( int )myGrayValue, ( int )myGrayValue, ( int )myGrayValue, myAlphaValue );
3988  }
3989  else
3990  {
3991  //Normal
3992  double myGrayValue = ( 0.3 * ( double )myBlueValue ) + ( 0.59 * ( double )myGreenValue ) + ( 0.11 * ( double )myRedValue );
3993  imageScanLine[ i ] = qRgba(( int )myGrayValue, ( int )myGrayValue, ( int )myGrayValue, myAlphaValue );
3994  }
3995  }
3996  }
3997 
3998  if ( transparencyImageBuffer )
3999  delete transparencyImageBuffer;
4000 }
4001 
4010 void QgsRasterLayer::drawPalettedSingleBandPseudoColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
4011  const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
4012 {
4013  QgsDebugMsg( "entered." );
4014  //Invalid band number, segfault prevention
4015  if ( 0 >= theBandNo )
4016  {
4017  return;
4018  }
4019 
4020  int myTransparencyBandNo = bandNumber( mTransparencyBandName );
4021  bool hasTransparencyBand = 0 < myTransparencyBandNo;
4022 
4023  if ( NULL == mRasterShader )
4024  {
4025  return;
4026  }
4027 
4028  QgsRasterBandStats myRasterBandStats = bandStatistics( theBandNo );
4029  int myDataType = mDataProvider->dataType( theBandNo );
4030  int myTransparencyType = hasTransparencyBand ? mDataProvider->dataType( myTransparencyBandNo ) : 0;
4031 
4032  QgsRasterImageBuffer imageBuffer( mDataProvider, theBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
4033  imageBuffer.reset();
4034 
4035  QgsRasterImageBuffer *transparencyImageBuffer = 0;
4036  if ( hasTransparencyBand )
4037  {
4038  transparencyImageBuffer = new QgsRasterImageBuffer( mDataProvider, myTransparencyBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
4039  transparencyImageBuffer->setWritingEnabled( false ); //only draw to imageBuffer
4040  transparencyImageBuffer->reset();
4041  }
4042 
4043  QRgb* imageScanLine = 0;
4044  void* rasterScanLine = 0;
4045  QRgb* transparencyImageScanLine = 0;
4046  void* transparencyRasterScanLine = 0;
4047 
4048  QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
4049  double myMinimumValue = 0.0;
4050  double myMaximumValue = 0.0;
4051  //Use standard deviations if set, otherwise, use min max of band
4052  if ( mStandardDeviations > 0 )
4053  {
4054  myMinimumValue = ( myRasterBandStats.mean - ( mStandardDeviations * myRasterBandStats.stdDev ) );
4055  myMaximumValue = ( myRasterBandStats.mean + ( mStandardDeviations * myRasterBandStats.stdDev ) );
4056  }
4057  else
4058  {
4059  myMinimumValue = myRasterBandStats.minimumValue;
4060  myMaximumValue = myRasterBandStats.maximumValue;
4061  }
4062 
4063  mRasterShader->setMinimumValue( myMinimumValue );
4064  mRasterShader->setMaximumValue( myMaximumValue );
4065 
4066  double myPixelValue = 0.0;
4067  int myRedValue = 0;
4068  int myGreenValue = 0;
4069  int myBlueValue = 0;
4070  int myTransparencyValue = 0;
4071  int myAlphaValue = 0;
4072 
4073  while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine )
4074  && ( !transparencyImageBuffer || transparencyImageBuffer->nextScanLine( &transparencyImageScanLine, &transparencyRasterScanLine ) ) )
4075  {
4076  for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i )
4077  {
4078  if ( transparencyImageBuffer )
4079  {
4080  myTransparencyValue = readValue( transparencyRasterScanLine, myTransparencyType, i );
4081  if ( 0 == myTransparencyValue )
4082  {
4083  imageScanLine[ i ] = myDefaultColor;
4084  continue;
4085  }
4086  }
4087 
4088  myPixelValue = readValue( rasterScanLine, myDataType, i );
4089 
4090  if ( mValidNoDataValue && ( qAbs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) )
4091  {
4092  imageScanLine[ i ] = myDefaultColor;
4093  continue;
4094  }
4095 
4096  myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel );
4097  if ( 0 == myAlphaValue )
4098  {
4099  imageScanLine[ i ] = myDefaultColor;
4100  continue;
4101  }
4102 
4103  if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) )
4104  {
4105  imageScanLine[ i ] = myDefaultColor;
4106  continue;
4107  }
4108 
4109  if ( myTransparencyValue )
4110  myAlphaValue *= myTransparencyValue / 255.0;
4111 
4112  if ( mInvertColor )
4113  {
4114  //Invert flag, flip blue and red
4115  imageScanLine[ i ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue );
4116  }
4117  else
4118  {
4119  //Normal
4120  imageScanLine[ i ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue );
4121  }
4122  }
4123  }
4124 
4125  if ( transparencyImageBuffer )
4126  delete transparencyImageBuffer;
4127 }
4128 
4137 void QgsRasterLayer::drawPalettedMultiBandColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
4138  const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
4139 {
4140  QgsDebugMsg( "Not supported at this time" );
4141 }
4142 
4143 void QgsRasterLayer::drawSingleBandGray( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
4144  const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
4145 {
4146  QgsDebugMsg( "layer=" + QString::number( theBandNo ) );
4147  //Invalid band number, segfault prevention
4148  if ( 0 >= theBandNo )
4149  {
4150  return;
4151  }
4152 
4153  int myTransparencyBandNo = bandNumber( mTransparencyBandName );
4154  bool hasTransparencyBand = 0 < myTransparencyBandNo;
4155 
4156  int myDataType = mDataProvider->dataType( theBandNo );
4157  QgsDebugMsg( "myDataType = " + QString::number( myDataType ) );
4158  int myTransparencyType = hasTransparencyBand ? mDataProvider->dataType( myTransparencyBandNo ) : 0;
4159 
4160  QgsRasterImageBuffer imageBuffer( mDataProvider, theBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
4161  imageBuffer.reset();
4162 
4163  QgsRasterImageBuffer *transparencyImageBuffer = 0;
4164  if ( hasTransparencyBand )
4165  {
4166  transparencyImageBuffer = new QgsRasterImageBuffer( mDataProvider, myTransparencyBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
4167  transparencyImageBuffer->setWritingEnabled( false ); //only draw to imageBuffer
4168  transparencyImageBuffer->reset();
4169  }
4170 
4171  QRgb* imageScanLine = 0;
4172  void* rasterScanLine = 0;
4173  QRgb* transparencyImageScanLine = 0;
4174  void* transparencyRasterScanLine = 0;
4175 
4176  QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
4177  double myGrayValue = 0.0;
4178  int myGrayVal = 0;
4179  int myTransparencyValue = 0;
4180  int myAlphaValue = 0;
4181  QgsContrastEnhancement* myContrastEnhancement = contrastEnhancement( theBandNo );
4182 
4183  QgsRasterBandStats myGrayBandStats;
4184  //myGrayBandStats = bandStatistics( theBandNo ); // debug
4186  {
4188  myGrayBandStats = bandStatistics( theBandNo );
4189  setMaximumValue( theBandNo, myGrayBandStats.mean + ( mStandardDeviations * myGrayBandStats.stdDev ) );
4190  setMinimumValue( theBandNo, myGrayBandStats.mean - ( mStandardDeviations * myGrayBandStats.stdDev ) );
4191  }
4193  {
4194  //This case will be true the first time the image is loaded, so just approimate the min max to keep
4195  //from calling generate raster band stats
4197  setMaximumValue( theBandNo, mDataProvider->maximumValue( theBandNo ) );
4198  setMinimumValue( theBandNo, mDataProvider->minimumValue( theBandNo ) );
4199  }
4200 
4201  QgsDebugMsg( " -> imageBuffer.nextScanLine" );
4202  while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine )
4203  && ( !transparencyImageBuffer || transparencyImageBuffer->nextScanLine( &transparencyImageScanLine, &transparencyRasterScanLine ) ) )
4204  {
4205  //QgsDebugMsg( " rendering line");
4206  for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i )
4207  {
4208  if ( transparencyImageBuffer )
4209  {
4210  myTransparencyValue = readValue( transparencyRasterScanLine, myTransparencyType, i );
4211  if ( 0 == myTransparencyValue )
4212  {
4213  imageScanLine[ i ] = myDefaultColor;
4214  continue;
4215  }
4216  }
4217 
4218  myGrayValue = readValue( rasterScanLine, myDataType, i );
4219  //QgsDebugMsg( QString( "i = %1 myGrayValue = %2 ").arg(i).arg( myGrayValue ) );
4220  //if ( myGrayValue != -2147483647 ) {
4221  //QgsDebugMsg( "myGrayValue = " + QString::number( myGrayValue ) );
4222  //}
4223 
4224  if ( mValidNoDataValue && ( qAbs( myGrayValue - mNoDataValue ) <= TINY_VALUE || myGrayValue != myGrayValue ) )
4225  {
4226  imageScanLine[ i ] = myDefaultColor;
4227  continue;
4228  }
4229 
4230  if ( !myContrastEnhancement->isValueInDisplayableRange( myGrayValue ) )
4231  {
4232  imageScanLine[ i ] = myDefaultColor;
4233  continue;
4234  }
4235 
4236  myAlphaValue = mRasterTransparency.alphaValue( myGrayValue, mTransparencyLevel );
4237  if ( 0 == myAlphaValue )
4238  {
4239  imageScanLine[ i ] = myDefaultColor;
4240  continue;
4241  }
4242 
4243 
4244  myGrayVal = myContrastEnhancement->enhanceContrast( myGrayValue );
4245 
4246  if ( mInvertColor )
4247  {
4248  myGrayVal = 255 - myGrayVal;
4249  }
4250 
4251  if ( myTransparencyValue )
4252  myAlphaValue *= myTransparencyValue / 255.0;
4253 
4254  //QgsDebugMsg( QString( "i = %1 myGrayValue = %2 myGrayVal = %3 myAlphaValue = %4").arg(i).arg( myGrayValue ).arg(myGrayVal).arg(myAlphaValue) );
4255  imageScanLine[ i ] = qRgba( myGrayVal, myGrayVal, myGrayVal, myAlphaValue );
4256  }
4257  }
4258 
4259  if ( transparencyImageBuffer )
4260  delete transparencyImageBuffer;
4261 } // QgsRasterLayer::drawSingleBandGray
4262 
4263 void QgsRasterLayer::drawSingleBandPseudoColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
4264  const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
4265 {
4266  QgsDebugMsg( "entered." );
4267  //Invalid band number, segfault prevention
4268  if ( 0 >= theBandNo )
4269  {
4270  return;
4271  }
4272 
4273  int myTransparencyBandNo = bandNumber( mTransparencyBandName );
4274  bool hasTransparencyBand = 0 < myTransparencyBandNo;
4275 
4276  if ( NULL == mRasterShader )
4277  {
4278  return;
4279  }
4280 
4281  QgsRasterBandStats myRasterBandStats = bandStatistics( theBandNo );
4282  int myDataType = mDataProvider->dataType( theBandNo );
4283  int myTransparencyType = hasTransparencyBand ? mDataProvider->dataType( myTransparencyBandNo ) : 0;
4284 
4285  QgsRasterImageBuffer imageBuffer( mDataProvider, theBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
4286  imageBuffer.reset();
4287 
4288  QgsRasterImageBuffer *transparencyImageBuffer = 0;
4289  if ( hasTransparencyBand )
4290  {
4291  transparencyImageBuffer = new QgsRasterImageBuffer( mDataProvider, myTransparencyBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
4292  transparencyImageBuffer->setWritingEnabled( false ); //only draw to imageBuffer
4293  transparencyImageBuffer->reset();
4294  }
4295 
4296  QRgb* imageScanLine = 0;
4297  void* rasterScanLine = 0;
4298  QRgb* transparencyImageScanLine = 0;
4299  void* transparencyRasterScanLine = 0;
4300 
4301  QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
4302 
4303  double myMinimumValue = 0.0;
4304  double myMaximumValue = 0.0;
4305  //Use standard deviations if set, otherwise, use min max of band
4306  if ( mStandardDeviations > 0 )
4307  {
4308  myMinimumValue = ( myRasterBandStats.mean - ( mStandardDeviations * myRasterBandStats.stdDev ) );
4309  myMaximumValue = ( myRasterBandStats.mean + ( mStandardDeviations * myRasterBandStats.stdDev ) );
4310  }
4311  else
4312  {
4313  myMinimumValue = myRasterBandStats.minimumValue;
4314  myMaximumValue = myRasterBandStats.maximumValue;
4315  }
4316 
4317  mRasterShader->setMinimumValue( myMinimumValue );
4318  mRasterShader->setMaximumValue( myMaximumValue );
4319 
4320  int myRedValue = 255;
4321  int myGreenValue = 255;
4322  int myBlueValue = 255;
4323  int myTransparencyValue = 0;
4324 
4325  double myPixelValue = 0.0;
4326  int myAlphaValue = 0;
4327 
4328  while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine )
4329  && ( !transparencyImageBuffer || transparencyImageBuffer->nextScanLine( &transparencyImageScanLine, &transparencyRasterScanLine ) ) )
4330  {
4331  for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i )
4332  {
4333  if ( transparencyImageBuffer )
4334  {
4335  myTransparencyValue = readValue( transparencyRasterScanLine, myTransparencyType, i );
4336  if ( 0 == myTransparencyValue )
4337  {
4338  imageScanLine[ i ] = myDefaultColor;
4339  continue;
4340  }
4341  }
4342 
4343  myPixelValue = readValue( rasterScanLine, myDataType, i );
4344 
4345  if ( mValidNoDataValue && ( qAbs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) )
4346  {
4347  imageScanLine[ i ] = myDefaultColor;
4348  continue;
4349  }
4350 
4351  myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel );
4352  if ( 0 == myAlphaValue )
4353  {
4354  imageScanLine[ i ] = myDefaultColor;
4355  continue;
4356  }
4357 
4358  if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) )
4359  {
4360  imageScanLine[ i ] = myDefaultColor;
4361  continue;
4362  }
4363 
4364  if ( myTransparencyValue )
4365  myAlphaValue *= myTransparencyValue / 255.0;
4366 
4367  if ( mInvertColor )
4368  {
4369  //Invert flag, flip blue and red
4370  imageScanLine[ i ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue );
4371  }
4372  else
4373  {
4374  //Normal
4375  imageScanLine[ i ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue );
4376  //QgsDebugMsg ( QString ( "%1 value : %2 rgba : %3 %4 %5 %6" ).arg (i).arg( myPixelValue ).arg(myRedValue).arg(myGreenValue).arg(myBlueValue).arg(myAlphaValue) );
4377  }
4378  }
4379  }
4380 
4381  if ( transparencyImageBuffer )
4382  delete transparencyImageBuffer;
4383 }
4384 
4385 #if 0
4386 QString QgsRasterLayer::generateBandName( int theBandNumber )
4387 {
4388  return tr( "Band" ) + QString( " %1" ) .arg( theBandNumber, 1 + ( int ) log10(( float ) bandCount() ), 10, QChar( '0' ) );
4389 }
4390 #endif
4391 
4396 bool QgsRasterLayer::hasBand( QString const & theBandName )
4397 {
4398  //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
4399  QgsDebugMsg( "Looking for band : " + theBandName );
4400 
4401  for ( int i = 1; i <= mDataProvider->bandCount(); i++ )
4402  {
4403  QString myColorQString = mDataProvider->colorInterpretationName( i );
4404 #ifdef QGISDEBUG
4405  QgsLogger::debug( "band", i, __FILE__, __FUNCTION__, __LINE__, 2 );
4406 #endif
4407 
4408  if ( myColorQString == theBandName )
4409  {
4410 #ifdef QGISDEBUG
4411  QgsLogger::debug( "band", i, __FILE__, __FUNCTION__, __LINE__, 2 );
4412  QgsDebugMsgLevel( "Found band : " + theBandName, 2 );
4413 #endif
4414 
4415  return true;
4416  }
4417  QgsDebugMsgLevel( "Found unmatched band : " + QString::number( i ) + " " + myColorQString, 2 );
4418  }
4419  return false;
4420 }
4421 
4423 {
4424  // TODO: where is it used? It would be better to use crs.
4425  return mDataProvider->crs().toWkt();
4426 }
4427 
4428 /*
4429  *data type is the same as raster band. The memory must be released later!
4430  * \return pointer to the memory
4431  */
4432 void *QgsRasterLayer::readData( int bandNo, QgsRasterViewPort *viewPort )
4433 {
4434  int size = mDataProvider->dataTypeSize( bandNo ) / 8;
4435 
4436 #if 0
4437  QgsDebugMsg( "calling RasterIO with " +
4438  QString( ", source NW corner: " ) + QString::number( viewPort->rectXOffset ) +
4439  ", " + QString::number( viewPort->rectYOffset ) +
4440  ", source size: " + QString::number( viewPort->clippedWidth ) +
4441  ", " + QString::number( viewPort->clippedHeight ) +
4442  ", dest size: " + QString::number( viewPort->drawableAreaXDim ) +
4443  ", " + QString::number( viewPort->drawableAreaYDim ) );
4444 #endif
4445  void *data = VSIMalloc( size * viewPort->drawableAreaXDim * viewPort->drawableAreaYDim );
4446 
4447  /* Abort if out of memory */
4448  if ( data == NULL )
4449  {
4450  QgsDebugMsg( "Layer " + name() + " couldn't allocate enough memory. Ignoring" );
4451  }
4452  else
4453  {
4454  // TODO: check extent
4455  QgsRectangle partExtent(
4456  viewPort->mDrawnExtent.xMinimum(),
4457  viewPort->mDrawnExtent.yMinimum(),
4458  viewPort->mDrawnExtent.xMaximum(),
4459  viewPort->mDrawnExtent.yMaximum()
4460  );
4461  mDataProvider->readBlock( bandNo, partExtent, viewPort->drawableAreaXDim, viewPort->drawableAreaYDim, viewPort->mSrcCRS, viewPort->mDestCRS, data );
4462  }
4463  return data;
4464 }
4465 
4466 /*
4467  * @note Called from ctor if a raster image given there
4468  *
4469  * @param theFilename absolute path and filename of the raster to be loaded
4470  * @returns true if successfully read file
4471  */
4472 bool QgsRasterLayer::readFile( QString const &theFilename )
4473 {
4474  mValid = false;
4475  return true;
4476 } // QgsRasterLayer::readFile
4477 
4478 /*
4479  * @param index index in memory block
4480  */
4481 double QgsRasterLayer::readValue( void *data, int type, int index )
4482 {
4483  if ( !data )
4484  return mValidNoDataValue ? mNoDataValue : 0.0;
4485 
4486  switch ( type )
4487  {
4489  return ( double )(( GByte * )data )[index];
4490  break;
4492  return ( double )(( GUInt16 * )data )[index];
4493  break;
4495  return ( double )(( GInt16 * )data )[index];
4496  break;
4498  return ( double )(( GUInt32 * )data )[index];
4499  break;
4501  return ( double )(( GInt32 * )data )[index];
4502  break;
4504  return ( double )(( float * )data )[index];
4505  break;
4507  return ( double )(( double * )data )[index];
4508  break;
4509  default:
4510  QgsLogger::warning( "GDAL data type is not supported" );
4511  }
4512 
4513  return mValidNoDataValue ? mNoDataValue : 0.0;
4514 }
4515 
4517 {
4518  QgsDebugMsg( "entered." );
4519  // Check if data changed
4521  {
4522  QgsDebugMsg( "reload data" );
4524  init();
4526  emit dataChanged();
4527  }
4528  return mValid;
4529 }
4530 
4532 {
4533  return !mProviderKey.isEmpty();
4534 }
4535 
4536 QString QgsRasterLayer::validateBandName( QString const & theBandName )
4537 {
4538  QgsDebugMsg( "Checking..." );
4539  //check if the band is unset
4540  if ( theBandName == TRSTRING_NOT_SET || theBandName == QSTRING_NOT_SET )
4541  {
4542  QgsDebugMsg( "Band name is '" + QSTRING_NOT_SET + "'. Nothing to do." );
4543  // Use translated name internally
4544  return TRSTRING_NOT_SET;
4545  }
4546 
4547  //check that a valid band name was passed
4548  QgsDebugMsg( "Looking through raster band stats for matching band name" );
4549  for ( int myIterator = 0; myIterator < mRasterStatsList.size(); ++myIterator )
4550  {
4551  //find out the name of this band
4552  if ( mRasterStatsList[myIterator].bandName == theBandName )
4553  {
4554  QgsDebugMsg( "Matching band name found" );
4555  return theBandName;
4556  }
4557  }
4558  QgsDebugMsg( "No matching band name found in raster band stats" );
4559 
4560  QgsDebugMsg( "Testing for non zero-buffered names" );
4561  //TODO Remove test in v2.0 or earlier
4562  QStringList myBandNameComponents = theBandName.split( " " );
4563  if ( myBandNameComponents.size() == 2 )
4564  {
4565  int myBandNumber = myBandNameComponents.at( 1 ).toInt();
4566  if ( myBandNumber > 0 )
4567  {
4568  QString myBandName = mDataProvider->generateBandName( myBandNumber );
4569  for ( int myIterator = 0; myIterator < mRasterStatsList.size(); ++myIterator )
4570  {
4571  //find out the name of this band
4572  if ( mRasterStatsList[myIterator].bandName == myBandName )
4573  {
4574  QgsDebugMsg( "Matching band name found" );
4575  return myBandName;
4576  }
4577  }
4578  }
4579  }
4580 
4581  QgsDebugMsg( "Testing older naming format" );
4582  //See of the band in an older format #:something.
4583  //TODO Remove test in v2.0 or earlier
4584  myBandNameComponents.clear();
4585  if ( theBandName.contains( ':' ) )
4586  {
4587  myBandNameComponents = theBandName.split( ":" );
4588  if ( myBandNameComponents.size() == 2 )
4589  {
4590  int myBandNumber = myBandNameComponents.at( 0 ).toInt();
4591  if ( myBandNumber > 0 )
4592  {
4593  QgsDebugMsg( "Transformed older name format to current format" );
4594  return "Band " + QString::number( myBandNumber );
4595  }
4596  }
4597  }
4598 
4599  //if no matches were found default to not set
4600  QgsDebugMsg( "All checks failed, returning '" + QSTRING_NOT_SET + "'" );
4601  return TRSTRING_NOT_SET;
4602 }
4603 
4604 QgsRasterImageBuffer::QgsRasterImageBuffer( QgsRasterDataProvider *dataProvider, int bandNo, QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* mapToPixel, double* geoTransform ):
4605  mDataProvider( dataProvider ), mBandNo( bandNo ), mPainter( p ), mViewPort( viewPort ), mMapToPixel( mapToPixel ), mGeoTransform( geoTransform ), mValid( false ), mWritingEnabled( true ), mDrawPixelRect( false ), mCurrentImage( 0 ), mCurrentGDALData( 0 )
4606 {
4607 
4608 }
4609 
4611 {
4612  delete mCurrentImage;
4613  CPLFree( mCurrentGDALData );
4614 }
4615 
4616 void QgsRasterImageBuffer::reset( int maxPixelsInVirtualMemory )
4617 {
4618  QgsDebugMsg( "Start" );
4619  //if ( !mRasterBand || !mPainter || !mViewPort )
4620  if ( !mDataProvider || mBandNo <= 0 || !mPainter || !mViewPort )
4621  {
4622  mValid = false;
4623  return;
4624  }
4625 
4626  mValid = true;
4627 
4628  //decide on the partition of the image
4629 
4631  int mNumPartImages = pixels / maxPixelsInVirtualMemory + 1.0;
4632  mNumRasterRowsPerPart = ( double )mViewPort->drawableAreaYDim / ( double )mNumPartImages + 0.5;
4633 
4634  mCurrentPartRasterMin = -1;
4635  mCurrentPartRasterMax = -1;
4638 
4639  mCurrentPart = 0;
4640 
4642 
4643  // TODO
4644  //if ( 2 >= mViewPort->clippedWidth && 2 >= mViewPort->clippedHeight )
4645  if ( false )
4646  {
4647  //use Peter's fix for zoomed in rasters
4648  mDrawPixelRect = true;
4649  }
4650 }
4651 
4652 bool QgsRasterImageBuffer::nextScanLine( QRgb** imageScanLine, void** rasterScanLine )
4653 {
4654  //QgsDebugMsg( "mCurrentRow = " + QString::number( mCurrentRow ) );
4655  if ( !mValid )
4656  return false;
4657 
4658  if ( !mCurrentImage && !mCurrentGDALData )
4659  {
4660  return false;
4661  }
4662 
4664  {
4665  if ( !createNextPartImage() )
4666  {
4667  return false;
4668  }
4669  }
4670 
4671  if ( mWritingEnabled )
4672  {
4673  *imageScanLine = ( QRgb* ) mCurrentImage->scanLine( mCurrentPartImageRow );
4674  }
4675  else
4676  {
4677  *imageScanLine = 0;
4678  }
4679  int size = mDataProvider->dataTypeSize( mBandNo ) / 8;
4680  *rasterScanLine = ( unsigned char * )mCurrentGDALData + mCurrentPartImageRow * mViewPort->drawableAreaXDim * size;
4681 
4683  ++mCurrentRow;
4684  return !mWritingEnabled || *imageScanLine;
4685 }
4686 
4688 {
4689  QgsDebugMsg( "Entered" );
4690  //draw the last image if mCurrentImage exists
4691  if ( mCurrentImage )
4692  {
4693  if ( mWritingEnabled )
4694  {
4695  // TODO: consider similar system with raster providers, see the comment
4696  // in QgsRasterImageBuffer::drawPixelRectangle()
4697  // e.g request the block with raster resolution and draw pixels as rectangles
4698  //if ( 2 >= mViewPort->clippedWidth && 2 >= mViewPort->clippedHeight )
4699  if ( false )
4700  {
4702  }
4703  else
4704  {
4705  //int paintXoffset = 0;
4706  //int paintYoffset = 0;
4707  double imageX = 0;
4708  double imageY = 0;
4709 
4710  if ( mMapToPixel )
4711  {
4712  imageX = mViewPort->topLeftPoint.x();
4714  }
4715 
4716  QgsDebugMsg( QString( "mCurrentPartRasterMin = %1" ).arg( mCurrentPartRasterMin ) );
4717  QgsDebugMsg( QString( "imageX = %1 imageY = %2" ).arg( imageX ).arg( imageY ) );
4718  mPainter->drawImage( QPointF( imageX, imageY ), //the top-left point in the paint device
4719  *mCurrentImage );
4720  }
4721  }
4722  }
4723 
4724  delete mCurrentImage; mCurrentImage = 0;
4725  CPLFree( mCurrentGDALData ); mCurrentGDALData = 0;
4726 
4727  mCurrentPart++; // NEW
4728  QgsDebugMsg( QString( "mCurrentPartRasterMax = %1 mViewPort->drawableAreaYDim = %2" ).arg( mCurrentPartRasterMax ).arg( mViewPort->drawableAreaYDim ) );
4730  {
4731  return false; //already at the end...
4732  }
4733 
4737  {
4739  }
4742 
4743  //read GDAL image data
4744  int size = mDataProvider->dataTypeSize( mBandNo ) / 8 ;
4745  int xSize = mViewPort->drawableAreaXDim;
4746  int ySize = mViewPort->drawableAreaYDim;
4747 
4748  //make the raster tiles overlap at least 2 pixels to avoid white stripes
4749  int overlapRows = 0;
4750  if ( mMapToPixel )
4751  {
4752  // TODO: do we still need overlaps?
4753  overlapRows = mMapToPixel->mapUnitsPerPixel() / qAbs( mGeoTransform[5] ) + 2;
4754  }
4755  //if ( mCurrentPartRasterMax + overlapRows >= mViewPort->clippedHeight )
4756  if ( mCurrentPartRasterMax + overlapRows >= mViewPort->drawableAreaYDim )
4757  {
4758  overlapRows = 0;
4759  }
4760  int rasterYSize = mCurrentPartRasterMax - mCurrentPartRasterMin + overlapRows;
4761  QgsDebugMsg( "rasterYSize = " + QString::number( rasterYSize ) );
4762 
4763  // TODO: consider something like this
4764  //if ( 2 >= mViewPort->clippedWidth && 2 >= mViewPort->clippedHeight ) //for zoomed in rasters
4765  if ( false )
4766  {
4767  //rasterYSize = mViewPort->clippedHeight;
4768  //ySize = mViewPort->drawableAreaYDim;
4769  }
4770  else //normal mode
4771  {
4772  if ( mMapToPixel )
4773  {
4774  // makes no more sense
4775  //ySize = qAbs((( rasterYSize ) / mMapToPixel->mapUnitsPerPixel() * mGeoTransform[5] ) ) + 0.5;
4776  }
4777  }
4778  QgsDebugMsg( QString( "xSize = %1 ySize = %2" ).arg( xSize ).arg( ySize ) );
4779  if ( ySize < 1 || xSize < 1 )
4780  {
4781  return false;
4782  }
4783  mNumCurrentImageRows = rasterYSize;
4784  QgsDebugMsg( "alloc " + QString::number( size * xSize * rasterYSize ) );
4785  mCurrentGDALData = VSIMalloc( size * xSize * rasterYSize );
4786 
4788  double yMin = yMax - rasterYSize * mMapToPixel->mapUnitsPerPixel();
4789 
4790  QgsDebugMsg( QString( "mCurrentRow = %1 yMaximum = %2 ySize = %3 mapUnitsPerPixel = %4" ).arg( mCurrentRow ).arg( mViewPort->mDrawnExtent.yMaximum() ).arg( ySize ).arg( mMapToPixel->mapUnitsPerPixel() ) );
4791  QgsRectangle myPartExtent( mViewPort->mDrawnExtent.xMinimum(), yMin,
4792  mViewPort->mDrawnExtent.xMaximum(), yMax );
4793  QgsDebugMsg( "myPartExtent is " + myPartExtent.toString() );
4794  mDataProvider->readBlock( mBandNo, myPartExtent, xSize, rasterYSize , mViewPort->mSrcCRS, mViewPort->mDestCRS, mCurrentGDALData );
4795 
4796  //create the QImage
4797  if ( mWritingEnabled )
4798  {
4799  mCurrentImage = new QImage( xSize, ySize, QImage::Format_ARGB32 );
4800  mCurrentImage->fill( qRgba( 255, 255, 255, 0 ) );
4801  }
4802  else
4803  {
4804  mCurrentImage = 0;
4805  }
4806  return true;
4807 }
4808 
4810 {
4811 // TODO: consider using similar with raster providers, originaly it was used only with
4812 // 2 >= mViewPort->clippedWidth && 2 >= mViewPort->clippedHeight
4813 // but why? but I believe that it should be used always if the ration of original
4814 // raster resolution and device resolution is under certain limit
4815 #if 0
4816  // Set up the initial offset into the myQImage we want to copy to the map canvas
4817  // This is useful when the source image pixels are larger than the screen image.
4818  int paintXoffset = 0;
4819  int paintYoffset = 0;
4820 
4821  if ( mMapToPixel )
4822  {
4823  paintXoffset = static_cast<int>(
4824  ( mViewPort->rectXOffsetFloat -
4825  mViewPort->rectXOffset )
4827  * qAbs( mGeoTransform[1] )
4828  );
4829 
4830  paintYoffset = static_cast<int>(
4831  ( mViewPort->rectYOffsetFloat -
4832  mViewPort->rectYOffset )
4834  * qAbs( mGeoTransform[5] )
4835  );
4836 
4837 
4838  }
4839 
4840  //fix for zoomed in rasters
4841  //Catch special rendering cases
4842  //INSTANCE: 1x1
4843  if ( 1 == mViewPort->clippedWidth && 1 == mViewPort->clippedHeight )
4844  {
4845  QColor myColor( mCurrentImage->pixel( 0, 0 ) );
4846  myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 0 ) ) );
4847  mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ),
4848  static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ),
4849  static_cast<int>( mViewPort->bottomRightPoint.x() ),
4850  static_cast<int>( mViewPort->bottomRightPoint.y() ),
4851  QBrush( myColor ) );
4852  }
4853  //1x2, 2x1 or 2x2
4854  else if ( 2 >= mViewPort->clippedWidth && 2 >= mViewPort->clippedHeight )
4855  {
4856  int myPixelBoundaryX = 0;
4857  int myPixelBoundaryY = 0;
4858  if ( mMapToPixel )
4859  {
4860  myPixelBoundaryX = static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ) + static_cast<int>( qAbs( mGeoTransform[1] / mMapToPixel->mapUnitsPerPixel() ) ) - paintXoffset;
4861  myPixelBoundaryY = static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ) + static_cast<int>( qAbs( mGeoTransform[5] / mMapToPixel->mapUnitsPerPixel() ) ) - paintYoffset;
4862  }
4863 
4864  //INSTANCE: 1x2
4865  if ( 1 == mViewPort->clippedWidth )
4866  {
4867  QColor myColor( mCurrentImage->pixel( 0, 0 ) );
4868  myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 0 ) ) );
4869  mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ),
4870  static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ),
4871  static_cast<int>( mViewPort->bottomRightPoint.x() ),
4872  static_cast<int>( myPixelBoundaryY ),
4873  QBrush( myColor ) );
4874  myColor = QColor( mCurrentImage->pixel( 0, 1 ) );
4875  myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 1 ) ) );
4876  mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ),
4877  static_cast<int>( myPixelBoundaryY ),
4878  static_cast<int>( mViewPort->bottomRightPoint.x() ),
4879  static_cast<int>( mViewPort->bottomRightPoint.y() ),
4880  QBrush( myColor ) );
4881  }
4882  else
4883  {
4884  //INSTANCE: 2x1
4885  if ( 1 == mViewPort->clippedHeight )
4886  {
4887  QColor myColor( mCurrentImage->pixel( 0, 0 ) );
4888  myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 0 ) ) );
4889  mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ),
4890  static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ),
4891  static_cast<int>( myPixelBoundaryX ),
4892  static_cast<int>( mViewPort->bottomRightPoint.y() ),
4893  QBrush( myColor ) );
4894  myColor = QColor( mCurrentImage->pixel( 1, 0 ) );
4895  myColor.setAlpha( qAlpha( mCurrentImage->pixel( 1, 0 ) ) );
4896  mPainter->fillRect( static_cast<int>( myPixelBoundaryX ),
4897  static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ),
4898  static_cast<int>( mViewPort->bottomRightPoint.x() ),
4899  static_cast<int>( mViewPort->bottomRightPoint.y() ),
4900  QBrush( myColor ) );
4901  }
4902  //INSTANCE: 2x2
4903  else
4904  {
4905  QColor myColor( mCurrentImage->pixel( 0, 0 ) );
4906  myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 0 ) ) );
4907  mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ),
4908  static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ),
4909  static_cast<int>( myPixelBoundaryX ),
4910  static_cast<int>( myPixelBoundaryY ),
4911  QBrush( myColor ) );
4912  myColor = QColor( mCurrentImage->pixel( 1, 0 ) );
4913  myColor.setAlpha( qAlpha( mCurrentImage->pixel( 1, 0 ) ) );
4914  mPainter->fillRect( static_cast<int>( myPixelBoundaryX ),
4915  static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ),
4916  static_cast<int>( mViewPort->bottomRightPoint.x() ),
4917  static_cast<int>( myPixelBoundaryY ),
4918  QBrush( myColor ) );
4919  myColor = QColor( mCurrentImage->pixel( 0, 1 ) );
4920  myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 1 ) ) );
4921  mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ),
4922  static_cast<int>( myPixelBoundaryY ),
4923  static_cast<int>( myPixelBoundaryX ),
4924  static_cast<int>( mViewPort->bottomRightPoint.y() ),
4925  QBrush( myColor ) );
4926  myColor = QColor( mCurrentImage->pixel( 1, 1 ) );
4927  myColor.setAlpha( qAlpha( mCurrentImage->pixel( 1, 1 ) ) );
4928  mPainter->fillRect( static_cast<int>( myPixelBoundaryX ),
4929  static_cast<int>( myPixelBoundaryY ),
4930  static_cast<int>( mViewPort->bottomRightPoint.x() ),
4931  static_cast<int>( mViewPort->bottomRightPoint.y() ),
4932  QBrush( myColor ) );
4933  }
4934  }
4935  }
4936 #endif
4937 }
4938 
4939 // Keep this for now, it is used by Python interface!!!
4941 {
4942  if ( GDALGetDriverCount() == 0 )
4943  GDALAllRegister();
4944 }
4945 
4946 // Keep this for QgsRasterLayerProperties
4947 bool QgsRasterLayer::readColorTable( int theBandNumber, QList<QgsColorRampShader::ColorRampItem>* theList )
4948 {
4949  // TODO : check if exists - returned vale?
4950  QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = mDataProvider->colorTable( theBandNumber );
4951  if ( myColorRampItemList.size() == 0 )
4952  {
4953  return false;
4954  }
4955  *theList = myColorRampItemList;
4956  return true;
4957 }
4958