Skip to content

Commit

Permalink
Partial port of raster calculator to new API
Browse files Browse the repository at this point in the history
TODO: modeler handling
  • Loading branch information
nyalldawson committed Aug 20, 2017
1 parent 338ee36 commit 4d242c5
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 76 deletions.
5 changes: 2 additions & 3 deletions python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
Expand Up @@ -124,6 +124,7 @@
from .RandomSelection import RandomSelection from .RandomSelection import RandomSelection
from .RandomSelectionWithinSubsets import RandomSelectionWithinSubsets from .RandomSelectionWithinSubsets import RandomSelectionWithinSubsets
from .Rasterize import RasterizeAlgorithm from .Rasterize import RasterizeAlgorithm
from .RasterCalculator import RasterCalculator
from .RasterLayerStatistics import RasterLayerStatistics from .RasterLayerStatistics import RasterLayerStatistics
from .RectanglesOvalsDiamondsFixed import RectanglesOvalsDiamondsFixed from .RectanglesOvalsDiamondsFixed import RectanglesOvalsDiamondsFixed
from .RectanglesOvalsDiamondsVariable import RectanglesOvalsDiamondsVariable from .RectanglesOvalsDiamondsVariable import RectanglesOvalsDiamondsVariable
Expand Down Expand Up @@ -172,7 +173,6 @@
# from .SpatialJoin import SpatialJoin # from .SpatialJoin import SpatialJoin
# from .GeometryConvert import GeometryConvert # from .GeometryConvert import GeometryConvert
# from .SelectByAttributeSum import SelectByAttributeSum # from .SelectByAttributeSum import SelectByAttributeSum
# from .RasterCalculator import RasterCalculator


pluginPath = os.path.normpath(os.path.join( pluginPath = os.path.normpath(os.path.join(
os.path.split(os.path.dirname(__file__))[0], os.pardir)) os.path.split(os.path.dirname(__file__))[0], os.pardir))
Expand All @@ -192,8 +192,6 @@ def getAlgs(self):
# SpatialJoin(), # SpatialJoin(),
# GeometryConvert(), # GeometryConvert(),
# SelectByAttributeSum() # SelectByAttributeSum()
# RasterCalculator(),
#
# ] # ]
algs = [AddTableField(), algs = [AddTableField(),
Aggregate(), Aggregate(),
Expand Down Expand Up @@ -278,6 +276,7 @@ def getAlgs(self):
RandomPointsPolygons(), RandomPointsPolygons(),
RandomSelection(), RandomSelection(),
RandomSelectionWithinSubsets(), RandomSelectionWithinSubsets(),
RasterCalculator(),
RasterizeAlgorithm(), RasterizeAlgorithm(),
RasterLayerStatistics(), RasterLayerStatistics(),
RectanglesOvalsDiamondsFixed(), RectanglesOvalsDiamondsFixed(),
Expand Down
99 changes: 55 additions & 44 deletions python/plugins/processing/algs/qgis/RasterCalculator.py
Expand Up @@ -16,7 +16,7 @@
* * * *
*************************************************************************** ***************************************************************************
""" """
from processing.modeler.ModelerAlgorithm import ValueFromInput, ValueFromOutput
import os import os


__author__ = 'Victor Olaya' __author__ = 'Victor Olaya'
Expand All @@ -29,17 +29,18 @@


import math import math
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm 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 processing.algs.gdal.GdalUtils import GdalUtils
from qgis.core import (QgsApplication, from qgis.core import (QgsProcessing,
QgsRectangle, QgsProcessingException,
QgsProcessingUtils, QgsProcessingUtils,
QgsProject) QgsProcessingParameterMultipleLayers,
QgsProcessingParameterNumber,
QgsProcessingParameterExtent,
QgsProcessingParameterRasterDestination,
QgsProcessingParameterRasterLayer,
QgsProcessingOutputRasterLayer,
QgsProcessingParameterString)
from qgis.analysis import QgsRasterCalculator, QgsRasterCalculatorEntry from qgis.analysis import QgsRasterCalculator, QgsRasterCalculatorEntry
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.algs.qgis.ui.RasterCalculatorWidgets import LayersListWidgetWrapper, ExpressionWidgetWrapper




class RasterCalculator(QgisAlgorithm): class RasterCalculator(QgisAlgorithm):
Expand All @@ -57,41 +58,54 @@ def __init__(self):
super().__init__() super().__init__()


def initAlgorithm(self, config=None): def initAlgorithm(self, config=None):
self.addParameter(ParameterMultipleInput(self.LAYERS, layer_param = QgsProcessingParameterMultipleLayers(self.LAYERS,
self.tr('Input layers'), self.tr('Input layers'),
datatype=dataobjects.TYPE_RASTER, layerType=QgsProcessing.TypeRaster,
optional=True, optional=True)
metadata={'widget_wrapper': LayersListWidgetWrapper})) 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): def evaluateForModeler(self, value, model):
for i in list(model.inputs.values()): for i in list(model.inputs.values()):
param = i.param param = i.param
if isinstance(param, ParameterRaster): if isinstance(param, QgsProcessingParameterRasterLayer):
new = "{}@".format(os.path.basename(param.value)) new = "{}@".format(os.path.basename(param.value))
old = "{}@".format(param.name()) old = "{}@".format(param.name())
value = value.replace(old, new) value = value.replace(old, new)


for alg in list(model.algs.values()): for alg in list(model.algs.values()):
for out in alg.algorithm.outputs: for out in alg.algorithm.outputs:
if isinstance(out, OutputRaster): if isinstance(out, QgsProcessingOutputRasterLayer):
if out.value: if out.value:
new = "{}@".format(os.path.basename(out.value)) new = "{}@".format(os.path.basename(out.value))
old = "{}:{}@".format(alg.modeler_name, out.name) old = "{}:{}@".format(alg.modeler_name, out.name)
value = value.replace(old, new) value = value.replace(old, new)
return value return value


self.addParameter(ParameterRasterCalculatorExpression(self.EXPRESSION, self.tr('Expression'), self.addParameter(ParameterRasterCalculatorExpression(self.EXPRESSION, self.tr('Expression'),
multiline=True, multiLine=True))
metadata={'widget_wrapper': ExpressionWidgetWrapper})) self.addParameter(QgsProcessingParameterNumber(self.CELLSIZE,
self.addParameter(ParameterNumber(self.CELLSIZE, self.tr('Cell size (use 0 or empty to set it automatically)'),
self.tr('Cell size (use 0 or empty to set it automatically)'), type=QgsProcessingParameterNumber.Double,
minValue=0.0, default=0.0, optional=True)) minValue=0.0, defaultValue=0.0, optional=True))
self.addParameter(ParameterExtent(self.EXTENT, self.addParameter(QgsProcessingParameterExtent(self.EXTENT,
self.tr('Output extent'), self.tr('Output extent'),
optional=True)) optional=True))
self.addOutput(OutputRaster(self.OUTPUT, self.tr('Output'))) self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Output')))


def name(self): def name(self):
return 'rastercalculator' return 'rastercalculator'
Expand All @@ -100,11 +114,10 @@ def displayName(self):
return self.tr('Raster calculator') return self.tr('Raster calculator')


def processAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
expression = self.getParameterValue(self.EXPRESSION) expression = self.parameterAsString(parameters, self.EXPRESSION, context)
layersValue = self.getParameterValue(self.LAYERS) layers = self.parameterAsLayerList(parameters, self.LAYERS, context)
layersDict = {} layersDict = {}
if layersValue: if layers:
layers = [QgsProcessingUtils.mapLayerFromString(f, context) for f in layersValue.split(";")]
layersDict = {os.path.basename(lyr.source().split(".")[0]): lyr for lyr in layers} layersDict = {os.path.basename(lyr.source().split(".")[0]): lyr for lyr in layers}


for lyr in QgsProcessingUtils.compatibleRasterLayers(context.project()): for lyr in QgsProcessingUtils.compatibleRasterLayers(context.project()):
Expand All @@ -121,26 +134,22 @@ def processAlgorithm(self, parameters, context, feedback):
entry.bandNumber = n + 1 entry.bandNumber = n + 1
entries.append(entry) entries.append(entry)


output = self.getOutputValue(self.OUTPUT) output = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
extentValue = self.getParameterValue(self.EXTENT) bbox = self.parameterAsExtent(parameters, self.EXTENT, context)
if not extentValue: if bbox.isNull():
extentValue = QgsProcessingUtils.combineLayerExtents(layersValue) bbox = QgsProcessingUtils.combineLayerExtents(layers)


if extentValue: if bbox.isNull():
extent = extentValue.split(',')
bbox = QgsRectangle(float(extent[0]), float(extent[2]),
float(extent[1]), float(extent[3]))
else:
if layersDict: if layersDict:
bbox = list(layersDict.values())[0].extent() bbox = list(layersDict.values())[0].extent()
for lyr in layersDict.values(): for lyr in layersDict.values():
bbox.combineExtentWith(lyr.extent()) bbox.combineExtentWith(lyr.extent())
else: else:
raise GeoAlgorithmExecutionException(self.tr("No layers selected")) raise QgsProcessingException(self.tr("No layers selected"))


def _cellsize(layer): def _cellsize(layer):
return (layer.extent().xMaximum() - layer.extent().xMinimum()) / layer.width() 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) width = math.floor((bbox.xMaximum() - bbox.xMinimum()) / cellsize)
height = math.floor((bbox.yMaximum() - bbox.yMinimum()) / cellsize) height = math.floor((bbox.yMaximum() - bbox.yMinimum()) / cellsize)
driverName = GdalUtils.getFormatShortNameFromFilename(output) driverName = GdalUtils.getFormatShortNameFromFilename(output)
Expand All @@ -154,14 +163,16 @@ def _cellsize(layer):


res = calc.processCalculation() res = calc.processCalculation()
if res == QgsRasterCalculator.ParserError: 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): def processBeforeAddingToModeler(self, algorithm, model):
values = [] values = []
expression = algorithm.params[self.EXPRESSION] expression = algorithm.params[self.EXPRESSION]
for i in list(model.inputs.values()): for i in list(model.inputs.values()):
param = i.param 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())) values.append(ValueFromInput(param.name()))


if algorithm.name: if algorithm.name:
Expand All @@ -171,7 +182,7 @@ def processBeforeAddingToModeler(self, algorithm, model):
for alg in list(model.algs.values()): for alg in list(model.algs.values()):
if alg.modeler_name not in dependent: if alg.modeler_name not in dependent:
for out in alg.algorithm.outputs: for out in alg.algorithm.outputs:
if (isinstance(out, OutputRaster) and if (isinstance(out, QgsProcessingOutputRasterLayer) and
"{}:{}@".format(alg.modeler_name, out.name) in expression): "{}:{}@".format(alg.modeler_name, out.name) in expression):
values.append(ValueFromOutput(alg.modeler_name, out.name)) values.append(ValueFromOutput(alg.modeler_name, out.name))


Expand Down
58 changes: 29 additions & 29 deletions python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
Expand Up @@ -2210,35 +2210,35 @@ tests:
- 'Maximum value: 15:29:22' - 'Maximum value: 15:29:22'
- 'NULL \(missing\) values: 1' - 'NULL \(missing\) values: 1'


# - algorithm: qgis:rastercalculator - algorithm: qgis:rastercalculator
# name: Raster Calculator with cellsize name: Raster Calculator with cellsize
# params: params:
# LAYERS: LAYERS:
# params: params:
# - name: dem.tif - name: dem.tif
# type: raster type: raster
# type: multi type: multi
# CELLSIZE: 0.001 CELLSIZE: 0.001
# EXPRESSION: dem@1 EXPRESSION: dem@1
# results: results:
# OUTPUT: OUTPUT:
# hash: ef97a22ee16e0e28bbdc0341449777b1527e37febc3c4339b2c057c9 hash: ef97a22ee16e0e28bbdc0341449777b1527e37febc3c4339b2c057c9
# type: rasterhash type: rasterhash
#
# - algorithm: qgis:rastercalculator - algorithm: qgis:rastercalculator
# name: Raster Calculator name: Raster Calculator
# params: params:
# LAYERS: LAYERS:
# params: params:
# - name: dem.tif - name: dem.tif
# type: raster type: raster
# type: multi type: multi
# CELLSIZE: 0.0 CELLSIZE: 0.0
# EXPRESSION: dem@1 * 2 EXPRESSION: dem@1 * 2
# results: results:
# OUTPUT: OUTPUT:
# hash: fe6e018be13c5a3c17f3f4d0f0dc7686c628cb440b74c4642aa0c939 hash: fe6e018be13c5a3c17f3f4d0f0dc7686c628cb440b74c4642aa0c939
# type: rasterhash type: rasterhash


- algorithm: qgis:orientedminimumboundingbox - algorithm: qgis:orientedminimumboundingbox
name: Oriented minimum bounding box polys name: Oriented minimum bounding box polys
Expand Down

0 comments on commit 4d242c5

Please sign in to comment.