Skip to content

Commit bd273f6

Browse files
committedJan 12, 2012
[FEATURE]: relief and hillshade function, modification of raster terrain structure
1 parent 92de863 commit bd273f6

24 files changed

+2152
-255
lines changed
 

‎src/analysis/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ SET(QGIS_ANALYSIS_SRCS
2626
raster/qgsninecellfilter.cpp
2727
raster/qgsruggednessfilter.cpp
2828
raster/qgsderivativefilter.cpp
29+
raster/qgshillshadefilter.cpp
2930
raster/qgsslopefilter.cpp
3031
raster/qgsaspectfilter.cpp
3132
raster/qgstotalcurvaturefilter.cpp
33+
raster/qgsrelief.cpp
3234
raster/qgsrastercalcnode.cpp
3335
raster/qgsrastercalculator.cpp
3436
raster/qgsrastermatrix.cpp

‎src/analysis/raster/qgsaspectfilter.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,11 @@ class ANALYSIS_EXPORT QgsAspectFilter: public QgsDerivativeFilter
2727
QgsAspectFilter( const QString& inputFile, const QString& outputFile, const QString& outputFormat );
2828
~QgsAspectFilter();
2929

30-
protected:
31-
protected:
32-
/**Calculates output value from nine input values. The input values and the output value can be equal to the
30+
/**Calculates output value from nine input values. The input values and the output value can be equal to the \
3331
nodata value if not present or outside of the border. Must be implemented by subclasses*/
34-
float processNineCellWindow( float* x11, float* x21, float* x31,
35-
float* x12, float* x22, float* x32,
36-
float* x13, float* x23, float* x33 );
32+
float processNineCellWindow( float* x11, float* x21, float* x31, \
33+
float* x12, float* x22, float* x32, float* x13, float* x23, float* x33 );
34+
3735
};
3836

3937
#endif // QGSASPECTFILTER_H

‎src/analysis/raster/qgsderivativefilter.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717

1818
#include "qgsderivativefilter.h"
1919

20-
QgsDerivativeFilter::QgsDerivativeFilter( const QString& inputFile, const QString& outputFile, const QString& outputFormat )
21-
: QgsNineCellFilter( inputFile, outputFile, outputFormat )
20+
QgsDerivativeFilter::QgsDerivativeFilter( const QString& inputFile, const QString& outputFile, const QString& outputFormat ): \
21+
QgsNineCellFilter( inputFile, outputFile, outputFormat )
2222
{
2323

2424
}
@@ -92,7 +92,7 @@ float QgsDerivativeFilter::calcFirstDerX( float* x11, float* x21, float* x31, fl
9292
return mOutputNodataValue;
9393
}
9494

95-
return sum / ( weight * mCellSizeX );
95+
return sum / ( weight * mCellSizeX * mZFactor );
9696
}
9797

9898
float QgsDerivativeFilter::calcFirstDerY( float* x11, float* x21, float* x31, float* x12, float* x22, float* x32, float* x13, float* x23, float* x33 )
@@ -159,7 +159,7 @@ float QgsDerivativeFilter::calcFirstDerY( float* x11, float* x21, float* x31, fl
159159
return mOutputNodataValue;
160160
}
161161

162-
return sum / ( weight * mCellSizeY );
162+
return sum / ( weight * mCellSizeY * mZFactor );
163163
}
164164

165165

‎src/analysis/raster/qgsderivativefilter.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,8 @@ class QgsDerivativeFilter: public QgsNineCellFilter
2727
QgsDerivativeFilter( const QString& inputFile, const QString& outputFile, const QString& outputFormat );
2828
virtual ~QgsDerivativeFilter();
2929
//to be implemented by subclasses
30-
virtual float processNineCellWindow( float* x11, float* x21, float* x31,
31-
float* x12, float* x22, float* x32,
32-
float* x13, float* x23, float* x33 ) = 0;
30+
virtual float processNineCellWindow( float* x11, float* x21, float* x31, float* x12, float* x22, \
31+
float* x32, float* x13, float* x23, float* x33 ) = 0;
3332

3433
protected:
3534
/**Calculates the first order derivative in x-direction according to Horn (1981)*/
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/***************************************************************************
2+
qgshillshadefilter.h - description
3+
--------------------------------
4+
begin : September 26th, 2011
5+
copyright : (C) 2011 by Marco Hugentobler
6+
email : marco dot hugentobler at sourcepole dot ch
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#include "qgshillshadefilter.h"
19+
20+
QgsHillshadeFilter::QgsHillshadeFilter( const QString& inputFile, const QString& outputFile, const QString& outputFormat, double lightAzimuth,
21+
double lightAngle): \
22+
QgsDerivativeFilter( inputFile, outputFile, outputFormat ), mLightAzimuth( lightAzimuth ), mLightAngle( lightAngle )
23+
{
24+
}
25+
26+
QgsHillshadeFilter::~QgsHillshadeFilter()
27+
{
28+
}
29+
30+
float QgsHillshadeFilter::processNineCellWindow( float* x11, float* x21, float* x31, \
31+
float* x12, float* x22, float* x32, float* x13, float* x23, float* x33 )
32+
{
33+
float derX = calcFirstDerX( x11, x21, x31, x12, x22, x32, x13, x23, x33 );
34+
float derY = calcFirstDerY( x11, x21, x31, x12, x22, x32, x13, x23, x33 );
35+
36+
if ( derX == mOutputNodataValue || derY == mOutputNodataValue )
37+
{
38+
return mOutputNodataValue;
39+
}
40+
41+
float zenith_rad = mLightAngle * M_PI / 180.0;
42+
float slope_rad = atan( sqrt( derX * derX + derY * derY ) );
43+
float azimuth_rad = mLightAzimuth * M_PI / 180.0;
44+
float aspect_rad = 0;
45+
if( derX == 0 && derY == 0 ) //aspect undefined, take a neutral value. Better solutions?
46+
{
47+
aspect_rad = azimuth_rad / 2.0;
48+
}
49+
else
50+
{
51+
aspect_rad = M_PI + atan2( derX, derY );
52+
}
53+
return qMax( 0.0, 255.0 * ( ( cos( zenith_rad ) * cos( slope_rad ) ) + ( sin( zenith_rad ) * sin( slope_rad ) * cos( azimuth_rad - aspect_rad ) ) ) );
54+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/***************************************************************************
2+
qgshillshadefilter.h - description
3+
--------------------------------
4+
begin : September 26th, 2011
5+
copyright : (C) 2011 by Marco Hugentobler
6+
email : marco dot hugentobler at sourcepole dot ch
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#ifndef QGSHILLSHADEFILTER_H
19+
#define QGSHILLSHADEFILTER_H
20+
21+
#include "qgsderivativefilter.h"
22+
23+
class ANALYSIS_EXPORT QgsHillshadeFilter: public QgsDerivativeFilter
24+
{
25+
public:
26+
QgsHillshadeFilter( const QString& inputFile, const QString& outputFile, const QString& outputFormat, double lightAzimuth = 300,
27+
double lightAngle = 40 );
28+
~QgsHillshadeFilter();
29+
30+
/**Calculates output value from nine input values. The input values and the output value can be equal to the \
31+
nodata value if not present or outside of the border. Must be implemented by subclasses*/
32+
float processNineCellWindow( float* x11, float* x21, float* x31, \
33+
float* x12, float* x22, float* x32, float* x13, float* x23, float* x33 );
34+
35+
float lightAzimuth() const { return mLightAzimuth; }
36+
void setLightAzimuth( float azimuth ){ mLightAzimuth = azimuth; }
37+
float lightAngle() const { return mLightAngle; }
38+
void setLightAngle( float angle ){ mLightAngle = angle; }
39+
40+
private:
41+
float mLightAzimuth;
42+
float mLightAngle;
43+
};
44+
45+
#endif // QGSHILLSHADEFILTER_H

‎src/analysis/raster/qgsninecellfilter.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@
2525
#define TO8(x) (x).toLocal8Bit().constData()
2626
#endif
2727

28-
QgsNineCellFilter::QgsNineCellFilter( const QString& inputFile, const QString& outputFile, const QString& outputFormat )
29-
: mInputFile( inputFile ), mOutputFile( outputFile ), mOutputFormat( outputFormat ), mCellSizeX( -1 ), mCellSizeY( -1 ), mInputNodataValue( -1 ), mOutputNodataValue( -1 )
28+
QgsNineCellFilter::QgsNineCellFilter( const QString& inputFile, const QString& outputFile, const QString& outputFormat ): \
29+
mInputFile( inputFile ), mOutputFile( outputFile ), mOutputFormat( outputFormat ), mCellSizeX( -1 ), mCellSizeY( -1 ), \
30+
mInputNodataValue( -1 ), mOutputNodataValue( -1 ), mZFactor( 1.0/*111120*/ )
3031
{
3132

3233
}
@@ -153,17 +154,17 @@ int QgsNineCellFilter::processRaster( QProgressDialog* p )
153154
{
154155
if ( j == 0 )
155156
{
156-
resultLine[j] = processNineCellWindow( &mInputNodataValue, &scanLine1[j], &scanLine1[j+1], &mInputNodataValue, &scanLine2[j],
157+
resultLine[j] = processNineCellWindow( &mInputNodataValue, &scanLine1[j], &scanLine1[j+1], &mInputNodataValue, &scanLine2[j], \
157158
&scanLine2[j+1], &mInputNodataValue, &scanLine3[j], &scanLine3[j+1] );
158159
}
159160
else if ( j == xSize - 1 )
160161
{
161-
resultLine[j] = processNineCellWindow( &scanLine1[j-1], &scanLine1[j], &mInputNodataValue, &scanLine2[j-1], &scanLine2[j],
162+
resultLine[j] = processNineCellWindow( &scanLine1[j-1], &scanLine1[j], &mInputNodataValue, &scanLine2[j-1], &scanLine2[j], \
162163
&mInputNodataValue, &scanLine3[j-1], &scanLine3[j], &mInputNodataValue );
163164
}
164165
else
165166
{
166-
resultLine[j] = processNineCellWindow( &scanLine1[j-1], &scanLine1[j], &scanLine1[j+1], &scanLine2[j-1], &scanLine2[j],
167+
resultLine[j] = processNineCellWindow( &scanLine1[j-1], &scanLine1[j], &scanLine1[j+1], &scanLine2[j-1], &scanLine2[j], \
167168
&scanLine2[j+1], &scanLine3[j-1], &scanLine3[j], &scanLine3[j+1] );
168169
}
169170
}

‎src/analysis/raster/qgsninecellfilter.h

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323

2424
class QProgressDialog;
2525

26-
/**Base class for raster analysis methods that work with a 3x3 cell filter and calculate the value of each cell based on
27-
the cell value and the eight neighbour cells. Common examples are slope and aspect calculation in DEMs. Subclasses only implement
26+
/**Base class for raster analysis methods that work with a 3x3 cell filter and calculate the value of each cell based on \
27+
the cell value and the eight neighbour cells. Common examples are slope and aspect calculation in DEMs. Subclasses only implement \
2828
the method that calculates the new value from the nine values. Everything else (reading file, writing file) is done by this subclass*/
2929

3030
class ANALYSIS_EXPORT QgsNineCellFilter
@@ -38,6 +38,24 @@ class ANALYSIS_EXPORT QgsNineCellFilter
3838
@return 0 in case of success*/
3939
int processRaster( QProgressDialog* p );
4040

41+
double cellSizeX() const { return mCellSizeX; }
42+
void setCellSizeX( double size ) { mCellSizeX = size; }
43+
double cellSizeY() const { return mCellSizeY; }
44+
void setCellSizeY( double size ) { mCellSizeY = size; }
45+
46+
double zFactor() const { return mZFactor; }
47+
void setZFactor( double factor ) { mZFactor = factor; }
48+
49+
double inputNodataValue() const { return mInputNodataValue; }
50+
void setInputNodataValue( double value ){ mInputNodataValue = value; }
51+
double outputNodataValue() const { return mOutputNodataValue; }
52+
void setOutputNodataValue( double value ){ mOutputNodataValue = value; }
53+
54+
/**Calculates output value from nine input values. The input values and the output value can be equal to the \
55+
nodata value if not present or outside of the border. Must be implemented by subclasses*/
56+
virtual float processNineCellWindow( float* x11, float* x21, float* x31, \
57+
float* x12, float* x22, float* x32, float* x13, float* x23, float* x33 ) = 0;
58+
4159
private:
4260
//default constructor forbidden. We need input file, output file and format obligatory
4361
QgsNineCellFilter();
@@ -52,11 +70,6 @@ class ANALYSIS_EXPORT QgsNineCellFilter
5270
GDALDatasetH openOutputFile( GDALDatasetH inputDataset, GDALDriverH outputDriver );
5371

5472
protected:
55-
/**Calculates output value from nine input values. The input values and the output value can be equal to the
56-
nodata value if not present or outside of the border. Must be implemented by subclasses*/
57-
virtual float processNineCellWindow( float* x11, float* x21, float* x31,
58-
float* x12, float* x22, float* x32,
59-
float* x13, float* x23, float* x33 ) = 0;
6073

6174
QString mInputFile;
6275
QString mOutputFile;
@@ -68,6 +81,8 @@ class ANALYSIS_EXPORT QgsNineCellFilter
6881
float mInputNodataValue;
6982
/**The nodata value of the output layer*/
7083
float mOutputNodataValue;
84+
/**Scale factor for z-value if x-/y- units are different to z-units (111120 for degree->meters and 370400 for degree->feet)*/
85+
double mZFactor;
7186
};
7287

7388
#endif // QGSNINECELLFILTER_H

‎src/analysis/raster/qgsrelief.cpp

Lines changed: 766 additions & 0 deletions
Large diffs are not rendered by default.

‎src/analysis/raster/qgsrelief.h

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#ifndef QGSRELIEF_H
2+
#define QGSRELIEF_H
3+
4+
#include <QColor>
5+
#include <QMap>
6+
#include <QPair>
7+
#include <QString>
8+
#include "gdal.h"
9+
10+
class QgsAspectFilter;
11+
class QgsSlopeFilter;
12+
class QgsHillshadeFilter;
13+
class QProgressDialog;
14+
15+
/**Produces coloured relief rasters from DEM*/
16+
class ANALYSIS_EXPORT QgsRelief
17+
{
18+
public:
19+
struct ReliefColor
20+
{
21+
ReliefColor( const QColor& c, double min, double max ): color( c ), minElevation( min ), maxElevation( max ) { }
22+
QColor color;
23+
double minElevation;
24+
double maxElevation;
25+
};
26+
27+
QgsRelief( const QString& inputFile, const QString& outputFile, const QString& outputFormat );
28+
~QgsRelief();
29+
30+
/**Starts the calculation, reads from mInputFile and stores the result in mOutputFile
31+
@param p progress dialog that receives update and that is checked for abort. 0 if no progress bar is needed.
32+
@return 0 in case of success*/
33+
int processRaster( QProgressDialog* p );
34+
35+
double zFactor() const { return mZFactor; }
36+
void setZFactor( double factor ) { mZFactor = factor; }
37+
38+
void clearReliefColors();
39+
void addReliefColorClass( const ReliefColor& color );
40+
const QList< ReliefColor >& reliefColors() const { return mReliefColors; }
41+
void setReliefColors( const QList< ReliefColor >& c ) { mReliefColors = c; }
42+
43+
/**Calculates class breaks according with the method of Buenzli (2011) using an iterative algorithm for segmented regression
44+
@return true in case of success*/
45+
QList< ReliefColor > calculateOptimizedReliefClasses();
46+
47+
/**Write frequency of elevation values to file for manual inspection*/
48+
bool exportFrequencyDistributionToCsv( const QString& file );
49+
50+
private:
51+
52+
QString mInputFile;
53+
QString mOutputFile;
54+
QString mOutputFormat;
55+
56+
double mCellSizeX;
57+
double mCellSizeY;
58+
/**The nodata value of the input layer*/
59+
float mInputNodataValue;
60+
/**The nodata value of the output layer*/
61+
float mOutputNodataValue;
62+
63+
double mZFactor;
64+
65+
QgsSlopeFilter* mSlopeFilter;
66+
QgsAspectFilter* mAspectFilter;
67+
QgsHillshadeFilter* mHillshadeFilter285;
68+
QgsHillshadeFilter* mHillshadeFilter300;
69+
QgsHillshadeFilter* mHillshadeFilter315;
70+
71+
//relief colors and corresponding elevations
72+
QList< ReliefColor > mReliefColors;
73+
74+
bool processNineCellWindow( float* x1, float* x2, float* x3, float* x4, float* x5, float* x6, float* x7, float* x8, float* x9,
75+
int* red, int* green, int* blue );
76+
77+
/**Opens the input file and returns the dataset handle and the number of pixels in x-/y- direction*/
78+
GDALDatasetH openInputFile( int& nCellsX, int& nCellsY );
79+
/**Opens the output driver and tests if it supports the creation of a new dataset
80+
@return NULL on error and the driver handle on success*/
81+
GDALDriverH openOutputDriver();
82+
/**Opens the output file and sets the same geotransform and CRS as the input data
83+
@return the output dataset or NULL in case of error*/
84+
GDALDatasetH openOutputFile( GDALDatasetH inputDataset, GDALDriverH outputDriver );
85+
86+
/**Set elevation color*/
87+
bool setElevationColor( double elevation, int* red, int* green, int* blue );
88+
89+
/**Sets relief colors*/
90+
void setDefaultReliefColors();
91+
/**Returns class (0-255) for an elevation value
92+
@return elevation class or -1 in case of error*/
93+
int frequencyClassForElevation( double elevation, double minElevation, double elevationClassRange );
94+
/**Do one iteration of class break optimisation (algorithm from Garcia and Rodriguez)*/
95+
void optimiseClassBreaks( QList<int>& breaks, double* frequencies );
96+
/**Calculates coefficients a (slope) and b (y value for x=0)
97+
@param input data points ( elevation class / frequency )*/
98+
bool calculateRegression( const QList< QPair < int, double > >& input, double& a, double& b );
99+
};
100+
101+
#endif // QGSRELIEF_H

‎src/analysis/raster/qgsruggednessfilter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ QgsRuggednessFilter::~QgsRuggednessFilter()
3333

3434
}
3535

36-
float QgsRuggednessFilter::processNineCellWindow( float* x11, float* x21, float* x31,
36+
float QgsRuggednessFilter::processNineCellWindow( float* x11, float* x21, float* x31, \
3737
float* x12, float* x22, float* x32, float* x13, float* x23, float* x33 )
3838
{
3939
//the formula would be that easy without nodata values...

‎src/analysis/raster/qgsruggednessfilter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class ANALYSIS_EXPORT QgsRuggednessFilter: public QgsNineCellFilter
2929
~QgsRuggednessFilter();
3030

3131
protected:
32-
/**Calculates output value from nine input values. The input values and the output value can be equal to the
32+
/**Calculates output value from nine input values. The input values and the output value can be equal to the \
3333
nodata value if not present or outside of the border. Must be implemented by subclasses*/
3434
float processNineCellWindow( float* x11, float* x21, float* x31, \
3535
float* x12, float* x22, float* x32, float* x13, float* x23, float* x33 );

‎src/analysis/raster/qgsslopefilter.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717

1818
#include "qgsslopefilter.h"
1919

20-
QgsSlopeFilter::QgsSlopeFilter( const QString& inputFile, const QString& outputFile, const QString& outputFormat )
21-
: QgsDerivativeFilter( inputFile, outputFile, outputFormat )
20+
QgsSlopeFilter::QgsSlopeFilter( const QString& inputFile, const QString& outputFile, const QString& outputFormat ): \
21+
QgsDerivativeFilter( inputFile, outputFile, outputFormat )
2222
{
2323

2424
}
@@ -28,7 +28,7 @@ QgsSlopeFilter::~QgsSlopeFilter()
2828

2929
}
3030

31-
float QgsSlopeFilter::processNineCellWindow( float* x11, float* x21, float* x31,
31+
float QgsSlopeFilter::processNineCellWindow( float* x11, float* x21, float* x31, \
3232
float* x12, float* x22, float* x32, float* x13, float* x23, float* x33 )
3333
{
3434
float derX = calcFirstDerX( x11, x21, x31, x12, x22, x32, x13, x23, x33 );

‎src/analysis/raster/qgsslopefilter.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,10 @@ class ANALYSIS_EXPORT QgsSlopeFilter: public QgsDerivativeFilter
2727
QgsSlopeFilter( const QString& inputFile, const QString& outputFile, const QString& outputFormat );
2828
~QgsSlopeFilter();
2929

30-
protected:
31-
/**Calculates output value from nine input values. The input values and the output value can be equal to the
30+
/**Calculates output value from nine input values. The input values and the output value can be equal to the \
3231
nodata value if not present or outside of the border. Must be implemented by subclasses*/
33-
float processNineCellWindow( float* x11, float* x21, float* x31,
34-
float* x12, float* x22, float* x32,
35-
float* x13, float* x23, float* x33 );
32+
float processNineCellWindow( float* x11, float* x21, float* x31, \
33+
float* x12, float* x22, float* x32, float* x13, float* x23, float* x33 );
3634
};
3735

3836
#endif // QGSSLOPEFILTER_H

‎src/analysis/raster/qgstotalcurvaturefilter.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717

1818
#include "qgstotalcurvaturefilter.h"
1919

20-
QgsTotalCurvatureFilter::QgsTotalCurvatureFilter( const QString& inputFile, const QString& outputFile, const QString& outputFormat )
21-
: QgsNineCellFilter( inputFile, outputFile, outputFormat )
20+
QgsTotalCurvatureFilter::QgsTotalCurvatureFilter( const QString& inputFile, const QString& outputFile, const QString& outputFormat ): \
21+
QgsNineCellFilter( inputFile, outputFile, outputFormat )
2222
{
2323

2424
}
@@ -28,12 +28,12 @@ QgsTotalCurvatureFilter::~QgsTotalCurvatureFilter()
2828

2929
}
3030

31-
float QgsTotalCurvatureFilter::processNineCellWindow( float* x11, float* x21, float* x31, float* x12,
31+
float QgsTotalCurvatureFilter::processNineCellWindow( float* x11, float* x21, float* x31, float* x12, \
3232
float* x22, float* x32, float* x13, float* x23, float* x33 )
3333
{
3434
//return nodata if one value is the nodata value
35-
if ( *x11 == mInputNodataValue || *x21 == mInputNodataValue || *x31 == mInputNodataValue || *x12 == mInputNodataValue
36-
|| *x22 == mInputNodataValue || *x32 == mInputNodataValue || *x13 == mInputNodataValue || *x23 == mInputNodataValue
35+
if ( *x11 == mInputNodataValue || *x21 == mInputNodataValue || *x31 == mInputNodataValue || *x12 == mInputNodataValue \
36+
|| *x22 == mInputNodataValue || *x32 == mInputNodataValue || *x13 == mInputNodataValue || *x23 == mInputNodataValue \
3737
|| *x33 == mInputNodataValue )
3838
{
3939
return mOutputNodataValue;

‎src/analysis/raster/qgstotalcurvaturefilter.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,10 @@ class ANALYSIS_EXPORT QgsTotalCurvatureFilter: public QgsNineCellFilter
2828
~QgsTotalCurvatureFilter();
2929

3030
protected:
31-
/**Calculates total curvature from nine input values. The input values and the output value can be equal to the
31+
/**Calculates total curvature from nine input values. The input values and the output value can be equal to the \
3232
nodata value if not present or outside of the border. Must be implemented by subclasses*/
33-
float processNineCellWindow( float* x11, float* x21, float* x31,
34-
float* x12, float* x22, float* x32,
35-
float* x13, float* x23, float* x33 );
33+
float processNineCellWindow( float* x11, float* x21, float* x31, \
34+
float* x12, float* x22, float* x32, float* x13, float* x23, float* x33 );
3635
};
3736

3837
#endif // QGSTOTALCURVATUREFILTER_H

‎src/plugins/raster_terrain_analysis/qgsrasterterrainanalysisdialog.cpp

Lines changed: 262 additions & 71 deletions
Large diffs are not rendered by default.
Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,51 @@
1-
/***************************************************************************
2-
qgsrasterterrainanalysisdialog.h - description
3-
-----------------------------
4-
begin : August 8th, 2009
5-
copyright : (C) 2009 by Marco Hugentobler
6-
email : marco dot hugentobler at karto dot baug dot ethz dot ch
7-
***************************************************************************/
8-
9-
/***************************************************************************
10-
* *
11-
* This program is free software; you can redistribute it and/or modify *
12-
* it under the terms of the GNU General Public License as published by *
13-
* the Free Software Foundation; either version 2 of the License, or *
14-
* (at your option) any later version. *
15-
* *
16-
***************************************************************************/
17-
181
#ifndef QGSRASTERTERRAINANALYSISDIALOG_H
192
#define QGSRASTERTERRAINANALYSISDIALOG_H
203

214
#include "ui_qgsrasterterrainanalysisdialogbase.h"
22-
23-
class QgisInterface;
5+
#include "qgsrelief.h"
246

257
class QgsRasterTerrainAnalysisDialog: public QDialog, private Ui::QgsRasterTerrainAnalysisDialogBase
268
{
279
Q_OBJECT
2810
public:
29-
QgsRasterTerrainAnalysisDialog( QgisInterface* iface, QWidget* parent = 0 );
11+
12+
enum DisplayMode
13+
{
14+
NoParameter,
15+
HillshadeInput,
16+
ReliefInput
17+
};
18+
19+
QgsRasterTerrainAnalysisDialog( DisplayMode mode = NoParameter, QWidget * parent = 0, Qt::WindowFlags f = 0 );
3020
~QgsRasterTerrainAnalysisDialog();
3121

32-
QString selectedInputLayerId() const;
33-
QString selectedDriverKey() const;
34-
QString selectedOuputFilePath() const;
35-
QString selectedAnalysisMethod() const;
36-
bool addLayerToProject() const;
22+
QList< QgsRelief::ReliefColor > reliefColors() const;
23+
QString inputFile() const;
24+
QString outputFile() const;
25+
QString outputFormat() const;
26+
27+
bool addResultToProject() const;
28+
double zFactor() const;
29+
double lightAzimuth() const;
30+
double lightAngle() const;
3731

3832
private slots:
3933
void on_mOutputLayerLineEdit_textChanged( const QString& text );
40-
void on_mOutputLayerPushButton_clicked();
34+
void on_mAutomaticColorButton_clicked();
35+
void on_mOutputLayerToolButton_clicked();
36+
void on_mAddClassButton_clicked();
37+
void on_mRemoveClassButton_clicked();
38+
void on_mUpPushButton_clicked();
39+
void on_mDownPushButton_clicked();
40+
void on_mReliefClassTreeWidget_itemDoubleClicked( QTreeWidgetItem* item, int column );
41+
void on_mExportToCsvButton_clicked();
42+
void on_mExportColorsButton_clicked();
43+
void on_mImportColorsButton_clicked();
4144
void on_mButtonBox_accepted();
4245

4346
private:
44-
QgisInterface* mIface;
45-
4647
/**Stores relation between driver name and extension*/
4748
QMap<QString, QString> mDriverExtensionMap;
4849
};
4950

50-
#endif // QGSRASTERTERRAINANALYSISDIALOG_H
51+
#endif //QGSRASTERTERRAINANALYSISDIALOG_H

‎src/plugins/raster_terrain_analysis/qgsrasterterrainanalysisdialogbase.ui

Lines changed: 162 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -6,100 +6,209 @@
66
<rect>
77
<x>0</x>
88
<y>0</y>
9-
<width>355</width>
10-
<height>176</height>
9+
<width>492</width>
10+
<height>473</height>
1111
</rect>
1212
</property>
1313
<property name="windowTitle">
14-
<string>Raster based terrain analysis</string>
14+
<string>Dialog</string>
1515
</property>
16-
<layout class="QGridLayout" name="gridLayout">
16+
<layout class="QGridLayout" name="gridLayout_3">
1717
<item row="0" column="0">
18-
<widget class="QLabel" name="mAnalysisLabel">
18+
<widget class="QLabel" name="mElevationLayerLabel">
1919
<property name="text">
20-
<string>Analysis</string>
21-
</property>
22-
<property name="buddy">
23-
<cstring>mAnalysisComboBox</cstring>
20+
<string>Elevation layer</string>
2421
</property>
2522
</widget>
2623
</item>
2724
<item row="0" column="1" colspan="2">
28-
<widget class="QComboBox" name="mAnalysisComboBox">
29-
<property name="sizePolicy">
30-
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
31-
<horstretch>0</horstretch>
32-
<verstretch>0</verstretch>
33-
</sizepolicy>
34-
</property>
35-
</widget>
25+
<widget class="QComboBox" name="mElevationLayerComboBox"/>
3626
</item>
3727
<item row="1" column="0">
38-
<widget class="QLabel" name="mInputLayerLabel">
39-
<property name="text">
40-
<string>Input layer</string>
41-
</property>
42-
<property name="buddy">
43-
<cstring>mInputLayerComboBox</cstring>
44-
</property>
45-
</widget>
46-
</item>
47-
<item row="1" column="1" colspan="2">
48-
<widget class="QComboBox" name="mInputLayerComboBox"/>
49-
</item>
50-
<item row="2" column="0">
5128
<widget class="QLabel" name="mOutputLayerLabel">
5229
<property name="text">
5330
<string>Output layer</string>
5431
</property>
55-
<property name="buddy">
56-
<cstring>mOutputLayerPushButton</cstring>
57-
</property>
5832
</widget>
5933
</item>
60-
<item row="2" column="1">
34+
<item row="1" column="1">
6135
<widget class="QLineEdit" name="mOutputLayerLineEdit"/>
6236
</item>
63-
<item row="2" column="2">
64-
<widget class="QPushButton" name="mOutputLayerPushButton">
65-
<property name="sizePolicy">
66-
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
67-
<horstretch>0</horstretch>
68-
<verstretch>0</verstretch>
69-
</sizepolicy>
70-
</property>
71-
<property name="minimumSize">
72-
<size>
73-
<width>20</width>
74-
<height>0</height>
75-
</size>
76-
</property>
37+
<item row="1" column="2">
38+
<widget class="QToolButton" name="mOutputLayerToolButton">
7739
<property name="text">
7840
<string>...</string>
7941
</property>
8042
</widget>
8143
</item>
82-
<item row="3" column="0">
44+
<item row="2" column="0">
8345
<widget class="QLabel" name="mOutputFormatLabel">
8446
<property name="text">
8547
<string>Output format</string>
8648
</property>
87-
<property name="buddy">
88-
<cstring>mOutputFormatComboBox</cstring>
49+
</widget>
50+
</item>
51+
<item row="2" column="1" colspan="2">
52+
<widget class="QComboBox" name="mOutputFormatComboBox"/>
53+
</item>
54+
<item row="3" column="0">
55+
<widget class="QLabel" name="mZFactorLabel">
56+
<property name="text">
57+
<string>Z factor</string>
8958
</property>
9059
</widget>
9160
</item>
9261
<item row="3" column="1" colspan="2">
93-
<widget class="QComboBox" name="mOutputFormatComboBox"/>
62+
<widget class="QLineEdit" name="mZFactorLineEdit"/>
9463
</item>
95-
<item row="4" column="0" colspan="3">
64+
<item row="4" column="0">
9665
<widget class="QCheckBox" name="mAddResultToProjectCheckBox">
9766
<property name="text">
9867
<string>Add result to project</string>
9968
</property>
10069
</widget>
10170
</item>
10271
<item row="5" column="0" colspan="3">
72+
<widget class="QGroupBox" name="mIlluminationGroupBox">
73+
<property name="title">
74+
<string>Illumination</string>
75+
</property>
76+
<layout class="QGridLayout" name="gridLayout_2">
77+
<item row="0" column="0">
78+
<widget class="QLabel" name="mLightAzimuthLabel">
79+
<property name="text">
80+
<string>Azimuth (horizontal angle)</string>
81+
</property>
82+
</widget>
83+
</item>
84+
<item row="0" column="1">
85+
<widget class="QDoubleSpinBox" name="mLightAzimuthAngleSpinBox">
86+
<property name="maximum">
87+
<double>360.000000000000000</double>
88+
</property>
89+
<property name="value">
90+
<double>300.000000000000000</double>
91+
</property>
92+
</widget>
93+
</item>
94+
<item row="1" column="0">
95+
<widget class="QLabel" name="mLightVerticalAngleLabel">
96+
<property name="text">
97+
<string>Vertical angle</string>
98+
</property>
99+
</widget>
100+
</item>
101+
<item row="1" column="1">
102+
<widget class="QDoubleSpinBox" name="mLightVerticalAngleSpinBox">
103+
<property name="maximum">
104+
<double>90.000000000000000</double>
105+
</property>
106+
<property name="value">
107+
<double>40.000000000000000</double>
108+
</property>
109+
</widget>
110+
</item>
111+
</layout>
112+
</widget>
113+
</item>
114+
<item row="6" column="0" colspan="3">
115+
<widget class="QGroupBox" name="mReliefColorsGroupBox">
116+
<property name="title">
117+
<string>Relief colors</string>
118+
</property>
119+
<layout class="QGridLayout" name="gridLayout">
120+
<item row="0" column="0" colspan="2">
121+
<widget class="QPushButton" name="mAutomaticColorButton">
122+
<property name="text">
123+
<string>Create automatically</string>
124+
</property>
125+
</widget>
126+
</item>
127+
<item row="0" column="2">
128+
<widget class="QPushButton" name="mExportToCsvButton">
129+
<property name="text">
130+
<string>Export distribution...</string>
131+
</property>
132+
</widget>
133+
</item>
134+
<item row="0" column="3">
135+
<spacer name="horizontalSpacer">
136+
<property name="orientation">
137+
<enum>Qt::Horizontal</enum>
138+
</property>
139+
<property name="sizeHint" stdset="0">
140+
<size>
141+
<width>268</width>
142+
<height>20</height>
143+
</size>
144+
</property>
145+
</spacer>
146+
</item>
147+
<item row="0" column="4">
148+
<widget class="QPushButton" name="mUpPushButton">
149+
<property name="text">
150+
<string>Up</string>
151+
</property>
152+
</widget>
153+
</item>
154+
<item row="0" column="5">
155+
<widget class="QPushButton" name="mDownPushButton">
156+
<property name="text">
157+
<string>Down</string>
158+
</property>
159+
</widget>
160+
</item>
161+
<item row="0" column="6">
162+
<widget class="QPushButton" name="mAddClassButton">
163+
<property name="text">
164+
<string>+</string>
165+
</property>
166+
</widget>
167+
</item>
168+
<item row="0" column="7">
169+
<widget class="QPushButton" name="mRemoveClassButton">
170+
<property name="text">
171+
<string>-</string>
172+
</property>
173+
</widget>
174+
</item>
175+
<item row="1" column="0" colspan="8">
176+
<widget class="QTreeWidget" name="mReliefClassTreeWidget">
177+
<column>
178+
<property name="text">
179+
<string>Lower bound</string>
180+
</property>
181+
</column>
182+
<column>
183+
<property name="text">
184+
<string>Upper bound</string>
185+
</property>
186+
</column>
187+
<column>
188+
<property name="text">
189+
<string>Color</string>
190+
</property>
191+
</column>
192+
</widget>
193+
</item>
194+
<item row="2" column="0">
195+
<widget class="QPushButton" name="mExportColorsButton">
196+
<property name="text">
197+
<string>Export colors...</string>
198+
</property>
199+
</widget>
200+
</item>
201+
<item row="2" column="1" colspan="2">
202+
<widget class="QPushButton" name="mImportColorsButton">
203+
<property name="text">
204+
<string>Import colors...</string>
205+
</property>
206+
</widget>
207+
</item>
208+
</layout>
209+
</widget>
210+
</item>
211+
<item row="7" column="0" colspan="2">
103212
<widget class="QDialogButtonBox" name="mButtonBox">
104213
<property name="orientation">
105214
<enum>Qt::Horizontal</enum>
@@ -111,15 +220,6 @@
111220
</item>
112221
</layout>
113222
</widget>
114-
<tabstops>
115-
<tabstop>mAnalysisComboBox</tabstop>
116-
<tabstop>mInputLayerComboBox</tabstop>
117-
<tabstop>mOutputLayerLineEdit</tabstop>
118-
<tabstop>mOutputLayerPushButton</tabstop>
119-
<tabstop>mOutputFormatComboBox</tabstop>
120-
<tabstop>mAddResultToProjectCheckBox</tabstop>
121-
<tabstop>mButtonBox</tabstop>
122-
</tabstops>
123223
<resources/>
124224
<connections>
125225
<connection>

‎src/plugins/raster_terrain_analysis/qgsrasterterrainanalysisplugin.cpp

Lines changed: 124 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,25 @@
2121
#include "qgsmaplayer.h"
2222
#include "qgsmaplayerregistry.h"
2323
#include "qgsaspectfilter.h"
24+
#include "qgshillshadefilter.h"
2425
#include "qgsslopefilter.h"
2526
#include "qgsruggednessfilter.h"
2627
#include "qgstotalcurvaturefilter.h"
28+
#include "qgsrelief.h"
2729
#include "qgsrasterterrainanalysisdialog.h"
2830
#include <QAction>
2931
#include <QFileInfo>
32+
#include <QMainWindow>
33+
#include <QMenu>
34+
#include <QMenuBar>
3035
#include <QProgressDialog>
3136

3237
static const QString name_ = QObject::tr( "Raster Terrain Analysis plugin" );
3338
static const QString description_ = QObject::tr( "A plugin for raster based terrain analysis" );
34-
static const QString category_ = QObject::tr( "Raster" );
3539
static const QString version_ = QObject::tr( "Version 0.1" );
3640
static const QString icon_ = ":/raster/raster_terrain_icon.png";
3741

38-
QgsRasterTerrainAnalysisPlugin::QgsRasterTerrainAnalysisPlugin( QgisInterface* iface ): mIface( iface ), mAction( 0 )
42+
QgsRasterTerrainAnalysisPlugin::QgsRasterTerrainAnalysisPlugin( QgisInterface* iface ): mIface( iface ), mTerrainAnalysisMenu( 0 )
3943
{
4044

4145
}
@@ -50,69 +54,148 @@ void QgsRasterTerrainAnalysisPlugin::initGui()
5054
//create Action
5155
if ( mIface )
5256
{
53-
mAction = new QAction( QIcon( ":/raster/raster_terrain_icon.png" ), tr( "&Raster based terrain analysis" ), 0 );
54-
QObject::connect( mAction, SIGNAL( triggered() ), this, SLOT( run() ) );
55-
mIface->addRasterToolBarIcon( mAction );
56-
mIface->addPluginToRasterMenu( tr( "&Raster based terrain analysis" ), mAction );
57+
//find raster menu
58+
QString rasterText = QCoreApplication::translate( "QgisApp", "&Raster" );
59+
QMainWindow* mainWindow = qobject_cast<QMainWindow*>( mIface->mainWindow() );
60+
if ( !mainWindow )
61+
{
62+
return;
63+
}
64+
65+
QMenuBar* menuBar = mainWindow->menuBar();
66+
if ( !menuBar )
67+
{
68+
return;
69+
}
70+
71+
QMenu* rasterMenu = 0;
72+
QList<QAction *> menuBarActions = menuBar->actions();
73+
QList<QAction *>::iterator menuActionIt = menuBarActions.begin();
74+
for ( ; menuActionIt != menuBarActions.end(); ++menuActionIt )
75+
{
76+
if (( *menuActionIt )->menu() && ( *menuActionIt )->menu()->title() == rasterText )
77+
{
78+
rasterMenu = ( *menuActionIt )->menu();
79+
rasterMenu->addSeparator();
80+
break;
81+
}
82+
}
83+
84+
if ( !rasterMenu )
85+
{
86+
return;
87+
}
88+
89+
mTerrainAnalysisMenu = new QMenu( tr( "Terrain analysis" ) );
90+
mTerrainAnalysisMenu->addAction( tr( "Slope" ), this, SLOT( slope() ) );
91+
mTerrainAnalysisMenu->addAction( tr( "Aspect" ), this, SLOT( aspect() ) );
92+
mTerrainAnalysisMenu->addAction( tr( "Hillshade" ), this, SLOT( hillshade() ) );
93+
mTerrainAnalysisMenu->addAction( tr( "Relief" ), this, SLOT( relief() ) );
94+
mTerrainAnalysisMenu->addAction( tr( "Ruggedness index" ), this, SLOT( ruggedness() ) );
95+
rasterMenu->addMenu( mTerrainAnalysisMenu );
5796
}
5897
}
5998

6099
void QgsRasterTerrainAnalysisPlugin::unload()
61100
{
62101
if ( mIface )
63102
{
64-
mIface->removePluginRasterMenu( tr( "&Raster based terrain analysis" ), mAction );
65-
mIface ->removeRasterToolBarIcon( mAction );
66-
delete mAction;
103+
delete mTerrainAnalysisMenu;
67104
}
68105
}
69106

70-
void QgsRasterTerrainAnalysisPlugin::run()
107+
void QgsRasterTerrainAnalysisPlugin::hillshade()
71108
{
72-
QgsRasterTerrainAnalysisDialog d( mIface );
109+
QgsRasterTerrainAnalysisDialog d( QgsRasterTerrainAnalysisDialog::HillshadeInput );
110+
d.setWindowTitle( tr( "Hillshade" ) );
73111
if ( d.exec() == QDialog::Accepted )
74112
{
75-
//get input layer from id
76-
QString inputLayerId = d.selectedInputLayerId();
77-
QgsMapLayer* inputLayer = QgsMapLayerRegistry::instance()->mapLayer( inputLayerId );
78-
if ( !inputLayer )
113+
QString outputFile = d.outputFile();
114+
QgsHillshadeFilter hillshade( d.inputFile(), outputFile, d.outputFormat(), d.lightAzimuth(), d.lightAngle() );
115+
hillshade.setZFactor( d.zFactor() );
116+
QProgressDialog p( tr( "Calculating hillshade..." ), tr( "Abort" ), 0, 0 );
117+
p.setWindowModality( Qt::WindowModal );
118+
hillshade.processRaster( &p );
119+
if ( d.addResultToProject() )
79120
{
80-
return;
121+
mIface->addRasterLayer( outputFile, QFileInfo( outputFile ).baseName() );
81122
}
82-
QString inputFilePath = inputLayer->source();
83-
84-
QString analysisMethod = d.selectedAnalysisMethod();
85-
QString selectedFormat = d.selectedDriverKey();
86-
QString outputFile = d.selectedOuputFilePath();
123+
}
124+
}
87125

88-
QgsNineCellFilter* filter = 0;
89-
if ( d.selectedAnalysisMethod() == tr( "Slope" ) )
90-
{
91-
filter = new QgsSlopeFilter( inputFilePath, outputFile, selectedFormat );
92-
}
93-
else if ( d.selectedAnalysisMethod() == tr( "Aspect" ) )
126+
void QgsRasterTerrainAnalysisPlugin::relief()
127+
{
128+
QgsRasterTerrainAnalysisDialog d( QgsRasterTerrainAnalysisDialog::ReliefInput );
129+
d.setWindowTitle( tr( "Relief" ) );
130+
if ( d.exec() == QDialog::Accepted )
131+
{
132+
QString outputFile = d.outputFile();
133+
QgsRelief relief( d.inputFile(), outputFile, d.outputFormat() );
134+
relief.setReliefColors( d.reliefColors() );
135+
relief.setZFactor( d.zFactor() );
136+
QProgressDialog p( tr( "Calculating relief..." ), tr( "Abort" ), 0, 0 );
137+
p.setWindowModality( Qt::WindowModal );
138+
relief.processRaster( &p );
139+
if ( d.addResultToProject( ) )
94140
{
95-
filter = new QgsAspectFilter( inputFilePath, outputFile, selectedFormat );
141+
mIface->addRasterLayer( outputFile, QFileInfo( outputFile ).baseName() );
96142
}
97-
else if ( d.selectedAnalysisMethod() == tr( "Ruggedness index" ) )
143+
}
144+
}
145+
146+
void QgsRasterTerrainAnalysisPlugin::slope()
147+
{
148+
QgsRasterTerrainAnalysisDialog d( QgsRasterTerrainAnalysisDialog::NoParameter );
149+
d.setWindowTitle( tr( "Slope" ) );
150+
if ( d.exec() == QDialog::Accepted )
151+
{
152+
QString outputFile = d.outputFile();
153+
QgsSlopeFilter slope( d.inputFile(), outputFile, d.outputFormat() );
154+
slope.setZFactor( d.zFactor() );
155+
QProgressDialog p( tr( "Calculating slope..." ), tr( "Abort" ), 0, 0 );
156+
p.setWindowModality( Qt::WindowModal );
157+
slope.processRaster( &p );
158+
if ( d.addResultToProject( ) )
98159
{
99-
filter = new QgsRuggednessFilter( inputFilePath, outputFile, selectedFormat );
160+
mIface->addRasterLayer( outputFile, QFileInfo( outputFile ).baseName() );
100161
}
101-
else if ( d.selectedAnalysisMethod() == tr( "Total curvature" ) )
162+
}
163+
}
164+
165+
void QgsRasterTerrainAnalysisPlugin::aspect()
166+
{
167+
QgsRasterTerrainAnalysisDialog d( QgsRasterTerrainAnalysisDialog::NoParameter );
168+
d.setWindowTitle( tr( "Aspect" ) );
169+
if ( d.exec() == QDialog::Accepted )
170+
{
171+
QString outputFile = d.outputFile();
172+
QgsAspectFilter aspect( d.inputFile(), outputFile, d.outputFormat() );
173+
aspect.setZFactor( d.zFactor() );
174+
QProgressDialog p( tr( "Calculating aspect..." ), tr( "Abort" ), 0, 0 );
175+
p.setWindowModality( Qt::WindowModal );
176+
aspect.processRaster( &p );
177+
if ( d.addResultToProject( ) )
102178
{
103-
filter = new QgsTotalCurvatureFilter( inputFilePath, outputFile, selectedFormat );
179+
mIface->addRasterLayer( outputFile, QFileInfo( outputFile ).baseName() );
104180
}
181+
}
182+
}
105183

106-
if ( filter )
184+
void QgsRasterTerrainAnalysisPlugin::ruggedness()
185+
{
186+
QgsRasterTerrainAnalysisDialog d( QgsRasterTerrainAnalysisDialog::NoParameter );
187+
d.setWindowTitle( tr( "Ruggedness" ) );
188+
if ( d.exec() == QDialog::Accepted )
189+
{
190+
QString outputFile = d.outputFile();
191+
QgsRuggednessFilter ruggedness( d.inputFile(), outputFile, d.outputFormat() );
192+
ruggedness.setZFactor( d.zFactor() );
193+
QProgressDialog p( tr( "Calculating ruggedness..." ), tr( "Abort" ), 0, 0 );
194+
p.setWindowModality( Qt::WindowModal );
195+
ruggedness.processRaster( &p );
196+
if ( d.addResultToProject( ) )
107197
{
108-
QProgressDialog p( tr( "Calculating " ) + d.selectedAnalysisMethod() + "...", tr( "Abort..." ), 0, 0 );
109-
p.setWindowModality( Qt::WindowModal );
110-
filter->processRaster( &p );
111-
delete filter;
112-
if ( d.addLayerToProject() )
113-
{
114-
mIface->addRasterLayer( outputFile, QFileInfo( outputFile ).baseName() );
115-
}
198+
mIface->addRasterLayer( outputFile, QFileInfo( outputFile ).baseName() );
116199
}
117200
}
118201
}
@@ -133,11 +216,6 @@ QGISEXTERN QString description()
133216
return description_;
134217
}
135218

136-
QGISEXTERN QString category()
137-
{
138-
return category_;
139-
}
140-
141219
QGISEXTERN QString version()
142220
{
143221
return version_;

‎src/plugins/raster_terrain_analysis/qgsrasterterrainanalysisplugin.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
class QgsInterface;
2525
class QAction;
26+
class QMenu;
2627

2728
/**A plugin for raster based terrain analysis (e.g. slope, aspect, ruggedness)*/
2829
class QgsRasterTerrainAnalysisPlugin: public QObject, public QgisPlugin
@@ -38,12 +39,15 @@ class QgsRasterTerrainAnalysisPlugin: public QObject, public QgisPlugin
3839
void unload();
3940

4041
private slots:
41-
/**Select input file, output file, format and analysis method*/
42-
void run();
42+
void hillshade();
43+
void relief();
44+
void slope();
45+
void aspect();
46+
void ruggedness();
4347

4448
private:
4549
QgisInterface* mIface;
46-
QAction* mAction;
50+
QMenu* mTerrainAnalysisMenu;
4751
};
4852

4953
#endif // QGSRASTERTERRAINANALYSISPLUGIN_H
Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
#include "qgsreliefdialog.h"
2+
#include "qgsmaplayerregistry.h"
3+
#include "qgsrasterlayer.h"
4+
#include <QColorDialog>
5+
#include <QDir>
6+
#include <QFileDialog>
7+
#include <QFileInfo>
8+
#include <QInputDialog>
9+
#include <QSettings>
10+
#include "cpl_string.h"
11+
#include "gdal.h"
12+
13+
QgsReliefDialog::QgsReliefDialog( DisplayMode mode, QWidget * parent, Qt::WindowFlags f ): QDialog( parent, f )
14+
{
15+
setupUi( this );
16+
17+
if ( mode == HillshadeInput )
18+
{
19+
mReliefColorsGroupBox->setVisible( false );
20+
mLightAzimuthAngleSpinBox->setValue( 300 );
21+
mLightVerticalAngleSpinBox->setValue( 40 );
22+
}
23+
else if ( mode == ReliefInput )
24+
{
25+
mIlluminationGroupBox->setVisible( false );
26+
}
27+
else //no parameters
28+
{
29+
mReliefColorsGroupBox->setVisible( false );
30+
mIlluminationGroupBox->setVisible( false );
31+
}
32+
33+
mZFactorLineEdit->setText( "1.0" );
34+
mZFactorLineEdit->setValidator( new QDoubleValidator( this ) );
35+
36+
//insert available raster layers
37+
//enter available layers into the combo box
38+
QMap<QString, QgsMapLayer*> mapLayers = QgsMapLayerRegistry::instance()->mapLayers();
39+
QMap<QString, QgsMapLayer*>::iterator layer_it = mapLayers.begin();
40+
41+
//insert available input layers
42+
for ( ; layer_it != mapLayers.end(); ++layer_it )
43+
{
44+
QgsRasterLayer* rl = qobject_cast<QgsRasterLayer *>( layer_it.value() );
45+
if ( rl )
46+
{
47+
mElevationLayerComboBox->addItem( rl->name(), QVariant( rl->id() ) );
48+
}
49+
}
50+
51+
//insert available drivers that support the create() operation
52+
GDALAllRegister();
53+
54+
int nDrivers = GDALGetDriverCount();
55+
for ( int i = 0; i < nDrivers; ++i )
56+
{
57+
GDALDriverH driver = GDALGetDriver( i );
58+
if ( driver != NULL )
59+
{
60+
char** driverMetadata = GDALGetMetadata( driver, NULL );
61+
if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_CREATE, false ) )
62+
{
63+
mOutputFormatComboBox->addItem( GDALGetDriverLongName( driver ), QVariant( GDALGetDriverShortName( driver ) ) );
64+
65+
//store the driver shortnames and the corresponding extensions
66+
//(just in case the user does not give an extension for the output file name)
67+
int index = 0;
68+
while (( driverMetadata ) && driverMetadata[index] != 0 )
69+
{
70+
QStringList metadataTokens = QString( driverMetadata[index] ).split( "=", QString::SkipEmptyParts );
71+
if ( metadataTokens.size() < 1 )
72+
{
73+
break;
74+
}
75+
76+
if ( metadataTokens[0] == "DMD_EXTENSION" )
77+
{
78+
if ( metadataTokens.size() < 2 )
79+
{
80+
++index;
81+
continue;
82+
}
83+
mDriverExtensionMap.insert( QString( GDALGetDriverShortName( driver ) ), metadataTokens[1] );
84+
break;
85+
}
86+
++index;
87+
}
88+
89+
}
90+
}
91+
}
92+
93+
//and set last used driver in combo box
94+
QSettings s;
95+
QString lastUsedDriver = s.value( "/RasterTerrainAnalysis/lastOutputFormat", "GeoTIFF" ).toString();
96+
int lastDriverIndex = mOutputFormatComboBox->findText( lastUsedDriver );
97+
if ( lastDriverIndex != -1 )
98+
{
99+
mOutputFormatComboBox->setCurrentIndex( lastDriverIndex );
100+
}
101+
102+
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( false );
103+
}
104+
105+
QgsReliefDialog::~QgsReliefDialog()
106+
{
107+
}
108+
109+
QList< QgsRelief::ReliefColor > QgsReliefDialog::reliefColors() const
110+
{
111+
QList< QgsRelief::ReliefColor > reliefColorList;
112+
113+
for ( int i = 0; i < mReliefClassTreeWidget->topLevelItemCount(); ++i )
114+
{
115+
QTreeWidgetItem* reliefItem = mReliefClassTreeWidget->topLevelItem( i );
116+
if ( reliefItem )
117+
{
118+
QgsRelief::ReliefColor rc( reliefItem->background( 2 ).color(), reliefItem->text( 0 ).toDouble(), reliefItem->text( 1 ).toDouble() );
119+
reliefColorList.push_back( rc );
120+
}
121+
}
122+
123+
return reliefColorList;
124+
}
125+
126+
QString QgsReliefDialog::inputFile() const
127+
{
128+
QgsMapLayer* inputLayer = QgsMapLayerRegistry::instance()->mapLayer( mElevationLayerComboBox->itemData( mElevationLayerComboBox->currentIndex() ).toString() );
129+
if ( !inputLayer )
130+
{
131+
return "";
132+
}
133+
134+
QString inputFilePath = inputLayer->source();
135+
return inputFilePath;
136+
}
137+
138+
QString QgsReliefDialog::outputFile() const
139+
{
140+
return mOutputLayerLineEdit->text();
141+
}
142+
143+
QString QgsReliefDialog::outputFormat() const
144+
{
145+
int index = mOutputFormatComboBox->currentIndex();
146+
if ( index == -1 )
147+
{
148+
return "";
149+
}
150+
return mOutputFormatComboBox->itemData( index ).toString();
151+
}
152+
153+
bool QgsReliefDialog::addResultToProject() const
154+
{
155+
return mAddResultToProjectCheckBox->isChecked();
156+
}
157+
158+
double QgsReliefDialog::zFactor() const
159+
{
160+
return mZFactorLineEdit->text().toDouble();
161+
}
162+
163+
void QgsReliefDialog::on_mOutputLayerLineEdit_textChanged( const QString& text )
164+
{
165+
bool enabled = false;
166+
167+
QFileInfo fi( text );
168+
if ( fi.absoluteDir().exists() && mElevationLayerComboBox->count() > 0 )
169+
{
170+
enabled = true;
171+
}
172+
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( enabled );
173+
}
174+
175+
void QgsReliefDialog::on_mAutomaticColorButton_clicked()
176+
{
177+
QgsRelief relief( inputFile(), outputFile(), outputFormat() );
178+
QList< QgsRelief::ReliefColor > reliefColorList = relief.calculateOptimizedReliefClasses();
179+
QList< QgsRelief::ReliefColor >::iterator it = reliefColorList.begin();
180+
181+
mReliefClassTreeWidget->clear();
182+
for ( ; it != reliefColorList.end(); ++it )
183+
{
184+
QTreeWidgetItem* item = new QTreeWidgetItem();
185+
item->setText( 0, QString::number( it->minElevation ) );
186+
item->setText( 1, QString::number( it->maxElevation ) );
187+
item->setBackground( 2, QBrush( it->color ) );
188+
mReliefClassTreeWidget->addTopLevelItem( item );
189+
}
190+
}
191+
192+
void QgsReliefDialog::on_mExportToCsvButton_clicked()
193+
{
194+
QString file = QFileDialog::getSaveFileName( 0, tr("Export Frequency distribution as csv") );
195+
if( file.isEmpty() )
196+
{
197+
return;
198+
}
199+
200+
QgsRelief relief( inputFile(), outputFile(), outputFormat() );
201+
relief.exportFrequencyDistributionToCsv( file );
202+
}
203+
204+
void QgsReliefDialog::on_mOutputLayerToolButton_clicked()
205+
{
206+
QSettings s;
207+
QString lastDir = s.value( "/RasterTerrainAnalysis/lastOutputDir" ).toString();
208+
QString saveFileName = QFileDialog::getSaveFileName( 0, tr( "Enter result file" ), lastDir );
209+
if ( !saveFileName.isNull() )
210+
{
211+
mOutputLayerLineEdit->setText( saveFileName );
212+
}
213+
}
214+
215+
double QgsReliefDialog::lightAzimuth() const
216+
{
217+
return mLightAzimuthAngleSpinBox->value();
218+
}
219+
220+
double QgsReliefDialog::lightAngle() const
221+
{
222+
return mLightVerticalAngleSpinBox->value();
223+
}
224+
225+
void QgsReliefDialog::on_mRemoveClassButton_clicked()
226+
{
227+
QList<QTreeWidgetItem*> selectedItems = mReliefClassTreeWidget->selectedItems();
228+
QList<QTreeWidgetItem*>::iterator itemIt = selectedItems.begin();
229+
for(; itemIt != selectedItems.end(); ++itemIt )
230+
{
231+
delete *itemIt;
232+
}
233+
}
234+
235+
void QgsReliefDialog::on_mReliefClassTreeWidget_itemDoubleClicked( QTreeWidgetItem* item, int column )
236+
{
237+
if( !item )
238+
{
239+
return;
240+
}
241+
242+
if( column == 0 )
243+
{
244+
bool ok;
245+
double d = QInputDialog::getDouble(0, tr("Enter lower elevation class bound"), tr("Elevation"), item->text( 0 ).toDouble(), -2147483647,
246+
2147483647, 2, &ok );
247+
if( ok )
248+
{
249+
item->setText( 0, QString::number( d ) );
250+
}
251+
}
252+
else if( column == 1 )
253+
{
254+
bool ok;
255+
double d = QInputDialog::getDouble(0, tr("Enter upper elevation class bound"), tr("Elevation"), item->text( 1 ).toDouble(), -2147483647,
256+
2147483647, 2, &ok );
257+
if( ok )
258+
{
259+
item->setText( 1, QString::number( d ) );
260+
}
261+
}
262+
else if( column == 2 )
263+
{
264+
QColor c = QColorDialog::getColor( item->background( 2 ).color(), 0, tr("Select color for relief class") );
265+
if( c.isValid() )
266+
{
267+
item->setBackground( 2, QBrush( c ) );
268+
}
269+
}
270+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#ifndef QGSRELIEFDIALOG_H
2+
#define QGSRELIEFDIALOG_H
3+
4+
#include "ui_qgsreliefdialogbase.h"
5+
#include "qgsrelief.h"
6+
7+
class QgsReliefDialog: public QDialog, private Ui::QgsReliefDialogBase
8+
{
9+
Q_OBJECT
10+
public:
11+
12+
enum DisplayMode
13+
{
14+
NoParameter,
15+
HillshadeInput,
16+
ReliefInput
17+
};
18+
19+
QgsReliefDialog( DisplayMode mode = NoParameter, QWidget * parent = 0, Qt::WindowFlags f = 0 );
20+
~QgsReliefDialog();
21+
22+
QList< QgsRelief::ReliefColor > reliefColors() const;
23+
QString inputFile() const;
24+
QString outputFile() const;
25+
QString outputFormat() const;
26+
27+
bool addResultToProject() const;
28+
double zFactor() const;
29+
double lightAzimuth() const;
30+
double lightAngle() const;
31+
32+
private slots:
33+
void on_mOutputLayerLineEdit_textChanged( const QString& text );
34+
void on_mAutomaticColorButton_clicked();
35+
void on_mOutputLayerToolButton_clicked();
36+
void on_mRemoveClassButton_clicked();
37+
void on_mReliefClassTreeWidget_itemDoubleClicked( QTreeWidgetItem* item, int column );
38+
void on_mExportToCsvButton_clicked();
39+
40+
private:
41+
/**Stores relation between driver name and extension*/
42+
QMap<QString, QString> mDriverExtensionMap;
43+
};
44+
45+
#endif // QGSRELIEFDIALOG_H
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ui version="4.0">
3+
<class>QgsReliefDialogBase</class>
4+
<widget class="QDialog" name="QgsReliefDialogBase">
5+
<property name="geometry">
6+
<rect>
7+
<x>0</x>
8+
<y>0</y>
9+
<width>393</width>
10+
<height>405</height>
11+
</rect>
12+
</property>
13+
<property name="windowTitle">
14+
<string>Dialog</string>
15+
</property>
16+
<layout class="QGridLayout" name="gridLayout_3">
17+
<item row="0" column="0">
18+
<widget class="QLabel" name="mElevationLayerLabel">
19+
<property name="text">
20+
<string>Elevation layer</string>
21+
</property>
22+
</widget>
23+
</item>
24+
<item row="0" column="1" colspan="2">
25+
<widget class="QComboBox" name="mElevationLayerComboBox"/>
26+
</item>
27+
<item row="1" column="0">
28+
<widget class="QLabel" name="mOutputLayerLabel">
29+
<property name="text">
30+
<string>Output layer</string>
31+
</property>
32+
</widget>
33+
</item>
34+
<item row="1" column="1">
35+
<widget class="QLineEdit" name="mOutputLayerLineEdit"/>
36+
</item>
37+
<item row="1" column="2">
38+
<widget class="QToolButton" name="mOutputLayerToolButton">
39+
<property name="text">
40+
<string>...</string>
41+
</property>
42+
</widget>
43+
</item>
44+
<item row="2" column="0">
45+
<widget class="QLabel" name="mOutputFormatLabel">
46+
<property name="text">
47+
<string>Output format</string>
48+
</property>
49+
</widget>
50+
</item>
51+
<item row="2" column="1" colspan="2">
52+
<widget class="QComboBox" name="mOutputFormatComboBox"/>
53+
</item>
54+
<item row="3" column="0">
55+
<widget class="QLabel" name="mZFactorLabel">
56+
<property name="text">
57+
<string>Z factor</string>
58+
</property>
59+
</widget>
60+
</item>
61+
<item row="3" column="1" colspan="2">
62+
<widget class="QLineEdit" name="mZFactorLineEdit"/>
63+
</item>
64+
<item row="4" column="0" colspan="2">
65+
<widget class="QCheckBox" name="mAddResultToProjectCheckBox">
66+
<property name="text">
67+
<string>Add result to project</string>
68+
</property>
69+
</widget>
70+
</item>
71+
<item row="5" column="0" colspan="3">
72+
<widget class="QGroupBox" name="mIlluminationGroupBox">
73+
<property name="title">
74+
<string>Illumination</string>
75+
</property>
76+
<layout class="QGridLayout" name="gridLayout_2">
77+
<item row="0" column="0">
78+
<widget class="QLabel" name="mLightAzimuthLabel">
79+
<property name="text">
80+
<string>Azimuth (horizontal angle)</string>
81+
</property>
82+
</widget>
83+
</item>
84+
<item row="0" column="1">
85+
<widget class="QDoubleSpinBox" name="mLightAzimuthAngleSpinBox">
86+
<property name="maximum">
87+
<double>360.000000000000000</double>
88+
</property>
89+
<property name="value">
90+
<double>300.000000000000000</double>
91+
</property>
92+
</widget>
93+
</item>
94+
<item row="1" column="0">
95+
<widget class="QLabel" name="mLightVerticalAngleLabel">
96+
<property name="text">
97+
<string>Vertical angle</string>
98+
</property>
99+
</widget>
100+
</item>
101+
<item row="1" column="1">
102+
<widget class="QDoubleSpinBox" name="mLightVerticalAngleSpinBox">
103+
<property name="maximum">
104+
<double>90.000000000000000</double>
105+
</property>
106+
<property name="value">
107+
<double>40.000000000000000</double>
108+
</property>
109+
</widget>
110+
</item>
111+
</layout>
112+
</widget>
113+
</item>
114+
<item row="6" column="0" colspan="3">
115+
<widget class="QGroupBox" name="mReliefColorsGroupBox">
116+
<property name="title">
117+
<string>Relief colors</string>
118+
</property>
119+
<layout class="QGridLayout" name="gridLayout">
120+
<item row="0" column="2">
121+
<spacer name="horizontalSpacer">
122+
<property name="orientation">
123+
<enum>Qt::Horizontal</enum>
124+
</property>
125+
<property name="sizeHint" stdset="0">
126+
<size>
127+
<width>268</width>
128+
<height>20</height>
129+
</size>
130+
</property>
131+
</spacer>
132+
</item>
133+
<item row="0" column="3">
134+
<widget class="QPushButton" name="mAddClassButton">
135+
<property name="text">
136+
<string>+</string>
137+
</property>
138+
</widget>
139+
</item>
140+
<item row="0" column="4">
141+
<widget class="QPushButton" name="mRemoveClassButton">
142+
<property name="text">
143+
<string>-</string>
144+
</property>
145+
</widget>
146+
</item>
147+
<item row="1" column="0" colspan="5">
148+
<widget class="QTreeWidget" name="mReliefClassTreeWidget">
149+
<column>
150+
<property name="text">
151+
<string>Lower bound</string>
152+
</property>
153+
</column>
154+
<column>
155+
<property name="text">
156+
<string>Upper bound</string>
157+
</property>
158+
</column>
159+
<column>
160+
<property name="text">
161+
<string>Color</string>
162+
</property>
163+
</column>
164+
</widget>
165+
</item>
166+
<item row="0" column="0">
167+
<widget class="QPushButton" name="mAutomaticColorButton">
168+
<property name="text">
169+
<string>Create automatically</string>
170+
</property>
171+
</widget>
172+
</item>
173+
<item row="0" column="1">
174+
<widget class="QPushButton" name="mExportToCsvButton">
175+
<property name="text">
176+
<string>Export distribution...</string>
177+
</property>
178+
</widget>
179+
</item>
180+
</layout>
181+
</widget>
182+
</item>
183+
<item row="7" column="0" colspan="2">
184+
<widget class="QDialogButtonBox" name="mButtonBox">
185+
<property name="orientation">
186+
<enum>Qt::Horizontal</enum>
187+
</property>
188+
<property name="standardButtons">
189+
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
190+
</property>
191+
</widget>
192+
</item>
193+
</layout>
194+
</widget>
195+
<resources/>
196+
<connections>
197+
<connection>
198+
<sender>mButtonBox</sender>
199+
<signal>accepted()</signal>
200+
<receiver>QgsReliefDialogBase</receiver>
201+
<slot>accept()</slot>
202+
<hints>
203+
<hint type="sourcelabel">
204+
<x>248</x>
205+
<y>254</y>
206+
</hint>
207+
<hint type="destinationlabel">
208+
<x>157</x>
209+
<y>274</y>
210+
</hint>
211+
</hints>
212+
</connection>
213+
<connection>
214+
<sender>mButtonBox</sender>
215+
<signal>rejected()</signal>
216+
<receiver>QgsReliefDialogBase</receiver>
217+
<slot>reject()</slot>
218+
<hints>
219+
<hint type="sourcelabel">
220+
<x>316</x>
221+
<y>260</y>
222+
</hint>
223+
<hint type="destinationlabel">
224+
<x>286</x>
225+
<y>274</y>
226+
</hint>
227+
</hints>
228+
</connection>
229+
</connections>
230+
</ui>

0 commit comments

Comments
 (0)
Please sign in to comment.