Skip to content

Commit

Permalink
Merge pull request #5968 from medspx/ProcessingGrassFixExt
Browse files Browse the repository at this point in the history
[Processing] GRASS fix all ext scripts
  • Loading branch information
alexbruy committed Jan 9, 2018
2 parents a934060 + 7120937 commit 566704a
Show file tree
Hide file tree
Showing 199 changed files with 1,191 additions and 2,363 deletions.
129 changes: 102 additions & 27 deletions python/plugins/processing/algs/grass7/Grass7Algorithm.py
Expand Up @@ -56,6 +56,7 @@
QgsProcessingParameterVectorDestination,
QgsProcessingParameterRasterDestination,
QgsProcessingParameterFileDestination,
QgsProcessingParameterFile,
QgsProcessingParameterFolderDestination,
QgsProcessingOutputFolder,
QgsProcessingOutputVectorLayer,
Expand Down Expand Up @@ -409,8 +410,12 @@ def processInputs(self, parameters, context):
paramName = param.name()
if not paramName in parameters:
continue
if isinstance(parameters[paramName], str) and len(parameters[paramName]) == 0:
# Handle Null parameter
if parameters[paramName] is None:
continue
elif isinstance(parameters[paramName], str) and len(parameters[paramName]) == 0:
continue

# Raster inputs needs to be imported into temp GRASS DB
if isinstance(param, QgsProcessingParameterRasterLayer):
if paramName not in self.exportedLayers:
Expand All @@ -419,11 +424,13 @@ def processInputs(self, parameters, context):
# Vector inputs needs to be imported into temp GRASS DB
elif isinstance(param, QgsProcessingParameterVectorLayer):
if paramName not in self.exportedLayers:
self.loadVectorLayerFromParameter(
paramName, parameters, context)
# TODO: find the best replacement for ParameterTable
#if isinstance(param, ParameterTable):
# pass
# Attribute tables are also vector inputs
if QgsProcessing.TypeFile in param.dataTypes():
self.loadAttributeTableFromParameter(
paramName, parameters, context)
else:
self.loadVectorLayerFromParameter(
paramName, parameters, context, None)
# For multiple inputs, process each layer
elif isinstance(param, QgsProcessingParameterMultipleLayers):
layers = self.parameterAsLayerList(parameters, paramName, context)
Expand All @@ -434,7 +441,7 @@ def processInputs(self, parameters, context):
self.loadRasterLayer(layerName, layer)
# Add a vector layer
elif layer.type() == QgsMapLayer.VectorLayer:
self.loadVectorLayer(layerName, layer)
self.loadVectorLayer(layerName, layer, None)

self.postInputs()

Expand Down Expand Up @@ -518,10 +525,19 @@ def processCommand(self, parameters, context, delOutputs=False):
elif isinstance(param, QgsProcessingParameterBoolean):
if self.parameterAsBool(parameters, paramName, context):
command += ' {}'.format(paramName)
# For Extents, remove if the value is null
elif isinstance(param, QgsProcessingParameterExtent):
if self.parameterAsExtent(parameters, paramName, context):
value = self.parameterAsString(parameters, paramName, context)
# For enumeration, we need to grab the string value
elif isinstance(param, QgsProcessingParameterEnum):
idx = self.parameterAsEnum(parameters, paramName, context)
value = '"{}"'.format(param.options()[idx])
# Handle multiple values
if param.allowMultiple():
indexes = self.parameterAsEnums(parameters, paramName, context)
else:
indexes = [self.parameterAsEnum(parameters, paramName, context)]
if indexes:
value = '"{}"'.format(','.join([param.options()[i] for i in indexes]))
# For strings, we just translate as string
elif isinstance(param, QgsProcessingParameterString):
data = self.parameterAsString(parameters, paramName, context)
Expand All @@ -532,9 +548,14 @@ def processCommand(self, parameters, context, delOutputs=False):
)
# For fields, we just translate as string
elif isinstance(param, QgsProcessingParameterField):
value = '{}'.format(
self.parameterAsString(parameters, paramName, context)
value = ','.join(
self.parameterAsFields(parameters, paramName, context)
)
elif isinstance(param, QgsProcessingParameterFile):
if self.parameterAsString(parameters, paramName, context):
value = '"{}"'.format(
self.parameterAsString(parameters, paramName, context)
)
# For numbers and points, we translate as a string
elif isinstance(param, (QgsProcessingParameterNumber,
QgsProcessingParameterPoint)):
Expand All @@ -550,6 +571,9 @@ def processCommand(self, parameters, context, delOutputs=False):
# Handle outputs
if not delOutputs:
for out in self.destinationParameterDefinitions():
# We exclude hidden parameters
if out.flags() & QgsProcessingParameterDefinition.FlagHidden:
continue
outName = out.name()
# For File destination
if isinstance(out, QgsProcessingParameterFileDestination):
Expand Down Expand Up @@ -624,24 +648,26 @@ def loadRasterLayerFromParameter(self, name, parameters, context, external=True,
layer = self.parameterAsRasterLayer(parameters, name, context)
self.loadRasterLayer(name, layer, external, band)

def loadRasterLayer(self, name, layer, external=True, band=1):
def loadRasterLayer(self, name, layer, external=True, band=1, destName=None):
"""
Creates a dedicated command to load a raster into
the temporary GRASS DB.
:param name: name of the parameter.
:param layer: QgsMapLayer for the raster layer.
:param external: True if using r.external.
:param band: imports only specified band. None for all bands.
:param destName: force the destination name of the raster.
"""
self.inputLayers.append(layer)
self.setSessionProjectionFromLayer(layer)
destFilename = 'a' + os.path.basename(getTempFilename())
self.exportedLayers[name] = destFilename
if not destName:
destName = 'rast_{}'.format(os.path.basename(getTempFilename()))
self.exportedLayers[name] = destName
command = '{0} input="{1}" {2}output="{3}" --overwrite -o'.format(
'r.external' if external else 'r.in.gdal',
os.path.normpath(layer.source()),
'band={} '.format(band) if band else '',
destFilename)
destName)
self.commands.append(command)

def exportRasterLayerFromParameter(self, name, parameters, context, colorTable=True):
Expand Down Expand Up @@ -683,33 +709,36 @@ def exportRasterLayer(self, grassName, fileName,
# Adjust region to layer before exporting
cmd.append('g.region raster={}'.format(grassName))
cmd.append(
'r.out.gdal -c -m{0} input="{1}" output="{2}" format="{3}" {4}{5} --overwrite'.format(
' -t' if colorTable else '',
'r.out.gdal -t -m{0} input="{1}" output="{2}" format="{3}" {4}{5} --overwrite'.format(
'' if colorTable else ' -c',
grassName, fileName,
outFormat,
' createopt="{}"'.format(createOpt) if createOpt else '',
' metaopt="{}"'.format(metaOpt) if metaOpt else ''
)
)

def exportRasterLayersIntoDirectory(self, name, parameters, context, colorTable=True):
def exportRasterLayersIntoDirectory(self, name, parameters, context, colorTable=True, wholeDB=False):
"""
Creates a dedicated loop command to export rasters from
temporary GRASS DB into a directory via gdal.
:param name: name of the output directory parameter.
:param parameters: Algorithm parameters dict.
:param context: Algorithm context.
:param colorTable: preserve color Table.
:param wholeDB: export every raster layer from the GRASSDB
"""
# Grab directory name and temporary basename
outDir = os.path.normpath(
self.parameterAsString(parameters, name, context))
basename = name + self.uniqueSuffix
basename = ''
if not wholeDB:
basename = name + self.uniqueSuffix

# Add a loop export from the basename
for cmd in [self.commands, self.outputCommands]:
# Adjust region to layer before exporting
# TODO: Does-it works under MS-Windows or MacOSX?
# TODO Windows support
# TODO Format/options support
cmd.append("for r in $(g.list type=rast pattern='{}*'); do".format(basename))
cmd.append(" r.out.gdal -m{0} input=${{r}} output={1}/${{r}}.tif {2}".format(
' -t' if colorTable else '', outDir,
Expand All @@ -718,7 +747,7 @@ def exportRasterLayersIntoDirectory(self, name, parameters, context, colorTable=
)
cmd.append("done")

def loadVectorLayerFromParameter(self, name, parameters, context, external=None):
def loadVectorLayerFromParameter(self, name, parameters, context, external=False):
"""
Creates a dedicated command to load a vector into
the temporary GRASS DB.
Expand All @@ -730,7 +759,7 @@ def loadVectorLayerFromParameter(self, name, parameters, context, external=None)
layer = self.parameterAsVectorLayer(parameters, name, context)
self.loadVectorLayer(name, layer, external)

def loadVectorLayer(self, name, layer, external=None):
def loadVectorLayer(self, name, layer, external=False):
"""
Creates a dedicated command to load a vector into
temporary GRASS DB.
Expand All @@ -745,7 +774,7 @@ def loadVectorLayer(self, name, layer, external=None):
Grass7Utils.GRASS_USE_VEXTERNAL)
self.inputLayers.append(layer)
self.setSessionProjectionFromLayer(layer)
destFilename = 'a' + os.path.basename(getTempFilename())
destFilename = 'vector_{}'.format(os.path.basename(getTempFilename()))
self.exportedLayers[name] = destFilename
command = '{0}{1}{2} input="{3}" output="{4}" --overwrite -o'.format(
'v.external' if external else 'v.in.ogr',
Expand Down Expand Up @@ -781,13 +810,16 @@ def exportVectorLayer(self, grassName, fileName, dataType='auto', layer=None, no
"""
Creates a dedicated command to export a vector from
temporary GRASS DB into a file via ogr.
:param grassName: name of the parameter
:param fileName: file path of raster layer
:param grassName: name of the parameter.
:param fileName: file path of raster layer.
:param dataType: GRASS data type for exporting data.
:param layer: In GRASS a vector can have multiple layers.
:param nocats: Also export features without category if True.
"""
for cmd in [self.commands, self.outputCommands]:
cmd.append(
'v.out.ogr{0} type={1} {2} input="{3}" output="{4}" {5}'.format(
'' if nocats else ' -c',
' -c' if nocats else '',
dataType,
'layer={}'.format(layer) if layer else '',
grassName,
Expand All @@ -796,6 +828,49 @@ def exportVectorLayer(self, grassName, fileName, dataType='auto', layer=None, no
)
)

def loadAttributeTableFromParameter(self, name, parameters, context):
"""
Creates a dedicated command to load an attribute table
into the temporary GRASS DB.
:param name: name of the parameter
:param parameters: Parameters of the algorithm.
:param context: Processing context
"""
table = self.parameterAsVectorLayer(parameters, name, context)
self.loadAttributeTable(name, table)

def loadAttributeTable(self, name, layer, destName=None):
"""
Creates a dedicated command to load an attribute table
into the temporary GRASS DB.
:param name: name of the input parameter.
:param layer: a layer object to import from.
:param destName: force the name for the table into GRASS DB.
"""
self.inputLayers.append(layer)
if not destName:
destName = 'table_{}'.format(os.path.basename(getTempFilename()))
self.exportedLayers[name] = destName
command = 'db.in.ogr --overwrite input="{0}" output="{1}"'.format(
os.path.normpath(layer.source()), destName)
self.commands.append(command)

def exportAttributeTable(self, grassName, fileName, outFormat='CSV', layer=1):
"""
Creates a dedicated command to export an attribute
table from the temporary GRASS DB into a file via ogr.
:param grassName: name of the parameter.
:param fileName: file path of raster layer.
:param outFormat: file format for export.
:param layer: In GRASS a vector can have multiple layers.
"""
for cmd in [self.commands, self.outputCommands]:
cmd.append(
'db.out.ogr input="{0}" output="{1}" layer={2} format={3} --overwrite'.format(
grassName, fileName, layer, outFormat
)
)

def setSessionProjectionFromProject(self):
"""
Set the projection from the project.
Expand Down
Expand Up @@ -70,11 +70,13 @@ def load(self):
self.tr('Location of GRASS docs'),
Grass7Utils.grassHelpPath()))
# Add a setting for using v.external instead of v.in.ogr
# But set it to False by default because some algorithms
# can't be used with external data (need a solid 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))
False))
ProcessingConfig.readSettings()
self.refreshAlgorithms()
return True
Expand Down
11 changes: 6 additions & 5 deletions python/plugins/processing/algs/grass7/Grass7Utils.py
Expand Up @@ -540,9 +540,10 @@ def getRasterFormatFromFilename(filename):
"""
ext = os.path.splitext(filename)[1].lower()
ext = ext.lstrip('.')
supported = GdalUtils.getSupportedRasters()
for name in list(supported.keys()):
exts = supported[name]
if ext in exts:
return name
if ext:
supported = GdalUtils.getSupportedRasters()
for name in list(supported.keys()):
exts = supported[name]
if ext in exts:
return name
return 'GTiff'

0 comments on commit 566704a

Please sign in to comment.