mirror of
				https://github.com/qgis/QGIS.git
				synced 2025-11-04 00:04:25 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			190 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			190 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# -*- coding: utf-8 -*-
 | 
						|
 | 
						|
"""
 | 
						|
***************************************************************************
 | 
						|
    RasterLayerCalculator.py
 | 
						|
    ---------------------
 | 
						|
    Date                 : November 2016
 | 
						|
    Copyright            : (C) 2016 by Victor Olaya
 | 
						|
    Email                : volayaf at gmail dot com
 | 
						|
***************************************************************************
 | 
						|
*                                                                         *
 | 
						|
*   This program is free software; you can redistribute it and/or modify  *
 | 
						|
*   it under the terms of the GNU General Public License as published by  *
 | 
						|
*   the Free Software Foundation; either version 2 of the License, or     *
 | 
						|
*   (at your option) any later version.                                   *
 | 
						|
*                                                                         *
 | 
						|
***************************************************************************
 | 
						|
"""
 | 
						|
 | 
						|
import os
 | 
						|
 | 
						|
__author__ = 'Victor Olaya'
 | 
						|
__date__ = 'November 2016'
 | 
						|
__copyright__ = '(C) 2016, Victor Olaya'
 | 
						|
 | 
						|
# This will get replaced with a git SHA1 when you do a git archive
 | 
						|
 | 
						|
__revision__ = '$Format:%H$'
 | 
						|
 | 
						|
import math
 | 
						|
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
 | 
						|
from processing.algs.gdal.GdalUtils import GdalUtils
 | 
						|
from qgis.core import (QgsProcessing,
 | 
						|
                       QgsProcessingException,
 | 
						|
                       QgsProcessingUtils,
 | 
						|
                       QgsProcessingParameterMultipleLayers,
 | 
						|
                       QgsProcessingParameterNumber,
 | 
						|
                       QgsProcessingParameterExtent,
 | 
						|
                       QgsProcessingParameterRasterDestination,
 | 
						|
                       QgsProcessingParameterRasterLayer,
 | 
						|
                       QgsProcessingOutputRasterLayer,
 | 
						|
                       QgsProcessingParameterString)
 | 
						|
from qgis.analysis import QgsRasterCalculator, QgsRasterCalculatorEntry
 | 
						|
 | 
						|
 | 
						|
class RasterCalculator(QgisAlgorithm):
 | 
						|
 | 
						|
    LAYERS = 'LAYERS'
 | 
						|
    EXTENT = 'EXTENT'
 | 
						|
    CELLSIZE = 'CELLSIZE'
 | 
						|
    EXPRESSION = 'EXPRESSION'
 | 
						|
    OUTPUT = 'OUTPUT'
 | 
						|
 | 
						|
    def group(self):
 | 
						|
        return self.tr('Raster analysis')
 | 
						|
 | 
						|
    def __init__(self):
 | 
						|
        super().__init__()
 | 
						|
 | 
						|
    def initAlgorithm(self, config=None):
 | 
						|
        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'
 | 
						|
                })
 | 
						|
 | 
						|
            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, 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, 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))
 | 
						|
        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'
 | 
						|
 | 
						|
    def displayName(self):
 | 
						|
        return self.tr('Raster calculator')
 | 
						|
 | 
						|
    def processAlgorithm(self, parameters, context, feedback):
 | 
						|
        expression = self.parameterAsString(parameters, self.EXPRESSION, context)
 | 
						|
        layers = self.parameterAsLayerList(parameters, self.LAYERS, context)
 | 
						|
        layersDict = {}
 | 
						|
        if layers:
 | 
						|
            layersDict = {os.path.basename(lyr.source().split(".")[0]): lyr for lyr in layers}
 | 
						|
 | 
						|
        for lyr in QgsProcessingUtils.compatibleRasterLayers(context.project()):
 | 
						|
            name = lyr.name()
 | 
						|
            if (name + "@") in expression:
 | 
						|
                layersDict[name] = lyr
 | 
						|
 | 
						|
        entries = []
 | 
						|
        for name, lyr in layersDict.items():
 | 
						|
            for n in range(lyr.bandCount()):
 | 
						|
                entry = QgsRasterCalculatorEntry()
 | 
						|
                entry.ref = '{:s}@{:d}'.format(name, n + 1)
 | 
						|
                entry.raster = lyr
 | 
						|
                entry.bandNumber = n + 1
 | 
						|
                entries.append(entry)
 | 
						|
 | 
						|
        output = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
 | 
						|
        bbox = self.parameterAsExtent(parameters, self.EXTENT, context)
 | 
						|
        if bbox.isNull():
 | 
						|
            bbox = QgsProcessingUtils.combineLayerExtents(layers)
 | 
						|
 | 
						|
        if bbox.isNull():
 | 
						|
            if layersDict:
 | 
						|
                bbox = list(layersDict.values())[0].extent()
 | 
						|
                for lyr in layersDict.values():
 | 
						|
                    bbox.combineExtentWith(lyr.extent())
 | 
						|
            else:
 | 
						|
                raise QgsProcessingException(self.tr("No layers selected"))
 | 
						|
 | 
						|
        def _cellsize(layer):
 | 
						|
            return (layer.extent().xMaximum() - layer.extent().xMinimum()) / layer.width()
 | 
						|
        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)
 | 
						|
        calc = QgsRasterCalculator(expression,
 | 
						|
                                   output,
 | 
						|
                                   driverName,
 | 
						|
                                   bbox,
 | 
						|
                                   width,
 | 
						|
                                   height,
 | 
						|
                                   entries)
 | 
						|
 | 
						|
        res = calc.processCalculation()
 | 
						|
        if res == QgsRasterCalculator.ParserError:
 | 
						|
            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, QgsProcessingParameterRasterLayer) and "{}@".format(param.name) in expression:
 | 
						|
                values.append(ValueFromInput(param.name()))
 | 
						|
 | 
						|
        if algorithm.name:
 | 
						|
            dependent = model.getDependentAlgorithms(algorithm.name)
 | 
						|
        else:
 | 
						|
            dependent = []
 | 
						|
        for alg in list(model.algs.values()):
 | 
						|
            if alg.modeler_name not in dependent:
 | 
						|
                for out in alg.algorithm.outputs:
 | 
						|
                    if (isinstance(out, QgsProcessingOutputRasterLayer) and
 | 
						|
                            "{}:{}@".format(alg.modeler_name, out.name) in expression):
 | 
						|
                        values.append(ValueFromOutput(alg.modeler_name, out.name))
 | 
						|
 | 
						|
        algorithm.params[self.LAYERS] = values
 |