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