Skip to content

Commit

Permalink
refactor qgsalgorithmrasterequaltofrequency to qgsalgorithmrasterfreq…
Browse files Browse the repository at this point in the history
…uencybycompariosnoperator, add new Greater than frequency and Less than frequency algorithms
  • Loading branch information
root676 authored and nyalldawson committed Jul 28, 2020
1 parent 3fe46e0 commit eb63902
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 66 deletions.
2 changes: 1 addition & 1 deletion src/analysis/CMakeLists.txt
Expand Up @@ -127,7 +127,7 @@ SET(QGIS_ANALYSIS_SRCS
processing/qgsalgorithmrandompointsinpolygons.cpp
processing/qgsalgorithmrandompointsonlines.cpp
processing/qgsalgorithmrandomraster.cpp
processing/qgsalgorithmrasterequaltofrequency.cpp
processing/qgsalgorithmrasterfrequencybycomparisonoperator.cpp
processing/qgsalgorithmrasterlayeruniquevalues.cpp
processing/qgsalgorithmrasterlogicalop.cpp
processing/qgsalgorithmrasterize.cpp
Expand Down
@@ -1,5 +1,5 @@
/***************************************************************************
qgsalgorithmrasterequaltofrequency.cpp
qgsalgorithmrasterfrequencybycomparisonoperator.cpp
---------------------
begin : June 2020
copyright : (C) 2020 by Clemens Raffler
Expand All @@ -15,58 +15,28 @@
* *
***************************************************************************/

#include "qgsalgorithmrasterequaltofrequency.h"
#include "qgsalgorithmrasterfrequencybycomparisonoperator.h"
#include "qgsrasterprojector.h"
#include "qgsrasterfilewriter.h"
#include "qgsrasteranalysisutils.h"

///@cond PRIVATE

QString QgsRasterEqualToFrequencyAlgorithm::displayName() const
{
return QObject::tr( "Equal to frequency" );
}

QString QgsRasterEqualToFrequencyAlgorithm::name() const
{
return QObject::tr( "equaltofrequency" );
}
//
//QgsRasterFrequencyByComparisonOperatorBase
//

QStringList QgsRasterEqualToFrequencyAlgorithm::tags() const
{
return QObject::tr( "cell,equal,frequency,pixel,stack" ).split( ',' );
}

QString QgsRasterEqualToFrequencyAlgorithm::group() const
QString QgsRasterFrequencyByComparisonOperatorBase::group() const
{
return QObject::tr( "Raster analysis" );
}

QString QgsRasterEqualToFrequencyAlgorithm::groupId() const
QString QgsRasterFrequencyByComparisonOperatorBase::groupId() const
{
return QStringLiteral( "rasteranalysis" );
}

QString QgsRasterEqualToFrequencyAlgorithm::shortHelpString() const
{
return QObject::tr( "The Equal to frequency algorithm evaluates on a cell-by-cell basis the frequency "
"(number of times) the values of an input stack of rasters are equal "
"to the value of an input raster. \n "
"If multiband rasters are used in the data raster stack, the algorithm will always "
"perform the analysis on the first band of the rasters - use GDAL to use other bands in the analysis."
"The input value layer serves as reference layer for the sample layers."
"Any NoData cells in the value raster or the data layer stack will result in a NoData cell "
"in the output raster if the ignore NoData parameter is not checked."
"The output NoData value can be set manually. The output rasters extent and resolution "
"is defined by the input raster layer and is always of int32 type." );
}

QgsRasterEqualToFrequencyAlgorithm *QgsRasterEqualToFrequencyAlgorithm::createInstance() const
{
return new QgsRasterEqualToFrequencyAlgorithm();
}

void QgsRasterEqualToFrequencyAlgorithm::initAlgorithm( const QVariantMap & )
void QgsRasterFrequencyByComparisonOperatorBase::initAlgorithm( const QVariantMap & )
{
addParameter( new QgsProcessingParameterRasterLayer( QStringLiteral( "INPUT_VALUE_RASTER" ), QObject::tr( "Input value raster" ) ) );
addParameter( new QgsProcessingParameterBand( QStringLiteral( "INPUT_VALUE_RASTER_BAND" ), QObject::tr( "Value raster band" ), 1, QStringLiteral( "INPUT_VALUE_RASTER" ) ) );
Expand All @@ -83,7 +53,7 @@ void QgsRasterEqualToFrequencyAlgorithm::initAlgorithm( const QVariantMap & )

addParameter( new QgsProcessingParameterRasterDestination( QStringLiteral( "OUTPUT" ),
QObject::tr( "Output layer" ) ) );
addOutput( new QgsProcessingOutputNumber( QStringLiteral( "EQUAL_VALUES_COUNT" ), QObject::tr( "Count of equal value occurrances" ) ) );
addOutput( new QgsProcessingOutputNumber( QStringLiteral( "OCCURENCE_COUNT" ), QObject::tr( "Count of value occurrances" ) ) );
addOutput( new QgsProcessingOutputNumber( QStringLiteral( "FOUND_LOCATIONS_COUNT" ), QObject::tr( "Count of cells with equal value occurrances" ) ) );
addOutput( new QgsProcessingOutputNumber( QStringLiteral( "MEAN_FREQUENCY_PER_LOCATION" ), QObject::tr( "Mean frequency at valid cell locations" ) ) );
addOutput( new QgsProcessingOutputString( QStringLiteral( "EXTENT" ), QObject::tr( "Extent" ) ) );
Expand All @@ -93,7 +63,7 @@ void QgsRasterEqualToFrequencyAlgorithm::initAlgorithm( const QVariantMap & )
addOutput( new QgsProcessingOutputNumber( QStringLiteral( "TOTAL_PIXEL_COUNT" ), QObject::tr( "Total pixel count" ) ) );
}

bool QgsRasterEqualToFrequencyAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
bool QgsRasterFrequencyByComparisonOperatorBase::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
QgsRasterLayer *inputValueRaster = parameterAsRasterLayer( parameters, QStringLiteral( "INPUT_VALUE_RASTER" ), context );
if ( !inputValueRaster )
Expand Down Expand Up @@ -142,7 +112,7 @@ bool QgsRasterEqualToFrequencyAlgorithm::prepareAlgorithm( const QVariantMap &pa
return true;
}

QVariantMap QgsRasterEqualToFrequencyAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
QVariantMap QgsRasterFrequencyByComparisonOperatorBase::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
const QString outputFile = parameterAsOutputLayer( parameters, QStringLiteral( "OUTPUT" ), context );
QFileInfo fi( outputFile );
Expand Down Expand Up @@ -175,7 +145,7 @@ QVariantMap QgsRasterEqualToFrequencyAlgorithm::processAlgorithm( const QVariant
int iterRows = 0;
QgsRectangle blockExtent;

unsigned long long equalValuesCount = 0;
unsigned long long occurrenceCount = 0;
unsigned long long noDataLocationsCount = 0;
std::unique_ptr< QgsRasterBlock > inputBlock;
while ( iter.readNextRasterPart( 1, iterCols, iterRows, inputBlock, iterLeft, iterTop, &blockExtent ) )
Expand Down Expand Up @@ -207,7 +177,7 @@ QVariantMap QgsRasterEqualToFrequencyAlgorithm::processAlgorithm( const QVariant
std::vector<double> cellValues = QgsRasterAnalysisUtils::getCellValuesFromBlockStack( inputBlocks, row, col, noDataInStack );

bool valueRasterCellIsNoData = false;
double searchValue = inputBlock->valueAndNoData( row, col, valueRasterCellIsNoData );
double value = inputBlock->valueAndNoData( row, col, valueRasterCellIsNoData );

if ( ( valueRasterCellIsNoData || noDataInStack ) && !mIgnoreNoData )
{
Expand All @@ -218,9 +188,9 @@ QVariantMap QgsRasterEqualToFrequencyAlgorithm::processAlgorithm( const QVariant
}
else
{
int equalCount = static_cast<int>( std::count( cellValues.begin(), cellValues.end(), searchValue ) );
outputBlock->setValue( row, col, equalCount );
equalValuesCount += equalCount;
int frequency = applyComparisonOperator( value, cellValues );
outputBlock->setValue( row, col, frequency );
occurrenceCount += frequency;
}
}
}
Expand All @@ -229,10 +199,10 @@ QVariantMap QgsRasterEqualToFrequencyAlgorithm::processAlgorithm( const QVariant
provider->setEditable( false );

unsigned long long foundLocationsCount = layerSize - noDataLocationsCount;
double meanEqualCountPerValidLocation = static_cast<double>( equalValuesCount ) / static_cast<double>( foundLocationsCount * mInputs.size() );
double meanEqualCountPerValidLocation = static_cast<double>( occurrenceCount ) / static_cast<double>( foundLocationsCount * mInputs.size() );

QVariantMap outputs;
outputs.insert( QStringLiteral( "EQUAL_VALUES_COUNT" ), equalValuesCount );
outputs.insert( QStringLiteral( "OCCURENCE_COUNT" ), occurrenceCount );
outputs.insert( QStringLiteral( "FOUND_LOCATIONS_COUNT" ), foundLocationsCount );
outputs.insert( QStringLiteral( "MEAN_FREQUENCY_PER_LOCATION" ), meanEqualCountPerValidLocation );
outputs.insert( QStringLiteral( "EXTENT" ), mExtent.toString() );
Expand All @@ -245,7 +215,134 @@ QVariantMap QgsRasterEqualToFrequencyAlgorithm::processAlgorithm( const QVariant
return outputs;
}

//
// QgsRasterFrequencyByEqualOperatorAlgorithm
//

QString QgsRasterFrequencyByEqualOperatorAlgorithm::displayName() const
{
return QObject::tr( "Equal to frequency" );
}

QString QgsRasterFrequencyByEqualOperatorAlgorithm::name() const
{
return QObject::tr( "equaltofrequency" );
}

QStringList QgsRasterFrequencyByEqualOperatorAlgorithm::tags() const
{
return QObject::tr( "cell,equal,frequency,pixel,stack" ).split( ',' );
}

QString QgsRasterFrequencyByEqualOperatorAlgorithm::shortHelpString() const
{
return QObject::tr( "The Equal to frequency algorithm evaluates on a cell-by-cell basis the frequency "
"(number of times) the values of an input stack of rasters are equal "
"to the value of a value raster. \n "
"If multiband rasters are used in the data raster stack, the algorithm will always "
"perform the analysis on the first band of the rasters - use GDAL to use other bands in the analysis."
"The input value layer serves as reference layer for the sample layers."
"Any NoData cells in the value raster or the data layer stack will result in a NoData cell "
"in the output raster if the ignore NoData parameter is not checked."
"The output NoData value can be set manually. The output rasters extent and resolution "
"is defined by the input raster layer and is always of int32 type." );
}

QgsRasterFrequencyByEqualOperatorAlgorithm *QgsRasterFrequencyByEqualOperatorAlgorithm::createInstance() const
{
return new QgsRasterFrequencyByEqualOperatorAlgorithm();
}

int QgsRasterFrequencyByEqualOperatorAlgorithm::applyComparisonOperator( double searchValue, std::vector<double> cellValueStack )
{
return static_cast<int>( std::count( cellValueStack.begin(), cellValueStack.end(), searchValue ) );
}

//
// QgsRasterFrequencyByGreaterThanOperatorAlgorithm
//

QString QgsRasterFrequencyByGreaterThanOperatorAlgorithm::displayName() const
{
return QObject::tr( "Greater than frequency" );
}

QString QgsRasterFrequencyByGreaterThanOperatorAlgorithm::name() const
{
return QObject::tr( "greaterthanfrequency" );
}

QStringList QgsRasterFrequencyByGreaterThanOperatorAlgorithm::tags() const
{
return QObject::tr( "cell,greater,frequency,pixel,stack" ).split( ',' );
}

QString QgsRasterFrequencyByGreaterThanOperatorAlgorithm::shortHelpString() const
{
return QObject::tr( "The Greater than frequency algorithm evaluates on a cell-by-cell basis the frequency "
"(number of times) the values of an input stack of rasters are greater than "
" the value of a value raster. \n "
"If multiband rasters are used in the data raster stack, the algorithm will always "
"perform the analysis on the first band of the rasters - use GDAL to use other bands in the analysis."
"The input value layer serves as reference layer for the sample layers."
"Any NoData cells in the value raster or the data layer stack will result in a NoData cell "
"in the output raster if the ignore NoData parameter is not checked."
"The output NoData value can be set manually. The output rasters extent and resolution "
"is defined by the input raster layer and is always of int32 type." );
}

QgsRasterFrequencyByGreaterThanOperatorAlgorithm *QgsRasterFrequencyByGreaterThanOperatorAlgorithm::createInstance() const
{
return new QgsRasterFrequencyByGreaterThanOperatorAlgorithm();
}

int QgsRasterFrequencyByGreaterThanOperatorAlgorithm::applyComparisonOperator( double searchValue, std::vector<double> cellValueStack )
{
return static_cast<int>( std::count_if(cellValueStack.begin(), cellValueStack.end(),[&](double const& stackValue){ return stackValue > searchValue; }) );
}

//
// QgsRasterFrequencyByLessThanOperatorAlgorithm
//

QString QgsRasterFrequencyByLessThanOperatorAlgorithm::displayName() const
{
return QObject::tr( "Less than frequency" );
}

QString QgsRasterFrequencyByLessThanOperatorAlgorithm::name() const
{
return QObject::tr( "lessthanfrequency" );
}

QStringList QgsRasterFrequencyByLessThanOperatorAlgorithm::tags() const
{
return QObject::tr( "cell,less,lower,frequency,pixel,stack" ).split( ',' );
}

QString QgsRasterFrequencyByLessThanOperatorAlgorithm::shortHelpString() const
{
return QObject::tr( "The Less than frequency algorithm evaluates on a cell-by-cell basis the frequency "
"(number of times) the values of an input stack of rasters are less than "
" the value of a value raster. \n "
"If multiband rasters are used in the data raster stack, the algorithm will always "
"perform the analysis on the first band of the rasters - use GDAL to use other bands in the analysis."
"The input value layer serves as reference layer for the sample layers."
"Any NoData cells in the value raster or the data layer stack will result in a NoData cell "
"in the output raster if the ignore NoData parameter is not checked."
"The output NoData value can be set manually. The output rasters extent and resolution "
"is defined by the input raster layer and is always of int32 type." );
}

QgsRasterFrequencyByLessThanOperatorAlgorithm *QgsRasterFrequencyByLessThanOperatorAlgorithm::createInstance() const
{
return new QgsRasterFrequencyByLessThanOperatorAlgorithm();
}

int QgsRasterFrequencyByLessThanOperatorAlgorithm::applyComparisonOperator( double searchValue, std::vector<double> cellValueStack )
{
return static_cast<int>( std::count_if(cellValueStack.begin(), cellValueStack.end(),[&](double const& stackValue){ return stackValue < searchValue; }) );
}

///@endcond

Expand Down
@@ -1,5 +1,5 @@
/***************************************************************************
qgsalgorithmrasterequaltofrequency.h
qgsalgorithmrasterfrequencybycomparisonoperator.h
---------------------
begin : June 2020
copyright : (C) 2020 by Clemens Raffler
Expand All @@ -15,8 +15,8 @@
* *
***************************************************************************/

#ifndef QGSALGORITHMRASTEREQUALTOFREQUENCY_H
#define QGSALGORITHMRASTEREQUALTOFREQUENCY_H
#ifndef QGSALGORITHMRASTERFREQUENCYBYCOMPARISON_H
#define QGSALGORITHMRASTERFREQUENCYBYCOMPARISON_H

#define SIP_NO_FILE

Expand All @@ -28,25 +28,18 @@

///@cond PRIVATE

class QgsRasterEqualToFrequencyAlgorithm : public QgsProcessingAlgorithm
class QgsRasterFrequencyByComparisonOperatorBase : public QgsProcessingAlgorithm
{

public:
QgsRasterEqualToFrequencyAlgorithm() = default;
QgsRasterFrequencyByComparisonOperatorBase() = default;
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
QString name() const override;
QString displayName() const override;
QStringList tags() const override;
QString group() const override;
QString groupId() const override;
QString shortHelpString() const override;
QgsRasterEqualToFrequencyAlgorithm *createInstance() const override SIP_FACTORY;

protected:

bool prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
virtual int applyComparisonOperator( double value, std::vector<double>cellValueStack ) = 0;

private:
std::unique_ptr< QgsRasterInterface > mInputValueRasterInterface;
Expand All @@ -62,7 +55,49 @@ class QgsRasterEqualToFrequencyAlgorithm : public QgsProcessingAlgorithm
double mRasterUnitsPerPixelY;
};

class QgsRasterFrequencyByEqualOperatorAlgorithm : public QgsRasterFrequencyByComparisonOperatorBase
{
public:
QgsRasterFrequencyByEqualOperatorAlgorithm() = default;
QString name() const override;
QString displayName() const override;
QStringList tags() const override;
QString shortHelpString() const override;
QgsRasterFrequencyByEqualOperatorAlgorithm *createInstance() const override SIP_FACTORY;

protected:
int applyComparisonOperator( double searchValue, std::vector<double>cellValueStack ) override;
};

class QgsRasterFrequencyByGreaterThanOperatorAlgorithm : public QgsRasterFrequencyByComparisonOperatorBase
{
public:
QgsRasterFrequencyByGreaterThanOperatorAlgorithm() = default;
QString name() const override;
QString displayName() const override;
QStringList tags() const override;
QString shortHelpString() const override;
QgsRasterFrequencyByGreaterThanOperatorAlgorithm *createInstance() const override SIP_FACTORY;

protected:
int applyComparisonOperator( double value, std::vector<double>cellValueStack ) override;
};

class QgsRasterFrequencyByLessThanOperatorAlgorithm : public QgsRasterFrequencyByComparisonOperatorBase
{
public:
QgsRasterFrequencyByLessThanOperatorAlgorithm() = default;
QString name() const override;
QString displayName() const override;
QStringList tags() const override;
QString shortHelpString() const override;
QgsRasterFrequencyByLessThanOperatorAlgorithm *createInstance() const override SIP_FACTORY;

protected:
int applyComparisonOperator( double value, std::vector<double>cellValueStack ) override;
};

///@endcond PRIVATE

#endif // QGSALGORITHMRASTEREQUALTOFREQUENCY_H
#endif // QGSALGORITHMRASTERFREQUENCYBYCOMPARISON_H

0 comments on commit eb63902

Please sign in to comment.