24 #include "cpl_string.h" 25 #include <QProgressDialog> 29 #include <QTextStream> 31 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800 32 #define TO8F(x) (x).toUtf8().constData() 34 #define TO8F(x) QFile::encodeName( x ).constData() 38 : mInputFile( inputFile )
39 , mOutputFile( outputFile )
40 , mOutputFormat( outputFormat )
43 , mInputNodataValue( -1 )
44 , mOutputNodataValue( -1 )
47 mSlopeFilter =
new QgsSlopeFilter( inputFile, outputFile, outputFormat );
48 mAspectFilter =
new QgsAspectFilter( inputFile, outputFile, outputFormat );
49 mHillshadeFilter285 =
new QgsHillshadeFilter( inputFile, outputFile, outputFormat, 285, 30 );
50 mHillshadeFilter300 =
new QgsHillshadeFilter( inputFile, outputFile, outputFormat, 300, 30 );
51 mHillshadeFilter315 =
new QgsHillshadeFilter( inputFile, outputFile, outputFormat, 315, 30 );
61 delete mHillshadeFilter285;
62 delete mHillshadeFilter300;
63 delete mHillshadeFilter315;
68 mReliefColors.clear();
73 mReliefColors.push_back( color );
76 void QgsRelief::setDefaultReliefColors()
91 GDALDatasetH inputDataset = openInputFile( xSize, ySize );
98 GDALDriverH outputDriver = openOutputDriver();
104 GDALDatasetH outputDataset = openOutputFile( inputDataset, outputDriver );
105 if ( !outputDataset )
128 GDALRasterBandH rasterBand = GDALGetRasterBand( inputDataset, 1 );
131 GDALClose( inputDataset );
132 GDALClose( outputDataset );
135 mInputNodataValue = GDALGetRasterNoDataValue( rasterBand,
nullptr );
142 GDALRasterBandH outputRedBand = GDALGetRasterBand( outputDataset, 1 );
143 GDALRasterBandH outputGreenBand = GDALGetRasterBand( outputDataset, 2 );
144 GDALRasterBandH outputBlueBand = GDALGetRasterBand( outputDataset, 3 );
146 if ( !outputRedBand || !outputGreenBand || !outputBlueBand )
148 GDALClose( inputDataset );
149 GDALClose( outputDataset );
153 GDALSetRasterNoDataValue( outputRedBand, -9999 );
154 GDALSetRasterNoDataValue( outputGreenBand, -9999 );
155 GDALSetRasterNoDataValue( outputBlueBand, -9999 );
156 mOutputNodataValue = GDALGetRasterNoDataValue( outputRedBand,
nullptr );
165 GDALClose( inputDataset );
166 GDALClose( outputDataset );
171 float* scanLine1 = (
float * ) CPLMalloc(
sizeof(
float ) * xSize );
172 float* scanLine2 = (
float * ) CPLMalloc(
sizeof(
float ) * xSize );
173 float* scanLine3 = (
float * ) CPLMalloc(
sizeof(
float ) * xSize );
175 unsigned char* resultRedLine = (
unsigned char * ) CPLMalloc(
sizeof(
unsigned char ) * xSize );
176 unsigned char* resultGreenLine = (
unsigned char * ) CPLMalloc(
sizeof(
unsigned char ) * xSize );
177 unsigned char* resultBlueLine = (
unsigned char * ) CPLMalloc(
sizeof(
unsigned char ) * xSize );
187 for (
int i = 0; i < ySize; ++i )
202 for (
int a = 0; a < xSize; ++a )
204 scanLine1[a] = mInputNodataValue;
206 if ( GDALRasterIO( rasterBand, GF_Read, 0, 0, xSize, 1, scanLine2, xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
214 CPLFree( scanLine1 );
215 scanLine1 = scanLine2;
216 scanLine2 = scanLine3;
217 scanLine3 = (
float * ) CPLMalloc(
sizeof(
float ) * xSize );
220 if ( i == ySize - 1 )
222 for (
int a = 0; a < xSize; ++a )
224 scanLine3[a] = mInputNodataValue;
229 if ( GDALRasterIO( rasterBand, GF_Read, 0, i + 1, xSize, 1, scanLine3, xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
235 for (
int j = 0; j < xSize; ++j )
239 resultOk = processNineCellWindow( &mInputNodataValue, &scanLine1[j], &scanLine1[j+1], &mInputNodataValue, &scanLine2[j], \
240 &scanLine2[j+1], &mInputNodataValue, &scanLine3[j], &scanLine3[j+1], \
241 &resultRedLine[j], &resultGreenLine[j], &resultBlueLine[j] );
243 else if ( j == xSize - 1 )
245 resultOk = processNineCellWindow( &scanLine1[j-1], &scanLine1[j], &mInputNodataValue, &scanLine2[j-1], &scanLine2[j], \
246 &mInputNodataValue, &scanLine3[j-1], &scanLine3[j], &mInputNodataValue, \
247 &resultRedLine[j], &resultGreenLine[j], &resultBlueLine[j] );
251 resultOk = processNineCellWindow( &scanLine1[j-1], &scanLine1[j], &scanLine1[j+1], &scanLine2[j-1], &scanLine2[j], \
252 &scanLine2[j+1], &scanLine3[j-1], &scanLine3[j], &scanLine3[j+1], \
253 &resultRedLine[j], &resultGreenLine[j], &resultBlueLine[j] );
258 resultRedLine[j] = mOutputNodataValue;
259 resultGreenLine[j] = mOutputNodataValue;
260 resultBlueLine[j] = mOutputNodataValue;
264 if ( GDALRasterIO( outputRedBand, GF_Write, 0, i, xSize, 1, resultRedLine, xSize, 1, GDT_Byte, 0, 0 ) != CE_None )
268 if ( GDALRasterIO( outputGreenBand, GF_Write, 0, i, xSize, 1, resultGreenLine, xSize, 1, GDT_Byte, 0, 0 ) != CE_None )
272 if ( GDALRasterIO( outputBlueBand, GF_Write, 0, i, xSize, 1, resultBlueLine, xSize, 1, GDT_Byte, 0, 0 ) != CE_None )
283 CPLFree( resultRedLine );
284 CPLFree( resultBlueLine );
285 CPLFree( resultGreenLine );
286 CPLFree( scanLine1 );
287 CPLFree( scanLine2 );
288 CPLFree( scanLine3 );
290 GDALClose( inputDataset );
295 GDALDeleteDataset( outputDriver,
TO8F( mOutputFile ) );
298 GDALClose( outputDataset );
303 bool QgsRelief::processNineCellWindow(
float* x1,
float* x2,
float* x3,
float* x4,
float* x5,
float* x6,
float* x7,
float* x8,
float* x9,
304 unsigned char* red,
unsigned char* green,
unsigned char* blue )
311 float hillShadeValue300 = mHillshadeFilter300->
processNineCellWindow( x1, x2, x3, x4, x5, x6, x7, x8, x9 );
312 if ( hillShadeValue300 != mOutputNodataValue )
314 if ( !setElevationColor( *x5, &r, &g, &b ) )
316 r = hillShadeValue300;
317 g = hillShadeValue300;
318 b = hillShadeValue300;
322 r = r / 2.0 + hillShadeValue300 / 2.0;
323 g = g / 2.0 + hillShadeValue300 / 2.0;
324 b = b / 2.0 + hillShadeValue300 / 2.0;
329 float hillShadeValue315 = mHillshadeFilter315->
processNineCellWindow( x1, x2, x3, x4, x5, x6, x7, x8, x9 );
331 if ( hillShadeValue315 != mOutputNodataValue && slope != mOutputNodataValue )
336 r2 = 0 / 2.0 + hillShadeValue315 / 2.0;
337 g2 = 0 / 2.0 + hillShadeValue315 / 2.0;
338 b2 = 0 / 2.0 + hillShadeValue315 / 2.0;
340 else if ( slope >= 1 )
342 int slopeValue = 255 - ( slope / 15.0 * 255.0 );
343 r2 = slopeValue / 2.0 + hillShadeValue315 / 2.0;
344 g2 = slopeValue / 2.0 + hillShadeValue315 / 2.0;
345 b2 = slopeValue / 2.0 + hillShadeValue315 / 2.0;
349 r2 = hillShadeValue315;
350 g2 = hillShadeValue315;
351 b2 = hillShadeValue315;
355 r = r * 0.7 + r2 * 0.3;
356 g = g * 0.7 + g2 * 0.3;
357 b = b * 0.7 + b2 * 0.3;
361 float hillShadeValue285 = mHillshadeFilter285->
processNineCellWindow( x1, x2, x3, x4, x5, x6, x7, x8, x9 );
363 if ( hillShadeValue285 != mOutputNodataValue && aspect != mOutputNodataValue )
365 double angle_diff = qAbs( 285 - aspect );
366 if ( angle_diff > 180 )
372 if ( angle_diff < 90 )
374 int aspectVal = ( 1 - cos( angle_diff *
M_PI / 180 ) ) * 255;
375 r3 = 0.5 * 255 + hillShadeValue315 * 0.5;
376 g3 = 0.5 * 255 + hillShadeValue315 * 0.5;
377 b3 = 0.5 * aspectVal + hillShadeValue315 * 0.5;
381 r3 = 0.5 * 255 + hillShadeValue315 * 0.5;
382 g3 = 0.5 * 255 + hillShadeValue315 * 0.5;
383 b3 = 0.5 * 255 + hillShadeValue315 * 0.5;
386 r = r3 * 0.1 + r * 0.9;
387 g = g3 * 0.1 + g * 0.9;
388 b = b3 * 0.1 + b * 0.9;
391 *red = (
unsigned char )r;
392 *green = (
unsigned char )g;
393 *blue = (
unsigned char )b;
397 bool QgsRelief::setElevationColor(
double elevation,
int* red,
int* green,
int* blue )
400 for ( ; reliefColorIt != mReliefColors.constEnd(); ++reliefColorIt )
402 if ( elevation >= reliefColorIt->minElevation && elevation <= reliefColorIt->maxElevation )
404 const QColor& c = reliefColorIt->color;
416 GDALDatasetH QgsRelief::openInputFile(
int& nCellsX,
int& nCellsY )
421 nCellsX = GDALGetRasterXSize( inputDataset );
422 nCellsY = GDALGetRasterYSize( inputDataset );
425 if ( GDALGetRasterCount( inputDataset ) < 1 )
427 GDALClose( inputDataset );
434 GDALDriverH QgsRelief::openOutputDriver()
436 char **driverMetadata;
439 GDALDriverH outputDriver = GDALGetDriverByName( mOutputFormat.
toLocal8Bit().
data() );
446 driverMetadata = GDALGetMetadata( outputDriver,
nullptr );
447 if ( !CSLFetchBoolean( driverMetadata, GDAL_DCAP_CREATE,
false ) )
462 int xSize = GDALGetRasterXSize( inputDataset );
463 int ySize = GDALGetRasterYSize( inputDataset );
466 char **papszOptions =
nullptr;
469 papszOptions = CSLSetNameValue( papszOptions,
"COMPRESS",
"PACKBITS" );
472 GDALDatasetH outputDataset = GDALCreate( outputDriver,
TO8F( mOutputFile ), xSize, ySize, 3, GDT_Byte, papszOptions );
473 if ( !outputDataset )
475 return outputDataset;
479 double geotransform[6];
480 if ( GDALGetGeoTransform( inputDataset, geotransform ) != CE_None )
482 GDALClose( outputDataset );
485 GDALSetGeoTransform( outputDataset, geotransform );
488 mCellSizeX = geotransform[1];
489 if ( mCellSizeX < 0 )
491 mCellSizeX = -mCellSizeX;
493 mCellSizeY = geotransform[5];
494 if ( mCellSizeY < 0 )
496 mCellSizeY = -mCellSizeY;
499 const char* projection = GDALGetProjectionRef( inputDataset );
500 GDALSetProjection( outputDataset, projection );
502 return outputDataset;
508 int nCellsX, nCellsY;
509 GDALDatasetH inputDataset = openInputFile( nCellsX, nCellsY );
516 GDALRasterBandH elevationBand = GDALGetRasterBand( inputDataset, 1 );
517 if ( !elevationBand )
519 GDALClose( inputDataset );
526 minMax[0] = GDALGetRasterMinimum( elevationBand, &minOk );
527 minMax[1] = GDALGetRasterMaximum( elevationBand, &maxOk );
529 if ( !minOk || !maxOk )
531 GDALComputeRasterMinMax( elevationBand,
true, minMax );
537 double frequency[252];
538 double frequencyClassRange = ( minMax[1] - minMax[0] ) / 252.0;
540 for (
int i = 0; i < 252; ++i )
545 float* scanLine = (
float * ) CPLMalloc(
sizeof(
float ) * nCellsX );
546 int elevationClass = -1;
548 for (
int i = 0; i < nCellsY; ++i )
550 if ( GDALRasterIO( elevationBand, GF_Read, 0, i, nCellsX, 1,
551 scanLine, nCellsX, 1, GDT_Float32,
557 for (
int j = 0; j < nCellsX; ++j )
559 elevationClass = frequencyClassForElevation( scanLine[j], minMax[0], frequencyClassRange );
560 if ( elevationClass >= 0 )
562 frequency[elevationClass] += 1.0;
570 for (
int i = 0; i < 252; ++i )
572 frequency[i] = log10( frequency[i] );
576 QFile outFile( file );
577 if ( !outFile.
open( QIODevice::WriteOnly ) )
583 for (
int i = 0; i < 252; ++i )
595 int nCellsX, nCellsY;
596 GDALDatasetH inputDataset = openInputFile( nCellsX, nCellsY );
603 GDALRasterBandH elevationBand = GDALGetRasterBand( inputDataset, 1 );
604 if ( !elevationBand )
606 GDALClose( inputDataset );
613 minMax[0] = GDALGetRasterMinimum( elevationBand, &minOk );
614 minMax[1] = GDALGetRasterMaximum( elevationBand, &maxOk );
616 if ( !minOk || !maxOk )
618 GDALComputeRasterMinMax( elevationBand,
true, minMax );
624 double frequency[252];
625 double frequencyClassRange = ( minMax[1] - minMax[0] ) / 252.0;
627 for (
int i = 0; i < 252; ++i )
632 float* scanLine = (
float * ) CPLMalloc(
sizeof(
float ) * nCellsX );
633 int elevationClass = -1;
635 for (
int i = 0; i < nCellsY; ++i )
637 if ( GDALRasterIO( elevationBand, GF_Read, 0, i, nCellsX, 1,
638 scanLine, nCellsX, 1, GDT_Float32,
643 for (
int j = 0; j < nCellsX; ++j )
645 elevationClass = frequencyClassForElevation( scanLine[j], minMax[0], frequencyClassRange );
646 if ( elevationClass < 0 )
650 else if ( elevationClass >= 252 )
652 elevationClass = 251;
654 frequency[elevationClass] += 1.0;
661 for (
int i = 0; i < 252; ++i )
663 frequency[i] = log10( frequency[i] );
672 classBreaks.
append( 112 );
673 classBreaks.
append( 140 );
674 classBreaks.
append( 168 );
675 classBreaks.
append( 196 );
676 classBreaks.
append( 224 );
677 classBreaks.
append( 252 );
679 for (
int i = 0; i < 10; ++i )
681 optimiseClassBreaks( classBreaks, frequency );
685 for (
int i = 0; i < classBreaks.
size(); ++i )
687 qWarning(
"%d", classBreaks[i] );
703 for (
int i = 1; i < classBreaks.
size(); ++i )
705 double minElevation = minMax[0] + classBreaks[i - 1] * frequencyClassRange;
706 double maxElevation = minMax[0] + classBreaks[i] * frequencyClassRange;
713 void QgsRelief::optimiseClassBreaks(
QList<int>& breaks,
double* frequencies )
715 int nClasses = breaks.
size() - 1;
716 double* a =
new double[nClasses];
717 double* b =
new double[nClasses];
719 for (
int i = 0; i < nClasses; ++i )
723 for (
int j = breaks.
at( i ); j < breaks.
at( i + 1 ); ++j )
725 regressionInput.
push_back( qMakePair( j, frequencies[j] ) );
728 double aParam, bParam;
729 if ( !regressionInput.
isEmpty() && calculateRegression( regressionInput, aParam, bParam ) )
744 for (
int i = 1; i < nClasses ; ++i )
746 if ( breaks[i] == breaks[ i - 1 ] )
757 int newX = ( b[i - 1] - b[ i ] ) / ( a[ i ] - a[ i - 1 ] );
759 if ( newX <= breaks[i - 1] )
761 newX = breaks[i - 1];
764 else if ( i < nClasses - 1 && newX >= breaks[i + 1] )
766 newX = breaks[i + 1];
774 for (
int i = classesToRemove.
size() - 1; i >= 0; --i )
783 int QgsRelief::frequencyClassForElevation(
double elevation,
double minElevation,
double elevationClassRange )
785 return ( elevation - minElevation ) / elevationClassRange;
794 for ( ; inputIt != input.
constEnd(); ++inputIt )
796 xSum += inputIt->
first;
797 ySum += inputIt->second;
799 xMean = xSum / input.
size();
800 yMean = ySum / input.size();
802 double sumCounter = 0;
803 double sumDenominator = 0;
805 for ( ; inputIt != input.
constEnd(); ++inputIt )
807 sumCounter += (( inputIt->
first - xMean ) * ( inputIt->second - yMean ) );
808 sumDenominator += (( inputIt->
first - xMean ) * ( inputIt->
first - xMean ) );
811 a = sumCounter / sumDenominator;
812 b = yMean - a * xMean;
float processNineCellWindow(float *x11, float *x21, float *x31, float *x12, float *x22, float *x32, float *x13, float *x23, float *x33) override
Calculates output value from nine input values.
void setZFactor(double factor)
void addReliefColorClass(const ReliefColor &color)
int processRaster(QProgressDialog *p)
Starts the calculation, reads from mInputFile and stores the result in mOutputFile.
void setMaximum(int maximum)
void push_back(const T &value)
QList< ReliefColor > calculateOptimizedReliefClasses()
Calculates class breaks according with the method of Buenzli (2011) using an iterative algorithm for ...
void setCellSizeY(double size)
const T & at(int i) const
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
void setValue(int progress)
bool exportFrequencyDistributionToCsv(const QString &file)
Write frequency of elevation values to file for manual inspection.
QString number(int n, int base)
void append(const T &value)
float processNineCellWindow(float *x11, float *x21, float *x31, float *x12, float *x22, float *x32, float *x13, float *x23, float *x33) override
Calculates output value from nine input values.
void setInputNodataValue(double value)
Calculates aspect values in a window of 3x3 cells based on first order derivatives in x- and y- direc...
void setCellSizeX(double size)
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
QByteArray toLocal8Bit() const
const T & at(int i) const
float processNineCellWindow(float *x11, float *x21, float *x31, float *x12, float *x22, float *x32, float *x13, float *x23, float *x33) override
Calculates output value from nine input values.
Calculates slope values in a window of 3x3 cells based on first order derivatives in x- and y- direct...
void setOutputNodataValue(double value)
void push_back(const T &value)
QgsRelief(const QString &inputFile, const QString &outputFile, const QString &outputFormat)
const_iterator constEnd() const
const_iterator constBegin() const