Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port gdalcalc with formula excaping fix #6984

Merged
merged 21 commits into from
May 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
9035cb1
ported gdalcalc with fix related to escaped formula
luipir May 12, 2018
95b591e
rise QgsProcessingException in case no parameters
luipir May 14, 2018
f34af51
added test for gdal_calc console command
luipir May 14, 2018
e4bcb9d
fix indentation
luipir May 14, 2018
9ef633e
moved alg to follow alphabetic order
luipir May 14, 2018
1628473
added raster advanced options
luipir May 14, 2018
d6ba22b
adapted test to AdvancedRasterOption default to GTiff
luipir May 14, 2018
159ece1
no .py extension to commandName return
luipir May 14, 2018
fadd343
better management of noData options
luipir May 14, 2018
0b18bdc
safer management of A layer
luipir May 14, 2018
33fdc5a
emit QgsProcessingException if A is not available
luipir May 14, 2018
39154f4
safer management of optional bands
luipir May 14, 2018
5e2aa0d
removed control of empty parameters delegating to band control the co…
luipir May 14, 2018
c9db84a
correct nodata management
luipir May 14, 2018
1ed9004
use gdal_calc.py directly and not commandName, otherwise cannot found…
luipir May 14, 2018
1c1c099
moved test to the correct alphabetic order
luipir May 14, 2018
6e91315
fixed test with JPEg out default in test environment
luipir May 14, 2018
82ad2a0
fixed way to manage NoData to avoid iniect value when None or ''
luipir May 14, 2018
449d841
correct use of Numeric for NoData + import cleaning
luipir May 14, 2018
a4c9e1b
revert using commandName() instead of gdal_calc.py directly
luipir May 14, 2018
06e5ca4
fixed tests to be adaptet to new numeric + fix for commandName
luipir May 14, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/gdal/GdalAlgorithmProvider.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
from .gdal2tiles import gdal2tiles
from .gdal2xyz import gdal2xyz
from .gdaladdo import gdaladdo
from .gdalcalc import gdalcalc
from .gdaltindex import gdaltindex
from .GridAverage import GridAverage
from .GridDataMetrics import GridDataMetrics
Expand All @@ -70,7 +71,6 @@
from .warp import warp

# from .extractprojection import ExtractProjection
# from .gdalcalc import gdalcalc
# from .rasterize_over import rasterize_over

from .Buffer import Buffer
Expand Down Expand Up @@ -151,6 +151,7 @@ def loadAlgorithms(self):
gdal2tiles(),
gdal2xyz(),
gdaladdo(),
gdalcalc(),
gdaltindex(),
GridAverage(),
GridDataMetrics(),
Expand All @@ -176,7 +177,6 @@ def loadAlgorithms(self):
warp(),
# rasterize(),
# ExtractProjection(),
# gdalcalc(),
# rasterize_over(),
# ----- OGR tools -----
Buffer(),
Expand Down
255 changes: 182 additions & 73 deletions python/plugins/processing/algs/gdal/gdalcalc.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@

__revision__ = '$Format:%H$'

from qgis.core import (QgsProcessingException,
QgsProcessingParameterDefinition,
QgsProcessingParameterRasterLayer,
QgsProcessingParameterBand,
QgsProcessingParameterNumber,
QgsProcessingParameterEnum,
QgsProcessingParameterString,
QgsProcessingParameterRasterDestination)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils

Expand All @@ -33,6 +41,7 @@

class gdalcalc(GdalAlgorithm):

OPTIONS = 'OPTIONS'
INPUT_A = 'INPUT_A'
INPUT_B = 'INPUT_B'
INPUT_C = 'INPUT_C'
Expand All @@ -57,41 +66,113 @@ def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterRaster(
self.INPUT_A, self.tr('Input layer A'), False))
self.addParameter(ParameterString(self.BAND_A,
self.tr('Number of raster band for raster A'), '1', optional=True))
self.addParameter(ParameterRaster(
self.INPUT_B, self.tr('Input layer B'), True))
self.addParameter(ParameterString(self.BAND_B,
self.tr('Number of raster band for raster B'), '1', optional=True))
self.addParameter(ParameterRaster(
self.INPUT_C, self.tr('Input layer C'), True))
self.addParameter(ParameterString(self.BAND_C,
self.tr('Number of raster band for raster C'), '1', optional=True))
self.addParameter(ParameterRaster(
self.INPUT_D, self.tr('Input layer D'), True))
self.addParameter(ParameterString(self.BAND_D,
self.tr('Number of raster band for raster D'), '1', optional=True))
self.addParameter(ParameterRaster(
self.INPUT_E, self.tr('Input layer E'), True))
self.addParameter(ParameterString(self.BAND_E,
self.tr('Number of raster band for raster E'), '1', optional=True))
self.addParameter(ParameterRaster(
self.INPUT_F, self.tr('Input layer F'), True))
self.addParameter(ParameterString(self.BAND_F,
self.tr('Number of raster band for raster F'), '1', optional=True))
self.addParameter(ParameterString(self.FORMULA,
self.tr('Calculation in gdalnumeric syntax using +-/* or any numpy array functions (i.e. logical_and())'), 'A*2', optional=False))
self.addParameter(ParameterString(self.NO_DATA,
self.tr('Set output nodata value'), '', optional=True))
self.addParameter(ParameterSelection(self.RTYPE,
self.tr('Output raster type'), self.TYPE, 5))
self.addParameter(
QgsProcessingParameterRasterLayer(
self.INPUT_A,
self.tr('Input layer A'),
optional=False))
self.addParameter(
QgsProcessingParameterBand(
self.BAND_A,
self.tr('Number of raster band for A'),
parentLayerParameterName=self.INPUT_A))
self.addParameter(
QgsProcessingParameterRasterLayer(
self.INPUT_B,
self.tr('Input layer B'),
optional=True))
self.addParameter(
QgsProcessingParameterBand(
self.BAND_B,
self.tr('Number of raster band for B'),
parentLayerParameterName=self.INPUT_B,
optional=True))
self.addParameter(
QgsProcessingParameterRasterLayer(
self.INPUT_C,
self.tr('Input layer C'),
optional=True))
self.addParameter(
QgsProcessingParameterBand(self.BAND_C,
self.tr('Number of raster band for C'),
parentLayerParameterName=self.INPUT_C,
optional=True))
self.addParameter(
QgsProcessingParameterRasterLayer(
self.INPUT_D,
self.tr('Input layer D'),
optional=True))
self.addParameter(
QgsProcessingParameterBand(
self.BAND_D,
self.tr('Number of raster band for D'),
parentLayerParameterName=self.INPUT_D,
optional=True))
self.addParameter(
QgsProcessingParameterRasterLayer(
self.INPUT_E,
self.tr('Input layer E'),
optional=True))
self.addParameter(
QgsProcessingParameterBand(
self.BAND_E,
self.tr('Number of raster band for E'),
parentLayerParameterName=self.INPUT_E,
optional=True))
self.addParameter(
QgsProcessingParameterRasterLayer(
self.INPUT_F,
self.tr('Input layer F'),
optional=True))
self.addParameter(
QgsProcessingParameterBand(
self.BAND_F,
self.tr('Number of raster band for F'),
parentLayerParameterName=self.INPUT_F,
optional=True))
self.addParameter(
QgsProcessingParameterString(
self.FORMULA,
self.tr('Calculation in gdalnumeric syntax using +-/* or any numpy array functions (i.e. logical_and())'),
'A*2',
optional=False))
self.addParameter(
QgsProcessingParameterNumber(
self.NO_DATA,
self.tr('Set output nodata value'),
type=QgsProcessingParameterNumber.Double,
defaultValue=None,
optional=True))
self.addParameter(
QgsProcessingParameterEnum(
self.RTYPE,
self.tr('Output raster type'),
options=self.TYPE,
defaultValue=5))
#self.addParameter(ParameterBoolean(
# self.DEBUG, self.tr('Print debugging information'), False))
self.addParameter(ParameterString(self.EXTRA,
self.tr('Additional creation parameters'), '', optional=True))
self.addOutput(OutputRaster(self.OUTPUT, self.tr('Calculated')))
self.addParameter(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set the metadata for this param to get the nice widget - e.g. copy https://github.com/qgis/QGIS/blob/master/python/plugins/processing/algs/gdal/merge.py#L93

QgsProcessingParameterString(
self.EXTRA,
self.tr('Additional creation parameters'),
'',
optional=True))

# advanced raster params
options_param = QgsProcessingParameterString(self.OPTIONS,
self.tr('Additional creation parameters'),
defaultValue='',
optional=True)
options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
options_param.setMetadata({
'widget_wrapper': {
'class': 'processing.algs.gdal.ui.RasterOptionsWidget.RasterOptionsWidgetWrapper'}})
self.addParameter(options_param)

self.addParameter(
QgsProcessingParameterRasterDestination(
self.OUTPUT,
self.tr('Calculated')))

def name(self):
return 'rastercalculator'
Expand All @@ -105,64 +186,92 @@ def group(self):
def groupId(self):
return 'rastermiscellaneous'

def commandName(self):
return 'gdal_calc'

def getConsoleCommands(self, parameters, context, feedback, executing=True):
out = self.getOutputValue(self.OUTPUT)
extra = self.getParameterValue(self.EXTRA)
if extra is not None:
extra = str(extra)
#debug = self.getParameterValue(self.DEBUG)
formula = self.getParameterValue(self.FORMULA)
noData = self.getParameterValue(self.NO_DATA)
if noData is not None:
noData = str(noData)
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
extra = self.parameterAsString(parameters, self.EXTRA, context)
# if extra is not None:
# extra = str(extra)
#debug = self.getParameterValue(parameters, self.DEBUG)
formula = self.parameterAsString(parameters, self.FORMULA, context)
if self.NO_DATA in parameters and parameters[self.NO_DATA] is not None:
noData = self.parameterAsDouble(parameters, self.NO_DATA, context)
else:
noData = None

arguments = []
arguments.append('--calc')
arguments.append('"' + formula + '"')
arguments.append('--calc "{}"'.format(formula))
arguments.append('--format')
arguments.append(GdalUtils.getFormatShortNameFromFilename(out))
arguments.append('--type')
arguments.append(self.TYPE[self.getParameterValue(self.RTYPE)])
if noData and len(noData) > 0:
arguments.append(self.TYPE[self.parameterAsEnum(parameters, self.RTYPE, context)])
if noData is not None:
arguments.append('--NoDataValue')
arguments.append(noData)
if extra and len(extra) > 0:
arguments.append(extra)
#if debug:
# arguments.append('--debug')
layer = self.parameterAsRasterLayer(parameters, self.INPUT_A, context)
if layer is None:
raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_A))
arguments.append('-A')
arguments.append(self.getParameterValue(self.INPUT_A))
if self.getParameterValue(self.BAND_A):
arguments.append('--A_band ' + self.getParameterValue(self.BAND_A))
if self.getParameterValue(self.INPUT_B):
arguments.append(layer.source())
if self.parameterAsString(parameters, self.BAND_A, context):
arguments.append('--A_band ' + self.parameterAsString(parameters, self.BAND_A, context))

if self.INPUT_B in parameters and parameters[self.INPUT_B] is not None:
layer = self.parameterAsRasterLayer(parameters, self.INPUT_B, context)
if layer is None:
raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_B))
arguments.append('-B')
arguments.append(self.getParameterValue(self.INPUT_B))
if self.getParameterValue(self.BAND_B):
arguments.append('--B_band ' + self.getParameterValue(self.BAND_B))
if self.getParameterValue(self.INPUT_C):
arguments.append(layer.source())
if self.parameterAsString(parameters, self.BAND_B, context):
arguments.append('--B_band ' + self.parameterAsString(parameters, self.BAND_B, context))

if self.INPUT_C in parameters and parameters[self.INPUT_C] is not None:
layer = self.parameterAsRasterLayer(parameters, self.INPUT_C, context)
if layer is None:
raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_C))
arguments.append('-C')
arguments.append(self.getParameterValue(self.INPUT_C))
if self.getParameterValue(self.BAND_C):
arguments.append('--C_band ' + self.getParameterValue(self.BAND_C))
if self.getParameterValue(self.INPUT_D):
arguments.append(layer.source())
if self.parameterAsString(parameters, self.BAND_C, context):
arguments.append('--C_band ' + self.parameterAsString(parameters, self.BAND_C, context))

if self.INPUT_D in parameters and parameters[self.INPUT_D] is not None:
layer = self.parameterAsRasterLayer(parameters, self.INPUT_D, context)
if layer is None:
raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_D))
arguments.append('-D')
arguments.append(self.getParameterValue(self.INPUT_D))
if self.getParameterValue(self.BAND_D):
arguments.append('--D_band ' + self.getParameterValue(self.BAND_D))
if self.getParameterValue(self.INPUT_E):
arguments.append(layer.source())
if self.parameterAsString(parameters, self.BAND_D, context):
arguments.append('--D_band ' + self.parameterAsString(parameters, self.BAND_D, context))

if self.INPUT_E in parameters and parameters[self.INPUT_E] is not None:
layer = self.parameterAsRasterLayer(parameters, self.INPUT_E, context)
if layer is None:
raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_E))
arguments.append('-E')
arguments.append(self.getParameterValue(self.INPUT_E))
if self.getParameterValue(self.BAND_E):
arguments.append('--E_band ' + self.getParameterValue(self.BAND_E))
if self.getParameterValue(self.INPUT_F):
arguments.append(layer.source())
if self.parameterAsString(parameters, self.BAND_E, context):
arguments.append('--E_band ' + self.parameterAsString(parameters, self.BAND_E, context))

if self.INPUT_F in parameters and parameters[self.INPUT_F] is not None:
layer = self.parameterAsRasterLayer(parameters, self.INPUT_F, context)
if layer is None:
raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_F))
arguments.append('-F')
arguments.append(self.getParameterValue(self.INPUT_F))
if self.getParameterValue(self.BAND_F):
arguments.append('--F_band ' + self.getParameterValue(self.BAND_F))
arguments.append(layer.source())
if self.parameterAsString(parameters, self.BAND_F, context):
arguments.append('--F_band ' + self.parameterAsString(parameters, self.BAND_F, context))

options = self.parameterAsString(parameters, self.OPTIONS, context)
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))

arguments.append('--outfile')
arguments.append(out)

if isWindows():
return ['gdal_calc', GdalUtils.escapeAndJoin(arguments)]
else:
return ['gdal_calc.py', GdalUtils.escapeAndJoin(arguments)]
return [self.commandName(), GdalUtils.escapeAndJoin(arguments)]
Loading