QGIS API Documentation  2.3.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties 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 #include "qgsapplication.h"
18 #include "qgscolorrampshader.h"
20 #include "qgscoordinatetransform.h"
21 #include "qgsdatasourceuri.h"
22 #include "qgslogger.h"
23 #include "qgsmaplayerregistry.h"
24 #include "qgsmaptopixel.h"
25 #include "qgsmessagelog.h"
29 #include "qgsproviderregistry.h"
30 #include "qgspseudocolorshader.h"
31 #include "qgsrasterdrawer.h"
32 #include "qgsrasteriterator.h"
33 #include "qgsrasterlayer.h"
34 #include "qgsrasterlayerrenderer.h"
35 #include "qgsrasterprojector.h"
36 #include "qgsrasterrange.h"
38 #include "qgsrectangle.h"
39 #include "qgsrendercontext.h"
43 
44 #include <cmath>
45 #include <cstdio>
46 #include <limits>
47 #include <typeinfo>
48 
49 #include <QApplication>
50 #include <QCursor>
51 #include <QDomElement>
52 #include <QDomNode>
53 #include <QFile>
54 #include <QFileInfo>
55 #include <QFont>
56 #include <QFontMetrics>
57 #include <QFrame>
58 #include <QImage>
59 #include <QLabel>
60 #include <QLibrary>
61 #include <QList>
62 #include <QMatrix>
63 #include <QMessageBox>
64 #include <QPainter>
65 #include <QPixmap>
66 #include <QRegExp>
67 #include <QSettings>
68 #include <QSlider>
69 #include <QTime>
70 
71 // typedefs for provider plugin functions of interest
72 typedef bool isvalidrasterfilename_t( QString const & theFileNameQString, QString & retErrMsg );
73 
74 #define ERR(message) QGS_ERROR_MESSAGE(message,"Raster layer")
75 
76 const double QgsRasterLayer::CUMULATIVE_CUT_LOWER = 0.02;
77 const double QgsRasterLayer::CUMULATIVE_CUT_UPPER = 0.98;
78 const double QgsRasterLayer::SAMPLE_SIZE = 250000;
79 
81  : QgsMapLayer( RasterLayer )
82  , QSTRING_NOT_SET( "Not Set" )
83  , TRSTRING_NOT_SET( tr( "Not Set" ) )
84  , mDataProvider( 0 )
85 {
86  init();
87  mValid = false;
88 }
89 
91  QString const & path,
92  QString const & baseName,
93  bool loadDefaultStyleFlag )
94  : QgsMapLayer( RasterLayer, baseName, path )
95  , QSTRING_NOT_SET( "Not Set" )
96  , TRSTRING_NOT_SET( tr( "Not Set" ) )
97  , mDataProvider( 0 )
98 {
99  QgsDebugMsg( "Entered" );
100 
101  // TODO, call constructor with provider key
102  init();
103  setDataProvider( "gdal" );
104  if ( !mValid ) return;
105 
106  bool defaultLoadedFlag = false;
107  if ( mValid && loadDefaultStyleFlag )
108  {
109  loadDefaultStyle( defaultLoadedFlag );
110  }
111  if ( !defaultLoadedFlag )
112  {
114  }
115  return;
116 } // QgsRasterLayer ctor
117 
122 QgsRasterLayer::QgsRasterLayer( const QString & uri,
123  const QString & baseName,
124  const QString & providerKey,
125  bool loadDefaultStyleFlag )
126  : QgsMapLayer( RasterLayer, baseName, uri )
127  // Constant that signals property not used.
128  , QSTRING_NOT_SET( "Not Set" )
129  , TRSTRING_NOT_SET( tr( "Not Set" ) )
130  , mDataProvider( 0 )
131  , mProviderKey( providerKey )
132 {
133  QgsDebugMsg( "Entered" );
134  init();
135  setDataProvider( providerKey );
136  if ( !mValid ) return;
137 
138  // load default style
139  bool defaultLoadedFlag = false;
140  if ( mValid && loadDefaultStyleFlag )
141  {
142  loadDefaultStyle( defaultLoadedFlag );
143  }
144  if ( !defaultLoadedFlag )
145  {
147  }
148 
149  // TODO: Connect signals from the dataprovider to the qgisapp
150 
151  emit statusChanged( tr( "QgsRasterLayer created" ) );
152 } // QgsRasterLayer ctor
153 
155 {
156  mValid = false;
157  // Note: provider and other interfaces are owned and deleted by pipe
158 }
159 
161 //
162 // Static Methods and members
163 //
165 
169 bool QgsRasterLayer::isValidRasterFileName( QString const & theFileNameQString, QString & retErrMsg )
170 {
171  isvalidrasterfilename_t *pValid = ( isvalidrasterfilename_t * ) cast_to_fptr( QgsProviderRegistry::instance()->function( "gdal", "isValidRasterFileName" ) );
172  if ( ! pValid )
173  {
174  QgsDebugMsg( "Could not resolve isValidRasterFileName in gdal provider library" );
175  return false;
176  }
177 
178  bool myIsValid = pValid( theFileNameQString, retErrMsg );
179  return myIsValid;
180 }
181 
182 bool QgsRasterLayer::isValidRasterFileName( QString const & theFileNameQString )
183 {
184  QString retErrMsg;
185  return isValidRasterFileName( theFileNameQString, retErrMsg );
186 }
187 
188 QDateTime QgsRasterLayer::lastModified( QString const & name )
189 {
190  QgsDebugMsg( "name=" + name );
191  QDateTime t;
192 
193  QFileInfo fi( name );
194 
195  // Is it file?
196  if ( !fi.exists() )
197  return t;
198 
199  t = fi.lastModified();
200 
201  QgsDebugMsg( "last modified = " + t.toString() );
202 
203  return t;
204 }
205 
206 // typedef for the QgsDataProvider class factory
207 typedef QgsDataProvider * classFactoryFunction_t( const QString * );
208 
210 //
211 // Non Static Public methods
212 //
214 
216 {
217  if ( !mDataProvider ) return 0;
218  return mDataProvider->bandCount();
219 }
220 
221 const QString QgsRasterLayer::bandName( int theBandNo )
222 {
223  return dataProvider()->generateBandName( theBandNo );
224 }
225 
227 {
228  setRenderer( QgsRasterRendererRegistry::instance()->defaultRendererForDrawingStyle( theDrawingStyle, mDataProvider ) );
229 }
230 
235 {
236  return mDataProvider;
237 }
238 
243 {
244  return mDataProvider;
245 }
246 
248 {
249  if ( mDataProvider )
250  {
252  }
253 }
254 
256 {
257  return new QgsRasterLayerRenderer( this, rendererContext );
258 }
259 
260 bool QgsRasterLayer::draw( QgsRenderContext& rendererContext )
261 {
262  QgsDebugMsg( "entered. (renderContext)" );
263 
264  QgsDebugMsg( "checking timestamp." );
265 
266  // Check timestamp
267  if ( !update() )
268  {
269  return false;
270  }
271 
272  QgsRasterLayerRenderer renderer( this, rendererContext );
273  return renderer.render();
274 }
275 
276 void QgsRasterLayer::draw( QPainter * theQPainter,
277  QgsRasterViewPort * theRasterViewPort,
278  const QgsMapToPixel* theQgsMapToPixel )
279 {
280  QgsDebugMsg( " 3 arguments" );
281  QTime time;
282  time.start();
283  //
284  //
285  // The goal here is to make as many decisions as possible early on (outside of the rendering loop)
286  // so that we can maximise performance of the rendering process. So now we check which drawing
287  // procedure to use :
288  //
289 
290  QgsRasterProjector *projector = mPipe.projector();
291 
292  // TODO add a method to interface to get provider and get provider
293  // params in QgsRasterProjector
294  if ( projector )
295  {
296  projector->setCRS( theRasterViewPort->mSrcCRS, theRasterViewPort->mDestCRS, theRasterViewPort->mSrcDatumTransform, theRasterViewPort->mDestDatumTransform );
297  }
298 
299  // Drawer to pipe?
300  QgsRasterIterator iterator( mPipe.last() );
301  QgsRasterDrawer drawer( &iterator );
302  drawer.draw( theQPainter, theRasterViewPort, theQgsMapToPixel );
303 
304  QgsDebugMsg( QString( "total raster draw time (ms): %1" ).arg( time.elapsed(), 5 ) );
305 } //end of draw method
306 
307 QList< QPair< QString, QColor > > QgsRasterLayer::legendSymbologyItems() const
308 {
309  QList< QPair< QString, QColor > > symbolList;
311  if ( renderer )
312  {
313  renderer->legendSymbologyItems( symbolList );
314  }
315  return symbolList;
316 }
317 
319 {
320  QString myMetadata ;
321  myMetadata += "<p class=\"glossy\">" + tr( "Driver" ) + "</p>\n";
322  myMetadata += "<p>";
323  myMetadata += mDataProvider->description();
324  myMetadata += "</p>\n";
325 
326  // Insert provider-specific (e.g. WMS-specific) metadata
327  // crashing
328  myMetadata += mDataProvider->metadata();
329 
330  myMetadata += "<p class=\"glossy\">";
331  myMetadata += tr( "No Data Value" );
332  myMetadata += "</p>\n";
333  myMetadata += "<p>";
334  // TODO: all bands
335  if ( mDataProvider->srcHasNoDataValue( 1 ) )
336  {
337  myMetadata += QString::number( mDataProvider->srcNoDataValue( 1 ) );
338  }
339  else
340  {
341  myMetadata += "*" + tr( "NoDataValue not set" ) + "*";
342  }
343  myMetadata += "</p>\n";
344 
345  myMetadata += "</p>\n";
346  myMetadata += "<p class=\"glossy\">";
347  myMetadata += tr( "Data Type" );
348  myMetadata += "</p>\n";
349  myMetadata += "<p>";
350  //just use the first band
351  switch ( mDataProvider->srcDataType( 1 ) )
352  {
353  case QGis::Byte:
354  myMetadata += tr( "Byte - Eight bit unsigned integer" );
355  break;
356  case QGis::UInt16:
357  myMetadata += tr( "UInt16 - Sixteen bit unsigned integer " );
358  break;
359  case QGis::Int16:
360  myMetadata += tr( "Int16 - Sixteen bit signed integer " );
361  break;
362  case QGis::UInt32:
363  myMetadata += tr( "UInt32 - Thirty two bit unsigned integer " );
364  break;
365  case QGis::Int32:
366  myMetadata += tr( "Int32 - Thirty two bit signed integer " );
367  break;
368  case QGis::Float32:
369  myMetadata += tr( "Float32 - Thirty two bit floating point " );
370  break;
371  case QGis::Float64:
372  myMetadata += tr( "Float64 - Sixty four bit floating point " );
373  break;
374  case QGis::CInt16:
375  myMetadata += tr( "CInt16 - Complex Int16 " );
376  break;
377  case QGis::CInt32:
378  myMetadata += tr( "CInt32 - Complex Int32 " );
379  break;
380  case QGis::CFloat32:
381  myMetadata += tr( "CFloat32 - Complex Float32 " );
382  break;
383  case QGis::CFloat64:
384  myMetadata += tr( "CFloat64 - Complex Float64 " );
385  break;
386  default:
387  myMetadata += tr( "Could not determine raster data type." );
388  }
389  myMetadata += "</p>\n";
390 
391  myMetadata += "<p class=\"glossy\">";
392  myMetadata += tr( "Pyramid overviews" );
393  myMetadata += "</p>\n";
394  myMetadata += "<p>";
395 
396  myMetadata += "<p class=\"glossy\">";
397  myMetadata += tr( "Layer Spatial Reference System" );
398  myMetadata += "</p>\n";
399  myMetadata += "<p>";
400  myMetadata += crs().toProj4();
401  myMetadata += "</p>\n";
402 
403  myMetadata += "<p class=\"glossy\">";
404  myMetadata += tr( "Layer Extent (layer original source projection)" );
405  myMetadata += "</p>\n";
406  myMetadata += "<p>";
407  myMetadata += mDataProvider->extent().toString();
408  myMetadata += "</p>\n";
409 
410  // output coordinate system
411  // TODO: this is not related to layer, to be removed? [MD]
412 #if 0
413  myMetadata += "<tr><td class=\"glossy\">";
414  myMetadata += tr( "Project Spatial Reference System" );
415  myMetadata += "</p>\n";
416  myMetadata += "<p>";
417  myMetadata += mCoordinateTransform->destCRS().toProj4();
418  myMetadata += "</p>\n";
419 #endif
420 
421  //
422  // Add the stats for each band to the output table
423  //
424  int myBandCountInt = bandCount();
425  for ( int myIteratorInt = 1; myIteratorInt <= myBandCountInt; ++myIteratorInt )
426  {
427  QgsDebugMsg( "Raster properties : checking if band " + QString::number( myIteratorInt ) + " has stats? " );
428  //band name
429  myMetadata += "<p class=\"glossy\">\n";
430  myMetadata += tr( "Band" );
431  myMetadata += "</p>\n";
432  myMetadata += "<p>";
433  myMetadata += bandName( myIteratorInt );
434  myMetadata += "</p>\n";
435  //band number
436  myMetadata += "<p>";
437  myMetadata += tr( "Band No" );
438  myMetadata += "</p>\n";
439  myMetadata += "<p>\n";
440  myMetadata += QString::number( myIteratorInt );
441  myMetadata += "</p>\n";
442 
443  //check if full stats for this layer have already been collected
444  if ( !dataProvider()->hasStatistics( myIteratorInt ) ) //not collected
445  {
446  QgsDebugMsg( ".....no" );
447 
448  myMetadata += "<p>";
449  myMetadata += tr( "No Stats" );
450  myMetadata += "</p>\n";
451  myMetadata += "<p>\n";
452  myMetadata += tr( "No stats collected yet" );
453  myMetadata += "</p>\n";
454  }
455  else // collected - show full detail
456  {
457  QgsDebugMsg( ".....yes" );
458 
459  QgsRasterBandStats myRasterBandStats = dataProvider()->bandStatistics( myIteratorInt );
460  //Min Val
461  myMetadata += "<p>";
462  myMetadata += tr( "Min Val" );
463  myMetadata += "</p>\n";
464  myMetadata += "<p>\n";
465  myMetadata += QString::number( myRasterBandStats.minimumValue, 'f', 10 );
466  myMetadata += "</p>\n";
467 
468  // Max Val
469  myMetadata += "<p>";
470  myMetadata += tr( "Max Val" );
471  myMetadata += "</p>\n";
472  myMetadata += "<p>\n";
473  myMetadata += QString::number( myRasterBandStats.maximumValue, 'f', 10 );
474  myMetadata += "</p>\n";
475 
476  // Range
477  myMetadata += "<p>";
478  myMetadata += tr( "Range" );
479  myMetadata += "</p>\n";
480  myMetadata += "<p>\n";
481  myMetadata += QString::number( myRasterBandStats.range, 'f', 10 );
482  myMetadata += "</p>\n";
483 
484  // Mean
485  myMetadata += "<p>";
486  myMetadata += tr( "Mean" );
487  myMetadata += "</p>\n";
488  myMetadata += "<p>\n";
489  myMetadata += QString::number( myRasterBandStats.mean, 'f', 10 );
490  myMetadata += "</p>\n";
491 
492  //sum of squares
493  myMetadata += "<p>";
494  myMetadata += tr( "Sum of squares" );
495  myMetadata += "</p>\n";
496  myMetadata += "<p>\n";
497  myMetadata += QString::number( myRasterBandStats.sumOfSquares, 'f', 10 );
498  myMetadata += "</p>\n";
499 
500  //standard deviation
501  myMetadata += "<p>";
502  myMetadata += tr( "Standard Deviation" );
503  myMetadata += "</p>\n";
504  myMetadata += "<p>\n";
505  myMetadata += QString::number( myRasterBandStats.stdDev, 'f', 10 );
506  myMetadata += "</p>\n";
507 
508  //sum of all cells
509  myMetadata += "<p>";
510  myMetadata += tr( "Sum of all cells" );
511  myMetadata += "</p>\n";
512  myMetadata += "<p>\n";
513  myMetadata += QString::number( myRasterBandStats.sum, 'f', 10 );
514  myMetadata += "</p>\n";
515 
516  //number of cells
517  myMetadata += "<p>";
518  myMetadata += tr( "Cell Count" );
519  myMetadata += "</p>\n";
520  myMetadata += "<p>\n";
521  myMetadata += QString::number( myRasterBandStats.elementCount );
522  myMetadata += "</p>\n";
523  }
524  }
525 
526  QgsDebugMsg( myMetadata );
527  return myMetadata;
528 }
529 
534 QPixmap QgsRasterLayer::paletteAsPixmap( int theBandNumber )
535 {
536  //TODO: This function should take dimensions
537  QgsDebugMsg( "entered." );
538 
539  // Only do this for the GDAL provider?
540  // Maybe WMS can do this differently using QImage::numColors and QImage::color()
541  if ( mDataProvider->colorInterpretation( theBandNumber ) == QgsRaster::PaletteIndex )
542  {
543  QgsDebugMsg( "....found paletted image" );
544  QgsColorRampShader myShader;
545  QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = mDataProvider->colorTable( theBandNumber );
546  if ( myColorRampItemList.size() > 0 )
547  {
548  QgsDebugMsg( "....got color ramp item list" );
549  myShader.setColorRampItemList( myColorRampItemList );
551  // Draw image
552  int mySize = 100;
553  QPixmap myPalettePixmap( mySize, mySize );
554  QPainter myQPainter( &myPalettePixmap );
555 
556  QImage myQImage = QImage( mySize, mySize, QImage::Format_RGB32 );
557  myQImage.fill( 0 );
558  myPalettePixmap.fill();
559 
560  double myStep = (( double )myColorRampItemList.size() - 1 ) / ( double )( mySize * mySize );
561  double myValue = 0.0;
562  for ( int myRow = 0; myRow < mySize; myRow++ )
563  {
564  QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
565  for ( int myCol = 0; myCol < mySize; myCol++ )
566  {
567  myValue = myStep * ( double )( myCol + myRow * mySize );
568  int c1, c2, c3, c4;
569  myShader.shade( myValue, &c1, &c2, &c3, &c4 );
570  myLineBuffer[ myCol ] = qRgba( c1, c2, c3, c4 );
571  }
572  }
573 
574  myQPainter.drawImage( 0, 0, myQImage );
575  return myPalettePixmap;
576  }
577  QPixmap myNullPixmap;
578  return myNullPixmap;
579  }
580  else
581  {
582  //invalid layer was requested
583  QPixmap myNullPixmap;
584  return myNullPixmap;
585  }
586 }
587 
589 {
590  return mProviderKey;
591 }
592 
597 {
598 // We return one raster pixel per map unit pixel
599 // One raster pixel can have several raster units...
600 
601 // We can only use one of the mGeoTransform[], so go with the
602 // horisontal one.
603 
605  {
606  return mDataProvider->extent().width() / mDataProvider->xSize();
607  }
608  return 1;
609 }
610 
612 {
614  {
615  return mDataProvider->extent().height() / mDataProvider->ySize();
616  }
617  return 1;
618 }
619 
621 {
623 
625 
626  //Initialize the last view port structure, should really be a class
627  mLastViewPort.mWidth = 0;
629 }
630 
631 void QgsRasterLayer::setDataProvider( QString const & provider )
632 {
633  QgsDebugMsg( "Entered" );
634  mValid = false; // assume the layer is invalid until we determine otherwise
635 
636  mPipe.remove( mDataProvider ); // deletes if exists
637  mDataProvider = 0;
638 
639  // XXX should I check for and possibly delete any pre-existing providers?
640  // XXX How often will that scenario occur?
641 
642  mProviderKey = provider;
643  // set the layer name (uppercase first character)
644  if ( ! mLayerName.isEmpty() ) // XXX shouldn't this happen in parent?
645  {
647  }
648 
649  //mBandCount = 0;
650 
652  if ( !mDataProvider )
653  {
654  //QgsMessageLog::logMessage( tr( "Cannot instantiate the data provider" ), tr( "Raster" ) );
655  appendError( ERR( tr( "Cannot instantiate the '%1' data provider" ).arg( mProviderKey ) ) );
656  return;
657  }
658  QgsDebugMsg( "Data provider created" );
659 
660  // Set data provider into pipe even if not valid so that it is deleted with pipe (with layer)
662  if ( !mDataProvider->isValid() )
663  {
665  appendError( ERR( tr( "Provider is not valid (provider: %1, URI: %2" ).arg( mProviderKey ).arg( mDataSource ) ) );
666  return;
667  }
668 
669  if ( provider == "gdal" )
670  {
671  // make sure that the /vsigzip or /vsizip is added to uri, if applicable
673  }
674 
675  // get the extent
677 
678  // show the extent
679  QString s = mbr.toString();
680  QgsDebugMsg( "Extent of layer: " + s );
681  // store the extent
682  setExtent( mbr );
683 
684  // upper case the first letter of the layer name
685  QgsDebugMsg( "mLayerName: " + name() );
686 
687  // set up the raster drawing style
688  // Do not set any 'sensible' style here, the style is set later
689 
690  // Setup source CRS
692 
693  QString mySourceWkt = crs().toWkt();
694 
695  QgsDebugMsg( "using wkt:\n" + mySourceWkt );
696 
697  //defaults - Needs to be set after the Contrast list has been build
698  //Try to read the default contrast enhancement from the config file
699 
700  QSettings myQSettings;
701 
702  //decide what type of layer this is...
703  //TODO Change this to look at the color interp and palette interp to decide which type of layer it is
704  QgsDebugMsg( "bandCount = " + QString::number( mDataProvider->bandCount() ) );
705  QgsDebugMsg( "dataType = " + QString::number( mDataProvider->dataType( 1 ) ) );
706  if (( mDataProvider->bandCount() > 1 ) )
707  {
709  }
710  else if ( mDataProvider->dataType( 1 ) == QGis::ARGB32
712  {
714  }
716  {
718  }
720  {
722  }
723  else
724  {
726  }
727 
728  QgsDebugMsg( "mRasterType = " + QString::number( mRasterType ) );
729  if ( mRasterType == ColorLayer )
730  {
731  QgsDebugMsg( "Setting drawing style to SingleBandColorDataStyle " + QString::number( QgsRaster::SingleBandColorDataStyle ) );
733  }
735  {
737  }
739  {
741  // Load color table
742  QList<QgsColorRampShader::ColorRampItem> colorTable = mDataProvider->colorTable( 1 );
744  if ( r )
745  {
746  // TODO: this should go somewhere else
747  QgsRasterShader* shader = new QgsRasterShader();
748  QgsColorRampShader* colorRampShader = new QgsColorRampShader();
750  colorRampShader->setColorRampItemList( colorTable );
751  shader->setRasterShaderFunction( colorRampShader );
752  r->setShader( shader );
753  }
754  }
755  else if ( mRasterType == Multiband )
756  {
758  }
759  else //GrayOrUndefined
760  {
762  }
763 
764  // Auto set alpha band
765  for ( int bandNo = 1; bandNo <= mDataProvider->bandCount(); bandNo++ )
766  {
768  {
769  if ( mPipe.renderer() )
770  {
771  mPipe.renderer()->setAlphaBand( bandNo );
772  }
773  break;
774  }
775  }
776 
777  // brightness filter
779  mPipe.set( brightnessFilter );
780 
781  // hue/saturation filter
783  mPipe.set( hueSaturationFilter );
784 
785  //resampler (must be after renderer)
787  mPipe.set( resampleFilter );
788 
789  // projector (may be anywhere in pipe)
790  QgsRasterProjector * projector = new QgsRasterProjector;
791  mPipe.set( projector );
792 
793  // Set default identify format - use the richest format available
794  int capabilities = mDataProvider->capabilities();
796  if ( capabilities & QgsRasterInterface::IdentifyHtml )
797  {
798  // HTML is usually richest
799  identifyFormat = QgsRaster::IdentifyFormatHtml;
800  }
801  else if ( capabilities & QgsRasterInterface::IdentifyFeature )
802  {
803  identifyFormat = QgsRaster::IdentifyFormatFeature;
804  }
805  else if ( capabilities & QgsRasterInterface::IdentifyText )
806  {
807  identifyFormat = QgsRaster::IdentifyFormatText;
808  }
809  else if ( capabilities & QgsRasterInterface::IdentifyValue )
810  {
811  identifyFormat = QgsRaster::IdentifyFormatValue;
812  }
813  setCustomProperty( "identify/format", QgsRasterDataProvider::identifyFormatName( identifyFormat ) );
814 
815  // Store timestamp
816  // TODO move to provider
818 
819  // Connect provider signals
820  connect(
821  mDataProvider, SIGNAL( progress( int, double, QString ) ),
822  this, SLOT( onProgress( int, double, QString ) )
823  );
824 
825  // Do a passthrough for the status bar text
826  connect(
827  mDataProvider, SIGNAL( statusChanged( QString ) ),
828  this, SIGNAL( statusChanged( QString ) )
829  );
830 
831  //mark the layer as valid
832  mValid = true;
833 
834  QgsDebugMsg( "exiting." );
835 } // QgsRasterLayer::setDataProvider
836 
838 {
839  mValid = false;
841  mDataProvider = 0;
842 }
843 
844 void QgsRasterLayer::setContrastEnhancement( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm, QgsRaster::ContrastEnhancementLimits theLimits, QgsRectangle theExtent, int theSampleSize, bool theGenerateLookupTableFlag )
845 {
846  QgsDebugMsg( QString( "theAlgorithm = %1 theLimits = %2 theExtent.isEmpty() = %3" ).arg( theAlgorithm ).arg( theLimits ).arg( theExtent.isEmpty() ) );
847  if ( !mPipe.renderer() || !mDataProvider )
848  {
849  return;
850  }
851 
852  QList<int> myBands;
853  QList<QgsContrastEnhancement*> myEnhancements;
854  QgsSingleBandGrayRenderer* myGrayRenderer = 0;
855  QgsMultiBandColorRenderer* myMultiBandRenderer = 0;
856  QString rendererType = mPipe.renderer()->type();
857  if ( rendererType == "singlebandgray" )
858  {
859  myGrayRenderer = dynamic_cast<QgsSingleBandGrayRenderer*>( mPipe.renderer() );
860  if ( !myGrayRenderer ) return;
861  myBands << myGrayRenderer->grayBand();
862  }
863  else if ( rendererType == "multibandcolor" )
864  {
865  myMultiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer*>( mPipe.renderer() );
866  if ( !myMultiBandRenderer ) return;
867  myBands << myMultiBandRenderer->redBand() << myMultiBandRenderer->greenBand() << myMultiBandRenderer->blueBand();
868  }
869 
870  foreach ( int myBand, myBands )
871  {
872  if ( myBand != -1 )
873  {
874  QGis::DataType myType = ( QGis::DataType )mDataProvider->dataType( myBand );
875  QgsContrastEnhancement* myEnhancement = new QgsContrastEnhancement(( QGis::DataType )myType );
876  myEnhancement->setContrastEnhancementAlgorithm( theAlgorithm, theGenerateLookupTableFlag );
877 
878  double myMin = std::numeric_limits<double>::quiet_NaN();
879  double myMax = std::numeric_limits<double>::quiet_NaN();
880 
881  if ( theLimits == QgsRaster::ContrastEnhancementMinMax )
882  {
883  QgsRasterBandStats myRasterBandStats = mDataProvider->bandStatistics( myBand, QgsRasterBandStats::Min | QgsRasterBandStats::Max, theExtent, theSampleSize );
884  myMin = myRasterBandStats.minimumValue;
885  myMax = myRasterBandStats.maximumValue;
886  }
887  else if ( theLimits == QgsRaster::ContrastEnhancementStdDev )
888  {
889  double myStdDev = 1; // make optional?
890  QgsRasterBandStats myRasterBandStats = mDataProvider->bandStatistics( myBand, QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev, theExtent, theSampleSize );
891  myMin = myRasterBandStats.mean - ( myStdDev * myRasterBandStats.stdDev );
892  myMax = myRasterBandStats.mean + ( myStdDev * myRasterBandStats.stdDev );
893  }
894  else if ( theLimits == QgsRaster::ContrastEnhancementCumulativeCut )
895  {
896  QSettings mySettings;
897  double myLower = mySettings.value( "/Raster/cumulativeCutLower", QString::number( CUMULATIVE_CUT_LOWER ) ).toDouble();
898  double myUpper = mySettings.value( "/Raster/cumulativeCutUpper", QString::number( CUMULATIVE_CUT_UPPER ) ).toDouble();
899  QgsDebugMsg( QString( "myLower = %1 myUpper = %2" ).arg( myLower ).arg( myUpper ) );
900  mDataProvider->cumulativeCut( myBand, myLower, myUpper, myMin, myMax, theExtent, theSampleSize );
901  }
902 
903  QgsDebugMsg( QString( "myBand = %1 myMin = %2 myMax = %3" ).arg( myBand ).arg( myMin ).arg( myMax ) );
904  myEnhancement->setMinimumValue( myMin );
905  myEnhancement->setMaximumValue( myMax );
906  myEnhancements.append( myEnhancement );
907  }
908  else
909  {
910  myEnhancements.append( 0 );
911  }
912  }
913 
914  if ( rendererType == "singlebandgray" )
915  {
916  if ( myEnhancements.value( 0 ) ) myGrayRenderer->setContrastEnhancement( myEnhancements.value( 0 ) );
917  }
918  else if ( rendererType == "multibandcolor" )
919  {
920  if ( myEnhancements.value( 0 ) ) myMultiBandRenderer->setRedContrastEnhancement( myEnhancements.value( 0 ) );
921  if ( myEnhancements.value( 1 ) ) myMultiBandRenderer->setGreenContrastEnhancement( myEnhancements.value( 1 ) );
922  if ( myEnhancements.value( 2 ) ) myMultiBandRenderer->setBlueContrastEnhancement( myEnhancements.value( 2 ) );
923  }
924 
925  emit repaintRequested();
926 }
927 
929 {
930  QgsDebugMsg( "Entered" );
931 
932  QSettings mySettings;
933 
934  QString myKey;
935  QString myDefault;
936 
937  // TODO: we should not test renderer class here, move it somehow to renderers
938  if ( dynamic_cast<QgsSingleBandGrayRenderer*>( renderer() ) )
939  {
940  myKey = "singleBand";
941  myDefault = "StretchToMinimumMaximum";
942  }
943  else if ( dynamic_cast<QgsMultiBandColorRenderer*>( renderer() ) )
944  {
945  if ( QgsRasterBlock::typeSize( dataProvider()->srcDataType( 1 ) ) == 1 )
946  {
947  myKey = "multiBandSingleByte";
948  myDefault = "NoEnhancement";
949  }
950  else
951  {
952  myKey = "multiBandMultiByte";
953  myDefault = "StretchToMinimumMaximum";
954  }
955  }
956 
957  if ( myKey.isEmpty() )
958  {
959  QgsDebugMsg( "No default contrast enhancement for this drawing style" );
960  }
961  QgsDebugMsg( "myKey = " + myKey );
962 
963  QString myAlgorithmString = mySettings.value( "/Raster/defaultContrastEnhancementAlgorithm/" + myKey, myDefault ).toString();
964  QgsDebugMsg( "myAlgorithmString = " + myAlgorithmString );
965 
967 
968  if ( myAlgorithm == QgsContrastEnhancement::NoEnhancement )
969  {
970  return;
971  }
972 
973  QString myLimitsString = mySettings.value( "/Raster/defaultContrastEnhancementLimits", "CumulativeCut" ).toString();
975 
976  setContrastEnhancement( myAlgorithm, myLimits );
977 }
978 
984 void QgsRasterLayer::setDrawingStyle( QString const & theDrawingStyleQString )
985 {
986  QgsDebugMsg( "DrawingStyle = " + theDrawingStyleQString );
987  QgsRaster::DrawingStyle drawingStyle;
988  if ( theDrawingStyleQString == "SingleBandGray" )//no need to tr() this its not shown in ui
989  {
990  drawingStyle = QgsRaster::SingleBandGray;
991  }
992  else if ( theDrawingStyleQString == "SingleBandPseudoColor" )//no need to tr() this its not shown in ui
993  {
994  drawingStyle = QgsRaster::SingleBandPseudoColor;
995  }
996  else if ( theDrawingStyleQString == "PalettedColor" )//no need to tr() this its not shown in ui
997  {
998  drawingStyle = QgsRaster::PalettedColor;
999  }
1000  else if ( theDrawingStyleQString == "PalettedSingleBandGray" )//no need to tr() this its not shown in ui
1001  {
1002  drawingStyle = QgsRaster::PalettedSingleBandGray;
1003  }
1004  else if ( theDrawingStyleQString == "PalettedSingleBandPseudoColor" )//no need to tr() this its not shown in ui
1005  {
1007  }
1008  else if ( theDrawingStyleQString == "PalettedMultiBandColor" )//no need to tr() this its not shown in ui
1009  {
1010  drawingStyle = QgsRaster::PalettedMultiBandColor;
1011  }
1012  else if ( theDrawingStyleQString == "MultiBandSingleBandGray" )//no need to tr() this its not shown in ui
1013  {
1014  drawingStyle = QgsRaster::MultiBandSingleBandGray;
1015  }
1016  else if ( theDrawingStyleQString == "MultiBandSingleBandPseudoColor" )//no need to tr() this its not shown in ui
1017  {
1019  }
1020  else if ( theDrawingStyleQString == "MultiBandColor" )//no need to tr() this its not shown in ui
1021  {
1022  drawingStyle = QgsRaster::MultiBandColor;
1023  }
1024  else if ( theDrawingStyleQString == "SingleBandColorDataStyle" )//no need to tr() this its not shown in ui
1025  {
1026  QgsDebugMsg( "Setting drawingStyle to SingleBandColorDataStyle " + QString::number( QgsRaster::SingleBandColorDataStyle ) );
1027  drawingStyle = QgsRaster::SingleBandColorDataStyle;
1028  QgsDebugMsg( "Setted drawingStyle to " + QString::number( drawingStyle ) );
1029  }
1030  else
1031  {
1032  drawingStyle = QgsRaster::UndefinedDrawingStyle;
1033  }
1034  setRendererForDrawingStyle( drawingStyle );
1035 }
1036 
1037 void QgsRasterLayer::setLayerOrder( QStringList const & layers )
1038 {
1039  QgsDebugMsg( "entered." );
1040 
1041  if ( mDataProvider )
1042  {
1043  QgsDebugMsg( "About to mDataProvider->setLayerOrder(layers)." );
1044  mDataProvider->setLayerOrder( layers );
1045  }
1046 
1047 }
1048 
1049 void QgsRasterLayer::setSubLayerVisibility( QString name, bool vis )
1050 {
1051 
1052  if ( mDataProvider )
1053  {
1054  QgsDebugMsg( "About to mDataProvider->setSubLayerVisibility(name, vis)." );
1055  mDataProvider->setSubLayerVisibility( name, vis );
1056  }
1057 
1058 }
1059 
1061 {
1062  QgsDebugMsg( "Entered" );
1063  if ( !theRenderer ) { return; }
1064  mPipe.set( theRenderer );
1065  emit rendererChanged();
1066 }
1067 
1068 void QgsRasterLayer::showProgress( int theValue )
1069 {
1070  emit progressUpdate( theValue );
1071 }
1072 
1073 
1074 void QgsRasterLayer::showStatusMessage( QString const & theMessage )
1075 {
1076  // QgsDebugMsg(QString("entered with '%1'.").arg(theMessage));
1077 
1078  // Pass-through
1079  // TODO: See if we can connect signal-to-signal. This is a kludge according to the Qt doc.
1080  emit statusChanged( theMessage );
1081 }
1082 
1083 QStringList QgsRasterLayer::subLayers() const
1084 {
1085  return mDataProvider->subLayers();
1086 }
1087 
1088 QPixmap QgsRasterLayer::previewAsPixmap( QSize size, QColor bgColor )
1089 {
1090  QPixmap myQPixmap( size );
1091 
1092  myQPixmap.fill( bgColor ); //defaults to white, set to transparent for rendering on a map
1093 
1094  QgsRasterViewPort *myRasterViewPort = new QgsRasterViewPort();
1095 
1096  double myMapUnitsPerPixel;
1097  double myX = 0.0;
1098  double myY = 0.0;
1099  QgsRectangle myExtent = mDataProvider->extent();
1100  if ( myExtent.width() / myExtent.height() >= myQPixmap.width() / myQPixmap.height() )
1101  {
1102  myMapUnitsPerPixel = myExtent.width() / myQPixmap.width();
1103  myY = ( myQPixmap.height() - myExtent.height() / myMapUnitsPerPixel ) / 2;
1104  }
1105  else
1106  {
1107  myMapUnitsPerPixel = myExtent.height() / myQPixmap.height();
1108  myX = ( myQPixmap.width() - myExtent.width() / myMapUnitsPerPixel ) / 2;
1109  }
1110 
1111  double myPixelWidth = myExtent.width() / myMapUnitsPerPixel;
1112  double myPixelHeight = myExtent.height() / myMapUnitsPerPixel;
1113 
1114  myRasterViewPort->mTopLeftPoint = QgsPoint( myX, myY );
1115  myRasterViewPort->mBottomRightPoint = QgsPoint( myPixelWidth, myPixelHeight );
1116  myRasterViewPort->mWidth = myQPixmap.width();
1117  myRasterViewPort->mHeight = myQPixmap.height();
1118 
1119  myRasterViewPort->mDrawnExtent = myExtent;
1120  myRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid
1121  myRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid
1122  myRasterViewPort->mSrcDatumTransform = -1;
1123  myRasterViewPort->mDestDatumTransform = -1;
1124 
1125  QgsMapToPixel *myMapToPixel = new QgsMapToPixel( myMapUnitsPerPixel );
1126 
1127  QPainter * myQPainter = new QPainter( &myQPixmap );
1128  draw( myQPainter, myRasterViewPort, myMapToPixel );
1129  delete myRasterViewPort;
1130  delete myMapToPixel;
1131  myQPainter->end();
1132  delete myQPainter;
1133 
1134  return myQPixmap;
1135 }
1136 
1137 // this function should be used when rendering with the MTR engine introduced in 2.3, as QPixmap is not thread safe (see bug #9626)
1138 // note: previewAsImage and previewAsPixmap should use a common low-level fct QgsRasterLayer::previewOnPaintDevice( QSize size, QColor bgColor, QPaintDevice &device )
1139 QImage QgsRasterLayer::previewAsImage( QSize size, QColor bgColor, QImage::Format format )
1140 {
1141  QImage myQImage( size, format );
1142 
1143  myQImage.setColor( 0, bgColor.rgba() );
1144  myQImage.fill( 0 ); //defaults to white, set to transparent for rendering on a map
1145 
1146  QgsRasterViewPort *myRasterViewPort = new QgsRasterViewPort();
1147 
1148  double myMapUnitsPerPixel;
1149  double myX = 0.0;
1150  double myY = 0.0;
1151  QgsRectangle myExtent = mDataProvider->extent();
1152  if ( myExtent.width() / myExtent.height() >= myQImage.width() / myQImage.height() )
1153  {
1154  myMapUnitsPerPixel = myExtent.width() / myQImage.width();
1155  myY = ( myQImage.height() - myExtent.height() / myMapUnitsPerPixel ) / 2;
1156  }
1157  else
1158  {
1159  myMapUnitsPerPixel = myExtent.height() / myQImage.height();
1160  myX = ( myQImage.width() - myExtent.width() / myMapUnitsPerPixel ) / 2;
1161  }
1162 
1163  double myPixelWidth = myExtent.width() / myMapUnitsPerPixel;
1164  double myPixelHeight = myExtent.height() / myMapUnitsPerPixel;
1165 
1166  myRasterViewPort->mTopLeftPoint = QgsPoint( myX, myY );
1167  myRasterViewPort->mBottomRightPoint = QgsPoint( myPixelWidth, myPixelHeight );
1168  myRasterViewPort->mWidth = myQImage.width();
1169  myRasterViewPort->mHeight = myQImage.height();
1170 
1171  myRasterViewPort->mDrawnExtent = myExtent;
1172  myRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid
1173  myRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid
1174  myRasterViewPort->mSrcDatumTransform = -1;
1175  myRasterViewPort->mDestDatumTransform = -1;
1176 
1177  QgsMapToPixel *myMapToPixel = new QgsMapToPixel( myMapUnitsPerPixel );
1178 
1179  QPainter * myQPainter = new QPainter( &myQImage );
1180  draw( myQPainter, myRasterViewPort, myMapToPixel );
1181  delete myRasterViewPort;
1182  delete myMapToPixel;
1183  myQPainter->end();
1184  delete myQPainter;
1185 
1186  return myQImage;
1187 }
1188 
1190 {
1191  emit repaintRequested();
1192 }
1193 
1194 void QgsRasterLayer::updateProgress( int theProgress, int theMax )
1195 {
1196  Q_UNUSED( theProgress );
1197  Q_UNUSED( theMax );
1198 }
1199 
1200 void QgsRasterLayer::onProgress( int theType, double theProgress, QString theMessage )
1201 {
1202  Q_UNUSED( theType );
1203  Q_UNUSED( theMessage );
1204  QgsDebugMsg( QString( "theProgress = %1" ).arg( theProgress ) );
1205  emit progressUpdate(( int )theProgress );
1206 }
1207 
1209 //
1210 // Protected methods
1211 //
1213 /*
1214  * @param QDomNode node that will contain the symbology definition for this layer.
1215  * @param errorMessage reference to string that will be updated with any error messages
1216  * @return true in case of success.
1217  */
1218 bool QgsRasterLayer::readSymbology( const QDomNode& layer_node, QString& errorMessage )
1219 {
1220  Q_UNUSED( errorMessage );
1221  QDomElement rasterRendererElem;
1222 
1223  // pipe element was introduced in the end of 1.9 development when there were
1224  // already many project files in use so we support 1.9 backward compatibility
1225  // even it was never officialy released -> use pipe element if present, otherwise
1226  // use layer node
1227  QDomNode pipeNode = layer_node.firstChildElement( "pipe" );
1228  if ( pipeNode.isNull() ) // old project
1229  {
1230  pipeNode = layer_node;
1231  }
1232 
1233  //rasterlayerproperties element there -> old format (1.8 and early 1.9)
1234  if ( !layer_node.firstChildElement( "rasterproperties" ).isNull() )
1235  {
1236  //copy node because layer_node is const
1237  QDomNode layerNodeCopy = layer_node.cloneNode();
1238  QDomDocument doc = layerNodeCopy.ownerDocument();
1239  QDomElement rasterPropertiesElem = layerNodeCopy.firstChildElement( "rasterproperties" );
1240  QgsProjectFileTransform::convertRasterProperties( doc, layerNodeCopy, rasterPropertiesElem,
1241  this );
1242  rasterRendererElem = layerNodeCopy.firstChildElement( "rasterrenderer" );
1243  QgsDebugMsg( doc.toString() );
1244  }
1245  else
1246  {
1247  rasterRendererElem = pipeNode.firstChildElement( "rasterrenderer" );
1248  }
1249 
1250  if ( !rasterRendererElem.isNull() )
1251  {
1252  QString rendererType = rasterRendererElem.attribute( "type" );
1253  QgsRasterRendererRegistryEntry rendererEntry;
1254  if ( QgsRasterRendererRegistry::instance()->rendererData( rendererType, rendererEntry ) )
1255  {
1256  QgsRasterRenderer *renderer = rendererEntry.rendererCreateFunction( rasterRendererElem, dataProvider() );
1257  mPipe.set( renderer );
1258  }
1259  }
1260 
1261  //brightness
1263  mPipe.set( brightnessFilter );
1264 
1265  //brightness coefficient
1266  QDomElement brightnessElem = pipeNode.firstChildElement( "brightnesscontrast" );
1267  if ( !brightnessElem.isNull() )
1268  {
1269  brightnessFilter->readXML( brightnessElem );
1270  }
1271 
1272  //hue/saturation
1274  mPipe.set( hueSaturationFilter );
1275 
1276  //saturation coefficient
1277  QDomElement hueSaturationElem = pipeNode.firstChildElement( "huesaturation" );
1278  if ( !hueSaturationElem.isNull() )
1279  {
1280  hueSaturationFilter->readXML( hueSaturationElem );
1281  }
1282 
1283  //resampler
1285  mPipe.set( resampleFilter );
1286 
1287  //max oversampling
1288  QDomElement resampleElem = pipeNode.firstChildElement( "rasterresampler" );
1289  if ( !resampleElem.isNull() )
1290  {
1291  resampleFilter->readXML( resampleElem );
1292  }
1293 
1294  // get and set the blend mode if it exists
1295  QDomNode blendModeNode = layer_node.namedItem( "blendMode" );
1296  if ( !blendModeNode.isNull() )
1297  {
1298  QDomElement e = blendModeNode.toElement();
1300  }
1301 
1302  return true;
1303 } //readSymbology
1304 
1311 bool QgsRasterLayer::readXml( const QDomNode& layer_node )
1312 {
1313  QgsDebugMsg( "Entered" );
1315 
1316  //process provider key
1317  QDomNode pkeyNode = layer_node.namedItem( "provider" );
1318 
1319  if ( pkeyNode.isNull() )
1320  {
1321  mProviderKey = "gdal";
1322  }
1323  else
1324  {
1325  QDomElement pkeyElt = pkeyNode.toElement();
1326  mProviderKey = pkeyElt.text();
1327  if ( mProviderKey.isEmpty() )
1328  {
1329  mProviderKey = "gdal";
1330  }
1331  }
1332 
1333  // Open the raster source based on provider and datasource
1334 
1335  // Go down the raster-data-provider paradigm
1336 
1337  // Collect provider-specific information
1338 
1339  QDomNode rpNode = layer_node.namedItem( "rasterproperties" );
1340 
1341  if ( mProviderKey == "wms" )
1342  {
1343  // >>> BACKWARD COMPATIBILITY < 1.9
1344  // The old WMS URI format does not contain all the informations, we add them here.
1345  if ( !mDataSource.contains( "crs=" ) && !mDataSource.contains( "format=" ) )
1346  {
1347  QgsDebugMsg( "Old WMS URI format detected -> adding params" );
1348  QgsDataSourceURI uri;
1349  uri.setEncodedUri( mDataSource );
1350  QDomElement layerElement = rpNode.firstChildElement( "wmsSublayer" );
1351  while ( !layerElement.isNull() )
1352  {
1353  // TODO: sublayer visibility - post-0.8 release timeframe
1354 
1355  // collect name for the sublayer
1356  uri.setParam( "layers", layerElement.namedItem( "name" ).toElement().text() );
1357 
1358  // collect style for the sublayer
1359  uri.setParam( "styles", layerElement.namedItem( "style" ).toElement().text() );
1360 
1361  layerElement = layerElement.nextSiblingElement( "wmsSublayer" );
1362  }
1363 
1364  // Collect format
1365  QDomNode formatNode = rpNode.namedItem( "wmsFormat" );
1366  uri.setParam( "format", rpNode.namedItem( "wmsFormat" ).toElement().text() );
1367 
1368  // WMS CRS URL param should not be mixed with that assigned to the layer.
1369  // In the old WMS URI version there was no CRS and layer crs().authid() was used.
1370  uri.setParam( "crs", crs().authid() );
1371  mDataSource = uri.encodedUri();
1372  }
1373  // <<< BACKWARD COMPATIBILITY < 1.9
1374  }
1375 
1377  if ( !mValid ) return false;
1378 
1379  QString theError;
1380  bool res = readSymbology( layer_node, theError );
1381 
1382  // old wms settings we need to correct
1383  if ( res && mProviderKey == "wms" && ( !renderer() || renderer()->type() != "singlebandcolordata" ) )
1384  {
1386  }
1387 
1388  // Check timestamp
1389  // This was probably introduced to reload completely raster if data changed and
1390  // reset completly symbology to reflect new data type etc. It creates however
1391  // problems, because user defined symbology is complete lost if data file time
1392  // changed (the content may be the same). See also 6900.
1393 #if 0
1394  QDomNode stampNode = layer_node.namedItem( "timestamp" );
1395  if ( !stampNode.isNull() )
1396  {
1397  QDateTime stamp = QDateTime::fromString( stampNode.toElement().text(), Qt::ISODate );
1398  // TODO: very bad, we have to load twice!!! Make QgsDataProvider::timestamp() static?
1399  if ( stamp < mDataProvider->dataTimestamp() )
1400  {
1401  QgsDebugMsg( "data changed, reload provider" );
1403  init();
1405  if ( !mValid ) return false;
1406  }
1407  }
1408 #endif
1409 
1410  // Load user no data value
1411  QDomElement noDataElement = layer_node.firstChildElement( "noData" );
1412 
1413  QDomNodeList noDataBandList = noDataElement.elementsByTagName( "noDataList" );
1414 
1415  for ( int i = 0; i < noDataBandList.size(); ++i )
1416  {
1417  QDomElement bandElement = noDataBandList.at( i ).toElement();
1418  bool ok;
1419  int bandNo = bandElement.attribute( "bandNo" ).toInt( &ok );
1420  QgsDebugMsg( QString( "bandNo = %1" ).arg( bandNo ) );
1421  if ( ok && ( bandNo > 0 ) && ( bandNo <= mDataProvider->bandCount() ) )
1422  {
1423  mDataProvider->setUseSrcNoDataValue( bandNo, bandElement.attribute( "useSrcNoData" ).toInt() );
1424  QgsRasterRangeList myNoDataRangeList;
1425 
1426  QDomNodeList rangeList = bandElement.elementsByTagName( "noDataRange" );
1427 
1428  for ( int j = 0; j < rangeList.size(); ++j )
1429  {
1430  QDomElement rangeElement = rangeList.at( j ).toElement();
1431  QgsRasterRange myNoDataRange( rangeElement.attribute( "min" ).toDouble(),
1432  rangeElement.attribute( "max" ).toDouble() );
1433  QgsDebugMsg( QString( "min = %1 %2" ).arg( rangeElement.attribute( "min" ) ).arg( myNoDataRange.min() ) );
1434  myNoDataRangeList << myNoDataRange;
1435  }
1436  mDataProvider->setUserNoDataValue( bandNo, myNoDataRangeList );
1437  }
1438  }
1439 
1440  return res;
1441 } // QgsRasterLayer::readXml( QDomNode & layer_node )
1442 
1443 /*
1444  * @param QDomNode the node that will have the style element added to it.
1445  * @param QDomDocument the document that will have the QDomNode added.
1446  * @param errorMessage reference to string that will be updated with any error messages
1447  * @return true in case of success.
1448  */
1449 bool QgsRasterLayer::writeSymbology( QDomNode & layer_node, QDomDocument & document, QString& errorMessage ) const
1450 {
1451  Q_UNUSED( errorMessage );
1452  QDomElement layerElem = layer_node.toElement();
1453 
1454  // Store pipe members (except provider) into pipe element, in future, it will be
1455  // possible to add custom filters into the pipe
1456  QDomElement pipeElement = document.createElement( "pipe" );
1457 
1458  for ( int i = 1; i < mPipe.size(); i++ )
1459  {
1460  QgsRasterInterface * interface = mPipe.at( i );
1461  if ( !interface ) continue;
1462  interface->writeXML( document, pipeElement );
1463  }
1464 
1465  layer_node.appendChild( pipeElement );
1466 
1467  // add blend mode node
1468  QDomElement blendModeElement = document.createElement( "blendMode" );
1469  QDomText blendModeText = document.createTextNode( QString::number( QgsMapRenderer::getBlendModeEnum( blendMode() ) ) );
1470  blendModeElement.appendChild( blendModeText );
1471  layer_node.appendChild( blendModeElement );
1472 
1473  return true;
1474 } // bool QgsRasterLayer::writeSymbology
1475 
1476 /*
1477  * virtual
1478  * @note Called by QgsMapLayer::writeXML().
1479  */
1480 bool QgsRasterLayer::writeXml( QDomNode & layer_node,
1481  QDomDocument & document )
1482 {
1483  // first get the layer element so that we can append the type attribute
1484 
1485  QDomElement mapLayerNode = layer_node.toElement();
1486 
1487  if ( mapLayerNode.isNull() || "maplayer" != mapLayerNode.nodeName() )
1488  {
1489  QgsMessageLog::logMessage( tr( "<maplayer> not found." ), tr( "Raster" ) );
1490  return false;
1491  }
1492 
1493  mapLayerNode.setAttribute( "type", "raster" );
1494 
1495  // add provider node
1496 
1497  QDomElement provider = document.createElement( "provider" );
1498  QDomText providerText = document.createTextNode( mProviderKey );
1499  provider.appendChild( providerText );
1500  layer_node.appendChild( provider );
1501 
1502  // User no data
1503  QDomElement noData = document.createElement( "noData" );
1504 
1505  for ( int bandNo = 1; bandNo <= mDataProvider->bandCount(); bandNo++ )
1506  {
1507  if ( mDataProvider->userNoDataValues( bandNo ).isEmpty() ) continue;
1508 
1509  QDomElement noDataRangeList = document.createElement( "noDataList" );
1510  noDataRangeList.setAttribute( "bandNo", bandNo );
1511  noDataRangeList.setAttribute( "useSrcNoData", mDataProvider->useSrcNoDataValue( bandNo ) );
1512 
1513  foreach ( QgsRasterRange range, mDataProvider->userNoDataValues( bandNo ) )
1514  {
1515  QDomElement noDataRange = document.createElement( "noDataRange" );
1516 
1517  noDataRange.setAttribute( "min", range.min() );
1518  noDataRange.setAttribute( "max", range.max() );
1519  noDataRangeList.appendChild( noDataRange );
1520  }
1521 
1522  noData.appendChild( noDataRangeList );
1523 
1524  }
1525  if ( noData.hasChildNodes() )
1526  {
1527  layer_node.appendChild( noData );
1528  }
1529 
1530  //write out the symbology
1531  QString errorMsg;
1532  return writeSymbology( layer_node, document, errorMsg );
1533 }
1534 
1536 {
1537  if ( !mDataProvider ) return 0;
1538  return mDataProvider->xSize();
1539 }
1540 
1542 {
1543  if ( !mDataProvider ) return 0;
1544  return mDataProvider->ySize();
1545 }
1546 
1548 //
1549 // Private methods
1550 //
1553 {
1554  QgsDebugMsg( "entered." );
1555  // Check if data changed
1557  {
1558  QgsDebugMsg( "reload data" );
1560  init();
1562  emit dataChanged();
1563  }
1564  return mValid;
1565 }
QgsDataProvider * classFactoryFunction_t(const QString *)
static void convertRasterProperties(QDomDocument &doc, QDomNode &parentNode, QDomElement &rasterPropertiesElem, QgsRasterLayer *rlayer)
virtual int bandCount() const =0
Get number of bands.
virtual void setSubLayerVisibility(const QString &name, bool vis)
Set the visibility of the given sublayer name.
void setRenderer(QgsRasterRenderer *theRenderer)
Set raster renderer.
#define ERR(message)
void setContrastEnhancementAlgorithm(ContrastEnhancementAlgorithm, bool generateTable=true)
Set the contrast enhancement algorithm.
virtual QStringList subLayers() const
Returns the sublayers of this layer - useful for providers that manage their own layers, such as WMS.
IdentifyFormat
Definition: qgsraster.h:54
A rectangle specified with double values.
Definition: qgsrectangle.h:35
Base class for all map layer types.
Definition: qgsmaplayer.h:46
Interface for all raster shaders.
bool isEmpty() const
test if rectangle is empty
double rasterUnitsPerPixelY()
QgsMapLayer::LayerType type() const
Get the type of the layer.
Definition: qgsmaplayer.cpp:86
double sum
The sum of all cells in the band.
void setCRS(const QgsCoordinateReferenceSystem &theSrcCRS, const QgsCoordinateReferenceSystem &theDestCRS, int srcDatumTransform=-1, int destDatumTransform=-1)
set source and destination CRS
Iterator for sequentially processing raster cells.
void rendererChanged()
Signal emitted when the symbology changes, through call to setRenderer()
DrawingStyle
This enumerator describes the different kinds of drawing we can do.
Definition: qgsraster.h:95
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
static QgsProviderRegistry * instance(QString pluginPath=QString::null)
means of accessing canonical single instance
void setEncodedUri(const QByteArray &uri)
set complete encoded uri (generic mode)
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
virtual QgsCoordinateReferenceSystem crs()=0
static ContrastEnhancementLimits contrastEnhancementLimitsFromString(QString theLimits)
Definition: qgsraster.cpp:39
void setDefaultContrastEnhancement()
Set default contrast enhancement.
void triggerRepaint()
Emit a signal asking for a repaint.
virtual void setUseSrcNoDataValue(int bandNo, bool use)
Set source nodata value usage.
virtual double srcNoDataValue(int bandNo) const
Value representing no data value.
void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for layer.
virtual void setLayerOrder(const QStringList &layers)
Reorders the previously selected sublayers of this layer from bottom to top.
double maximumValue
The maximum cell value in the raster band.
int mWidth
Width, number of columns to be rendered.
QgsRasterInterface * last() const
Definition: qgsrasterpipe.h:86
virtual QgsRasterRangeList userNoDataValues(int bandNo) const
Get list of user no data value ranges.
static QDateTime lastModified(const QString &name)
Return time stamp for given file name.
Raster values range container.
static bool isValidRasterFileName(const QString &theFileNameQString, QString &retError)
This helper checks to see whether the file name appears to be a valid raster file name...
Resample filter pipe for rasters.
Abstract base class for spatial data provider implementations.
void setColorRampItemList(const QList< QgsColorRampShader::ColorRampItem > &theList)
Set custom colormap.
void readXML(const QDomElement &filterElem)
Sets base class members from xml.
bool draw(QgsRenderContext &rendererContext)
This is called when the view on the raster layer needs to be redrawn.
static const double SAMPLE_SIZE
Default sample size (number of pixels) for estimated statistics/histogram calculation.
Q_DECL_DEPRECATED void updateProgress(int, int)
void readXML(const QDomElement &filterElem)
Sets base class members from xml.
void setBlendMode(const QPainter::CompositionMode &blendMode)
Write blend mode for layer.
QString mLayerName
Name of the layer - used for display.
Definition: qgsmaplayer.h:484
void setShader(QgsRasterShader *shader)
Takes ownership of the shader.
BlendMode
Blending modes enum defining the available composition modes that can be used when rendering a layer...
double rasterUnitsPerPixelX()
Returns the number of raster units per each raster pixel.
virtual int ySize() const
void setGreenContrastEnhancement(QgsContrastEnhancement *ce)
Takes ownership.
static QString identifyFormatName(QgsRaster::IdentifyFormat format)
virtual QDateTime dataTimestamp() const
Current time stamp of data source.
static void logMessage(QString message, QString tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
int size() const
Definition: qgsrasterpipe.h:84
QgsCoordinateReferenceSystem mDestCRS
Target coordinate system.
void setDrawingStyle(const QString &theDrawingStyleQString)
Overloaded version of the above function for convenience when restoring from xml. ...
void setRendererForDrawingStyle(const QgsRaster::DrawingStyle &theDrawingStyle)
Sets corresponding renderer for style.
void init()
Initialize default values.
virtual bool useSrcNoDataValue(int bandNo) const
Get source nodata value usage.
const QString & name() const
Get the display name of the layer.
void onProgress(int, double, QString)
receive progress signal from provider
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:33
virtual QgsRasterBandStats bandStatistics(int theBandNo, int theStats=QgsRasterBandStats::All, const QgsRectangle &theExtent=QgsRectangle(), int theSampleSize=0)
Get band statistics.
The drawing pipe for raster layers.
bool readXml(const QDomNode &layer_node)
Reads layer specific state from project file Dom node.
double stdDev
The standard deviation of the cell values.
virtual QStringList subLayers() const
Returns the sublayers of this layer - Useful for providers that manage their own layers, such as WMS.
The RasterBandStats struct is a container for statistics about a single raster band.
static QgsRasterRendererRegistry * instance()
void setError(const QgsError &theError)
Set error message.
Definition: qgsmaplayer.h:472
double mean
The mean cell value for the band.
int height() const
Accessor that returns the height of the (unclipped) raster.
QPainter::CompositionMode blendMode() const
Read blend mode for layer.
void readXML(const QDomElement &filterElem)
Sets base class members from xml.
void setRedContrastEnhancement(QgsContrastEnhancement *ce)
Takes ownership.
QgsRasterRenderer * renderer() const
virtual void setUserNoDataValue(int bandNo, QgsRasterRangeList noData)
int bandCount() const
Get the number of bands in this layer.
QgsDataProvider * provider(const QString &providerKey, const QString &dataSource)
Create an instance of the provider.
void setParam(const QString &key, const QString &value)
Set generic param (generic mode)
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
QgsRasterViewPort mLastViewPort
virtual QGis::DataType srcDataType(int bandNo) const =0
Returns source data type for the band specified by number, source data type may be shorter than dataT...
virtual QgsRectangle extent()=0
Get the extent of the data source.
void statusChanged(QString theStatus)
Emit a signal with status (e.g.
virtual void setExtent(const QgsRectangle &rect)
Set the extent.
bool readSymbology(const QDomNode &node, QString &errorMessage)
Read the symbology for the current layer from the Dom node supplied.
static const double CUMULATIVE_CUT_UPPER
Default cumulative cut upper limit.
~QgsRasterLayer()
The destructor.
ContrastEnhancementLimits
Contrast enhancement limits.
Definition: qgsraster.h:86
qgssize elementCount
The number of not no data cells in the band.
void setMinimumValue(double, bool generateTable=true)
Return the minimum value for the contrast enhancement range.
Raster renderer pipe for single band pseudocolor.
void dataChanged()
This is emitted whenever data or metadata (e.g.
virtual QGis::DataType dataType(int bandNo) const =0
Returns data type for the band specified by number.
QImage previewAsImage(QSize size, QColor bgColor=Qt::white, QImage::Format format=QImage::Format_ARGB32_Premultiplied)
Draws a preview of the rasterlayer into a QImage.
const QString bandName(int theBandNoInt)
Get the name of a band given its number.
bool isvalidrasterfilename_t(QString const &theFileNameQString, QString &retErrMsg)
double min() const
Raster renderer pipe for single band gray.
virtual QString generateBandName(int theBandNumber) const
helper function to create zero padded band names
QgsRasterResampleFilter * resampleFilter() const
Set raster resample filter.
static int typeSize(int dataType)
virtual void setLayerOrder(const QStringList &layers)
Reorder the list of layer names to be rendered by this provider (in order from bottom to top) ...
QgsRasterProjector * projector() const
void setAlphaBand(int band)
bool mValid
Indicates if the layer is valid and can be drawn.
Definition: qgsmaplayer.h:478
void setContrastEnhancement(QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm, QgsRaster::ContrastEnhancementLimits theLimits=QgsRaster::ContrastEnhancementMinMax, QgsRectangle theExtent=QgsRectangle(), int theSampleSize=SAMPLE_SIZE, bool theGenerateLookupTableFlag=true)
Set contrast enhancement algorithm.
void setDataProvider(const QString &provider)
[ data provider interface ] Set the data provider
QgsRasterDataProvider * mDataProvider
Pointer to data provider.
void setRasterShaderFunction(QgsRasterShaderFunction *)
A public method that allows the user to set their own shader function.
Base class for processing filters like renderers, reprojector, resampler etc.
A class to represent a point geometry.
Definition: qgspoint.h:63
void setColorRampType(QgsColorRampShader::ColorRamp_TYPE theColorRampType)
Set the color ramp type.
Q_DECL_DEPRECATED QPixmap previewAsPixmap(QSize size, QColor bgColor=Qt::white)
Draws a preview of the rasterlayer into a pixmap.
Class for storing the component parts of a PostgreSQL/RDBMS datasource URI.
QPixmap paletteAsPixmap(int theBandNumber=1)
Get an 100x100 pixmap of the color palette.
bool shade(double, int *, int *, int *, int *)
Generates and new RGB value based on one input value.
static ContrastEnhancementAlgorithm contrastEnhancementAlgorithmFromString(const QString &contrastEnhancementString)
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
virtual int colorInterpretation(int theBandNo) const
Returns data type for the band specified by number.
QgsCoordinateReferenceSystem mSrcCRS
Source coordinate system.
void progressUpdate(int theValue)
Signal for notifying listeners of long running processes.
static QPainter::CompositionMode getCompositionMode(const QgsMapRenderer::BlendMode &blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode Added in 1.9.
void showProgress(int theValue)
[ data provider interface ] A wrapper function to emit a progress update signal
Registry for raster renderer entries.
bool writeSymbology(QDomNode &, QDomDocument &doc, QString &errorMessage) const
Write the symbology for the layer into the docment provided.
LayerType mRasterType
QgsPoint mBottomRightPoint
Coordinate (in output device coordinate system) of bottom right corner of the part of the raster that...
void setContrastEnhancement(QgsContrastEnhancement *ce)
Takes ownership.
QString metadata()
Obtain GDAL Metadata for this layer.
ContrastEnhancementAlgorithm
This enumerator describes the types of contrast enhancement algorithms that can be used...
QString mProviderKey
[ data provider interface ] Data provider key
Contains information about the context of a rendering operation.
virtual void legendSymbologyItems(QList< QPair< QString, QColor > > &symbolItems) const
Get symbology items if provided by renderer.
QDateTime mLastModified
[ data provider interface ] Timestamp, the last modified time of the data source when the layer was c...
bool remove(int idx)
Remove and delete interface at given index if possible.
QList< QgsRasterRange > QgsRasterRangeList
virtual int xSize() const
Get raster size.
QString mDataSource
data source description string, varies by layer type
Definition: qgsmaplayer.h:481
virtual QString loadDefaultStyle(bool &theResultFlag)
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
virtual QDateTime timestamp() const
Time stamp of data source in the moment when data/metadata were loaded by provider.
virtual QString type() const
virtual QString metadata()=0
Get metadata in a format suitable for feeding directly into a subset of the GUI raster properties "Me...
virtual void reloadData()
Reloads the data from the source.
virtual bool isValid()=0
Returns true if this is a valid layer.
void repaintRequested()
By emitting this signal the layer tells that either appearance or content have been changed and any v...
int mHeight
Distance in map units from bottom edge to top edge for the part of the raster that is to be rendered...
bool update()
Update the layer if it is outdated.
Brightness/contrast filter pipe for rasters.
Class for storing a coordinate reference system (CRS)
Color and saturation filter pipe for rasters.
static const double CUMULATIVE_CUT_LOWER
Default cumulative cut lower limit.
DataType
Raster data types.
Definition: qgis.h:204
virtual QString description() const =0
return description
double range
The range is the distance between min & max.
void setBlueContrastEnhancement(QgsContrastEnhancement *ce)
Takes ownership.
void closeDataProvider()
Close data provider and clear related members.
QgsHueSaturationFilter * hueSaturationFilter() const
double minimumValue
The minimum cell value in the raster band.
Renderer for multiband images with the color components.
Base class for utility classes that encapsulate information necessary for rendering of map layers...
void setLayerName(const QString &name)
Set the display name of the layer.
Definition: qgsmaplayer.cpp:98
const QgsCoordinateReferenceSystem & crs() const
Returns layer's spatial reference system.
void * function(const QString &providerKey, const QString &functionName)
Get pointer to provider function.
void appendError(const QgsErrorMessage &theMessage)
Add error message.
Definition: qgsmaplayer.h:470
Manipulates raster pixel values so that they enhanceContrast or clip into a specified numerical range...
double max() const
QByteArray encodedUri() const
return complete encoded uri (generic mode)
void(*)() cast_to_fptr(void *p)
Definition: qgis.h:301
QgsRasterDataProvider * dataProvider()
Returns the data provider.
static QgsMapRenderer::BlendMode getBlendModeEnum(const QPainter::CompositionMode &blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode Added in 1.9.
virtual void setSubLayerVisibility(QString name, bool vis)
Set the visibility of the given sublayer name.
QString providerType() const
[ data provider interface ] Which provider is being used for this Raster Layer?
QgsPoint mTopLeftPoint
Coordinate (in output device coordinate system) of top left corner of the part of the raster that is ...
virtual bool srcHasNoDataValue(int bandNo) const
virtual bool render()
Do the rendering (based on data stored in the class)
This class provides details of the viewable area that a raster will be rendered into.
virtual QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext)
Return new instance of QgsMapLayerRenderer that will be used for rendering of given context...
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:199
virtual void cumulativeCut(int theBandNo, double theLowerCount, double theUpperCount, double &theLowerValue, double &theUpperValue, const QgsRectangle &theExtent=QgsRectangle(), int theSampleSize=0)
Find values for cumulative pixel count cut.
virtual QList< QgsColorRampShader::ColorRampItem > colorTable(int bandNo) const
double size
Definition: qgssvgcache.cpp:77
QString toString(bool automaticPrecision=false) const
returns string representation of form xmin,ymin xmax,ymax
QgsRasterRenderer * renderer() const
QgsRasterPipe mPipe
bool set(QgsRasterInterface *theInterface)
Insert a new known interface in default place or replace interface of the same role if it already exi...
virtual QgsError error() const
Get current status error.
QList< QPair< QString, QColor > > legendSymbologyItems() const
Returns a list with classification items (Text and color)
Raster renderer pipe that applies colors to a raster.
QgsRasterRendererCreateFunc rendererCreateFunction
virtual QString dataSourceUri() const
Get the data source specification.
void setMaximumValue(double, bool generateTable=true)
Set the maximum value for the contrast enhancement range.
void showStatusMessage(const QString &theMessage)
bool writeXml(QDomNode &layer_node, QDomDocument &doc)
Write layer specific state to project file Dom node.
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:204
QgsBrightnessContrastFilter * brightnessFilter() const
QgsRectangle mDrawnExtent
Intersection of current map extent and layer extent.
QString toProj4() const
Get the Proj Proj4 string representation of this srs.
virtual void reload()
Synchronises with changes in the datasource.
Base class for raster data providers.
int width() const
Accessor that returns the width of the (unclipped) raster.
double sumOfSquares
The sum of the squares.
#define tr(sourceText)
QgsRasterLayer()
Constructor.