diff --git a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py index a93ae2cf7f09..7ec40a0afb7d 100644 --- a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py +++ b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py @@ -124,6 +124,7 @@ from .RandomSelection import RandomSelection from .RandomSelectionWithinSubsets import RandomSelectionWithinSubsets from .Rasterize import RasterizeAlgorithm +from .RasterCalculator import RasterCalculator from .RasterLayerStatistics import RasterLayerStatistics from .RectanglesOvalsDiamondsFixed import RectanglesOvalsDiamondsFixed from .RectanglesOvalsDiamondsVariable import RectanglesOvalsDiamondsVariable @@ -172,7 +173,6 @@ # from .SpatialJoin import SpatialJoin # from .GeometryConvert import GeometryConvert # from .SelectByAttributeSum import SelectByAttributeSum -# from .RasterCalculator import RasterCalculator pluginPath = os.path.normpath(os.path.join( os.path.split(os.path.dirname(__file__))[0], os.pardir)) @@ -192,8 +192,6 @@ def getAlgs(self): # SpatialJoin(), # GeometryConvert(), # SelectByAttributeSum() - # RasterCalculator(), - # # ] algs = [AddTableField(), Aggregate(), @@ -278,6 +276,7 @@ def getAlgs(self): RandomPointsPolygons(), RandomSelection(), RandomSelectionWithinSubsets(), + RasterCalculator(), RasterizeAlgorithm(), RasterLayerStatistics(), RectanglesOvalsDiamondsFixed(), diff --git a/python/plugins/processing/algs/qgis/RasterCalculator.py b/python/plugins/processing/algs/qgis/RasterCalculator.py index 87a0b31e3f30..6944729e5006 100644 --- a/python/plugins/processing/algs/qgis/RasterCalculator.py +++ b/python/plugins/processing/algs/qgis/RasterCalculator.py @@ -16,7 +16,7 @@ * * *************************************************************************** """ -from processing.modeler.ModelerAlgorithm import ValueFromInput, ValueFromOutput + import os __author__ = 'Victor Olaya' @@ -29,17 +29,18 @@ import math from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm -from processing.core.parameters import ParameterMultipleInput, ParameterExtent, ParameterString, ParameterRaster, ParameterNumber -from processing.core.outputs import OutputRaster -from processing.tools import dataobjects from processing.algs.gdal.GdalUtils import GdalUtils -from qgis.core import (QgsApplication, - QgsRectangle, +from qgis.core import (QgsProcessing, + QgsProcessingException, QgsProcessingUtils, - QgsProject) + QgsProcessingParameterMultipleLayers, + QgsProcessingParameterNumber, + QgsProcessingParameterExtent, + QgsProcessingParameterRasterDestination, + QgsProcessingParameterRasterLayer, + QgsProcessingOutputRasterLayer, + QgsProcessingParameterString) from qgis.analysis import QgsRasterCalculator, QgsRasterCalculatorEntry -from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException -from processing.algs.qgis.ui.RasterCalculatorWidgets import LayersListWidgetWrapper, ExpressionWidgetWrapper class RasterCalculator(QgisAlgorithm): @@ -57,25 +58,38 @@ def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(ParameterMultipleInput(self.LAYERS, - self.tr('Input layers'), - datatype=dataobjects.TYPE_RASTER, - optional=True, - metadata={'widget_wrapper': LayersListWidgetWrapper})) + layer_param = QgsProcessingParameterMultipleLayers(self.LAYERS, + self.tr('Input layers'), + layerType=QgsProcessing.TypeRaster, + optional=True) + layer_param.setMetadata({'widget_wrapper': 'processing.algs.qgis.ui.RasterCalculatorWidgets.LayersListWidgetWrapper'}) + self.addParameter(layer_param) + + class ParameterRasterCalculatorExpression(QgsProcessingParameterString): + + def __init__(self, name='', description='', multiLine=False): + super().__init__(name, description, multiLine=multiLine) + self.setMetadata({ + 'widget_wrapper': 'processing.algs.qgis.ui.RasterCalculatorWidgets.ExpressionWidgetWrapper' + }) - class ParameterRasterCalculatorExpression(ParameterString): + def type(self): + return 'raster_calc_expression' + + def clone(self): + return ParameterRasterCalculatorExpression(self.name(), self.description(), self.multiLine()) def evaluateForModeler(self, value, model): for i in list(model.inputs.values()): param = i.param - if isinstance(param, ParameterRaster): + if isinstance(param, QgsProcessingParameterRasterLayer): new = "{}@".format(os.path.basename(param.value)) old = "{}@".format(param.name()) value = value.replace(old, new) for alg in list(model.algs.values()): for out in alg.algorithm.outputs: - if isinstance(out, OutputRaster): + if isinstance(out, QgsProcessingOutputRasterLayer): if out.value: new = "{}@".format(os.path.basename(out.value)) old = "{}:{}@".format(alg.modeler_name, out.name) @@ -83,15 +97,15 @@ def evaluateForModeler(self, value, model): return value self.addParameter(ParameterRasterCalculatorExpression(self.EXPRESSION, self.tr('Expression'), - multiline=True, - metadata={'widget_wrapper': ExpressionWidgetWrapper})) - self.addParameter(ParameterNumber(self.CELLSIZE, - self.tr('Cell size (use 0 or empty to set it automatically)'), - minValue=0.0, default=0.0, optional=True)) - self.addParameter(ParameterExtent(self.EXTENT, - self.tr('Output extent'), - optional=True)) - self.addOutput(OutputRaster(self.OUTPUT, self.tr('Output'))) + multiLine=True)) + self.addParameter(QgsProcessingParameterNumber(self.CELLSIZE, + self.tr('Cell size (use 0 or empty to set it automatically)'), + type=QgsProcessingParameterNumber.Double, + minValue=0.0, defaultValue=0.0, optional=True)) + self.addParameter(QgsProcessingParameterExtent(self.EXTENT, + self.tr('Output extent'), + optional=True)) + self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Output'))) def name(self): return 'rastercalculator' @@ -100,11 +114,10 @@ def displayName(self): return self.tr('Raster calculator') def processAlgorithm(self, parameters, context, feedback): - expression = self.getParameterValue(self.EXPRESSION) - layersValue = self.getParameterValue(self.LAYERS) + expression = self.parameterAsString(parameters, self.EXPRESSION, context) + layers = self.parameterAsLayerList(parameters, self.LAYERS, context) layersDict = {} - if layersValue: - layers = [QgsProcessingUtils.mapLayerFromString(f, context) for f in layersValue.split(";")] + if layers: layersDict = {os.path.basename(lyr.source().split(".")[0]): lyr for lyr in layers} for lyr in QgsProcessingUtils.compatibleRasterLayers(context.project()): @@ -121,26 +134,22 @@ def processAlgorithm(self, parameters, context, feedback): entry.bandNumber = n + 1 entries.append(entry) - output = self.getOutputValue(self.OUTPUT) - extentValue = self.getParameterValue(self.EXTENT) - if not extentValue: - extentValue = QgsProcessingUtils.combineLayerExtents(layersValue) + output = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) + bbox = self.parameterAsExtent(parameters, self.EXTENT, context) + if bbox.isNull(): + bbox = QgsProcessingUtils.combineLayerExtents(layers) - if extentValue: - extent = extentValue.split(',') - bbox = QgsRectangle(float(extent[0]), float(extent[2]), - float(extent[1]), float(extent[3])) - else: + if bbox.isNull(): if layersDict: bbox = list(layersDict.values())[0].extent() for lyr in layersDict.values(): bbox.combineExtentWith(lyr.extent()) else: - raise GeoAlgorithmExecutionException(self.tr("No layers selected")) + raise QgsProcessingException(self.tr("No layers selected")) def _cellsize(layer): return (layer.extent().xMaximum() - layer.extent().xMinimum()) / layer.width() - cellsize = self.getParameterValue(self.CELLSIZE) or min([_cellsize(lyr) for lyr in layersDict.values()]) + cellsize = self.parameterAsDouble(parameters, self.CELLSIZE, context) or min([_cellsize(lyr) for lyr in layersDict.values()]) width = math.floor((bbox.xMaximum() - bbox.xMinimum()) / cellsize) height = math.floor((bbox.yMaximum() - bbox.yMinimum()) / cellsize) driverName = GdalUtils.getFormatShortNameFromFilename(output) @@ -154,14 +163,16 @@ def _cellsize(layer): res = calc.processCalculation() if res == QgsRasterCalculator.ParserError: - raise GeoAlgorithmExecutionException(self.tr("Error parsing formula")) + raise QgsProcessingException(self.tr("Error parsing formula")) + + return {self.OUTPUT: output} def processBeforeAddingToModeler(self, algorithm, model): values = [] expression = algorithm.params[self.EXPRESSION] for i in list(model.inputs.values()): param = i.param - if isinstance(param, ParameterRaster) and "{}@".format(param.name) in expression: + if isinstance(param, QgsProcessingParameterRasterLayer) and "{}@".format(param.name) in expression: values.append(ValueFromInput(param.name())) if algorithm.name: @@ -171,7 +182,7 @@ def processBeforeAddingToModeler(self, algorithm, model): for alg in list(model.algs.values()): if alg.modeler_name not in dependent: for out in alg.algorithm.outputs: - if (isinstance(out, OutputRaster) and + if (isinstance(out, QgsProcessingOutputRasterLayer) and "{}:{}@".format(alg.modeler_name, out.name) in expression): values.append(ValueFromOutput(alg.modeler_name, out.name)) diff --git a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml index 4d4fba9b4373..aae17f4b2c07 100644 --- a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml +++ b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml @@ -2210,35 +2210,35 @@ tests: - 'Maximum value: 15:29:22' - 'NULL \(missing\) values: 1' -# - algorithm: qgis:rastercalculator -# name: Raster Calculator with cellsize -# params: -# LAYERS: -# params: -# - name: dem.tif -# type: raster -# type: multi -# CELLSIZE: 0.001 -# EXPRESSION: dem@1 -# results: -# OUTPUT: -# hash: ef97a22ee16e0e28bbdc0341449777b1527e37febc3c4339b2c057c9 -# type: rasterhash -# -# - algorithm: qgis:rastercalculator -# name: Raster Calculator -# params: -# LAYERS: -# params: -# - name: dem.tif -# type: raster -# type: multi -# CELLSIZE: 0.0 -# EXPRESSION: dem@1 * 2 -# results: -# OUTPUT: -# hash: fe6e018be13c5a3c17f3f4d0f0dc7686c628cb440b74c4642aa0c939 -# type: rasterhash + - algorithm: qgis:rastercalculator + name: Raster Calculator with cellsize + params: + LAYERS: + params: + - name: dem.tif + type: raster + type: multi + CELLSIZE: 0.001 + EXPRESSION: dem@1 + results: + OUTPUT: + hash: ef97a22ee16e0e28bbdc0341449777b1527e37febc3c4339b2c057c9 + type: rasterhash + + - algorithm: qgis:rastercalculator + name: Raster Calculator + params: + LAYERS: + params: + - name: dem.tif + type: raster + type: multi + CELLSIZE: 0.0 + EXPRESSION: dem@1 * 2 + results: + OUTPUT: + hash: fe6e018be13c5a3c17f3f4d0f0dc7686c628cb440b74c4642aa0c939 + type: rasterhash - algorithm: qgis:orientedminimumboundingbox name: Oriented minimum bounding box polys