Improve ext scripts and support OutputFolder

This commit is contained in:
Médéric Ribreux 2017-09-14 16:22:43 +02:00 committed by Médéric RIBREUX
parent 5827513c4b
commit 56b963e313
7 changed files with 116 additions and 87 deletions

View File

@ -72,6 +72,12 @@ class Grass7AlgorithmProvider(QgsProcessingProvider):
Grass7Utils.GRASS_HELP_PATH, Grass7Utils.GRASS_HELP_PATH,
self.tr('Location of GRASS docs'), self.tr('Location of GRASS docs'),
Grass7Utils.grassHelpPath())) Grass7Utils.grassHelpPath()))
# Add a setting for using v.external instead of v.in.ogr
ProcessingConfig.addSetting(Setting(
self.name(),
Grass7Utils.GRASS_USE_VEXTERNAL,
self.tr('For vector layers, use v.external (faster) instead of v.in.ogr'),
True))
ProcessingConfig.readSettings() ProcessingConfig.readSettings()
self.refreshAlgorithms() self.refreshAlgorithms()
return True return True
@ -83,6 +89,7 @@ class Grass7AlgorithmProvider(QgsProcessingProvider):
ProcessingConfig.removeSetting(Grass7Utils.GRASS_LOG_COMMANDS) ProcessingConfig.removeSetting(Grass7Utils.GRASS_LOG_COMMANDS)
ProcessingConfig.removeSetting(Grass7Utils.GRASS_LOG_CONSOLE) ProcessingConfig.removeSetting(Grass7Utils.GRASS_LOG_CONSOLE)
ProcessingConfig.removeSetting(Grass7Utils.GRASS_HELP_PATH) ProcessingConfig.removeSetting(Grass7Utils.GRASS_HELP_PATH)
ProcessingConfig.removeSetting(Grass7Utils.GRASS_USE_VEXTERNAL)
def isActive(self): def isActive(self):
return ProcessingConfig.getSetting('ACTIVATE_GRASS7') return ProcessingConfig.getSetting('ACTIVATE_GRASS7')

View File

@ -10,13 +10,19 @@ QGIS3 Processing Port
* Replace all parameters by QgsProcessingParameters. * Replace all parameters by QgsProcessingParameters.
* Re-enable GRASS algorithm by default. * Re-enable GRASS algorithm by default.
* Add GRASS 7.2 new algorithms. * Add GRASS 7.2 new algorithms.
* Improve unit tests * Improve unit tests.
* GRASS_REGION_CELLSIZE_PARAMETER is integer or double? * Use some raster/vector layers with spacename into their path.
* GRASS_SNAP_TOLERANCE_PARAMETER is integer or double? * Better support for files output that are not HTML.
* Do we need to use QgsProcessingParameters::parameterFromScriptCode for description files? * Use prepareAlgorithm for algorithm preparation.
We don't NEED but we have to improve getParameterFromString (or use an internal method) at least. * Opens HTML files in Viewer.
There is also a problem for parameterFromScriptCode: it doesn't use description very well. * Support ParameterTable.
We can also use parameterFromVariantMap and a custom internal Grass7Algorithm getParameterFromString. * Remove specific algorithms code in Grass7Algorithm.py (move them in ext).
* Convert all ext scripts.
* Support OutputFolder.
* Support multiple output raster formats.
* Support multiple output vector formats.
* Support multiple bands input rasters.
* Review all the methods of QgsProcessingAlgorithm.
* Make tests under MS-Windows 7 for Utf-8 support. * Make tests under MS-Windows 7 for Utf-8 support.
Unit tests Unit tests

View File

@ -2,8 +2,11 @@ r.horizon
Horizon angle computation from a digital elevation model. Horizon angle computation from a digital elevation model.
Raster (r.*) Raster (r.*)
QgsProcessingParameterRasterLayer|elevation|Name of input elevation raster map|None|False QgsProcessingParameterRasterLayer|elevation|Name of input elevation raster map|None|False
QgsProcessingParameterNumber|direction|Direction in which you want to know the horizon height|QgsProcessingParameterNumber.Double|0.0|False|360|0 QgsProcessingParameterNumber|direction|Direction in which you want to know the horizon height|QgsProcessingParameterNumber.Double|0.0|True|0.0|360.0
QgsProcessingParameterNumber|maxdistance|The maximum distance to consider when finding the horizon height|QgsProcessingParameterNumber.Double|10000|False|None|0 QgsProcessingParameterNumber|step|Angle step size for multidirectional horizon|QgsProcessingParameterNumber.Double|None|True|0.0|360.0
QgsProcessingParameterString|distance|Sampling distance step coefficient (0.5-1.5)|1.0 QgsProcessingParameterNumber|start|Start angle for multidirectional horizon|QgsProcessingParameterNumber.Double|0.0|True|0.0|360.0
QgsProcessingParameterNumber|end|End angle for multidirectional horizon|QgsProcessingParameterNumber.Double|360.0|True|0.0|360.0
QgsProcessingParameterNumber|maxdistance|The maximum distance to consider when finding the horizon height|QgsProcessingParameterNumber.Double|None|True|0|None
QgsProcessingParameterNumber|distance|Sampling distance step coefficient|QgsProcessingParameterNumber.Double|1.0|True|0.5|1.5
QgsProcessingParameterBoolean|-d|Write output in degrees (default is radians)|False QgsProcessingParameterBoolean|-d|Write output in degrees (default is radians)|False
QgsProcessingParameterRasterDestination|output|Horizon QgsProcessingParameterFolderDestination|output|Folder to get horizon rasters

View File

@ -16,7 +16,6 @@
* * * *
*************************************************************************** ***************************************************************************
""" """
from builtins import str
__author__ = 'Médéric Ribreux' __author__ = 'Médéric Ribreux'
__date__ = 'February 2016' __date__ = 'February 2016'
@ -27,49 +26,26 @@ __copyright__ = '(C) 2016, Médéric Ribreux'
__revision__ = '$Format:%H$' __revision__ = '$Format:%H$'
def processInputs(alg): def processInputs(alg, parameters, context):
# If there is another raster to copy categories from if 'first' and 'second' in alg.exportedLayers:
# we need to import it with r.in.gdal rather than r.external
first = alg.getParameterValue(u'first')
second = alg.getParameterValue(u'second')
if first in list(alg.exportedLayers.keys()) and second in list(alg.exportedLayers.keys()):
return return
for raster in [first, second]: for name in ['first', 'second']:
alg.setSessionProjectionFromLayer(raster, alg.commands) raster = alg.parameterAsRasterLayer(parameters, name, context)
alg.setSessionProjectionFromLayer(raster)
destFilename = alg.getTempFilename() # We need to import all the bands and color tables of the input raster
alg.exportedLayers[raster] = destFilename alg.commands.append(
command = 'r.in.gdal input={} output={} --overwrite -o'.format(raster, destFilename) alg.loadRasterLayer(name,
alg.commands.append(command) parameters[name],
False, None
alg.setSessionProjectionFromProject(alg.commands)
region = str(alg.getParameterValue(alg.GRASS_REGION_EXTENT_PARAMETER))
regionCoords = region.split(',')
command = 'g.region'
command += ' -a'
command += ' n=' + str(regionCoords[3])
command += ' s=' + str(regionCoords[2])
command += ' e=' + str(regionCoords[1])
command += ' w=' + str(regionCoords[0])
cellsize = alg.getParameterValue(alg.GRASS_REGION_CELLSIZE_PARAMETER)
if cellsize:
command += ' res=' + str(cellsize)
else:
command += ' res=' + str(alg.getDefaultCellsize(parameters, context))
alignToResolution = alg.getParameterValue(alg.GRASS_REGION_ALIGN_TO_RESOLUTION)
if alignToResolution:
command += ' -a'
alg.commands.append(command)
def processOutputs(alg):
# Keep color table
output = alg.getOutputValue(u'output')
command = u"r.out.gdal -t createopt=\"TFW=YES,COMPRESS=LZW\" input={} output=\"{}\" --overwrite".format(
alg.exportedLayers[output],
output
) )
alg.commands.append(command) )
alg.outputCommands.append(command) alg.inputLayers.append(raster)
alg.postInputs(parameters, context)
def processOutputs(alg, parameters, context):
# Keep color table
self.exportRasterLayer('output', parameters, context, True)

View File

@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
"""
***************************************************************************
r_horizon.py
------------
Date : September 2017
Copyright : (C) 2017 by Médéric Ribreux
Email : medspx at medspx dot fr
***************************************************************************
* *
* 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. *
* *
***************************************************************************
"""
__author__ = 'Médéric Ribreux'
__date__ = 'September 2017'
__copyright__ = '(C) 2017, Médéric Ribreux'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import os
def processOutputs(alg, parameters, context):
# There will be as outputs as the difference between start and end divided by steps
start = alg.parameterAsDouble(parameters, 'start', context)
end = alg.parameterAsDouble(parameters, 'end', context)
step = alg.parameterAsDouble(parameters, 'step', context)
num = start + step
directory = alg.parameterAsString(parameters, 'output', context)
while num < end:
grassName = '{}_{}'.format(alg.exportedLayers['output'], int(num))
fileName = '{}.tif'.format(os.path.join(directory, '{0:0>3}'.format(int(num))))
alg.exportRasterLayer(grassName, fileName)
num += step

View File

@ -27,44 +27,39 @@ __revision__ = '$Format:%H$'
def processInputs(alg, parameters, context): def processInputs(alg, parameters, context):
# We need to import all the bands and color tables of the input raster
if 'input' in alg.exportedLayers: if 'input' in alg.exportedLayers:
return return
raster = alg.parameterAsRasterLayer(parameters, 'input', context)
alg.setSessionProjectionFromLayer(raster) # We need to import all the bands and color tables of the input raster
alg.prepareInputs() alg.loadRasterLayerFromParameter('input', parameters, context, False, None)
alg.postInputs(parameters, context)
def processCommand(alg, parameters, context): def processCommand(alg, parameters, context):
# We need to introduce something clever:
# if the input raster is multiband: export each component directly # if the input raster is multiband: export each component directly
raster = alg.exportedLayers[alg.getParameterValue('input')] rasterInput = alg.exportedLayers['input']
raster = alg.parameterAsRasterLayer(parameters, 'input', context)
for color in ['red', 'green', 'blue']: for color in ['red', 'green', 'blue']:
alg.exportedLayers[alg.getOutputValue(color)] = color + alg.uniqueSuffix alg.exportedLayers[color] = color + alg.uniqueSuffix
commands = ["if [ $(g.list type=rast pattern='{}.*' | wc -l) -eq \"0\" ]; then".format(raster)] # If the raster is not multiband, really do r.rgb
commands.append(" r.rgb input={} red={} green={} blue={} --overwrite".format( if raster.bandCount() == 1:
raster, alg.commands.append(" r.rgb input={} red={} green={} blue={} --overwrite".format(
alg.exportedLayers[alg.getOutputValue('red')], rasterInput,
alg.exportedLayers[alg.getOutputValue('green')], alg.exportedLayers['red'],
alg.exportedLayers[alg.getOutputValue('blue')] alg.exportedLayers['green'],
alg.exportedLayers['blue']
)) ))
commands.append("fi")
alg.commands.extend(commands)
def processOutputs(alg, parameters, context): def processOutputs(alg, parameters, context):
raster = alg.exportedLayers[alg.getParameterValue('input')] raster = alg.parameterAsRasterLayer(parameters, 'input', context)
commands = ["if [ $(g.list type=rast pattern='{}.*' | wc -l) -eq \"0\" ]; then".format(raster)]
# if the raster was monoband, export from r.rgb
if raster.bandCount() == 1:
for color in ['red', 'green', 'blue']: for color in ['red', 'green', 'blue']:
commands.append(" r.out.gdal -t input={} output={} createopt=\"TFW=YES,COMPRESS=LZW\" --overwrite".format( alg.exportRasterLayerFromOutput(color, parameters, context, True)
alg.exportedLayers[alg.getOutputValue(color)], # otherwise, export directly from the multibands
alg.getOutputValue(color) else:
))
commands.append("else")
for color in ['red', 'green', 'blue']: for color in ['red', 'green', 'blue']:
commands.append(" r.out.gdal -t input={} output={} createopt=\"TFW=YES,COMPRESS=LZW\" --overwrite".format( fileName = alg.parameterAsOutputLayer(parameters, color, context)
'{}.{}'.format(raster, color), grassName = '{}{}'.format(alg.exportedLayers['input'], color)
alg.getOutputValue(color) alg.exportRasterLayer(grassName, fileName, True)
))
commands.append("fi")
alg.commands.extend(commands)

View File

@ -60,12 +60,14 @@ from qgis.core import (QgsRasterLayer, QgsVectorLayer, QgsMapLayer, QgsCoordinat
QgsProcessingParameterRasterDestination, # NOQA QgsProcessingParameterRasterDestination, # NOQA
QgsProcessingParameterVectorDestination, # NOQA QgsProcessingParameterVectorDestination, # NOQA
QgsProcessingParameterFileDestination, QgsProcessingParameterFileDestination,
QgsProcessingParameterFolderDestination,
QgsProcessingParameterString, # NOQA QgsProcessingParameterString, # NOQA
QgsProcessingParameterMultipleLayers, QgsProcessingParameterMultipleLayers,
QgsProcessingParameterFeatureSource, QgsProcessingParameterFeatureSource,
QgsProcessingParameterNumber) QgsProcessingParameterNumber)
# TODELETE # TODELETE
from qgis.core import (QgsMessageLog) from qgis.core import (QgsMessageLog)
from processing.tools.vector import resolveFieldIndex from processing.tools.vector import resolveFieldIndex
from processing.tools import dataobjects from processing.tools import dataobjects
from processing.core.outputs import OutputNumber, OutputRaster, OutputVector from processing.core.outputs import OutputNumber, OutputRaster, OutputVector