26using namespace Qt::StringLiterals;
34QString QgsRasterFrequencyByComparisonOperatorBase::group()
const
36 return QObject::tr(
"Raster analysis" );
39QString QgsRasterFrequencyByComparisonOperatorBase::groupId()
const
41 return u
"rasteranalysis"_s;
44void QgsRasterFrequencyByComparisonOperatorBase::initAlgorithm(
const QVariantMap & )
47 addParameter(
new QgsProcessingParameterBand( u
"INPUT_VALUE_RASTER_BAND"_s, QObject::tr(
"Value raster band" ), 1, u
"INPUT_VALUE_RASTER"_s ) );
53 addParameter( output_nodata_parameter.release() );
57 auto createOptsParam = std::make_unique<QgsProcessingParameterString>( u
"CREATE_OPTIONS"_s, QObject::tr(
"Creation options" ), QVariant(),
false,
true );
58 createOptsParam->setMetadata( QVariantMap( { { u
"widget_wrapper"_s, QVariantMap( { { u
"widget_type"_s, u
"rasteroptions"_s } } ) } } ) );
60 addParameter( createOptsParam.release() );
62 auto creationOptsParam = std::make_unique<QgsProcessingParameterString>( u
"CREATION_OPTIONS"_s, QObject::tr(
"Creation options" ), QVariant(),
false,
true );
63 creationOptsParam->setMetadata( QVariantMap( { { u
"widget_wrapper"_s, QVariantMap( { { u
"widget_type"_s, u
"rasteroptions"_s } } ) } } ) );
65 addParameter( creationOptsParam.release() );
69 addOutput(
new QgsProcessingOutputNumber( u
"FOUND_LOCATIONS_COUNT"_s, QObject::tr(
"Count of cells with equal value occurrences" ) ) );
70 addOutput(
new QgsProcessingOutputNumber( u
"MEAN_FREQUENCY_PER_LOCATION"_s, QObject::tr(
"Mean frequency at valid cell locations" ) ) );
80 QgsRasterLayer *inputValueRaster = parameterAsRasterLayer( parameters, u
"INPUT_VALUE_RASTER"_s, context );
81 if ( !inputValueRaster )
84 mInputValueRasterBand = parameterAsInt( parameters, u
"INPUT_VALUE_RASTER_BAND"_s, context );
85 mIgnoreNoData = parameterAsBool( parameters, u
"IGNORE_NODATA"_s, context );
88 mNoDataValue = parameterAsDouble( parameters, u
"OUTPUT_NODATA_VALUE"_s, context );
89 mCrs = inputValueRaster->
crs();
92 mLayerWidth = inputValueRaster->
width();
93 mLayerHeight = inputValueRaster->
height();
94 mExtent = inputValueRaster->
extent();
96 const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, u
"INPUT_RASTERS"_s, context );
97 QList<QgsRasterLayer *> rasterLayers;
98 rasterLayers.reserve( layers.count() );
107 QgsRasterAnalysisUtils::RasterLogicInput input;
111 input.interface = input.sourceDataProvider.get();
113 if ( layer->
crs() != mCrs )
115 input.projector = std::make_unique<QgsRasterProjector>();
116 input.projector->setInput( input.sourceDataProvider.get() );
118 input.interface = input.projector.get();
120 mInputs.emplace_back( std::move( input ) );
129 QString creationOptions = parameterAsString( parameters, u
"CREATION_OPTIONS"_s, context ).trimmed();
131 const QString optionsString = parameterAsString( parameters, u
"CREATE_OPTIONS"_s, context );
132 if ( !optionsString.isEmpty() )
133 creationOptions = optionsString;
135 const QString outputFile = parameterAsOutputLayer( parameters, u
"OUTPUT"_s, context );
136 const QString outputFormat = parameterAsOutputRasterFormat( parameters, u
"OUTPUT"_s, context );
138 auto writer = std::make_unique<QgsRasterFileWriter>( outputFile );
139 writer->setOutputProviderKey( u
"gdal"_s );
140 if ( !creationOptions.isEmpty() )
142 writer->setCreationOptions( creationOptions.split(
'|' ) );
144 writer->setOutputFormat( outputFormat );
145 std::unique_ptr<QgsRasterDataProvider> provider( writer->createOneBandRaster(
Qgis::DataType::Int32, mLayerWidth, mLayerHeight, mExtent, mCrs ) );
148 if ( !provider->isValid() )
151 provider->setNoDataValue( 1, mNoDataValue );
152 const qgssize layerSize =
static_cast<qgssize>( mLayerWidth ) *
static_cast<qgssize>( mLayerHeight );
154 provider->setEditable(
true );
157 iter.startRasterRead( mInputValueRasterBand, mLayerWidth, mLayerHeight, mExtent );
164 const bool hasReportsDuringClose = provider->hasReportsDuringClose();
165 const double maxProgressDuringBlockWriting = hasReportsDuringClose ? 50.0 : 100.0;
167 unsigned long long occurrenceCount = 0;
168 unsigned long long noDataLocationsCount = 0;
169 std::unique_ptr<QgsRasterBlock> inputBlock;
170 while ( iter.readNextRasterPart( 1, iterCols, iterRows, inputBlock, iterLeft, iterTop, &blockExtent ) )
172 std::vector<std::unique_ptr<QgsRasterBlock>> inputBlocks;
173 for (
const QgsRasterAnalysisUtils::RasterLogicInput &i : mInputs )
177 for (
const int band : i.bands )
181 std::unique_ptr<QgsRasterBlock> b( i.interface->block( band, blockExtent, iterCols, iterRows ) );
182 inputBlocks.emplace_back( std::move( b ) );
187 feedback->
setProgress( maxProgressDuringBlockWriting * iter.progress( 1 ) );
188 for (
int row = 0; row < iterRows; row++ )
193 for (
int col = 0; col < iterCols; col++ )
195 bool valueRasterCellIsNoData =
false;
196 const double value = inputBlock->valueAndNoData( row, col, valueRasterCellIsNoData );
198 if ( valueRasterCellIsNoData && !mIgnoreNoData )
202 outputBlock->setValue( row, col, mNoDataValue );
203 noDataLocationsCount++;
207 bool noDataInStack =
false;
208 const std::vector<double> cellValues = QgsRasterAnalysisUtils::getCellValuesFromBlockStack( inputBlocks, row, col, noDataInStack );
210 if ( noDataInStack && !mIgnoreNoData )
212 outputBlock->setValue( row, col, mNoDataValue );
213 noDataLocationsCount++;
217 const int frequency = applyComparisonOperator( value, cellValues );
218 outputBlock->setValue( row, col, frequency );
219 occurrenceCount += frequency;
224 if ( !provider->writeBlock( outputBlock.get(), 1, iterLeft, iterTop ) )
226 throw QgsProcessingException( QObject::tr(
"Could not write raster block: %1" ).arg( provider->error().summary() ) );
229 provider->setEditable(
false );
230 if ( feedback && hasReportsDuringClose )
233 if ( !provider->closeWithProgress( scaledFeedback.get() ) )
241 const unsigned long long foundLocationsCount = layerSize - noDataLocationsCount;
242 const double meanEqualCountPerValidLocation =
static_cast<double>( occurrenceCount ) /
static_cast<double>( foundLocationsCount * mInputs.size() );
245 outputs.insert( u
"OCCURRENCE_COUNT"_s, occurrenceCount );
246 outputs.insert( u
"FOUND_LOCATIONS_COUNT"_s, foundLocationsCount );
247 outputs.insert( u
"MEAN_FREQUENCY_PER_LOCATION"_s, meanEqualCountPerValidLocation );
248 outputs.insert( u
"EXTENT"_s, mExtent.toString() );
249 outputs.insert( u
"CRS_AUTHID"_s, mCrs.authid() );
250 outputs.insert( u
"WIDTH_IN_PIXELS"_s, mLayerWidth );
251 outputs.insert( u
"HEIGHT_IN_PIXELS"_s, mLayerHeight );
252 outputs.insert( u
"TOTAL_PIXEL_COUNT"_s, layerSize );
253 outputs.insert( u
"OUTPUT"_s, outputFile );
262QString QgsRasterFrequencyByEqualOperatorAlgorithm::displayName()
const
264 return QObject::tr(
"Equal to frequency" );
267QString QgsRasterFrequencyByEqualOperatorAlgorithm::name()
const
269 return u
"equaltofrequency"_s;
272QStringList QgsRasterFrequencyByEqualOperatorAlgorithm::tags()
const
274 return QObject::tr(
"cell,equal,frequency,pixel,stack" ).split(
',' );
277QString QgsRasterFrequencyByEqualOperatorAlgorithm::shortHelpString()
const
279 return QObject::tr(
"This algorithm evaluates on a cell-by-cell basis the frequency "
280 "(number of times) the values of an input stack of rasters are equal "
281 "to the value of a value raster. \n "
282 "If multiband rasters are used in the data raster stack, the algorithm will always "
283 "perform the analysis on the first band of the rasters - use GDAL to use other bands in the analysis. "
284 "The input value layer serves as reference layer for the sample layers. "
285 "Any NoData cells in the value raster or the data layer stack will result in a NoData cell "
286 "in the output raster if the ignore NoData parameter is not checked. "
287 "The output NoData value can be set manually. The output rasters extent and resolution "
288 "is defined by the input raster layer and is always of int32 type." );
291QString QgsRasterFrequencyByEqualOperatorAlgorithm::shortDescription()
const
293 return QObject::tr(
"Evaluates on a cell-by-cell basis the frequency (number of times) "
294 "the values of an input stack of rasters are equal to the value of a value raster." );
297QgsRasterFrequencyByEqualOperatorAlgorithm *QgsRasterFrequencyByEqualOperatorAlgorithm::createInstance()
const
299 return new QgsRasterFrequencyByEqualOperatorAlgorithm();
302int QgsRasterFrequencyByEqualOperatorAlgorithm::applyComparisonOperator(
double searchValue, std::vector<double> cellValueStack )
304 return static_cast<int>( std::count( cellValueStack.begin(), cellValueStack.end(), searchValue ) );
311QString QgsRasterFrequencyByGreaterThanOperatorAlgorithm::displayName()
const
313 return QObject::tr(
"Greater than frequency" );
316QString QgsRasterFrequencyByGreaterThanOperatorAlgorithm::name()
const
318 return u
"greaterthanfrequency"_s;
321QStringList QgsRasterFrequencyByGreaterThanOperatorAlgorithm::tags()
const
323 return QObject::tr(
"cell,greater,frequency,pixel,stack" ).split(
',' );
326QString QgsRasterFrequencyByGreaterThanOperatorAlgorithm::shortHelpString()
const
328 return QObject::tr(
"This algorithm evaluates on a cell-by-cell basis the frequency "
329 "(number of times) the values of an input stack of rasters are greater than "
330 "the value of a value raster. \n "
331 "If multiband rasters are used in the data raster stack, the algorithm will always "
332 "perform the analysis on the first band of the rasters - use GDAL to use other bands in the analysis. "
333 "The input value layer serves as reference layer for the sample layers. "
334 "Any NoData cells in the value raster or the data layer stack will result in a NoData cell "
335 "in the output raster if the ignore NoData parameter is not checked. "
336 "The output NoData value can be set manually. The output rasters extent and resolution "
337 "is defined by the input raster layer and is always of int32 type." );
340QString QgsRasterFrequencyByGreaterThanOperatorAlgorithm::shortDescription()
const
342 return QObject::tr(
"Evaluates on a cell-by-cell basis the frequency (number of times) "
343 "the values of an input stack of rasters are greater than the value of a value raster." );
346QgsRasterFrequencyByGreaterThanOperatorAlgorithm *QgsRasterFrequencyByGreaterThanOperatorAlgorithm::createInstance()
const
348 return new QgsRasterFrequencyByGreaterThanOperatorAlgorithm();
351int QgsRasterFrequencyByGreaterThanOperatorAlgorithm::applyComparisonOperator(
double searchValue, std::vector<double> cellValueStack )
353 return static_cast<int>( std::count_if( cellValueStack.begin(), cellValueStack.end(), [&](
double const &stackValue ) { return stackValue > searchValue; } ) );
360QString QgsRasterFrequencyByLessThanOperatorAlgorithm::displayName()
const
362 return QObject::tr(
"Less than frequency" );
365QString QgsRasterFrequencyByLessThanOperatorAlgorithm::name()
const
367 return u
"lessthanfrequency"_s;
370QStringList QgsRasterFrequencyByLessThanOperatorAlgorithm::tags()
const
372 return QObject::tr(
"cell,less,lower,frequency,pixel,stack" ).split(
',' );
375QString QgsRasterFrequencyByLessThanOperatorAlgorithm::shortHelpString()
const
377 return QObject::tr(
"This algorithm evaluates on a cell-by-cell basis the frequency "
378 "(number of times) the values of an input stack of rasters are less than "
379 "the value of a value raster. \n "
380 "If multiband rasters are used in the data raster stack, the algorithm will always "
381 "perform the analysis on the first band of the rasters - use GDAL to use other bands in the analysis. "
382 "The input value layer serves as reference layer for the sample layers. "
383 "Any NoData cells in the value raster or the data layer stack will result in a NoData cell "
384 "in the output raster if the ignore NoData parameter is not checked. "
385 "The output NoData value can be set manually. The output rasters extent and resolution "
386 "is defined by the input raster layer and is always of int32 type." );
389QString QgsRasterFrequencyByLessThanOperatorAlgorithm::shortDescription()
const
391 return QObject::tr(
"Evaluates on a cell-by-cell basis the frequency (number of times) "
392 "the values of an input stack of rasters are less than the value of a value raster." );
395QgsRasterFrequencyByLessThanOperatorAlgorithm *QgsRasterFrequencyByLessThanOperatorAlgorithm::createInstance()
const
397 return new QgsRasterFrequencyByLessThanOperatorAlgorithm();
400int QgsRasterFrequencyByLessThanOperatorAlgorithm::applyComparisonOperator(
double searchValue, std::vector<double> cellValueStack )
402 return static_cast<int>( std::count_if( cellValueStack.begin(), cellValueStack.end(), [&](
double const &stackValue ) { return stackValue < searchValue; } ) );
@ Int32
Thirty two bit signed integer (qint32).
@ Hidden
Parameter is hidden and should not be shown to users.
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
@ Double
Double/float values.
bool isCanceled() const
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
static std::unique_ptr< QgsFeedback > createScaledFeedback(QgsFeedback *parentFeedback, double startPercentage, double endPercentage)
Returns a feedback object whose [0, 100] progression range will be mapped to parentFeedback [startPer...
Base class for all map layer types.
virtual QgsRectangle extent() const
Returns the extent of the layer.
QgsCoordinateReferenceSystem crs
Contains information about the context in which a processing algorithm is executed.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
A numeric output for processing algorithms.
A string output for processing algorithms.
A raster band parameter for Processing algorithms.
A boolean parameter for processing algorithms.
A parameter for processing algorithms which accepts multiple map layers.
A raster layer destination parameter, for specifying the destination path for a raster layer created ...
A raster layer parameter for processing algorithms.
QgsRasterDataProvider * clone() const override=0
Clone itself, create deep copy.
virtual bool sourceHasNoDataValue(int bandNo) const
Returns true if source band has no data value.
Iterator for sequentially processing raster cells.
Represents a raster layer.
int height() const
Returns the height of the (unclipped) raster.
double rasterUnitsPerPixelX() const
Returns the number of raster units per each raster pixel in X axis.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
double rasterUnitsPerPixelY() const
Returns the number of raster units per each raster pixel in Y axis.
int width() const
Returns the width of the (unclipped) raster.
A rectangle specified with double values.
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...