Skip to content
Permalink
Browse files

Partial port of raster calculator to new API

TODO: modeler handling
  • Loading branch information
nyalldawson committed Aug 20, 2017
1 parent 338ee36 commit 4d242c5673ebadc304476e7e5dc5c9599e722a00
@@ -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(),
@@ -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,41 +58,54 @@ 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)
value = value.replace(old, new)
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))

@@ -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

0 comments on commit 4d242c5

Please sign in to comment.
You can’t perform that action at this time.