Regenerated docs post raster-stats merge

This commit is contained in:
Tim Sutton 2011-08-04 10:45:08 +02:00
parent 58c737d930
commit 1c946725c1
17 changed files with 580 additions and 311 deletions

170
CODING
View File

@ -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)

View File

@ -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

View File

@ -45,13 +45,13 @@ pre, code { font-family: monospace }
<DIV CLASS="header" ID="header">
<H1>Quantum GIS (QGIS)</H1>
<H2>Building QGIS from source - step by step</H2>
<H3>Sunday June 12, 2011</H3>
<H3>Thursday August 04, 2011</H3>
</DIV>
<DIV CLASS="body" ID="body">
<P>
Last Updated: Sunday June 12, 2011
Last Change : Sunday June 05, 2011
Last Updated: Thursday August 04, 2011
Last Change : Tuesday June 28, 2011
</P>
<DIV CLASS="toc">

View File

@ -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();

View File

@ -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() );

View File

@ -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 );

View File

@ -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

View File

@ -30,6 +30,7 @@
#include "qgscoordinatereferencesystem.h"
#include "qgsrasterbandstats.h"
#include "cpl_conv.h"
#include <cmath>
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<QgsRasterPyramid> buildPyramidList() { return QList<QgsRasterPyramid>(); };
/** 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

View File

@ -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 );

View File

@ -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++ )

View File

@ -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()

View File

@ -26,6 +26,7 @@
#include "qgsrasterdataprovider.h"
#include "qgsrectangle.h"
#include "qgscolorrampshader.h"
#include "qgsrasterbandstats.h"
#include <QString>
#include <QStringList>
@ -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,

View File

@ -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()

View File

@ -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","<br />");
//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 += "<h1>Raster Layer Tests</h1>\n";
mReport += "<p>" + mySettings + "</p>";
}
//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 += "<h2>Check Dimensions</h2>\n";
mReport += "<p>Passed</p>";
}
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 += "<h2>Check Stats</h2>\n";
mReport += "<p>Passed</p>";
}
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 += "<h2>Check Overviews</h2>\n";
mReport += "<p>Passed</p>";
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 76 KiB

View File

@ -1,73 +1,64 @@
<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
<qgis projectname="" version="0.9.2-Ganymede" >
<maplayer minimumScale="1" maximumScale="1e+08" hasScaleBasedVisibilityFlag="0" type="raster" >
<id>landsat_clip20080125220410500</id>
<datasource>landsat_clip.tif</datasource>
<layername>landsat_clip</layername>
<srs>
<spatialrefsys>
<proj4>+proj=utm +zone=33 +ellps=WGS84 +datum=WGS84 +units=m +no_defs</proj4>
<srsid>2267</srsid>
<srid>32633</srid>
<epsg>32633</epsg>
<description>WGS 84 / UTM zone 33N</description>
<projectionacronym>utm</projectionacronym>
<ellipsoidacronym>WGS84</ellipsoidacronym>
<geographicflag>true</geographicflag>
</spatialrefsys>
</srs>
<transparencyLevelInt>255</transparencyLevelInt>
<provider></provider>
<rasterproperties>
<mDebugOverlayFlag boolean="false" />
<drawingStyle>MULTI_BAND_COLOR</drawingStyle>
<mColorShadingAlgorithm>UNDEFINED_SHADING_ALGORITHM</mColorShadingAlgorithm>
<mInvertPixelsFlag boolean="false" />
<mRedBandName>8 : Undefined</mRedBandName>
<mGreenBandName>7 : Undefined</mGreenBandName>
<mBlueBandName>5 : Undefined</mBlueBandName>
<mGrayBandName>Not Set</mGrayBandName>
<mStandardDeviations>0</mStandardDeviations>
<mContrastEnhancementAlgorithm>STRETCH_TO_MINMAX</mContrastEnhancementAlgorithm>
<contrastEnhancementMinMaxValues>
<minMaxEntry>
<min>122</min>
<max>130</max>
</minMaxEntry>
<minMaxEntry>
<min>133</min>
<max>148</max>
</minMaxEntry>
<minMaxEntry>
<min>57</min>
<max>157</max>
</minMaxEntry>
<minMaxEntry>
<min>0</min>
<max>255</max>
</minMaxEntry>
<minMaxEntry>
<min>61</min>
<max>117</max>
</minMaxEntry>
<minMaxEntry>
<min>0</min>
<max>255</max>
</minMaxEntry>
<minMaxEntry>
<min>92</min>
<max>213</max>
</minMaxEntry>
<minMaxEntry>
<min>122</min>
<max>255</max>
</minMaxEntry>
<minMaxEntry>
<min>0</min>
<max>255</max>
</minMaxEntry>
</contrastEnhancementMinMaxValues>
<mNoDataValue mValidNoDataValue="false" >-9999.000000</mNoDataValue>
</rasterproperties>
</maplayer>
<qgis version="1.8.0-Trunk" minimumScale="0" maximumScale="1e+08" hasScaleBasedVisibilityFlag="0">
<transparencyLevelInt>255</transparencyLevelInt>
<rasterproperties>
<mDrawingStyle>MultiBandColor</mDrawingStyle>
<mColorShadingAlgorithm>UndefinedShader</mColorShadingAlgorithm>
<mInvertColor boolean="false"/>
<mRedBandName>Band 8</mRedBandName>
<mGreenBandName>Band 7</mGreenBandName>
<mBlueBandName>Band 5</mBlueBandName>
<mGrayBandName>Band 1</mGrayBandName>
<mStandardDeviations>0</mStandardDeviations>
<mUserDefinedRGBMinimumMaximum boolean="false"/>
<mRGBMinimumMaximumEstimated boolean="true"/>
<mUserDefinedGrayMinimumMaximum boolean="false"/>
<mGrayMinimumMaximumEstimated boolean="true"/>
<mContrastEnhancementAlgorithm>StretchToMinimumMaximum</mContrastEnhancementAlgorithm>
<contrastEnhancementMinMaxValues>
<minMaxEntry>
<min>0</min>
<max>255</max>
</minMaxEntry>
<minMaxEntry>
<min>0</min>
<max>255</max>
</minMaxEntry>
<minMaxEntry>
<min>0</min>
<max>255</max>
</minMaxEntry>
<minMaxEntry>
<min>0</min>
<max>255</max>
</minMaxEntry>
<minMaxEntry>
<min>61</min>
<max>123</max>
</minMaxEntry>
<minMaxEntry>
<min>0</min>
<max>255</max>
</minMaxEntry>
<minMaxEntry>
<min>92</min>
<max>232</max>
</minMaxEntry>
<minMaxEntry>
<min>122</min>
<max>255</max>
</minMaxEntry>
<minMaxEntry>
<min>0</min>
<max>255</max>
</minMaxEntry>
</contrastEnhancementMinMaxValues>
<mNoDataValue mValidNoDataValue="true">-32768.000000</mNoDataValue>
<singleValuePixelList>
<pixelListEntry pixelValue="-32768.000000" percentTransparent="100"/>
</singleValuePixelList>
<threeValuePixelList>
<pixelListEntry red="-32768.000000" blue="-32768.000000" green="-32768.000000" percentTransparent="100"/>
</threeValuePixelList>
</rasterproperties>
</qgis>