diff --git a/CODING b/CODING
index 972e9ea17a2..65d4d14b957 100644
--- a/CODING
+++ b/CODING
@@ -58,8 +58,14 @@ Developers guide for QGIS
3.4. The ADD_QGIS_TEST macro explained
3.5. Building your unit test
3.6. Run your tests
- 4. HIG (Human Interface Guidelines)
- 5. Authors
+ 4. Getting up and running with QtCreator and QGIS
+ 4.1. Installing QtCreator
+ 4.2. Setting up your project
+ 4.3. Setting up your build environment
+ 4.4. Setting your run environment
+ 4.5. Running and debugging
+ 5. HIG (Human Interface Guidelines)
+ 6. Authors
------------------------------------------------------------------------
@@ -1208,7 +1214,163 @@ works in a truly platform way. I will update this document as things
progress.
- 4. HIG (Human Interface Guidelines)
+ 4. Getting up and running with QtCreator and QGIS
+ =================================================
+
+QtCreator is a newish IDE from the makers of the Qt library. With QtCreator you
+can build any C++ project, but it's really optimised for people working on
+Qt(4) based applications (including mobile apps). Everything I describe below
+assumes you are running Ubuntu 11.04 'Natty'.
+
+
+ 4.1. Installing QtCreator
+ =========================
+
+This part is easy:
+
+ sudo apt-get install qtcreator qtcreator-doc
+
+After installing you should find it in your gnome menu.
+
+
+ 4.2. Setting up your project
+ ============================
+
+I'm assuming you have already got a local Quantum-GIS clone containing the
+source code, and have installed all needed build dependencies etc. There are
+detailed in instructions on doing that here:
+
+http://github.com/qgis/Quantum-GIS/blob/master/CODING
+
+On my system I have checked out the code into $HOME/dev/cpp/Quantum-GIS and the
+rest of the article is written assuming that, you should update these paths as
+appropriate for your local system.
+
+On launching QtCreator do:
+
+ File->Open File or Project
+
+Then use the resulting file selection dialog to browse to and open this file:
+
+ $HOME/dev/cpp/Quantum-GIS/CMakeLists.txt
+
+[images/image01.jpeg]
+
+Next you will be prompted for a build location. I create a specific build dir
+for QtCreator to work in under:
+
+ $HOME/dev/cpp/Quantum-GIS/build-master-qtcreator
+
+Its probably a good idea to create separate build directories for different
+branches if you can afford the disk space.
+
+[images/image02.jpeg]
+
+Next you will be asked if you have any CMake build options to pass to CMake. We
+will tell CMake that we want a debug build by adding this option:
+
+ -DCMAKE_BUILD_TYPE=Debug
+
+[images/image03.jpeg]
+
+Thats the basics of it. When you complete the Wizard, QtCreator will start
+scanning the source tree for autocompletion support and do some other
+housekeeping stuff in the background. We want to tweak a few things before we
+start to build though.
+
+
+ 4.3. Setting up your build environment
+ ======================================
+
+Click on the 'Projects' icon on the left of the QtCreator window.
+
+[images/image04.jpeg]
+
+Select the build settings tab (normally active by default).
+
+[images/image05.jpeg]
+
+We now want to add a custom process step. Why? Because QGIS can currently only
+run from an install directory, not its build directory, so we need to ensure
+that it is installed whenever we build it. Under 'Build Steps', click on the
+'Add Build Step' combo button and choose 'Custom Process Step'.
+
+[images/image06.jpeg]
+
+Now we set the following details:
+
+ Enable custom process step [yes]
+ Command: make
+ Working directory: $HOME/dev/cpp/Quantum-GIS/build-master-qtcreator
+ Command arguments: install
+
+[images/image07.jpeg]
+
+You are almost ready to build. Just one note: QtCreator will need write
+permissions on the install prefix. By default (which I am using here) QGIS is
+going to get installed to /usr/local. For my purposes on my development
+machine, I just gave myself write permissions to the /usr/local directory.
+
+To start the build, click that big hammer icon on the bottom left of the
+window.
+
+[images/image08.jpeg]
+
+
+ 4.4. Setting your run environment
+ =================================
+
+As mentioned above, we cannot run QGIS from directly in the build directly, so
+we need to create a custom run target to tell QtCreator to run QGIS from the
+install dir (in my case /usr/local/). To do that, return to the projects
+configuration screen.
+
+[images/image04.jpeg]
+
+Now select the 'Run Settings' tab
+
+[images/image09.jpeg]
+
+We need to update the default run settings from using the 'qgis' run
+configuration to using a custom one.
+
+[images/image10.jpeg]
+
+Do do that, click the 'Add v' combo button next to the Run configuration
+combo and choose 'Custom Executable' from the top of the list.
+
+[images/image11.jpeg]
+
+Now in the properties area set the following details:
+
+ Executable: /usr/local/bin/qgis
+ Arguments :
+ Working directory: $HOME
+ Run in terminal: [no]
+ Debugger: C++ [yes]
+ Qml [no]
+
+Then click the 'Rename' button and give your custom executable a meaning full
+name e.g. 'Installed QGIS'
+
+[images/image12.jpeg]
+
+
+ 4.5. Running and debugging
+ ==========================
+
+Now you are ready to run and debug QGIS. To set a break point, simply open a
+source file and click in the left column.
+
+[images/image14.jpeg]
+
+Now launch QGIS under the debugger by clicking the icon with a bug on it in the
+bottom left of the window.
+
+[images/image13.jpeg]
+
+
+ 5. HIG (Human Interface Guidelines)
===================================
In order for all graphical user interface elements to appear consistant and to
@@ -1257,7 +1419,7 @@ guidelines are followed in layout and design of GUIs.
suffixed to the button text.
- 5. Authors
+ 6. Authors
==========
- Tim Sutton (author and editor)
diff --git a/INSTALL b/INSTALL
index bd84ba27b52..fa56ba51610 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,10 +1,10 @@
Quantum GIS (QGIS)
Building QGIS from source - step by step
-Sunday June 12, 2011
+Thursday August 04, 2011
-Last Updated: Sunday June 12, 2011
-Last Change : Sunday June 05, 2011
+Last Updated: Thursday August 04, 2011
+Last Change : Tuesday June 28, 2011
1. Introduction
diff --git a/doc/INSTALL.html b/doc/INSTALL.html
index c82b5039654..d3a64c15c5b 100644
--- a/doc/INSTALL.html
+++ b/doc/INSTALL.html
@@ -45,13 +45,13 @@ pre, code { font-family: monospace }
-Last Updated: Sunday June 12, 2011
-Last Change : Sunday June 05, 2011
+Last Updated: Thursday August 04, 2011
+Last Change : Tuesday June 28, 2011
diff --git a/src/app/qgsrasterlayerproperties.cpp b/src/app/qgsrasterlayerproperties.cpp
index 7fef395fdea..81656e6b6ff 100644
--- a/src/app/qgsrasterlayerproperties.cpp
+++ b/src/app/qgsrasterlayerproperties.cpp
@@ -1882,7 +1882,7 @@ void QgsRasterLayerProperties::refreshHistogram()
// bin in all selected layers, and the min. It then draws a scaled line between min
// and max - scaled to image height. 1 line drawn per selected band
//
- const int BINCOUNT = 255;
+ const int BINCOUNT = 256;
bool myIgnoreOutOfRangeFlag = true;
bool myThoroughBandScanFlag = false;
int myBandCountInt = mRasterLayer->bandCount();
diff --git a/src/core/qgsapplication.cpp b/src/core/qgsapplication.cpp
index 4c8115e1c08..61711877f42 100644
--- a/src/core/qgsapplication.cpp
+++ b/src/core/qgsapplication.cpp
@@ -64,6 +64,10 @@ QString QgsApplication::mBuildOutputPath;
*/
QgsApplication::QgsApplication( int & argc, char ** argv, bool GUIenabled, QString customConfigPath )
: QApplication( argc, argv, GUIenabled )
+{
+ init( customConfigPath ); //initi can also be called directly by e.g. unit tests that dont inherit QApplication.
+}
+void QgsApplication::init( QString customConfigPath )
{
// check if QGIS is run from build directory (not the install directory)
QDir appDir( applicationDirPath() );
diff --git a/src/core/qgsapplication.h b/src/core/qgsapplication.h
index 7642da1ee0c..86967004474 100644
--- a/src/core/qgsapplication.h
+++ b/src/core/qgsapplication.h
@@ -32,6 +32,10 @@ class CORE_EXPORT QgsApplication: public QApplication
QgsApplication( int & argc, char ** argv, bool GUIenabled, QString customConfigPath = QString() );
virtual ~QgsApplication();
+ /** This method initialises paths etc for QGIS. Called by the ctor or call it manually
+ when your app does not extend the QApplication class. */
+ static void init( QString customConfigPath = QString() );
+
//! Watch for QFileOpenEvent.
virtual bool event( QEvent * event );
diff --git a/src/core/qgsrasterdataprovider.cpp b/src/core/qgsrasterdataprovider.cpp
index 2a76a15ef5e..b7206ce4474 100644
--- a/src/core/qgsrasterdataprovider.cpp
+++ b/src/core/qgsrasterdataprovider.cpp
@@ -201,31 +201,31 @@ QByteArray QgsRasterDataProvider::noValueBytes( int theBandNo )
double d;
switch ( type )
{
- case QgsRasterDataProvider::Byte:
+ case Byte:
uc = ( unsigned char )noval;
memcpy( data, &uc, size );
break;
- case QgsRasterDataProvider::UInt16:
+ case UInt16:
us = ( unsigned short )noval;
memcpy( data, &us, size );
break;
- case QgsRasterDataProvider::Int16:
+ case Int16:
s = ( short )noval;
memcpy( data, &s, size );
break;
- case QgsRasterDataProvider::UInt32:
+ case UInt32:
ui = ( unsigned int )noval;
memcpy( data, &ui, size );
break;
- case QgsRasterDataProvider::Int32:
+ case Int32:
i = ( int )noval;
memcpy( data, &i, size );
break;
- case QgsRasterDataProvider::Float32:
+ case Float32:
f = ( float )noval;
memcpy( data, &f, size );
break;
- case QgsRasterDataProvider::Float64:
+ case Float64:
d = ( double )noval;
memcpy( data, &d, size );
break;
@@ -235,4 +235,188 @@ QByteArray QgsRasterDataProvider::noValueBytes( int theBandNo )
return ba;
}
+
+QgsRasterBandStats QgsRasterDataProvider::bandStatistics( int theBandNo )
+{
+ double myNoDataValue = noDataValue();
+ QgsRasterBandStats myRasterBandStats;
+ myRasterBandStats.elementCount = 0; // because we'll be counting only VALID pixels later
+
+ int myDataType = dataType( theBandNo );
+
+ int myNXBlocks, myNYBlocks, myXBlockSize, myYBlockSize;
+ myXBlockSize = xBlockSize();
+ myYBlockSize = yBlockSize();
+
+ myNXBlocks = ( xSize() + myXBlockSize - 1 ) / myXBlockSize;
+ myNYBlocks = ( ySize() + myYBlockSize - 1 ) / myYBlockSize;
+
+ void *myData = CPLMalloc( myXBlockSize * myYBlockSize * ( dataTypeSize( theBandNo ) / 8 ) );
+
+ // unfortunately we need to make two passes through the data to calculate stddev
+ bool myFirstIterationFlag = true;
+
+ int myBandXSize = xSize();
+ int myBandYSize = ySize();
+ for ( int iYBlock = 0; iYBlock < myNYBlocks; iYBlock++ )
+ {
+ for ( int iXBlock = 0; iXBlock < myNXBlocks; iXBlock++ )
+ {
+ int nXValid, nYValid;
+ readBlock( theBandNo, iXBlock, iYBlock, myData );
+
+ // Compute the portion of the block that is valid
+ // for partial edge blocks.
+ if (( iXBlock + 1 ) * myXBlockSize > myBandXSize )
+ nXValid = myBandXSize - iXBlock * myXBlockSize;
+ else
+ nXValid = myXBlockSize;
+
+ if (( iYBlock + 1 ) * myYBlockSize > myBandYSize )
+ nYValid = myBandYSize - iYBlock * myYBlockSize;
+ else
+ nYValid = myYBlockSize;
+
+ // Collect the histogram counts.
+ for ( int iY = 0; iY < nYValid; iY++ )
+ {
+ for ( int iX = 0; iX < nXValid; iX++ )
+ {
+ double myValue = readValue( myData, myDataType, iX + ( iY * myXBlockSize ) );
+ //QgsDebugMsg ( QString ( "%1 %2 value %3" ).arg (iX).arg(iY).arg( myValue ) );
+
+ if ( mValidNoDataValue && ( qAbs( myValue - myNoDataValue ) <= TINY_VALUE ) )
+ {
+ continue; // NULL
+ }
+
+ myRasterBandStats.sum += myValue;
+ ++myRasterBandStats.elementCount;
+ //only use this element if we have a non null element
+ if ( myFirstIterationFlag )
+ {
+ //this is the first iteration so initialise vars
+ myFirstIterationFlag = false;
+ myRasterBandStats.minimumValue = myValue;
+ myRasterBandStats.maximumValue = myValue;
+ } //end of true part for first iteration check
+ else
+ {
+ //this is done for all subsequent iterations
+ if ( myValue < myRasterBandStats.minimumValue )
+ {
+ myRasterBandStats.minimumValue = myValue;
+ }
+ if ( myValue > myRasterBandStats.maximumValue )
+ {
+ myRasterBandStats.maximumValue = myValue;
+ }
+ } //end of false part for first iteration check
+ }
+ }
+ } //end of column wise loop
+ } //end of row wise loop
+
+
+ //end of first pass through data now calculate the range
+ myRasterBandStats.range = myRasterBandStats.maximumValue - myRasterBandStats.minimumValue;
+ //calculate the mean
+ myRasterBandStats.mean = myRasterBandStats.sum / myRasterBandStats.elementCount;
+
+ //for the second pass we will get the sum of the squares / mean
+ for ( int iYBlock = 0; iYBlock < myNYBlocks; iYBlock++ )
+ {
+ for ( int iXBlock = 0; iXBlock < myNXBlocks; iXBlock++ )
+ {
+ int nXValid, nYValid;
+
+ readBlock( theBandNo, iXBlock, iYBlock, myData );
+
+ // Compute the portion of the block that is valid
+ // for partial edge blocks.
+ if (( iXBlock + 1 ) * myXBlockSize > myBandXSize )
+ nXValid = myBandXSize - iXBlock * myXBlockSize;
+ else
+ nXValid = myXBlockSize;
+
+ if (( iYBlock + 1 ) * myYBlockSize > myBandYSize )
+ nYValid = myBandYSize - iYBlock * myYBlockSize;
+ else
+ nYValid = myYBlockSize;
+
+ // Collect the histogram counts.
+ for ( int iY = 0; iY < nYValid; iY++ )
+ {
+ for ( int iX = 0; iX < nXValid; iX++ )
+ {
+ double myValue = readValue( myData, myDataType, iX + ( iY * myXBlockSize ) );
+ //QgsDebugMsg ( "myValue = " + QString::number(myValue) );
+
+ if ( mValidNoDataValue && ( qAbs( myValue - myNoDataValue ) <= TINY_VALUE ) )
+ {
+ continue; // NULL
+ }
+
+ myRasterBandStats.sumOfSquares += static_cast < double >
+ ( pow( myValue - myRasterBandStats.mean, 2 ) );
+ }
+ }
+ } //end of column wise loop
+ } //end of row wise loop
+
+ //divide result by sample size - 1 and get square root to get stdev
+ myRasterBandStats.stdDev = static_cast < double >( sqrt( myRasterBandStats.sumOfSquares /
+ ( myRasterBandStats.elementCount - 1 ) ) );
+
+#ifdef QGISDEBUG
+ QgsLogger::debug( "************ STATS **************", 1, __FILE__, __FUNCTION__, __LINE__ );
+ QgsLogger::debug( "VALID NODATA", mValidNoDataValue, 1, __FILE__, __FUNCTION__, __LINE__ );
+ QgsLogger::debug( "NULL", noDataValue() , 1, __FILE__, __FUNCTION__, __LINE__ );
+ QgsLogger::debug( "MIN", myRasterBandStats.minimumValue, 1, __FILE__, __FUNCTION__, __LINE__ );
+ QgsLogger::debug( "MAX", myRasterBandStats.maximumValue, 1, __FILE__, __FUNCTION__, __LINE__ );
+ QgsLogger::debug( "RANGE", myRasterBandStats.range, 1, __FILE__, __FUNCTION__, __LINE__ );
+ QgsLogger::debug( "MEAN", myRasterBandStats.mean, 1, __FILE__, __FUNCTION__, __LINE__ );
+ QgsLogger::debug( "STDDEV", myRasterBandStats.stdDev, 1, __FILE__, __FUNCTION__, __LINE__ );
+#endif
+
+ CPLFree( myData );
+ myRasterBandStats.statsGathered = true;
+ return myRasterBandStats;
+}
+
+double QgsRasterDataProvider::readValue( void *data, int type, int index )
+{
+ if ( !data )
+ return mValidNoDataValue ? noDataValue() : 0.0;
+
+ switch ( type )
+ {
+ case Byte:
+ return ( double )(( GByte * )data )[index];
+ break;
+ case UInt16:
+ return ( double )(( GUInt16 * )data )[index];
+ break;
+ case Int16:
+ return ( double )(( GInt16 * )data )[index];
+ break;
+ case UInt32:
+ return ( double )(( GUInt32 * )data )[index];
+ break;
+ case Int32:
+ return ( double )(( GInt32 * )data )[index];
+ break;
+ case Float32:
+ return ( double )(( float * )data )[index];
+ break;
+ case Float64:
+ return ( double )(( double * )data )[index];
+ break;
+ default:
+ QgsLogger::warning( "GDAL data type is not supported" );
+ }
+
+ return mValidNoDataValue ? noDataValue() : 0.0;
+}
+
// ENDS
diff --git a/src/core/qgsrasterdataprovider.h b/src/core/qgsrasterdataprovider.h
index 839c9e30ee5..f2f5a09c5a4 100644
--- a/src/core/qgsrasterdataprovider.h
+++ b/src/core/qgsrasterdataprovider.h
@@ -30,6 +30,7 @@
#include "qgscoordinatereferencesystem.h"
#include "qgsrasterbandstats.h"
+#include "cpl_conv.h"
#include
class QImage;
@@ -109,10 +110,11 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider
};
// Progress types
- enum Progress
+ enum RasterProgressType
{
ProgressHistogram = 0,
- ProgressPyramids = 1
+ ProgressPyramids = 1,
+ ProgressStatistics = 2
};
QgsRasterDataProvider();
@@ -325,6 +327,9 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider
/** read block of data using give extent and size */
virtual void readBlock( int bandNo, QgsRectangle const & viewExtent, int width, int height, QgsCoordinateReferenceSystem theSrcCRS, QgsCoordinateReferenceSystem theDestCRS, void *data );
+
+ /* Read a value from a data block at a given index. */
+ virtual double readValue( void *data, int type, int index );
/** value representing null data */
virtual double noDataValue() const { return 0; }
@@ -365,13 +370,16 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider
*/
virtual QList buildPyramidList() { return QList(); };
+ /** If the provider supports it, return band stats for the
+ given band. Default behaviour is to blockwise read the data
+ and generate the stats unless the provider overloads this function. */
+ virtual QgsRasterBandStats bandStatistics( int theBandNo );
/** \brief helper function to create zero padded band names */
QString generateBandName( int theBandNumber )
{
return tr( "Band" ) + QString( " %1" ) .arg( theBandNumber, 1 + ( int ) log10(( float ) bandCount() ), 10, QChar( '0' ) );
- }
-
+ };
/**
* Get metadata in a format suitable for feeding directly
diff --git a/src/core/raster/qgspseudocolorshader.cpp b/src/core/raster/qgspseudocolorshader.cpp
index 96175a570a0..4f132418e6f 100644
--- a/src/core/raster/qgspseudocolorshader.cpp
+++ b/src/core/raster/qgspseudocolorshader.cpp
@@ -44,7 +44,7 @@ bool QgsPseudoColorShader::shade( double theValue, int* theReturnRedValue, int*
}
//check if we are in the first class break
- if (( myPixelValue >= mClassBreakMin1 ) && ( myPixelValue < mClassBreakMax1 ) )
+ if ( ( myPixelValue >= mClassBreakMin1 ) && ( myPixelValue < mClassBreakMax1 ) )
{
*theReturnRedValue = 0;
*theReturnGreenValue = static_cast < int >((( 255 / mMinimumMaximumRange ) * ( myPixelValue - mClassBreakMin1 ) ) * 3 );
diff --git a/src/core/raster/qgsrasterlayer.cpp b/src/core/raster/qgsrasterlayer.cpp
index 29800556c8a..10c3b94da61 100755
--- a/src/core/raster/qgsrasterlayer.cpp
+++ b/src/core/raster/qgsrasterlayer.cpp
@@ -327,7 +327,6 @@ const QgsRasterBandStats QgsRasterLayer::bandStatistics( int theBandNo )
QgsRasterBandStats myNullReturnStats;
return myNullReturnStats;
}
-
// check if we have received a valid band number
if (( mDataProvider->bandCount() < theBandNo ) && mRasterType != Palette )
{
@@ -341,7 +340,6 @@ const QgsRasterBandStats QgsRasterLayer::bandStatistics( int theBandNo )
QgsRasterBandStats myNullReturnStats;
return myNullReturnStats;
}
-
// check if we have previously gathered stats for this band...
if ( theBandNo < 1 || theBandNo > mRasterStatsList.size() )
{
@@ -358,174 +356,23 @@ const QgsRasterBandStats QgsRasterLayer::bandStatistics( int theBandNo )
{
return myRasterBandStats;
}
- // only print message if we are actually gathering the stats
- emit statusChanged( tr( "Retrieving stats for %1" ).arg( name() ) );
- qApp->processEvents();
- QgsDebugMsg( "stats for band " + QString::number( theBandNo ) );
-
- myRasterBandStats.elementCount = 0; // because we'll be counting only VALID pixels later
-
- emit statusChanged( tr( "Calculating stats for %1" ).arg( name() ) );
- //reset the main app progress bar
- emit drawingProgress( 0, 0 );
-
- int myDataType = mDataProvider->dataType( theBandNo );
-
- int myNXBlocks, myNYBlocks, myXBlockSize, myYBlockSize;
- myXBlockSize = mDataProvider->xBlockSize();
- myYBlockSize = mDataProvider->yBlockSize();
-
- myNXBlocks = ( mDataProvider->xSize() + myXBlockSize - 1 ) / myXBlockSize;
- myNYBlocks = ( mDataProvider->ySize() + myYBlockSize - 1 ) / myYBlockSize;
-
- void *myData = CPLMalloc( myXBlockSize * myYBlockSize * ( mDataProvider->dataTypeSize( theBandNo ) / 8 ) );
-
- // unfortunately we need to make two passes through the data to calculate stddev
- bool myFirstIterationFlag = true;
-
- int myBandXSize = mDataProvider->xSize();
- int myBandYSize = mDataProvider->ySize();
- for ( int iYBlock = 0; iYBlock < myNYBlocks; iYBlock++ )
- {
- emit drawingProgress( iYBlock, myNYBlocks * 2 );
-
- for ( int iXBlock = 0; iXBlock < myNXBlocks; iXBlock++ )
- {
- int nXValid, nYValid;
- mDataProvider->readBlock( theBandNo, iXBlock, iYBlock, myData );
-
- // Compute the portion of the block that is valid
- // for partial edge blocks.
- if (( iXBlock + 1 ) * myXBlockSize > myBandXSize )
- nXValid = myBandXSize - iXBlock * myXBlockSize;
- else
- nXValid = myXBlockSize;
-
- if (( iYBlock + 1 ) * myYBlockSize > myBandYSize )
- nYValid = myBandYSize - iYBlock * myYBlockSize;
- else
- nYValid = myYBlockSize;
-
- // Collect the histogram counts.
- for ( int iY = 0; iY < nYValid; iY++ )
- {
- for ( int iX = 0; iX < nXValid; iX++ )
- {
- double myValue = readValue( myData, myDataType, iX + ( iY * myXBlockSize ) );
- //QgsDebugMsg ( QString ( "%1 %2 value %3" ).arg (iX).arg(iY).arg( myValue ) );
-
- if ( mValidNoDataValue && ( qAbs( myValue - mNoDataValue ) <= TINY_VALUE || myValue != myValue ) )
- {
- continue; // NULL
- }
-
- myRasterBandStats.sum += myValue;
- ++myRasterBandStats.elementCount;
- //only use this element if we have a non null element
- if ( myFirstIterationFlag )
- {
- //this is the first iteration so initialise vars
- myFirstIterationFlag = false;
- myRasterBandStats.minimumValue = myValue;
- myRasterBandStats.maximumValue = myValue;
- } //end of true part for first iteration check
- else
- {
- //this is done for all subsequent iterations
- if ( myValue < myRasterBandStats.minimumValue )
- {
- myRasterBandStats.minimumValue = myValue;
- }
- if ( myValue > myRasterBandStats.maximumValue )
- {
- myRasterBandStats.maximumValue = myValue;
- }
- } //end of false part for first iteration check
- }
- }
- } //end of column wise loop
- } //end of row wise loop
-
-
- //end of first pass through data now calculate the range
- myRasterBandStats.range = myRasterBandStats.maximumValue - myRasterBandStats.minimumValue;
- //calculate the mean
- myRasterBandStats.mean = myRasterBandStats.sum / myRasterBandStats.elementCount;
-
- //for the second pass we will get the sum of the squares / mean
- for ( int iYBlock = 0; iYBlock < myNYBlocks; iYBlock++ )
- {
- emit drawingProgress( iYBlock + myNYBlocks, myNYBlocks * 2 );
-
- for ( int iXBlock = 0; iXBlock < myNXBlocks; iXBlock++ )
- {
- int nXValid, nYValid;
-
- mDataProvider->readBlock( theBandNo, iXBlock, iYBlock, myData );
-
- // Compute the portion of the block that is valid
- // for partial edge blocks.
- if (( iXBlock + 1 ) * myXBlockSize > myBandXSize )
- nXValid = myBandXSize - iXBlock * myXBlockSize;
- else
- nXValid = myXBlockSize;
-
- if (( iYBlock + 1 ) * myYBlockSize > myBandYSize )
- nYValid = myBandYSize - iYBlock * myYBlockSize;
- else
- nYValid = myYBlockSize;
-
- // Collect the histogram counts.
- for ( int iY = 0; iY < nYValid; iY++ )
- {
- for ( int iX = 0; iX < nXValid; iX++ )
- {
- double myValue = readValue( myData, myDataType, iX + ( iY * myXBlockSize ) );
- //QgsDebugMsg ( "myValue = " + QString::number(myValue) );
-
- if ( mValidNoDataValue && ( qAbs( myValue - mNoDataValue ) <= TINY_VALUE || myValue != myValue ) )
- {
- continue; // NULL
- }
-
- myRasterBandStats.sumOfSquares += static_cast < double >
- ( pow( myValue - myRasterBandStats.mean, 2 ) );
- }
- }
- } //end of column wise loop
- } //end of row wise loop
-
- //divide result by sample size - 1 and get square root to get stdev
- myRasterBandStats.stdDev = static_cast < double >( sqrt( myRasterBandStats.sumOfSquares /
- ( myRasterBandStats.elementCount - 1 ) ) );
-
-#ifdef QGISDEBUG
- QgsLogger::debug( "************ STATS **************", 1, __FILE__, __FUNCTION__, __LINE__ );
- QgsLogger::debug( "VALID NODATA", mValidNoDataValue, 1, __FILE__, __FUNCTION__, __LINE__ );
- QgsLogger::debug( "NULL", mNoDataValue, 1, __FILE__, __FUNCTION__, __LINE__ );
- QgsLogger::debug( "MIN", myRasterBandStats.minimumValue, 1, __FILE__, __FUNCTION__, __LINE__ );
- QgsLogger::debug( "MAX", myRasterBandStats.maximumValue, 1, __FILE__, __FUNCTION__, __LINE__ );
- QgsLogger::debug( "RANGE", myRasterBandStats.range, 1, __FILE__, __FUNCTION__, __LINE__ );
- QgsLogger::debug( "MEAN", myRasterBandStats.mean, 1, __FILE__, __FUNCTION__, __LINE__ );
- QgsLogger::debug( "STDDEV", myRasterBandStats.stdDev, 1, __FILE__, __FUNCTION__, __LINE__ );
-#endif
-
- CPLFree( myData );
- myRasterBandStats.statsGathered = true;
+ myRasterBandStats = mDataProvider->bandStatistics( theBandNo );
QgsDebugMsg( "adding stats to stats collection at position " + QString::number( theBandNo - 1 ) );
//add this band to the class stats map
mRasterStatsList[theBandNo - 1] = myRasterBandStats;
emit drawingProgress( mHeight, mHeight ); //reset progress
- //QApplication::restoreOverrideCursor(); //restore the cursor
QgsDebugMsg( "Stats collection completed returning" );
return myRasterBandStats;
-
} // QgsRasterLayer::bandStatistics
const QgsRasterBandStats QgsRasterLayer::bandStatistics( QString const & theBandName )
{
-
+ // only print message if we are actually gathering the stats
+ emit statusChanged( tr( "Retrieving stats for %1" ).arg( name() ) );
+ qApp->processEvents();
+ //reset the main app progress bar
+ emit drawingProgress( 0, 0 );
//we cant use a vector iterator because the iterator is astruct not a class
//and the qvector model does not like this.
for ( int i = 1; i <= mDataProvider->bandCount(); i++ )
diff --git a/src/providers/gdal/qgsgdalprovider.cpp b/src/providers/gdal/qgsgdalprovider.cpp
index 086cf844322..52524db1bfb 100644
--- a/src/providers/gdal/qgsgdalprovider.cpp
+++ b/src/providers/gdal/qgsgdalprovider.cpp
@@ -105,7 +105,9 @@ QgsGdalProvider::QgsGdalProvider( QString const & uri )
// To get buildSupportedRasterFileFilter the provider is called with empty uri
if ( uri.isEmpty() )
+ {
return;
+ }
mGdalDataset = NULL;
@@ -287,51 +289,6 @@ QgsGdalProvider::QgsGdalProvider( QString const & uri )
QgsDebugMsg( QString( "mNoDataValue[%1] = %1" ).arg( i - 1 ).arg( mNoDataValue[i-1] ) );
}
- // This block of code was in old version in QgsRasterLayer::bandStatistics
- //ifdefs below to remove compiler warning about unused vars
-#ifdef QGISDEBUG
-#if 0
- int success;
- double GDALminimum = GDALGetRasterMinimum( myGdalBand, &success );
-
- if ( ! success )
- {
- QgsDebugMsg( "myGdalBand->GetMinimum() failed" );
- }
-
- double GDALmaximum = GDALGetRasterMaximum( myGdalBand, &success );
-
- if ( ! success )
- {
- QgsDebugMsg( "myGdalBand->GetMaximum() failed" );
- }
-
- double GDALnodata = GDALGetRasterNoDataValue( myGdalBand, &success );
-
- if ( ! success )
- {
- QgsDebugMsg( "myGdalBand->GetNoDataValue() failed" );
- }
-
- QgsLogger::debug( "GDALminium: ", GDALminimum, __FILE__, __FUNCTION__, __LINE__ );
- QgsLogger::debug( "GDALmaximum: ", GDALmaximum, __FILE__, __FUNCTION__, __LINE__ );
- QgsLogger::debug( "GDALnodata: ", GDALnodata, __FILE__, __FUNCTION__, __LINE__ );
-
- double GDALrange[2]; // calculated min/max, as opposed to the
- // dataset provided
-
- GDALComputeRasterMinMax( myGdalBand, 1, GDALrange );
- QgsLogger::debug( "approximate computed GDALminium:", GDALrange[0], __FILE__, __FUNCTION__, __LINE__, 1 );
- QgsLogger::debug( "approximate computed GDALmaximum:", GDALrange[1], __FILE__, __FUNCTION__, __LINE__, 1 );
-
- GDALComputeRasterMinMax( myGdalBand, 0, GDALrange );
- QgsLogger::debug( "exactly computed GDALminium:", GDALrange[0] );
- QgsLogger::debug( "exactly computed GDALmaximum:", GDALrange[1] );
-
- QgsDebugMsg( "starting manual stat computation" );
-#endif
-#endif
-
mValid = true;
QgsDebugMsg( "end" );
}
@@ -391,7 +348,9 @@ QgsGdalProvider::~QgsGdalProvider()
void QgsGdalProvider::closeDataset()
{
if ( !mValid )
+ {
return;
+ }
mValid = false;
GDALDereferenceDataset( mGdalBaseDataset );
@@ -921,25 +880,37 @@ void QgsGdalProvider::computeMinMax( int theBandNo )
{
QgsDebugMsg( QString( "theBandNo = %1 mMinMaxComputed = %2" ).arg( theBandNo ).arg( mMinMaxComputed[theBandNo-1] ) );
if ( mMinMaxComputed[theBandNo-1] )
+ {
return;
- double GDALrange[2];
+ }
+ int bApproxOK=false;
+ double pdfMin;
+ double pdfMax;
+ double pdfMean;
+ double pdfStdDev;
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
- GDALComputeRasterMinMax( myGdalBand, 1, GDALrange ); //Approximate
- QgsDebugMsg( QString( "GDALrange[0] = %1 GDALrange[1] = %2" ).arg( GDALrange[0] ).arg( GDALrange[1] ) );
- mMinimum[theBandNo-1] = GDALrange[0];
- mMaximum[theBandNo-1] = GDALrange[1];
+ double myerval = GDALGetRasterStatistics (
+ myGdalBand,
+ bApproxOK,
+ TRUE,
+ &pdfMin,
+ &pdfMax,
+ &pdfMean,
+ &pdfStdDev
+ );
+ Q_UNUSED(myerval);
+ mMinimum[theBandNo-1] = pdfMin;
+ mMaximum[theBandNo-1] = pdfMax;
}
double QgsGdalProvider::minimumValue( int theBandNo ) const
{
QgsDebugMsg( QString( "theBandNo = %1" ).arg( theBandNo ) );
- //computeMinMax ( theBandNo );
return mMinimum[theBandNo-1];
}
double QgsGdalProvider::maximumValue( int theBandNo ) const
{
QgsDebugMsg( QString( "theBandNo = %1" ).arg( theBandNo ) );
- //computeMinMax ( theBandNo );
return mMaximum[theBandNo-1];
}
@@ -1294,7 +1265,9 @@ void QgsGdalProvider::populateHistogram( int theBandNo, QgsRasterBandStats & t
//vector is not equal to the number of bins
//i.e if the histogram has never previously been generated or the user has
//selected a new number of bins.
- if ( theBandStats.histogramVector->size() != theBinCount ||
+ bool myCollectHistogramFlag = true;
+ if ( theBandStats.histogramVector == 0 ||
+ theBandStats.histogramVector->size() != theBinCount ||
theIgnoreOutOfRangeFlag != theBandStats.isHistogramOutOfRange ||
theHistogramEstimatedFlag != theBandStats.isHistogramEstimated )
{
@@ -1865,6 +1838,74 @@ QGISEXTERN bool isValidRasterFileName( QString const & theFileNameQString, QStri
}
}
+
+
+QgsRasterBandStats QgsGdalProvider::bandStatistics( int theBandNo )
+{
+ GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
+ QgsRasterBandStats myRasterBandStats;
+ int bApproxOK=false;
+ double pdfMin;
+ double pdfMax;
+ double pdfMean;
+ double pdfStdDev;
+ QgsGdalProgress myProg;
+ myProg.type = ProgressHistogram;
+ myProg.provider = this;
+
+ // Suggested by Etienne Sky to use getrasterstatistics instead of compute
+ // since computerasterstatistics forces collection each time
+ // where as getrasterstatistics uses aux.xml cached copy if available
+ // Note: there is currently no progress callback in this method
+ double myerval = GDALGetRasterStatistics (
+ myGdalBand,
+ bApproxOK,
+ TRUE,
+ &pdfMin,
+ &pdfMax,
+ &pdfMean,
+ &pdfStdDev
+ );
+ //double myerval = GDALComputeRasterStatistics ( myGdalBand,
+ // bApproxOK,
+ // &pdfMin,
+ // &pdfMax,
+ // &pdfMean,
+ // &pdfStdDev,
+ // progressCallback,
+ // &myProg
+ //) ;
+ //end of first pass through data now calculate the range
+ myRasterBandStats.bandName = generateBandName( theBandNo );
+ myRasterBandStats.bandNumber = theBandNo;
+ myRasterBandStats.range = pdfMax - pdfMin;
+ myRasterBandStats.minimumValue = pdfMin;
+ myRasterBandStats.maximumValue = pdfMax;
+ //calculate the mean
+ myRasterBandStats.mean = pdfMean;
+ myRasterBandStats.sum = 0; //not available via gdal
+ myRasterBandStats.elementCount = mWidth * mHeight;
+ myRasterBandStats.sumOfSquares = 0; //not available via gdal
+ myRasterBandStats.stdDev = pdfStdDev;
+ myRasterBandStats.statsGathered = true;
+
+#ifdef QGISDEBUG
+ QgsLogger::debug( "************ STATS **************", 1, __FILE__, __FUNCTION__, __LINE__ );
+ QgsLogger::debug( "VALID NODATA", mValidNoDataValue, 1, __FILE__, __FUNCTION__, __LINE__ );
+ QgsLogger::debug( "MIN", myRasterBandStats.minimumValue, 1, __FILE__, __FUNCTION__, __LINE__ );
+ QgsLogger::debug( "MAX", myRasterBandStats.maximumValue, 1, __FILE__, __FUNCTION__, __LINE__ );
+ QgsLogger::debug( "RANGE", myRasterBandStats.range, 1, __FILE__, __FUNCTION__, __LINE__ );
+ QgsLogger::debug( "MEAN", myRasterBandStats.mean, 1, __FILE__, __FUNCTION__, __LINE__ );
+ QgsLogger::debug( "STDDEV", myRasterBandStats.stdDev, 1, __FILE__, __FUNCTION__, __LINE__ );
+#endif
+
+ myRasterBandStats.statsGathered = true;
+
+ return myRasterBandStats;
+
+} // QgsGdalProvider::bandStatistics
+
+
/**
Builds the list of file filter strings to later be used by
QgisApp::addRasterLayer()
diff --git a/src/providers/gdal/qgsgdalprovider.h b/src/providers/gdal/qgsgdalprovider.h
index 9d5a24ecd35..db6ed3d93d7 100644
--- a/src/providers/gdal/qgsgdalprovider.h
+++ b/src/providers/gdal/qgsgdalprovider.h
@@ -26,6 +26,7 @@
#include "qgsrasterdataprovider.h"
#include "qgsrectangle.h"
#include "qgscolorrampshader.h"
+#include "qgsrasterbandstats.h"
#include
#include
@@ -222,6 +223,13 @@ class QgsGdalProvider : public QgsRasterDataProvider
/** \brief Returns the sublayers of this layer - Useful for providers that manage their own layers, such as WMS */
QStringList subLayers() const;
+ /** \brief If the provider supports it, return band stats for the
+ given band.
+ @note added in QGIS 1.7
+ @note overloads virtual method from QgsRasterProvider::bandStatistics
+
+ */
+ QgsRasterBandStats bandStatistics( int theBandNo );
void populateHistogram( int theBandNoInt,
QgsRasterBandStats & theBandStats,
diff --git a/tests/src/core/testqgsapplication.cpp b/tests/src/core/testqgsapplication.cpp
index 4490e39aac9..8527eec8d72 100644
--- a/tests/src/core/testqgsapplication.cpp
+++ b/tests/src/core/testqgsapplication.cpp
@@ -41,7 +41,7 @@ void TestQgsApplication::initTestCase()
// init QGIS's paths - true means that all path will be inited from prefix
QString qgisPath = QCoreApplication::applicationDirPath();
QgsApplication::setPrefixPath( INSTALL_PREFIX, true );
- QgsApplication::showSettings();
+ qDebug( QgsApplication::showSettings().toUtf8() );
};
void TestQgsApplication::checkTheme()
diff --git a/tests/src/core/testqgsrasterlayer.cpp b/tests/src/core/testqgsrasterlayer.cpp
index 058b025bed5..d6e0b335035 100644
--- a/tests/src/core/testqgsrasterlayer.cpp
+++ b/tests/src/core/testqgsrasterlayer.cpp
@@ -57,6 +57,7 @@ class TestQgsRasterLayer: public QObject
void landsatBasic();
void landsatBasic875Qml();
void checkDimensions();
+ void checkStats();
void buildExternalOverviews();
void registry();
private:
@@ -73,9 +74,10 @@ class TestQgsRasterLayer: public QObject
void TestQgsRasterLayer::initTestCase()
{
// init QGIS's paths - true means that all path will be inited from prefix
- QString qgisPath = QCoreApplication::applicationDirPath();
- QgsApplication::setPrefixPath( INSTALL_PREFIX, true );
- QgsApplication::showSettings();
+ QgsApplication::init( QString() );
+ QgsApplication::initQgis();
+ QString mySettings = QgsApplication::showSettings();
+ mySettings = mySettings.replace("\n","
");
//create some objects that will be used in all tests...
//create a raster layer that will be used in all tests...
mTestDataDir = QString( TEST_DATA_DIR ) + QDir::separator(); //defined in CmakeLists.txt
@@ -96,6 +98,7 @@ void TestQgsRasterLayer::initTestCase()
myLayers << mpRasterLayer->id();
mpMapRenderer->setLayerSet( myLayers );
mReport += "Raster Layer Tests
\n";
+ mReport += "" + mySettings + "
";
}
//runs after all tests
void TestQgsRasterLayer::cleanupTestCase()
@@ -115,6 +118,7 @@ void TestQgsRasterLayer::cleanupTestCase()
void TestQgsRasterLayer::isValid()
{
QVERIFY( mpRasterLayer->isValid() );
+ mpRasterLayer->setContrastEnhancementAlgorithm( QgsContrastEnhancement::StretchToMinimumMaximum, false );
mpMapRenderer->setExtent( mpRasterLayer->extent() );
QVERIFY( render( "raster" ) );
}
@@ -133,6 +137,7 @@ void TestQgsRasterLayer::pseudoColor()
void TestQgsRasterLayer::landsatBasic()
{
+ mpLandsatRasterLayer->setContrastEnhancementAlgorithm( QgsContrastEnhancement::StretchToMinimumMaximum, false );
QStringList myLayers;
myLayers << mpLandsatRasterLayer->id();
mpMapRenderer->setLayerSet( myLayers );
@@ -156,13 +161,26 @@ void TestQgsRasterLayer::checkDimensions()
// regression check for ticket #832
// note bandStatistics call is base 1
QVERIFY( mpRasterLayer->bandStatistics( 1 ).elementCount == 100 );
+ mReport += "Check Dimensions
\n";
+ mReport += "Passed
";
+}
+void TestQgsRasterLayer::checkStats()
+{
+ QVERIFY( mpRasterLayer->width() == 10 );
+ QVERIFY( mpRasterLayer->height() == 10 );
+ QVERIFY( mpRasterLayer->bandStatistics( 1 ).elementCount == 100 );
+ QVERIFY( mpRasterLayer->bandStatistics( 1 ).minimumValue == 0 );
+ QVERIFY( mpRasterLayer->bandStatistics( 1 ).maximumValue == 9 );
+ QVERIFY( mpRasterLayer->bandStatistics( 1 ).mean == 4.5 );
+ QVERIFY( mpRasterLayer->bandStatistics( 1 ).stdDev == 2.872281323269 );
+ mReport += "Check Stats
\n";
+ mReport += "Passed
";
}
void TestQgsRasterLayer::buildExternalOverviews()
{
//before we begin delete any old ovr file (if it exists)
//and make a copy of the landsat raster into the temp dir
-
QString myTempPath = QDir::tempPath() + QDir::separator();
QFile::remove( myTempPath + "landsat.tif.ovr" );
QFile::copy( mTestDataDir + "landsat.tif", myTempPath + "landsat.tif" );
@@ -205,6 +223,8 @@ void TestQgsRasterLayer::buildExternalOverviews()
QVERIFY( QFile::exists( myTempPath + "landsat.tif.ovr" ) );
//cleanup
delete mypLayer;
+ mReport += "Check Overviews
\n";
+ mReport += "Passed
";
}
diff --git a/tests/testdata/expected_landsat_875.png b/tests/testdata/expected_landsat_875.png
index 7ff32ba87ac..ef2a77b4738 100644
Binary files a/tests/testdata/expected_landsat_875.png and b/tests/testdata/expected_landsat_875.png differ
diff --git a/tests/testdata/expected_landsat_basic.png b/tests/testdata/expected_landsat_basic.png
index b7ed1421ae9..966df40f769 100644
Binary files a/tests/testdata/expected_landsat_basic.png and b/tests/testdata/expected_landsat_basic.png differ
diff --git a/tests/testdata/landsat_875.qml b/tests/testdata/landsat_875.qml
index bdfec09ffaf..c3663289f84 100644
--- a/tests/testdata/landsat_875.qml
+++ b/tests/testdata/landsat_875.qml
@@ -1,73 +1,64 @@
-
-
- landsat_clip20080125220410500
- landsat_clip.tif
- landsat_clip
-
-
- +proj=utm +zone=33 +ellps=WGS84 +datum=WGS84 +units=m +no_defs
- 2267
- 32633
- 32633
- WGS 84 / UTM zone 33N
- utm
- WGS84
- true
-
-
- 255
-
-
-
- MULTI_BAND_COLOR
- UNDEFINED_SHADING_ALGORITHM
-
- 8 : Undefined
- 7 : Undefined
- 5 : Undefined
- Not Set
- 0
- STRETCH_TO_MINMAX
-
-
- 122
- 130
-
-
- 133
- 148
-
-
- 57
- 157
-
-
- 0
- 255
-
-
- 61
- 117
-
-
- 0
- 255
-
-
- 92
- 213
-
-
- 122
- 255
-
-
- 0
- 255
-
-
- -9999.000000
-
-
+
+ 255
+
+ MultiBandColor
+ UndefinedShader
+
+ Band 8
+ Band 7
+ Band 5
+ Band 1
+ 0
+
+
+
+
+ StretchToMinimumMaximum
+
+
+ 0
+ 255
+
+
+ 0
+ 255
+
+
+ 0
+ 255
+
+
+ 0
+ 255
+
+
+ 61
+ 123
+
+
+ 0
+ 255
+
+
+ 92
+ 232
+
+
+ 122
+ 255
+
+
+ 0
+ 255
+
+
+ -32768.000000
+
+
+
+
+
+
+