~ubuntu-branches/ubuntu/wily/qgis/wily

« back to all changes in this revision

Viewing changes to src/core/raster/qgsrasterlayer.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Johan Van de Wauw
  • Date: 2010-07-11 20:23:24 UTC
  • mfrom: (3.1.4 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100711202324-5ktghxa7hracohmr
Tags: 1.4.0+12730-3ubuntu1
* Merge from Debian unstable (LP: #540941).
* Fix compilation issues with QT 4.7
* Add build-depends on libqt4-webkit-dev 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* **************************************************************************
 
2
        qgsrasterlayer.cpp -  description
 
3
   -------------------
 
4
begin                : Sat Jun 22 2002
 
5
copyright            : (C) 2003 by Tim Sutton, Steve Halasz and Gary E.Sherman
 
6
email                : tim at linfiniti.com
 
7
 ***************************************************************************/
 
8
 
 
9
/* **************************************************************************
 
10
 *                                                                         *
 
11
 *   This program is free software; you can redistribute it and/or modify  *
 
12
 *   it under the terms of the GNU General Public License as published by  *
 
13
 *   the Free Software Foundation; either version 2 of the License, or     *
 
14
 *   (at your option) any later version.                                   *
 
15
 *                                                                         *
 
16
 ***************************************************************************/
 
17
/* $Id$ */
 
18
 
 
19
#include "qgsapplication.h"
 
20
#include "qgslogger.h"
 
21
#include "qgsmaplayerregistry.h"
 
22
#include "qgsmaptopixel.h"
 
23
#include "qgsproviderregistry.h"
 
24
#include "qgsrasterbandstats.h"
 
25
#include "qgsrasterlayer.h"
 
26
#include "qgsrasterpyramid.h"
 
27
#include "qgsrectangle.h"
 
28
#include "qgsrendercontext.h"
 
29
#include "qgscoordinatereferencesystem.h"
 
30
 
 
31
#include "gdalwarper.h"
 
32
#include "cpl_conv.h"
 
33
 
 
34
#include "qgspseudocolorshader.h"
 
35
#include "qgsfreakoutshader.h"
 
36
#include "qgscolorrampshader.h"
 
37
 
 
38
#include <cstdio>
 
39
#include <cmath>
 
40
#include <limits>
 
41
 
 
42
#include <QApplication>
 
43
#include <QCursor>
 
44
#include <QDomElement>
 
45
#include <QDomNode>
 
46
#include <QFile>
 
47
#include <QFileInfo>
 
48
#include <QFont>
 
49
#include <QFontMetrics>
 
50
#include <QFrame>
 
51
#include <QImage>
 
52
#include <QLabel>
 
53
#include <QList>
 
54
#include <QMatrix>
 
55
#include <QMessageBox>
 
56
#include <QLibrary>
 
57
#include <QPainter>
 
58
#include <QPixmap>
 
59
#include <QRegExp>
 
60
#include <QSlider>
 
61
#include <QSettings>
 
62
#include "qgslogger.h"
 
63
// workaround for MSVC compiler which already has defined macro max
 
64
// that interferes with calling std::numeric_limits<int>::max
 
65
#ifdef _MSC_VER
 
66
# ifdef max
 
67
#  undef max
 
68
# endif
 
69
#endif
 
70
 
 
71
// Comparison value for equality; i.e., we shouldn't directly compare two
 
72
// floats so it's better to take their difference and see if they're within
 
73
// a certain range -- in this case twenty times the smallest value that
 
74
// doubles can take for the current system.  (Yes, 20 was arbitrary.)
 
75
#define TINY_VALUE  std::numeric_limits<double>::epsilon() * 20
 
76
 
 
77
 
 
78
QgsRasterLayer::QgsRasterLayer(
 
79
  QString const & path,
 
80
  QString const & baseName,
 
81
  bool loadDefaultStyleFlag )
 
82
    : QgsMapLayer( RasterLayer, baseName, path ),
 
83
    // Constant that signals property not used.
 
84
    QSTRING_NOT_SET( "Not Set" ),
 
85
    TRSTRING_NOT_SET( tr( "Not Set" ) ),
 
86
    mStandardDeviations( 0 ),
 
87
    mDataProvider( 0 ),
 
88
    mWidth( std::numeric_limits<int>::max() ),
 
89
    mHeight( std::numeric_limits<int>::max() ),
 
90
    mInvertColor( false )
 
91
{
 
92
 
 
93
  mRasterType = QgsRasterLayer::GrayOrUndefined;
 
94
 
 
95
  mRedBandName = TRSTRING_NOT_SET;
 
96
  mGreenBandName = TRSTRING_NOT_SET;
 
97
  mBlueBandName = TRSTRING_NOT_SET;
 
98
  mGrayBandName = TRSTRING_NOT_SET;
 
99
  mTransparencyBandName = TRSTRING_NOT_SET;
 
100
 
 
101
 
 
102
  mUserDefinedRGBMinimumMaximum = false; //defaults needed to bypass enhanceContrast
 
103
  mUserDefinedGrayMinimumMaximum = false;
 
104
  mRGBMinimumMaximumEstimated = true;
 
105
  mGrayMinimumMaximumEstimated = true;
 
106
 
 
107
  mDrawingStyle = QgsRasterLayer::UndefinedDrawingStyle;
 
108
  mContrastEnhancementAlgorithm = QgsContrastEnhancement::NoEnhancement;
 
109
  mColorShadingAlgorithm = QgsRasterLayer::UndefinedShader;
 
110
  mRasterShader = new QgsRasterShader();
 
111
 
 
112
  mBandCount = 0;
 
113
  mHasPyramids = false;
 
114
  mNoDataValue = -9999.0;
 
115
  mValidNoDataValue = false;
 
116
 
 
117
  mGdalBaseDataset = 0;
 
118
  mGdalDataset = 0;
 
119
 
 
120
  // Initialise the affine transform matrix
 
121
  mGeoTransform[0] =  0;
 
122
  mGeoTransform[1] =  1;
 
123
  mGeoTransform[2] =  0;
 
124
  mGeoTransform[3] =  0;
 
125
  mGeoTransform[4] =  0;
 
126
  mGeoTransform[5] = -1;
 
127
 
 
128
  // set the layer name (uppercase first character)
 
129
 
 
130
  if ( ! baseName.isEmpty() )   // XXX shouldn't this happen in parent?
 
131
  {
 
132
    setLayerName( baseName );
 
133
  }
 
134
 
 
135
  // load the file if one specified
 
136
  if ( ! path.isEmpty() )
 
137
  {
 
138
    readFile( path ); // XXX check for failure?
 
139
 
 
140
    //readFile() is really an extension of the constructor as many imporant fields are set in this method
 
141
    //loadDefaultStyle() can not be called before the layer has actually be opened
 
142
    if ( loadDefaultStyleFlag )
 
143
    {
 
144
      bool defaultLoadedFlag = false;
 
145
      loadDefaultStyle( defaultLoadedFlag );
 
146
      if ( defaultLoadedFlag )
 
147
      {
 
148
        return;
 
149
      }
 
150
    }
 
151
  }
 
152
 
 
153
  //Initialize the last view port structure, should really be a class
 
154
  mLastViewPort.rectXOffset = 0;
 
155
  mLastViewPort.rectXOffsetFloat = 0.0;
 
156
  mLastViewPort.rectYOffset = 0;
 
157
  mLastViewPort.rectYOffsetFloat = 0.0;
 
158
  mLastViewPort.clippedXMin = 0.0;
 
159
  mLastViewPort.clippedXMax = 0.0;
 
160
  mLastViewPort.clippedYMin = 0.0;
 
161
  mLastViewPort.clippedYMax = 0.0;
 
162
  mLastViewPort.clippedWidth = 0;
 
163
  mLastViewPort.clippedHeight = 0;
 
164
  mLastViewPort.drawableAreaXDim = 0;
 
165
  mLastViewPort.drawableAreaYDim = 0;
 
166
 
 
167
} // QgsRasterLayer ctor
 
168
 
 
169
/**
 
170
 * TODO Rename into a general constructor when the old raster interface is retired
 
171
 * @param  dummy  is just there to distinguish this function signature from the old non-provider one.
 
172
 */
 
173
QgsRasterLayer::QgsRasterLayer( int dummy,
 
174
                                QString const & rasterLayerPath,
 
175
                                QString const & baseName,
 
176
                                QString const & providerKey,
 
177
                                QStringList const & layers,
 
178
                                QStringList const & styles,
 
179
                                QString const & format,
 
180
                                QString const & crs )
 
181
    : QgsMapLayer( RasterLayer, baseName, rasterLayerPath ),
 
182
    mStandardDeviations( 0 ),
 
183
    mDataProvider( 0 ),
 
184
    mEditable( false ),
 
185
    mWidth( std::numeric_limits<int>::max() ),
 
186
    mHeight( std::numeric_limits<int>::max() ),
 
187
    mInvertColor( false ),
 
188
    mModified( false ),
 
189
    mProviderKey( providerKey )
 
190
{
 
191
  QgsDebugMsg( "(8 arguments) starting. with layer list of " +
 
192
               layers.join( ", " ) +  " and style list of " + styles.join( ", " ) + " and format of " +
 
193
               format +  " and CRS of " + crs );
 
194
 
 
195
  mBandCount = 0;
 
196
  mRasterShader = new QgsRasterShader();
 
197
 
 
198
  // Initialise the affine transform matrix
 
199
  mGeoTransform[0] =  0;
 
200
  mGeoTransform[1] =  1;
 
201
  mGeoTransform[2] =  0;
 
202
  mGeoTransform[3] =  0;
 
203
  mGeoTransform[4] =  0;
 
204
  mGeoTransform[5] = -1;
 
205
 
 
206
  // if we're given a provider type, try to create and bind one to this layer
 
207
  if ( ! providerKey.isEmpty() )
 
208
  {
 
209
    setDataProvider( providerKey, layers, styles, format, crs );
 
210
  }
 
211
 
 
212
  // Default for the popup menu
 
213
  // TODO: popMenu = 0;
 
214
 
 
215
  // Get the update threshold from user settings. We
 
216
  // do this only on construction to avoid the penality of
 
217
  // fetching this each time the layer is drawn. If the user
 
218
  // changes the threshold from the preferences dialog, it will
 
219
  // have no effect on existing layers
 
220
  // TODO: QSettings settings;
 
221
  // updateThreshold = settings.readNumEntry("Map/updateThreshold", 1000);
 
222
 
 
223
 
 
224
  // TODO: Connect signals from the dataprovider to the qgisapp
 
225
 
 
226
  // Do a passthrough for the status bar text
 
227
  connect(
 
228
    mDataProvider, SIGNAL( statusChanged( QString ) ),
 
229
    this,           SLOT( showStatusMessage( QString ) )
 
230
  );
 
231
  QgsDebugMsg( "(8 arguments) exiting." );
 
232
 
 
233
  emit statusChanged( tr( "QgsRasterLayer created" ) );
 
234
} // QgsRasterLayer ctor
 
235
 
 
236
QgsRasterLayer::~QgsRasterLayer()
 
237
{
 
238
 
 
239
  if ( mProviderKey.isEmpty() )
 
240
  {
 
241
    if ( mGdalBaseDataset )
 
242
    {
 
243
      GDALDereferenceDataset( mGdalBaseDataset );
 
244
    }
 
245
 
 
246
    if ( mGdalDataset )
 
247
    {
 
248
      GDALClose( mGdalDataset );
 
249
    }
 
250
  }
 
251
}
 
252
 
 
253
 
 
254
 
 
255
 
 
256
 
 
257
//////////////////////////////////////////////////////////
 
258
//
 
259
// Static Methods and members
 
260
//
 
261
/////////////////////////////////////////////////////////
 
262
/**
 
263
  Builds the list of file filter strings to later be used by
 
264
  QgisApp::addRasterLayer()
 
265
 
 
266
  We query GDAL for a list of supported raster formats; we then build
 
267
  a list of file filter strings from that list.  We return a string
 
268
  that contains this list that is suitable for use in a
 
269
  QFileDialog::getOpenFileNames() call.
 
270
 
 
271
*/
 
272
void QgsRasterLayer::buildSupportedRasterFileFilter( QString & theFileFiltersString )
 
273
{
 
274
  // first get the GDAL driver manager
 
275
  registerGdalDrivers();
 
276
 
 
277
  // then iterate through all of the supported drivers, adding the
 
278
  // corresponding file filter
 
279
 
 
280
  GDALDriverH myGdalDriver;           // current driver
 
281
 
 
282
  char **myGdalDriverMetadata;        // driver metadata strings
 
283
 
 
284
  QString myGdalDriverLongName( "" ); // long name for the given driver
 
285
  QString myGdalDriverExtension( "" );  // file name extension for given driver
 
286
  QString myGdalDriverDescription;    // QString wrapper of GDAL driver description
 
287
 
 
288
  QStringList metadataTokens;   // essentially the metadata string delimited by '='
 
289
 
 
290
  QStringList catchallFilter;   // for Any file(*.*), but also for those
 
291
  // drivers with no specific file filter
 
292
 
 
293
  GDALDriverH jp2Driver = NULL; // first JPEG2000 driver found
 
294
 
 
295
  // Grind through all the drivers and their respective metadata.
 
296
  // We'll add a file filter for those drivers that have a file
 
297
  // extension defined for them; the others, well, even though
 
298
  // theoreticaly we can open those files because there exists a
 
299
  // driver for them, the user will have to use the "All Files" to
 
300
  // open datasets with no explicitly defined file name extension.
 
301
  // Note that file name extension strings are of the form
 
302
  // "DMD_EXTENSION=.*".  We'll also store the long name of the
 
303
  // driver, which will be found in DMD_LONGNAME, which will have the
 
304
  // same form.
 
305
 
 
306
  for ( int i = 0; i < GDALGetDriverCount(); ++i )
 
307
  {
 
308
    myGdalDriver = GDALGetDriver( i );
 
309
 
 
310
    Q_CHECK_PTR( myGdalDriver );
 
311
 
 
312
    if ( !myGdalDriver )
 
313
    {
 
314
      QgsLogger::warning( "unable to get driver " + QString::number( i ) );
 
315
      continue;
 
316
    }
 
317
    // now we need to see if the driver is for something currently
 
318
    // supported; if not, we give it a miss for the next driver
 
319
 
 
320
    myGdalDriverDescription = GDALGetDescription( myGdalDriver );
 
321
 
 
322
    // QgsDebugMsg(QString("got driver string %1").arg(myGdalDriverDescription));
 
323
 
 
324
    myGdalDriverMetadata = GDALGetMetadata( myGdalDriver, NULL );
 
325
 
 
326
    // presumably we know we've run out of metadta if either the
 
327
    // address is 0, or the first character is null
 
328
    while ( myGdalDriverMetadata && '\0' != myGdalDriverMetadata[0] )
 
329
    {
 
330
      metadataTokens = QString( *myGdalDriverMetadata ).split( "=", QString::SkipEmptyParts );
 
331
      // QgsDebugMsg(QString("\t%1").arg(*myGdalDriverMetadata));
 
332
 
 
333
      // XXX add check for malformed metadataTokens
 
334
 
 
335
      // Note that it's oddly possible for there to be a
 
336
      // DMD_EXTENSION with no corresponding defined extension
 
337
      // string; so we check that there're more than two tokens.
 
338
 
 
339
      if ( metadataTokens.count() > 1 )
 
340
      {
 
341
        if ( "DMD_EXTENSION" == metadataTokens[0] )
 
342
        {
 
343
          myGdalDriverExtension = metadataTokens[1];
 
344
 
 
345
        }
 
346
        else if ( "DMD_LONGNAME" == metadataTokens[0] )
 
347
        {
 
348
          myGdalDriverLongName = metadataTokens[1];
 
349
 
 
350
          // remove any superfluous (.*) strings at the end as
 
351
          // they'll confuse QFileDialog::getOpenFileNames()
 
352
 
 
353
          myGdalDriverLongName.remove( QRegExp( "\\(.*\\)$" ) );
 
354
        }
 
355
      }
 
356
      // if we have both the file name extension and the long name,
 
357
      // then we've all the information we need for the current
 
358
      // driver; therefore emit a file filter string and move to
 
359
      // the next driver
 
360
      if ( !( myGdalDriverExtension.isEmpty() || myGdalDriverLongName.isEmpty() ) )
 
361
      {
 
362
        // XXX add check for SDTS; in that case we want (*CATD.DDF)
 
363
        QString glob = "*." + myGdalDriverExtension;
 
364
        // Add only the first JP2 driver found to the filter list (it's the one GDAL uses)
 
365
        if ( myGdalDriverDescription == "JPEG2000" ||
 
366
             myGdalDriverDescription.startsWith( "JP2" ) ) // JP2ECW, JP2KAK, JP2MrSID
 
367
        {
 
368
          if ( jp2Driver )
 
369
            break; // skip if already found a JP2 driver
 
370
 
 
371
          jp2Driver = myGdalDriver;   // first JP2 driver found
 
372
          glob += " *.j2k";           // add alternate extension
 
373
        }
 
374
        else if ( myGdalDriverDescription == "GTiff" )
 
375
        {
 
376
          glob += " *.tiff";
 
377
        }
 
378
        else if ( myGdalDriverDescription == "JPEG" )
 
379
        {
 
380
          glob += " *.jpeg";
 
381
        }
 
382
 
 
383
        theFileFiltersString += myGdalDriverLongName + " (" + glob.toLower() + " " + glob.toUpper() + ");;";
 
384
 
 
385
        break;            // ... to next driver, if any.
 
386
      }
 
387
 
 
388
      ++myGdalDriverMetadata;
 
389
 
 
390
    }                       // each metadata item
 
391
 
 
392
    if ( myGdalDriverExtension.isEmpty() && !myGdalDriverLongName.isEmpty() )
 
393
    {
 
394
      // Then what we have here is a driver with no corresponding
 
395
      // file extension; e.g., GRASS.  In which case we append the
 
396
      // string to the "catch-all" which will match all file types.
 
397
      // (I.e., "*.*") We use the driver description intead of the
 
398
      // long time to prevent the catch-all line from getting too
 
399
      // large.
 
400
 
 
401
      // ... OTOH, there are some drivers with missing
 
402
      // DMD_EXTENSION; so let's check for them here and handle
 
403
      // them appropriately
 
404
 
 
405
      // USGS DEMs use "*.dem"
 
406
      if ( myGdalDriverDescription.startsWith( "USGSDEM" ) )
 
407
      {
 
408
        QString glob = "*.dem";
 
409
        theFileFiltersString += myGdalDriverLongName + " (" + glob.toLower() + " " + glob.toUpper() + ");;";
 
410
      }
 
411
      else if ( myGdalDriverDescription.startsWith( "DTED" ) )
 
412
      {
 
413
        // DTED use "*.dt0"
 
414
        QString glob = "*.dt0";
 
415
        theFileFiltersString += myGdalDriverLongName + " (" + glob.toLower() + " " + glob.toUpper() + ");;";
 
416
      }
 
417
      else if ( myGdalDriverDescription.startsWith( "MrSID" ) )
 
418
      {
 
419
        // MrSID use "*.sid"
 
420
        QString glob = "*.sid";
 
421
        theFileFiltersString += myGdalDriverLongName + " (" + glob.toLower() + " " + glob.toUpper() + ");;";
 
422
      }
 
423
      else
 
424
      {
 
425
        catchallFilter << QString( GDALGetDescription( myGdalDriver ) );
 
426
      }
 
427
    }
 
428
 
 
429
    myGdalDriverExtension = myGdalDriverLongName = "";  // reset for next driver
 
430
 
 
431
  }                           // each loaded GDAL driver
 
432
 
 
433
  // can't forget the default case
 
434
  theFileFiltersString += tr( "All other files (*)" );
 
435
  QgsDebugMsg( "Raster filter list built: " + theFileFiltersString );
 
436
}                               // buildSupportedRasterFileFilter_()
 
437
 
 
438
/**
 
439
 * This helper checks to see whether the file name appears to be a valid raster file name
 
440
 */
 
441
bool QgsRasterLayer::isValidRasterFileName( QString const & theFileNameQString,
 
442
    QString & retErrMsg )
 
443
{
 
444
 
 
445
  GDALDatasetH myDataset;
 
446
  registerGdalDrivers();
 
447
 
 
448
  CPLErrorReset();
 
449
 
 
450
  //open the file using gdal making sure we have handled locale properly
 
451
  myDataset = GDALOpen( QFile::encodeName( theFileNameQString ).constData(), GA_ReadOnly );
 
452
  if ( myDataset == NULL )
 
453
  {
 
454
    if ( CPLGetLastErrorNo() != CPLE_OpenFailed )
 
455
      retErrMsg = QString::fromUtf8( CPLGetLastErrorMsg() );
 
456
    return false;
 
457
  }
 
458
  else if ( GDALGetRasterCount( myDataset ) == 0 )
 
459
  {
 
460
    GDALClose( myDataset );
 
461
    myDataset = NULL;
 
462
    retErrMsg = "This raster file has no bands and is invalid as a raster layer.";
 
463
    return false;
 
464
  }
 
465
  else
 
466
  {
 
467
    GDALClose( myDataset );
 
468
    return true;
 
469
  }
 
470
}
 
471
 
 
472
bool QgsRasterLayer::isValidRasterFileName( QString const & theFileNameQString )
 
473
 
 
474
{
 
475
  QString retErrMsg;
 
476
 
 
477
  return isValidRasterFileName( theFileNameQString, retErrMsg );
 
478
}
 
479
 
 
480
QDateTime QgsRasterLayer::lastModified( QString const & name )
 
481
{
 
482
  QgsDebugMsg( "name=" + name );
 
483
  QDateTime t;
 
484
 
 
485
  QFileInfo fi( name );
 
486
 
 
487
  // Is it file?
 
488
  if ( !fi.exists() ) return t;
 
489
 
 
490
  t = fi.lastModified();
 
491
 
 
492
  // Check also color table for GRASS
 
493
  if ( name.contains( "cellhd" ) > 0 )
 
494
  { // most probably GRASS
 
495
    QString dir = fi.path();
 
496
    QString map = fi.fileName();
 
497
    fi.setFile( dir + "/../colr/" + map );
 
498
 
 
499
    if ( fi.exists() )
 
500
    {
 
501
      if ( fi.lastModified() > t ) t = fi.lastModified();
 
502
    }
 
503
  }
 
504
 
 
505
  // Check GRASS group members (bands)
 
506
  if ( name.contains( "group" ) > 0 )
 
507
  { // probably GRASS group
 
508
    fi.setFile( name + "/REF" );
 
509
 
 
510
    if ( fi.exists() )
 
511
    {  // most probably GRASS group
 
512
      QFile f( name + "/REF" );
 
513
      if ( f.open( QIODevice::ReadOnly ) )
 
514
      {
 
515
        QString dir = fi.path() + "/../../../";
 
516
 
 
517
        char buf[101];
 
518
        while ( f.readLine( buf, 100 ) != -1 )
 
519
        {
 
520
          QString ln = QString( buf );
 
521
          QStringList sl = ln.trimmed().split( ' ', QString::SkipEmptyParts );
 
522
          QString map = sl.first();
 
523
          sl.pop_front();
 
524
          QString mapset = sl.first();
 
525
 
 
526
          // header
 
527
          fi.setFile( dir + mapset + "/cellhd/" +  map );
 
528
          if ( fi.exists() )
 
529
          {
 
530
            if ( fi.lastModified() > t ) t = fi.lastModified();
 
531
          }
 
532
 
 
533
          // color
 
534
          fi.setFile( dir + mapset + "/colr/" +  map );
 
535
          if ( fi.exists() )
 
536
          {
 
537
            if ( fi.lastModified() > t ) t = fi.lastModified();
 
538
          }
 
539
        }
 
540
      }
 
541
    }
 
542
  }
 
543
 
 
544
  QgsDebugMsg( "last modified = " + t.toString() );
 
545
 
 
546
  return t;
 
547
}
 
548
 
 
549
 
 
550
 
 
551
void QgsRasterLayer::registerGdalDrivers()
 
552
{
 
553
  if ( GDALGetDriverCount() == 0 )
 
554
    GDALAllRegister();
 
555
}
 
556
 
 
557
 
 
558
 
 
559
 
 
560
//////////////////////////////////////////////////////////
 
561
//
 
562
//Random Static convenience function
 
563
//
 
564
/////////////////////////////////////////////////////////
 
565
//TODO: Change these to private function or make seprate class
 
566
// convenience function for building metadata() HTML table cells
 
567
static QString makeTableCell_( QString const & value )
 
568
{
 
569
  return "<p>\n" + value + "</p>\n";
 
570
} // makeTableCell_
 
571
 
 
572
 
 
573
 
 
574
// convenience function for building metadata() HTML table cells
 
575
static QString makeTableCells_( QStringList const & values )
 
576
{
 
577
  QString s( "<tr>" );
 
578
 
 
579
  for ( QStringList::const_iterator i = values.begin();
 
580
        i != values.end();
 
581
        ++i )
 
582
  {
 
583
    s += makeTableCell_( *i );
 
584
  }
 
585
 
 
586
  s += "</tr>";
 
587
 
 
588
  return s;
 
589
} // makeTableCell_
 
590
 
 
591
 
 
592
 
 
593
// convenience function for creating a string list from a C style string list
 
594
static QStringList cStringList2Q_( char ** stringList )
 
595
{
 
596
  QStringList strings;
 
597
 
 
598
  // presume null terminated string list
 
599
  for ( size_t i = 0; stringList[i]; ++i )
 
600
  {
 
601
    strings.append( stringList[i] );
 
602
  }
 
603
 
 
604
  return strings;
 
605
 
 
606
} // cStringList2Q_
 
607
 
 
608
 
 
609
// typedef for the QgsDataProvider class factory
 
610
typedef QgsDataProvider * classFactoryFunction_t( const QString * );
 
611
 
 
612
 
 
613
//
 
614
// global callback function
 
615
//
 
616
int CPL_STDCALL progressCallback( double dfComplete,
 
617
                                  const char * pszMessage,
 
618
                                  void * pProgressArg )
 
619
{
 
620
  static double dfLastComplete = -1.0;
 
621
 
 
622
  QgsRasterLayer * mypLayer = ( QgsRasterLayer * ) pProgressArg;
 
623
 
 
624
  if ( dfLastComplete > dfComplete )
 
625
  {
 
626
    if ( dfLastComplete >= 1.0 )
 
627
      dfLastComplete = -1.0;
 
628
    else
 
629
      dfLastComplete = dfComplete;
 
630
  }
 
631
 
 
632
  if ( floor( dfLastComplete*10 ) != floor( dfComplete*10 ) )
 
633
  {
 
634
    int    nPercent = ( int ) floor( dfComplete * 100 );
 
635
 
 
636
    if ( nPercent == 0 && pszMessage != NULL )
 
637
    {
 
638
      //fprintf( stdout, "%s:", pszMessage );
 
639
    }
 
640
 
 
641
    if ( nPercent == 100 )
 
642
    {
 
643
      //fprintf( stdout, "%d - done.\n", (int) floor(dfComplete*100) );
 
644
      mypLayer->showProgress( 100 );
 
645
    }
 
646
    else
 
647
    {
 
648
      int myProgress = ( int ) floor( dfComplete * 100 );
 
649
      //fprintf( stdout, "%d.", myProgress);
 
650
      mypLayer->showProgress( myProgress );
 
651
      //fflush( stdout );
 
652
    }
 
653
  }
 
654
  dfLastComplete = dfComplete;
 
655
 
 
656
  return TRUE;
 
657
}
 
658
 
 
659
 
 
660
 
 
661
 
 
662
//////////////////////////////////////////////////////////
 
663
//
 
664
// Non Static Public methods
 
665
//
 
666
/////////////////////////////////////////////////////////
 
667
 
 
668
unsigned int QgsRasterLayer::bandCount()
 
669
{
 
670
  return mBandCount;
 
671
}
 
672
 
 
673
const QString QgsRasterLayer::bandName( int theBandNo )
 
674
{
 
675
  if ( theBandNo <= mRasterStatsList.size() && theBandNo > 0 )
 
676
  {
 
677
    //vector starts at base 0, band counts at base1 !
 
678
    return mRasterStatsList[theBandNo - 1].bandName;
 
679
  }
 
680
  else
 
681
  {
 
682
    return QString( "" );
 
683
  }
 
684
}
 
685
 
 
686
int QgsRasterLayer::bandNumber( QString const & theBandName )
 
687
{
 
688
  for ( int myIterator = 0; myIterator < mRasterStatsList.size(); ++myIterator )
 
689
  {
 
690
    //find out the name of this band
 
691
    QgsRasterBandStats myRasterBandStats = mRasterStatsList[myIterator];
 
692
    QgsDebugMsg( "myRasterBandStats.bandName: " + myRasterBandStats.bandName + "  :: theBandName: "
 
693
                 + theBandName );
 
694
 
 
695
    if ( myRasterBandStats.bandName == theBandName )
 
696
    {
 
697
      QgsDebugMsg( "********** band " + QString::number( myRasterBandStats.bandNumber ) +
 
698
                   " was found in bandNumber " + theBandName );
 
699
 
 
700
      return myRasterBandStats.bandNumber;
 
701
    }
 
702
  }
 
703
  QgsDebugMsg( "********** no band was found in bandNumber " + theBandName );
 
704
 
 
705
  return 0;                     //no band was found
 
706
}
 
707
 
 
708
 
 
709
/**
 
710
 * Private method to calculate statistics for a band. Populates rasterStatsMemArray.
 
711
 * Calculates:
 
712
 *
 
713
 * <ul>
 
714
 * <li>myRasterBandStats.elementCount
 
715
 * <li>myRasterBandStats.minimumValue
 
716
 * <li>myRasterBandStats.maximumValue
 
717
 * <li>myRasterBandStats.sum
 
718
 * <li>myRasterBandStats.range
 
719
 * <li>myRasterBandStats.mean
 
720
 * <li>myRasterBandStats.sumOfSquares
 
721
 * <li>myRasterBandStats.stdDev
 
722
 * <li>myRasterBandStats.colorTable
 
723
 * </ul>
 
724
 *
 
725
 * @seealso RasterBandStats
 
726
 * @note This is a cpu intensive and slow task!
 
727
 */
 
728
const QgsRasterBandStats QgsRasterLayer::bandStatistics( int theBandNo )
 
729
{
 
730
  // check if we have received a valid band number
 
731
  if (( GDALGetRasterCount( mGdalDataset ) < theBandNo ) && mRasterType != Palette )
 
732
  {
 
733
    // invalid band id, return nothing
 
734
    QgsRasterBandStats myNullReturnStats;
 
735
    return myNullReturnStats;
 
736
  }
 
737
  if ( mRasterType == Palette && ( theBandNo > 3 ) )
 
738
  {
 
739
    // invalid band id, return nothing
 
740
    QgsRasterBandStats myNullReturnStats;
 
741
    return myNullReturnStats;
 
742
  }
 
743
 
 
744
  // check if we have previously gathered stats for this band...
 
745
  if ( theBandNo < 1 || theBandNo > mRasterStatsList.size() )
 
746
  {
 
747
    // invalid band id, return nothing
 
748
    QgsRasterBandStats myNullReturnStats;
 
749
    return myNullReturnStats;
 
750
  }
 
751
 
 
752
  QgsRasterBandStats myRasterBandStats = mRasterStatsList[theBandNo - 1];
 
753
  myRasterBandStats.bandNumber = theBandNo;
 
754
 
 
755
  // don't bother with this if we already have stats
 
756
  if ( myRasterBandStats.statsGathered )
 
757
  {
 
758
    return myRasterBandStats;
 
759
  }
 
760
  // only print message if we are actually gathering the stats
 
761
  emit statusChanged( tr( "Retrieving stats for %1" ).arg( name() ) );
 
762
  qApp->processEvents();
 
763
  QgsDebugMsg( "stats for band " + QString::number( theBandNo ) );
 
764
  GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
 
765
 
 
766
 
 
767
  QString myColorerpretation = GDALGetColorInterpretationName( GDALGetRasterColorInterpretation( myGdalBand ) );
 
768
 
 
769
  // XXX this sets the element count to a sensible value; but then you ADD to
 
770
  // XXX it later while iterating through all the pixels?
 
771
  //myRasterBandStats.elementCount = mWidth * mHeight;
 
772
 
 
773
  myRasterBandStats.elementCount = 0; // because we'll be counting only VALID pixels later
 
774
 
 
775
  emit statusChanged( tr( "Calculating stats for %1" ).arg( name() ) );
 
776
  //reset the main app progress bar
 
777
  emit drawingProgress( 0, 0 );
 
778
 
 
779
  // let the user know we're going to possibly be taking a while
 
780
  //QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
 
781
 
 
782
  GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
 
783
 
 
784
  int  myNXBlocks, myNYBlocks, myXBlockSize, myYBlockSize;
 
785
  GDALGetBlockSize( myGdalBand, &myXBlockSize, &myYBlockSize );
 
786
 
 
787
  myNXBlocks = ( GDALGetRasterXSize( myGdalBand ) + myXBlockSize - 1 ) / myXBlockSize;
 
788
  myNYBlocks = ( GDALGetRasterYSize( myGdalBand ) + myYBlockSize - 1 ) / myYBlockSize;
 
789
 
 
790
  void *myData = CPLMalloc( myXBlockSize * myYBlockSize * ( GDALGetDataTypeSize( myDataType ) / 8 ) );
 
791
 
 
792
  // unfortunately we need to make two passes through the data to calculate stddev
 
793
  bool myFirstIterationFlag = true;
 
794
 
 
795
  //ifdefs below to remove compiler warning about unused vars
 
796
#ifdef QGISDEBUG
 
797
  int success;
 
798
  double GDALminimum = GDALGetRasterMinimum( myGdalBand, &success );
 
799
 
 
800
  if ( ! success )
 
801
  {
 
802
    QgsDebugMsg( "myGdalBand->GetMinimum() failed" );
 
803
  }
 
804
 
 
805
  double GDALmaximum = GDALGetRasterMaximum( myGdalBand, &success );
 
806
 
 
807
  if ( ! success )
 
808
  {
 
809
    QgsDebugMsg( "myGdalBand->GetMaximum() failed" );
 
810
  }
 
811
 
 
812
  double GDALnodata = GDALGetRasterNoDataValue( myGdalBand, &success );
 
813
 
 
814
  if ( ! success )
 
815
  {
 
816
    QgsDebugMsg( "myGdalBand->GetNoDataValue() failed" );
 
817
  }
 
818
 
 
819
  QgsLogger::debug( "GDALminium: ", GDALminimum, __FILE__, __FUNCTION__, __LINE__ );
 
820
  QgsLogger::debug( "GDALmaximum: ", GDALmaximum, __FILE__, __FUNCTION__, __LINE__ );
 
821
  QgsLogger::debug( "GDALnodata: ", GDALnodata, __FILE__, __FUNCTION__, __LINE__ );
 
822
 
 
823
  double GDALrange[2];          // calculated min/max, as opposed to the
 
824
  // dataset provided
 
825
 
 
826
  GDALComputeRasterMinMax( myGdalBand, 1, GDALrange );
 
827
  QgsLogger::debug( "approximate computed GDALminium:", GDALrange[0], __FILE__, __FUNCTION__, __LINE__, 1 );
 
828
  QgsLogger::debug( "approximate computed GDALmaximum:", GDALrange[1], __FILE__, __FUNCTION__, __LINE__, 1 );
 
829
 
 
830
  GDALComputeRasterMinMax( myGdalBand, 0, GDALrange );
 
831
  QgsLogger::debug( "exactly computed GDALminium:", GDALrange[0] );
 
832
  QgsLogger::debug( "exactly computed GDALmaximum:", GDALrange[1] );
 
833
 
 
834
  QgsDebugMsg( "starting manual stat computation" );
 
835
#endif
 
836
 
 
837
  int myGdalBandXSize = GDALGetRasterXSize( myGdalBand );
 
838
  int myGdalBandYSize = GDALGetRasterYSize( myGdalBand );
 
839
  for ( int iYBlock = 0; iYBlock < myNYBlocks; iYBlock++ )
 
840
  {
 
841
    emit drawingProgress( iYBlock, myNYBlocks * 2 );
 
842
 
 
843
    for ( int iXBlock = 0; iXBlock < myNXBlocks; iXBlock++ )
 
844
    {
 
845
      int  nXValid, nYValid;
 
846
      GDALReadBlock( myGdalBand, iXBlock, iYBlock, myData );
 
847
 
 
848
      // Compute the portion of the block that is valid
 
849
      // for partial edge blocks.
 
850
      if (( iXBlock + 1 ) * myXBlockSize > myGdalBandXSize )
 
851
        nXValid = myGdalBandXSize - iXBlock * myXBlockSize;
 
852
      else
 
853
        nXValid = myXBlockSize;
 
854
 
 
855
      if (( iYBlock + 1 ) * myYBlockSize > myGdalBandYSize )
 
856
        nYValid = myGdalBandYSize - iYBlock * myYBlockSize;
 
857
      else
 
858
        nYValid = myYBlockSize;
 
859
 
 
860
      // Collect the histogram counts.
 
861
      for ( int iY = 0; iY < nYValid; iY++ )
 
862
      {
 
863
        for ( int iX = 0; iX < nXValid; iX++ )
 
864
        {
 
865
          double myValue = readValue( myData, myDataType, iX + ( iY * myXBlockSize ) );
 
866
 
 
867
          if ( mValidNoDataValue && ( fabs( myValue - mNoDataValue ) <= TINY_VALUE || myValue != myValue ) )
 
868
          {
 
869
            continue; // NULL
 
870
          }
 
871
 
 
872
          //only use this element if we have a non null element
 
873
          if ( myFirstIterationFlag )
 
874
          {
 
875
            //this is the first iteration so initialise vars
 
876
            myFirstIterationFlag = false;
 
877
            myRasterBandStats.minimumValue = myValue;
 
878
            myRasterBandStats.maximumValue = myValue;
 
879
            ++myRasterBandStats.elementCount;
 
880
          }               //end of true part for first iteration check
 
881
          else
 
882
          {
 
883
            //this is done for all subsequent iterations
 
884
            if ( myValue < myRasterBandStats.minimumValue )
 
885
            {
 
886
              myRasterBandStats.minimumValue = myValue;
 
887
            }
 
888
            if ( myValue > myRasterBandStats.maximumValue )
 
889
            {
 
890
              myRasterBandStats.maximumValue = myValue;
 
891
            }
 
892
 
 
893
            myRasterBandStats.sum += myValue;
 
894
            ++myRasterBandStats.elementCount;
 
895
          }               //end of false part for first iteration check
 
896
        }
 
897
      }
 
898
    }                       //end of column wise loop
 
899
  }                           //end of row wise loop
 
900
 
 
901
 
 
902
  //end of first pass through data now calculate the range
 
903
  myRasterBandStats.range = myRasterBandStats.maximumValue - myRasterBandStats.minimumValue;
 
904
  //calculate the mean
 
905
  myRasterBandStats.mean = myRasterBandStats.sum / myRasterBandStats.elementCount;
 
906
 
 
907
  //for the second pass we will get the sum of the squares / mean
 
908
  for ( int iYBlock = 0; iYBlock < myNYBlocks; iYBlock++ )
 
909
  {
 
910
    emit drawingProgress( iYBlock + myNYBlocks, myNYBlocks * 2 );
 
911
 
 
912
    for ( int iXBlock = 0; iXBlock < myNXBlocks; iXBlock++ )
 
913
    {
 
914
      int  nXValid, nYValid;
 
915
 
 
916
      GDALReadBlock( myGdalBand, iXBlock, iYBlock, myData );
 
917
 
 
918
      // Compute the portion of the block that is valid
 
919
      // for partial edge blocks.
 
920
      if (( iXBlock + 1 ) * myXBlockSize > myGdalBandXSize )
 
921
        nXValid = myGdalBandXSize - iXBlock * myXBlockSize;
 
922
      else
 
923
        nXValid = myXBlockSize;
 
924
 
 
925
      if (( iYBlock + 1 ) * myYBlockSize > myGdalBandYSize )
 
926
        nYValid = myGdalBandYSize - iYBlock * myYBlockSize;
 
927
      else
 
928
        nYValid = myYBlockSize;
 
929
 
 
930
      // Collect the histogram counts.
 
931
      for ( int iY = 0; iY < nYValid; iY++ )
 
932
      {
 
933
        for ( int iX = 0; iX < nXValid; iX++ )
 
934
        {
 
935
          double myValue = readValue( myData, myDataType, iX + ( iY * myXBlockSize ) );
 
936
 
 
937
          if ( mValidNoDataValue && ( fabs( myValue - mNoDataValue ) <= TINY_VALUE || myValue != myValue ) )
 
938
          {
 
939
            continue; // NULL
 
940
          }
 
941
 
 
942
          myRasterBandStats.sumOfSquares += static_cast < double >
 
943
                                            ( pow( myValue - myRasterBandStats.mean, 2 ) );
 
944
        }
 
945
      }
 
946
    }                       //end of column wise loop
 
947
  }                           //end of row wise loop
 
948
 
 
949
  //divide result by sample size - 1 and get square root to get stdev
 
950
  myRasterBandStats.stdDev = static_cast < double >( sqrt( myRasterBandStats.sumOfSquares /
 
951
                             ( myRasterBandStats.elementCount - 1 ) ) );
 
952
 
 
953
#ifdef QGISDEBUG
 
954
  QgsLogger::debug( "************ STATS **************", 1, __FILE__, __FUNCTION__, __LINE__ );
 
955
  QgsLogger::debug( "VALID NODATA", mValidNoDataValue, 1, __FILE__, __FUNCTION__, __LINE__ );
 
956
  QgsLogger::debug( "NULL", mNoDataValue, 1, __FILE__, __FUNCTION__, __LINE__ );
 
957
  QgsLogger::debug( "MIN", myRasterBandStats.minimumValue, 1, __FILE__, __FUNCTION__, __LINE__ );
 
958
  QgsLogger::debug( "MAX", myRasterBandStats.maximumValue, 1, __FILE__, __FUNCTION__, __LINE__ );
 
959
  QgsLogger::debug( "RANGE", myRasterBandStats.range, 1, __FILE__, __FUNCTION__, __LINE__ );
 
960
  QgsLogger::debug( "MEAN", myRasterBandStats.mean, 1, __FILE__, __FUNCTION__, __LINE__ );
 
961
  QgsLogger::debug( "STDDEV", myRasterBandStats.stdDev, 1, __FILE__, __FUNCTION__, __LINE__ );
 
962
#endif
 
963
 
 
964
  CPLFree( myData );
 
965
  myRasterBandStats.statsGathered = true;
 
966
 
 
967
  QgsDebugMsg( "adding stats to stats collection at position " + QString::number( theBandNo - 1 ) );
 
968
  //add this band to the class stats map
 
969
  mRasterStatsList[theBandNo - 1] = myRasterBandStats;
 
970
  emit drawingProgress( mHeight, mHeight ); //reset progress
 
971
  //QApplication::restoreOverrideCursor(); //restore the cursor
 
972
  QgsDebugMsg( "Stats collection completed returning" );
 
973
  return myRasterBandStats;
 
974
 
 
975
} // QgsRasterLayer::bandStatistics
 
976
 
 
977
const QgsRasterBandStats QgsRasterLayer::bandStatistics( QString const & theBandName )
 
978
{
 
979
 
 
980
  //we cant use a vector iterator because the iterator is astruct not a class
 
981
  //and the qvector model does not like this.
 
982
  for ( int i = 1; i <= GDALGetRasterCount( mGdalDataset ); i++ )
 
983
  {
 
984
    QgsRasterBandStats myRasterBandStats = bandStatistics( i );
 
985
    if ( myRasterBandStats.bandName == theBandName )
 
986
    {
 
987
      return myRasterBandStats;
 
988
    }
 
989
  }
 
990
 
 
991
  return QgsRasterBandStats();     // return a null one
 
992
}
 
993
 
 
994
 
 
995
/*
 
996
 * This will speed up performance at the expense of hard drive space.
 
997
 * Also, write access to the file is required for creating internal pyramids,
 
998
 * and to the directory in which the files exists if external
 
999
 * pyramids (.ovr) are to be created. If no parameter is passed in
 
1000
 * it will default to nearest neighbor resampling.
 
1001
 *
 
1002
 * @param theTryInternalFlag - Try to make the pyramids internal if supported (e.g. geotiff). If not supported it will revert to creating external .ovr file anyway.
 
1003
 * @return null string on success, otherwise a string specifying error
 
1004
 */
 
1005
QString QgsRasterLayer::buildPyramids( RasterPyramidList const & theRasterPyramidList,
 
1006
                                       QString const & theResamplingMethod, bool theTryInternalFlag )
 
1007
{
 
1008
  //TODO: Consider making theRasterPyramidList modifyable by this method to indicate if the pyramid exists after build attempt
 
1009
  //without requiring the user to rebuild the pyramid list to get the updated infomation
 
1010
 
 
1011
  //
 
1012
  // Note: Make sure the raster is not opened in write mode
 
1013
  // in order to force overviews to be written to a separate file.
 
1014
  // Otherwise reoopen it in read/write mode to stick overviews
 
1015
  // into the same file (if supported)
 
1016
  //
 
1017
 
 
1018
 
 
1019
  emit drawingProgress( 0, 0 );
 
1020
  //first test if the file is writeable
 
1021
  QFileInfo myQFile( mDataSource );
 
1022
 
 
1023
  if ( !myQFile.isWritable() )
 
1024
  {
 
1025
    return "ERROR_WRITE_ACCESS";
 
1026
  }
 
1027
 
 
1028
  if ( mGdalDataset != mGdalBaseDataset )
 
1029
  {
 
1030
    QgsLogger::warning( "Pyramid building not currently supported for 'warped virtual dataset'." );
 
1031
    return "ERROR_VIRTUAL";
 
1032
  }
 
1033
 
 
1034
  if ( theTryInternalFlag )
 
1035
  {
 
1036
    // libtiff < 4.0 has a bug that prevents safe building of overviews on JPEG compressed files
 
1037
    // we detect libtiff < 4.0 by checking that BIGTIFF is not in the creation options of the GTiff driver
 
1038
    // see https://trac.osgeo.org/qgis/ticket/1357
 
1039
    const char* pszGTiffCreationOptions =
 
1040
      GDALGetMetadataItem( GDALGetDriverByName( "GTiff" ), GDAL_DMD_CREATIONOPTIONLIST, "" );
 
1041
    if ( strstr( pszGTiffCreationOptions, "BIGTIFF" ) == NULL )
 
1042
    {
 
1043
      QString myCompressionType = QString( GDALGetMetadataItem( mGdalDataset, "COMPRESSION", "IMAGE_STRUCTURE" ) );
 
1044
      if ( "JPEG" == myCompressionType )
 
1045
      {
 
1046
        return "ERROR_JPEG_COMPRESSION";
 
1047
      }
 
1048
    }
 
1049
 
 
1050
    //close the gdal dataset and reopen it in read / write mode
 
1051
    GDALClose( mGdalDataset );
 
1052
    mGdalBaseDataset = GDALOpen( QFile::encodeName( mDataSource ).constData(), GA_Update );
 
1053
 
 
1054
    // if the dataset couldn't be opened in read / write mode, tell the user
 
1055
    if ( !mGdalBaseDataset )
 
1056
    {
 
1057
      mGdalBaseDataset = GDALOpen( QFile::encodeName( mDataSource ).constData(), GA_ReadOnly );
 
1058
      //Since we are not a virtual warped dataset, mGdalDataSet and mGdalBaseDataset are supposed to be the same
 
1059
      mGdalDataset = mGdalBaseDataset;
 
1060
      return "ERROR_WRITE_FORMAT";
 
1061
    }
 
1062
  }
 
1063
 
 
1064
  //
 
1065
  // Iterate through the Raster Layer Pyramid Vector, building any pyramid
 
1066
  // marked as exists in eaxh RasterPyramid struct.
 
1067
  //
 
1068
  CPLErr myError; //in case anything fails
 
1069
  int myCount = 1;
 
1070
  int myTotal = theRasterPyramidList.count();
 
1071
  RasterPyramidList::const_iterator myRasterPyramidIterator;
 
1072
  for ( myRasterPyramidIterator = theRasterPyramidList.begin();
 
1073
        myRasterPyramidIterator != theRasterPyramidList.end();
 
1074
        ++myRasterPyramidIterator )
 
1075
  {
 
1076
#ifdef QGISDEBUG
 
1077
    QgsLogger::debug( "Build pyramids:: Level", ( *myRasterPyramidIterator ).level, 1, __FILE__, __FUNCTION__, __LINE__ );
 
1078
    QgsLogger::debug( "x", ( *myRasterPyramidIterator ).xDim, 1, __FILE__, __FUNCTION__, __LINE__ );
 
1079
    QgsLogger::debug( "y", ( *myRasterPyramidIterator ).yDim, 1, __FILE__, __FUNCTION__, __LINE__ );
 
1080
    QgsLogger::debug( "exists :", ( *myRasterPyramidIterator ).exists,  1, __FILE__, __FUNCTION__, __LINE__ );
 
1081
#endif
 
1082
    if (( *myRasterPyramidIterator ).build )
 
1083
    {
 
1084
      QgsDebugMsg( "Building....." );
 
1085
      emit drawingProgress( myCount, myTotal );
 
1086
      int myOverviewLevelsArray[1] = {( *myRasterPyramidIterator ).level };
 
1087
      /* From : http://remotesensing.org/gdal/classGDALDataset.html#a23
 
1088
       * pszResampling : one of "NEAREST", "AVERAGE" or "MODE" controlling the downsampling method applied.
 
1089
       * nOverviews : number of overviews to build.
 
1090
       * panOverviewList : the list of overview decimation factors to build.
 
1091
       * nBand : number of bands to build overviews for in panBandList. Build for all bands if this is 0.
 
1092
       * panBandList : list of band numbers.
 
1093
       * pfnProgress : a function to call to report progress, or NULL.
 
1094
       * pProgressData : application data to pass to the progress function.
 
1095
       */
 
1096
      //build the pyramid and show progress to console
 
1097
      try
 
1098
      {
 
1099
 
 
1100
        //build the pyramid and show progress to console
 
1101
        //NOTE this (magphase) is disabled in teh gui since it tends
 
1102
        //to create corrupted images. The images can be repaired
 
1103
        //by running one of the other resampling strategies below.
 
1104
        //see ticket #284
 
1105
        if ( theResamplingMethod == tr( "Average Magphase" ) )
 
1106
        {
 
1107
          myError = GDALBuildOverviews( mGdalBaseDataset, "MODE", 1, myOverviewLevelsArray, 0, NULL,
 
1108
                                        progressCallback, this ); //this is the arg for the gdal progress callback
 
1109
        }
 
1110
        else if ( theResamplingMethod == tr( "Average" ) )
 
1111
 
 
1112
        {
 
1113
          myError = GDALBuildOverviews( mGdalBaseDataset, "AVERAGE", 1, myOverviewLevelsArray, 0, NULL,
 
1114
                                        progressCallback, this ); //this is the arg for the gdal progress callback
 
1115
        }
 
1116
        else // fall back to nearest neighbor
 
1117
        {
 
1118
          myError = GDALBuildOverviews( mGdalBaseDataset, "NEAREST", 1, myOverviewLevelsArray, 0, NULL,
 
1119
                                        progressCallback, this ); //this is the arg for the gdal progress callback
 
1120
        }
 
1121
 
 
1122
        if ( myError == CE_Failure || CPLGetLastErrorNo() == CPLE_NotSupported )
 
1123
        {
 
1124
          //something bad happenend
 
1125
          //QString myString = QString (CPLGetLastError());
 
1126
          GDALClose( mGdalBaseDataset );
 
1127
          mGdalBaseDataset = GDALOpen( QFile::encodeName( mDataSource ).constData(), GA_ReadOnly );
 
1128
          //Since we are not a virtual warped dataset, mGdalDataSet and mGdalBaseDataset are supposed to be the same
 
1129
          mGdalDataset = mGdalBaseDataset;
 
1130
 
 
1131
          emit drawingProgress( 0, 0 );
 
1132
          return "FAILED_NOT_SUPPORTED";
 
1133
        }
 
1134
        else
 
1135
        {
 
1136
          //make sure the raster knows it has pyramids
 
1137
          mHasPyramids = true;
 
1138
        }
 
1139
        myCount++;
 
1140
 
 
1141
      }
 
1142
      catch ( CPLErr )
 
1143
      {
 
1144
        QgsLogger::warning( "Pyramid overview building failed!" );
 
1145
      }
 
1146
    }
 
1147
  }
 
1148
 
 
1149
  QgsDebugMsg( "Pyramid overviews built" );
 
1150
  if ( theTryInternalFlag )
 
1151
  {
 
1152
    //close the gdal dataset and reopen it in read only mode
 
1153
    GDALClose( mGdalBaseDataset );
 
1154
    mGdalBaseDataset = GDALOpen( QFile::encodeName( mDataSource ).constData(), GA_ReadOnly );
 
1155
    //Since we are not a virtual warped dataset, mGdalDataSet and mGdalBaseDataset are supposed to be the same
 
1156
    mGdalDataset = mGdalBaseDataset;
 
1157
  }
 
1158
 
 
1159
  emit drawingProgress( 0, 0 );
 
1160
  return NULL; // returning null on success
 
1161
}
 
1162
 
 
1163
 
 
1164
QgsRasterLayer::RasterPyramidList  QgsRasterLayer::buildPyramidList()
 
1165
{
 
1166
  //
 
1167
  // First we build up a list of potential pyramid layers
 
1168
  //
 
1169
  int myWidth = mWidth;
 
1170
  int myHeight = mHeight;
 
1171
  int myDivisor = 2;
 
1172
  GDALRasterBandH myGDALBand = GDALGetRasterBand( mGdalDataset, 1 ); //just use the first band
 
1173
 
 
1174
  mPyramidList.clear();
 
1175
  QgsDebugMsg( "Building initial pyramid list" );
 
1176
  while (( myWidth / myDivisor > 32 ) && (( myHeight / myDivisor ) > 32 ) )
 
1177
  {
 
1178
 
 
1179
    QgsRasterPyramid myRasterPyramid;
 
1180
    myRasterPyramid.level = myDivisor;
 
1181
    myRasterPyramid.xDim = ( int )( 0.5 + ( myWidth / ( double )myDivisor ) );
 
1182
    myRasterPyramid.yDim = ( int )( 0.5 + ( myHeight / ( double )myDivisor ) );
 
1183
    myRasterPyramid.exists = false;
 
1184
#ifdef QGISDEBUG
 
1185
    QgsLogger::debug( "Pyramid", myRasterPyramid.level, 1, __FILE__, __FUNCTION__, __LINE__ );
 
1186
    QgsLogger::debug( "xDim", myRasterPyramid.xDim, 1, __FILE__, __FUNCTION__, __LINE__ );
 
1187
    QgsLogger::debug( "yDim", myRasterPyramid.yDim, 1, __FILE__, __FUNCTION__, __LINE__ );
 
1188
#endif
 
1189
 
 
1190
    //
 
1191
    // Now we check if it actually exists in the raster layer
 
1192
    // and also adjust the dimensions if the dimensions calculated
 
1193
    // above are only a near match.
 
1194
    //
 
1195
    const int myNearMatchLimit = 5;
 
1196
    if ( GDALGetOverviewCount( myGDALBand ) > 0 )
 
1197
    {
 
1198
      int myOverviewCount;
 
1199
      for ( myOverviewCount = 0;
 
1200
            myOverviewCount < GDALGetOverviewCount( myGDALBand );
 
1201
            ++myOverviewCount )
 
1202
      {
 
1203
        GDALRasterBandH myOverview;
 
1204
        myOverview = GDALGetOverview( myGDALBand, myOverviewCount );
 
1205
        int myOverviewXDim = GDALGetRasterBandXSize( myOverview );
 
1206
        int myOverviewYDim = GDALGetRasterBandYSize( myOverview );
 
1207
        //
 
1208
        // here is where we check if its a near match:
 
1209
        // we will see if its within 5 cells either side of
 
1210
        //
 
1211
        QgsDebugMsg( "Checking whether " + QString::number( myRasterPyramid.xDim ) + " x " +
 
1212
                     QString::number( myRasterPyramid.yDim ) + " matches " +
 
1213
                     QString::number( myOverviewXDim ) + " x " + QString::number( myOverviewYDim ) );
 
1214
 
 
1215
 
 
1216
        if (( myOverviewXDim <= ( myRasterPyramid.xDim + myNearMatchLimit ) ) &&
 
1217
            ( myOverviewXDim >= ( myRasterPyramid.xDim - myNearMatchLimit ) ) &&
 
1218
            ( myOverviewYDim <= ( myRasterPyramid.yDim + myNearMatchLimit ) ) &&
 
1219
            ( myOverviewYDim >= ( myRasterPyramid.yDim - myNearMatchLimit ) ) )
 
1220
        {
 
1221
          //right we have a match so adjust the a / y before they get added to the list
 
1222
          myRasterPyramid.xDim = myOverviewXDim;
 
1223
          myRasterPyramid.yDim = myOverviewYDim;
 
1224
          myRasterPyramid.exists = true;
 
1225
          QgsDebugMsg( ".....YES!" );
 
1226
        }
 
1227
        else
 
1228
        {
 
1229
          //no match
 
1230
          QgsDebugMsg( ".....no." );
 
1231
        }
 
1232
      }
 
1233
    }
 
1234
    mPyramidList.append( myRasterPyramid );
 
1235
    //sqare the divisor each step
 
1236
    myDivisor = ( myDivisor * 2 );
 
1237
  }
 
1238
 
 
1239
  return mPyramidList;
 
1240
}
 
1241
 
 
1242
QString QgsRasterLayer::colorShadingAlgorithmAsString() const
 
1243
{
 
1244
  switch ( mColorShadingAlgorithm )
 
1245
  {
 
1246
    case PseudoColorShader:
 
1247
      return QString( "PseudoColorShader" );
 
1248
      break;
 
1249
    case FreakOutShader:
 
1250
      return QString( "FreakOutShader" );
 
1251
      break;
 
1252
    case ColorRampShader:
 
1253
      return QString( "ColorRampShader" );
 
1254
      break;
 
1255
    case UserDefinedShader:
 
1256
      return QString( "UserDefinedShader" );
 
1257
      break;
 
1258
    default:
 
1259
      break;
 
1260
  }
 
1261
 
 
1262
  return QString( "UndefinedShader" );
 
1263
}
 
1264
 
 
1265
/**
 
1266
 * @param theBand The band (number) for which to estimate the min max values
 
1267
 * @param theMinMax Pointer to a double[2] which hold the estimated min max
 
1268
 */
 
1269
void QgsRasterLayer::computeMinimumMaximumEstimates( int theBand, double* theMinMax )
 
1270
{
 
1271
  if ( 0 == theMinMax ) { return; }
 
1272
 
 
1273
  if ( 0 < theBand && theBand <= ( int ) bandCount() )
 
1274
  {
 
1275
    GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBand );
 
1276
    GDALComputeRasterMinMax( myGdalBand, 1, theMinMax );
 
1277
  }
 
1278
}
 
1279
 
 
1280
/**
 
1281
 * @param theBand The band (name) for which to estimate the min max values
 
1282
 * @param theMinMax Pointer to a double[2] which hold the estimated min max
 
1283
 */
 
1284
void QgsRasterLayer::computeMinimumMaximumEstimates( QString theBand, double* theMinMax )
 
1285
{
 
1286
  computeMinimumMaximumEstimates( bandNumber( theBand ), theMinMax );
 
1287
}
 
1288
 
 
1289
/**
 
1290
 * @param theBand The band (number) for which to calculate the min max values
 
1291
 * @param theMinMax Pointer to a double[2] which hold the estimated min max
 
1292
 */
 
1293
void QgsRasterLayer::computeMinimumMaximumFromLastExtent( int theBand, double* theMinMax )
 
1294
{
 
1295
  if ( 0 == theMinMax ) { return; }
 
1296
 
 
1297
  GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBand );
 
1298
  GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
 
1299
  void* myGdalScanData = readData( myGdalBand, &mLastViewPort );
 
1300
 
 
1301
  /* Check for out of memory error */
 
1302
  if ( myGdalScanData == NULL )
 
1303
  {
 
1304
    return;
 
1305
  }
 
1306
 
 
1307
  if ( 0 < theBand && theBand <= ( int ) bandCount() )
 
1308
  {
 
1309
    float myMin = std::numeric_limits<float>::max();
 
1310
    float myMax = -1 * std::numeric_limits<float>::max();
 
1311
    float myValue = 0.0;
 
1312
    for ( int myRow = 0; myRow < mLastViewPort.drawableAreaYDim; ++myRow )
 
1313
    {
 
1314
      for ( int myColumn = 0; myColumn < mLastViewPort.drawableAreaXDim; ++myColumn )
 
1315
      {
 
1316
        myValue = readValue( myGdalScanData, myDataType, myRow * mLastViewPort.drawableAreaXDim + myColumn );
 
1317
        if ( mValidNoDataValue && ( fabs( myValue - mNoDataValue ) <= TINY_VALUE || myValue != myValue ) )
 
1318
        {
 
1319
          continue;
 
1320
        }
 
1321
        myMin = qMin( myMin, myValue );
 
1322
        myMax = qMax( myMax, myValue );
 
1323
      }
 
1324
    }
 
1325
    theMinMax[0] = myMin;
 
1326
    theMinMax[1] = myMax;
 
1327
  }
 
1328
}
 
1329
 
 
1330
/**
 
1331
 * @param theBand The band (name) for which to calculate the min max values
 
1332
 * @param theMinMax Pointer to a double[2] which hold the estimated min max
 
1333
 */
 
1334
void QgsRasterLayer::computeMinimumMaximumFromLastExtent( QString theBand, double* theMinMax )
 
1335
{
 
1336
  computeMinimumMaximumFromLastExtent( bandNumber( theBand ), theMinMax );
 
1337
}
 
1338
 
 
1339
/**
 
1340
 * @param theBand The band (number) for which to get the contrast enhancement for
 
1341
 * @return Pointer to the contrast enhancement or 0 on failure
 
1342
 */
 
1343
QgsContrastEnhancement* QgsRasterLayer::contrastEnhancement( unsigned int theBand )
 
1344
{
 
1345
  if ( 0 < theBand && theBand <= bandCount() )
 
1346
  {
 
1347
    return &mContrastEnhancementList[theBand - 1];
 
1348
  }
 
1349
 
 
1350
  return 0;
 
1351
}
 
1352
 
 
1353
QString QgsRasterLayer::contrastEnhancementAlgorithmAsString() const
 
1354
{
 
1355
  switch ( mContrastEnhancementAlgorithm )
 
1356
  {
 
1357
    case QgsContrastEnhancement::NoEnhancement:
 
1358
      return QString( "NoEnhancement" );
 
1359
      break;
 
1360
    case QgsContrastEnhancement::StretchToMinimumMaximum:
 
1361
      return QString( "StretchToMinimumMaximum" );
 
1362
      break;
 
1363
    case QgsContrastEnhancement::StretchAndClipToMinimumMaximum:
 
1364
      return QString( "StretchAndClipToMinimumMaximum" );
 
1365
      break;
 
1366
    case QgsContrastEnhancement::ClipToMinimumMaximum:
 
1367
      return QString( "ClipToMinimumMaximum" );
 
1368
      break;
 
1369
    case QgsContrastEnhancement::UserDefinedEnhancement:
 
1370
      return QString( "UserDefined" );
 
1371
      break;
 
1372
  }
 
1373
 
 
1374
  return QString( "NoEnhancement" );
 
1375
}
 
1376
 
 
1377
/**
 
1378
 * @note Note implemented yet
 
1379
 * @return always returns false
 
1380
 */
 
1381
bool QgsRasterLayer::copySymbologySettings( const QgsMapLayer& theOther )
 
1382
{
 
1383
  //preventwarnings
 
1384
  if ( theOther.type() < 0 )
 
1385
  {
 
1386
    return false;
 
1387
  }
 
1388
  return false;
 
1389
} //todo
 
1390
 
 
1391
/**
 
1392
 * @param band number
 
1393
 * @return pointer to the color table
 
1394
 */
 
1395
QList<QgsColorRampShader::ColorRampItem>* QgsRasterLayer::colorTable( int theBandNo )
 
1396
{
 
1397
  return &( mRasterStatsList[theBandNo-1].colorTable );
 
1398
}
 
1399
 
 
1400
/**
 
1401
 * @return 0 if not using the data provider model (i.e. directly using GDAL)
 
1402
 */
 
1403
QgsRasterDataProvider* QgsRasterLayer::dataProvider()
 
1404
{
 
1405
  return mDataProvider;
 
1406
}
 
1407
 
 
1408
/**
 
1409
 * @return 0 if not using the data provider model (i.e. directly using GDAL)
 
1410
 */
 
1411
const QgsRasterDataProvider* QgsRasterLayer::dataProvider() const
 
1412
{
 
1413
  return mDataProvider;
 
1414
}
 
1415
 
 
1416
bool QgsRasterLayer::draw( QgsRenderContext& rendererContext )
 
1417
{
 
1418
  QgsDebugMsg( "entered. (renderContext)" );
 
1419
 
 
1420
  // Don't waste time drawing if transparency is at 0 (completely transparent)
 
1421
  if ( mTransparencyLevel == 0 )
 
1422
    return TRUE;
 
1423
 
 
1424
  QgsDebugMsg( "checking timestamp." );
 
1425
 
 
1426
  // Check timestamp
 
1427
  if ( !update() )
 
1428
  {
 
1429
    return FALSE;
 
1430
  }
 
1431
 
 
1432
  const QgsMapToPixel& theQgsMapToPixel = rendererContext.mapToPixel();
 
1433
  const QgsRectangle& theViewExtent = rendererContext.extent();
 
1434
  QPainter* theQPainter = rendererContext.painter();
 
1435
 
 
1436
  if ( !theQPainter )
 
1437
  {
 
1438
    return false;
 
1439
  }
 
1440
 
 
1441
  // clip raster extent to view extent
 
1442
  QgsRectangle myRasterExtent = theViewExtent.intersect( &mLayerExtent );
 
1443
  if ( myRasterExtent.isEmpty() )
 
1444
  {
 
1445
    // nothing to do
 
1446
    return TRUE;
 
1447
  }
 
1448
 
 
1449
  QgsDebugMsg( "theViewExtent is " + theViewExtent.toString() );
 
1450
  QgsDebugMsg( "myRasterExtent is " + myRasterExtent.toString() );
 
1451
 
 
1452
  //
 
1453
  // The first thing we do is set up the QgsRasterViewPort. This struct stores all the settings
 
1454
  // relating to the size (in pixels and coordinate system units) of the raster part that is
 
1455
  // in view in the map window. It also stores the origin.
 
1456
  //
 
1457
  //this is not a class level member because every time the user pans or zooms
 
1458
  //the contents of the rasterViewPort will change
 
1459
  QgsRasterViewPort *myRasterViewPort = new QgsRasterViewPort();
 
1460
 
 
1461
 
 
1462
  // calculate raster pixel offsets from origin to clipped rect
 
1463
  // we're only interested in positive offsets where the origin of the raster
 
1464
  // is northwest of the origin of the view
 
1465
  myRasterViewPort->rectXOffsetFloat = ( theViewExtent.xMinimum() - mLayerExtent.xMinimum() ) / fabs( mGeoTransform[1] );
 
1466
  myRasterViewPort->rectYOffsetFloat = ( mLayerExtent.yMaximum() - theViewExtent.yMaximum() ) / fabs( mGeoTransform[5] );
 
1467
 
 
1468
  if ( myRasterViewPort->rectXOffsetFloat < 0 )
 
1469
  {
 
1470
    myRasterViewPort->rectXOffsetFloat = 0;
 
1471
  }
 
1472
 
 
1473
  if ( myRasterViewPort->rectYOffsetFloat < 0 )
 
1474
  {
 
1475
    myRasterViewPort->rectYOffsetFloat = 0;
 
1476
  }
 
1477
 
 
1478
  myRasterViewPort->rectXOffset = static_cast < int >( myRasterViewPort->rectXOffsetFloat );
 
1479
  myRasterViewPort->rectYOffset = static_cast < int >( myRasterViewPort->rectYOffsetFloat );
 
1480
 
 
1481
  QgsDebugMsg( QString( "mGeoTransform[0] = %1" ).arg( mGeoTransform[0] ) );
 
1482
  QgsDebugMsg( QString( "mGeoTransform[1] = %1" ).arg( mGeoTransform[1] ) );
 
1483
  QgsDebugMsg( QString( "mGeoTransform[2] = %1" ).arg( mGeoTransform[2] ) );
 
1484
  QgsDebugMsg( QString( "mGeoTransform[3] = %1" ).arg( mGeoTransform[3] ) );
 
1485
  QgsDebugMsg( QString( "mGeoTransform[4] = %1" ).arg( mGeoTransform[4] ) );
 
1486
  QgsDebugMsg( QString( "mGeoTransform[5] = %1" ).arg( mGeoTransform[5] ) );
 
1487
 
 
1488
  // get dimensions of clipped raster image in raster pixel space/ RasterIO will do the scaling for us.
 
1489
  // So for example, if the user is zoomed in a long way, there may only be e.g. 5x5 pixels retrieved from
 
1490
  // the raw raster data, but rasterio will seamlessly scale the up to whatever the screen coordinats are
 
1491
  // e.g. a 600x800 display window (see next section below)
 
1492
  myRasterViewPort->clippedXMin = ( myRasterExtent.xMinimum() - mGeoTransform[0] ) / mGeoTransform[1];
 
1493
  myRasterViewPort->clippedXMax = ( myRasterExtent.xMaximum() - mGeoTransform[0] ) / mGeoTransform[1];
 
1494
  myRasterViewPort->clippedYMin = ( myRasterExtent.yMinimum() - mGeoTransform[3] ) / mGeoTransform[5];
 
1495
  myRasterViewPort->clippedYMax = ( myRasterExtent.yMaximum() - mGeoTransform[3] ) / mGeoTransform[5];
 
1496
 
 
1497
  // Sometimes the Ymin/Ymax are reversed.
 
1498
  if ( myRasterViewPort->clippedYMin > myRasterViewPort->clippedYMax )
 
1499
  {
 
1500
    double t = myRasterViewPort->clippedYMin;
 
1501
    myRasterViewPort->clippedYMin = myRasterViewPort->clippedYMax;
 
1502
    myRasterViewPort->clippedYMax = t;
 
1503
  }
 
1504
 
 
1505
  // Set the clipped width and height to encompass all of the source pixels
 
1506
  // that could end up being displayed.
 
1507
  myRasterViewPort->clippedWidth =
 
1508
    static_cast<int>( ceil( myRasterViewPort->clippedXMax ) - floor( myRasterViewPort->clippedXMin ) );
 
1509
 
 
1510
  myRasterViewPort->clippedHeight =
 
1511
    static_cast<int>( ceil( myRasterViewPort->clippedYMax ) - floor( myRasterViewPort->clippedYMin ) );
 
1512
 
 
1513
  // but make sure the intended SE corner extent doesn't exceed the SE corner
 
1514
  // of the source raster, otherwise GDAL's RasterIO gives an error and returns nothing.
 
1515
  // The SE corner = NW origin + dimensions of the image itself.
 
1516
  if (( myRasterViewPort->rectXOffset + myRasterViewPort->clippedWidth )
 
1517
      > mWidth )
 
1518
  {
 
1519
    myRasterViewPort->clippedWidth =
 
1520
      mWidth - myRasterViewPort->rectXOffset;
 
1521
  }
 
1522
  if (( myRasterViewPort->rectYOffset + myRasterViewPort->clippedHeight )
 
1523
      > mHeight )
 
1524
  {
 
1525
    myRasterViewPort->clippedHeight =
 
1526
      mHeight - myRasterViewPort->rectYOffset;
 
1527
  }
 
1528
 
 
1529
  // get dimensions of clipped raster image in device coordinate space (this is the size of the viewport)
 
1530
  myRasterViewPort->topLeftPoint = theQgsMapToPixel.transform( myRasterExtent.xMinimum(), myRasterExtent.yMaximum() );
 
1531
  myRasterViewPort->bottomRightPoint = theQgsMapToPixel.transform( myRasterExtent.xMaximum(), myRasterExtent.yMinimum() );
 
1532
 
 
1533
  myRasterViewPort->drawableAreaXDim = static_cast<int>( fabs(( myRasterViewPort->clippedWidth / theQgsMapToPixel.mapUnitsPerPixel() * mGeoTransform[1] ) ) + 0.5 );
 
1534
  myRasterViewPort->drawableAreaYDim = static_cast<int>( fabs(( myRasterViewPort->clippedHeight / theQgsMapToPixel.mapUnitsPerPixel() * mGeoTransform[5] ) ) + 0.5 );
 
1535
 
 
1536
  QgsDebugMsg( QString( "mapUnitsPerPixel = %1" ).arg( theQgsMapToPixel.mapUnitsPerPixel() ) );
 
1537
  QgsDebugMsg( QString( "mWidth = %1" ).arg( mWidth ) );
 
1538
  QgsDebugMsg( QString( "mHeight = %1" ).arg( mHeight ) );
 
1539
  QgsDebugMsg( QString( "rectXOffset = %1" ).arg( myRasterViewPort->rectXOffset ) );
 
1540
  QgsDebugMsg( QString( "rectXOffsetFloat = %1" ).arg( myRasterViewPort->rectXOffsetFloat ) );
 
1541
  QgsDebugMsg( QString( "rectYOffset = %1" ).arg( myRasterViewPort->rectYOffset ) );
 
1542
  QgsDebugMsg( QString( "rectYOffsetFloat = %1" ).arg( myRasterViewPort->rectYOffsetFloat ) );
 
1543
 
 
1544
  QgsDebugMsg( QString( "myRasterExtent.xMinimum() = %1" ).arg( myRasterExtent.xMinimum() ) );
 
1545
  QgsDebugMsg( QString( "myRasterExtent.xMaximum() = %1" ).arg( myRasterExtent.xMaximum() ) );
 
1546
  QgsDebugMsg( QString( "myRasterExtent.yMinimum() = %1" ).arg( myRasterExtent.yMinimum() ) );
 
1547
  QgsDebugMsg( QString( "myRasterExtent.yMaximum() = %1" ).arg( myRasterExtent.yMaximum() ) );
 
1548
 
 
1549
  QgsDebugMsg( QString( "topLeftPoint.x() = %1" ).arg( myRasterViewPort->topLeftPoint.x() ) );
 
1550
  QgsDebugMsg( QString( "bottomRightPoint.x() = %1" ).arg( myRasterViewPort->bottomRightPoint.x() ) );
 
1551
  QgsDebugMsg( QString( "topLeftPoint.y() = %1" ).arg( myRasterViewPort->topLeftPoint.y() ) );
 
1552
  QgsDebugMsg( QString( "bottomRightPoint.y() = %1" ).arg( myRasterViewPort->bottomRightPoint.y() ) );
 
1553
 
 
1554
  QgsDebugMsg( QString( "clippedXMin = %1" ).arg( myRasterViewPort->clippedXMin ) );
 
1555
  QgsDebugMsg( QString( "clippedXMax = %1" ).arg( myRasterViewPort->clippedXMax ) );
 
1556
  QgsDebugMsg( QString( "clippedYMin = %1" ).arg( myRasterViewPort->clippedYMin ) );
 
1557
  QgsDebugMsg( QString( "clippedYMax = %1" ).arg( myRasterViewPort->clippedYMax ) );
 
1558
 
 
1559
  QgsDebugMsg( QString( "clippedWidth = %1" ).arg( myRasterViewPort->clippedWidth ) );
 
1560
  QgsDebugMsg( QString( "clippedHeight = %1" ).arg( myRasterViewPort->clippedHeight ) );
 
1561
  QgsDebugMsg( QString( "drawableAreaXDim = %1" ).arg( myRasterViewPort->drawableAreaXDim ) );
 
1562
  QgsDebugMsg( QString( "drawableAreaYDim = %1" ).arg( myRasterViewPort->drawableAreaYDim ) );
 
1563
 
 
1564
  QgsDebugMsg( "ReadXml: gray band name : " + mGrayBandName );
 
1565
  QgsDebugMsg( "ReadXml: red band name : " + mRedBandName );
 
1566
  QgsDebugMsg( "ReadXml: green band name : " + mGreenBandName );
 
1567
  QgsDebugMsg( "ReadXml: blue band name : " + mBlueBandName );
 
1568
 
 
1569
  // /\/\/\ - added to handle zoomed-in rasters
 
1570
 
 
1571
  mLastViewPort = *myRasterViewPort;
 
1572
 
 
1573
  // Provider mode: See if a provider key is specified, and if so use the provider instead
 
1574
 
 
1575
  QgsDebugMsg( "Checking for provider key." );
 
1576
 
 
1577
  if ( !mProviderKey.isEmpty() )
 
1578
  {
 
1579
    QgsDebugMsg( "Wanting a '" + mProviderKey + "' provider to draw this." );
 
1580
 
 
1581
    emit statusChanged( tr( "Retrieving %1 using %2" ).arg( name() ).arg( mProviderKey ) );
 
1582
 
 
1583
    mDataProvider->setDpi( rendererContext.rasterScaleFactor() * 25.4 * rendererContext.scaleFactor() );
 
1584
 
 
1585
    QImage* image =
 
1586
      mDataProvider->draw(
 
1587
        myRasterExtent,
 
1588
        // Below should calculate to the actual pixel size of the
 
1589
        // part of the layer that's visible.
 
1590
        static_cast<int>( fabs(( myRasterViewPort->clippedXMax -  myRasterViewPort->clippedXMin )
 
1591
                               / theQgsMapToPixel.mapUnitsPerPixel() * mGeoTransform[1] ) + 1 ),
 
1592
        static_cast<int>( fabs(( myRasterViewPort->clippedYMax -  myRasterViewPort->clippedYMin )
 
1593
                               / theQgsMapToPixel.mapUnitsPerPixel() * mGeoTransform[5] ) + 1 )
 
1594
//                         myRasterViewPort->drawableAreaXDim,
 
1595
//                         myRasterViewPort->drawableAreaYDim
 
1596
      );
 
1597
 
 
1598
    if ( !image )
 
1599
    {
 
1600
      // An error occurred.
 
1601
      mErrorCaption = mDataProvider->lastErrorTitle();
 
1602
      mError        = mDataProvider->lastError();
 
1603
 
 
1604
      delete myRasterViewPort;
 
1605
      return FALSE;
 
1606
    }
 
1607
 
 
1608
    QgsDebugMsg( "Done mDataProvider->draw." );
 
1609
    QgsDebugMsg( "image stats: " );
 
1610
 
 
1611
    QgsDebugMsg( QString( "depth=%1" ).arg( image->depth() ) );
 
1612
    QgsDebugMsg( QString( "bytes=%1" ).arg( image->numBytes() ) );
 
1613
    QgsDebugMsg( QString( "width=%1" ).arg( image->width() ) );
 
1614
    QgsDebugMsg( QString( "height=%1" ).arg( image->height() ) );
 
1615
 
 
1616
    QgsDebugMsg( "Want to theQPainter->drawImage with" );
 
1617
 
 
1618
    QgsDebugMsg( QString( "origin x: %1" ).arg( myRasterViewPort->topLeftPoint.x() ) );
 
1619
    QgsDebugMsg( QString( "(int)origin x: %1" ).arg( static_cast<int>( myRasterViewPort->topLeftPoint.x() ) ) );
 
1620
    QgsDebugMsg( QString( "origin y: %1" ).arg( myRasterViewPort->topLeftPoint.y() ) );
 
1621
    QgsDebugMsg( QString( "(int)origin y: %1" ).arg( static_cast<int>( myRasterViewPort->topLeftPoint.y() ) ) );
 
1622
 
 
1623
    //Set the transparency for the whole layer
 
1624
    //QImage::setAlphaChannel does not work quite as expected so set each pixel individually
 
1625
    //Currently this is only done for WMS images, which should be small enough not to impact performance
 
1626
 
 
1627
    if ( mTransparencyLevel != 255 ) //improve performance if layer transparency not altered
 
1628
    {
 
1629
      QImage* transparentImageCopy = new QImage( *image ); //copy image if there is user transparency
 
1630
      image = transparentImageCopy;
 
1631
      int myWidth = image->width();
 
1632
      int myHeight = image->height();
 
1633
      QRgb myRgb;
 
1634
      int newTransparency;
 
1635
      for ( int myHeightRunner = 0; myHeightRunner < myHeight; myHeightRunner++ )
 
1636
      {
 
1637
        QRgb* myLineBuffer = ( QRgb* ) transparentImageCopy->scanLine( myHeightRunner );
 
1638
        for ( int myWidthRunner = 0; myWidthRunner < myWidth; myWidthRunner++ )
 
1639
        {
 
1640
          myRgb = image->pixel( myWidthRunner, myHeightRunner );
 
1641
          //combine transparency from WMS and layer transparency
 
1642
          newTransparency = ( double ) mTransparencyLevel / 255.0 * ( double )( qAlpha( myRgb ) );
 
1643
          myLineBuffer[ myWidthRunner ] = qRgba( qRed( myRgb ), qGreen( myRgb ), qBlue( myRgb ), newTransparency );
 
1644
        }
 
1645
      }
 
1646
    }
 
1647
 
 
1648
    // Since GDAL's RasterIO can't handle floating point, we have to round to
 
1649
    // the nearest pixel.  Add 0.5 to get rounding instead of truncation
 
1650
    // out of static_cast<int>.
 
1651
    theQPainter->drawImage( static_cast<int>(
 
1652
                              myRasterViewPort->topLeftPoint.x()
 
1653
                              + 0.5    // try simulating rounding instead of truncation, to avoid off-by-one errors
 
1654
                              // TODO: Check for rigorous correctness
 
1655
                            ),
 
1656
                            static_cast<int>(
 
1657
                              myRasterViewPort->topLeftPoint.y()
 
1658
                              + 0.5    // try simulating rounding instead of truncation, to avoid off-by-one errors
 
1659
                              // TODO: Check for rigorous correctness
 
1660
                            ),
 
1661
                            *image );
 
1662
 
 
1663
    if ( mTransparencyLevel != 255 )
 
1664
    {
 
1665
      delete image;
 
1666
    }
 
1667
 
 
1668
    emit statusChanged( tr( "%1 retrieved using %2" ).arg( name() ).arg( mProviderKey ) );
 
1669
  }
 
1670
  else
 
1671
  {
 
1672
    // Otherwise use the old-fashioned GDAL direct-drawing style
 
1673
    // TODO: Move into its own GDAL provider.
 
1674
 
 
1675
    // \/\/\/ - commented-out to handle zoomed-in rasters
 
1676
    //    draw(theQPainter,myRasterViewPort);
 
1677
    // /\/\/\ - commented-out to handle zoomed-in rasters
 
1678
    // \/\/\/ - added to handle zoomed-in rasters
 
1679
    draw( theQPainter, myRasterViewPort, &theQgsMapToPixel );
 
1680
    // /\/\/\ - added to handle zoomed-in rasters
 
1681
  }
 
1682
 
 
1683
  delete myRasterViewPort;
 
1684
  QgsDebugMsg( "exiting." );
 
1685
 
 
1686
  return TRUE;
 
1687
 
 
1688
}
 
1689
 
 
1690
void QgsRasterLayer::draw( QPainter * theQPainter,
 
1691
                           QgsRasterViewPort * theRasterViewPort,
 
1692
                           const QgsMapToPixel* theQgsMapToPixel )
 
1693
{
 
1694
  QgsDebugMsg( " 3 arguments" );
 
1695
  //
 
1696
  //
 
1697
  // The goal here is to make as many decisions as possible early on (outside of the rendering loop)
 
1698
  // so that we can maximise performance of the rendering process. So now we check which drawing
 
1699
  // procedure to use :
 
1700
  //
 
1701
 
 
1702
  switch ( mDrawingStyle )
 
1703
  {
 
1704
      // a "Gray" or "Undefined" layer drawn as a range of gray colors
 
1705
    case SingleBandGray:
 
1706
      //check the band is set!
 
1707
      if ( mGrayBandName == TRSTRING_NOT_SET )
 
1708
      {
 
1709
        break;
 
1710
      }
 
1711
      else
 
1712
      {
 
1713
        drawSingleBandGray( theQPainter, theRasterViewPort,
 
1714
                            theQgsMapToPixel, bandNumber( mGrayBandName ) );
 
1715
        break;
 
1716
      }
 
1717
      // a "Gray" or "Undefined" layer drawn using a pseudocolor algorithm
 
1718
    case SingleBandPseudoColor:
 
1719
      //check the band is set!
 
1720
      if ( mGrayBandName == TRSTRING_NOT_SET )
 
1721
      {
 
1722
        break;
 
1723
      }
 
1724
      else
 
1725
      {
 
1726
        drawSingleBandPseudoColor( theQPainter, theRasterViewPort,
 
1727
                                   theQgsMapToPixel, bandNumber( mGrayBandName ) );
 
1728
        break;
 
1729
      }
 
1730
      // a single band with a color map
 
1731
    case PalettedColor:
 
1732
      //check the band is set!
 
1733
      if ( mGrayBandName == TRSTRING_NOT_SET )
 
1734
      {
 
1735
        break;
 
1736
      }
 
1737
      else
 
1738
      {
 
1739
        QgsDebugMsg( "PalettedColor drawing type detected..." );
 
1740
 
 
1741
        drawPalettedSingleBandColor( theQPainter, theRasterViewPort,
 
1742
                                     theQgsMapToPixel, bandNumber( mGrayBandName ) );
 
1743
 
 
1744
        break;
 
1745
      }
 
1746
      // a "Palette" layer drawn in gray scale (using only one of the color components)
 
1747
    case PalettedSingleBandGray:
 
1748
      //check the band is set!
 
1749
      if ( mGrayBandName == TRSTRING_NOT_SET )
 
1750
      {
 
1751
        break;
 
1752
      }
 
1753
      else
 
1754
      {
 
1755
        QgsDebugMsg( "PalettedSingleBandGray drawing type detected..." );
 
1756
 
 
1757
        int myBandNo = 1;
 
1758
        drawPalettedSingleBandGray( theQPainter, theRasterViewPort,
 
1759
                                    theQgsMapToPixel, myBandNo );
 
1760
 
 
1761
        break;
 
1762
      }
 
1763
      // a "Palette" layer having only one of its color components rendered as psuedo color
 
1764
    case PalettedSingleBandPseudoColor:
 
1765
      //check the band is set!
 
1766
      if ( mGrayBandName == TRSTRING_NOT_SET )
 
1767
      {
 
1768
        break;
 
1769
      }
 
1770
      else
 
1771
      {
 
1772
 
 
1773
        int myBandNo = 1;
 
1774
        drawPalettedSingleBandPseudoColor( theQPainter, theRasterViewPort,
 
1775
                                           theQgsMapToPixel, myBandNo );
 
1776
        break;
 
1777
      }
 
1778
      //a "Palette" image where the bands contains 24bit color info and 8 bits is pulled out per color
 
1779
    case PalettedMultiBandColor:
 
1780
      drawPalettedMultiBandColor( theQPainter, theRasterViewPort,
 
1781
                                  theQgsMapToPixel, 1 );
 
1782
      break;
 
1783
      // a layer containing 2 or more bands, but using only one band to produce a grayscale image
 
1784
    case MultiBandSingleGandGray:
 
1785
      QgsDebugMsg( "MultiBandSingleGandGray drawing type detected..." );
 
1786
      //check the band is set!
 
1787
      if ( mGrayBandName == TRSTRING_NOT_SET )
 
1788
      {
 
1789
        QgsDebugMsg( "MultiBandSingleGandGray Not Set detected..." + mGrayBandName );
 
1790
        break;
 
1791
      }
 
1792
      else
 
1793
      {
 
1794
 
 
1795
        //get the band number for the mapped gray band
 
1796
        drawMultiBandSingleBandGray( theQPainter, theRasterViewPort,
 
1797
                                     theQgsMapToPixel, bandNumber( mGrayBandName ) );
 
1798
        break;
 
1799
      }
 
1800
      //a layer containing 2 or more bands, but using only one band to produce a pseudocolor image
 
1801
    case MultiBandSingleBandPseudoColor:
 
1802
      //check the band is set!
 
1803
      if ( mGrayBandName == TRSTRING_NOT_SET )
 
1804
      {
 
1805
        break;
 
1806
      }
 
1807
      else
 
1808
      {
 
1809
 
 
1810
        drawMultiBandSingleBandPseudoColor( theQPainter, theRasterViewPort,
 
1811
                                            theQgsMapToPixel, bandNumber( mGrayBandName ) );
 
1812
        break;
 
1813
      }
 
1814
      //a layer containing 2 or more bands, mapped to the three RGBcolors.
 
1815
      //In the case of a multiband with only two bands,
 
1816
      //one band will have to be mapped to more than one color
 
1817
    case MultiBandColor:
 
1818
      if ( mRedBandName == TRSTRING_NOT_SET ||
 
1819
           mGreenBandName == TRSTRING_NOT_SET ||
 
1820
           mBlueBandName == TRSTRING_NOT_SET )
 
1821
      {
 
1822
        break;
 
1823
      }
 
1824
      else
 
1825
      {
 
1826
        drawMultiBandColor( theQPainter, theRasterViewPort,
 
1827
                            theQgsMapToPixel );
 
1828
      }
 
1829
      break;
 
1830
 
 
1831
    default:
 
1832
      break;
 
1833
 
 
1834
  }
 
1835
 
 
1836
} //end of draw method
 
1837
 
 
1838
QString QgsRasterLayer::drawingStyleAsString() const
 
1839
{
 
1840
  switch ( mDrawingStyle )
 
1841
  {
 
1842
    case SingleBandGray:
 
1843
      return QString( "SingleBandGray" ); //no need to tr() this its not shown in ui
 
1844
      break;
 
1845
    case SingleBandPseudoColor:
 
1846
      return QString( "SingleBandPseudoColor" );//no need to tr() this its not shown in ui
 
1847
      break;
 
1848
    case PalettedColor:
 
1849
      return QString( "PalettedColor" );//no need to tr() this its not shown in ui
 
1850
      break;
 
1851
    case PalettedSingleBandGray:
 
1852
      return QString( "PalettedSingleBandGray" );//no need to tr() this its not shown in ui
 
1853
      break;
 
1854
    case PalettedSingleBandPseudoColor:
 
1855
      return QString( "PalettedSingleBandPseudoColor" );//no need to tr() this its not shown in ui
 
1856
      break;
 
1857
    case PalettedMultiBandColor:
 
1858
      return QString( "PalettedMultiBandColor" );//no need to tr() this its not shown in ui
 
1859
      break;
 
1860
    case MultiBandSingleGandGray:
 
1861
      return QString( "MultiBandSingleGandGray" );//no need to tr() this its not shown in ui
 
1862
      break;
 
1863
    case MultiBandSingleBandPseudoColor:
 
1864
      return QString( "MultiBandSingleBandPseudoColor" );//no need to tr() this its not shown in ui
 
1865
      break;
 
1866
    case MultiBandColor:
 
1867
      return QString( "MultiBandColor" );//no need to tr() this its not shown in ui
 
1868
      break;
 
1869
    default:
 
1870
      break;
 
1871
  }
 
1872
 
 
1873
  return QString( "UndefinedDrawingStyle" );
 
1874
 
 
1875
}
 
1876
 
 
1877
/**
 
1878
 * @note Note implemented yet
 
1879
 * @return always returns false
 
1880
 */
 
1881
bool QgsRasterLayer::hasCompatibleSymbology( const QgsMapLayer& theOther ) const
 
1882
{
 
1883
  //preventwarnings
 
1884
  if ( theOther.type() < 0 )
 
1885
  {
 
1886
    return false;
 
1887
  }
 
1888
  return false;
 
1889
} //todo
 
1890
 
 
1891
/**
 
1892
 * @param theBandNo The number of the band to check
 
1893
 * @return true if statistics have already been build for this band otherwise false
 
1894
 */
 
1895
bool QgsRasterLayer::hasStatistics( int theBandNo )
 
1896
{
 
1897
  if ( theBandNo <= mRasterStatsList.size() && theBandNo > 0 )
 
1898
  {
 
1899
    //vector starts at base 0, band counts at base1 !
 
1900
    return mRasterStatsList[theBandNo - 1].statsGathered;
 
1901
  }
 
1902
  else
 
1903
  {
 
1904
    return false;
 
1905
  }
 
1906
}
 
1907
 
 
1908
/**
 
1909
 * @param thePoint the QgsPoint for which to obtain pixel values
 
1910
 * @param theResults QMap to hold the pixel values at thePoint for each layer in the raster file
 
1911
 * @return False if WMS layer and true otherwise
 
1912
 */
 
1913
bool QgsRasterLayer::identify( const QgsPoint& thePoint, QMap<QString, QString>& theResults )
 
1914
{
 
1915
  theResults.clear();
 
1916
  if ( mProviderKey == "wms" )
 
1917
  {
 
1918
    return false;
 
1919
  }
 
1920
 
 
1921
  QgsDebugMsg( thePoint.toString() );
 
1922
 
 
1923
  if ( !mLayerExtent.contains( thePoint ) )
 
1924
  {
 
1925
    // Outside the raster
 
1926
    for ( int i = 1; i <= GDALGetRasterCount( mGdalDataset ); i++ )
 
1927
    {
 
1928
      theResults[ generateBandName( i )] = tr( "out of extent" );
 
1929
    }
 
1930
  }
 
1931
  else
 
1932
  {
 
1933
    double x = thePoint.x();
 
1934
    double y = thePoint.y();
 
1935
 
 
1936
    /* Calculate the row / column where the point falls */
 
1937
    double xres = ( mLayerExtent.xMaximum() - mLayerExtent.xMinimum() ) / mWidth;
 
1938
    double yres = ( mLayerExtent.yMaximum() - mLayerExtent.yMinimum() ) / mHeight;
 
1939
 
 
1940
    // Offset, not the cell index -> flor
 
1941
    int col = ( int ) floor(( x - mLayerExtent.xMinimum() ) / xres );
 
1942
    int row = ( int ) floor(( mLayerExtent.yMaximum() - y ) / yres );
 
1943
 
 
1944
    QgsDebugMsg( "row = " + QString::number( row ) + " col = " + QString::number( col ) );
 
1945
 
 
1946
    for ( int i = 1; i <= GDALGetRasterCount( mGdalDataset ); i++ )
 
1947
    {
 
1948
      GDALRasterBandH gdalBand = GDALGetRasterBand( mGdalDataset, i );
 
1949
      GDALDataType type = GDALGetRasterDataType( gdalBand );
 
1950
      int size = GDALGetDataTypeSize( type ) / 8;
 
1951
      void *data = CPLMalloc( size );
 
1952
 
 
1953
      CPLErr err = GDALRasterIO( gdalBand, GF_Read, col, row, 1, 1,
 
1954
                                 data, 1, 1, type, 0, 0 );
 
1955
 
 
1956
      if ( err != CPLE_None )
 
1957
      {
 
1958
        QgsLogger::warning( "RasterIO error: " + QString::fromUtf8( CPLGetLastErrorMsg() ) );
 
1959
      }
 
1960
 
 
1961
      double value = readValue( data, type, 0 );
 
1962
#ifdef QGISDEBUG
 
1963
      QgsLogger::debug( "value", value, 1, __FILE__, __FUNCTION__, __LINE__ );
 
1964
#endif
 
1965
      QString v;
 
1966
 
 
1967
      if ( mValidNoDataValue && ( fabs( value - mNoDataValue ) <= TINY_VALUE || value != value ) )
 
1968
      {
 
1969
        v = tr( "null (no data)" );
 
1970
      }
 
1971
      else
 
1972
      {
 
1973
        v.setNum( value );
 
1974
      }
 
1975
 
 
1976
      theResults[ generateBandName( i )] = v;
 
1977
 
 
1978
      CPLFree( data );
 
1979
    }
 
1980
  }
 
1981
 
 
1982
  return true;
 
1983
} // bool QgsRasterLayer::identify
 
1984
 
 
1985
/**
 
1986
 * @note  The arbitraryness of the returned document is enforced by WMS standards up to at least v1.3.0
 
1987
 *
 
1988
 * @param thePoint  an image pixel coordinate in the last requested extent of layer.
 
1989
 * @return  A text document containing the return from the WMS server
 
1990
 */
 
1991
QString QgsRasterLayer::identifyAsText( const QgsPoint& thePoint )
 
1992
{
 
1993
  if ( mProviderKey != "wms" )
 
1994
  {
 
1995
    // Currently no meaning for anything other than OGC WMS layers
 
1996
    return QString();
 
1997
  }
 
1998
 
 
1999
  return ( mDataProvider->identifyAsText( thePoint ) );
 
2000
}
 
2001
 
 
2002
/**
 
2003
 * @note Note implemented yet
 
2004
 * @return Always returns false
 
2005
 */
 
2006
bool QgsRasterLayer::isEditable() const
 
2007
{
 
2008
  return false;
 
2009
}
 
2010
 
 
2011
QString QgsRasterLayer::lastError()
 
2012
{
 
2013
  return mError;
 
2014
}
 
2015
 
 
2016
QString QgsRasterLayer::lastErrorTitle()
 
2017
{
 
2018
  return mErrorCaption;
 
2019
}
 
2020
 
 
2021
/**
 
2022
 * This is an overloaded version of the legendAsPixmap( bool ) assumes false for the legend name flag.
 
2023
 * @return a pixmap representing a legend image
 
2024
 */
 
2025
QPixmap QgsRasterLayer::legendAsPixmap()
 
2026
{
 
2027
  return legendAsPixmap( false );
 
2028
}
 
2029
 
 
2030
/**
 
2031
 * @param theWithNameFlag - boolena flag whether to overlay the legend name in the text
 
2032
 * @return a pixmap representing a legend image
 
2033
 */
 
2034
QPixmap QgsRasterLayer::legendAsPixmap( bool theWithNameFlag )
 
2035
{
 
2036
  QgsDebugMsg( "called (" + drawingStyleAsString() + ")" );
 
2037
 
 
2038
  QPixmap myLegendQPixmap;      //will be initialised once we know what drawing style is active
 
2039
  QPainter myQPainter;
 
2040
 
 
2041
 
 
2042
  if ( !mProviderKey.isEmpty() )
 
2043
  {
 
2044
    QgsDebugMsg( "provider Key (" + mProviderKey + ")" );
 
2045
    myLegendQPixmap = QPixmap( 3, 1 );
 
2046
    myQPainter.begin( &myLegendQPixmap );
 
2047
    //draw legend red part
 
2048
    myQPainter.setPen( QPen( QColor( 255,   0,   0 ), 0 ) );
 
2049
    myQPainter.drawPoint( 0, 0 );
 
2050
    //draw legend green part
 
2051
    myQPainter.setPen( QPen( QColor( 0, 255,   0 ), 0 ) );
 
2052
    myQPainter.drawPoint( 1, 0 );
 
2053
    //draw legend blue part
 
2054
    myQPainter.setPen( QPen( QColor( 0,   0, 255 ), 0 ) );
 
2055
    myQPainter.drawPoint( 2, 0 );
 
2056
 
 
2057
  }
 
2058
  else
 
2059
  {
 
2060
    // Legacy GDAL (non-provider)
 
2061
 
 
2062
    //
 
2063
    // Get the adjusted matrix stats
 
2064
    //
 
2065
    GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, 1 );
 
2066
    QString myColorerpretation = GDALGetColorInterpretationName( GDALGetRasterColorInterpretation( myGdalBand ) );
 
2067
 
 
2068
 
 
2069
 
 
2070
    //
 
2071
    // Create the legend pixmap - note it is generated on the preadjusted stats
 
2072
    //
 
2073
    if ( mDrawingStyle == MultiBandSingleGandGray || mDrawingStyle == PalettedSingleBandGray || mDrawingStyle == SingleBandGray )
 
2074
    {
 
2075
 
 
2076
      myLegendQPixmap = QPixmap( 100, 1 );
 
2077
      myQPainter.begin( &myLegendQPixmap );
 
2078
      int myPos = 0;
 
2079
      for ( double my = 0; my < 255; my += 2.55 )
 
2080
      {
 
2081
        if ( !mInvertColor ) //histogram is not inverted
 
2082
        {
 
2083
          //draw legend as grayscale
 
2084
          int myGray = static_cast < int >( my );
 
2085
          myQPainter.setPen( QPen( QColor( myGray, myGray, myGray ), 0 ) );
 
2086
        }
 
2087
        else                //histogram is inverted
 
2088
        {
 
2089
          //draw legend as inverted grayscale
 
2090
          int myGray = 255 - static_cast < int >( my );
 
2091
          myQPainter.setPen( QPen( QColor( myGray, myGray, myGray ), 0 ) );
 
2092
        }                   //end of invert histogram  check
 
2093
        myQPainter.drawPoint( myPos++, 0 );
 
2094
      }
 
2095
    }                           //end of gray check
 
2096
    else if ( mDrawingStyle == MultiBandSingleBandPseudoColor ||
 
2097
              mDrawingStyle == PalettedSingleBandPseudoColor || mDrawingStyle == SingleBandPseudoColor )
 
2098
    {
 
2099
 
 
2100
      //set up the three class breaks for pseudocolor mapping
 
2101
      double myRangeSize = 90;  //hard coded for now
 
2102
      double myBreakSize = myRangeSize / 3;
 
2103
      double myClassBreakMin1 = 0;
 
2104
      double myClassBreakMax1 = myClassBreakMin1 + myBreakSize;
 
2105
      double myClassBreakMin2 = myClassBreakMax1;
 
2106
      double myClassBreakMax2 = myClassBreakMin2 + myBreakSize;
 
2107
      double myClassBreakMin3 = myClassBreakMax2;
 
2108
 
 
2109
      //
 
2110
      // Create the legend pixmap - note it is generated on the preadjusted stats
 
2111
      //
 
2112
      myLegendQPixmap = QPixmap( 100, 1 );
 
2113
      myQPainter.begin( &myLegendQPixmap );
 
2114
      int myPos = 0;
 
2115
      for ( double my = 0; my < myRangeSize; my += myRangeSize / 100.0 )
 
2116
      {
 
2117
        //draw pseudocolor legend
 
2118
        if ( !mInvertColor )
 
2119
        {
 
2120
          //check if we are in the first class break
 
2121
          if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) )
 
2122
          {
 
2123
            int myRed = 0;
 
2124
            int myBlue = 255;
 
2125
            int myGreen = static_cast < int >((( 255 / myRangeSize ) * ( my - myClassBreakMin1 ) ) * 3 );
 
2126
            // testing this stuff still ...
 
2127
            if ( mColorShadingAlgorithm == FreakOutShader )
 
2128
            {
 
2129
              myRed = 255 - myGreen;
 
2130
            }
 
2131
            myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
 
2132
          }
 
2133
          //check if we are in the second class break
 
2134
          else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) )
 
2135
          {
 
2136
            int myRed = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 );
 
2137
            int myBlue = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ) );
 
2138
            int myGreen = 255;
 
2139
            // testing this stuff still ...
 
2140
            if ( mColorShadingAlgorithm == FreakOutShader )
 
2141
            {
 
2142
              myGreen = myBlue;
 
2143
            }
 
2144
            myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
 
2145
          }
 
2146
          //otherwise we must be in the third classbreak
 
2147
          else
 
2148
          {
 
2149
            int myRed = 255;
 
2150
            int myBlue = 0;
 
2151
            int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin3 ) / 1 ) * 3 ) ) );
 
2152
            // testing this stuff still ...
 
2153
            if ( mColorShadingAlgorithm == FreakOutShader )
 
2154
            {
 
2155
              myRed = myGreen;
 
2156
              myGreen = 255 - myGreen;
 
2157
            }
 
2158
            myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
 
2159
          }
 
2160
        }                   //end of invert histogram == false check
 
2161
        else                  //invert histogram toggle is off
 
2162
        {
 
2163
          //check if we are in the first class break
 
2164
          if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) )
 
2165
          {
 
2166
            int myRed = 255;
 
2167
            int myBlue = 0;
 
2168
            int myGreen = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin1 ) / 1 ) * 3 ) );
 
2169
            // testing this stuff still ...
 
2170
            if ( mColorShadingAlgorithm == FreakOutShader )
 
2171
            {
 
2172
              myRed = 255 - myGreen;
 
2173
            }
 
2174
            myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
 
2175
          }
 
2176
          //check if we are in the second class break
 
2177
          else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) )
 
2178
          {
 
2179
            int myRed = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ) );
 
2180
            int myBlue = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 );
 
2181
            int myGreen = 255;
 
2182
            // testing this stuff still ...
 
2183
            if ( mColorShadingAlgorithm == FreakOutShader )
 
2184
            {
 
2185
              myGreen = myBlue;
 
2186
            }
 
2187
            myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
 
2188
          }
 
2189
          //otherwise we must be in the third classbreak
 
2190
          else
 
2191
          {
 
2192
            int myRed = 0;
 
2193
            int myBlue = 255;
 
2194
            int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * ( my - myClassBreakMin3 ) ) * 3 ) );
 
2195
            // testing this stuff still ...
 
2196
            if ( mColorShadingAlgorithm == FreakOutShader )
 
2197
            {
 
2198
              myRed = 255 - myGreen;
 
2199
            }
 
2200
            myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
 
2201
          }
 
2202
 
 
2203
        }                   //end of invert histogram check
 
2204
        myQPainter.drawPoint( myPos++, 0 );
 
2205
      }
 
2206
 
 
2207
    }                           //end of pseudocolor check
 
2208
    else if ( mDrawingStyle == PalettedMultiBandColor || mDrawingStyle == MultiBandColor )
 
2209
    {
 
2210
      //
 
2211
      // Create the legend pixmap showing red green and blue band mappings
 
2212
      //
 
2213
      // TODO update this so it actually shows the mappings for paletted images
 
2214
      myLegendQPixmap = QPixmap( 3, 1 );
 
2215
      myQPainter.begin( &myLegendQPixmap );
 
2216
      //draw legend red part
 
2217
      myQPainter.setPen( QPen( QColor( 224, 103, 103 ), 0 ) );
 
2218
      myQPainter.drawPoint( 0, 0 );
 
2219
      //draw legend green part
 
2220
      myQPainter.setPen( QPen( QColor( 132, 224, 127 ), 0 ) );
 
2221
      myQPainter.drawPoint( 1, 0 );
 
2222
      //draw legend blue part
 
2223
      myQPainter.setPen( QPen( QColor( 127, 160, 224 ), 0 ) );
 
2224
      myQPainter.drawPoint( 2, 0 );
 
2225
    }
 
2226
  }
 
2227
 
 
2228
  myQPainter.end();
 
2229
 
 
2230
 
 
2231
  // see if the caller wants the name of the layer in the pixmap (used for legend bar)
 
2232
  if ( theWithNameFlag )
 
2233
  {
 
2234
    QFont myQFont( "arial", 10, QFont::Normal );
 
2235
    QFontMetrics myQFontMetrics( myQFont );
 
2236
 
 
2237
    int myHeight = ( myQFontMetrics.height() + 10 > 35 ) ? myQFontMetrics.height() + 10 : 35;
 
2238
 
 
2239
    //create a matrix to
 
2240
    QMatrix myQWMatrix;
 
2241
    //scale the raster legend up a bit bigger to the legend item size
 
2242
    //note that scaling parameters are factors, not absolute values,
 
2243
    // so scale (0.25,1) scales the painter to a quarter of its size in the x direction
 
2244
    //TODO We need to decide how much to scale by later especially for rgb images which are only 3x1 pix
 
2245
    //hard coding thes values for now.
 
2246
    if ( myLegendQPixmap.width() == 3 )
 
2247
    {
 
2248
      //scale width by factor of 50 (=150px wide)
 
2249
      myQWMatrix.scale( 60, myHeight );
 
2250
    }
 
2251
    else
 
2252
    {
 
2253
      //assume 100px so scale by factor of 1.5 (=150px wide)
 
2254
      myQWMatrix.scale( 1.8, myHeight );
 
2255
    }
 
2256
    //apply the matrix
 
2257
    QPixmap myQPixmap2 = myLegendQPixmap.transformed( myQWMatrix );
 
2258
    QPainter myQPainter( &myQPixmap2 );
 
2259
 
 
2260
    //load  up the pyramid icons
 
2261
    QString myThemePath = QgsApplication::activeThemePath();
 
2262
    QPixmap myPyramidPixmap( myThemePath + "/mIconPyramid.png" );
 
2263
    QPixmap myNoPyramidPixmap( myThemePath + "/mIconNoPyramid.png" );
 
2264
 
 
2265
    //
 
2266
    // Overlay a pyramid icon
 
2267
    //
 
2268
    if ( mHasPyramids )
 
2269
    {
 
2270
      myQPainter.drawPixmap( 0, myHeight - myPyramidPixmap.height(), myPyramidPixmap );
 
2271
    }
 
2272
    else
 
2273
    {
 
2274
      myQPainter.drawPixmap( 0, myHeight - myNoPyramidPixmap.height(), myNoPyramidPixmap );
 
2275
    }
 
2276
    //
 
2277
    // Overlay the layer name
 
2278
    //
 
2279
    if ( mDrawingStyle == MultiBandSingleGandGray || mDrawingStyle == PalettedSingleBandGray || mDrawingStyle == SingleBandGray )
 
2280
    {
 
2281
      myQPainter.setPen( Qt::white );
 
2282
    }
 
2283
    else
 
2284
    {
 
2285
      myQPainter.setPen( Qt::black );
 
2286
    }
 
2287
    myQPainter.setFont( myQFont );
 
2288
    myQPainter.drawText( 25, myHeight - 10, name() );
 
2289
    //
 
2290
    // finish up
 
2291
    //
 
2292
    myLegendQPixmap = myQPixmap2;
 
2293
    myQPainter.end();
 
2294
  }
 
2295
  //finish up
 
2296
 
 
2297
  return myLegendQPixmap;
 
2298
 
 
2299
}                               //end of legendAsPixmap function
 
2300
 
 
2301
/**
 
2302
 * \param int theLabelCountInt Number of vertical labels to display
 
2303
 * @return a pixmap representing a legend image
 
2304
 */
 
2305
QPixmap QgsRasterLayer::legendAsPixmap( int theLabelCount )
 
2306
{
 
2307
  QgsDebugMsg( "entered." );
 
2308
  QFont myQFont( "arial", 10, QFont::Normal );
 
2309
  QFontMetrics myQFontMetrics( myQFont );
 
2310
 
 
2311
  int myFontHeight = ( myQFontMetrics.height() );
 
2312
  const int myerLabelSpacing = 5;
 
2313
  int myImageHeight = (( myFontHeight + ( myerLabelSpacing * 2 ) ) * theLabelCount );
 
2314
  //these next two vars are not used anywhere so commented out for now
 
2315
  //int myLongestLabelWidth =  myQFontMetrics.width(name());
 
2316
  //const int myHorizontalLabelSpacing = 5;
 
2317
  const int myColorBarWidth = 10;
 
2318
  //
 
2319
  // Get the adjusted matrix stats
 
2320
  //
 
2321
  GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, 1 );
 
2322
  QString myColorerpretation = GDALGetColorInterpretationName( GDALGetRasterColorInterpretation( myGdalBand ) );
 
2323
  QPixmap myLegendQPixmap;      //will be initialised once we know what drawing style is active
 
2324
  QPainter myQPainter;
 
2325
  //
 
2326
  // Create the legend pixmap - note it is generated on the preadjusted stats
 
2327
  //
 
2328
  if ( mDrawingStyle == MultiBandSingleGandGray || mDrawingStyle == PalettedSingleBandGray || mDrawingStyle == SingleBandGray )
 
2329
  {
 
2330
 
 
2331
    myLegendQPixmap = QPixmap( 1, myImageHeight );
 
2332
    const double myIncrement = static_cast<double>( myImageHeight ) / 255.0;
 
2333
    myQPainter.begin( &myLegendQPixmap );
 
2334
    int myPos = 0;
 
2335
    for ( double my = 0; my < 255; my += myIncrement )
 
2336
    {
 
2337
      if ( !mInvertColor ) //histogram is not inverted
 
2338
      {
 
2339
        //draw legend as grayscale
 
2340
        int myGray = static_cast < int >( my );
 
2341
        myQPainter.setPen( QPen( QColor( myGray, myGray, myGray ), 0 ) );
 
2342
      }
 
2343
      else                //histogram is inverted
 
2344
      {
 
2345
        //draw legend as inverted grayscale
 
2346
        int myGray = 255 - static_cast < int >( my );
 
2347
        myQPainter.setPen( QPen( QColor( myGray, myGray, myGray ), 0 ) );
 
2348
      }                   //end of invert histogram  check
 
2349
      myQPainter.drawPoint( 0, myPos++ );
 
2350
    }
 
2351
  }                           //end of gray check
 
2352
  else if ( mDrawingStyle == MultiBandSingleBandPseudoColor ||
 
2353
            mDrawingStyle == PalettedSingleBandPseudoColor || mDrawingStyle == SingleBandPseudoColor )
 
2354
  {
 
2355
 
 
2356
    //set up the three class breaks for pseudocolor mapping
 
2357
    double myRangeSize = 90;  //hard coded for now
 
2358
    double myBreakSize = myRangeSize / 3;
 
2359
    double myClassBreakMin1 = 0;
 
2360
    double myClassBreakMax1 = myClassBreakMin1 + myBreakSize;
 
2361
    double myClassBreakMin2 = myClassBreakMax1;
 
2362
    double myClassBreakMax2 = myClassBreakMin2 + myBreakSize;
 
2363
    double myClassBreakMin3 = myClassBreakMax2;
 
2364
 
 
2365
    //
 
2366
    // Create the legend pixmap - note it is generated on the preadjusted stats
 
2367
    //
 
2368
    myLegendQPixmap = QPixmap( 1, myImageHeight );
 
2369
    const double myIncrement = myImageHeight / myRangeSize;
 
2370
    myQPainter.begin( &myLegendQPixmap );
 
2371
    int myPos = 0;
 
2372
    for ( double my = 0; my < 255; my += myIncrement )
 
2373
      for ( double my = 0; my < myRangeSize; my += myIncrement )
 
2374
      {
 
2375
        //draw pseudocolor legend
 
2376
        if ( !mInvertColor )
 
2377
        {
 
2378
          //check if we are in the first class break
 
2379
          if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) )
 
2380
          {
 
2381
            int myRed = 0;
 
2382
            int myBlue = 255;
 
2383
            int myGreen = static_cast < int >((( 255 / myRangeSize ) * ( my - myClassBreakMin1 ) ) * 3 );
 
2384
            // testing this stuff still ...
 
2385
            if ( mColorShadingAlgorithm == FreakOutShader )
 
2386
            {
 
2387
              myRed = 255 - myGreen;
 
2388
            }
 
2389
            myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
 
2390
          }
 
2391
          //check if we are in the second class break
 
2392
          else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) )
 
2393
          {
 
2394
            int myRed = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 );
 
2395
            int myBlue = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ) );
 
2396
            int myGreen = 255;
 
2397
            // testing this stuff still ...
 
2398
            if ( mColorShadingAlgorithm == FreakOutShader )
 
2399
            {
 
2400
              myGreen = myBlue;
 
2401
            }
 
2402
            myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
 
2403
          }
 
2404
          //otherwise we must be in the third classbreak
 
2405
          else
 
2406
          {
 
2407
            int myRed = 255;
 
2408
            int myBlue = 0;
 
2409
            int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin3 ) / 1 ) * 3 ) ) );
 
2410
            // testing this stuff still ...
 
2411
            if ( mColorShadingAlgorithm == FreakOutShader )
 
2412
            {
 
2413
              myRed = myGreen;
 
2414
              myGreen = 255 - myGreen;
 
2415
            }
 
2416
            myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
 
2417
          }
 
2418
        }                   //end of invert histogram == false check
 
2419
        else                  //invert histogram toggle is off
 
2420
        {
 
2421
          //check if we are in the first class break
 
2422
          if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) )
 
2423
          {
 
2424
            int myRed = 255;
 
2425
            int myBlue = 0;
 
2426
            int myGreen = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin1 ) / 1 ) * 3 ) );
 
2427
            // testing this stuff still ...
 
2428
            if ( mColorShadingAlgorithm == FreakOutShader )
 
2429
            {
 
2430
              myRed = 255 - myGreen;
 
2431
            }
 
2432
            myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
 
2433
          }
 
2434
          //check if we are in the second class break
 
2435
          else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) )
 
2436
          {
 
2437
            int myRed = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ) );
 
2438
            int myBlue = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 );
 
2439
            int myGreen = 255;
 
2440
            // testing this stuff still ...
 
2441
            if ( mColorShadingAlgorithm == FreakOutShader )
 
2442
            {
 
2443
              myGreen = myBlue;
 
2444
            }
 
2445
            myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
 
2446
          }
 
2447
          //otherwise we must be in the third classbreak
 
2448
          else
 
2449
          {
 
2450
            int myRed = 0;
 
2451
            int myBlue = 255;
 
2452
            int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * ( my - myClassBreakMin3 ) ) * 3 ) );
 
2453
            // testing this stuff still ...
 
2454
            if ( mColorShadingAlgorithm == FreakOutShader )
 
2455
            {
 
2456
              myRed = 255 - myGreen;
 
2457
            }
 
2458
            myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
 
2459
          }
 
2460
 
 
2461
        }                   //end of invert histogram check
 
2462
        myQPainter.drawPoint( 0, myPos++ );
 
2463
      }
 
2464
 
 
2465
  }                           //end of pseudocolor check
 
2466
  else if ( mDrawingStyle == PalettedMultiBandColor || mDrawingStyle == MultiBandColor )
 
2467
  {
 
2468
    //
 
2469
    // Create the legend pixmap showing red green and blue band mappings
 
2470
    //
 
2471
    // TODO update this so it actually shows the mappings for paletted images
 
2472
    myLegendQPixmap = QPixmap( 1, 3 );
 
2473
    myQPainter.begin( &myLegendQPixmap );
 
2474
    //draw legend red part
 
2475
    myQPainter.setPen( QPen( QColor( 224, 103, 103 ), 0 ) );
 
2476
    myQPainter.drawPoint( 0, 0 );
 
2477
    //draw legend green part
 
2478
    myQPainter.setPen( QPen( QColor( 132, 224, 127 ), 0 ) );
 
2479
    myQPainter.drawPoint( 0, 1 );
 
2480
    //draw legend blue part
 
2481
    myQPainter.setPen( QPen( QColor( 127, 160, 224 ), 0 ) );
 
2482
    myQPainter.drawPoint( 0, 2 );
 
2483
  }
 
2484
 
 
2485
 
 
2486
  myQPainter.end();
 
2487
 
 
2488
 
 
2489
 
 
2490
  //create a matrix to
 
2491
  QMatrix myQWMatrix;
 
2492
  //scale the raster legend up a bit bigger to the legend item size
 
2493
  //note that scaling parameters are factors, not absolute values,
 
2494
  // so scale (0.25,1) scales the painter to a quarter of its size in the x direction
 
2495
  //TODO We need to decide how much to scale by later especially for rgb images which are only 3x1 pix
 
2496
  //hard coding thes values for now.
 
2497
  if ( myLegendQPixmap.height() == 3 )
 
2498
  {
 
2499
    myQWMatrix.scale( myColorBarWidth, 2 );
 
2500
  }
 
2501
  else
 
2502
  {
 
2503
    myQWMatrix.scale( myColorBarWidth, 2 );
 
2504
  }
 
2505
  //apply the matrix
 
2506
  QPixmap myQPixmap2 = myLegendQPixmap.transformed( myQWMatrix );
 
2507
  QPainter myQPainter2( &myQPixmap2 );
 
2508
  //
 
2509
  // Overlay the layer name
 
2510
  //
 
2511
  if ( mDrawingStyle == MultiBandSingleGandGray || mDrawingStyle == PalettedSingleBandGray || mDrawingStyle == SingleBandGray )
 
2512
  {
 
2513
    myQPainter2.setPen( Qt::white );
 
2514
  }
 
2515
  else
 
2516
  {
 
2517
    myQPainter2.setPen( Qt::black );
 
2518
  }
 
2519
  myQPainter2.setFont( myQFont );
 
2520
  myQPainter2.drawText( 25, myImageHeight - 10, name() );
 
2521
  //
 
2522
  // finish up
 
2523
  //
 
2524
  myLegendQPixmap = myQPixmap2;
 
2525
  myQPainter2.end();
 
2526
  //finish up
 
2527
 
 
2528
  return myLegendQPixmap;
 
2529
 
 
2530
}//end of getDetailedLegend
 
2531
 
 
2532
/**
 
2533
 * @param theBand the band number for which to get the maximum pixel value
 
2534
 * @return the maximum pixel value
 
2535
 */
 
2536
double QgsRasterLayer::maximumValue( unsigned int theBand )
 
2537
{
 
2538
  if ( 0 < theBand && theBand <= bandCount() )
 
2539
  {
 
2540
    return mContrastEnhancementList[theBand - 1].maximumValue();
 
2541
  }
 
2542
 
 
2543
  return 0.0;
 
2544
}
 
2545
 
 
2546
/**
 
2547
 * @param theBand the band name for which to get the maximum pixel value
 
2548
 * @return the maximum pixel value
 
2549
 */
 
2550
double QgsRasterLayer::maximumValue( QString theBand )
 
2551
{
 
2552
  if ( theBand != tr( "Not Set" ) )
 
2553
  {
 
2554
    return maximumValue( bandNumber( theBand ) );
 
2555
  }
 
2556
 
 
2557
  return 0.0;
 
2558
}
 
2559
 
 
2560
 
 
2561
QString QgsRasterLayer::metadata()
 
2562
{
 
2563
  QString myMetadata ;
 
2564
  myMetadata += "<p class=\"glossy\">" + tr( "Driver:" ) + "</p>\n";
 
2565
  myMetadata += "<p>";
 
2566
  if ( mProviderKey.isEmpty() )
 
2567
  {
 
2568
    myMetadata += QString( GDALGetDescription( GDALGetDatasetDriver( mGdalDataset ) ) );
 
2569
    myMetadata += "<br>";
 
2570
    myMetadata += QString( GDALGetMetadataItem( GDALGetDatasetDriver( mGdalDataset ), GDAL_DMD_LONGNAME, NULL ) );
 
2571
  }
 
2572
  else
 
2573
  {
 
2574
    myMetadata += mDataProvider->description();
 
2575
  }
 
2576
  myMetadata += "</p>\n";
 
2577
 
 
2578
  if ( !mProviderKey.isEmpty() )
 
2579
  {
 
2580
    // Insert provider-specific (e.g. WMS-specific) metadata
 
2581
    myMetadata += mDataProvider->metadata();
 
2582
  }
 
2583
  else
 
2584
  {
 
2585
 
 
2586
    // my added code (MColetti)
 
2587
 
 
2588
    myMetadata += "<p class=\"glossy\">";
 
2589
    myMetadata += tr( "Dataset Description" );
 
2590
    myMetadata += "</p>\n";
 
2591
    myMetadata += "<p>";
 
2592
    myMetadata += QFile::decodeName( GDALGetDescription( mGdalDataset ) );
 
2593
    myMetadata += "</p>\n";
 
2594
 
 
2595
 
 
2596
    char ** GDALmetadata = GDALGetMetadata( mGdalDataset, NULL );
 
2597
 
 
2598
    if ( GDALmetadata )
 
2599
    {
 
2600
      QStringList metadata = cStringList2Q_( GDALmetadata );
 
2601
      myMetadata += makeTableCells_( metadata );
 
2602
    }
 
2603
    else
 
2604
    {
 
2605
      QgsDebugMsg( "dataset has no metadata" );
 
2606
    }
 
2607
 
 
2608
    for ( int i = 1; i <= GDALGetRasterCount( mGdalDataset ); ++i )
 
2609
    {
 
2610
      myMetadata += "<p class=\"glossy\">" + tr( "Band %1" ).arg( i ) + "</p>\n";
 
2611
      GDALRasterBandH gdalBand = GDALGetRasterBand( mGdalDataset, i );
 
2612
      GDALmetadata = GDALGetMetadata( gdalBand, NULL );
 
2613
 
 
2614
      if ( GDALmetadata )
 
2615
      {
 
2616
        QStringList metadata = cStringList2Q_( GDALmetadata );
 
2617
        myMetadata += makeTableCells_( metadata );
 
2618
      }
 
2619
      else
 
2620
      {
 
2621
        QgsDebugMsg( "band " + QString::number( i ) + "has no metadata" );
 
2622
      }
 
2623
 
 
2624
      char ** GDALcategories = GDALGetRasterCategoryNames( gdalBand );
 
2625
 
 
2626
      if ( GDALcategories )
 
2627
      {
 
2628
        QStringList categories = cStringList2Q_( GDALcategories );
 
2629
        myMetadata += makeTableCells_( categories );
 
2630
      }
 
2631
      else
 
2632
      {
 
2633
        QgsDebugMsg( "band " + QString::number( i ) + " has no categories" );
 
2634
      }
 
2635
 
 
2636
    }
 
2637
 
 
2638
    // end my added code
 
2639
 
 
2640
    myMetadata += "<p class=\"glossy\">";
 
2641
    myMetadata += tr( "Dimensions:" );
 
2642
    myMetadata += "</p>\n";
 
2643
    myMetadata += "<p>";
 
2644
    myMetadata += tr( "X: %1 Y: %2 Bands: %3" )
 
2645
                  .arg( GDALGetRasterXSize( mGdalDataset ) )
 
2646
                  .arg( GDALGetRasterYSize( mGdalDataset ) )
 
2647
                  .arg( GDALGetRasterCount( mGdalDataset ) );
 
2648
    myMetadata += "</p>\n";
 
2649
 
 
2650
    //just use the first band
 
2651
    GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, 1 );
 
2652
 
 
2653
    myMetadata += "<p class=\"glossy\">";
 
2654
    myMetadata += tr( "No Data Value" );
 
2655
    myMetadata += "</p>\n";
 
2656
    myMetadata += "<p>";
 
2657
    if ( mValidNoDataValue )
 
2658
    {
 
2659
      myMetadata += QString::number( mNoDataValue );
 
2660
    }
 
2661
    else
 
2662
    {
 
2663
      myMetadata += "*" + tr( "NoDataValue not set" ) + "*";
 
2664
    }
 
2665
    myMetadata += "</p>\n";
 
2666
 
 
2667
    myMetadata += "</p>\n";
 
2668
    myMetadata += "<p class=\"glossy\">";
 
2669
    myMetadata += tr( "Data Type:" );
 
2670
    myMetadata += "</p>\n";
 
2671
    myMetadata += "<p>";
 
2672
    switch ( GDALGetRasterDataType( myGdalBand ) )
 
2673
    {
 
2674
      case GDT_Byte:
 
2675
        myMetadata += tr( "GDT_Byte - Eight bit unsigned integer" );
 
2676
        break;
 
2677
      case GDT_UInt16:
 
2678
        myMetadata += tr( "GDT_UInt16 - Sixteen bit unsigned integer " );
 
2679
        break;
 
2680
      case GDT_Int16:
 
2681
        myMetadata += tr( "GDT_Int16 - Sixteen bit signed integer " );
 
2682
        break;
 
2683
      case GDT_UInt32:
 
2684
        myMetadata += tr( "GDT_UInt32 - Thirty two bit unsigned integer " );
 
2685
        break;
 
2686
      case GDT_Int32:
 
2687
        myMetadata += tr( "GDT_Int32 - Thirty two bit signed integer " );
 
2688
        break;
 
2689
      case GDT_Float32:
 
2690
        myMetadata += tr( "GDT_Float32 - Thirty two bit floating point " );
 
2691
        break;
 
2692
      case GDT_Float64:
 
2693
        myMetadata += tr( "GDT_Float64 - Sixty four bit floating point " );
 
2694
        break;
 
2695
      case GDT_CInt16:
 
2696
        myMetadata += tr( "GDT_CInt16 - Complex Int16 " );
 
2697
        break;
 
2698
      case GDT_CInt32:
 
2699
        myMetadata += tr( "GDT_CInt32 - Complex Int32 " );
 
2700
        break;
 
2701
      case GDT_CFloat32:
 
2702
        myMetadata += tr( "GDT_CFloat32 - Complex Float32 " );
 
2703
        break;
 
2704
      case GDT_CFloat64:
 
2705
        myMetadata += tr( "GDT_CFloat64 - Complex Float64 " );
 
2706
        break;
 
2707
      default:
 
2708
        myMetadata += tr( "Could not determine raster data type." );
 
2709
    }
 
2710
    myMetadata += "</p>\n";
 
2711
 
 
2712
    myMetadata += "<p class=\"glossy\">";
 
2713
    myMetadata += tr( "Pyramid overviews:" );
 
2714
    myMetadata += "</p>\n";
 
2715
    myMetadata += "<p>";
 
2716
 
 
2717
    if ( GDALGetOverviewCount( myGdalBand ) > 0 )
 
2718
    {
 
2719
      int myOverviewInt;
 
2720
      for ( myOverviewInt = 0;
 
2721
            myOverviewInt < GDALGetOverviewCount( myGdalBand );
 
2722
            myOverviewInt++ )
 
2723
      {
 
2724
        GDALRasterBandH myOverview;
 
2725
        myOverview = GDALGetOverview( myGdalBand, myOverviewInt );
 
2726
        myMetadata += "<p>X : " + QString::number( GDALGetRasterBandXSize( myOverview ) );
 
2727
        myMetadata += ",Y " + QString::number( GDALGetRasterBandYSize( myOverview ) ) + "</p>";
 
2728
      }
 
2729
    }
 
2730
    myMetadata += "</p>\n";
 
2731
  }  // if (mProviderKey.isEmpty())
 
2732
 
 
2733
  myMetadata += "<p class=\"glossy\">";
 
2734
  myMetadata += tr( "Layer Spatial Reference System: " );
 
2735
  myMetadata += "</p>\n";
 
2736
  myMetadata += "<p>";
 
2737
  myMetadata += mCRS->toProj4();
 
2738
  myMetadata += "</p>\n";
 
2739
 
 
2740
  // output coordinate system
 
2741
  // TODO: this is not related to layer, to be removed? [MD]
 
2742
#if 0
 
2743
  myMetadata += "<tr><td class=\"glossy\">";
 
2744
  myMetadata += tr( "Project Spatial Reference System: " );
 
2745
  myMetadata += "</p>\n";
 
2746
  myMetadata += "<p>";
 
2747
  myMetadata +=  mCoordinateTransform->destCRS().toProj4();
 
2748
  myMetadata += "</p>\n";
 
2749
#endif
 
2750
 
 
2751
  if ( mProviderKey.isEmpty() )
 
2752
  {
 
2753
    if ( GDALGetGeoTransform( mGdalDataset, mGeoTransform ) != CE_None )
 
2754
    {
 
2755
      // if the raster does not have a valid transform we need to use
 
2756
      // a pixel size of (1,-1), but GDAL returns (1,1)
 
2757
      mGeoTransform[5] = -1;
 
2758
    }
 
2759
    else
 
2760
    {
 
2761
      myMetadata += "<p class=\"glossy\">";
 
2762
      myMetadata += tr( "Origin:" );
 
2763
      myMetadata += "</p>\n";
 
2764
      myMetadata += "<p>";
 
2765
      myMetadata += QString::number( mGeoTransform[0] );
 
2766
      myMetadata += ",";
 
2767
      myMetadata += QString::number( mGeoTransform[3] );
 
2768
      myMetadata += "</p>\n";
 
2769
 
 
2770
      myMetadata += "<p class=\"glossy\">";
 
2771
      myMetadata += tr( "Pixel Size:" );
 
2772
      myMetadata += "</p>\n";
 
2773
      myMetadata += "<p>";
 
2774
      myMetadata += QString::number( mGeoTransform[1] );
 
2775
      myMetadata += ",";
 
2776
      myMetadata += QString::number( mGeoTransform[5] );
 
2777
      myMetadata += "</p>\n";
 
2778
    }
 
2779
 
 
2780
    //
 
2781
    // Add the stats for each band to the output table
 
2782
    //
 
2783
    int myBandCountInt = bandCount();
 
2784
    for ( int myIteratorInt = 1; myIteratorInt <= myBandCountInt; ++myIteratorInt )
 
2785
    {
 
2786
      QgsDebugMsg( "Raster properties : checking if band " + QString::number( myIteratorInt ) + " has stats? " );
 
2787
      //band name
 
2788
      myMetadata += "<p class=\"glossy\">\n";
 
2789
      myMetadata += tr( "Band" );
 
2790
      myMetadata += "</p>\n";
 
2791
      myMetadata += "<p>";
 
2792
      myMetadata += bandName( myIteratorInt );
 
2793
      myMetadata += "</p>\n";
 
2794
      //band number
 
2795
      myMetadata += "<p>";
 
2796
      myMetadata += tr( "Band No" );
 
2797
      myMetadata += "</p>\n";
 
2798
      myMetadata += "<p>\n";
 
2799
      myMetadata += QString::number( myIteratorInt );
 
2800
      myMetadata += "</p>\n";
 
2801
 
 
2802
      //check if full stats for this layer have already been collected
 
2803
      if ( !hasStatistics( myIteratorInt ) )  //not collected
 
2804
      {
 
2805
        QgsDebugMsg( ".....no" );
 
2806
 
 
2807
        myMetadata += "<p>";
 
2808
        myMetadata += tr( "No Stats" );
 
2809
        myMetadata += "</p>\n";
 
2810
        myMetadata += "<p>\n";
 
2811
        myMetadata += tr( "No stats collected yet" );
 
2812
        myMetadata += "</p>\n";
 
2813
      }
 
2814
      else                    // collected - show full detail
 
2815
      {
 
2816
        QgsDebugMsg( ".....yes" );
 
2817
 
 
2818
        QgsRasterBandStats myRasterBandStats = bandStatistics( myIteratorInt );
 
2819
        //Min Val
 
2820
        myMetadata += "<p>";
 
2821
        myMetadata += tr( "Min Val" );
 
2822
        myMetadata += "</p>\n";
 
2823
        myMetadata += "<p>\n";
 
2824
        myMetadata += QString::number( myRasterBandStats.minimumValue, 'f', 10 );
 
2825
        myMetadata += "</p>\n";
 
2826
 
 
2827
        // Max Val
 
2828
        myMetadata += "<p>";
 
2829
        myMetadata += tr( "Max Val" );
 
2830
        myMetadata += "</p>\n";
 
2831
        myMetadata += "<p>\n";
 
2832
        myMetadata += QString::number( myRasterBandStats.maximumValue, 'f', 10 );
 
2833
        myMetadata += "</p>\n";
 
2834
 
 
2835
        // Range
 
2836
        myMetadata += "<p>";
 
2837
        myMetadata += tr( "Range" );
 
2838
        myMetadata += "</p>\n";
 
2839
        myMetadata += "<p>\n";
 
2840
        myMetadata += QString::number( myRasterBandStats.range, 'f', 10 );
 
2841
        myMetadata += "</p>\n";
 
2842
 
 
2843
        // Mean
 
2844
        myMetadata += "<p>";
 
2845
        myMetadata += tr( "Mean" );
 
2846
        myMetadata += "</p>\n";
 
2847
        myMetadata += "<p>\n";
 
2848
        myMetadata += QString::number( myRasterBandStats.mean, 'f', 10 );
 
2849
        myMetadata += "</p>\n";
 
2850
 
 
2851
        //sum of squares
 
2852
        myMetadata += "<p>";
 
2853
        myMetadata += tr( "Sum of squares" );
 
2854
        myMetadata += "</p>\n";
 
2855
        myMetadata += "<p>\n";
 
2856
        myMetadata += QString::number( myRasterBandStats.sumOfSquares, 'f', 10 );
 
2857
        myMetadata += "</p>\n";
 
2858
 
 
2859
        //standard deviation
 
2860
        myMetadata += "<p>";
 
2861
        myMetadata += tr( "Standard Deviation" );
 
2862
        myMetadata += "</p>\n";
 
2863
        myMetadata += "<p>\n";
 
2864
        myMetadata += QString::number( myRasterBandStats.stdDev, 'f', 10 );
 
2865
        myMetadata += "</p>\n";
 
2866
 
 
2867
        //sum of all cells
 
2868
        myMetadata += "<p>";
 
2869
        myMetadata += tr( "Sum of all cells" );
 
2870
        myMetadata += "</p>\n";
 
2871
        myMetadata += "<p>\n";
 
2872
        myMetadata += QString::number( myRasterBandStats.sum, 'f', 10 );
 
2873
        myMetadata += "</p>\n";
 
2874
 
 
2875
        //number of cells
 
2876
        myMetadata += "<p>";
 
2877
        myMetadata += tr( "Cell Count" );
 
2878
        myMetadata += "</p>\n";
 
2879
        myMetadata += "<p>\n";
 
2880
        myMetadata += QString::number( myRasterBandStats.elementCount );
 
2881
        myMetadata += "</p>\n";
 
2882
      }
 
2883
    }
 
2884
  } // if (mProviderKey.isEmpty())
 
2885
 
 
2886
  QgsDebugMsg( myMetadata );
 
2887
  return myMetadata;
 
2888
}
 
2889
 
 
2890
/**
 
2891
 * @param theBand the band number for which to get the minimum pixel value
 
2892
 * @return the minimum pixel value
 
2893
 */
 
2894
double QgsRasterLayer::minimumValue( unsigned int theBand )
 
2895
{
 
2896
  if ( 0 < theBand && theBand <= bandCount() )
 
2897
  {
 
2898
    return mContrastEnhancementList[theBand - 1].minimumValue();
 
2899
  }
 
2900
 
 
2901
  return 0.0;
 
2902
}
 
2903
 
 
2904
/**
 
2905
 * @param theBand the band name for which to get the minimum pixel value
 
2906
 * @return the minimum pixel value
 
2907
 */
 
2908
double QgsRasterLayer::minimumValue( QString theBand )
 
2909
{
 
2910
  return minimumValue( bandNumber( theBand ) );
 
2911
}
 
2912
 
 
2913
/**
 
2914
 * @param theBandNumber the number of the band to use for generating a pixmap of the associated palette
 
2915
 * @return a 100x100 pixel QPixmap of the bands palette
 
2916
 */
 
2917
QPixmap QgsRasterLayer::paletteAsPixmap( int theBandNumber )
 
2918
{
 
2919
  //TODO: This function should take dimensions
 
2920
  QgsDebugMsg( "entered." );
 
2921
 
 
2922
  // Only do this for the non-provider (hard-coded GDAL) scenario...
 
2923
  // Maybe WMS can do this differently using QImage::numColors and QImage::color()
 
2924
  if ( mProviderKey.isEmpty() && hasBand( "Palette" ) && theBandNumber > 0 ) //don't tr() this its a gdal word!
 
2925
  {
 
2926
    QgsDebugMsg( "....found paletted image" );
 
2927
    QgsColorRampShader myShader;
 
2928
    QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = myShader.colorRampItemList();
 
2929
 
 
2930
    if ( readColorTable( 1, &myColorRampItemList ) )
 
2931
    {
 
2932
      QgsDebugMsg( "....got color ramp item list" );
 
2933
      myShader.setColorRampItemList( myColorRampItemList );
 
2934
      myShader.setColorRampType( QgsColorRampShader::DISCRETE );
 
2935
      // Draw image
 
2936
      int mySize = 100;
 
2937
      QPixmap myPalettePixmap( mySize, mySize );
 
2938
      QPainter myQPainter( &myPalettePixmap );
 
2939
 
 
2940
      QImage myQImage = QImage( mySize, mySize, QImage::Format_RGB32 );
 
2941
      myQImage.fill( 0 );
 
2942
      myPalettePixmap.fill();
 
2943
 
 
2944
      double myStep = (( double )myColorRampItemList.size() - 1 ) / ( double )( mySize * mySize );
 
2945
      double myValue = 0.0;
 
2946
      for ( int myRow = 0; myRow < mySize; myRow++ )
 
2947
      {
 
2948
        QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
 
2949
        for ( int myCol = 0; myCol < mySize; myCol++ )
 
2950
        {
 
2951
          myValue = myStep * ( double )( myCol + myRow * mySize );
 
2952
          int c1, c2, c3;
 
2953
          myShader.shade( myValue, &c1, &c2, &c3 );
 
2954
          myLineBuffer[ myCol ] = qRgb( c1, c2, c3 );
 
2955
        }
 
2956
      }
 
2957
 
 
2958
      myQPainter.drawImage( 0, 0, myQImage );
 
2959
      return myPalettePixmap;
 
2960
    }
 
2961
    QPixmap myNullPixmap;
 
2962
    return myNullPixmap;
 
2963
  }
 
2964
  else
 
2965
  {
 
2966
    //invalid layer  was requested
 
2967
    QPixmap myNullPixmap;
 
2968
    return myNullPixmap;
 
2969
  }
 
2970
}
 
2971
 
 
2972
/*
 
2973
 * @param theBandNoInt - which band to compute the histogram for
 
2974
 * @param theBinCountInt - how many 'bins' to categorise the data into
 
2975
 * @param theIgnoreOutOfRangeFlag - whether to ignore values that are out of range (default=true)
 
2976
 * @param theThoroughBandScanFlag - whether to visit each cell when computing the histogram (default=false)
 
2977
 */
 
2978
void QgsRasterLayer::populateHistogram( int theBandNo, int theBinCount, bool theIgnoreOutOfRangeFlag, bool theHistogramEstimatedFlag )
 
2979
{
 
2980
 
 
2981
  GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
 
2982
  QgsRasterBandStats myRasterBandStats = bandStatistics( theBandNo );
 
2983
  //calculate the histogram for this band
 
2984
  //we assume that it only needs to be calculated if the length of the histogram
 
2985
  //vector is not equal to the number of bins
 
2986
  //i.e if the histogram has never previously been generated or the user has
 
2987
  //selected a new number of bins.
 
2988
  if ( myRasterBandStats.histogramVector->size() != theBinCount ||
 
2989
       theIgnoreOutOfRangeFlag != myRasterBandStats.isHistogramOutOfRange ||
 
2990
       theHistogramEstimatedFlag != myRasterBandStats.isHistogramEstimated )
 
2991
  {
 
2992
    myRasterBandStats.histogramVector->clear();
 
2993
    myRasterBandStats.isHistogramEstimated = theHistogramEstimatedFlag;
 
2994
    myRasterBandStats.isHistogramOutOfRange = theIgnoreOutOfRangeFlag;
 
2995
    int *myHistogramArray = new int[theBinCount];
 
2996
 
 
2997
 
 
2998
    /*
 
2999
     *  CPLErr GDALRasterBand::GetHistogram (
 
3000
     *          double       dfMin,
 
3001
     *          double      dfMax,
 
3002
     *          int     nBuckets,
 
3003
     *          int *   panHistogram,
 
3004
     *          int     bIncludeOutOfRange,
 
3005
     *          int     bApproxOK,
 
3006
     *          GDALProgressFunc    pfnProgress,
 
3007
     *          void *      pProgressData
 
3008
     *          )
 
3009
     */
 
3010
    double myerval = ( myRasterBandStats.maximumValue - myRasterBandStats.minimumValue ) / theBinCount;
 
3011
    GDALGetRasterHistogram( myGdalBand, myRasterBandStats.minimumValue - 0.1*myerval,
 
3012
                            myRasterBandStats.maximumValue + 0.1*myerval, theBinCount, myHistogramArray,
 
3013
                            theIgnoreOutOfRangeFlag, theHistogramEstimatedFlag, progressCallback,
 
3014
                            this ); //this is the arg for our custome gdal progress callback
 
3015
 
 
3016
    for ( int myBin = 0; myBin < theBinCount; myBin++ )
 
3017
    {
 
3018
      myRasterBandStats.histogramVector->push_back( myHistogramArray[myBin] );
 
3019
      QgsDebugMsg( "Added " + QString::number( myHistogramArray[myBin] ) + " to histogram vector" );
 
3020
    }
 
3021
 
 
3022
  }
 
3023
  QgsDebugMsg( ">>>>> Histogram vector now contains " + QString::number( myRasterBandStats.histogramVector->size() ) +
 
3024
               " elements" );
 
3025
}
 
3026
 
 
3027
 
 
3028
QString QgsRasterLayer::providerKey()
 
3029
{
 
3030
  if ( mProviderKey.isEmpty() )
 
3031
  {
 
3032
    return QString();
 
3033
  }
 
3034
  else
 
3035
  {
 
3036
    return mProviderKey;
 
3037
  }
 
3038
}
 
3039
 
 
3040
/**
 
3041
 * @return the horizontal units per pixel as reported in the  GDAL geotramsform[1]
 
3042
 */
 
3043
double QgsRasterLayer::rasterUnitsPerPixel()
 
3044
{
 
3045
// We return one raster pixel per map unit pixel
 
3046
// One raster pixel can have several raster units...
 
3047
 
 
3048
// We can only use one of the mGeoTransform[], so go with the
 
3049
// horisontal one.
 
3050
 
 
3051
  return fabs( mGeoTransform[1] );
 
3052
}
 
3053
 
 
3054
/**
 
3055
 * @param theBandNumber the number of the band for which you want a color table
 
3056
 * @param theList a pointer the object that will hold the color table
 
3057
 * @return true of a color table was able to be read, false otherwise
 
3058
 */
 
3059
bool QgsRasterLayer::readColorTable( int theBandNumber, QList<QgsColorRampShader::ColorRampItem>* theList )
 
3060
{
 
3061
  QgsDebugMsg( "entered." );
 
3062
  //Invalid band number, segfault prevention
 
3063
  if ( 0 >= theBandNumber || 0 == theList )
 
3064
  {
 
3065
    QgsDebugMsg( "Invalid parameter" );
 
3066
    return false;
 
3067
  }
 
3068
 
 
3069
  GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNumber );
 
3070
  GDALColorTableH myGdalColorTable = GDALGetRasterColorTable( myGdalBand );
 
3071
 
 
3072
  if ( myGdalColorTable )
 
3073
  {
 
3074
    QgsDebugMsg( "Color table found" );
 
3075
    int myEntryCount = GDALGetColorEntryCount( myGdalColorTable );
 
3076
    GDALColorInterp myColorInterpretation =  GDALGetRasterColorInterpretation( myGdalBand );
 
3077
    QgsDebugMsg( "Color Interpretation: " + QString::number(( int )myColorInterpretation ) );
 
3078
    GDALPaletteInterp myPaletteInterpretation  = GDALGetPaletteInterpretation( myGdalColorTable );
 
3079
    QgsDebugMsg( "Palette Interpretation: " + QString::number(( int )myPaletteInterpretation ) );
 
3080
 
 
3081
    const GDALColorEntry* myColorEntry = 0;
 
3082
    for ( int myIterator = 0; myIterator < myEntryCount; myIterator++ )
 
3083
    {
 
3084
      myColorEntry = GDALGetColorEntry( myGdalColorTable, myIterator );
 
3085
 
 
3086
      if ( !myColorEntry )
 
3087
      {
 
3088
        continue;
 
3089
      }
 
3090
      else
 
3091
      {
 
3092
        //Branch on the color interpretation type
 
3093
        if ( myColorInterpretation == GCI_GrayIndex )
 
3094
        {
 
3095
          QgsColorRampShader::ColorRampItem myColorRampItem;
 
3096
          myColorRampItem.label = "";
 
3097
          myColorRampItem.value = ( double )myIterator;
 
3098
          myColorRampItem.color = QColor::fromRgb( myColorEntry->c1, myColorEntry->c1, myColorEntry->c1, myColorEntry->c4 );
 
3099
          theList->append( myColorRampItem );
 
3100
        }
 
3101
        else if ( myColorInterpretation == GCI_PaletteIndex )
 
3102
        {
 
3103
          QgsColorRampShader::ColorRampItem myColorRampItem;
 
3104
          myColorRampItem.label = "";
 
3105
          myColorRampItem.value = ( double )myIterator;
 
3106
          //Branch on palette interpretation
 
3107
          if ( myPaletteInterpretation  == GPI_RGB )
 
3108
          {
 
3109
            myColorRampItem.color = QColor::fromRgb( myColorEntry->c1, myColorEntry->c2, myColorEntry->c3, myColorEntry->c4 );
 
3110
          }
 
3111
          else if ( myPaletteInterpretation  == GPI_CMYK )
 
3112
          {
 
3113
            myColorRampItem.color = QColor::fromCmyk( myColorEntry->c1, myColorEntry->c2, myColorEntry->c3, myColorEntry->c4 );
 
3114
          }
 
3115
          else if ( myPaletteInterpretation  == GPI_HLS )
 
3116
          {
 
3117
            myColorRampItem.color = QColor::fromHsv( myColorEntry->c1, myColorEntry->c3, myColorEntry->c2, myColorEntry->c4 );
 
3118
          }
 
3119
          else
 
3120
          {
 
3121
            myColorRampItem.color = QColor::fromRgb( myColorEntry->c1, myColorEntry->c1, myColorEntry->c1, myColorEntry->c4 );
 
3122
          }
 
3123
          theList->append( myColorRampItem );
 
3124
        }
 
3125
        else
 
3126
        {
 
3127
          QgsDebugMsg( "Color interpretation type not supported yet" );
 
3128
          return false;
 
3129
        }
 
3130
      }
 
3131
    }
 
3132
  }
 
3133
  else
 
3134
  {
 
3135
    QgsDebugMsg( "No color table found for band " + QString::number( theBandNumber ) );
 
3136
    return false;
 
3137
  }
 
3138
 
 
3139
  QgsDebugMsg( "Color table loaded sucessfully" );
 
3140
  return true;
 
3141
}
 
3142
 
 
3143
void QgsRasterLayer::resetNoDataValue()
 
3144
{
 
3145
  mNoDataValue = std::numeric_limits<int>::max();
 
3146
  mValidNoDataValue = false;
 
3147
  if ( mGdalDataset != NULL && GDALGetRasterCount( mGdalDataset ) > 0 )
 
3148
  {
 
3149
    int myRequestValid;
 
3150
    double myValue = GDALGetRasterNoDataValue(
 
3151
                       GDALGetRasterBand( mGdalDataset, 1 ), &myRequestValid );
 
3152
 
 
3153
    if ( 0 != myRequestValid )
 
3154
    {
 
3155
      setNoDataValue( myValue );
 
3156
    }
 
3157
    else
 
3158
    {
 
3159
      setNoDataValue( -9999.0 );
 
3160
      mValidNoDataValue = false;
 
3161
    }
 
3162
  }
 
3163
}
 
3164
 
 
3165
 
 
3166
void QgsRasterLayer::setBlueBandName( QString const & theBandName )
 
3167
{
 
3168
  mBlueBandName = validateBandName( theBandName );
 
3169
}
 
3170
 
 
3171
/** Copied from QgsVectorLayer::setDataProvider
 
3172
 *  TODO: Make it work in the raster environment
 
3173
 */
 
3174
void QgsRasterLayer::setDataProvider( QString const & provider,
 
3175
                                      QStringList const & layers,
 
3176
                                      QStringList const & styles,
 
3177
                                      QString const & format,
 
3178
                                      QString const & crs )
 
3179
{
 
3180
  // XXX should I check for and possibly delete any pre-existing providers?
 
3181
  // XXX How often will that scenario occur?
 
3182
 
 
3183
  mProviderKey = provider;     // XXX is this necessary?  Usually already set
 
3184
  // XXX when execution gets here.
 
3185
 
 
3186
  // load the plugin
 
3187
  QgsProviderRegistry * pReg = QgsProviderRegistry::instance();
 
3188
  QString ogrlib = pReg->library( provider );
 
3189
 
 
3190
  //QString ogrlib = libDir + "/libpostgresprovider.so";
 
3191
 
 
3192
#ifdef TESTPROVIDERLIB
 
3193
  const char *cOgrLib = ( const char * ) ogrlib;
 
3194
  // test code to help debug provider loading problems
 
3195
  //  void *handle = dlopen(cOgrLib, RTLD_LAZY);
 
3196
  void *handle = dlopen( cOgrLib, RTLD_LAZY | RTLD_GLOBAL );
 
3197
  if ( !handle )
 
3198
  {
 
3199
    QgsLogger::warning( "Error in dlopen: " );
 
3200
  }
 
3201
  else
 
3202
  {
 
3203
    QgsDebugMsg( "dlopen suceeded" );
 
3204
    dlclose( handle );
 
3205
  }
 
3206
 
 
3207
#endif
 
3208
 
 
3209
  // load the data provider
 
3210
  mLib = new QLibrary( ogrlib );
 
3211
  QgsDebugMsg( "Library name is " + mLib->fileName() );
 
3212
  bool loaded = mLib->load();
 
3213
 
 
3214
  if ( loaded )
 
3215
  {
 
3216
    QgsDebugMsg( "Loaded data provider library" );
 
3217
    QgsDebugMsg( "Attempting to resolve the classFactory function" );
 
3218
    classFactoryFunction_t * classFactory = ( classFactoryFunction_t * ) cast_to_fptr( mLib->resolve( "classFactory" ) );
 
3219
 
 
3220
    mValid = false;            // assume the layer is invalid until we
 
3221
    // determine otherwise
 
3222
    if ( classFactory )
 
3223
    {
 
3224
      QgsDebugMsg( "Getting pointer to a mDataProvider object from the library" );
 
3225
      //XXX - This was a dynamic cast but that kills the Windows
 
3226
      //      version big-time with an abnormal termination error
 
3227
      //      mDataProvider = (QgsRasterDataProvider*)(classFactory((const
 
3228
      //                                              char*)(dataSource.utf8())));
 
3229
 
 
3230
      // Copied from qgsproviderregistry in preference to the above.
 
3231
      mDataProvider = ( QgsRasterDataProvider* )( *classFactory )( &mDataSource );
 
3232
 
 
3233
      if ( mDataProvider )
 
3234
      {
 
3235
        QgsDebugMsg( "Instantiated the data provider plugin" +
 
3236
                     QString( " with layer list of " ) + layers.join( ", " ) + " and style list of " + styles.join( ", " ) +
 
3237
                     " and format of " + format +  " and CRS of " + crs );
 
3238
        if ( mDataProvider->isValid() )
 
3239
        {
 
3240
          mValid = true;
 
3241
 
 
3242
          mDataProvider->addLayers( layers, styles );
 
3243
          mDataProvider->setImageEncoding( format );
 
3244
          mDataProvider->setImageCrs( crs );
 
3245
 
 
3246
          // get the extent
 
3247
          QgsRectangle mbr = mDataProvider->extent();
 
3248
 
 
3249
          // show the extent
 
3250
          QString s = mbr.toString();
 
3251
          QgsDebugMsg( "Extent of layer: " + s );
 
3252
          // store the extent
 
3253
          mLayerExtent.setXMaximum( mbr.xMaximum() );
 
3254
          mLayerExtent.setXMinimum( mbr.xMinimum() );
 
3255
          mLayerExtent.setYMaximum( mbr.yMaximum() );
 
3256
          mLayerExtent.setYMinimum( mbr.yMinimum() );
 
3257
 
 
3258
          // upper case the first letter of the layer name
 
3259
          QgsDebugMsg( "mLayerName: " + name() );
 
3260
 
 
3261
          // set up the raster drawing style
 
3262
          mDrawingStyle = MultiBandColor;  //sensible default
 
3263
 
 
3264
          // Setup source CRS
 
3265
          *mCRS = QgsCoordinateReferenceSystem();
 
3266
          mCRS->createFromOgcWmsCrs( crs );
 
3267
        }
 
3268
      }
 
3269
      else
 
3270
      {
 
3271
        QgsLogger::warning( "QgsRasterLayer::setDataProvider: Unable to instantiate the data provider plugin" );
 
3272
        mValid = false;
 
3273
      }
 
3274
    }
 
3275
  }
 
3276
  else
 
3277
  {
 
3278
    mValid = false;
 
3279
    QgsLogger::warning( "QgsRasterLayer::setDataProvider: Failed to load ../providers/libproviders.so" );
 
3280
 
 
3281
  }
 
3282
  QgsDebugMsg( "exiting." );
 
3283
 
 
3284
} // QgsRasterLayer::setDataProvider
 
3285
 
 
3286
void QgsRasterLayer::setColorShadingAlgorithm( ColorShadingAlgorithm theShadingAlgorithm )
 
3287
{
 
3288
  QgsDebugMsg( "called with [" + QString::number( theShadingAlgorithm ) + "]" );
 
3289
  if ( mColorShadingAlgorithm != theShadingAlgorithm )
 
3290
  {
 
3291
    if ( 0 == mRasterShader )
 
3292
    {
 
3293
      mRasterShader = new QgsRasterShader();
 
3294
    }
 
3295
 
 
3296
    switch ( theShadingAlgorithm )
 
3297
    {
 
3298
      case PseudoColorShader:
 
3299
        mRasterShader->setRasterShaderFunction( new QgsPseudoColorShader() );
 
3300
        break;
 
3301
      case FreakOutShader:
 
3302
        mRasterShader->setRasterShaderFunction( new QgsFreakOutShader() );
 
3303
        break;
 
3304
      case ColorRampShader:
 
3305
        mRasterShader->setRasterShaderFunction( new QgsColorRampShader() );
 
3306
        break;
 
3307
      case UserDefinedShader:
 
3308
        //do nothing
 
3309
        break;
 
3310
      default:
 
3311
        mRasterShader->setRasterShaderFunction( new QgsRasterShaderFunction() );
 
3312
        break;
 
3313
    }
 
3314
 
 
3315
    //Set the class variable after the call to setRasterShader(), so memory recovery can happen
 
3316
    mColorShadingAlgorithm = theShadingAlgorithm;
 
3317
  }
 
3318
  QgsDebugMsg( "mColorShadingAlgorithm = " + QString::number( theShadingAlgorithm ) );
 
3319
}
 
3320
 
 
3321
void QgsRasterLayer::setColorShadingAlgorithm( QString theShaderAlgorithm )
 
3322
{
 
3323
  QgsDebugMsg( "called with [" + theShaderAlgorithm + "]" );
 
3324
 
 
3325
  if ( theShaderAlgorithm == "PseudoColorShader" )
 
3326
    setColorShadingAlgorithm( PseudoColorShader );
 
3327
  else if ( theShaderAlgorithm == "FreakOutShader" )
 
3328
    setColorShadingAlgorithm( FreakOutShader );
 
3329
  else if ( theShaderAlgorithm == "ColorRampShader" )
 
3330
    setColorShadingAlgorithm( ColorRampShader );
 
3331
  else if ( theShaderAlgorithm == "UserDefinedShader" )
 
3332
    setColorShadingAlgorithm( UserDefinedShader );
 
3333
  else
 
3334
    setColorShadingAlgorithm( UndefinedShader );
 
3335
}
 
3336
 
 
3337
void QgsRasterLayer::setContrastEnhancementAlgorithm( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm, bool theGenerateLookupTableFlag )
 
3338
{
 
3339
  QList<QgsContrastEnhancement>::iterator myIterator = mContrastEnhancementList.begin();
 
3340
  while ( myIterator !=  mContrastEnhancementList.end() )
 
3341
  {
 
3342
    ( *myIterator ).setContrastEnhancementAlgorithm( theAlgorithm, theGenerateLookupTableFlag );
 
3343
    ++myIterator;
 
3344
  }
 
3345
  mContrastEnhancementAlgorithm = theAlgorithm;
 
3346
}
 
3347
 
 
3348
void QgsRasterLayer::setContrastEnhancementAlgorithm( QString theAlgorithm, bool theGenerateLookupTableFlag )
 
3349
{
 
3350
  QgsDebugMsg( "called with [" + theAlgorithm + "] and flag=" + QString::number(( int )theGenerateLookupTableFlag ) );
 
3351
 
 
3352
  if ( theAlgorithm == "NoEnhancement" )
 
3353
  {
 
3354
    setContrastEnhancementAlgorithm( QgsContrastEnhancement::NoEnhancement, theGenerateLookupTableFlag );
 
3355
  }
 
3356
  else if ( theAlgorithm == "StretchToMinimumMaximum" )
 
3357
  {
 
3358
    setContrastEnhancementAlgorithm( QgsContrastEnhancement::StretchToMinimumMaximum, theGenerateLookupTableFlag );
 
3359
  }
 
3360
  else if ( theAlgorithm == "StretchAndClipToMinimumMaximum" )
 
3361
  {
 
3362
    setContrastEnhancementAlgorithm( QgsContrastEnhancement::StretchAndClipToMinimumMaximum, theGenerateLookupTableFlag );
 
3363
  }
 
3364
  else if ( theAlgorithm == "ClipToMinimumMaximum" )
 
3365
  {
 
3366
    setContrastEnhancementAlgorithm( QgsContrastEnhancement::ClipToMinimumMaximum, theGenerateLookupTableFlag );
 
3367
  }
 
3368
  else if ( theAlgorithm == "UserDefined" )
 
3369
  {
 
3370
    setContrastEnhancementAlgorithm( QgsContrastEnhancement::UserDefinedEnhancement, theGenerateLookupTableFlag );
 
3371
  }
 
3372
  else
 
3373
  {
 
3374
    setContrastEnhancementAlgorithm( QgsContrastEnhancement::NoEnhancement, theGenerateLookupTableFlag );
 
3375
  }
 
3376
}
 
3377
 
 
3378
void QgsRasterLayer::setContrastEnhancementFunction( QgsContrastEnhancementFunction* theFunction )
 
3379
{
 
3380
  if ( theFunction )
 
3381
  {
 
3382
    QList<QgsContrastEnhancement>::iterator myIterator = mContrastEnhancementList.begin();
 
3383
    while ( myIterator !=  mContrastEnhancementList.end() )
 
3384
    {
 
3385
      ( *myIterator ).setContrastEnhancementFunction( theFunction );
 
3386
      ++myIterator;
 
3387
    }
 
3388
  }
 
3389
}
 
3390
 
 
3391
/**
 
3392
 *
 
3393
 * Implemented mainly for serialisation / deserialisation of settings to xml.
 
3394
 * \note May be deprecated in the future! Use setDrawingStyle( DrawingStyle ) instead.
 
3395
 */
 
3396
void QgsRasterLayer::setDrawingStyle( QString const & theDrawingStyleQString )
 
3397
{
 
3398
  if ( theDrawingStyleQString == "SingleBandGray" )//no need to tr() this its not shown in ui
 
3399
  {
 
3400
    mDrawingStyle = SingleBandGray;
 
3401
  }
 
3402
  else if ( theDrawingStyleQString == "SingleBandPseudoColor" )//no need to tr() this its not shown in ui
 
3403
  {
 
3404
    mDrawingStyle = SingleBandPseudoColor;
 
3405
  }
 
3406
  else if ( theDrawingStyleQString == "PalettedColor" )//no need to tr() this its not shown in ui
 
3407
  {
 
3408
    mDrawingStyle = PalettedColor;
 
3409
  }
 
3410
  else if ( theDrawingStyleQString == "PalettedSingleBandGray" )//no need to tr() this its not shown in ui
 
3411
  {
 
3412
    mDrawingStyle = PalettedSingleBandGray;
 
3413
  }
 
3414
  else if ( theDrawingStyleQString == "PalettedSingleBandPseudoColor" )//no need to tr() this its not shown in ui
 
3415
  {
 
3416
    mDrawingStyle = PalettedSingleBandPseudoColor;
 
3417
  }
 
3418
  else if ( theDrawingStyleQString == "PalettedMultiBandColor" )//no need to tr() this its not shown in ui
 
3419
  {
 
3420
    mDrawingStyle = PalettedMultiBandColor;
 
3421
  }
 
3422
  else if ( theDrawingStyleQString == "MultiBandSingleGandGray" )//no need to tr() this its not shown in ui
 
3423
  {
 
3424
    mDrawingStyle = MultiBandSingleGandGray;
 
3425
  }
 
3426
  else if ( theDrawingStyleQString == "MultiBandSingleBandPseudoColor" )//no need to tr() this its not shown in ui
 
3427
  {
 
3428
    mDrawingStyle = MultiBandSingleBandPseudoColor;
 
3429
  }
 
3430
  else if ( theDrawingStyleQString == "MultiBandColor" )//no need to tr() this its not shown in ui
 
3431
  {
 
3432
    mDrawingStyle = MultiBandColor;
 
3433
  }
 
3434
  else
 
3435
  {
 
3436
    mDrawingStyle = UndefinedDrawingStyle;
 
3437
  }
 
3438
}
 
3439
 
 
3440
void QgsRasterLayer::setGrayBandName( QString const & theBandName )
 
3441
{
 
3442
  mGrayBandName = validateBandName( theBandName );
 
3443
}
 
3444
 
 
3445
void QgsRasterLayer::setGreenBandName( QString const & theBandName )
 
3446
{
 
3447
  mGreenBandName = validateBandName( theBandName );
 
3448
}
 
3449
 
 
3450
void QgsRasterLayer::setLayerOrder( QStringList const & layers )
 
3451
{
 
3452
  QgsDebugMsg( "entered." );
 
3453
 
 
3454
  if ( mDataProvider )
 
3455
  {
 
3456
    QgsDebugMsg( "About to mDataProvider->setLayerOrder(layers)." );
 
3457
    mDataProvider->setLayerOrder( layers );
 
3458
  }
 
3459
 
 
3460
}
 
3461
 
 
3462
void QgsRasterLayer::setMaximumValue( unsigned int theBand, double theValue, bool theGenerateLookupTableFlag )
 
3463
{
 
3464
  if ( 0 < theBand && theBand <= bandCount() )
 
3465
  {
 
3466
    mContrastEnhancementList[theBand - 1].setMaximumValue( theValue, theGenerateLookupTableFlag );
 
3467
  }
 
3468
}
 
3469
 
 
3470
void QgsRasterLayer::setMaximumValue( QString theBand, double theValue, bool theGenerateLookupTableFlag )
 
3471
{
 
3472
  if ( theBand != tr( "Not Set" ) )
 
3473
  {
 
3474
    setMaximumValue( bandNumber( theBand ), theValue, theGenerateLookupTableFlag );
 
3475
  }
 
3476
}
 
3477
 
 
3478
void QgsRasterLayer::setMinimumValue( unsigned int theBand, double theValue, bool theGenerateLookupTableFlag )
 
3479
{
 
3480
  if ( 0 < theBand && theBand <= bandCount() )
 
3481
  {
 
3482
    mContrastEnhancementList[theBand - 1].setMinimumValue( theValue, theGenerateLookupTableFlag );
 
3483
  }
 
3484
}
 
3485
 
 
3486
void QgsRasterLayer::setMinimumValue( QString theBand, double theValue, bool theGenerateLookupTableFlag )
 
3487
{
 
3488
  if ( theBand != tr( "Not Set" ) )
 
3489
  {
 
3490
    setMinimumValue( bandNumber( theBand ), theValue, theGenerateLookupTableFlag );
 
3491
  }
 
3492
 
 
3493
}
 
3494
 
 
3495
void QgsRasterLayer::setNoDataValue( double theNoDataValue )
 
3496
{
 
3497
  if ( theNoDataValue != mNoDataValue )
 
3498
  {
 
3499
    mNoDataValue = theNoDataValue;
 
3500
    mValidNoDataValue = true;
 
3501
    //Basically set the raster stats as invalid
 
3502
    QList<QgsRasterBandStats>::iterator myIterator = mRasterStatsList.begin();
 
3503
    while ( myIterator !=  mRasterStatsList.end() )
 
3504
    {
 
3505
      ( *myIterator ).statsGathered = false;
 
3506
      ++myIterator;
 
3507
    }
 
3508
  }
 
3509
}
 
3510
 
 
3511
void QgsRasterLayer::setRasterShaderFunction( QgsRasterShaderFunction* theFunction )
 
3512
{
 
3513
  //Free old shader if it is not a userdefined shader
 
3514
  if ( mColorShadingAlgorithm != QgsRasterLayer::UserDefinedShader && 0 != mRasterShader->rasterShaderFunction() )
 
3515
  {
 
3516
    delete( mRasterShader->rasterShaderFunction() );
 
3517
  }
 
3518
 
 
3519
  if ( theFunction )
 
3520
  {
 
3521
    mRasterShader->setRasterShaderFunction( theFunction );
 
3522
    mColorShadingAlgorithm = QgsRasterLayer::UserDefinedShader;
 
3523
  }
 
3524
  else
 
3525
  {
 
3526
    //If NULL as passed in, set a default shader function to prevent segfaults
 
3527
    mRasterShader->setRasterShaderFunction( new QgsRasterShaderFunction() );
 
3528
    mColorShadingAlgorithm = QgsRasterLayer::UndefinedShader;
 
3529
  }
 
3530
}
 
3531
 
 
3532
void QgsRasterLayer::setRedBandName( QString const & theBandName )
 
3533
{
 
3534
  QgsDebugMsg( "setRedBandName :  " + theBandName );
 
3535
  mRedBandName = validateBandName( theBandName );
 
3536
}
 
3537
 
 
3538
void QgsRasterLayer::setSubLayerVisibility( QString const & name, bool vis )
 
3539
{
 
3540
 
 
3541
  if ( mDataProvider )
 
3542
  {
 
3543
    QgsDebugMsg( "About to mDataProvider->setSubLayerVisibility(name, vis)." );
 
3544
    mDataProvider->setSubLayerVisibility( name, vis );
 
3545
  }
 
3546
 
 
3547
}
 
3548
 
 
3549
void QgsRasterLayer::setTransparentBandName( QString const & theBandName )
 
3550
{
 
3551
  mTransparencyBandName = validateBandName( theBandName );
 
3552
}
 
3553
 
 
3554
void QgsRasterLayer::showProgress( int theValue )
 
3555
{
 
3556
  emit progressUpdate( theValue );
 
3557
}
 
3558
 
 
3559
 
 
3560
void QgsRasterLayer::showStatusMessage( QString const & theMessage )
 
3561
{
 
3562
  // QgsDebugMsg(QString("entered with '%1'.").arg(theMessage));
 
3563
 
 
3564
  // Pass-through
 
3565
  // TODO: See if we can connect signal-to-signal.  This is a kludge according to the Qt doc.
 
3566
  emit statusChanged( theMessage );
 
3567
}
 
3568
 
 
3569
QStringList QgsRasterLayer::subLayers() const
 
3570
{
 
3571
 
 
3572
  if ( mDataProvider )
 
3573
  {
 
3574
    return mDataProvider->subLayers();
 
3575
  }
 
3576
  else
 
3577
  {
 
3578
    return QStringList();   // Empty
 
3579
  }
 
3580
 
 
3581
}
 
3582
 
 
3583
void QgsRasterLayer::thumbnailAsPixmap( QPixmap * theQPixmap )
 
3584
{
 
3585
  //TODO: This should be depreciated and a new function written that just returns a new QPixmap, it will be safer
 
3586
  if ( 0 == theQPixmap ) { return; }
 
3587
 
 
3588
  theQPixmap->fill(); //defaults to white
 
3589
 
 
3590
  // Raster providers are disabled (for the moment)
 
3591
  if ( mProviderKey.isEmpty() )
 
3592
  {
 
3593
    QgsRasterViewPort *myRasterViewPort = new QgsRasterViewPort();
 
3594
    myRasterViewPort->rectXOffset = 0;
 
3595
    myRasterViewPort->rectYOffset = 0;
 
3596
    myRasterViewPort->clippedXMin = 0;
 
3597
    myRasterViewPort->clippedXMax = mWidth;
 
3598
    myRasterViewPort->clippedYMin = mHeight;
 
3599
    myRasterViewPort->clippedYMax = 0;
 
3600
    myRasterViewPort->clippedWidth   = mWidth;
 
3601
    myRasterViewPort->clippedHeight  = mHeight;
 
3602
    myRasterViewPort->topLeftPoint = QgsPoint( 0, 0 );
 
3603
    myRasterViewPort->bottomRightPoint = QgsPoint( theQPixmap->width(), theQPixmap->height() );
 
3604
    myRasterViewPort->drawableAreaXDim = theQPixmap->width();
 
3605
    myRasterViewPort->drawableAreaYDim = theQPixmap->height();
 
3606
 
 
3607
    QPainter * myQPainter = new QPainter( theQPixmap );
 
3608
    draw( myQPainter, myRasterViewPort );
 
3609
    delete myRasterViewPort;
 
3610
    myQPainter->end();
 
3611
    delete myQPainter;
 
3612
  }
 
3613
 
 
3614
}
 
3615
 
 
3616
void QgsRasterLayer::triggerRepaint()
 
3617
{
 
3618
  emit repaintRequested();
 
3619
}
 
3620
 
 
3621
void QgsRasterLayer::updateProgress( int theProgress, int theMax )
 
3622
{
 
3623
  //simply propogate it on!
 
3624
  emit drawingProgress( theProgress, theMax );
 
3625
}
 
3626
 
 
3627
 
 
3628
 
 
3629
 
 
3630
//////////////////////////////////////////////////////////
 
3631
//
 
3632
// Protected methods
 
3633
//
 
3634
/////////////////////////////////////////////////////////
 
3635
/*
 
3636
 * @param QDomNode node that will contain the symbology definition for this layer.
 
3637
 * @param errorMessage reference to string that will be updated with any error messages
 
3638
 * @return true in case of success.
 
3639
 */
 
3640
bool QgsRasterLayer::readSymbology( const QDomNode& layer_node, QString& errorMessage )
 
3641
{
 
3642
  QDomNode mnl = layer_node.namedItem( "rasterproperties" );
 
3643
  QDomNode snode = mnl.namedItem( "mDrawingStyle" );
 
3644
  QDomElement myElement = snode.toElement();
 
3645
  setDrawingStyle( myElement.text() );
 
3646
 
 
3647
  snode = mnl.namedItem( "mColorShadingAlgorithm" );
 
3648
  myElement = snode.toElement();
 
3649
  setColorShadingAlgorithm( myElement.text() );
 
3650
 
 
3651
  snode = mnl.namedItem( "mInvertColor" );
 
3652
  myElement = snode.toElement();
 
3653
  QVariant myVariant = ( QVariant ) myElement.attribute( "boolean" );
 
3654
  setInvertHistogram( myVariant.toBool() );
 
3655
 
 
3656
  snode = mnl.namedItem( "mRedBandName" );
 
3657
  myElement = snode.toElement();
 
3658
  setRedBandName( myElement.text() );
 
3659
 
 
3660
  snode = mnl.namedItem( "mGreenBandName" );
 
3661
  myElement = snode.toElement();
 
3662
  setGreenBandName( myElement.text() );
 
3663
 
 
3664
  snode = mnl.namedItem( "mBlueBandName" );
 
3665
  myElement = snode.toElement();
 
3666
  setBlueBandName( myElement.text() );
 
3667
 
 
3668
  snode = mnl.namedItem( "mGrayBandName" );
 
3669
  myElement = snode.toElement();
 
3670
  QgsDebugMsg( QString( " Setting gray band to : " ) + myElement.text() );
 
3671
  setGrayBandName( myElement.text() );
 
3672
 
 
3673
  snode = mnl.namedItem( "mStandardDeviations" );
 
3674
  myElement = snode.toElement();
 
3675
  setStandardDeviations( myElement.text().toDouble() );
 
3676
 
 
3677
  snode = mnl.namedItem( "mUserDefinedRGBMinimumMaximum" );
 
3678
  myElement = snode.toElement();
 
3679
  myVariant = ( QVariant ) myElement.attribute( "boolean" );
 
3680
  setUserDefinedRGBMinimumMaximum( myVariant.toBool() );
 
3681
 
 
3682
  snode = mnl.namedItem( "mRGBMinimumMaximumEstimated" );
 
3683
  myElement = snode.toElement();
 
3684
  myVariant = ( QVariant ) myElement.attribute( "boolean" );
 
3685
  setRGBMinimumMaximumEstimated( myVariant.toBool() );
 
3686
 
 
3687
  snode = mnl.namedItem( "mUserDefinedGrayMinimumMaximum" );
 
3688
  myElement = snode.toElement();
 
3689
  myVariant = ( QVariant ) myElement.attribute( "boolean" );
 
3690
  setUserDefinedGrayMinimumMaximum( myVariant.toBool() );
 
3691
 
 
3692
  snode = mnl.namedItem( "mGrayMinimumMaximumEstimated" );
 
3693
  myElement = snode.toElement();
 
3694
  myVariant = ( QVariant ) myElement.attribute( "boolean" );
 
3695
  setGrayMinimumMaximumEstimated( myVariant.toBool() );
 
3696
 
 
3697
  snode = mnl.namedItem( "mContrastEnhancementAlgorithm" );
 
3698
  myElement = snode.toElement();
 
3699
  setContrastEnhancementAlgorithm( myElement.text(), false );
 
3700
 
 
3701
  QDomNode contrastEnhancementMinMaxValues = mnl.namedItem( "contrastEnhancementMinMaxValues" );
 
3702
  QDomNodeList minMaxValueList = contrastEnhancementMinMaxValues.toElement().elementsByTagName( "minMaxEntry" );
 
3703
  for ( int i = 0; i < minMaxValueList.size(); ++i )
 
3704
  {
 
3705
    QDomNode minMaxEntry = minMaxValueList.at( i ).toElement();
 
3706
    if ( minMaxEntry.isNull() )
 
3707
    {
 
3708
      continue;
 
3709
    }
 
3710
    QDomNode minEntry = minMaxEntry.namedItem( "min" );
 
3711
    QDomNode maxEntry = minMaxEntry.namedItem( "max" );
 
3712
 
 
3713
    setMinimumValue( i + 1, minEntry.toElement().text().toDouble(), false );
 
3714
    setMaximumValue( i + 1, maxEntry.toElement().text().toDouble(), false );
 
3715
  }
 
3716
 
 
3717
  QgsDebugMsg( "ReadXml: gray band name " + mGrayBandName );
 
3718
  QgsDebugMsg( "ReadXml: red band name " + mRedBandName );
 
3719
  QgsDebugMsg( "ReadXml: green band name  " + mGreenBandName );
 
3720
  QgsDebugMsg( "Drawing style " + drawingStyleAsString() );
 
3721
 
 
3722
  /*
 
3723
   * Transparency tab
 
3724
   */
 
3725
  snode = mnl.namedItem( "mNoDataValue" );
 
3726
  myElement = snode.toElement();
 
3727
  setNoDataValue( myElement.text().toDouble() );
 
3728
  if ( myElement.attribute( "mValidNoDataValue", "false" ).compare( "true" ) )
 
3729
  {
 
3730
    // If flag element is not true, set to false.
 
3731
    mValidNoDataValue = false;
 
3732
  }
 
3733
 
 
3734
  QDomNode singleValuePixelListNode = mnl.namedItem( "singleValuePixelList" );
 
3735
  if ( !singleValuePixelListNode.isNull() )
 
3736
  {
 
3737
    QList<QgsRasterTransparency::TransparentSingleValuePixel> newSingleValuePixelList;
 
3738
 
 
3739
    //entries
 
3740
    QDomNodeList singleValuePixelList = singleValuePixelListNode.toElement().elementsByTagName( "pixelListEntry" );
 
3741
    for ( int i = 0; i < singleValuePixelList.size(); ++i )
 
3742
    {
 
3743
      QgsRasterTransparency::TransparentSingleValuePixel myNewItem;
 
3744
      QDomElement singleValuePixelListElement = singleValuePixelList.at( i ).toElement();
 
3745
      if ( singleValuePixelListElement.isNull() )
 
3746
      {
 
3747
        continue;
 
3748
      }
 
3749
 
 
3750
      myNewItem.pixelValue = singleValuePixelListElement.attribute( "pixelValue" ).toDouble();
 
3751
      myNewItem.percentTransparent = singleValuePixelListElement.attribute( "percentTransparent" ).toDouble();
 
3752
 
 
3753
      newSingleValuePixelList.push_back( myNewItem );
 
3754
    }
 
3755
    mRasterTransparency.setTransparentSingleValuePixelList( newSingleValuePixelList );
 
3756
  }
 
3757
 
 
3758
  QDomNode threeValuePixelListNode = mnl.namedItem( "threeValuePixelList" );
 
3759
  if ( !threeValuePixelListNode.isNull() )
 
3760
  {
 
3761
    QList<QgsRasterTransparency::TransparentThreeValuePixel> newThreeValuePixelList;
 
3762
 
 
3763
    //entries
 
3764
    QDomNodeList threeValuePixelList = threeValuePixelListNode.toElement().elementsByTagName( "pixelListEntry" );
 
3765
    for ( int i = 0; i < threeValuePixelList.size(); ++i )
 
3766
    {
 
3767
      QgsRasterTransparency::TransparentThreeValuePixel myNewItem;
 
3768
      QDomElement threeValuePixelListElement = threeValuePixelList.at( i ).toElement();
 
3769
      if ( threeValuePixelListElement.isNull() )
 
3770
      {
 
3771
        continue;
 
3772
      }
 
3773
 
 
3774
      myNewItem.red = threeValuePixelListElement.attribute( "red" ).toDouble();
 
3775
      myNewItem.green = threeValuePixelListElement.attribute( "green" ).toDouble();
 
3776
      myNewItem.blue = threeValuePixelListElement.attribute( "blue" ).toDouble();
 
3777
      myNewItem.percentTransparent = threeValuePixelListElement.attribute( "percentTransparent" ).toDouble();
 
3778
 
 
3779
      newThreeValuePixelList.push_back( myNewItem );
 
3780
    }
 
3781
    mRasterTransparency.setTransparentThreeValuePixelList( newThreeValuePixelList );
 
3782
  }
 
3783
 
 
3784
  /*
 
3785
   * Color Ramp tab
 
3786
   */
 
3787
  //restore custom color ramp settings
 
3788
  QDomNode customColorRampNode = mnl.namedItem( "customColorRamp" );
 
3789
  if ( !customColorRampNode.isNull() )
 
3790
  {
 
3791
    QgsColorRampShader* myColorRampShader = ( QgsColorRampShader* ) mRasterShader->rasterShaderFunction();
 
3792
 
 
3793
    //TODO: Remove the customColorRampType check and following if() in v2.0, added for compatibility with older ( bugged ) project files
 
3794
    QDomNode customColorRampTypeNode = customColorRampNode.namedItem( "customColorRampType" );
 
3795
    QDomNode colorRampTypeNode = customColorRampNode.namedItem( "colorRampType" );
 
3796
    QString myRampType = "";
 
3797
    if ( "" == customColorRampTypeNode.toElement().text() )
 
3798
    {
 
3799
      myRampType = colorRampTypeNode.toElement().text();
 
3800
    }
 
3801
    else
 
3802
    {
 
3803
      myRampType = customColorRampTypeNode.toElement().text();
 
3804
    }
 
3805
    myColorRampShader->setColorRampType( myRampType );
 
3806
 
 
3807
 
 
3808
    //entries
 
3809
    QList<QgsColorRampShader::ColorRampItem> myColorRampItemList;
 
3810
    QDomNodeList colorRampEntryList = customColorRampNode.toElement().elementsByTagName( "colorRampEntry" );
 
3811
    for ( int i = 0; i < colorRampEntryList.size(); ++i )
 
3812
    {
 
3813
      QgsColorRampShader::ColorRampItem myNewItem;
 
3814
      QDomElement colorRampEntryElement = colorRampEntryList.at( i ).toElement();
 
3815
      if ( colorRampEntryElement.isNull() )
 
3816
      {
 
3817
        continue;
 
3818
      }
 
3819
 
 
3820
      myNewItem.color = QColor( colorRampEntryElement.attribute( "red" ).toInt(), colorRampEntryElement.attribute( "green" ).toInt(), colorRampEntryElement.attribute( "blue" ).toInt() );
 
3821
      myNewItem.label = colorRampEntryElement.attribute( "label" );
 
3822
      myNewItem.value = colorRampEntryElement.attribute( "value" ).toDouble();
 
3823
 
 
3824
      myColorRampItemList.push_back( myNewItem );
 
3825
    }
 
3826
    myColorRampShader->setColorRampItemList( myColorRampItemList );
 
3827
  }
 
3828
  return true;
 
3829
} //readSymbology
 
3830
 
 
3831
/**
 
3832
 
 
3833
  Raster layer project file XML of form:
 
3834
 
 
3835
  <maplayer type="raster" visible="1" showInOverviewFlag="1">
 
3836
  <layername>Wynoochee_dem</layername>
 
3837
  <datasource>/home/mcoletti/mnt/MCOLETTIF8F9/c/Toolkit_Course/Answers/Training_Data/wynoochee_dem.img</datasource>
 
3838
  <zorder>0</zorder>
 
3839
  <transparencyLevelInt>255</transparencyLevelInt>
 
3840
  <rasterproperties>
 
3841
  <mDrawingStyle>SingleBandGray</mDrawingStyle>
 
3842
  <mInvertColor boolean="false"/>
 
3843
  <mStandardDeviations>0</mStandardDeviations>
 
3844
  <mRedBandName>Not Set</mRedBandName>
 
3845
  <mGreenBandName>Not Set</mGreenBandName>
 
3846
  <mBlueBandName>Not Set</mBlueBandName>
 
3847
  <mGrayBandName>Undefined</mGrayBandName>
 
3848
  </rasterproperties>
 
3849
  </maplayer>
 
3850
 
 
3851
  @note Called by QgsMapLayer::readXML().
 
3852
*/
 
3853
bool QgsRasterLayer::readXml( QDomNode & layer_node )
 
3854
{
 
3855
  //! @NOTE Make sure to read the file first so stats etc are initialised properly!
 
3856
 
 
3857
  //process provider key
 
3858
  QDomNode pkeyNode = layer_node.namedItem( "provider" );
 
3859
 
 
3860
  if ( pkeyNode.isNull() )
 
3861
  {
 
3862
    mProviderKey = "";
 
3863
  }
 
3864
  else
 
3865
  {
 
3866
    QDomElement pkeyElt = pkeyNode.toElement();
 
3867
    mProviderKey = pkeyElt.text();
 
3868
  }
 
3869
 
 
3870
  // Open the raster source based on provider and datasource
 
3871
 
 
3872
  if ( !mProviderKey.isEmpty() )
 
3873
  {
 
3874
    // Go down the raster-data-provider paradigm
 
3875
 
 
3876
    // Collect provider-specific information
 
3877
 
 
3878
    QDomNode rpNode = layer_node.namedItem( "rasterproperties" );
 
3879
 
 
3880
    // Collect sublayer names and styles
 
3881
    QStringList layers;
 
3882
    QStringList styles;
 
3883
    QDomElement layerElement = rpNode.firstChildElement( "wmsSublayer" );
 
3884
    while ( !layerElement.isNull() )
 
3885
    {
 
3886
      // TODO: sublayer visibility - post-0.8 release timeframe
 
3887
 
 
3888
      // collect name for the sublayer
 
3889
      layers += layerElement.namedItem( "name" ).toElement().text();
 
3890
 
 
3891
      // collect style for the sublayer
 
3892
      styles += layerElement.namedItem( "style" ).toElement().text();
 
3893
 
 
3894
      layerElement = layerElement.nextSiblingElement( "wmsSublayer" );
 
3895
    }
 
3896
 
 
3897
    // Collect format
 
3898
    QString format = rpNode.namedItem( "wmsFormat" ).toElement().text();
 
3899
 
 
3900
    // Collect CRS
 
3901
    QString crs = QString( "EPSG:%1" ).arg( srs().epsg() );
 
3902
 
 
3903
    setDataProvider( mProviderKey, layers, styles, format, crs );
 
3904
  }
 
3905
  else
 
3906
  {
 
3907
    // Go down the monolithic-gdal-provider paradigm
 
3908
 
 
3909
    if ( !readFile( source() ) )   // Data source name set in
 
3910
      // QgsMapLayer::readXML()
 
3911
    {
 
3912
      QgsLogger::warning( QString( __FILE__ ) + ":" + QString( __LINE__ ) +
 
3913
                          " unable to read from raster file " + source() );
 
3914
      return false;
 
3915
    }
 
3916
 
 
3917
  }
 
3918
 
 
3919
  QString theError;
 
3920
  return readSymbology( layer_node, theError );
 
3921
 
 
3922
 
 
3923
} // QgsRasterLayer::readXml( QDomNode & layer_node )
 
3924
 
 
3925
 
 
3926
/*
 
3927
 * @param QDomNode the node that will have the style element added to it.
 
3928
 * @param QDomDocument the document that will have the QDomNode added.
 
3929
 * @param errorMessage reference to string that will be updated with any error messages
 
3930
 * @return true in case of success.
 
3931
 */
 
3932
bool QgsRasterLayer::writeSymbology( QDomNode & layer_node, QDomDocument & document, QString& errorMessage ) const
 
3933
{
 
3934
  // <rasterproperties>
 
3935
  QDomElement rasterPropertiesElement = document.createElement( "rasterproperties" );
 
3936
  layer_node.appendChild( rasterPropertiesElement );
 
3937
 
 
3938
  if ( !mProviderKey.isEmpty() )
 
3939
  {
 
3940
    QStringList sl = subLayers();
 
3941
    QStringList sls = mDataProvider->subLayerStyles();
 
3942
 
 
3943
    QStringList::const_iterator layerStyle = sls.begin();
 
3944
 
 
3945
    // <rasterproperties><wmsSublayer>
 
3946
    for ( QStringList::const_iterator layerName  = sl.begin();
 
3947
          layerName != sl.end();
 
3948
          ++layerName )
 
3949
    {
 
3950
 
 
3951
      QgsDebugMsg( QString( "<rasterproperties><wmsSublayer> %1" ).arg( layerName->toLocal8Bit().data() ) );
 
3952
 
 
3953
      QDomElement sublayerElement = document.createElement( "wmsSublayer" );
 
3954
 
 
3955
      // TODO: sublayer visibility - post-0.8 release timeframe
 
3956
 
 
3957
      // <rasterproperties><wmsSublayer><name>
 
3958
      QDomElement sublayerNameElement = document.createElement( "name" );
 
3959
      QDomText sublayerNameText = document.createTextNode( *layerName );
 
3960
      sublayerNameElement.appendChild( sublayerNameText );
 
3961
      sublayerElement.appendChild( sublayerNameElement );
 
3962
 
 
3963
      // <rasterproperties><wmsSublayer><style>
 
3964
      QDomElement sublayerStyleElement = document.createElement( "style" );
 
3965
      QDomText sublayerStyleText = document.createTextNode( *layerStyle );
 
3966
      sublayerStyleElement.appendChild( sublayerStyleText );
 
3967
      sublayerElement.appendChild( sublayerStyleElement );
 
3968
 
 
3969
      rasterPropertiesElement.appendChild( sublayerElement );
 
3970
 
 
3971
      // This assumes there are exactly the same number of "layerName"s as there are "layerStyle"s
 
3972
      ++layerStyle;
 
3973
    }
 
3974
 
 
3975
    // <rasterproperties><wmsFormat>
 
3976
    QDomElement formatElement = document.createElement( "wmsFormat" );
 
3977
    QDomText formatText =
 
3978
      document.createTextNode( mDataProvider->imageEncoding() );
 
3979
    formatElement.appendChild( formatText );
 
3980
    rasterPropertiesElement.appendChild( formatElement );
 
3981
 
 
3982
  }
 
3983
 
 
3984
  // <mDrawingStyle>
 
3985
  QDomElement drawStyleElement = document.createElement( "mDrawingStyle" );
 
3986
  QDomText    drawStyleText    = document.createTextNode( drawingStyleAsString() );
 
3987
 
 
3988
  drawStyleElement.appendChild( drawStyleText );
 
3989
 
 
3990
  rasterPropertiesElement.appendChild( drawStyleElement );
 
3991
 
 
3992
  // <colorShadingAlgorithm>
 
3993
  QDomElement colorShadingAlgorithmElement = document.createElement( "mColorShadingAlgorithm" );
 
3994
  QDomText    colorShadingAlgorithmText    = document.createTextNode( colorShadingAlgorithmAsString() );
 
3995
 
 
3996
  colorShadingAlgorithmElement.appendChild( colorShadingAlgorithmText );
 
3997
 
 
3998
  rasterPropertiesElement.appendChild( colorShadingAlgorithmElement );
 
3999
 
 
4000
  // <mInvertColor>
 
4001
  QDomElement mInvertColorElement = document.createElement( "mInvertColor" );
 
4002
 
 
4003
  if ( invertHistogram() )
 
4004
  {
 
4005
    mInvertColorElement.setAttribute( "boolean", "true" );
 
4006
  }
 
4007
  else
 
4008
  {
 
4009
    mInvertColorElement.setAttribute( "boolean", "false" );
 
4010
  }
 
4011
 
 
4012
  rasterPropertiesElement.appendChild( mInvertColorElement );
 
4013
 
 
4014
 
 
4015
  // <mRedBandName>
 
4016
  QDomElement mRedBandNameElement = document.createElement( "mRedBandName" );
 
4017
  QString writtenRedBandName =  redBandName();
 
4018
  if ( writtenRedBandName == TRSTRING_NOT_SET )
 
4019
  {
 
4020
    // Write english "not set" only.
 
4021
    writtenRedBandName = QSTRING_NOT_SET;
 
4022
  }
 
4023
  QDomText    mRedBandNameText    = document.createTextNode( writtenRedBandName );
 
4024
 
 
4025
  mRedBandNameElement.appendChild( mRedBandNameText );
 
4026
 
 
4027
  rasterPropertiesElement.appendChild( mRedBandNameElement );
 
4028
 
 
4029
 
 
4030
  // <mGreenBandName>
 
4031
  QDomElement mGreenBandNameElement = document.createElement( "mGreenBandName" );
 
4032
  QString writtenGreenBandName =  greenBandName();
 
4033
  if ( writtenGreenBandName == TRSTRING_NOT_SET )
 
4034
  {
 
4035
    // Write english "not set" only.
 
4036
    writtenGreenBandName = QSTRING_NOT_SET;
 
4037
  }
 
4038
  QDomText    mGreenBandNameText    = document.createTextNode( writtenGreenBandName );
 
4039
 
 
4040
  mGreenBandNameElement.appendChild( mGreenBandNameText );
 
4041
 
 
4042
  rasterPropertiesElement.appendChild( mGreenBandNameElement );
 
4043
 
 
4044
 
 
4045
  // <mBlueBandName>
 
4046
  QDomElement mBlueBandNameElement = document.createElement( "mBlueBandName" );
 
4047
  QString writtenBlueBandName =  blueBandName();
 
4048
  if ( writtenBlueBandName == TRSTRING_NOT_SET )
 
4049
  {
 
4050
    // Write english "not set" only.
 
4051
    writtenBlueBandName = QSTRING_NOT_SET;
 
4052
  }
 
4053
  QDomText    mBlueBandNameText    = document.createTextNode( writtenBlueBandName );
 
4054
 
 
4055
  mBlueBandNameElement.appendChild( mBlueBandNameText );
 
4056
 
 
4057
  rasterPropertiesElement.appendChild( mBlueBandNameElement );
 
4058
 
 
4059
 
 
4060
  // <mGrayBandName>
 
4061
  QDomElement mGrayBandNameElement = document.createElement( "mGrayBandName" );
 
4062
  QString writtenGrayBandName =  grayBandName();
 
4063
  if ( writtenGrayBandName == TRSTRING_NOT_SET )
 
4064
  {
 
4065
    // Write english "not set" only.
 
4066
    writtenGrayBandName = QSTRING_NOT_SET;
 
4067
  }
 
4068
  QDomText    mGrayBandNameText    = document.createTextNode( writtenGrayBandName );
 
4069
 
 
4070
  mGrayBandNameElement.appendChild( mGrayBandNameText );
 
4071
  rasterPropertiesElement.appendChild( mGrayBandNameElement );
 
4072
 
 
4073
  // <mStandardDeviations>
 
4074
  QDomElement mStandardDeviationsElement = document.createElement( "mStandardDeviations" );
 
4075
  QDomText    mStandardDeviationsText    = document.createTextNode( QString::number( standardDeviations() ) );
 
4076
 
 
4077
  mStandardDeviationsElement.appendChild( mStandardDeviationsText );
 
4078
 
 
4079
  rasterPropertiesElement.appendChild( mStandardDeviationsElement );
 
4080
 
 
4081
  // <mUserDefinedRGBMinimumMaximum>
 
4082
  QDomElement userDefinedRGBMinMaxFlag = document.createElement( "mUserDefinedRGBMinimumMaximum" );
 
4083
 
 
4084
  if ( hasUserDefinedRGBMinimumMaximum() )
 
4085
  {
 
4086
    userDefinedRGBMinMaxFlag.setAttribute( "boolean", "true" );
 
4087
  }
 
4088
  else
 
4089
  {
 
4090
    userDefinedRGBMinMaxFlag.setAttribute( "boolean", "false" );
 
4091
  }
 
4092
 
 
4093
  rasterPropertiesElement.appendChild( userDefinedRGBMinMaxFlag );
 
4094
 
 
4095
  // <mRGBMinimumMaximumEstimated>
 
4096
  QDomElement RGBMinimumMaximumEstimated = document.createElement( "mRGBMinimumMaximumEstimated" );
 
4097
 
 
4098
  if ( isRGBMinimumMaximumEstimated() )
 
4099
  {
 
4100
    RGBMinimumMaximumEstimated.setAttribute( "boolean", "true" );
 
4101
  }
 
4102
  else
 
4103
  {
 
4104
    RGBMinimumMaximumEstimated.setAttribute( "boolean", "false" );
 
4105
  }
 
4106
 
 
4107
  rasterPropertiesElement.appendChild( RGBMinimumMaximumEstimated );
 
4108
 
 
4109
  // <mUserDefinedGrayMinimumMaximum>
 
4110
  QDomElement userDefinedGrayMinMaxFlag = document.createElement( "mUserDefinedGrayMinimumMaximum" );
 
4111
 
 
4112
  if ( hasUserDefinedGrayMinimumMaximum() )
 
4113
  {
 
4114
    userDefinedGrayMinMaxFlag.setAttribute( "boolean", "true" );
 
4115
  }
 
4116
  else
 
4117
  {
 
4118
    userDefinedGrayMinMaxFlag.setAttribute( "boolean", "false" );
 
4119
  }
 
4120
 
 
4121
  rasterPropertiesElement.appendChild( userDefinedGrayMinMaxFlag );
 
4122
 
 
4123
  // <mGrayMinimumMaximumEstimated>
 
4124
  QDomElement GrayMinimumMaximumEstimated = document.createElement( "mGrayMinimumMaximumEstimated" );
 
4125
 
 
4126
  if ( isGrayMinimumMaximumEstimated() )
 
4127
  {
 
4128
    GrayMinimumMaximumEstimated.setAttribute( "boolean", "true" );
 
4129
  }
 
4130
  else
 
4131
  {
 
4132
    GrayMinimumMaximumEstimated.setAttribute( "boolean", "false" );
 
4133
  }
 
4134
 
 
4135
  rasterPropertiesElement.appendChild( GrayMinimumMaximumEstimated );
 
4136
 
 
4137
  // <contrastEnhancementAlgorithm>
 
4138
  QDomElement contrastEnhancementAlgorithmElement = document.createElement( "mContrastEnhancementAlgorithm" );
 
4139
  QDomText    contrastEnhancementAlgorithmText    = document.createTextNode( contrastEnhancementAlgorithmAsString() );
 
4140
 
 
4141
  contrastEnhancementAlgorithmElement.appendChild( contrastEnhancementAlgorithmText );
 
4142
 
 
4143
  rasterPropertiesElement.appendChild( contrastEnhancementAlgorithmElement );
 
4144
 
 
4145
  // <minMaxValues>
 
4146
  QList<QgsContrastEnhancement>::const_iterator it;
 
4147
  QDomElement contrastEnhancementMinMaxValuesElement = document.createElement( "contrastEnhancementMinMaxValues" );
 
4148
  for ( it =  mContrastEnhancementList.constBegin(); it != mContrastEnhancementList.constEnd(); ++it )
 
4149
  {
 
4150
    QDomElement minMaxEntry = document.createElement( "minMaxEntry" );
 
4151
    QDomElement minEntry = document.createElement( "min" );
 
4152
    QDomElement maxEntry = document.createElement( "max" );
 
4153
 
 
4154
    QDomText minEntryText = document.createTextNode( QString::number( it->minimumValue() ) );
 
4155
    minEntry.appendChild( minEntryText );
 
4156
 
 
4157
    QDomText maxEntryText = document.createTextNode( QString::number( it->maximumValue() ) );
 
4158
    maxEntry.appendChild( maxEntryText );
 
4159
 
 
4160
    minMaxEntry.appendChild( minEntry );
 
4161
    minMaxEntry.appendChild( maxEntry );
 
4162
 
 
4163
    contrastEnhancementMinMaxValuesElement.appendChild( minMaxEntry );
 
4164
  }
 
4165
 
 
4166
  rasterPropertiesElement.appendChild( contrastEnhancementMinMaxValuesElement );
 
4167
 
 
4168
  /*
 
4169
   * Transparency tab
 
4170
   */
 
4171
  // <mNodataValue>
 
4172
  QDomElement mNoDataValueElement = document.createElement( "mNoDataValue" );
 
4173
  QDomText    mNoDataValueText    = document.createTextNode( QString::number( mNoDataValue, 'f' ) );
 
4174
  if ( mValidNoDataValue )
 
4175
  {
 
4176
    mNoDataValueElement.setAttribute( "mValidNoDataValue", "true" );
 
4177
  }
 
4178
  else
 
4179
  {
 
4180
    mNoDataValueElement.setAttribute( "mValidNoDataValue", "false" );
 
4181
  }
 
4182
 
 
4183
  mNoDataValueElement.appendChild( mNoDataValueText );
 
4184
 
 
4185
  rasterPropertiesElement.appendChild( mNoDataValueElement );
 
4186
 
 
4187
 
 
4188
  if ( mRasterTransparency.transparentSingleValuePixelList().count() > 0 )
 
4189
  {
 
4190
    QDomElement singleValuePixelListElement = document.createElement( "singleValuePixelList" );
 
4191
 
 
4192
 
 
4193
    QList<QgsRasterTransparency::TransparentSingleValuePixel> myPixelList = mRasterTransparency.transparentSingleValuePixelList();
 
4194
    QList<QgsRasterTransparency::TransparentSingleValuePixel>::iterator it;
 
4195
    for ( it =  myPixelList.begin(); it != myPixelList.end(); ++it )
 
4196
    {
 
4197
      QDomElement pixelListElement = document.createElement( "pixelListEntry" );
 
4198
      pixelListElement.setAttribute( "pixelValue", QString::number( it->pixelValue, 'f' ) );
 
4199
      pixelListElement.setAttribute( "percentTransparent", QString::number( it->percentTransparent ) );
 
4200
 
 
4201
      singleValuePixelListElement.appendChild( pixelListElement );
 
4202
    }
 
4203
 
 
4204
    rasterPropertiesElement.appendChild( singleValuePixelListElement );
 
4205
  }
 
4206
 
 
4207
  if ( mRasterTransparency.transparentThreeValuePixelList().count() > 0 )
 
4208
  {
 
4209
    QDomElement threeValuePixelListElement = document.createElement( "threeValuePixelList" );
 
4210
 
 
4211
 
 
4212
    QList<QgsRasterTransparency::TransparentThreeValuePixel> myPixelList = mRasterTransparency.transparentThreeValuePixelList();
 
4213
    QList<QgsRasterTransparency::TransparentThreeValuePixel>::iterator it;
 
4214
    for ( it =  myPixelList.begin(); it != myPixelList.end(); ++it )
 
4215
    {
 
4216
      QDomElement pixelListElement = document.createElement( "pixelListEntry" );
 
4217
      pixelListElement.setAttribute( "red", QString::number( it->red, 'f' ) );
 
4218
      pixelListElement.setAttribute( "green", QString::number( it->green, 'f' ) );
 
4219
      pixelListElement.setAttribute( "blue", QString::number( it->blue, 'f' ) );
 
4220
      pixelListElement.setAttribute( "percentTransparent", QString::number( it->percentTransparent ) );
 
4221
 
 
4222
      threeValuePixelListElement.appendChild( pixelListElement );
 
4223
    }
 
4224
 
 
4225
    rasterPropertiesElement.appendChild( threeValuePixelListElement );
 
4226
  }
 
4227
 
 
4228
  /*
 
4229
   * Color Ramp tab
 
4230
   */
 
4231
  if ( QgsRasterLayer::ColorRampShader ==  colorShadingAlgorithm() )
 
4232
  {
 
4233
    QDomElement customColorRampElement = document.createElement( "customColorRamp" );
 
4234
 
 
4235
    QDomElement customColorRampType = document.createElement( "colorRampType" );
 
4236
    QDomText customColorRampTypeText = document.createTextNode((( QgsColorRampShader* )mRasterShader->rasterShaderFunction() )->colorRampTypeAsQString() );
 
4237
    customColorRampType.appendChild( customColorRampTypeText );
 
4238
    customColorRampElement.appendChild( customColorRampType );
 
4239
 
 
4240
    QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = (( QgsColorRampShader* )mRasterShader->rasterShaderFunction() )->colorRampItemList();
 
4241
    QList<QgsColorRampShader::ColorRampItem>::iterator it;
 
4242
    for ( it =  myColorRampItemList.begin(); it != myColorRampItemList.end(); ++it )
 
4243
    {
 
4244
      QDomElement colorRampEntryElement = document.createElement( "colorRampEntry" );
 
4245
      colorRampEntryElement.setAttribute( "red", QString::number( it->color.red() ) );
 
4246
      colorRampEntryElement.setAttribute( "green", QString::number( it->color.green() ) );
 
4247
      colorRampEntryElement.setAttribute( "blue", QString::number( it->color.blue() ) );
 
4248
      colorRampEntryElement.setAttribute( "value", QString::number( it->value, 'f' ) );
 
4249
      colorRampEntryElement.setAttribute( "label", it->label );
 
4250
 
 
4251
      customColorRampElement.appendChild( colorRampEntryElement );
 
4252
    }
 
4253
 
 
4254
    rasterPropertiesElement.appendChild( customColorRampElement );
 
4255
  }
 
4256
 
 
4257
  return true;
 
4258
} // bool QgsRasterLayer::writeSymbology
 
4259
 
 
4260
/*
 
4261
 *  virtual
 
4262
 *  @note Called by QgsMapLayer::writeXML().
 
4263
 */
 
4264
bool QgsRasterLayer::writeXml( QDomNode & layer_node,
 
4265
                               QDomDocument & document )
 
4266
{
 
4267
  // first get the layer element so that we can append the type attribute
 
4268
 
 
4269
  QDomElement mapLayerNode = layer_node.toElement();
 
4270
 
 
4271
  if ( mapLayerNode.isNull() || ( "maplayer" != mapLayerNode.nodeName() ) )
 
4272
  {
 
4273
    QgsLogger::warning( "QgsRasterLayer::writeXML() can't find <maplayer>" );
 
4274
    return false;
 
4275
  }
 
4276
 
 
4277
  mapLayerNode.setAttribute( "type", "raster" );
 
4278
 
 
4279
  // add provider node
 
4280
 
 
4281
  QDomElement provider  = document.createElement( "provider" );
 
4282
  QDomText providerText = document.createTextNode( mProviderKey );
 
4283
  provider.appendChild( providerText );
 
4284
  layer_node.appendChild( provider );
 
4285
 
 
4286
  //write out the symbology
 
4287
  QString errorMsg;
 
4288
  return writeSymbology( layer_node, document, errorMsg );
 
4289
}
 
4290
 
 
4291
 
 
4292
 
 
4293
 
 
4294
//////////////////////////////////////////////////////////
 
4295
//
 
4296
// Private methods
 
4297
//
 
4298
/////////////////////////////////////////////////////////
 
4299
void QgsRasterLayer::drawMultiBandColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
 
4300
    const QgsMapToPixel* theQgsMapToPixel )
 
4301
{
 
4302
  QgsDebugMsg( "entered." );
 
4303
  int myRedBandNo = bandNumber( mRedBandName );
 
4304
  //Invalid band number, segfault prevention
 
4305
  if ( 0 >= myRedBandNo )
 
4306
  {
 
4307
    return;
 
4308
  }
 
4309
 
 
4310
  int myGreenBandNo = bandNumber( mGreenBandName );
 
4311
  //Invalid band number, segfault prevention
 
4312
  if ( 0 >= myGreenBandNo )
 
4313
  {
 
4314
    return;
 
4315
  }
 
4316
 
 
4317
  int myBlueBandNo = bandNumber( mBlueBandName );
 
4318
  //Invalid band number, segfault prevention
 
4319
  if ( 0 >= myBlueBandNo )
 
4320
  {
 
4321
    return;
 
4322
  }
 
4323
  GDALRasterBandH myGdalRedBand = GDALGetRasterBand( mGdalDataset, myRedBandNo );
 
4324
  GDALRasterBandH myGdalGreenBand = GDALGetRasterBand( mGdalDataset, myGreenBandNo );
 
4325
  GDALRasterBandH myGdalBlueBand = GDALGetRasterBand( mGdalDataset, myBlueBandNo );
 
4326
 
 
4327
  GDALDataType myRedType = GDALGetRasterDataType( myGdalRedBand );
 
4328
  GDALDataType myGreenType = GDALGetRasterDataType( myGdalGreenBand );
 
4329
  GDALDataType myBlueType = GDALGetRasterDataType( myGdalBlueBand );
 
4330
 
 
4331
  void *myGdalRedData = readData( myGdalRedBand, theRasterViewPort );
 
4332
  void *myGdalGreenData = readData( myGdalGreenBand, theRasterViewPort );
 
4333
  void *myGdalBlueData = readData( myGdalBlueBand, theRasterViewPort );
 
4334
 
 
4335
  /* Check for out of memory error */
 
4336
  if ( myGdalRedData == NULL || myGdalGreenData == NULL || myGdalBlueData == NULL )
 
4337
  {
 
4338
    // Safe to free NULL-pointer */
 
4339
    VSIFree( myGdalRedData );
 
4340
    VSIFree( myGdalGreenData );
 
4341
    VSIFree( myGdalBlueData );
 
4342
    return;
 
4343
  }
 
4344
 
 
4345
  QImage myQImage = QImage( theRasterViewPort->drawableAreaXDim, theRasterViewPort->drawableAreaYDim, QImage::Format_ARGB32 );
 
4346
  QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
 
4347
 
 
4348
  QgsRasterBandStats myRedBandStats;
 
4349
  QgsRasterBandStats myGreenBandStats;
 
4350
  QgsRasterBandStats myBlueBandStats;
 
4351
  /*
 
4352
   * If a stetch is requested and there are no user defined Min Max values
 
4353
   * we need to get these values from the bands themselves.
 
4354
   *
 
4355
   */
 
4356
  if ( QgsContrastEnhancement::NoEnhancement != contrastEnhancementAlgorithm() && !mUserDefinedRGBMinimumMaximum && mStandardDeviations > 0 )
 
4357
  {
 
4358
    myRedBandStats = bandStatistics( myRedBandNo );
 
4359
    myGreenBandStats = bandStatistics( myGreenBandNo );
 
4360
    myBlueBandStats = bandStatistics( myBlueBandNo );
 
4361
    mRGBMinimumMaximumEstimated = false;
 
4362
    setMaximumValue( myRedBandNo, myRedBandStats.mean + ( mStandardDeviations * myRedBandStats.stdDev ) );
 
4363
    setMinimumValue( myRedBandNo, myRedBandStats.mean - ( mStandardDeviations * myRedBandStats.stdDev ) );
 
4364
    setMaximumValue( myGreenBandNo, myGreenBandStats.mean + ( mStandardDeviations * myGreenBandStats.stdDev ) );
 
4365
    setMinimumValue( myGreenBandNo, myGreenBandStats.mean - ( mStandardDeviations * myGreenBandStats.stdDev ) );
 
4366
    setMaximumValue( myBlueBandNo, myBlueBandStats.mean + ( mStandardDeviations * myBlueBandStats.stdDev ) );
 
4367
    setMinimumValue( myBlueBandNo, myBlueBandStats.mean - ( mStandardDeviations * myBlueBandStats.stdDev ) );
 
4368
  }
 
4369
  else if ( QgsContrastEnhancement::NoEnhancement != contrastEnhancementAlgorithm() && !mUserDefinedRGBMinimumMaximum )
 
4370
  {
 
4371
    //This case will be true the first time the image is loaded, so just approimate the min max to keep
 
4372
    //from calling generate raster band stats
 
4373
    double GDALrange[2];
 
4374
    mRGBMinimumMaximumEstimated = true;
 
4375
 
 
4376
    GDALComputeRasterMinMax( myGdalRedBand, 1, GDALrange ); //Approximate
 
4377
    setMaximumValue( myRedBandNo, GDALrange[1] );
 
4378
    setMinimumValue( myRedBandNo, GDALrange[0] );
 
4379
 
 
4380
    GDALComputeRasterMinMax( myGdalGreenBand, 1, GDALrange ); //Approximate
 
4381
    setMaximumValue( myGreenBandNo, GDALrange[1] );
 
4382
    setMinimumValue( myGreenBandNo, GDALrange[0] );
 
4383
 
 
4384
    GDALComputeRasterMinMax( myGdalBlueBand, 1, GDALrange ); //Approximate
 
4385
    setMaximumValue( myBlueBandNo, GDALrange[1] );
 
4386
    setMinimumValue( myBlueBandNo, GDALrange[0] );
 
4387
  }
 
4388
 
 
4389
  //Read and display pixels
 
4390
  double myRedValue = 0.0;
 
4391
  double myGreenValue = 0.0;
 
4392
  double myBlueValue = 0.0;
 
4393
 
 
4394
  int myStretchedRedValue   = 0;
 
4395
  int myStretchedGreenValue = 0;
 
4396
  int myStretchedBlueValue  = 0;
 
4397
  int myAlphaValue = 0;
 
4398
  QgsContrastEnhancement* myRedContrastEnhancement = contrastEnhancement( myRedBandNo );
 
4399
  QgsContrastEnhancement* myGreenContrastEnhancement = contrastEnhancement( myGreenBandNo );
 
4400
  QgsContrastEnhancement* myBlueContrastEnhancement = contrastEnhancement( myBlueBandNo );
 
4401
 
 
4402
  QgsDebugMsg( "Starting main render loop" );
 
4403
  for ( int myRow = 0; myRow < theRasterViewPort->drawableAreaYDim; ++myRow )
 
4404
  {
 
4405
    QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
 
4406
    for ( int myColumn = 0; myColumn < theRasterViewPort->drawableAreaXDim; ++myColumn )
 
4407
    {
 
4408
      myRedValue   = readValue( myGdalRedData, ( GDALDataType )myRedType,
 
4409
                                myRow * theRasterViewPort->drawableAreaXDim + myColumn );
 
4410
      myGreenValue = readValue( myGdalGreenData, ( GDALDataType )myGreenType,
 
4411
                                myRow * theRasterViewPort->drawableAreaXDim + myColumn );
 
4412
      myBlueValue  = readValue( myGdalBlueData, ( GDALDataType )myBlueType,
 
4413
                                myRow * theRasterViewPort->drawableAreaXDim + myColumn );
 
4414
 
 
4415
      if ( mValidNoDataValue && (( fabs( myRedValue - mNoDataValue ) <= TINY_VALUE || myRedValue != myRedValue ) || ( fabs( myGreenValue - mNoDataValue ) <= TINY_VALUE || myGreenValue != myGreenValue ) || ( fabs( myBlueValue - mNoDataValue ) <= TINY_VALUE || myBlueValue != myBlueValue ) ) )
 
4416
      {
 
4417
        myLineBuffer[ myColumn ] = myDefaultColor;
 
4418
        continue;
 
4419
      }
 
4420
 
 
4421
      if ( !myRedContrastEnhancement->isValueInDisplayableRange( myRedValue ) || !myGreenContrastEnhancement->isValueInDisplayableRange( myGreenValue ) || !myBlueContrastEnhancement->isValueInDisplayableRange( myBlueValue ) )
 
4422
      {
 
4423
        myLineBuffer[ myColumn ] = myDefaultColor;
 
4424
        continue;
 
4425
      }
 
4426
 
 
4427
      myAlphaValue = mRasterTransparency.alphaValue( myRedValue, myGreenValue, myBlueValue, mTransparencyLevel );
 
4428
      if ( 0 == myAlphaValue )
 
4429
      {
 
4430
        myLineBuffer[ myColumn ] = myDefaultColor;
 
4431
        continue;
 
4432
      }
 
4433
 
 
4434
      myStretchedRedValue = myRedContrastEnhancement->enhanceContrast( myRedValue );
 
4435
      myStretchedGreenValue = myGreenContrastEnhancement->enhanceContrast( myGreenValue );
 
4436
      myStretchedBlueValue = myBlueContrastEnhancement->enhanceContrast( myBlueValue );
 
4437
 
 
4438
      if ( mInvertColor )
 
4439
      {
 
4440
        myStretchedRedValue = 255 - myStretchedRedValue;
 
4441
        myStretchedGreenValue = 255 - myStretchedGreenValue;
 
4442
        myStretchedBlueValue = 255 - myStretchedBlueValue;
 
4443
      }
 
4444
 
 
4445
      myLineBuffer[ myColumn ] = qRgba( myStretchedRedValue, myStretchedGreenValue, myStretchedBlueValue, myAlphaValue );
 
4446
    }
 
4447
  }
 
4448
  //free the scanline memory
 
4449
  CPLFree( myGdalRedData );
 
4450
  CPLFree( myGdalGreenData );
 
4451
  CPLFree( myGdalBlueData );
 
4452
 
 
4453
#ifdef QGISDEBUG
 
4454
  QPixmap *pm = dynamic_cast<QPixmap *>( theQPainter->device() );
 
4455
  if ( pm )
 
4456
  {
 
4457
    QgsDebugMsg( "theQPainter stats: " );
 
4458
    QgsDebugMsg( "width = " + QString::number( pm->width() ) );
 
4459
    QgsDebugMsg( "height = " + QString::number( pm->height() ) );
 
4460
    pm->save( "/tmp/qgis-rasterlayer-drawmultibandcolor-test-a.png", "PNG" );
 
4461
  }
 
4462
#endif
 
4463
 
 
4464
  paintImageToCanvas( theQPainter, theRasterViewPort, theQgsMapToPixel, &myQImage );
 
4465
 
 
4466
#ifdef QGISDEBUG
 
4467
  QgsDebugMsg( "theQPainter->drawImage." );
 
4468
  if ( pm )
 
4469
  {
 
4470
    pm->save( "/tmp/qgis-rasterlayer-drawmultibandcolor-test-b.png", "PNG" );
 
4471
  }
 
4472
#endif
 
4473
}
 
4474
 
 
4475
void QgsRasterLayer::drawMultiBandSingleBandGray( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
 
4476
    const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
 
4477
{
 
4478
  //delegate to drawSingleBandGray!
 
4479
  drawSingleBandGray( theQPainter, theRasterViewPort, theQgsMapToPixel, theBandNo );
 
4480
}
 
4481
 
 
4482
void QgsRasterLayer::drawMultiBandSingleBandPseudoColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
 
4483
    const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
 
4484
{
 
4485
  //delegate to drawSinglePseudocolor!
 
4486
  drawSingleBandPseudoColor( theQPainter, theRasterViewPort, theQgsMapToPixel, theBandNo );
 
4487
}
 
4488
 
 
4489
/**
 
4490
 * This method is used to render a single band with a color map.
 
4491
 * @param theQPainter - pointer to the QPainter onto which the layer should be drawn.
 
4492
 * @param theRasterViewPort - pointer to the ViewPort struct containing dimensions of viewable area and subset area to be extracted from data file.
 
4493
 * @param theGdalBand - pointer to the GDALRasterBand which should be rendered.
 
4494
 */
 
4495
void QgsRasterLayer::drawPalettedSingleBandColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
 
4496
    const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
 
4497
{
 
4498
  QgsDebugMsg( "entered." );
 
4499
  //Invalid band number, segfault prevention
 
4500
  if ( 0 >= theBandNo )
 
4501
  {
 
4502
    return;
 
4503
  }
 
4504
 
 
4505
  if ( NULL == mRasterShader )
 
4506
  {
 
4507
    return;
 
4508
  }
 
4509
 
 
4510
  GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
 
4511
  GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
 
4512
  void *myGdalScanData = readData( myGdalBand, theRasterViewPort );
 
4513
 
 
4514
  /* Check for out of memory error */
 
4515
  if ( myGdalScanData == NULL )
 
4516
  {
 
4517
    return;
 
4518
  }
 
4519
 
 
4520
  QImage myQImage = QImage( theRasterViewPort->drawableAreaXDim, theRasterViewPort->drawableAreaYDim, QImage::Format_ARGB32 );
 
4521
  QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
 
4522
 
 
4523
  double myPixelValue = 0.0;
 
4524
  int myRedValue = 0;
 
4525
  int myGreenValue = 0;
 
4526
  int myBlueValue = 0;
 
4527
  int myAlphaValue = 0;
 
4528
 
 
4529
  QgsDebugMsg( "Starting main render loop" );
 
4530
  for ( int myRow = 0; myRow < theRasterViewPort->drawableAreaYDim; ++myRow )
 
4531
  {
 
4532
    QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
 
4533
    for ( int myColumn = 0; myColumn < theRasterViewPort->drawableAreaXDim; ++myColumn )
 
4534
    {
 
4535
      myRedValue = 0;
 
4536
      myGreenValue = 0;
 
4537
      myBlueValue = 0;
 
4538
      myPixelValue = readValue( myGdalScanData, ( GDALDataType )myDataType,
 
4539
                                myRow * theRasterViewPort->drawableAreaXDim + myColumn );
 
4540
 
 
4541
      if ( mValidNoDataValue && ( fabs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) )
 
4542
      {
 
4543
        myLineBuffer[ myColumn ] = myDefaultColor;
 
4544
        continue;
 
4545
      }
 
4546
 
 
4547
      myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel );
 
4548
      if ( 0 == myAlphaValue )
 
4549
      {
 
4550
        myLineBuffer[ myColumn ] = myDefaultColor;
 
4551
        continue;
 
4552
      }
 
4553
 
 
4554
      if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) )
 
4555
      {
 
4556
        myLineBuffer[ myColumn ] = myDefaultColor;
 
4557
        continue;
 
4558
      }
 
4559
 
 
4560
      if ( mInvertColor )
 
4561
      {
 
4562
        //Invert flag, flip blue and read
 
4563
        myLineBuffer[ myColumn ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue );
 
4564
      }
 
4565
      else
 
4566
      {
 
4567
        //Normal
 
4568
        myLineBuffer[ myColumn ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue );
 
4569
      }
 
4570
    }
 
4571
  }
 
4572
  CPLFree( myGdalScanData );
 
4573
 
 
4574
  paintImageToCanvas( theQPainter, theRasterViewPort, theQgsMapToPixel, &myQImage );
 
4575
}
 
4576
 
 
4577
/**
 
4578
 * This method is used to render a paletted raster layer as a gray image.
 
4579
 * @param theQPainter - pointer to the QPainter onto which the layer should be drawn.
 
4580
 * @param theRasterViewPort - pointer to the ViewPort struct containing dimensions of viewable area and subset area to be extracted from data file.
 
4581
 * @param theGdalBand - pointer to the GDALRasterBand which should be rendered.
 
4582
  */
 
4583
void QgsRasterLayer::drawPalettedSingleBandGray( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
 
4584
    const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
 
4585
{
 
4586
  QgsDebugMsg( "entered." );
 
4587
  //Invalid band number, segfault prevention
 
4588
  if ( 0 >= theBandNo )
 
4589
  {
 
4590
    return;
 
4591
  }
 
4592
 
 
4593
  if ( NULL == mRasterShader )
 
4594
  {
 
4595
    return;
 
4596
  }
 
4597
 
 
4598
  GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
 
4599
  GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
 
4600
  void *myGdalScanData = readData( myGdalBand, theRasterViewPort );
 
4601
 
 
4602
  /* Check for out of memory error */
 
4603
  if ( myGdalScanData == NULL )
 
4604
  {
 
4605
    return;
 
4606
  }
 
4607
 
 
4608
  QImage myQImage = QImage( theRasterViewPort->drawableAreaXDim, theRasterViewPort->drawableAreaYDim, QImage::Format_ARGB32 );
 
4609
  QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
 
4610
 
 
4611
  double myPixelValue = 0.0;
 
4612
  int myRedValue = 0;
 
4613
  int myGreenValue = 0;
 
4614
  int myBlueValue = 0;
 
4615
  int myAlphaValue = 0;
 
4616
 
 
4617
  QgsDebugMsg( "Starting main render loop" );
 
4618
  for ( int myRow = 0; myRow < theRasterViewPort->drawableAreaYDim; ++myRow )
 
4619
  {
 
4620
    QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
 
4621
    for ( int myColumn = 0; myColumn < theRasterViewPort->drawableAreaXDim; ++myColumn )
 
4622
    {
 
4623
      myRedValue = 0;
 
4624
      myGreenValue = 0;
 
4625
      myBlueValue = 0;
 
4626
      myPixelValue = readValue( myGdalScanData, ( GDALDataType )myDataType,
 
4627
                                myRow * theRasterViewPort->drawableAreaXDim + myColumn );
 
4628
 
 
4629
      if ( mValidNoDataValue && ( fabs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) )
 
4630
      {
 
4631
        myLineBuffer[ myColumn ] = myDefaultColor;
 
4632
        continue;
 
4633
      }
 
4634
 
 
4635
      myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel );
 
4636
      if ( 0 == myAlphaValue )
 
4637
      {
 
4638
        myLineBuffer[ myColumn ] = myDefaultColor;
 
4639
        continue;
 
4640
      }
 
4641
 
 
4642
      if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) )
 
4643
      {
 
4644
        myLineBuffer[ myColumn ] = myDefaultColor;
 
4645
        continue;
 
4646
      }
 
4647
 
 
4648
      if ( mInvertColor )
 
4649
      {
 
4650
        //Invert flag, flip blue and read
 
4651
        double myGrayValue = ( 0.3 * ( double )myRedValue ) + ( 0.59 * ( double )myGreenValue ) + ( 0.11 * ( double )myBlueValue );
 
4652
        myLineBuffer[ myColumn ] = qRgba(( int )myGrayValue, ( int )myGrayValue, ( int )myGrayValue, myAlphaValue );
 
4653
      }
 
4654
      else
 
4655
      {
 
4656
        //Normal
 
4657
        double myGrayValue = ( 0.3 * ( double )myBlueValue ) + ( 0.59 * ( double )myGreenValue ) + ( 0.11 * ( double )myRedValue );
 
4658
        myLineBuffer[ myColumn ] = qRgba(( int )myGrayValue, ( int )myGrayValue, ( int )myGrayValue, myAlphaValue );
 
4659
      }
 
4660
    }
 
4661
  }
 
4662
  CPLFree( myGdalScanData );
 
4663
 
 
4664
  paintImageToCanvas( theQPainter, theRasterViewPort, theQgsMapToPixel, &myQImage );
 
4665
}
 
4666
 
 
4667
/**
 
4668
 * This method is used to render a paletted raster layer as a pseudocolor image.
 
4669
 * @param theQPainter - pointer to the QPainter onto which the layer should be drawn.
 
4670
 * @param theRasterViewPort - pointer to the ViewPort struct containing dimensions of viewable area and subset area to be extracted from data file.
 
4671
 * @param theGdalBand - pointer to the GDALRasterBand which should be rendered.
 
4672
 gray.
 
4673
 */
 
4674
 
 
4675
void QgsRasterLayer::drawPalettedSingleBandPseudoColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
 
4676
    const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
 
4677
{
 
4678
  QgsDebugMsg( "entered." );
 
4679
  //Invalid band number, segfault prevention
 
4680
  if ( 0 >= theBandNo )
 
4681
  {
 
4682
    return;
 
4683
  }
 
4684
 
 
4685
  QgsRasterBandStats myRasterBandStats = bandStatistics( theBandNo );
 
4686
  GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
 
4687
  GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
 
4688
  void *myGdalScanData = readData( myGdalBand, theRasterViewPort );
 
4689
 
 
4690
  /* Check for out of memory error */
 
4691
  if ( myGdalScanData == NULL )
 
4692
  {
 
4693
    return;
 
4694
  }
 
4695
 
 
4696
  QImage myQImage = QImage( theRasterViewPort->drawableAreaXDim, theRasterViewPort->drawableAreaYDim, QImage::Format_ARGB32 );
 
4697
  QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
 
4698
 
 
4699
  if ( NULL == mRasterShader )
 
4700
  {
 
4701
    return;
 
4702
  }
 
4703
 
 
4704
  double myMinimumValue = 0.0;
 
4705
  double myMaximumValue = 0.0;
 
4706
  //Use standard deviations if set, otherwise, use min max of band
 
4707
  if ( mStandardDeviations > 0 )
 
4708
  {
 
4709
    myMinimumValue = ( myRasterBandStats.mean - ( mStandardDeviations * myRasterBandStats.stdDev ) );
 
4710
    myMaximumValue = ( myRasterBandStats.mean + ( mStandardDeviations * myRasterBandStats.stdDev ) );
 
4711
  }
 
4712
  else
 
4713
  {
 
4714
    myMinimumValue = myRasterBandStats.minimumValue;
 
4715
    myMaximumValue = myRasterBandStats.maximumValue;
 
4716
  }
 
4717
 
 
4718
  mRasterShader->setMinimumValue( myMinimumValue );
 
4719
  mRasterShader->setMaximumValue( myMaximumValue );
 
4720
 
 
4721
  double myPixelValue = 0.0;
 
4722
  int myRedValue = 0;
 
4723
  int myGreenValue = 0;
 
4724
  int myBlueValue = 0;
 
4725
  int myAlphaValue = 0;
 
4726
 
 
4727
  QgsDebugMsg( "Starting main render loop" );
 
4728
  for ( int myRow = 0; myRow < theRasterViewPort->drawableAreaYDim; ++myRow )
 
4729
  {
 
4730
    QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
 
4731
    for ( int myColumn = 0; myColumn < theRasterViewPort->drawableAreaXDim; ++myColumn )
 
4732
    {
 
4733
      myRedValue = 0;
 
4734
      myGreenValue = 0;
 
4735
      myBlueValue = 0;
 
4736
      myPixelValue = readValue( myGdalScanData, ( GDALDataType )myDataType,
 
4737
                                myRow * theRasterViewPort->drawableAreaXDim + myColumn );
 
4738
 
 
4739
      if ( mValidNoDataValue && ( fabs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) )
 
4740
      {
 
4741
        myLineBuffer[ myColumn ] = myDefaultColor;
 
4742
        continue;
 
4743
      }
 
4744
 
 
4745
      myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel );
 
4746
      if ( 0 == myAlphaValue )
 
4747
      {
 
4748
        myLineBuffer[ myColumn ] = myDefaultColor;
 
4749
        continue;
 
4750
      }
 
4751
 
 
4752
      if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) )
 
4753
      {
 
4754
        myLineBuffer[ myColumn ] = myDefaultColor;
 
4755
        continue;
 
4756
      }
 
4757
 
 
4758
      if ( mInvertColor )
 
4759
      {
 
4760
        //Invert flag, flip blue and read
 
4761
        myLineBuffer[ myColumn ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue );
 
4762
      }
 
4763
      else
 
4764
      {
 
4765
        //Normal
 
4766
        myLineBuffer[ myColumn ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue );
 
4767
      }
 
4768
    }
 
4769
  }
 
4770
  CPLFree( myGdalScanData );
 
4771
 
 
4772
  paintImageToCanvas( theQPainter, theRasterViewPort, theQgsMapToPixel, &myQImage );
 
4773
}
 
4774
 
 
4775
/**
 
4776
 * This method is used to render a paletted raster layer as a color image -- currently not supported
 
4777
 * @param theQPainter - pointer to the QPainter onto which the layer should be drawn.
 
4778
 * @param theRasterViewPort - pointer to the ViewPort struct containing dimensions of viewable area and subset area to be extracted from data file.
 
4779
 * @param theGdalBand - pointer to the GDALRasterBand which should be rendered.
 
4780
 */
 
4781
void QgsRasterLayer::drawPalettedMultiBandColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
 
4782
    const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
 
4783
{
 
4784
  QgsDebugMsg( "Not supported at this time" );
 
4785
}
 
4786
 
 
4787
void QgsRasterLayer::drawSingleBandGray( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
 
4788
{
 
4789
  QgsDebugMsg( "layer=" + QString::number( theBandNo ) );
 
4790
  //Invalid band number, segfault prevention
 
4791
  if ( 0 >= theBandNo )
 
4792
  {
 
4793
    return;
 
4794
  }
 
4795
 
 
4796
  GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
 
4797
  GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
 
4798
  void *myGdalScanData = readData( myGdalBand, theRasterViewPort );
 
4799
 
 
4800
  /* Check for out of memory error */
 
4801
  if ( myGdalScanData == NULL )
 
4802
  {
 
4803
    return;
 
4804
  }
 
4805
 
 
4806
  QImage myQImage = QImage( theRasterViewPort->drawableAreaXDim, theRasterViewPort->drawableAreaYDim, QImage::Format_ARGB32 );
 
4807
  QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
 
4808
 
 
4809
  QgsRasterBandStats myGrayBandStats;
 
4810
 
 
4811
  if ( QgsContrastEnhancement::NoEnhancement != contrastEnhancementAlgorithm() && !mUserDefinedGrayMinimumMaximum && mStandardDeviations > 0 )
 
4812
  {
 
4813
    mGrayMinimumMaximumEstimated = false;
 
4814
    myGrayBandStats = bandStatistics( theBandNo );
 
4815
    setMaximumValue( theBandNo, myGrayBandStats.mean + ( mStandardDeviations * myGrayBandStats.stdDev ) );
 
4816
    setMinimumValue( theBandNo, myGrayBandStats.mean - ( mStandardDeviations * myGrayBandStats.stdDev ) );
 
4817
  }
 
4818
  else if ( QgsContrastEnhancement::NoEnhancement != contrastEnhancementAlgorithm() && !mUserDefinedGrayMinimumMaximum )
 
4819
  {
 
4820
    //This case will be true the first time the image is loaded, so just approimate the min max to keep
 
4821
    //from calling generate raster band stats
 
4822
    double GDALrange[2];
 
4823
    GDALComputeRasterMinMax( myGdalBand, 1, GDALrange ); //Approximate
 
4824
    mGrayMinimumMaximumEstimated = true;
 
4825
    setMaximumValue( theBandNo, GDALrange[1] );
 
4826
    setMinimumValue( theBandNo, GDALrange[0] );
 
4827
 
 
4828
  }
 
4829
 
 
4830
  QgsDebugMsg( "Starting main render loop" );
 
4831
  // print each point in myGdalScanData with equal parts R, G, B or make it show as gray
 
4832
  double myGrayValue = 0.0;
 
4833
  int myGrayVal = 0;
 
4834
  int myAlphaValue = 0;
 
4835
  QgsContrastEnhancement* myContrastEnhancement = contrastEnhancement( theBandNo );
 
4836
  for ( int myRow = 0; myRow < theRasterViewPort->drawableAreaYDim; ++myRow )
 
4837
  {
 
4838
    QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
 
4839
    for ( int myColumn = 0; myColumn < theRasterViewPort->drawableAreaXDim; ++myColumn )
 
4840
    {
 
4841
      myGrayValue = readValue( myGdalScanData, myDataType,
 
4842
                               myRow * theRasterViewPort->drawableAreaXDim + myColumn );
 
4843
 
 
4844
      // If mNoDataValue is 'nan', the comparison
 
4845
      // against myGrayVal will always fail ( nan==nan always
 
4846
      // returns false, by design), hence the slightly odd comparison
 
4847
      // of myGrayVal against itself.
 
4848
 
 
4849
      if ( mValidNoDataValue && ( fabs( myGrayValue - mNoDataValue ) <= TINY_VALUE || myGrayValue != myGrayValue ) )
 
4850
      {
 
4851
        myLineBuffer[ myColumn ] = myDefaultColor;
 
4852
        continue;
 
4853
      }
 
4854
 
 
4855
      if ( !myContrastEnhancement->isValueInDisplayableRange( myGrayValue ) )
 
4856
      {
 
4857
        myLineBuffer[ myColumn ] = myDefaultColor;
 
4858
        continue;
 
4859
      }
 
4860
 
 
4861
      myAlphaValue = mRasterTransparency.alphaValue( myGrayValue, mTransparencyLevel );
 
4862
      if ( 0 == myAlphaValue )
 
4863
      {
 
4864
        myLineBuffer[ myColumn ] = myDefaultColor;
 
4865
        continue;
 
4866
      }
 
4867
 
 
4868
 
 
4869
      myGrayVal = myContrastEnhancement->enhanceContrast( myGrayValue );
 
4870
 
 
4871
      if ( mInvertColor )
 
4872
      {
 
4873
        myGrayVal = 255 - myGrayVal;
 
4874
      }
 
4875
 
 
4876
      myLineBuffer[ myColumn ] = qRgba( myGrayVal, myGrayVal, myGrayVal, myAlphaValue );
 
4877
    }
 
4878
  }
 
4879
 
 
4880
  CPLFree( myGdalScanData );
 
4881
 
 
4882
  QgsDebugMsg( "Render done, preparing to copy to canvas" );
 
4883
 
 
4884
  paintImageToCanvas( theQPainter, theRasterViewPort, theQgsMapToPixel, &myQImage );
 
4885
 
 
4886
} // QgsRasterLayer::drawSingleBandGray
 
4887
 
 
4888
void QgsRasterLayer::drawSingleBandPseudoColor( QPainter * theQPainter,
 
4889
    QgsRasterViewPort * theRasterViewPort,
 
4890
    const QgsMapToPixel* theQgsMapToPixel,
 
4891
    int theBandNo )
 
4892
{
 
4893
  QgsDebugMsg( "entered." );
 
4894
  //Invalid band number, segfault prevention
 
4895
  if ( 0 >= theBandNo )
 
4896
  {
 
4897
    return;
 
4898
  }
 
4899
 
 
4900
  QgsRasterBandStats myRasterBandStats = bandStatistics( theBandNo );
 
4901
  GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
 
4902
  GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
 
4903
  void *myGdalScanData = readData( myGdalBand, theRasterViewPort );
 
4904
 
 
4905
  /* Check for out of memory error */
 
4906
  if ( myGdalScanData == NULL )
 
4907
  {
 
4908
    return;
 
4909
  }
 
4910
 
 
4911
  QImage myQImage = QImage( theRasterViewPort->drawableAreaXDim, theRasterViewPort->drawableAreaYDim, QImage::Format_ARGB32 );
 
4912
  QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
 
4913
 
 
4914
  if ( NULL == mRasterShader )
 
4915
  {
 
4916
    return;
 
4917
  }
 
4918
 
 
4919
  double myMinimumValue = 0.0;
 
4920
  double myMaximumValue = 0.0;
 
4921
  //Use standard deviations if set, otherwise, use min max of band
 
4922
  if ( mStandardDeviations > 0 )
 
4923
  {
 
4924
    myMinimumValue = ( myRasterBandStats.mean - ( mStandardDeviations * myRasterBandStats.stdDev ) );
 
4925
    myMaximumValue = ( myRasterBandStats.mean + ( mStandardDeviations * myRasterBandStats.stdDev ) );
 
4926
  }
 
4927
  else
 
4928
  {
 
4929
    myMinimumValue = myRasterBandStats.minimumValue;
 
4930
    myMaximumValue = myRasterBandStats.maximumValue;
 
4931
  }
 
4932
 
 
4933
  mRasterShader->setMinimumValue( myMinimumValue );
 
4934
  mRasterShader->setMaximumValue( myMaximumValue );
 
4935
 
 
4936
 
 
4937
  int myRedValue = 255;
 
4938
  int myGreenValue = 255;
 
4939
  int myBlueValue = 255;
 
4940
 
 
4941
  double myPixelValue = 0.0;
 
4942
  int myAlphaValue = 0;
 
4943
  QgsDebugMsg( "Starting main render loop" );
 
4944
  for ( int myRow = 0; myRow < theRasterViewPort->drawableAreaYDim; ++myRow )
 
4945
  {
 
4946
    QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
 
4947
    for ( int myColumn = 0; myColumn < theRasterViewPort->drawableAreaXDim; ++myColumn )
 
4948
    {
 
4949
      myPixelValue = readValue( myGdalScanData, myDataType,
 
4950
                                myRow * theRasterViewPort->drawableAreaXDim + myColumn );
 
4951
 
 
4952
      if ( mValidNoDataValue && ( fabs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) )
 
4953
      {
 
4954
        myLineBuffer[ myColumn ] = myDefaultColor;
 
4955
        continue;
 
4956
      }
 
4957
 
 
4958
      myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel );
 
4959
      if ( 0 == myAlphaValue )
 
4960
      {
 
4961
        myLineBuffer[ myColumn ] = myDefaultColor;
 
4962
        continue;
 
4963
      }
 
4964
 
 
4965
      if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) )
 
4966
      {
 
4967
        myLineBuffer[ myColumn ] = myDefaultColor;
 
4968
        continue;
 
4969
      }
 
4970
 
 
4971
      if ( mInvertColor )
 
4972
      {
 
4973
        //Invert flag, flip blue and read
 
4974
        myLineBuffer[ myColumn ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue );
 
4975
      }
 
4976
      else
 
4977
      {
 
4978
        //Normal
 
4979
        myLineBuffer[ myColumn ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue );
 
4980
      }
 
4981
    }                       //end of columnwise loop
 
4982
  }                           //end of rowwise loop
 
4983
 
 
4984
  CPLFree( myGdalScanData );
 
4985
 
 
4986
  paintImageToCanvas( theQPainter, theRasterViewPort, theQgsMapToPixel, &myQImage );
 
4987
}
 
4988
 
 
4989
 
 
4990
void QgsRasterLayer::closeDataset()
 
4991
{
 
4992
  if ( !mValid ) return;
 
4993
  mValid = FALSE;
 
4994
 
 
4995
  GDALDereferenceDataset( mGdalBaseDataset );
 
4996
  mGdalBaseDataset = NULL;
 
4997
 
 
4998
  GDALClose( mGdalDataset );
 
4999
  mGdalDataset = NULL;
 
5000
 
 
5001
  mHasPyramids = false;
 
5002
  mPyramidList.clear();
 
5003
 
 
5004
  mRasterStatsList.clear();
 
5005
}
 
5006
 
 
5007
QString QgsRasterLayer::generateBandName( int theBandNumber )
 
5008
{
 
5009
  return tr( "Band" ) + QString( " %1" ) .arg( theBandNumber,  1 + ( int ) log10(( float ) bandCount() ), 10, QChar( '0' ) );
 
5010
}
 
5011
 
 
5012
/**
 
5013
 * This method looks to see if a given band name exists.
 
5014
 *@note This function is no longer really needed and about to be removed
 
5015
 */
 
5016
bool QgsRasterLayer::hasBand( QString const & theBandName )
 
5017
{
 
5018
  //TODO: This function is no longer really needed and about be removed -- it is only used to see if "Palette" exists which is not the correct way to see if a band is paletted or not
 
5019
  QgsDebugMsg( "Looking for band : " + theBandName );
 
5020
 
 
5021
  for ( int i = 1; i <= GDALGetRasterCount( mGdalDataset ); i++ )
 
5022
  {
 
5023
    GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, i );
 
5024
    QString myColorQString = GDALGetColorInterpretationName( GDALGetRasterColorInterpretation( myGdalBand ) );
 
5025
#ifdef QGISDEBUG
 
5026
    QgsLogger::debug( "band", i, __FILE__, __FUNCTION__, __LINE__, 2 );
 
5027
#endif
 
5028
 
 
5029
    if ( myColorQString == theBandName )
 
5030
    {
 
5031
#ifdef QGISDEBUG
 
5032
      QgsLogger::debug( "band", i, __FILE__, __FUNCTION__, __LINE__, 2 );
 
5033
      QgsDebugMsgLevel( "Found band : " + theBandName, 2 );
 
5034
#endif
 
5035
 
 
5036
      return true;
 
5037
    }
 
5038
    QgsDebugMsgLevel( "Found unmatched band : " + QString::number( i ) + " " + myColorQString, 2 );
 
5039
  }
 
5040
  return false;
 
5041
}
 
5042
 
 
5043
void QgsRasterLayer::paintImageToCanvas( QPainter* theQPainter, QgsRasterViewPort * theRasterViewPort, const QgsMapToPixel* theQgsMapToPixel, QImage* theImage )
 
5044
{
 
5045
  // Set up the initial offset into the myQImage we want to copy to the map canvas
 
5046
  // This is useful when the source image pixels are larger than the screen image.
 
5047
  int paintXoffset = 0;
 
5048
  int paintYoffset = 0;
 
5049
 
 
5050
  if ( theQgsMapToPixel )
 
5051
  {
 
5052
    paintXoffset = static_cast<int>(
 
5053
                     ( theRasterViewPort->rectXOffsetFloat -
 
5054
                       theRasterViewPort->rectXOffset )
 
5055
                     / theQgsMapToPixel->mapUnitsPerPixel()
 
5056
                     * fabs( mGeoTransform[1] )
 
5057
                   );
 
5058
 
 
5059
    paintYoffset = static_cast<int>(
 
5060
                     ( theRasterViewPort->rectYOffsetFloat -
 
5061
                       theRasterViewPort->rectYOffset )
 
5062
                     / theQgsMapToPixel->mapUnitsPerPixel()
 
5063
                     * fabs( mGeoTransform[5] )
 
5064
                   );
 
5065
  }
 
5066
 
 
5067
  QgsDebugMsg( "painting image to canvas from "
 
5068
               + QString::number( paintXoffset ) + ", " + QString::number( paintYoffset )
 
5069
               + " to "
 
5070
               + QString::number( static_cast<int>( theRasterViewPort->topLeftPoint.x() + 0.5 ) )
 
5071
               + ", "
 
5072
               + QString::number( static_cast<int>( theRasterViewPort->topLeftPoint.y() + 0.5 ) )
 
5073
               + "." );
 
5074
 
 
5075
  theQPainter->drawImage( static_cast<int>( theRasterViewPort->topLeftPoint.x() + 0.5 ),
 
5076
                          static_cast<int>( theRasterViewPort->topLeftPoint.y() + 0.5 ),
 
5077
                          *theImage,
 
5078
                          paintXoffset,
 
5079
                          paintYoffset );
 
5080
}
 
5081
 
 
5082
QString QgsRasterLayer::projectionWkt()
 
5083
{
 
5084
  QString myWktString;
 
5085
  QgsCoordinateReferenceSystem myCRS;
 
5086
  myWktString = QString( GDALGetProjectionRef( mGdalDataset ) );
 
5087
  myCRS.createFromWkt( myWktString );
 
5088
  if ( !myCRS.isValid() )
 
5089
  {
 
5090
    //try to get the gcp srs from the raster layer if available
 
5091
    myWktString = QString( GDALGetGCPProjection( mGdalDataset ) );
 
5092
 
 
5093
// What is the purpose of this piece of code?
 
5094
// Sideeffects from validate()?
 
5095
//    myCRS.createFromWkt(myWktString);
 
5096
//    if (!myCRS.isValid())
 
5097
//    {
 
5098
//      // use force and make CRS valid!
 
5099
//      myCRS.validate();
 
5100
//    }
 
5101
 
 
5102
  }
 
5103
 
 
5104
  return myWktString;
 
5105
}
 
5106
 
 
5107
/*
 
5108
 *data type is the same as raster band. The memory must be released later!
 
5109
 *  \return pointer to the memory
 
5110
 */
 
5111
void *QgsRasterLayer::readData( GDALRasterBandH gdalBand, QgsRasterViewPort *viewPort )
 
5112
{
 
5113
  GDALDataType type = GDALGetRasterDataType( gdalBand );
 
5114
  int size = GDALGetDataTypeSize( type ) / 8;
 
5115
 
 
5116
  QgsDebugMsg( "calling RasterIO with " +
 
5117
               QString( ", source NW corner: " ) + QString::number( viewPort->rectXOffset ) +
 
5118
               ", " + QString::number( viewPort->rectYOffset ) +
 
5119
               ", source size: " + QString::number( viewPort->clippedWidth ) +
 
5120
               ", " + QString::number( viewPort->clippedHeight ) +
 
5121
               ", dest size: " + QString::number( viewPort->drawableAreaXDim ) +
 
5122
               ", " + QString::number( viewPort->drawableAreaYDim ) );
 
5123
 
 
5124
  void *data = VSIMalloc( size * viewPort->drawableAreaXDim * viewPort->drawableAreaYDim );
 
5125
 
 
5126
  /* Abort if out of memory */
 
5127
  if ( data == NULL )
 
5128
  {
 
5129
    QgsDebugMsg( "Layer " + name() + " couldn't allocate enough memory. Ignoring" );
 
5130
  }
 
5131
  else
 
5132
  {
 
5133
    CPLErr myErr = GDALRasterIO( gdalBand, GF_Read,
 
5134
                                 viewPort->rectXOffset,
 
5135
                                 viewPort->rectYOffset,
 
5136
                                 viewPort->clippedWidth,
 
5137
                                 viewPort->clippedHeight,
 
5138
                                 data,
 
5139
                                 viewPort->drawableAreaXDim,
 
5140
                                 viewPort->drawableAreaYDim,
 
5141
                                 type, 0, 0 );
 
5142
    if ( myErr != CPLE_None )
 
5143
    {
 
5144
      QgsLogger::warning( "RasterIO error: " + QString::fromUtf8( CPLGetLastErrorMsg() ) );
 
5145
    }
 
5146
  }
 
5147
  return data;
 
5148
}
 
5149
 
 
5150
/*
 
5151
 * @note Called from ctor if a raster image given there
 
5152
 *
 
5153
 * @param theFilename absolute path and filename of the raster to be loaded
 
5154
 * @returns true if successfully read file
 
5155
 */
 
5156
bool QgsRasterLayer::readFile( QString const &theFilename )
 
5157
{
 
5158
  registerGdalDrivers();
 
5159
 
 
5160
  mGdalDataset = NULL;
 
5161
 
 
5162
  //open the dataset making sure we handle char encoding of locale properly
 
5163
  mGdalBaseDataset = GDALOpen( QFile::encodeName( theFilename ).constData(), GA_ReadOnly );
 
5164
 
 
5165
  if ( mGdalBaseDataset == NULL )
 
5166
  {
 
5167
    mValid = FALSE;
 
5168
    return false;
 
5169
  }
 
5170
 
 
5171
  // Store timestamp
 
5172
  mLastModified = lastModified( theFilename );
 
5173
 
 
5174
  // Check if we need a warped VRT for this file.
 
5175
  if (( GDALGetGeoTransform( mGdalBaseDataset, mGeoTransform ) == CE_None
 
5176
        && ( mGeoTransform[1] < 0.0
 
5177
             || mGeoTransform[2] != 0.0
 
5178
             || mGeoTransform[4] != 0.0
 
5179
             || mGeoTransform[5] > 0.0 ) )
 
5180
      || GDALGetGCPCount( mGdalBaseDataset ) > 0 )
 
5181
  {
 
5182
    QgsLogger::warning( "Creating Warped VRT." );
 
5183
 
 
5184
    mGdalDataset =
 
5185
      GDALAutoCreateWarpedVRT( mGdalBaseDataset, NULL, NULL,
 
5186
                               GRA_NearestNeighbour, 0.2, NULL );
 
5187
    if ( mGdalDataset == NULL )
 
5188
    {
 
5189
      QgsLogger::warning( "Warped VRT Creation failed." );
 
5190
      mGdalDataset = mGdalBaseDataset;
 
5191
      GDALReferenceDataset( mGdalDataset );
 
5192
    }
 
5193
  }
 
5194
  else
 
5195
  {
 
5196
    mGdalDataset = mGdalBaseDataset;
 
5197
    GDALReferenceDataset( mGdalDataset );
 
5198
  }
 
5199
 
 
5200
  //check f this file has pyramids
 
5201
  GDALRasterBandH myGDALBand = GDALGetRasterBand( mGdalDataset, 1 ); //just use the first band
 
5202
  if ( myGDALBand == NULL )
 
5203
  {
 
5204
    GDALDereferenceDataset( mGdalBaseDataset );
 
5205
    mGdalBaseDataset = NULL;
 
5206
 
 
5207
    GDALClose( mGdalDataset );
 
5208
    mGdalDataset = NULL;
 
5209
    mValid = FALSE;
 
5210
    return false;
 
5211
  }
 
5212
  if ( GDALGetOverviewCount( myGDALBand ) > 0 )
 
5213
  {
 
5214
    mHasPyramids = true;
 
5215
  }
 
5216
  else
 
5217
  {
 
5218
    mHasPyramids = false;
 
5219
  }
 
5220
 
 
5221
  //populate the list of what pyramids exist
 
5222
  buildPyramidList();
 
5223
 
 
5224
  // Get the layer's projection info and set up the
 
5225
  // QgsCoordinateTransform for this layer
 
5226
  // NOTE: we must do this before metadata is called
 
5227
 
 
5228
  QString mySourceWkt = projectionWkt();
 
5229
 
 
5230
  QgsDebugMsg( "--------------------------------------------------------------------------------------" );
 
5231
  QgsDebugMsg( "using wkt:\n" + mySourceWkt );
 
5232
  QgsDebugMsg( "--------------------------------------------------------------------------------------" );
 
5233
 
 
5234
  mCRS->createFromWkt( mySourceWkt );
 
5235
  //get the project projection, defaulting to this layer's projection
 
5236
  //if none exists....
 
5237
  if ( !mCRS->isValid() )
 
5238
  {
 
5239
    mCRS->validate();
 
5240
  }
 
5241
 
 
5242
  //set up the coordinat transform - in the case of raster this is mainly used to convert
 
5243
  //the inverese projection of the map extents of the canvas when zzooming in etc. so
 
5244
  //that they match the coordinate system of this layer
 
5245
  QgsDebugMsg( "Layer registry has " + QString::number( QgsMapLayerRegistry::instance()->count() ) + "layers" );
 
5246
 
 
5247
  metadata();
 
5248
 
 
5249
  // Use the affine transform to get geo coordinates for
 
5250
  // the corners of the raster
 
5251
  double myXMax = mGeoTransform[0] +
 
5252
                  GDALGetRasterXSize( mGdalDataset ) * mGeoTransform[1] +
 
5253
                  GDALGetRasterYSize( mGdalDataset ) * mGeoTransform[2];
 
5254
  double myYMin = mGeoTransform[3] +
 
5255
                  GDALGetRasterXSize( mGdalDataset ) * mGeoTransform[4] +
 
5256
                  GDALGetRasterYSize( mGdalDataset ) * mGeoTransform[5];
 
5257
 
 
5258
  mLayerExtent.setXMaximum( myXMax );
 
5259
  // The affine transform reduces to these values at the
 
5260
  // top-left corner of the raster
 
5261
  mLayerExtent.setXMinimum( mGeoTransform[0] );
 
5262
  mLayerExtent.setYMaximum( mGeoTransform[3] );
 
5263
  mLayerExtent.setYMinimum( myYMin );
 
5264
 
 
5265
  //
 
5266
  // Set up the x and y dimensions of this raster layer
 
5267
  //
 
5268
  mWidth = GDALGetRasterXSize( mGdalDataset );
 
5269
  mHeight = GDALGetRasterYSize( mGdalDataset );
 
5270
 
 
5271
  //
 
5272
  // Determine the nodata value
 
5273
  //
 
5274
  mNoDataValue = -9999.0; //Standard default?
 
5275
  mValidNoDataValue = false;
 
5276
  int isValid = false;
 
5277
  double myNoDataValue = GDALGetRasterNoDataValue( GDALGetRasterBand( mGdalDataset, 1 ), &isValid );
 
5278
  if ( isValid )
 
5279
  {
 
5280
    mNoDataValue = myNoDataValue;
 
5281
    mValidNoDataValue = true;
 
5282
  }
 
5283
 
 
5284
  if ( mValidNoDataValue )
 
5285
  {
 
5286
    mRasterTransparency.initializeTransparentPixelList( mNoDataValue, mNoDataValue, mNoDataValue );
 
5287
    mRasterTransparency.initializeTransparentPixelList( mNoDataValue );
 
5288
  }
 
5289
 
 
5290
  mBandCount = GDALGetRasterCount( mGdalDataset );
 
5291
  for ( int i = 1; i <= mBandCount; i++ )
 
5292
  {
 
5293
    GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, i );
 
5294
    QgsRasterBandStats myRasterBandStats;
 
5295
    myRasterBandStats.bandName = generateBandName( i );
 
5296
    myRasterBandStats.bandNumber = i;
 
5297
    myRasterBandStats.statsGathered = false;
 
5298
    myRasterBandStats.histogramVector = new QgsRasterBandStats::HistogramVector();
 
5299
    //Store the default color table
 
5300
    readColorTable( i, &myRasterBandStats.colorTable );
 
5301
 
 
5302
    mRasterStatsList.push_back( myRasterBandStats );
 
5303
 
 
5304
    //Build a new contrast enhancement for the band and store in list
 
5305
    QgsContrastEnhancement myContrastEnhancement(( QgsContrastEnhancement::QgsRasterDataType )GDALGetRasterDataType( myGdalBand ) );
 
5306
    mContrastEnhancementList.append( myContrastEnhancement );
 
5307
  }
 
5308
 
 
5309
  //defaults - Needs to be set after the Contrast list has been build
 
5310
  //Try to read the default contrast enhancement from the config file
 
5311
  QSettings myQSettings;
 
5312
  setContrastEnhancementAlgorithm( myQSettings.value( "/Raster/defaultContrastEnhancementAlgorithm", "StretchToMinimumMaximum" ).toString() );
 
5313
 
 
5314
  //decide what type of layer this is...
 
5315
  //TODO Change this to look at the color interp and palette interp to decide which type of layer it is
 
5316
  if (( GDALGetRasterCount( mGdalDataset ) > 1 ) )
 
5317
  {
 
5318
    mRasterType = Multiband;
 
5319
  }
 
5320
  //TODO hasBand is really obsolete and only used in the Palette instance, change to new function hasPalette(int)
 
5321
  else if ( hasBand( "Palette" ) ) //don't tr() this its a gdal word!
 
5322
  {
 
5323
    mRasterType = Palette;
 
5324
  }
 
5325
  else
 
5326
  {
 
5327
    mRasterType = GrayOrUndefined;
 
5328
  }
 
5329
 
 
5330
  if ( mRasterType == Palette )
 
5331
  {
 
5332
    mRedBandName = TRSTRING_NOT_SET; // sensible default
 
5333
    mGreenBandName = TRSTRING_NOT_SET; // sensible default
 
5334
    mBlueBandName = TRSTRING_NOT_SET;// sensible default
 
5335
    mTransparencyBandName = TRSTRING_NOT_SET; // sensible default
 
5336
    mGrayBandName = bandName( 1 );  //sensible default
 
5337
    QgsDebugMsg( mGrayBandName );
 
5338
 
 
5339
    mDrawingStyle = PalettedColor; //sensible default
 
5340
 
 
5341
    //Set up a new color ramp shader
 
5342
    setColorShadingAlgorithm( ColorRampShader );
 
5343
    QgsColorRampShader* myColorRampShader = ( QgsColorRampShader* ) mRasterShader->rasterShaderFunction();
 
5344
    //TODO: Make sure the set algorithm and cast was successful,
 
5345
    //e.g., if ( 0 != myColorRampShader && myColorRampShader->shaderTypeAsString == "ColorRampShader" )
 
5346
    myColorRampShader->setColorRampType( QgsColorRampShader::INTERPOLATED );
 
5347
    myColorRampShader->setColorRampItemList( *colorTable( 1 ) );
 
5348
  }
 
5349
  else if ( mRasterType == Multiband )
 
5350
  {
 
5351
    //we know we have at least 2 layers...
 
5352
    mRedBandName = bandName( myQSettings.value( "/Raster/defaultRedBand", 1 ).toInt() );  // sensible default
 
5353
    mGreenBandName = bandName( myQSettings.value( "/Raster/defaultGreenBand", 2 ).toInt() );  // sensible default
 
5354
    //for the third layer we cant be sure so..
 
5355
    if ( GDALGetRasterCount( mGdalDataset ) > 2 )
 
5356
    {
 
5357
      mBlueBandName = bandName( myQSettings.value( "/Raster/defaultBlueBand", 3 ).toInt() ); // sensible default
 
5358
    }
 
5359
    else
 
5360
    {
 
5361
      mBlueBandName = bandName( myQSettings.value( "/Raster/defaultBlueBand", 2 ).toInt() );  // sensible default
 
5362
    }
 
5363
 
 
5364
    mTransparencyBandName = TRSTRING_NOT_SET;
 
5365
    mGrayBandName = TRSTRING_NOT_SET;  //sensible default
 
5366
    mDrawingStyle = MultiBandColor;  //sensible default
 
5367
  }
 
5368
  else                        //GrayOrUndefined
 
5369
  {
 
5370
    mRedBandName = TRSTRING_NOT_SET; //sensible default
 
5371
    mGreenBandName = TRSTRING_NOT_SET; //sensible default
 
5372
    mBlueBandName = TRSTRING_NOT_SET;  //sensible default
 
5373
    mTransparencyBandName = TRSTRING_NOT_SET;  //sensible default
 
5374
    mDrawingStyle = SingleBandGray;  //sensible default
 
5375
    mGrayBandName = bandName( 1 );
 
5376
  }
 
5377
 
 
5378
  //mark the layer as valid
 
5379
  mValid = TRUE;
 
5380
  return true;
 
5381
 
 
5382
} // QgsRasterLayer::readFile
 
5383
 
 
5384
/*
 
5385
 *  @param index index in memory block
 
5386
 */
 
5387
double QgsRasterLayer::readValue( void *data, GDALDataType type, int index )
 
5388
{
 
5389
  double val;
 
5390
 
 
5391
  switch ( type )
 
5392
  {
 
5393
    case GDT_Byte:
 
5394
      return ( double )(( GByte * )data )[index];
 
5395
      break;
 
5396
    case GDT_UInt16:
 
5397
      return ( double )(( GUInt16 * )data )[index];
 
5398
      break;
 
5399
    case GDT_Int16:
 
5400
      return ( double )(( GInt16 * )data )[index];
 
5401
      break;
 
5402
    case GDT_UInt32:
 
5403
      return ( double )(( GUInt32 * )data )[index];
 
5404
      break;
 
5405
    case GDT_Int32:
 
5406
      return ( double )(( GInt32 * )data )[index];
 
5407
      break;
 
5408
    case GDT_Float32:
 
5409
      return ( double )(( float * )data )[index];
 
5410
      break;
 
5411
    case GDT_Float64:
 
5412
      val = (( double * )data )[index];
 
5413
      return ( double )(( double * )data )[index];
 
5414
      break;
 
5415
    default:
 
5416
      QgsLogger::warning( "GDAL data type is not supported" );
 
5417
  }
 
5418
  return 0.0;
 
5419
}
 
5420
 
 
5421
bool QgsRasterLayer::update()
 
5422
{
 
5423
  QgsDebugMsg( "entered." );
 
5424
 
 
5425
  if ( mLastModified < QgsRasterLayer::lastModified( source() ) )
 
5426
  {
 
5427
    QgsDebugMsg( "Outdated -> reload" );
 
5428
    closeDataset();
 
5429
    return readFile( source() );
 
5430
  }
 
5431
  return true;
 
5432
}
 
5433
 
 
5434
bool QgsRasterLayer::usesProvider()
 
5435
{
 
5436
  if ( mProviderKey.isEmpty() )
 
5437
  {
 
5438
    return FALSE;
 
5439
  }
 
5440
  else
 
5441
  {
 
5442
    return TRUE;
 
5443
  }
 
5444
}
 
5445
 
 
5446
QString QgsRasterLayer::validateBandName( QString const & theBandName )
 
5447
{
 
5448
  QgsDebugMsg( "Checking..." );
 
5449
  //check if the band is unset
 
5450
  if ( theBandName == TRSTRING_NOT_SET || theBandName == QSTRING_NOT_SET )
 
5451
  {
 
5452
    QgsDebugMsg( "Band name is '" + QSTRING_NOT_SET + "'. Nothing to do." );
 
5453
    // Use translated name internally
 
5454
    return TRSTRING_NOT_SET;
 
5455
  }
 
5456
 
 
5457
  //check that a valid band name was passed
 
5458
  QgsDebugMsg( "Looking through raster band stats for matching band name" );
 
5459
  for ( int myIterator = 0; myIterator < mRasterStatsList.size(); ++myIterator )
 
5460
  {
 
5461
    //find out the name of this band
 
5462
    if ( mRasterStatsList[myIterator].bandName == theBandName )
 
5463
    {
 
5464
      QgsDebugMsg( "Matching band name found" );
 
5465
      return theBandName;
 
5466
    }
 
5467
  }
 
5468
  QgsDebugMsg( "No matching band name found in raster band stats" );
 
5469
 
 
5470
  QgsDebugMsg( "Testing for non zero-buffered names" );
 
5471
  //TODO Remove test in v2.0 or earlier
 
5472
  QStringList myBandNameComponents = theBandName.split( " " );
 
5473
  if ( myBandNameComponents.size() == 2 )
 
5474
  {
 
5475
    int myBandNumber = myBandNameComponents.at( 1 ).toInt();
 
5476
    if ( myBandNumber > 0 )
 
5477
    {
 
5478
      QString myBandName = generateBandName( myBandNumber );
 
5479
      for ( int myIterator = 0; myIterator < mRasterStatsList.size(); ++myIterator )
 
5480
      {
 
5481
        //find out the name of this band
 
5482
        if ( mRasterStatsList[myIterator].bandName == myBandName )
 
5483
        {
 
5484
          QgsDebugMsg( "Matching band name found" );
 
5485
          return myBandName;
 
5486
        }
 
5487
      }
 
5488
    }
 
5489
  }
 
5490
 
 
5491
  QgsDebugMsg( "Testing older naming format" );
 
5492
  //See of the band in an older format #:something.
 
5493
  //TODO Remove test in v2.0 or earlier
 
5494
  myBandNameComponents.clear();
 
5495
  if ( theBandName.contains( ':' ) )
 
5496
  {
 
5497
    myBandNameComponents = theBandName.split( ":" );
 
5498
    if ( myBandNameComponents.size() == 2 )
 
5499
    {
 
5500
      int myBandNumber = myBandNameComponents.at( 0 ).toInt();
 
5501
      if ( myBandNumber > 0 )
 
5502
      {
 
5503
        QgsDebugMsg( "Transformed older name format to current format" );
 
5504
        return "Band " + QString::number( myBandNumber );
 
5505
      }
 
5506
    }
 
5507
  }
 
5508
 
 
5509
  //if no matches were found default to not set
 
5510
  QgsDebugMsg( "All checks failed, returning '" + QSTRING_NOT_SET + "'" );
 
5511
  return TRSTRING_NOT_SET;
 
5512
}