1
/* **************************************************************************
2
qgsrasterlayer.cpp - description
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
***************************************************************************/
9
/* **************************************************************************
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. *
16
***************************************************************************/
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"
31
#include "gdalwarper.h"
34
#include "qgspseudocolorshader.h"
35
#include "qgsfreakoutshader.h"
36
#include "qgscolorrampshader.h"
42
#include <QApplication>
44
#include <QDomElement>
49
#include <QFontMetrics>
55
#include <QMessageBox>
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
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
78
QgsRasterLayer::QgsRasterLayer(
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 ),
88
mWidth( std::numeric_limits<int>::max() ),
89
mHeight( std::numeric_limits<int>::max() ),
93
mRasterType = QgsRasterLayer::GrayOrUndefined;
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;
102
mUserDefinedRGBMinimumMaximum = false; //defaults needed to bypass enhanceContrast
103
mUserDefinedGrayMinimumMaximum = false;
104
mRGBMinimumMaximumEstimated = true;
105
mGrayMinimumMaximumEstimated = true;
107
mDrawingStyle = QgsRasterLayer::UndefinedDrawingStyle;
108
mContrastEnhancementAlgorithm = QgsContrastEnhancement::NoEnhancement;
109
mColorShadingAlgorithm = QgsRasterLayer::UndefinedShader;
110
mRasterShader = new QgsRasterShader();
113
mHasPyramids = false;
114
mNoDataValue = -9999.0;
115
mValidNoDataValue = false;
117
mGdalBaseDataset = 0;
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;
128
// set the layer name (uppercase first character)
130
if ( ! baseName.isEmpty() ) // XXX shouldn't this happen in parent?
132
setLayerName( baseName );
135
// load the file if one specified
136
if ( ! path.isEmpty() )
138
readFile( path ); // XXX check for failure?
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 )
144
bool defaultLoadedFlag = false;
145
loadDefaultStyle( defaultLoadedFlag );
146
if ( defaultLoadedFlag )
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;
167
} // QgsRasterLayer ctor
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.
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 ),
185
mWidth( std::numeric_limits<int>::max() ),
186
mHeight( std::numeric_limits<int>::max() ),
187
mInvertColor( false ),
189
mProviderKey( providerKey )
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 );
196
mRasterShader = new QgsRasterShader();
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;
206
// if we're given a provider type, try to create and bind one to this layer
207
if ( ! providerKey.isEmpty() )
209
setDataProvider( providerKey, layers, styles, format, crs );
212
// Default for the popup menu
213
// TODO: popMenu = 0;
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);
224
// TODO: Connect signals from the dataprovider to the qgisapp
226
// Do a passthrough for the status bar text
228
mDataProvider, SIGNAL( statusChanged( QString ) ),
229
this, SLOT( showStatusMessage( QString ) )
231
QgsDebugMsg( "(8 arguments) exiting." );
233
emit statusChanged( tr( "QgsRasterLayer created" ) );
234
} // QgsRasterLayer ctor
236
QgsRasterLayer::~QgsRasterLayer()
239
if ( mProviderKey.isEmpty() )
241
if ( mGdalBaseDataset )
243
GDALDereferenceDataset( mGdalBaseDataset );
248
GDALClose( mGdalDataset );
257
//////////////////////////////////////////////////////////
259
// Static Methods and members
261
/////////////////////////////////////////////////////////
263
Builds the list of file filter strings to later be used by
264
QgisApp::addRasterLayer()
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.
272
void QgsRasterLayer::buildSupportedRasterFileFilter( QString & theFileFiltersString )
274
// first get the GDAL driver manager
275
registerGdalDrivers();
277
// then iterate through all of the supported drivers, adding the
278
// corresponding file filter
280
GDALDriverH myGdalDriver; // current driver
282
char **myGdalDriverMetadata; // driver metadata strings
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
288
QStringList metadataTokens; // essentially the metadata string delimited by '='
290
QStringList catchallFilter; // for Any file(*.*), but also for those
291
// drivers with no specific file filter
293
GDALDriverH jp2Driver = NULL; // first JPEG2000 driver found
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
306
for ( int i = 0; i < GDALGetDriverCount(); ++i )
308
myGdalDriver = GDALGetDriver( i );
310
Q_CHECK_PTR( myGdalDriver );
314
QgsLogger::warning( "unable to get driver " + QString::number( i ) );
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
320
myGdalDriverDescription = GDALGetDescription( myGdalDriver );
322
// QgsDebugMsg(QString("got driver string %1").arg(myGdalDriverDescription));
324
myGdalDriverMetadata = GDALGetMetadata( myGdalDriver, NULL );
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] )
330
metadataTokens = QString( *myGdalDriverMetadata ).split( "=", QString::SkipEmptyParts );
331
// QgsDebugMsg(QString("\t%1").arg(*myGdalDriverMetadata));
333
// XXX add check for malformed metadataTokens
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.
339
if ( metadataTokens.count() > 1 )
341
if ( "DMD_EXTENSION" == metadataTokens[0] )
343
myGdalDriverExtension = metadataTokens[1];
346
else if ( "DMD_LONGNAME" == metadataTokens[0] )
348
myGdalDriverLongName = metadataTokens[1];
350
// remove any superfluous (.*) strings at the end as
351
// they'll confuse QFileDialog::getOpenFileNames()
353
myGdalDriverLongName.remove( QRegExp( "\\(.*\\)$" ) );
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
360
if ( !( myGdalDriverExtension.isEmpty() || myGdalDriverLongName.isEmpty() ) )
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
369
break; // skip if already found a JP2 driver
371
jp2Driver = myGdalDriver; // first JP2 driver found
372
glob += " *.j2k"; // add alternate extension
374
else if ( myGdalDriverDescription == "GTiff" )
378
else if ( myGdalDriverDescription == "JPEG" )
383
theFileFiltersString += myGdalDriverLongName + " (" + glob.toLower() + " " + glob.toUpper() + ");;";
385
break; // ... to next driver, if any.
388
++myGdalDriverMetadata;
390
} // each metadata item
392
if ( myGdalDriverExtension.isEmpty() && !myGdalDriverLongName.isEmpty() )
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
401
// ... OTOH, there are some drivers with missing
402
// DMD_EXTENSION; so let's check for them here and handle
403
// them appropriately
405
// USGS DEMs use "*.dem"
406
if ( myGdalDriverDescription.startsWith( "USGSDEM" ) )
408
QString glob = "*.dem";
409
theFileFiltersString += myGdalDriverLongName + " (" + glob.toLower() + " " + glob.toUpper() + ");;";
411
else if ( myGdalDriverDescription.startsWith( "DTED" ) )
414
QString glob = "*.dt0";
415
theFileFiltersString += myGdalDriverLongName + " (" + glob.toLower() + " " + glob.toUpper() + ");;";
417
else if ( myGdalDriverDescription.startsWith( "MrSID" ) )
420
QString glob = "*.sid";
421
theFileFiltersString += myGdalDriverLongName + " (" + glob.toLower() + " " + glob.toUpper() + ");;";
425
catchallFilter << QString( GDALGetDescription( myGdalDriver ) );
429
myGdalDriverExtension = myGdalDriverLongName = ""; // reset for next driver
431
} // each loaded GDAL driver
433
// can't forget the default case
434
theFileFiltersString += tr( "All other files (*)" );
435
QgsDebugMsg( "Raster filter list built: " + theFileFiltersString );
436
} // buildSupportedRasterFileFilter_()
439
* This helper checks to see whether the file name appears to be a valid raster file name
441
bool QgsRasterLayer::isValidRasterFileName( QString const & theFileNameQString,
442
QString & retErrMsg )
445
GDALDatasetH myDataset;
446
registerGdalDrivers();
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 )
454
if ( CPLGetLastErrorNo() != CPLE_OpenFailed )
455
retErrMsg = QString::fromUtf8( CPLGetLastErrorMsg() );
458
else if ( GDALGetRasterCount( myDataset ) == 0 )
460
GDALClose( myDataset );
462
retErrMsg = "This raster file has no bands and is invalid as a raster layer.";
467
GDALClose( myDataset );
472
bool QgsRasterLayer::isValidRasterFileName( QString const & theFileNameQString )
477
return isValidRasterFileName( theFileNameQString, retErrMsg );
480
QDateTime QgsRasterLayer::lastModified( QString const & name )
482
QgsDebugMsg( "name=" + name );
485
QFileInfo fi( name );
488
if ( !fi.exists() ) return t;
490
t = fi.lastModified();
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 );
501
if ( fi.lastModified() > t ) t = fi.lastModified();
505
// Check GRASS group members (bands)
506
if ( name.contains( "group" ) > 0 )
507
{ // probably GRASS group
508
fi.setFile( name + "/REF" );
511
{ // most probably GRASS group
512
QFile f( name + "/REF" );
513
if ( f.open( QIODevice::ReadOnly ) )
515
QString dir = fi.path() + "/../../../";
518
while ( f.readLine( buf, 100 ) != -1 )
520
QString ln = QString( buf );
521
QStringList sl = ln.trimmed().split( ' ', QString::SkipEmptyParts );
522
QString map = sl.first();
524
QString mapset = sl.first();
527
fi.setFile( dir + mapset + "/cellhd/" + map );
530
if ( fi.lastModified() > t ) t = fi.lastModified();
534
fi.setFile( dir + mapset + "/colr/" + map );
537
if ( fi.lastModified() > t ) t = fi.lastModified();
544
QgsDebugMsg( "last modified = " + t.toString() );
551
void QgsRasterLayer::registerGdalDrivers()
553
if ( GDALGetDriverCount() == 0 )
560
//////////////////////////////////////////////////////////
562
//Random Static convenience function
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 )
569
return "<p>\n" + value + "</p>\n";
574
// convenience function for building metadata() HTML table cells
575
static QString makeTableCells_( QStringList const & values )
579
for ( QStringList::const_iterator i = values.begin();
583
s += makeTableCell_( *i );
593
// convenience function for creating a string list from a C style string list
594
static QStringList cStringList2Q_( char ** stringList )
598
// presume null terminated string list
599
for ( size_t i = 0; stringList[i]; ++i )
601
strings.append( stringList[i] );
609
// typedef for the QgsDataProvider class factory
610
typedef QgsDataProvider * classFactoryFunction_t( const QString * );
614
// global callback function
616
int CPL_STDCALL progressCallback( double dfComplete,
617
const char * pszMessage,
618
void * pProgressArg )
620
static double dfLastComplete = -1.0;
622
QgsRasterLayer * mypLayer = ( QgsRasterLayer * ) pProgressArg;
624
if ( dfLastComplete > dfComplete )
626
if ( dfLastComplete >= 1.0 )
627
dfLastComplete = -1.0;
629
dfLastComplete = dfComplete;
632
if ( floor( dfLastComplete*10 ) != floor( dfComplete*10 ) )
634
int nPercent = ( int ) floor( dfComplete * 100 );
636
if ( nPercent == 0 && pszMessage != NULL )
638
//fprintf( stdout, "%s:", pszMessage );
641
if ( nPercent == 100 )
643
//fprintf( stdout, "%d - done.\n", (int) floor(dfComplete*100) );
644
mypLayer->showProgress( 100 );
648
int myProgress = ( int ) floor( dfComplete * 100 );
649
//fprintf( stdout, "%d.", myProgress);
650
mypLayer->showProgress( myProgress );
654
dfLastComplete = dfComplete;
662
//////////////////////////////////////////////////////////
664
// Non Static Public methods
666
/////////////////////////////////////////////////////////
668
unsigned int QgsRasterLayer::bandCount()
673
const QString QgsRasterLayer::bandName( int theBandNo )
675
if ( theBandNo <= mRasterStatsList.size() && theBandNo > 0 )
677
//vector starts at base 0, band counts at base1 !
678
return mRasterStatsList[theBandNo - 1].bandName;
682
return QString( "" );
686
int QgsRasterLayer::bandNumber( QString const & theBandName )
688
for ( int myIterator = 0; myIterator < mRasterStatsList.size(); ++myIterator )
690
//find out the name of this band
691
QgsRasterBandStats myRasterBandStats = mRasterStatsList[myIterator];
692
QgsDebugMsg( "myRasterBandStats.bandName: " + myRasterBandStats.bandName + " :: theBandName: "
695
if ( myRasterBandStats.bandName == theBandName )
697
QgsDebugMsg( "********** band " + QString::number( myRasterBandStats.bandNumber ) +
698
" was found in bandNumber " + theBandName );
700
return myRasterBandStats.bandNumber;
703
QgsDebugMsg( "********** no band was found in bandNumber " + theBandName );
705
return 0; //no band was found
710
* Private method to calculate statistics for a band. Populates rasterStatsMemArray.
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
725
* @seealso RasterBandStats
726
* @note This is a cpu intensive and slow task!
728
const QgsRasterBandStats QgsRasterLayer::bandStatistics( int theBandNo )
730
// check if we have received a valid band number
731
if (( GDALGetRasterCount( mGdalDataset ) < theBandNo ) && mRasterType != Palette )
733
// invalid band id, return nothing
734
QgsRasterBandStats myNullReturnStats;
735
return myNullReturnStats;
737
if ( mRasterType == Palette && ( theBandNo > 3 ) )
739
// invalid band id, return nothing
740
QgsRasterBandStats myNullReturnStats;
741
return myNullReturnStats;
744
// check if we have previously gathered stats for this band...
745
if ( theBandNo < 1 || theBandNo > mRasterStatsList.size() )
747
// invalid band id, return nothing
748
QgsRasterBandStats myNullReturnStats;
749
return myNullReturnStats;
752
QgsRasterBandStats myRasterBandStats = mRasterStatsList[theBandNo - 1];
753
myRasterBandStats.bandNumber = theBandNo;
755
// don't bother with this if we already have stats
756
if ( myRasterBandStats.statsGathered )
758
return myRasterBandStats;
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 );
767
QString myColorerpretation = GDALGetColorInterpretationName( GDALGetRasterColorInterpretation( myGdalBand ) );
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;
773
myRasterBandStats.elementCount = 0; // because we'll be counting only VALID pixels later
775
emit statusChanged( tr( "Calculating stats for %1" ).arg( name() ) );
776
//reset the main app progress bar
777
emit drawingProgress( 0, 0 );
779
// let the user know we're going to possibly be taking a while
780
//QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
782
GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
784
int myNXBlocks, myNYBlocks, myXBlockSize, myYBlockSize;
785
GDALGetBlockSize( myGdalBand, &myXBlockSize, &myYBlockSize );
787
myNXBlocks = ( GDALGetRasterXSize( myGdalBand ) + myXBlockSize - 1 ) / myXBlockSize;
788
myNYBlocks = ( GDALGetRasterYSize( myGdalBand ) + myYBlockSize - 1 ) / myYBlockSize;
790
void *myData = CPLMalloc( myXBlockSize * myYBlockSize * ( GDALGetDataTypeSize( myDataType ) / 8 ) );
792
// unfortunately we need to make two passes through the data to calculate stddev
793
bool myFirstIterationFlag = true;
795
//ifdefs below to remove compiler warning about unused vars
798
double GDALminimum = GDALGetRasterMinimum( myGdalBand, &success );
802
QgsDebugMsg( "myGdalBand->GetMinimum() failed" );
805
double GDALmaximum = GDALGetRasterMaximum( myGdalBand, &success );
809
QgsDebugMsg( "myGdalBand->GetMaximum() failed" );
812
double GDALnodata = GDALGetRasterNoDataValue( myGdalBand, &success );
816
QgsDebugMsg( "myGdalBand->GetNoDataValue() failed" );
819
QgsLogger::debug( "GDALminium: ", GDALminimum, __FILE__, __FUNCTION__, __LINE__ );
820
QgsLogger::debug( "GDALmaximum: ", GDALmaximum, __FILE__, __FUNCTION__, __LINE__ );
821
QgsLogger::debug( "GDALnodata: ", GDALnodata, __FILE__, __FUNCTION__, __LINE__ );
823
double GDALrange[2]; // calculated min/max, as opposed to the
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 );
830
GDALComputeRasterMinMax( myGdalBand, 0, GDALrange );
831
QgsLogger::debug( "exactly computed GDALminium:", GDALrange[0] );
832
QgsLogger::debug( "exactly computed GDALmaximum:", GDALrange[1] );
834
QgsDebugMsg( "starting manual stat computation" );
837
int myGdalBandXSize = GDALGetRasterXSize( myGdalBand );
838
int myGdalBandYSize = GDALGetRasterYSize( myGdalBand );
839
for ( int iYBlock = 0; iYBlock < myNYBlocks; iYBlock++ )
841
emit drawingProgress( iYBlock, myNYBlocks * 2 );
843
for ( int iXBlock = 0; iXBlock < myNXBlocks; iXBlock++ )
845
int nXValid, nYValid;
846
GDALReadBlock( myGdalBand, iXBlock, iYBlock, myData );
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;
853
nXValid = myXBlockSize;
855
if (( iYBlock + 1 ) * myYBlockSize > myGdalBandYSize )
856
nYValid = myGdalBandYSize - iYBlock * myYBlockSize;
858
nYValid = myYBlockSize;
860
// Collect the histogram counts.
861
for ( int iY = 0; iY < nYValid; iY++ )
863
for ( int iX = 0; iX < nXValid; iX++ )
865
double myValue = readValue( myData, myDataType, iX + ( iY * myXBlockSize ) );
867
if ( mValidNoDataValue && ( fabs( myValue - mNoDataValue ) <= TINY_VALUE || myValue != myValue ) )
872
//only use this element if we have a non null element
873
if ( myFirstIterationFlag )
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
883
//this is done for all subsequent iterations
884
if ( myValue < myRasterBandStats.minimumValue )
886
myRasterBandStats.minimumValue = myValue;
888
if ( myValue > myRasterBandStats.maximumValue )
890
myRasterBandStats.maximumValue = myValue;
893
myRasterBandStats.sum += myValue;
894
++myRasterBandStats.elementCount;
895
} //end of false part for first iteration check
898
} //end of column wise loop
899
} //end of row wise loop
902
//end of first pass through data now calculate the range
903
myRasterBandStats.range = myRasterBandStats.maximumValue - myRasterBandStats.minimumValue;
905
myRasterBandStats.mean = myRasterBandStats.sum / myRasterBandStats.elementCount;
907
//for the second pass we will get the sum of the squares / mean
908
for ( int iYBlock = 0; iYBlock < myNYBlocks; iYBlock++ )
910
emit drawingProgress( iYBlock + myNYBlocks, myNYBlocks * 2 );
912
for ( int iXBlock = 0; iXBlock < myNXBlocks; iXBlock++ )
914
int nXValid, nYValid;
916
GDALReadBlock( myGdalBand, iXBlock, iYBlock, myData );
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;
923
nXValid = myXBlockSize;
925
if (( iYBlock + 1 ) * myYBlockSize > myGdalBandYSize )
926
nYValid = myGdalBandYSize - iYBlock * myYBlockSize;
928
nYValid = myYBlockSize;
930
// Collect the histogram counts.
931
for ( int iY = 0; iY < nYValid; iY++ )
933
for ( int iX = 0; iX < nXValid; iX++ )
935
double myValue = readValue( myData, myDataType, iX + ( iY * myXBlockSize ) );
937
if ( mValidNoDataValue && ( fabs( myValue - mNoDataValue ) <= TINY_VALUE || myValue != myValue ) )
942
myRasterBandStats.sumOfSquares += static_cast < double >
943
( pow( myValue - myRasterBandStats.mean, 2 ) );
946
} //end of column wise loop
947
} //end of row wise loop
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 ) ) );
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__ );
965
myRasterBandStats.statsGathered = true;
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;
975
} // QgsRasterLayer::bandStatistics
977
const QgsRasterBandStats QgsRasterLayer::bandStatistics( QString const & theBandName )
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++ )
984
QgsRasterBandStats myRasterBandStats = bandStatistics( i );
985
if ( myRasterBandStats.bandName == theBandName )
987
return myRasterBandStats;
991
return QgsRasterBandStats(); // return a null one
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.
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
1005
QString QgsRasterLayer::buildPyramids( RasterPyramidList const & theRasterPyramidList,
1006
QString const & theResamplingMethod, bool theTryInternalFlag )
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
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)
1019
emit drawingProgress( 0, 0 );
1020
//first test if the file is writeable
1021
QFileInfo myQFile( mDataSource );
1023
if ( !myQFile.isWritable() )
1025
return "ERROR_WRITE_ACCESS";
1028
if ( mGdalDataset != mGdalBaseDataset )
1030
QgsLogger::warning( "Pyramid building not currently supported for 'warped virtual dataset'." );
1031
return "ERROR_VIRTUAL";
1034
if ( theTryInternalFlag )
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 )
1043
QString myCompressionType = QString( GDALGetMetadataItem( mGdalDataset, "COMPRESSION", "IMAGE_STRUCTURE" ) );
1044
if ( "JPEG" == myCompressionType )
1046
return "ERROR_JPEG_COMPRESSION";
1050
//close the gdal dataset and reopen it in read / write mode
1051
GDALClose( mGdalDataset );
1052
mGdalBaseDataset = GDALOpen( QFile::encodeName( mDataSource ).constData(), GA_Update );
1054
// if the dataset couldn't be opened in read / write mode, tell the user
1055
if ( !mGdalBaseDataset )
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";
1065
// Iterate through the Raster Layer Pyramid Vector, building any pyramid
1066
// marked as exists in eaxh RasterPyramid struct.
1068
CPLErr myError; //in case anything fails
1070
int myTotal = theRasterPyramidList.count();
1071
RasterPyramidList::const_iterator myRasterPyramidIterator;
1072
for ( myRasterPyramidIterator = theRasterPyramidList.begin();
1073
myRasterPyramidIterator != theRasterPyramidList.end();
1074
++myRasterPyramidIterator )
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__ );
1082
if (( *myRasterPyramidIterator ).build )
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.
1096
//build the pyramid and show progress to console
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.
1105
if ( theResamplingMethod == tr( "Average Magphase" ) )
1107
myError = GDALBuildOverviews( mGdalBaseDataset, "MODE", 1, myOverviewLevelsArray, 0, NULL,
1108
progressCallback, this ); //this is the arg for the gdal progress callback
1110
else if ( theResamplingMethod == tr( "Average" ) )
1113
myError = GDALBuildOverviews( mGdalBaseDataset, "AVERAGE", 1, myOverviewLevelsArray, 0, NULL,
1114
progressCallback, this ); //this is the arg for the gdal progress callback
1116
else // fall back to nearest neighbor
1118
myError = GDALBuildOverviews( mGdalBaseDataset, "NEAREST", 1, myOverviewLevelsArray, 0, NULL,
1119
progressCallback, this ); //this is the arg for the gdal progress callback
1122
if ( myError == CE_Failure || CPLGetLastErrorNo() == CPLE_NotSupported )
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;
1131
emit drawingProgress( 0, 0 );
1132
return "FAILED_NOT_SUPPORTED";
1136
//make sure the raster knows it has pyramids
1137
mHasPyramids = true;
1144
QgsLogger::warning( "Pyramid overview building failed!" );
1149
QgsDebugMsg( "Pyramid overviews built" );
1150
if ( theTryInternalFlag )
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;
1159
emit drawingProgress( 0, 0 );
1160
return NULL; // returning null on success
1164
QgsRasterLayer::RasterPyramidList QgsRasterLayer::buildPyramidList()
1167
// First we build up a list of potential pyramid layers
1169
int myWidth = mWidth;
1170
int myHeight = mHeight;
1172
GDALRasterBandH myGDALBand = GDALGetRasterBand( mGdalDataset, 1 ); //just use the first band
1174
mPyramidList.clear();
1175
QgsDebugMsg( "Building initial pyramid list" );
1176
while (( myWidth / myDivisor > 32 ) && (( myHeight / myDivisor ) > 32 ) )
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;
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__ );
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.
1195
const int myNearMatchLimit = 5;
1196
if ( GDALGetOverviewCount( myGDALBand ) > 0 )
1198
int myOverviewCount;
1199
for ( myOverviewCount = 0;
1200
myOverviewCount < GDALGetOverviewCount( myGDALBand );
1203
GDALRasterBandH myOverview;
1204
myOverview = GDALGetOverview( myGDALBand, myOverviewCount );
1205
int myOverviewXDim = GDALGetRasterBandXSize( myOverview );
1206
int myOverviewYDim = GDALGetRasterBandYSize( myOverview );
1208
// here is where we check if its a near match:
1209
// we will see if its within 5 cells either side of
1211
QgsDebugMsg( "Checking whether " + QString::number( myRasterPyramid.xDim ) + " x " +
1212
QString::number( myRasterPyramid.yDim ) + " matches " +
1213
QString::number( myOverviewXDim ) + " x " + QString::number( myOverviewYDim ) );
1216
if (( myOverviewXDim <= ( myRasterPyramid.xDim + myNearMatchLimit ) ) &&
1217
( myOverviewXDim >= ( myRasterPyramid.xDim - myNearMatchLimit ) ) &&
1218
( myOverviewYDim <= ( myRasterPyramid.yDim + myNearMatchLimit ) ) &&
1219
( myOverviewYDim >= ( myRasterPyramid.yDim - myNearMatchLimit ) ) )
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!" );
1230
QgsDebugMsg( ".....no." );
1234
mPyramidList.append( myRasterPyramid );
1235
//sqare the divisor each step
1236
myDivisor = ( myDivisor * 2 );
1239
return mPyramidList;
1242
QString QgsRasterLayer::colorShadingAlgorithmAsString() const
1244
switch ( mColorShadingAlgorithm )
1246
case PseudoColorShader:
1247
return QString( "PseudoColorShader" );
1249
case FreakOutShader:
1250
return QString( "FreakOutShader" );
1252
case ColorRampShader:
1253
return QString( "ColorRampShader" );
1255
case UserDefinedShader:
1256
return QString( "UserDefinedShader" );
1262
return QString( "UndefinedShader" );
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
1269
void QgsRasterLayer::computeMinimumMaximumEstimates( int theBand, double* theMinMax )
1271
if ( 0 == theMinMax ) { return; }
1273
if ( 0 < theBand && theBand <= ( int ) bandCount() )
1275
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBand );
1276
GDALComputeRasterMinMax( myGdalBand, 1, theMinMax );
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
1284
void QgsRasterLayer::computeMinimumMaximumEstimates( QString theBand, double* theMinMax )
1286
computeMinimumMaximumEstimates( bandNumber( theBand ), theMinMax );
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
1293
void QgsRasterLayer::computeMinimumMaximumFromLastExtent( int theBand, double* theMinMax )
1295
if ( 0 == theMinMax ) { return; }
1297
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBand );
1298
GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
1299
void* myGdalScanData = readData( myGdalBand, &mLastViewPort );
1301
/* Check for out of memory error */
1302
if ( myGdalScanData == NULL )
1307
if ( 0 < theBand && theBand <= ( int ) bandCount() )
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 )
1314
for ( int myColumn = 0; myColumn < mLastViewPort.drawableAreaXDim; ++myColumn )
1316
myValue = readValue( myGdalScanData, myDataType, myRow * mLastViewPort.drawableAreaXDim + myColumn );
1317
if ( mValidNoDataValue && ( fabs( myValue - mNoDataValue ) <= TINY_VALUE || myValue != myValue ) )
1321
myMin = qMin( myMin, myValue );
1322
myMax = qMax( myMax, myValue );
1325
theMinMax[0] = myMin;
1326
theMinMax[1] = myMax;
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
1334
void QgsRasterLayer::computeMinimumMaximumFromLastExtent( QString theBand, double* theMinMax )
1336
computeMinimumMaximumFromLastExtent( bandNumber( theBand ), theMinMax );
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
1343
QgsContrastEnhancement* QgsRasterLayer::contrastEnhancement( unsigned int theBand )
1345
if ( 0 < theBand && theBand <= bandCount() )
1347
return &mContrastEnhancementList[theBand - 1];
1353
QString QgsRasterLayer::contrastEnhancementAlgorithmAsString() const
1355
switch ( mContrastEnhancementAlgorithm )
1357
case QgsContrastEnhancement::NoEnhancement:
1358
return QString( "NoEnhancement" );
1360
case QgsContrastEnhancement::StretchToMinimumMaximum:
1361
return QString( "StretchToMinimumMaximum" );
1363
case QgsContrastEnhancement::StretchAndClipToMinimumMaximum:
1364
return QString( "StretchAndClipToMinimumMaximum" );
1366
case QgsContrastEnhancement::ClipToMinimumMaximum:
1367
return QString( "ClipToMinimumMaximum" );
1369
case QgsContrastEnhancement::UserDefinedEnhancement:
1370
return QString( "UserDefined" );
1374
return QString( "NoEnhancement" );
1378
* @note Note implemented yet
1379
* @return always returns false
1381
bool QgsRasterLayer::copySymbologySettings( const QgsMapLayer& theOther )
1384
if ( theOther.type() < 0 )
1392
* @param band number
1393
* @return pointer to the color table
1395
QList<QgsColorRampShader::ColorRampItem>* QgsRasterLayer::colorTable( int theBandNo )
1397
return &( mRasterStatsList[theBandNo-1].colorTable );
1401
* @return 0 if not using the data provider model (i.e. directly using GDAL)
1403
QgsRasterDataProvider* QgsRasterLayer::dataProvider()
1405
return mDataProvider;
1409
* @return 0 if not using the data provider model (i.e. directly using GDAL)
1411
const QgsRasterDataProvider* QgsRasterLayer::dataProvider() const
1413
return mDataProvider;
1416
bool QgsRasterLayer::draw( QgsRenderContext& rendererContext )
1418
QgsDebugMsg( "entered. (renderContext)" );
1420
// Don't waste time drawing if transparency is at 0 (completely transparent)
1421
if ( mTransparencyLevel == 0 )
1424
QgsDebugMsg( "checking timestamp." );
1432
const QgsMapToPixel& theQgsMapToPixel = rendererContext.mapToPixel();
1433
const QgsRectangle& theViewExtent = rendererContext.extent();
1434
QPainter* theQPainter = rendererContext.painter();
1441
// clip raster extent to view extent
1442
QgsRectangle myRasterExtent = theViewExtent.intersect( &mLayerExtent );
1443
if ( myRasterExtent.isEmpty() )
1449
QgsDebugMsg( "theViewExtent is " + theViewExtent.toString() );
1450
QgsDebugMsg( "myRasterExtent is " + myRasterExtent.toString() );
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.
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();
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] );
1468
if ( myRasterViewPort->rectXOffsetFloat < 0 )
1470
myRasterViewPort->rectXOffsetFloat = 0;
1473
if ( myRasterViewPort->rectYOffsetFloat < 0 )
1475
myRasterViewPort->rectYOffsetFloat = 0;
1478
myRasterViewPort->rectXOffset = static_cast < int >( myRasterViewPort->rectXOffsetFloat );
1479
myRasterViewPort->rectYOffset = static_cast < int >( myRasterViewPort->rectYOffsetFloat );
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] ) );
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];
1497
// Sometimes the Ymin/Ymax are reversed.
1498
if ( myRasterViewPort->clippedYMin > myRasterViewPort->clippedYMax )
1500
double t = myRasterViewPort->clippedYMin;
1501
myRasterViewPort->clippedYMin = myRasterViewPort->clippedYMax;
1502
myRasterViewPort->clippedYMax = t;
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 ) );
1510
myRasterViewPort->clippedHeight =
1511
static_cast<int>( ceil( myRasterViewPort->clippedYMax ) - floor( myRasterViewPort->clippedYMin ) );
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 )
1519
myRasterViewPort->clippedWidth =
1520
mWidth - myRasterViewPort->rectXOffset;
1522
if (( myRasterViewPort->rectYOffset + myRasterViewPort->clippedHeight )
1525
myRasterViewPort->clippedHeight =
1526
mHeight - myRasterViewPort->rectYOffset;
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() );
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 );
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 ) );
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() ) );
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() ) );
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 ) );
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 ) );
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 );
1569
// /\/\/\ - added to handle zoomed-in rasters
1571
mLastViewPort = *myRasterViewPort;
1573
// Provider mode: See if a provider key is specified, and if so use the provider instead
1575
QgsDebugMsg( "Checking for provider key." );
1577
if ( !mProviderKey.isEmpty() )
1579
QgsDebugMsg( "Wanting a '" + mProviderKey + "' provider to draw this." );
1581
emit statusChanged( tr( "Retrieving %1 using %2" ).arg( name() ).arg( mProviderKey ) );
1583
mDataProvider->setDpi( rendererContext.rasterScaleFactor() * 25.4 * rendererContext.scaleFactor() );
1586
mDataProvider->draw(
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
1600
// An error occurred.
1601
mErrorCaption = mDataProvider->lastErrorTitle();
1602
mError = mDataProvider->lastError();
1604
delete myRasterViewPort;
1608
QgsDebugMsg( "Done mDataProvider->draw." );
1609
QgsDebugMsg( "image stats: " );
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() ) );
1616
QgsDebugMsg( "Want to theQPainter->drawImage with" );
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() ) ) );
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
1627
if ( mTransparencyLevel != 255 ) //improve performance if layer transparency not altered
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();
1634
int newTransparency;
1635
for ( int myHeightRunner = 0; myHeightRunner < myHeight; myHeightRunner++ )
1637
QRgb* myLineBuffer = ( QRgb* ) transparentImageCopy->scanLine( myHeightRunner );
1638
for ( int myWidthRunner = 0; myWidthRunner < myWidth; myWidthRunner++ )
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 );
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
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
1663
if ( mTransparencyLevel != 255 )
1668
emit statusChanged( tr( "%1 retrieved using %2" ).arg( name() ).arg( mProviderKey ) );
1672
// Otherwise use the old-fashioned GDAL direct-drawing style
1673
// TODO: Move into its own GDAL provider.
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
1683
delete myRasterViewPort;
1684
QgsDebugMsg( "exiting." );
1690
void QgsRasterLayer::draw( QPainter * theQPainter,
1691
QgsRasterViewPort * theRasterViewPort,
1692
const QgsMapToPixel* theQgsMapToPixel )
1694
QgsDebugMsg( " 3 arguments" );
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 :
1702
switch ( mDrawingStyle )
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 )
1713
drawSingleBandGray( theQPainter, theRasterViewPort,
1714
theQgsMapToPixel, bandNumber( mGrayBandName ) );
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 )
1726
drawSingleBandPseudoColor( theQPainter, theRasterViewPort,
1727
theQgsMapToPixel, bandNumber( mGrayBandName ) );
1730
// a single band with a color map
1732
//check the band is set!
1733
if ( mGrayBandName == TRSTRING_NOT_SET )
1739
QgsDebugMsg( "PalettedColor drawing type detected..." );
1741
drawPalettedSingleBandColor( theQPainter, theRasterViewPort,
1742
theQgsMapToPixel, bandNumber( mGrayBandName ) );
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 )
1755
QgsDebugMsg( "PalettedSingleBandGray drawing type detected..." );
1758
drawPalettedSingleBandGray( theQPainter, theRasterViewPort,
1759
theQgsMapToPixel, myBandNo );
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 )
1774
drawPalettedSingleBandPseudoColor( theQPainter, theRasterViewPort,
1775
theQgsMapToPixel, myBandNo );
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 );
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 )
1789
QgsDebugMsg( "MultiBandSingleGandGray Not Set detected..." + mGrayBandName );
1795
//get the band number for the mapped gray band
1796
drawMultiBandSingleBandGray( theQPainter, theRasterViewPort,
1797
theQgsMapToPixel, bandNumber( mGrayBandName ) );
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 )
1810
drawMultiBandSingleBandPseudoColor( theQPainter, theRasterViewPort,
1811
theQgsMapToPixel, bandNumber( mGrayBandName ) );
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 )
1826
drawMultiBandColor( theQPainter, theRasterViewPort,
1836
} //end of draw method
1838
QString QgsRasterLayer::drawingStyleAsString() const
1840
switch ( mDrawingStyle )
1842
case SingleBandGray:
1843
return QString( "SingleBandGray" ); //no need to tr() this its not shown in ui
1845
case SingleBandPseudoColor:
1846
return QString( "SingleBandPseudoColor" );//no need to tr() this its not shown in ui
1849
return QString( "PalettedColor" );//no need to tr() this its not shown in ui
1851
case PalettedSingleBandGray:
1852
return QString( "PalettedSingleBandGray" );//no need to tr() this its not shown in ui
1854
case PalettedSingleBandPseudoColor:
1855
return QString( "PalettedSingleBandPseudoColor" );//no need to tr() this its not shown in ui
1857
case PalettedMultiBandColor:
1858
return QString( "PalettedMultiBandColor" );//no need to tr() this its not shown in ui
1860
case MultiBandSingleGandGray:
1861
return QString( "MultiBandSingleGandGray" );//no need to tr() this its not shown in ui
1863
case MultiBandSingleBandPseudoColor:
1864
return QString( "MultiBandSingleBandPseudoColor" );//no need to tr() this its not shown in ui
1866
case MultiBandColor:
1867
return QString( "MultiBandColor" );//no need to tr() this its not shown in ui
1873
return QString( "UndefinedDrawingStyle" );
1878
* @note Note implemented yet
1879
* @return always returns false
1881
bool QgsRasterLayer::hasCompatibleSymbology( const QgsMapLayer& theOther ) const
1884
if ( theOther.type() < 0 )
1892
* @param theBandNo The number of the band to check
1893
* @return true if statistics have already been build for this band otherwise false
1895
bool QgsRasterLayer::hasStatistics( int theBandNo )
1897
if ( theBandNo <= mRasterStatsList.size() && theBandNo > 0 )
1899
//vector starts at base 0, band counts at base1 !
1900
return mRasterStatsList[theBandNo - 1].statsGathered;
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
1913
bool QgsRasterLayer::identify( const QgsPoint& thePoint, QMap<QString, QString>& theResults )
1916
if ( mProviderKey == "wms" )
1921
QgsDebugMsg( thePoint.toString() );
1923
if ( !mLayerExtent.contains( thePoint ) )
1925
// Outside the raster
1926
for ( int i = 1; i <= GDALGetRasterCount( mGdalDataset ); i++ )
1928
theResults[ generateBandName( i )] = tr( "out of extent" );
1933
double x = thePoint.x();
1934
double y = thePoint.y();
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;
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 );
1944
QgsDebugMsg( "row = " + QString::number( row ) + " col = " + QString::number( col ) );
1946
for ( int i = 1; i <= GDALGetRasterCount( mGdalDataset ); i++ )
1948
GDALRasterBandH gdalBand = GDALGetRasterBand( mGdalDataset, i );
1949
GDALDataType type = GDALGetRasterDataType( gdalBand );
1950
int size = GDALGetDataTypeSize( type ) / 8;
1951
void *data = CPLMalloc( size );
1953
CPLErr err = GDALRasterIO( gdalBand, GF_Read, col, row, 1, 1,
1954
data, 1, 1, type, 0, 0 );
1956
if ( err != CPLE_None )
1958
QgsLogger::warning( "RasterIO error: " + QString::fromUtf8( CPLGetLastErrorMsg() ) );
1961
double value = readValue( data, type, 0 );
1963
QgsLogger::debug( "value", value, 1, __FILE__, __FUNCTION__, __LINE__ );
1967
if ( mValidNoDataValue && ( fabs( value - mNoDataValue ) <= TINY_VALUE || value != value ) )
1969
v = tr( "null (no data)" );
1976
theResults[ generateBandName( i )] = v;
1983
} // bool QgsRasterLayer::identify
1986
* @note The arbitraryness of the returned document is enforced by WMS standards up to at least v1.3.0
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
1991
QString QgsRasterLayer::identifyAsText( const QgsPoint& thePoint )
1993
if ( mProviderKey != "wms" )
1995
// Currently no meaning for anything other than OGC WMS layers
1999
return ( mDataProvider->identifyAsText( thePoint ) );
2003
* @note Note implemented yet
2004
* @return Always returns false
2006
bool QgsRasterLayer::isEditable() const
2011
QString QgsRasterLayer::lastError()
2016
QString QgsRasterLayer::lastErrorTitle()
2018
return mErrorCaption;
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
2025
QPixmap QgsRasterLayer::legendAsPixmap()
2027
return legendAsPixmap( false );
2031
* @param theWithNameFlag - boolena flag whether to overlay the legend name in the text
2032
* @return a pixmap representing a legend image
2034
QPixmap QgsRasterLayer::legendAsPixmap( bool theWithNameFlag )
2036
QgsDebugMsg( "called (" + drawingStyleAsString() + ")" );
2038
QPixmap myLegendQPixmap; //will be initialised once we know what drawing style is active
2039
QPainter myQPainter;
2042
if ( !mProviderKey.isEmpty() )
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 );
2060
// Legacy GDAL (non-provider)
2063
// Get the adjusted matrix stats
2065
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, 1 );
2066
QString myColorerpretation = GDALGetColorInterpretationName( GDALGetRasterColorInterpretation( myGdalBand ) );
2071
// Create the legend pixmap - note it is generated on the preadjusted stats
2073
if ( mDrawingStyle == MultiBandSingleGandGray || mDrawingStyle == PalettedSingleBandGray || mDrawingStyle == SingleBandGray )
2076
myLegendQPixmap = QPixmap( 100, 1 );
2077
myQPainter.begin( &myLegendQPixmap );
2079
for ( double my = 0; my < 255; my += 2.55 )
2081
if ( !mInvertColor ) //histogram is not inverted
2083
//draw legend as grayscale
2084
int myGray = static_cast < int >( my );
2085
myQPainter.setPen( QPen( QColor( myGray, myGray, myGray ), 0 ) );
2087
else //histogram is inverted
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 );
2095
} //end of gray check
2096
else if ( mDrawingStyle == MultiBandSingleBandPseudoColor ||
2097
mDrawingStyle == PalettedSingleBandPseudoColor || mDrawingStyle == SingleBandPseudoColor )
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;
2110
// Create the legend pixmap - note it is generated on the preadjusted stats
2112
myLegendQPixmap = QPixmap( 100, 1 );
2113
myQPainter.begin( &myLegendQPixmap );
2115
for ( double my = 0; my < myRangeSize; my += myRangeSize / 100.0 )
2117
//draw pseudocolor legend
2118
if ( !mInvertColor )
2120
//check if we are in the first class break
2121
if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) )
2125
int myGreen = static_cast < int >((( 255 / myRangeSize ) * ( my - myClassBreakMin1 ) ) * 3 );
2126
// testing this stuff still ...
2127
if ( mColorShadingAlgorithm == FreakOutShader )
2129
myRed = 255 - myGreen;
2131
myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
2133
//check if we are in the second class break
2134
else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) )
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 ) );
2139
// testing this stuff still ...
2140
if ( mColorShadingAlgorithm == FreakOutShader )
2144
myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
2146
//otherwise we must be in the third classbreak
2151
int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin3 ) / 1 ) * 3 ) ) );
2152
// testing this stuff still ...
2153
if ( mColorShadingAlgorithm == FreakOutShader )
2156
myGreen = 255 - myGreen;
2158
myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
2160
} //end of invert histogram == false check
2161
else //invert histogram toggle is off
2163
//check if we are in the first class break
2164
if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) )
2168
int myGreen = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin1 ) / 1 ) * 3 ) );
2169
// testing this stuff still ...
2170
if ( mColorShadingAlgorithm == FreakOutShader )
2172
myRed = 255 - myGreen;
2174
myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
2176
//check if we are in the second class break
2177
else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) )
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 );
2182
// testing this stuff still ...
2183
if ( mColorShadingAlgorithm == FreakOutShader )
2187
myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
2189
//otherwise we must be in the third classbreak
2194
int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * ( my - myClassBreakMin3 ) ) * 3 ) );
2195
// testing this stuff still ...
2196
if ( mColorShadingAlgorithm == FreakOutShader )
2198
myRed = 255 - myGreen;
2200
myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
2203
} //end of invert histogram check
2204
myQPainter.drawPoint( myPos++, 0 );
2207
} //end of pseudocolor check
2208
else if ( mDrawingStyle == PalettedMultiBandColor || mDrawingStyle == MultiBandColor )
2211
// Create the legend pixmap showing red green and blue band mappings
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 );
2231
// see if the caller wants the name of the layer in the pixmap (used for legend bar)
2232
if ( theWithNameFlag )
2234
QFont myQFont( "arial", 10, QFont::Normal );
2235
QFontMetrics myQFontMetrics( myQFont );
2237
int myHeight = ( myQFontMetrics.height() + 10 > 35 ) ? myQFontMetrics.height() + 10 : 35;
2239
//create a matrix to
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 )
2248
//scale width by factor of 50 (=150px wide)
2249
myQWMatrix.scale( 60, myHeight );
2253
//assume 100px so scale by factor of 1.5 (=150px wide)
2254
myQWMatrix.scale( 1.8, myHeight );
2257
QPixmap myQPixmap2 = myLegendQPixmap.transformed( myQWMatrix );
2258
QPainter myQPainter( &myQPixmap2 );
2260
//load up the pyramid icons
2261
QString myThemePath = QgsApplication::activeThemePath();
2262
QPixmap myPyramidPixmap( myThemePath + "/mIconPyramid.png" );
2263
QPixmap myNoPyramidPixmap( myThemePath + "/mIconNoPyramid.png" );
2266
// Overlay a pyramid icon
2270
myQPainter.drawPixmap( 0, myHeight - myPyramidPixmap.height(), myPyramidPixmap );
2274
myQPainter.drawPixmap( 0, myHeight - myNoPyramidPixmap.height(), myNoPyramidPixmap );
2277
// Overlay the layer name
2279
if ( mDrawingStyle == MultiBandSingleGandGray || mDrawingStyle == PalettedSingleBandGray || mDrawingStyle == SingleBandGray )
2281
myQPainter.setPen( Qt::white );
2285
myQPainter.setPen( Qt::black );
2287
myQPainter.setFont( myQFont );
2288
myQPainter.drawText( 25, myHeight - 10, name() );
2292
myLegendQPixmap = myQPixmap2;
2297
return myLegendQPixmap;
2299
} //end of legendAsPixmap function
2302
* \param int theLabelCountInt Number of vertical labels to display
2303
* @return a pixmap representing a legend image
2305
QPixmap QgsRasterLayer::legendAsPixmap( int theLabelCount )
2307
QgsDebugMsg( "entered." );
2308
QFont myQFont( "arial", 10, QFont::Normal );
2309
QFontMetrics myQFontMetrics( myQFont );
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;
2319
// Get the adjusted matrix stats
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;
2326
// Create the legend pixmap - note it is generated on the preadjusted stats
2328
if ( mDrawingStyle == MultiBandSingleGandGray || mDrawingStyle == PalettedSingleBandGray || mDrawingStyle == SingleBandGray )
2331
myLegendQPixmap = QPixmap( 1, myImageHeight );
2332
const double myIncrement = static_cast<double>( myImageHeight ) / 255.0;
2333
myQPainter.begin( &myLegendQPixmap );
2335
for ( double my = 0; my < 255; my += myIncrement )
2337
if ( !mInvertColor ) //histogram is not inverted
2339
//draw legend as grayscale
2340
int myGray = static_cast < int >( my );
2341
myQPainter.setPen( QPen( QColor( myGray, myGray, myGray ), 0 ) );
2343
else //histogram is inverted
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++ );
2351
} //end of gray check
2352
else if ( mDrawingStyle == MultiBandSingleBandPseudoColor ||
2353
mDrawingStyle == PalettedSingleBandPseudoColor || mDrawingStyle == SingleBandPseudoColor )
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;
2366
// Create the legend pixmap - note it is generated on the preadjusted stats
2368
myLegendQPixmap = QPixmap( 1, myImageHeight );
2369
const double myIncrement = myImageHeight / myRangeSize;
2370
myQPainter.begin( &myLegendQPixmap );
2372
for ( double my = 0; my < 255; my += myIncrement )
2373
for ( double my = 0; my < myRangeSize; my += myIncrement )
2375
//draw pseudocolor legend
2376
if ( !mInvertColor )
2378
//check if we are in the first class break
2379
if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) )
2383
int myGreen = static_cast < int >((( 255 / myRangeSize ) * ( my - myClassBreakMin1 ) ) * 3 );
2384
// testing this stuff still ...
2385
if ( mColorShadingAlgorithm == FreakOutShader )
2387
myRed = 255 - myGreen;
2389
myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
2391
//check if we are in the second class break
2392
else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) )
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 ) );
2397
// testing this stuff still ...
2398
if ( mColorShadingAlgorithm == FreakOutShader )
2402
myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
2404
//otherwise we must be in the third classbreak
2409
int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin3 ) / 1 ) * 3 ) ) );
2410
// testing this stuff still ...
2411
if ( mColorShadingAlgorithm == FreakOutShader )
2414
myGreen = 255 - myGreen;
2416
myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
2418
} //end of invert histogram == false check
2419
else //invert histogram toggle is off
2421
//check if we are in the first class break
2422
if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) )
2426
int myGreen = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin1 ) / 1 ) * 3 ) );
2427
// testing this stuff still ...
2428
if ( mColorShadingAlgorithm == FreakOutShader )
2430
myRed = 255 - myGreen;
2432
myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
2434
//check if we are in the second class break
2435
else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) )
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 );
2440
// testing this stuff still ...
2441
if ( mColorShadingAlgorithm == FreakOutShader )
2445
myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
2447
//otherwise we must be in the third classbreak
2452
int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * ( my - myClassBreakMin3 ) ) * 3 ) );
2453
// testing this stuff still ...
2454
if ( mColorShadingAlgorithm == FreakOutShader )
2456
myRed = 255 - myGreen;
2458
myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) );
2461
} //end of invert histogram check
2462
myQPainter.drawPoint( 0, myPos++ );
2465
} //end of pseudocolor check
2466
else if ( mDrawingStyle == PalettedMultiBandColor || mDrawingStyle == MultiBandColor )
2469
// Create the legend pixmap showing red green and blue band mappings
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 );
2490
//create a matrix to
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 )
2499
myQWMatrix.scale( myColorBarWidth, 2 );
2503
myQWMatrix.scale( myColorBarWidth, 2 );
2506
QPixmap myQPixmap2 = myLegendQPixmap.transformed( myQWMatrix );
2507
QPainter myQPainter2( &myQPixmap2 );
2509
// Overlay the layer name
2511
if ( mDrawingStyle == MultiBandSingleGandGray || mDrawingStyle == PalettedSingleBandGray || mDrawingStyle == SingleBandGray )
2513
myQPainter2.setPen( Qt::white );
2517
myQPainter2.setPen( Qt::black );
2519
myQPainter2.setFont( myQFont );
2520
myQPainter2.drawText( 25, myImageHeight - 10, name() );
2524
myLegendQPixmap = myQPixmap2;
2528
return myLegendQPixmap;
2530
}//end of getDetailedLegend
2533
* @param theBand the band number for which to get the maximum pixel value
2534
* @return the maximum pixel value
2536
double QgsRasterLayer::maximumValue( unsigned int theBand )
2538
if ( 0 < theBand && theBand <= bandCount() )
2540
return mContrastEnhancementList[theBand - 1].maximumValue();
2547
* @param theBand the band name for which to get the maximum pixel value
2548
* @return the maximum pixel value
2550
double QgsRasterLayer::maximumValue( QString theBand )
2552
if ( theBand != tr( "Not Set" ) )
2554
return maximumValue( bandNumber( theBand ) );
2561
QString QgsRasterLayer::metadata()
2563
QString myMetadata ;
2564
myMetadata += "<p class=\"glossy\">" + tr( "Driver:" ) + "</p>\n";
2565
myMetadata += "<p>";
2566
if ( mProviderKey.isEmpty() )
2568
myMetadata += QString( GDALGetDescription( GDALGetDatasetDriver( mGdalDataset ) ) );
2569
myMetadata += "<br>";
2570
myMetadata += QString( GDALGetMetadataItem( GDALGetDatasetDriver( mGdalDataset ), GDAL_DMD_LONGNAME, NULL ) );
2574
myMetadata += mDataProvider->description();
2576
myMetadata += "</p>\n";
2578
if ( !mProviderKey.isEmpty() )
2580
// Insert provider-specific (e.g. WMS-specific) metadata
2581
myMetadata += mDataProvider->metadata();
2586
// my added code (MColetti)
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";
2596
char ** GDALmetadata = GDALGetMetadata( mGdalDataset, NULL );
2600
QStringList metadata = cStringList2Q_( GDALmetadata );
2601
myMetadata += makeTableCells_( metadata );
2605
QgsDebugMsg( "dataset has no metadata" );
2608
for ( int i = 1; i <= GDALGetRasterCount( mGdalDataset ); ++i )
2610
myMetadata += "<p class=\"glossy\">" + tr( "Band %1" ).arg( i ) + "</p>\n";
2611
GDALRasterBandH gdalBand = GDALGetRasterBand( mGdalDataset, i );
2612
GDALmetadata = GDALGetMetadata( gdalBand, NULL );
2616
QStringList metadata = cStringList2Q_( GDALmetadata );
2617
myMetadata += makeTableCells_( metadata );
2621
QgsDebugMsg( "band " + QString::number( i ) + "has no metadata" );
2624
char ** GDALcategories = GDALGetRasterCategoryNames( gdalBand );
2626
if ( GDALcategories )
2628
QStringList categories = cStringList2Q_( GDALcategories );
2629
myMetadata += makeTableCells_( categories );
2633
QgsDebugMsg( "band " + QString::number( i ) + " has no categories" );
2638
// end my added code
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";
2650
//just use the first band
2651
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, 1 );
2653
myMetadata += "<p class=\"glossy\">";
2654
myMetadata += tr( "No Data Value" );
2655
myMetadata += "</p>\n";
2656
myMetadata += "<p>";
2657
if ( mValidNoDataValue )
2659
myMetadata += QString::number( mNoDataValue );
2663
myMetadata += "*" + tr( "NoDataValue not set" ) + "*";
2665
myMetadata += "</p>\n";
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 ) )
2675
myMetadata += tr( "GDT_Byte - Eight bit unsigned integer" );
2678
myMetadata += tr( "GDT_UInt16 - Sixteen bit unsigned integer " );
2681
myMetadata += tr( "GDT_Int16 - Sixteen bit signed integer " );
2684
myMetadata += tr( "GDT_UInt32 - Thirty two bit unsigned integer " );
2687
myMetadata += tr( "GDT_Int32 - Thirty two bit signed integer " );
2690
myMetadata += tr( "GDT_Float32 - Thirty two bit floating point " );
2693
myMetadata += tr( "GDT_Float64 - Sixty four bit floating point " );
2696
myMetadata += tr( "GDT_CInt16 - Complex Int16 " );
2699
myMetadata += tr( "GDT_CInt32 - Complex Int32 " );
2702
myMetadata += tr( "GDT_CFloat32 - Complex Float32 " );
2705
myMetadata += tr( "GDT_CFloat64 - Complex Float64 " );
2708
myMetadata += tr( "Could not determine raster data type." );
2710
myMetadata += "</p>\n";
2712
myMetadata += "<p class=\"glossy\">";
2713
myMetadata += tr( "Pyramid overviews:" );
2714
myMetadata += "</p>\n";
2715
myMetadata += "<p>";
2717
if ( GDALGetOverviewCount( myGdalBand ) > 0 )
2720
for ( myOverviewInt = 0;
2721
myOverviewInt < GDALGetOverviewCount( myGdalBand );
2724
GDALRasterBandH myOverview;
2725
myOverview = GDALGetOverview( myGdalBand, myOverviewInt );
2726
myMetadata += "<p>X : " + QString::number( GDALGetRasterBandXSize( myOverview ) );
2727
myMetadata += ",Y " + QString::number( GDALGetRasterBandYSize( myOverview ) ) + "</p>";
2730
myMetadata += "</p>\n";
2731
} // if (mProviderKey.isEmpty())
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";
2740
// output coordinate system
2741
// TODO: this is not related to layer, to be removed? [MD]
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";
2751
if ( mProviderKey.isEmpty() )
2753
if ( GDALGetGeoTransform( mGdalDataset, mGeoTransform ) != CE_None )
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;
2761
myMetadata += "<p class=\"glossy\">";
2762
myMetadata += tr( "Origin:" );
2763
myMetadata += "</p>\n";
2764
myMetadata += "<p>";
2765
myMetadata += QString::number( mGeoTransform[0] );
2767
myMetadata += QString::number( mGeoTransform[3] );
2768
myMetadata += "</p>\n";
2770
myMetadata += "<p class=\"glossy\">";
2771
myMetadata += tr( "Pixel Size:" );
2772
myMetadata += "</p>\n";
2773
myMetadata += "<p>";
2774
myMetadata += QString::number( mGeoTransform[1] );
2776
myMetadata += QString::number( mGeoTransform[5] );
2777
myMetadata += "</p>\n";
2781
// Add the stats for each band to the output table
2783
int myBandCountInt = bandCount();
2784
for ( int myIteratorInt = 1; myIteratorInt <= myBandCountInt; ++myIteratorInt )
2786
QgsDebugMsg( "Raster properties : checking if band " + QString::number( myIteratorInt ) + " has stats? " );
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";
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";
2802
//check if full stats for this layer have already been collected
2803
if ( !hasStatistics( myIteratorInt ) ) //not collected
2805
QgsDebugMsg( ".....no" );
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";
2814
else // collected - show full detail
2816
QgsDebugMsg( ".....yes" );
2818
QgsRasterBandStats myRasterBandStats = bandStatistics( myIteratorInt );
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";
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";
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";
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";
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";
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";
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";
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";
2884
} // if (mProviderKey.isEmpty())
2886
QgsDebugMsg( myMetadata );
2891
* @param theBand the band number for which to get the minimum pixel value
2892
* @return the minimum pixel value
2894
double QgsRasterLayer::minimumValue( unsigned int theBand )
2896
if ( 0 < theBand && theBand <= bandCount() )
2898
return mContrastEnhancementList[theBand - 1].minimumValue();
2905
* @param theBand the band name for which to get the minimum pixel value
2906
* @return the minimum pixel value
2908
double QgsRasterLayer::minimumValue( QString theBand )
2910
return minimumValue( bandNumber( theBand ) );
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
2917
QPixmap QgsRasterLayer::paletteAsPixmap( int theBandNumber )
2919
//TODO: This function should take dimensions
2920
QgsDebugMsg( "entered." );
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!
2926
QgsDebugMsg( "....found paletted image" );
2927
QgsColorRampShader myShader;
2928
QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = myShader.colorRampItemList();
2930
if ( readColorTable( 1, &myColorRampItemList ) )
2932
QgsDebugMsg( "....got color ramp item list" );
2933
myShader.setColorRampItemList( myColorRampItemList );
2934
myShader.setColorRampType( QgsColorRampShader::DISCRETE );
2937
QPixmap myPalettePixmap( mySize, mySize );
2938
QPainter myQPainter( &myPalettePixmap );
2940
QImage myQImage = QImage( mySize, mySize, QImage::Format_RGB32 );
2942
myPalettePixmap.fill();
2944
double myStep = (( double )myColorRampItemList.size() - 1 ) / ( double )( mySize * mySize );
2945
double myValue = 0.0;
2946
for ( int myRow = 0; myRow < mySize; myRow++ )
2948
QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
2949
for ( int myCol = 0; myCol < mySize; myCol++ )
2951
myValue = myStep * ( double )( myCol + myRow * mySize );
2953
myShader.shade( myValue, &c1, &c2, &c3 );
2954
myLineBuffer[ myCol ] = qRgb( c1, c2, c3 );
2958
myQPainter.drawImage( 0, 0, myQImage );
2959
return myPalettePixmap;
2961
QPixmap myNullPixmap;
2962
return myNullPixmap;
2966
//invalid layer was requested
2967
QPixmap myNullPixmap;
2968
return myNullPixmap;
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)
2978
void QgsRasterLayer::populateHistogram( int theBandNo, int theBinCount, bool theIgnoreOutOfRangeFlag, bool theHistogramEstimatedFlag )
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 )
2992
myRasterBandStats.histogramVector->clear();
2993
myRasterBandStats.isHistogramEstimated = theHistogramEstimatedFlag;
2994
myRasterBandStats.isHistogramOutOfRange = theIgnoreOutOfRangeFlag;
2995
int *myHistogramArray = new int[theBinCount];
2999
* CPLErr GDALRasterBand::GetHistogram (
3003
* int * panHistogram,
3004
* int bIncludeOutOfRange,
3006
* GDALProgressFunc pfnProgress,
3007
* void * pProgressData
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
3016
for ( int myBin = 0; myBin < theBinCount; myBin++ )
3018
myRasterBandStats.histogramVector->push_back( myHistogramArray[myBin] );
3019
QgsDebugMsg( "Added " + QString::number( myHistogramArray[myBin] ) + " to histogram vector" );
3023
QgsDebugMsg( ">>>>> Histogram vector now contains " + QString::number( myRasterBandStats.histogramVector->size() ) +
3028
QString QgsRasterLayer::providerKey()
3030
if ( mProviderKey.isEmpty() )
3036
return mProviderKey;
3041
* @return the horizontal units per pixel as reported in the GDAL geotramsform[1]
3043
double QgsRasterLayer::rasterUnitsPerPixel()
3045
// We return one raster pixel per map unit pixel
3046
// One raster pixel can have several raster units...
3048
// We can only use one of the mGeoTransform[], so go with the
3051
return fabs( mGeoTransform[1] );
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
3059
bool QgsRasterLayer::readColorTable( int theBandNumber, QList<QgsColorRampShader::ColorRampItem>* theList )
3061
QgsDebugMsg( "entered." );
3062
//Invalid band number, segfault prevention
3063
if ( 0 >= theBandNumber || 0 == theList )
3065
QgsDebugMsg( "Invalid parameter" );
3069
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNumber );
3070
GDALColorTableH myGdalColorTable = GDALGetRasterColorTable( myGdalBand );
3072
if ( myGdalColorTable )
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 ) );
3081
const GDALColorEntry* myColorEntry = 0;
3082
for ( int myIterator = 0; myIterator < myEntryCount; myIterator++ )
3084
myColorEntry = GDALGetColorEntry( myGdalColorTable, myIterator );
3086
if ( !myColorEntry )
3092
//Branch on the color interpretation type
3093
if ( myColorInterpretation == GCI_GrayIndex )
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 );
3101
else if ( myColorInterpretation == GCI_PaletteIndex )
3103
QgsColorRampShader::ColorRampItem myColorRampItem;
3104
myColorRampItem.label = "";
3105
myColorRampItem.value = ( double )myIterator;
3106
//Branch on palette interpretation
3107
if ( myPaletteInterpretation == GPI_RGB )
3109
myColorRampItem.color = QColor::fromRgb( myColorEntry->c1, myColorEntry->c2, myColorEntry->c3, myColorEntry->c4 );
3111
else if ( myPaletteInterpretation == GPI_CMYK )
3113
myColorRampItem.color = QColor::fromCmyk( myColorEntry->c1, myColorEntry->c2, myColorEntry->c3, myColorEntry->c4 );
3115
else if ( myPaletteInterpretation == GPI_HLS )
3117
myColorRampItem.color = QColor::fromHsv( myColorEntry->c1, myColorEntry->c3, myColorEntry->c2, myColorEntry->c4 );
3121
myColorRampItem.color = QColor::fromRgb( myColorEntry->c1, myColorEntry->c1, myColorEntry->c1, myColorEntry->c4 );
3123
theList->append( myColorRampItem );
3127
QgsDebugMsg( "Color interpretation type not supported yet" );
3135
QgsDebugMsg( "No color table found for band " + QString::number( theBandNumber ) );
3139
QgsDebugMsg( "Color table loaded sucessfully" );
3143
void QgsRasterLayer::resetNoDataValue()
3145
mNoDataValue = std::numeric_limits<int>::max();
3146
mValidNoDataValue = false;
3147
if ( mGdalDataset != NULL && GDALGetRasterCount( mGdalDataset ) > 0 )
3150
double myValue = GDALGetRasterNoDataValue(
3151
GDALGetRasterBand( mGdalDataset, 1 ), &myRequestValid );
3153
if ( 0 != myRequestValid )
3155
setNoDataValue( myValue );
3159
setNoDataValue( -9999.0 );
3160
mValidNoDataValue = false;
3166
void QgsRasterLayer::setBlueBandName( QString const & theBandName )
3168
mBlueBandName = validateBandName( theBandName );
3171
/** Copied from QgsVectorLayer::setDataProvider
3172
* TODO: Make it work in the raster environment
3174
void QgsRasterLayer::setDataProvider( QString const & provider,
3175
QStringList const & layers,
3176
QStringList const & styles,
3177
QString const & format,
3178
QString const & crs )
3180
// XXX should I check for and possibly delete any pre-existing providers?
3181
// XXX How often will that scenario occur?
3183
mProviderKey = provider; // XXX is this necessary? Usually already set
3184
// XXX when execution gets here.
3187
QgsProviderRegistry * pReg = QgsProviderRegistry::instance();
3188
QString ogrlib = pReg->library( provider );
3190
//QString ogrlib = libDir + "/libpostgresprovider.so";
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 );
3199
QgsLogger::warning( "Error in dlopen: " );
3203
QgsDebugMsg( "dlopen suceeded" );
3209
// load the data provider
3210
mLib = new QLibrary( ogrlib );
3211
QgsDebugMsg( "Library name is " + mLib->fileName() );
3212
bool loaded = mLib->load();
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" ) );
3220
mValid = false; // assume the layer is invalid until we
3221
// determine otherwise
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())));
3230
// Copied from qgsproviderregistry in preference to the above.
3231
mDataProvider = ( QgsRasterDataProvider* )( *classFactory )( &mDataSource );
3233
if ( mDataProvider )
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() )
3242
mDataProvider->addLayers( layers, styles );
3243
mDataProvider->setImageEncoding( format );
3244
mDataProvider->setImageCrs( crs );
3247
QgsRectangle mbr = mDataProvider->extent();
3250
QString s = mbr.toString();
3251
QgsDebugMsg( "Extent of layer: " + s );
3253
mLayerExtent.setXMaximum( mbr.xMaximum() );
3254
mLayerExtent.setXMinimum( mbr.xMinimum() );
3255
mLayerExtent.setYMaximum( mbr.yMaximum() );
3256
mLayerExtent.setYMinimum( mbr.yMinimum() );
3258
// upper case the first letter of the layer name
3259
QgsDebugMsg( "mLayerName: " + name() );
3261
// set up the raster drawing style
3262
mDrawingStyle = MultiBandColor; //sensible default
3265
*mCRS = QgsCoordinateReferenceSystem();
3266
mCRS->createFromOgcWmsCrs( crs );
3271
QgsLogger::warning( "QgsRasterLayer::setDataProvider: Unable to instantiate the data provider plugin" );
3279
QgsLogger::warning( "QgsRasterLayer::setDataProvider: Failed to load ../providers/libproviders.so" );
3282
QgsDebugMsg( "exiting." );
3284
} // QgsRasterLayer::setDataProvider
3286
void QgsRasterLayer::setColorShadingAlgorithm( ColorShadingAlgorithm theShadingAlgorithm )
3288
QgsDebugMsg( "called with [" + QString::number( theShadingAlgorithm ) + "]" );
3289
if ( mColorShadingAlgorithm != theShadingAlgorithm )
3291
if ( 0 == mRasterShader )
3293
mRasterShader = new QgsRasterShader();
3296
switch ( theShadingAlgorithm )
3298
case PseudoColorShader:
3299
mRasterShader->setRasterShaderFunction( new QgsPseudoColorShader() );
3301
case FreakOutShader:
3302
mRasterShader->setRasterShaderFunction( new QgsFreakOutShader() );
3304
case ColorRampShader:
3305
mRasterShader->setRasterShaderFunction( new QgsColorRampShader() );
3307
case UserDefinedShader:
3311
mRasterShader->setRasterShaderFunction( new QgsRasterShaderFunction() );
3315
//Set the class variable after the call to setRasterShader(), so memory recovery can happen
3316
mColorShadingAlgorithm = theShadingAlgorithm;
3318
QgsDebugMsg( "mColorShadingAlgorithm = " + QString::number( theShadingAlgorithm ) );
3321
void QgsRasterLayer::setColorShadingAlgorithm( QString theShaderAlgorithm )
3323
QgsDebugMsg( "called with [" + theShaderAlgorithm + "]" );
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 );
3334
setColorShadingAlgorithm( UndefinedShader );
3337
void QgsRasterLayer::setContrastEnhancementAlgorithm( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm, bool theGenerateLookupTableFlag )
3339
QList<QgsContrastEnhancement>::iterator myIterator = mContrastEnhancementList.begin();
3340
while ( myIterator != mContrastEnhancementList.end() )
3342
( *myIterator ).setContrastEnhancementAlgorithm( theAlgorithm, theGenerateLookupTableFlag );
3345
mContrastEnhancementAlgorithm = theAlgorithm;
3348
void QgsRasterLayer::setContrastEnhancementAlgorithm( QString theAlgorithm, bool theGenerateLookupTableFlag )
3350
QgsDebugMsg( "called with [" + theAlgorithm + "] and flag=" + QString::number(( int )theGenerateLookupTableFlag ) );
3352
if ( theAlgorithm == "NoEnhancement" )
3354
setContrastEnhancementAlgorithm( QgsContrastEnhancement::NoEnhancement, theGenerateLookupTableFlag );
3356
else if ( theAlgorithm == "StretchToMinimumMaximum" )
3358
setContrastEnhancementAlgorithm( QgsContrastEnhancement::StretchToMinimumMaximum, theGenerateLookupTableFlag );
3360
else if ( theAlgorithm == "StretchAndClipToMinimumMaximum" )
3362
setContrastEnhancementAlgorithm( QgsContrastEnhancement::StretchAndClipToMinimumMaximum, theGenerateLookupTableFlag );
3364
else if ( theAlgorithm == "ClipToMinimumMaximum" )
3366
setContrastEnhancementAlgorithm( QgsContrastEnhancement::ClipToMinimumMaximum, theGenerateLookupTableFlag );
3368
else if ( theAlgorithm == "UserDefined" )
3370
setContrastEnhancementAlgorithm( QgsContrastEnhancement::UserDefinedEnhancement, theGenerateLookupTableFlag );
3374
setContrastEnhancementAlgorithm( QgsContrastEnhancement::NoEnhancement, theGenerateLookupTableFlag );
3378
void QgsRasterLayer::setContrastEnhancementFunction( QgsContrastEnhancementFunction* theFunction )
3382
QList<QgsContrastEnhancement>::iterator myIterator = mContrastEnhancementList.begin();
3383
while ( myIterator != mContrastEnhancementList.end() )
3385
( *myIterator ).setContrastEnhancementFunction( theFunction );
3393
* Implemented mainly for serialisation / deserialisation of settings to xml.
3394
* \note May be deprecated in the future! Use setDrawingStyle( DrawingStyle ) instead.
3396
void QgsRasterLayer::setDrawingStyle( QString const & theDrawingStyleQString )
3398
if ( theDrawingStyleQString == "SingleBandGray" )//no need to tr() this its not shown in ui
3400
mDrawingStyle = SingleBandGray;
3402
else if ( theDrawingStyleQString == "SingleBandPseudoColor" )//no need to tr() this its not shown in ui
3404
mDrawingStyle = SingleBandPseudoColor;
3406
else if ( theDrawingStyleQString == "PalettedColor" )//no need to tr() this its not shown in ui
3408
mDrawingStyle = PalettedColor;
3410
else if ( theDrawingStyleQString == "PalettedSingleBandGray" )//no need to tr() this its not shown in ui
3412
mDrawingStyle = PalettedSingleBandGray;
3414
else if ( theDrawingStyleQString == "PalettedSingleBandPseudoColor" )//no need to tr() this its not shown in ui
3416
mDrawingStyle = PalettedSingleBandPseudoColor;
3418
else if ( theDrawingStyleQString == "PalettedMultiBandColor" )//no need to tr() this its not shown in ui
3420
mDrawingStyle = PalettedMultiBandColor;
3422
else if ( theDrawingStyleQString == "MultiBandSingleGandGray" )//no need to tr() this its not shown in ui
3424
mDrawingStyle = MultiBandSingleGandGray;
3426
else if ( theDrawingStyleQString == "MultiBandSingleBandPseudoColor" )//no need to tr() this its not shown in ui
3428
mDrawingStyle = MultiBandSingleBandPseudoColor;
3430
else if ( theDrawingStyleQString == "MultiBandColor" )//no need to tr() this its not shown in ui
3432
mDrawingStyle = MultiBandColor;
3436
mDrawingStyle = UndefinedDrawingStyle;
3440
void QgsRasterLayer::setGrayBandName( QString const & theBandName )
3442
mGrayBandName = validateBandName( theBandName );
3445
void QgsRasterLayer::setGreenBandName( QString const & theBandName )
3447
mGreenBandName = validateBandName( theBandName );
3450
void QgsRasterLayer::setLayerOrder( QStringList const & layers )
3452
QgsDebugMsg( "entered." );
3454
if ( mDataProvider )
3456
QgsDebugMsg( "About to mDataProvider->setLayerOrder(layers)." );
3457
mDataProvider->setLayerOrder( layers );
3462
void QgsRasterLayer::setMaximumValue( unsigned int theBand, double theValue, bool theGenerateLookupTableFlag )
3464
if ( 0 < theBand && theBand <= bandCount() )
3466
mContrastEnhancementList[theBand - 1].setMaximumValue( theValue, theGenerateLookupTableFlag );
3470
void QgsRasterLayer::setMaximumValue( QString theBand, double theValue, bool theGenerateLookupTableFlag )
3472
if ( theBand != tr( "Not Set" ) )
3474
setMaximumValue( bandNumber( theBand ), theValue, theGenerateLookupTableFlag );
3478
void QgsRasterLayer::setMinimumValue( unsigned int theBand, double theValue, bool theGenerateLookupTableFlag )
3480
if ( 0 < theBand && theBand <= bandCount() )
3482
mContrastEnhancementList[theBand - 1].setMinimumValue( theValue, theGenerateLookupTableFlag );
3486
void QgsRasterLayer::setMinimumValue( QString theBand, double theValue, bool theGenerateLookupTableFlag )
3488
if ( theBand != tr( "Not Set" ) )
3490
setMinimumValue( bandNumber( theBand ), theValue, theGenerateLookupTableFlag );
3495
void QgsRasterLayer::setNoDataValue( double theNoDataValue )
3497
if ( theNoDataValue != mNoDataValue )
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() )
3505
( *myIterator ).statsGathered = false;
3511
void QgsRasterLayer::setRasterShaderFunction( QgsRasterShaderFunction* theFunction )
3513
//Free old shader if it is not a userdefined shader
3514
if ( mColorShadingAlgorithm != QgsRasterLayer::UserDefinedShader && 0 != mRasterShader->rasterShaderFunction() )
3516
delete( mRasterShader->rasterShaderFunction() );
3521
mRasterShader->setRasterShaderFunction( theFunction );
3522
mColorShadingAlgorithm = QgsRasterLayer::UserDefinedShader;
3526
//If NULL as passed in, set a default shader function to prevent segfaults
3527
mRasterShader->setRasterShaderFunction( new QgsRasterShaderFunction() );
3528
mColorShadingAlgorithm = QgsRasterLayer::UndefinedShader;
3532
void QgsRasterLayer::setRedBandName( QString const & theBandName )
3534
QgsDebugMsg( "setRedBandName : " + theBandName );
3535
mRedBandName = validateBandName( theBandName );
3538
void QgsRasterLayer::setSubLayerVisibility( QString const & name, bool vis )
3541
if ( mDataProvider )
3543
QgsDebugMsg( "About to mDataProvider->setSubLayerVisibility(name, vis)." );
3544
mDataProvider->setSubLayerVisibility( name, vis );
3549
void QgsRasterLayer::setTransparentBandName( QString const & theBandName )
3551
mTransparencyBandName = validateBandName( theBandName );
3554
void QgsRasterLayer::showProgress( int theValue )
3556
emit progressUpdate( theValue );
3560
void QgsRasterLayer::showStatusMessage( QString const & theMessage )
3562
// QgsDebugMsg(QString("entered with '%1'.").arg(theMessage));
3565
// TODO: See if we can connect signal-to-signal. This is a kludge according to the Qt doc.
3566
emit statusChanged( theMessage );
3569
QStringList QgsRasterLayer::subLayers() const
3572
if ( mDataProvider )
3574
return mDataProvider->subLayers();
3578
return QStringList(); // Empty
3583
void QgsRasterLayer::thumbnailAsPixmap( QPixmap * theQPixmap )
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; }
3588
theQPixmap->fill(); //defaults to white
3590
// Raster providers are disabled (for the moment)
3591
if ( mProviderKey.isEmpty() )
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();
3607
QPainter * myQPainter = new QPainter( theQPixmap );
3608
draw( myQPainter, myRasterViewPort );
3609
delete myRasterViewPort;
3616
void QgsRasterLayer::triggerRepaint()
3618
emit repaintRequested();
3621
void QgsRasterLayer::updateProgress( int theProgress, int theMax )
3623
//simply propogate it on!
3624
emit drawingProgress( theProgress, theMax );
3630
//////////////////////////////////////////////////////////
3632
// Protected methods
3634
/////////////////////////////////////////////////////////
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.
3640
bool QgsRasterLayer::readSymbology( const QDomNode& layer_node, QString& errorMessage )
3642
QDomNode mnl = layer_node.namedItem( "rasterproperties" );
3643
QDomNode snode = mnl.namedItem( "mDrawingStyle" );
3644
QDomElement myElement = snode.toElement();
3645
setDrawingStyle( myElement.text() );
3647
snode = mnl.namedItem( "mColorShadingAlgorithm" );
3648
myElement = snode.toElement();
3649
setColorShadingAlgorithm( myElement.text() );
3651
snode = mnl.namedItem( "mInvertColor" );
3652
myElement = snode.toElement();
3653
QVariant myVariant = ( QVariant ) myElement.attribute( "boolean" );
3654
setInvertHistogram( myVariant.toBool() );
3656
snode = mnl.namedItem( "mRedBandName" );
3657
myElement = snode.toElement();
3658
setRedBandName( myElement.text() );
3660
snode = mnl.namedItem( "mGreenBandName" );
3661
myElement = snode.toElement();
3662
setGreenBandName( myElement.text() );
3664
snode = mnl.namedItem( "mBlueBandName" );
3665
myElement = snode.toElement();
3666
setBlueBandName( myElement.text() );
3668
snode = mnl.namedItem( "mGrayBandName" );
3669
myElement = snode.toElement();
3670
QgsDebugMsg( QString( " Setting gray band to : " ) + myElement.text() );
3671
setGrayBandName( myElement.text() );
3673
snode = mnl.namedItem( "mStandardDeviations" );
3674
myElement = snode.toElement();
3675
setStandardDeviations( myElement.text().toDouble() );
3677
snode = mnl.namedItem( "mUserDefinedRGBMinimumMaximum" );
3678
myElement = snode.toElement();
3679
myVariant = ( QVariant ) myElement.attribute( "boolean" );
3680
setUserDefinedRGBMinimumMaximum( myVariant.toBool() );
3682
snode = mnl.namedItem( "mRGBMinimumMaximumEstimated" );
3683
myElement = snode.toElement();
3684
myVariant = ( QVariant ) myElement.attribute( "boolean" );
3685
setRGBMinimumMaximumEstimated( myVariant.toBool() );
3687
snode = mnl.namedItem( "mUserDefinedGrayMinimumMaximum" );
3688
myElement = snode.toElement();
3689
myVariant = ( QVariant ) myElement.attribute( "boolean" );
3690
setUserDefinedGrayMinimumMaximum( myVariant.toBool() );
3692
snode = mnl.namedItem( "mGrayMinimumMaximumEstimated" );
3693
myElement = snode.toElement();
3694
myVariant = ( QVariant ) myElement.attribute( "boolean" );
3695
setGrayMinimumMaximumEstimated( myVariant.toBool() );
3697
snode = mnl.namedItem( "mContrastEnhancementAlgorithm" );
3698
myElement = snode.toElement();
3699
setContrastEnhancementAlgorithm( myElement.text(), false );
3701
QDomNode contrastEnhancementMinMaxValues = mnl.namedItem( "contrastEnhancementMinMaxValues" );
3702
QDomNodeList minMaxValueList = contrastEnhancementMinMaxValues.toElement().elementsByTagName( "minMaxEntry" );
3703
for ( int i = 0; i < minMaxValueList.size(); ++i )
3705
QDomNode minMaxEntry = minMaxValueList.at( i ).toElement();
3706
if ( minMaxEntry.isNull() )
3710
QDomNode minEntry = minMaxEntry.namedItem( "min" );
3711
QDomNode maxEntry = minMaxEntry.namedItem( "max" );
3713
setMinimumValue( i + 1, minEntry.toElement().text().toDouble(), false );
3714
setMaximumValue( i + 1, maxEntry.toElement().text().toDouble(), false );
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() );
3725
snode = mnl.namedItem( "mNoDataValue" );
3726
myElement = snode.toElement();
3727
setNoDataValue( myElement.text().toDouble() );
3728
if ( myElement.attribute( "mValidNoDataValue", "false" ).compare( "true" ) )
3730
// If flag element is not true, set to false.
3731
mValidNoDataValue = false;
3734
QDomNode singleValuePixelListNode = mnl.namedItem( "singleValuePixelList" );
3735
if ( !singleValuePixelListNode.isNull() )
3737
QList<QgsRasterTransparency::TransparentSingleValuePixel> newSingleValuePixelList;
3740
QDomNodeList singleValuePixelList = singleValuePixelListNode.toElement().elementsByTagName( "pixelListEntry" );
3741
for ( int i = 0; i < singleValuePixelList.size(); ++i )
3743
QgsRasterTransparency::TransparentSingleValuePixel myNewItem;
3744
QDomElement singleValuePixelListElement = singleValuePixelList.at( i ).toElement();
3745
if ( singleValuePixelListElement.isNull() )
3750
myNewItem.pixelValue = singleValuePixelListElement.attribute( "pixelValue" ).toDouble();
3751
myNewItem.percentTransparent = singleValuePixelListElement.attribute( "percentTransparent" ).toDouble();
3753
newSingleValuePixelList.push_back( myNewItem );
3755
mRasterTransparency.setTransparentSingleValuePixelList( newSingleValuePixelList );
3758
QDomNode threeValuePixelListNode = mnl.namedItem( "threeValuePixelList" );
3759
if ( !threeValuePixelListNode.isNull() )
3761
QList<QgsRasterTransparency::TransparentThreeValuePixel> newThreeValuePixelList;
3764
QDomNodeList threeValuePixelList = threeValuePixelListNode.toElement().elementsByTagName( "pixelListEntry" );
3765
for ( int i = 0; i < threeValuePixelList.size(); ++i )
3767
QgsRasterTransparency::TransparentThreeValuePixel myNewItem;
3768
QDomElement threeValuePixelListElement = threeValuePixelList.at( i ).toElement();
3769
if ( threeValuePixelListElement.isNull() )
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();
3779
newThreeValuePixelList.push_back( myNewItem );
3781
mRasterTransparency.setTransparentThreeValuePixelList( newThreeValuePixelList );
3787
//restore custom color ramp settings
3788
QDomNode customColorRampNode = mnl.namedItem( "customColorRamp" );
3789
if ( !customColorRampNode.isNull() )
3791
QgsColorRampShader* myColorRampShader = ( QgsColorRampShader* ) mRasterShader->rasterShaderFunction();
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() )
3799
myRampType = colorRampTypeNode.toElement().text();
3803
myRampType = customColorRampTypeNode.toElement().text();
3805
myColorRampShader->setColorRampType( myRampType );
3809
QList<QgsColorRampShader::ColorRampItem> myColorRampItemList;
3810
QDomNodeList colorRampEntryList = customColorRampNode.toElement().elementsByTagName( "colorRampEntry" );
3811
for ( int i = 0; i < colorRampEntryList.size(); ++i )
3813
QgsColorRampShader::ColorRampItem myNewItem;
3814
QDomElement colorRampEntryElement = colorRampEntryList.at( i ).toElement();
3815
if ( colorRampEntryElement.isNull() )
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();
3824
myColorRampItemList.push_back( myNewItem );
3826
myColorRampShader->setColorRampItemList( myColorRampItemList );
3833
Raster layer project file XML of form:
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>
3839
<transparencyLevelInt>255</transparencyLevelInt>
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>
3851
@note Called by QgsMapLayer::readXML().
3853
bool QgsRasterLayer::readXml( QDomNode & layer_node )
3855
//! @NOTE Make sure to read the file first so stats etc are initialised properly!
3857
//process provider key
3858
QDomNode pkeyNode = layer_node.namedItem( "provider" );
3860
if ( pkeyNode.isNull() )
3866
QDomElement pkeyElt = pkeyNode.toElement();
3867
mProviderKey = pkeyElt.text();
3870
// Open the raster source based on provider and datasource
3872
if ( !mProviderKey.isEmpty() )
3874
// Go down the raster-data-provider paradigm
3876
// Collect provider-specific information
3878
QDomNode rpNode = layer_node.namedItem( "rasterproperties" );
3880
// Collect sublayer names and styles
3883
QDomElement layerElement = rpNode.firstChildElement( "wmsSublayer" );
3884
while ( !layerElement.isNull() )
3886
// TODO: sublayer visibility - post-0.8 release timeframe
3888
// collect name for the sublayer
3889
layers += layerElement.namedItem( "name" ).toElement().text();
3891
// collect style for the sublayer
3892
styles += layerElement.namedItem( "style" ).toElement().text();
3894
layerElement = layerElement.nextSiblingElement( "wmsSublayer" );
3898
QString format = rpNode.namedItem( "wmsFormat" ).toElement().text();
3901
QString crs = QString( "EPSG:%1" ).arg( srs().epsg() );
3903
setDataProvider( mProviderKey, layers, styles, format, crs );
3907
// Go down the monolithic-gdal-provider paradigm
3909
if ( !readFile( source() ) ) // Data source name set in
3910
// QgsMapLayer::readXML()
3912
QgsLogger::warning( QString( __FILE__ ) + ":" + QString( __LINE__ ) +
3913
" unable to read from raster file " + source() );
3920
return readSymbology( layer_node, theError );
3923
} // QgsRasterLayer::readXml( QDomNode & layer_node )
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.
3932
bool QgsRasterLayer::writeSymbology( QDomNode & layer_node, QDomDocument & document, QString& errorMessage ) const
3934
// <rasterproperties>
3935
QDomElement rasterPropertiesElement = document.createElement( "rasterproperties" );
3936
layer_node.appendChild( rasterPropertiesElement );
3938
if ( !mProviderKey.isEmpty() )
3940
QStringList sl = subLayers();
3941
QStringList sls = mDataProvider->subLayerStyles();
3943
QStringList::const_iterator layerStyle = sls.begin();
3945
// <rasterproperties><wmsSublayer>
3946
for ( QStringList::const_iterator layerName = sl.begin();
3947
layerName != sl.end();
3951
QgsDebugMsg( QString( "<rasterproperties><wmsSublayer> %1" ).arg( layerName->toLocal8Bit().data() ) );
3953
QDomElement sublayerElement = document.createElement( "wmsSublayer" );
3955
// TODO: sublayer visibility - post-0.8 release timeframe
3957
// <rasterproperties><wmsSublayer><name>
3958
QDomElement sublayerNameElement = document.createElement( "name" );
3959
QDomText sublayerNameText = document.createTextNode( *layerName );
3960
sublayerNameElement.appendChild( sublayerNameText );
3961
sublayerElement.appendChild( sublayerNameElement );
3963
// <rasterproperties><wmsSublayer><style>
3964
QDomElement sublayerStyleElement = document.createElement( "style" );
3965
QDomText sublayerStyleText = document.createTextNode( *layerStyle );
3966
sublayerStyleElement.appendChild( sublayerStyleText );
3967
sublayerElement.appendChild( sublayerStyleElement );
3969
rasterPropertiesElement.appendChild( sublayerElement );
3971
// This assumes there are exactly the same number of "layerName"s as there are "layerStyle"s
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 );
3985
QDomElement drawStyleElement = document.createElement( "mDrawingStyle" );
3986
QDomText drawStyleText = document.createTextNode( drawingStyleAsString() );
3988
drawStyleElement.appendChild( drawStyleText );
3990
rasterPropertiesElement.appendChild( drawStyleElement );
3992
// <colorShadingAlgorithm>
3993
QDomElement colorShadingAlgorithmElement = document.createElement( "mColorShadingAlgorithm" );
3994
QDomText colorShadingAlgorithmText = document.createTextNode( colorShadingAlgorithmAsString() );
3996
colorShadingAlgorithmElement.appendChild( colorShadingAlgorithmText );
3998
rasterPropertiesElement.appendChild( colorShadingAlgorithmElement );
4001
QDomElement mInvertColorElement = document.createElement( "mInvertColor" );
4003
if ( invertHistogram() )
4005
mInvertColorElement.setAttribute( "boolean", "true" );
4009
mInvertColorElement.setAttribute( "boolean", "false" );
4012
rasterPropertiesElement.appendChild( mInvertColorElement );
4016
QDomElement mRedBandNameElement = document.createElement( "mRedBandName" );
4017
QString writtenRedBandName = redBandName();
4018
if ( writtenRedBandName == TRSTRING_NOT_SET )
4020
// Write english "not set" only.
4021
writtenRedBandName = QSTRING_NOT_SET;
4023
QDomText mRedBandNameText = document.createTextNode( writtenRedBandName );
4025
mRedBandNameElement.appendChild( mRedBandNameText );
4027
rasterPropertiesElement.appendChild( mRedBandNameElement );
4031
QDomElement mGreenBandNameElement = document.createElement( "mGreenBandName" );
4032
QString writtenGreenBandName = greenBandName();
4033
if ( writtenGreenBandName == TRSTRING_NOT_SET )
4035
// Write english "not set" only.
4036
writtenGreenBandName = QSTRING_NOT_SET;
4038
QDomText mGreenBandNameText = document.createTextNode( writtenGreenBandName );
4040
mGreenBandNameElement.appendChild( mGreenBandNameText );
4042
rasterPropertiesElement.appendChild( mGreenBandNameElement );
4046
QDomElement mBlueBandNameElement = document.createElement( "mBlueBandName" );
4047
QString writtenBlueBandName = blueBandName();
4048
if ( writtenBlueBandName == TRSTRING_NOT_SET )
4050
// Write english "not set" only.
4051
writtenBlueBandName = QSTRING_NOT_SET;
4053
QDomText mBlueBandNameText = document.createTextNode( writtenBlueBandName );
4055
mBlueBandNameElement.appendChild( mBlueBandNameText );
4057
rasterPropertiesElement.appendChild( mBlueBandNameElement );
4061
QDomElement mGrayBandNameElement = document.createElement( "mGrayBandName" );
4062
QString writtenGrayBandName = grayBandName();
4063
if ( writtenGrayBandName == TRSTRING_NOT_SET )
4065
// Write english "not set" only.
4066
writtenGrayBandName = QSTRING_NOT_SET;
4068
QDomText mGrayBandNameText = document.createTextNode( writtenGrayBandName );
4070
mGrayBandNameElement.appendChild( mGrayBandNameText );
4071
rasterPropertiesElement.appendChild( mGrayBandNameElement );
4073
// <mStandardDeviations>
4074
QDomElement mStandardDeviationsElement = document.createElement( "mStandardDeviations" );
4075
QDomText mStandardDeviationsText = document.createTextNode( QString::number( standardDeviations() ) );
4077
mStandardDeviationsElement.appendChild( mStandardDeviationsText );
4079
rasterPropertiesElement.appendChild( mStandardDeviationsElement );
4081
// <mUserDefinedRGBMinimumMaximum>
4082
QDomElement userDefinedRGBMinMaxFlag = document.createElement( "mUserDefinedRGBMinimumMaximum" );
4084
if ( hasUserDefinedRGBMinimumMaximum() )
4086
userDefinedRGBMinMaxFlag.setAttribute( "boolean", "true" );
4090
userDefinedRGBMinMaxFlag.setAttribute( "boolean", "false" );
4093
rasterPropertiesElement.appendChild( userDefinedRGBMinMaxFlag );
4095
// <mRGBMinimumMaximumEstimated>
4096
QDomElement RGBMinimumMaximumEstimated = document.createElement( "mRGBMinimumMaximumEstimated" );
4098
if ( isRGBMinimumMaximumEstimated() )
4100
RGBMinimumMaximumEstimated.setAttribute( "boolean", "true" );
4104
RGBMinimumMaximumEstimated.setAttribute( "boolean", "false" );
4107
rasterPropertiesElement.appendChild( RGBMinimumMaximumEstimated );
4109
// <mUserDefinedGrayMinimumMaximum>
4110
QDomElement userDefinedGrayMinMaxFlag = document.createElement( "mUserDefinedGrayMinimumMaximum" );
4112
if ( hasUserDefinedGrayMinimumMaximum() )
4114
userDefinedGrayMinMaxFlag.setAttribute( "boolean", "true" );
4118
userDefinedGrayMinMaxFlag.setAttribute( "boolean", "false" );
4121
rasterPropertiesElement.appendChild( userDefinedGrayMinMaxFlag );
4123
// <mGrayMinimumMaximumEstimated>
4124
QDomElement GrayMinimumMaximumEstimated = document.createElement( "mGrayMinimumMaximumEstimated" );
4126
if ( isGrayMinimumMaximumEstimated() )
4128
GrayMinimumMaximumEstimated.setAttribute( "boolean", "true" );
4132
GrayMinimumMaximumEstimated.setAttribute( "boolean", "false" );
4135
rasterPropertiesElement.appendChild( GrayMinimumMaximumEstimated );
4137
// <contrastEnhancementAlgorithm>
4138
QDomElement contrastEnhancementAlgorithmElement = document.createElement( "mContrastEnhancementAlgorithm" );
4139
QDomText contrastEnhancementAlgorithmText = document.createTextNode( contrastEnhancementAlgorithmAsString() );
4141
contrastEnhancementAlgorithmElement.appendChild( contrastEnhancementAlgorithmText );
4143
rasterPropertiesElement.appendChild( contrastEnhancementAlgorithmElement );
4146
QList<QgsContrastEnhancement>::const_iterator it;
4147
QDomElement contrastEnhancementMinMaxValuesElement = document.createElement( "contrastEnhancementMinMaxValues" );
4148
for ( it = mContrastEnhancementList.constBegin(); it != mContrastEnhancementList.constEnd(); ++it )
4150
QDomElement minMaxEntry = document.createElement( "minMaxEntry" );
4151
QDomElement minEntry = document.createElement( "min" );
4152
QDomElement maxEntry = document.createElement( "max" );
4154
QDomText minEntryText = document.createTextNode( QString::number( it->minimumValue() ) );
4155
minEntry.appendChild( minEntryText );
4157
QDomText maxEntryText = document.createTextNode( QString::number( it->maximumValue() ) );
4158
maxEntry.appendChild( maxEntryText );
4160
minMaxEntry.appendChild( minEntry );
4161
minMaxEntry.appendChild( maxEntry );
4163
contrastEnhancementMinMaxValuesElement.appendChild( minMaxEntry );
4166
rasterPropertiesElement.appendChild( contrastEnhancementMinMaxValuesElement );
4172
QDomElement mNoDataValueElement = document.createElement( "mNoDataValue" );
4173
QDomText mNoDataValueText = document.createTextNode( QString::number( mNoDataValue, 'f' ) );
4174
if ( mValidNoDataValue )
4176
mNoDataValueElement.setAttribute( "mValidNoDataValue", "true" );
4180
mNoDataValueElement.setAttribute( "mValidNoDataValue", "false" );
4183
mNoDataValueElement.appendChild( mNoDataValueText );
4185
rasterPropertiesElement.appendChild( mNoDataValueElement );
4188
if ( mRasterTransparency.transparentSingleValuePixelList().count() > 0 )
4190
QDomElement singleValuePixelListElement = document.createElement( "singleValuePixelList" );
4193
QList<QgsRasterTransparency::TransparentSingleValuePixel> myPixelList = mRasterTransparency.transparentSingleValuePixelList();
4194
QList<QgsRasterTransparency::TransparentSingleValuePixel>::iterator it;
4195
for ( it = myPixelList.begin(); it != myPixelList.end(); ++it )
4197
QDomElement pixelListElement = document.createElement( "pixelListEntry" );
4198
pixelListElement.setAttribute( "pixelValue", QString::number( it->pixelValue, 'f' ) );
4199
pixelListElement.setAttribute( "percentTransparent", QString::number( it->percentTransparent ) );
4201
singleValuePixelListElement.appendChild( pixelListElement );
4204
rasterPropertiesElement.appendChild( singleValuePixelListElement );
4207
if ( mRasterTransparency.transparentThreeValuePixelList().count() > 0 )
4209
QDomElement threeValuePixelListElement = document.createElement( "threeValuePixelList" );
4212
QList<QgsRasterTransparency::TransparentThreeValuePixel> myPixelList = mRasterTransparency.transparentThreeValuePixelList();
4213
QList<QgsRasterTransparency::TransparentThreeValuePixel>::iterator it;
4214
for ( it = myPixelList.begin(); it != myPixelList.end(); ++it )
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 ) );
4222
threeValuePixelListElement.appendChild( pixelListElement );
4225
rasterPropertiesElement.appendChild( threeValuePixelListElement );
4231
if ( QgsRasterLayer::ColorRampShader == colorShadingAlgorithm() )
4233
QDomElement customColorRampElement = document.createElement( "customColorRamp" );
4235
QDomElement customColorRampType = document.createElement( "colorRampType" );
4236
QDomText customColorRampTypeText = document.createTextNode((( QgsColorRampShader* )mRasterShader->rasterShaderFunction() )->colorRampTypeAsQString() );
4237
customColorRampType.appendChild( customColorRampTypeText );
4238
customColorRampElement.appendChild( customColorRampType );
4240
QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = (( QgsColorRampShader* )mRasterShader->rasterShaderFunction() )->colorRampItemList();
4241
QList<QgsColorRampShader::ColorRampItem>::iterator it;
4242
for ( it = myColorRampItemList.begin(); it != myColorRampItemList.end(); ++it )
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 );
4251
customColorRampElement.appendChild( colorRampEntryElement );
4254
rasterPropertiesElement.appendChild( customColorRampElement );
4258
} // bool QgsRasterLayer::writeSymbology
4262
* @note Called by QgsMapLayer::writeXML().
4264
bool QgsRasterLayer::writeXml( QDomNode & layer_node,
4265
QDomDocument & document )
4267
// first get the layer element so that we can append the type attribute
4269
QDomElement mapLayerNode = layer_node.toElement();
4271
if ( mapLayerNode.isNull() || ( "maplayer" != mapLayerNode.nodeName() ) )
4273
QgsLogger::warning( "QgsRasterLayer::writeXML() can't find <maplayer>" );
4277
mapLayerNode.setAttribute( "type", "raster" );
4279
// add provider node
4281
QDomElement provider = document.createElement( "provider" );
4282
QDomText providerText = document.createTextNode( mProviderKey );
4283
provider.appendChild( providerText );
4284
layer_node.appendChild( provider );
4286
//write out the symbology
4288
return writeSymbology( layer_node, document, errorMsg );
4294
//////////////////////////////////////////////////////////
4298
/////////////////////////////////////////////////////////
4299
void QgsRasterLayer::drawMultiBandColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
4300
const QgsMapToPixel* theQgsMapToPixel )
4302
QgsDebugMsg( "entered." );
4303
int myRedBandNo = bandNumber( mRedBandName );
4304
//Invalid band number, segfault prevention
4305
if ( 0 >= myRedBandNo )
4310
int myGreenBandNo = bandNumber( mGreenBandName );
4311
//Invalid band number, segfault prevention
4312
if ( 0 >= myGreenBandNo )
4317
int myBlueBandNo = bandNumber( mBlueBandName );
4318
//Invalid band number, segfault prevention
4319
if ( 0 >= myBlueBandNo )
4323
GDALRasterBandH myGdalRedBand = GDALGetRasterBand( mGdalDataset, myRedBandNo );
4324
GDALRasterBandH myGdalGreenBand = GDALGetRasterBand( mGdalDataset, myGreenBandNo );
4325
GDALRasterBandH myGdalBlueBand = GDALGetRasterBand( mGdalDataset, myBlueBandNo );
4327
GDALDataType myRedType = GDALGetRasterDataType( myGdalRedBand );
4328
GDALDataType myGreenType = GDALGetRasterDataType( myGdalGreenBand );
4329
GDALDataType myBlueType = GDALGetRasterDataType( myGdalBlueBand );
4331
void *myGdalRedData = readData( myGdalRedBand, theRasterViewPort );
4332
void *myGdalGreenData = readData( myGdalGreenBand, theRasterViewPort );
4333
void *myGdalBlueData = readData( myGdalBlueBand, theRasterViewPort );
4335
/* Check for out of memory error */
4336
if ( myGdalRedData == NULL || myGdalGreenData == NULL || myGdalBlueData == NULL )
4338
// Safe to free NULL-pointer */
4339
VSIFree( myGdalRedData );
4340
VSIFree( myGdalGreenData );
4341
VSIFree( myGdalBlueData );
4345
QImage myQImage = QImage( theRasterViewPort->drawableAreaXDim, theRasterViewPort->drawableAreaYDim, QImage::Format_ARGB32 );
4346
QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
4348
QgsRasterBandStats myRedBandStats;
4349
QgsRasterBandStats myGreenBandStats;
4350
QgsRasterBandStats myBlueBandStats;
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.
4356
if ( QgsContrastEnhancement::NoEnhancement != contrastEnhancementAlgorithm() && !mUserDefinedRGBMinimumMaximum && mStandardDeviations > 0 )
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 ) );
4369
else if ( QgsContrastEnhancement::NoEnhancement != contrastEnhancementAlgorithm() && !mUserDefinedRGBMinimumMaximum )
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;
4376
GDALComputeRasterMinMax( myGdalRedBand, 1, GDALrange ); //Approximate
4377
setMaximumValue( myRedBandNo, GDALrange[1] );
4378
setMinimumValue( myRedBandNo, GDALrange[0] );
4380
GDALComputeRasterMinMax( myGdalGreenBand, 1, GDALrange ); //Approximate
4381
setMaximumValue( myGreenBandNo, GDALrange[1] );
4382
setMinimumValue( myGreenBandNo, GDALrange[0] );
4384
GDALComputeRasterMinMax( myGdalBlueBand, 1, GDALrange ); //Approximate
4385
setMaximumValue( myBlueBandNo, GDALrange[1] );
4386
setMinimumValue( myBlueBandNo, GDALrange[0] );
4389
//Read and display pixels
4390
double myRedValue = 0.0;
4391
double myGreenValue = 0.0;
4392
double myBlueValue = 0.0;
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 );
4402
QgsDebugMsg( "Starting main render loop" );
4403
for ( int myRow = 0; myRow < theRasterViewPort->drawableAreaYDim; ++myRow )
4405
QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
4406
for ( int myColumn = 0; myColumn < theRasterViewPort->drawableAreaXDim; ++myColumn )
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 );
4415
if ( mValidNoDataValue && (( fabs( myRedValue - mNoDataValue ) <= TINY_VALUE || myRedValue != myRedValue ) || ( fabs( myGreenValue - mNoDataValue ) <= TINY_VALUE || myGreenValue != myGreenValue ) || ( fabs( myBlueValue - mNoDataValue ) <= TINY_VALUE || myBlueValue != myBlueValue ) ) )
4417
myLineBuffer[ myColumn ] = myDefaultColor;
4421
if ( !myRedContrastEnhancement->isValueInDisplayableRange( myRedValue ) || !myGreenContrastEnhancement->isValueInDisplayableRange( myGreenValue ) || !myBlueContrastEnhancement->isValueInDisplayableRange( myBlueValue ) )
4423
myLineBuffer[ myColumn ] = myDefaultColor;
4427
myAlphaValue = mRasterTransparency.alphaValue( myRedValue, myGreenValue, myBlueValue, mTransparencyLevel );
4428
if ( 0 == myAlphaValue )
4430
myLineBuffer[ myColumn ] = myDefaultColor;
4434
myStretchedRedValue = myRedContrastEnhancement->enhanceContrast( myRedValue );
4435
myStretchedGreenValue = myGreenContrastEnhancement->enhanceContrast( myGreenValue );
4436
myStretchedBlueValue = myBlueContrastEnhancement->enhanceContrast( myBlueValue );
4440
myStretchedRedValue = 255 - myStretchedRedValue;
4441
myStretchedGreenValue = 255 - myStretchedGreenValue;
4442
myStretchedBlueValue = 255 - myStretchedBlueValue;
4445
myLineBuffer[ myColumn ] = qRgba( myStretchedRedValue, myStretchedGreenValue, myStretchedBlueValue, myAlphaValue );
4448
//free the scanline memory
4449
CPLFree( myGdalRedData );
4450
CPLFree( myGdalGreenData );
4451
CPLFree( myGdalBlueData );
4454
QPixmap *pm = dynamic_cast<QPixmap *>( theQPainter->device() );
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" );
4464
paintImageToCanvas( theQPainter, theRasterViewPort, theQgsMapToPixel, &myQImage );
4467
QgsDebugMsg( "theQPainter->drawImage." );
4470
pm->save( "/tmp/qgis-rasterlayer-drawmultibandcolor-test-b.png", "PNG" );
4475
void QgsRasterLayer::drawMultiBandSingleBandGray( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
4476
const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
4478
//delegate to drawSingleBandGray!
4479
drawSingleBandGray( theQPainter, theRasterViewPort, theQgsMapToPixel, theBandNo );
4482
void QgsRasterLayer::drawMultiBandSingleBandPseudoColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
4483
const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
4485
//delegate to drawSinglePseudocolor!
4486
drawSingleBandPseudoColor( theQPainter, theRasterViewPort, theQgsMapToPixel, theBandNo );
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.
4495
void QgsRasterLayer::drawPalettedSingleBandColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
4496
const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
4498
QgsDebugMsg( "entered." );
4499
//Invalid band number, segfault prevention
4500
if ( 0 >= theBandNo )
4505
if ( NULL == mRasterShader )
4510
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
4511
GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
4512
void *myGdalScanData = readData( myGdalBand, theRasterViewPort );
4514
/* Check for out of memory error */
4515
if ( myGdalScanData == NULL )
4520
QImage myQImage = QImage( theRasterViewPort->drawableAreaXDim, theRasterViewPort->drawableAreaYDim, QImage::Format_ARGB32 );
4521
QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
4523
double myPixelValue = 0.0;
4525
int myGreenValue = 0;
4526
int myBlueValue = 0;
4527
int myAlphaValue = 0;
4529
QgsDebugMsg( "Starting main render loop" );
4530
for ( int myRow = 0; myRow < theRasterViewPort->drawableAreaYDim; ++myRow )
4532
QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
4533
for ( int myColumn = 0; myColumn < theRasterViewPort->drawableAreaXDim; ++myColumn )
4538
myPixelValue = readValue( myGdalScanData, ( GDALDataType )myDataType,
4539
myRow * theRasterViewPort->drawableAreaXDim + myColumn );
4541
if ( mValidNoDataValue && ( fabs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) )
4543
myLineBuffer[ myColumn ] = myDefaultColor;
4547
myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel );
4548
if ( 0 == myAlphaValue )
4550
myLineBuffer[ myColumn ] = myDefaultColor;
4554
if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) )
4556
myLineBuffer[ myColumn ] = myDefaultColor;
4562
//Invert flag, flip blue and read
4563
myLineBuffer[ myColumn ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue );
4568
myLineBuffer[ myColumn ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue );
4572
CPLFree( myGdalScanData );
4574
paintImageToCanvas( theQPainter, theRasterViewPort, theQgsMapToPixel, &myQImage );
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.
4583
void QgsRasterLayer::drawPalettedSingleBandGray( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
4584
const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
4586
QgsDebugMsg( "entered." );
4587
//Invalid band number, segfault prevention
4588
if ( 0 >= theBandNo )
4593
if ( NULL == mRasterShader )
4598
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
4599
GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
4600
void *myGdalScanData = readData( myGdalBand, theRasterViewPort );
4602
/* Check for out of memory error */
4603
if ( myGdalScanData == NULL )
4608
QImage myQImage = QImage( theRasterViewPort->drawableAreaXDim, theRasterViewPort->drawableAreaYDim, QImage::Format_ARGB32 );
4609
QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
4611
double myPixelValue = 0.0;
4613
int myGreenValue = 0;
4614
int myBlueValue = 0;
4615
int myAlphaValue = 0;
4617
QgsDebugMsg( "Starting main render loop" );
4618
for ( int myRow = 0; myRow < theRasterViewPort->drawableAreaYDim; ++myRow )
4620
QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
4621
for ( int myColumn = 0; myColumn < theRasterViewPort->drawableAreaXDim; ++myColumn )
4626
myPixelValue = readValue( myGdalScanData, ( GDALDataType )myDataType,
4627
myRow * theRasterViewPort->drawableAreaXDim + myColumn );
4629
if ( mValidNoDataValue && ( fabs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) )
4631
myLineBuffer[ myColumn ] = myDefaultColor;
4635
myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel );
4636
if ( 0 == myAlphaValue )
4638
myLineBuffer[ myColumn ] = myDefaultColor;
4642
if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) )
4644
myLineBuffer[ myColumn ] = myDefaultColor;
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 );
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 );
4662
CPLFree( myGdalScanData );
4664
paintImageToCanvas( theQPainter, theRasterViewPort, theQgsMapToPixel, &myQImage );
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.
4675
void QgsRasterLayer::drawPalettedSingleBandPseudoColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
4676
const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
4678
QgsDebugMsg( "entered." );
4679
//Invalid band number, segfault prevention
4680
if ( 0 >= theBandNo )
4685
QgsRasterBandStats myRasterBandStats = bandStatistics( theBandNo );
4686
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
4687
GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
4688
void *myGdalScanData = readData( myGdalBand, theRasterViewPort );
4690
/* Check for out of memory error */
4691
if ( myGdalScanData == NULL )
4696
QImage myQImage = QImage( theRasterViewPort->drawableAreaXDim, theRasterViewPort->drawableAreaYDim, QImage::Format_ARGB32 );
4697
QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
4699
if ( NULL == mRasterShader )
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 )
4709
myMinimumValue = ( myRasterBandStats.mean - ( mStandardDeviations * myRasterBandStats.stdDev ) );
4710
myMaximumValue = ( myRasterBandStats.mean + ( mStandardDeviations * myRasterBandStats.stdDev ) );
4714
myMinimumValue = myRasterBandStats.minimumValue;
4715
myMaximumValue = myRasterBandStats.maximumValue;
4718
mRasterShader->setMinimumValue( myMinimumValue );
4719
mRasterShader->setMaximumValue( myMaximumValue );
4721
double myPixelValue = 0.0;
4723
int myGreenValue = 0;
4724
int myBlueValue = 0;
4725
int myAlphaValue = 0;
4727
QgsDebugMsg( "Starting main render loop" );
4728
for ( int myRow = 0; myRow < theRasterViewPort->drawableAreaYDim; ++myRow )
4730
QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
4731
for ( int myColumn = 0; myColumn < theRasterViewPort->drawableAreaXDim; ++myColumn )
4736
myPixelValue = readValue( myGdalScanData, ( GDALDataType )myDataType,
4737
myRow * theRasterViewPort->drawableAreaXDim + myColumn );
4739
if ( mValidNoDataValue && ( fabs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) )
4741
myLineBuffer[ myColumn ] = myDefaultColor;
4745
myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel );
4746
if ( 0 == myAlphaValue )
4748
myLineBuffer[ myColumn ] = myDefaultColor;
4752
if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) )
4754
myLineBuffer[ myColumn ] = myDefaultColor;
4760
//Invert flag, flip blue and read
4761
myLineBuffer[ myColumn ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue );
4766
myLineBuffer[ myColumn ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue );
4770
CPLFree( myGdalScanData );
4772
paintImageToCanvas( theQPainter, theRasterViewPort, theQgsMapToPixel, &myQImage );
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.
4781
void QgsRasterLayer::drawPalettedMultiBandColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort,
4782
const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
4784
QgsDebugMsg( "Not supported at this time" );
4787
void QgsRasterLayer::drawSingleBandGray( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, const QgsMapToPixel* theQgsMapToPixel, int theBandNo )
4789
QgsDebugMsg( "layer=" + QString::number( theBandNo ) );
4790
//Invalid band number, segfault prevention
4791
if ( 0 >= theBandNo )
4796
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
4797
GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
4798
void *myGdalScanData = readData( myGdalBand, theRasterViewPort );
4800
/* Check for out of memory error */
4801
if ( myGdalScanData == NULL )
4806
QImage myQImage = QImage( theRasterViewPort->drawableAreaXDim, theRasterViewPort->drawableAreaYDim, QImage::Format_ARGB32 );
4807
QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
4809
QgsRasterBandStats myGrayBandStats;
4811
if ( QgsContrastEnhancement::NoEnhancement != contrastEnhancementAlgorithm() && !mUserDefinedGrayMinimumMaximum && mStandardDeviations > 0 )
4813
mGrayMinimumMaximumEstimated = false;
4814
myGrayBandStats = bandStatistics( theBandNo );
4815
setMaximumValue( theBandNo, myGrayBandStats.mean + ( mStandardDeviations * myGrayBandStats.stdDev ) );
4816
setMinimumValue( theBandNo, myGrayBandStats.mean - ( mStandardDeviations * myGrayBandStats.stdDev ) );
4818
else if ( QgsContrastEnhancement::NoEnhancement != contrastEnhancementAlgorithm() && !mUserDefinedGrayMinimumMaximum )
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] );
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;
4834
int myAlphaValue = 0;
4835
QgsContrastEnhancement* myContrastEnhancement = contrastEnhancement( theBandNo );
4836
for ( int myRow = 0; myRow < theRasterViewPort->drawableAreaYDim; ++myRow )
4838
QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
4839
for ( int myColumn = 0; myColumn < theRasterViewPort->drawableAreaXDim; ++myColumn )
4841
myGrayValue = readValue( myGdalScanData, myDataType,
4842
myRow * theRasterViewPort->drawableAreaXDim + myColumn );
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.
4849
if ( mValidNoDataValue && ( fabs( myGrayValue - mNoDataValue ) <= TINY_VALUE || myGrayValue != myGrayValue ) )
4851
myLineBuffer[ myColumn ] = myDefaultColor;
4855
if ( !myContrastEnhancement->isValueInDisplayableRange( myGrayValue ) )
4857
myLineBuffer[ myColumn ] = myDefaultColor;
4861
myAlphaValue = mRasterTransparency.alphaValue( myGrayValue, mTransparencyLevel );
4862
if ( 0 == myAlphaValue )
4864
myLineBuffer[ myColumn ] = myDefaultColor;
4869
myGrayVal = myContrastEnhancement->enhanceContrast( myGrayValue );
4873
myGrayVal = 255 - myGrayVal;
4876
myLineBuffer[ myColumn ] = qRgba( myGrayVal, myGrayVal, myGrayVal, myAlphaValue );
4880
CPLFree( myGdalScanData );
4882
QgsDebugMsg( "Render done, preparing to copy to canvas" );
4884
paintImageToCanvas( theQPainter, theRasterViewPort, theQgsMapToPixel, &myQImage );
4886
} // QgsRasterLayer::drawSingleBandGray
4888
void QgsRasterLayer::drawSingleBandPseudoColor( QPainter * theQPainter,
4889
QgsRasterViewPort * theRasterViewPort,
4890
const QgsMapToPixel* theQgsMapToPixel,
4893
QgsDebugMsg( "entered." );
4894
//Invalid band number, segfault prevention
4895
if ( 0 >= theBandNo )
4900
QgsRasterBandStats myRasterBandStats = bandStatistics( theBandNo );
4901
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
4902
GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
4903
void *myGdalScanData = readData( myGdalBand, theRasterViewPort );
4905
/* Check for out of memory error */
4906
if ( myGdalScanData == NULL )
4911
QImage myQImage = QImage( theRasterViewPort->drawableAreaXDim, theRasterViewPort->drawableAreaYDim, QImage::Format_ARGB32 );
4912
QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
4914
if ( NULL == mRasterShader )
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 )
4924
myMinimumValue = ( myRasterBandStats.mean - ( mStandardDeviations * myRasterBandStats.stdDev ) );
4925
myMaximumValue = ( myRasterBandStats.mean + ( mStandardDeviations * myRasterBandStats.stdDev ) );
4929
myMinimumValue = myRasterBandStats.minimumValue;
4930
myMaximumValue = myRasterBandStats.maximumValue;
4933
mRasterShader->setMinimumValue( myMinimumValue );
4934
mRasterShader->setMaximumValue( myMaximumValue );
4937
int myRedValue = 255;
4938
int myGreenValue = 255;
4939
int myBlueValue = 255;
4941
double myPixelValue = 0.0;
4942
int myAlphaValue = 0;
4943
QgsDebugMsg( "Starting main render loop" );
4944
for ( int myRow = 0; myRow < theRasterViewPort->drawableAreaYDim; ++myRow )
4946
QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
4947
for ( int myColumn = 0; myColumn < theRasterViewPort->drawableAreaXDim; ++myColumn )
4949
myPixelValue = readValue( myGdalScanData, myDataType,
4950
myRow * theRasterViewPort->drawableAreaXDim + myColumn );
4952
if ( mValidNoDataValue && ( fabs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) )
4954
myLineBuffer[ myColumn ] = myDefaultColor;
4958
myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel );
4959
if ( 0 == myAlphaValue )
4961
myLineBuffer[ myColumn ] = myDefaultColor;
4965
if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) )
4967
myLineBuffer[ myColumn ] = myDefaultColor;
4973
//Invert flag, flip blue and read
4974
myLineBuffer[ myColumn ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue );
4979
myLineBuffer[ myColumn ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue );
4981
} //end of columnwise loop
4982
} //end of rowwise loop
4984
CPLFree( myGdalScanData );
4986
paintImageToCanvas( theQPainter, theRasterViewPort, theQgsMapToPixel, &myQImage );
4990
void QgsRasterLayer::closeDataset()
4992
if ( !mValid ) return;
4995
GDALDereferenceDataset( mGdalBaseDataset );
4996
mGdalBaseDataset = NULL;
4998
GDALClose( mGdalDataset );
4999
mGdalDataset = NULL;
5001
mHasPyramids = false;
5002
mPyramidList.clear();
5004
mRasterStatsList.clear();
5007
QString QgsRasterLayer::generateBandName( int theBandNumber )
5009
return tr( "Band" ) + QString( " %1" ) .arg( theBandNumber, 1 + ( int ) log10(( float ) bandCount() ), 10, QChar( '0' ) );
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
5016
bool QgsRasterLayer::hasBand( QString const & theBandName )
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 );
5021
for ( int i = 1; i <= GDALGetRasterCount( mGdalDataset ); i++ )
5023
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, i );
5024
QString myColorQString = GDALGetColorInterpretationName( GDALGetRasterColorInterpretation( myGdalBand ) );
5026
QgsLogger::debug( "band", i, __FILE__, __FUNCTION__, __LINE__, 2 );
5029
if ( myColorQString == theBandName )
5032
QgsLogger::debug( "band", i, __FILE__, __FUNCTION__, __LINE__, 2 );
5033
QgsDebugMsgLevel( "Found band : " + theBandName, 2 );
5038
QgsDebugMsgLevel( "Found unmatched band : " + QString::number( i ) + " " + myColorQString, 2 );
5043
void QgsRasterLayer::paintImageToCanvas( QPainter* theQPainter, QgsRasterViewPort * theRasterViewPort, const QgsMapToPixel* theQgsMapToPixel, QImage* theImage )
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;
5050
if ( theQgsMapToPixel )
5052
paintXoffset = static_cast<int>(
5053
( theRasterViewPort->rectXOffsetFloat -
5054
theRasterViewPort->rectXOffset )
5055
/ theQgsMapToPixel->mapUnitsPerPixel()
5056
* fabs( mGeoTransform[1] )
5059
paintYoffset = static_cast<int>(
5060
( theRasterViewPort->rectYOffsetFloat -
5061
theRasterViewPort->rectYOffset )
5062
/ theQgsMapToPixel->mapUnitsPerPixel()
5063
* fabs( mGeoTransform[5] )
5067
QgsDebugMsg( "painting image to canvas from "
5068
+ QString::number( paintXoffset ) + ", " + QString::number( paintYoffset )
5070
+ QString::number( static_cast<int>( theRasterViewPort->topLeftPoint.x() + 0.5 ) )
5072
+ QString::number( static_cast<int>( theRasterViewPort->topLeftPoint.y() + 0.5 ) )
5075
theQPainter->drawImage( static_cast<int>( theRasterViewPort->topLeftPoint.x() + 0.5 ),
5076
static_cast<int>( theRasterViewPort->topLeftPoint.y() + 0.5 ),
5082
QString QgsRasterLayer::projectionWkt()
5084
QString myWktString;
5085
QgsCoordinateReferenceSystem myCRS;
5086
myWktString = QString( GDALGetProjectionRef( mGdalDataset ) );
5087
myCRS.createFromWkt( myWktString );
5088
if ( !myCRS.isValid() )
5090
//try to get the gcp srs from the raster layer if available
5091
myWktString = QString( GDALGetGCPProjection( mGdalDataset ) );
5093
// What is the purpose of this piece of code?
5094
// Sideeffects from validate()?
5095
// myCRS.createFromWkt(myWktString);
5096
// if (!myCRS.isValid())
5098
// // use force and make CRS valid!
5099
// myCRS.validate();
5108
*data type is the same as raster band. The memory must be released later!
5109
* \return pointer to the memory
5111
void *QgsRasterLayer::readData( GDALRasterBandH gdalBand, QgsRasterViewPort *viewPort )
5113
GDALDataType type = GDALGetRasterDataType( gdalBand );
5114
int size = GDALGetDataTypeSize( type ) / 8;
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 ) );
5124
void *data = VSIMalloc( size * viewPort->drawableAreaXDim * viewPort->drawableAreaYDim );
5126
/* Abort if out of memory */
5129
QgsDebugMsg( "Layer " + name() + " couldn't allocate enough memory. Ignoring" );
5133
CPLErr myErr = GDALRasterIO( gdalBand, GF_Read,
5134
viewPort->rectXOffset,
5135
viewPort->rectYOffset,
5136
viewPort->clippedWidth,
5137
viewPort->clippedHeight,
5139
viewPort->drawableAreaXDim,
5140
viewPort->drawableAreaYDim,
5142
if ( myErr != CPLE_None )
5144
QgsLogger::warning( "RasterIO error: " + QString::fromUtf8( CPLGetLastErrorMsg() ) );
5151
* @note Called from ctor if a raster image given there
5153
* @param theFilename absolute path and filename of the raster to be loaded
5154
* @returns true if successfully read file
5156
bool QgsRasterLayer::readFile( QString const &theFilename )
5158
registerGdalDrivers();
5160
mGdalDataset = NULL;
5162
//open the dataset making sure we handle char encoding of locale properly
5163
mGdalBaseDataset = GDALOpen( QFile::encodeName( theFilename ).constData(), GA_ReadOnly );
5165
if ( mGdalBaseDataset == NULL )
5172
mLastModified = lastModified( theFilename );
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 )
5182
QgsLogger::warning( "Creating Warped VRT." );
5185
GDALAutoCreateWarpedVRT( mGdalBaseDataset, NULL, NULL,
5186
GRA_NearestNeighbour, 0.2, NULL );
5187
if ( mGdalDataset == NULL )
5189
QgsLogger::warning( "Warped VRT Creation failed." );
5190
mGdalDataset = mGdalBaseDataset;
5191
GDALReferenceDataset( mGdalDataset );
5196
mGdalDataset = mGdalBaseDataset;
5197
GDALReferenceDataset( mGdalDataset );
5200
//check f this file has pyramids
5201
GDALRasterBandH myGDALBand = GDALGetRasterBand( mGdalDataset, 1 ); //just use the first band
5202
if ( myGDALBand == NULL )
5204
GDALDereferenceDataset( mGdalBaseDataset );
5205
mGdalBaseDataset = NULL;
5207
GDALClose( mGdalDataset );
5208
mGdalDataset = NULL;
5212
if ( GDALGetOverviewCount( myGDALBand ) > 0 )
5214
mHasPyramids = true;
5218
mHasPyramids = false;
5221
//populate the list of what pyramids exist
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
5228
QString mySourceWkt = projectionWkt();
5230
QgsDebugMsg( "--------------------------------------------------------------------------------------" );
5231
QgsDebugMsg( "using wkt:\n" + mySourceWkt );
5232
QgsDebugMsg( "--------------------------------------------------------------------------------------" );
5234
mCRS->createFromWkt( mySourceWkt );
5235
//get the project projection, defaulting to this layer's projection
5236
//if none exists....
5237
if ( !mCRS->isValid() )
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" );
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];
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 );
5266
// Set up the x and y dimensions of this raster layer
5268
mWidth = GDALGetRasterXSize( mGdalDataset );
5269
mHeight = GDALGetRasterYSize( mGdalDataset );
5272
// Determine the nodata value
5274
mNoDataValue = -9999.0; //Standard default?
5275
mValidNoDataValue = false;
5276
int isValid = false;
5277
double myNoDataValue = GDALGetRasterNoDataValue( GDALGetRasterBand( mGdalDataset, 1 ), &isValid );
5280
mNoDataValue = myNoDataValue;
5281
mValidNoDataValue = true;
5284
if ( mValidNoDataValue )
5286
mRasterTransparency.initializeTransparentPixelList( mNoDataValue, mNoDataValue, mNoDataValue );
5287
mRasterTransparency.initializeTransparentPixelList( mNoDataValue );
5290
mBandCount = GDALGetRasterCount( mGdalDataset );
5291
for ( int i = 1; i <= mBandCount; i++ )
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 );
5302
mRasterStatsList.push_back( myRasterBandStats );
5304
//Build a new contrast enhancement for the band and store in list
5305
QgsContrastEnhancement myContrastEnhancement(( QgsContrastEnhancement::QgsRasterDataType )GDALGetRasterDataType( myGdalBand ) );
5306
mContrastEnhancementList.append( myContrastEnhancement );
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() );
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 ) )
5318
mRasterType = Multiband;
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!
5323
mRasterType = Palette;
5327
mRasterType = GrayOrUndefined;
5330
if ( mRasterType == Palette )
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 );
5339
mDrawingStyle = PalettedColor; //sensible default
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 ) );
5349
else if ( mRasterType == Multiband )
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 )
5357
mBlueBandName = bandName( myQSettings.value( "/Raster/defaultBlueBand", 3 ).toInt() ); // sensible default
5361
mBlueBandName = bandName( myQSettings.value( "/Raster/defaultBlueBand", 2 ).toInt() ); // sensible default
5364
mTransparencyBandName = TRSTRING_NOT_SET;
5365
mGrayBandName = TRSTRING_NOT_SET; //sensible default
5366
mDrawingStyle = MultiBandColor; //sensible default
5368
else //GrayOrUndefined
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 );
5378
//mark the layer as valid
5382
} // QgsRasterLayer::readFile
5385
* @param index index in memory block
5387
double QgsRasterLayer::readValue( void *data, GDALDataType type, int index )
5394
return ( double )(( GByte * )data )[index];
5397
return ( double )(( GUInt16 * )data )[index];
5400
return ( double )(( GInt16 * )data )[index];
5403
return ( double )(( GUInt32 * )data )[index];
5406
return ( double )(( GInt32 * )data )[index];
5409
return ( double )(( float * )data )[index];
5412
val = (( double * )data )[index];
5413
return ( double )(( double * )data )[index];
5416
QgsLogger::warning( "GDAL data type is not supported" );
5421
bool QgsRasterLayer::update()
5423
QgsDebugMsg( "entered." );
5425
if ( mLastModified < QgsRasterLayer::lastModified( source() ) )
5427
QgsDebugMsg( "Outdated -> reload" );
5429
return readFile( source() );
5434
bool QgsRasterLayer::usesProvider()
5436
if ( mProviderKey.isEmpty() )
5446
QString QgsRasterLayer::validateBandName( QString const & theBandName )
5448
QgsDebugMsg( "Checking..." );
5449
//check if the band is unset
5450
if ( theBandName == TRSTRING_NOT_SET || theBandName == QSTRING_NOT_SET )
5452
QgsDebugMsg( "Band name is '" + QSTRING_NOT_SET + "'. Nothing to do." );
5453
// Use translated name internally
5454
return TRSTRING_NOT_SET;
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 )
5461
//find out the name of this band
5462
if ( mRasterStatsList[myIterator].bandName == theBandName )
5464
QgsDebugMsg( "Matching band name found" );
5468
QgsDebugMsg( "No matching band name found in raster band stats" );
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 )
5475
int myBandNumber = myBandNameComponents.at( 1 ).toInt();
5476
if ( myBandNumber > 0 )
5478
QString myBandName = generateBandName( myBandNumber );
5479
for ( int myIterator = 0; myIterator < mRasterStatsList.size(); ++myIterator )
5481
//find out the name of this band
5482
if ( mRasterStatsList[myIterator].bandName == myBandName )
5484
QgsDebugMsg( "Matching band name found" );
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( ':' ) )
5497
myBandNameComponents = theBandName.split( ":" );
5498
if ( myBandNameComponents.size() == 2 )
5500
int myBandNumber = myBandNameComponents.at( 0 ).toInt();
5501
if ( myBandNumber > 0 )
5503
QgsDebugMsg( "Transformed older name format to current format" );
5504
return "Band " + QString::number( myBandNumber );
5509
//if no matches were found default to not set
5510
QgsDebugMsg( "All checks failed, returning '" + QSTRING_NOT_SET + "'" );
5511
return TRSTRING_NOT_SET;