[processing] simplified saga algorithms

Now it assumes matching grid extents and does not perform resampling
This commit is contained in:
Victor Olaya 2014-05-18 12:01:36 +02:00
parent c1a2ac8678
commit 202d331abb
5 changed files with 27 additions and 161 deletions

View File

@ -63,34 +63,18 @@ class SagaAlgorithm(GeoAlgorithm):
OUTPUT_EXTENT = 'OUTPUT_EXTENT' OUTPUT_EXTENT = 'OUTPUT_EXTENT'
def __init__(self, descriptionfile): def __init__(self, descriptionfile):
# True if it should resample self.allowUnmatchingGridExtents = False
self.resample = True
# In case several non-matching raster layers are used as input # In case several non-matching raster layers are used as input
GeoAlgorithm.__init__(self) GeoAlgorithm.__init__(self)
self.descriptionFile = descriptionfile self.descriptionFile = descriptionfile
self.defineCharacteristicsFromFile() self.defineCharacteristicsFromFile()
if self.resample:
# Reconsider resampling policy now that we know the input
# parameters
self.resample = self.setResamplingPolicy()
def getCopy(self): def getCopy(self):
newone = SagaAlgorithm(self.descriptionFile) newone = SagaAlgorithm(self.descriptionFile)
newone.provider = self.provider newone.provider = self.provider
return newone return newone
def setResamplingPolicy(self):
count = 0
for param in self.parameters:
if isinstance(param, ParameterRaster):
count += 1
if isinstance(param, ParameterMultipleInput):
if param.datatype == ParameterMultipleInput.TYPE_RASTER:
return True
return count > 1
def getIcon(self): def getIcon(self):
return QIcon(os.path.dirname(__file__) + '/../../images/saga.png') return QIcon(os.path.dirname(__file__) + '/../../images/saga.png')
@ -116,8 +100,8 @@ class SagaAlgorithm(GeoAlgorithm):
self.hardcodedStrings.append(line[len('Harcoded|') + 1:]) self.hardcodedStrings.append(line[len('Harcoded|') + 1:])
elif line.startswith('Parameter'): elif line.startswith('Parameter'):
self.addParameter(ParameterFactory.getFromString(line)) self.addParameter(ParameterFactory.getFromString(line))
elif line.startswith('DontResample'): elif line.startswith('AllowUnmatching'):
self.resample = False self.allowUnmatchingGridExtents = True
elif line.startswith('Extent'): elif line.startswith('Extent'):
# An extent parameter that wraps 4 SAGA numerical parameters # An extent parameter that wraps 4 SAGA numerical parameters
self.extentParamNames = line[6:].strip().split(' ') self.extentParamNames = line[6:].strip().split(' ')
@ -128,71 +112,6 @@ class SagaAlgorithm(GeoAlgorithm):
line = lines.readline().strip('\n').strip() line = lines.readline().strip('\n').strip()
lines.close() lines.close()
def calculateResamplingExtent(self):
"""This method calculates the resampling extent, but it might
set self.resample to False if, with the current layers, there
is no need to resample.
"""
auto = ProcessingConfig.getSetting(SagaUtils.SAGA_AUTO_RESAMPLING)
if auto:
first = True
self.inputExtentsCount = 0
for param in self.parameters:
if param.value:
if isinstance(param, ParameterRaster):
if isinstance(param.value, QgsRasterLayer):
layer = param.value
else:
layer = dataobjects.getObjectFromUri(param.value)
self.addToResamplingExtent(layer, first)
first = False
if isinstance(param, ParameterMultipleInput):
if param.datatype \
== ParameterMultipleInput.TYPE_RASTER:
layers = param.value.split(';')
for layername in layers:
layer = dataobjects.getObjectFromUri(layername)
self.addToResamplingExtent(layer, first)
first = False
if self.inputExtentsCount < 2:
self.resample = False
else:
self.xmin = ProcessingConfig.getSetting(
SagaUtils.SAGA_RESAMPLING_REGION_XMIN)
self.xmax = ProcessingConfig.getSetting(
SagaUtils.SAGA_RESAMPLING_REGION_XMAX)
self.ymin = ProcessingConfig.getSetting(
SagaUtils.SAGA_RESAMPLING_REGION_YMIN)
self.ymax = ProcessingConfig.getSetting(
SagaUtils.SAGA_RESAMPLING_REGION_YMAX)
self.cellsize = ProcessingConfig.getSetting(
SagaUtils.SAGA_RESAMPLING_REGION_CELLSIZE)
def addToResamplingExtent(self, layer, first):
if layer is None:
return
if first:
self.inputExtentsCount = 1
self.xmin = layer.extent().xMinimum()
self.xmax = layer.extent().xMaximum()
self.ymin = layer.extent().yMinimum()
self.ymax = layer.extent().yMaximum()
self.cellsize = (layer.extent().xMaximum()
- layer.extent().xMinimum()) / layer.width()
else:
cellsize = (layer.extent().xMaximum() -
layer.extent().xMinimum()) / layer.width()
if self.xmin != layer.extent().xMinimum() or self.xmax \
!= layer.extent().xMaximum() or self.ymin \
!= layer.extent().yMinimum() or self.ymax \
!= layer.extent().yMaximum() or self.cellsize != cellsize:
self.xmin = min(self.xmin, layer.extent().xMinimum())
self.xmax = max(self.xmax, layer.extent().xMaximum())
self.ymin = min(self.ymin, layer.extent().yMinimum())
self.ymax = max(self.ymax, layer.extent().yMaximum())
self.cellsize = min(self.cellsize, cellsize)
self.inputExtentsCount += 1
def processAlgorithm(self, progress): def processAlgorithm(self, progress):
if isWindows(): if isWindows():
@ -208,8 +127,6 @@ class SagaAlgorithm(GeoAlgorithm):
# 1: Export rasters to sgrd and vectors to shp # 1: Export rasters to sgrd and vectors to shp
# Tables must be in dbf format. We check that. # Tables must be in dbf format. We check that.
if self.resample:
self.calculateResamplingExtent()
for param in self.parameters: for param in self.parameters:
if isinstance(param, ParameterRaster): if isinstance(param, ParameterRaster):
if param.value is None: if param.value is None:
@ -219,8 +136,6 @@ class SagaAlgorithm(GeoAlgorithm):
exportCommand = self.exportRasterLayer(value) exportCommand = self.exportRasterLayer(value)
if exportCommand is not None: if exportCommand is not None:
commands.append(exportCommand) commands.append(exportCommand)
if self.resample:
commands.append(self.resampleRasterLayer(value))
if isinstance(param, ParameterVector): if isinstance(param, ParameterVector):
if param.value is None: if param.value is None:
continue continue
@ -253,9 +168,6 @@ class SagaAlgorithm(GeoAlgorithm):
exportCommand = self.exportRasterLayer(layerfile) exportCommand = self.exportRasterLayer(layerfile)
if exportCommand is not None: if exportCommand is not None:
commands.append(exportCommand) commands.append(exportCommand)
if self.resample:
commands.append(
self.resampleRasterLayer(layerfile))
elif param.datatype == ParameterMultipleInput.TYPE_VECTOR_ANY: elif param.datatype == ParameterMultipleInput.TYPE_VECTOR_ANY:
for layerfile in layers: for layerfile in layers:
layer = dataobjects.getObjectFromUri(layerfile, False) layer = dataobjects.getObjectFromUri(layerfile, False)
@ -421,34 +333,7 @@ class SagaAlgorithm(GeoAlgorithm):
cellsize = float(param.value) cellsize = float(param.value)
break break
return cellsize return cellsize
def resampleRasterLayer(self, layer):
"""This is supposed to be run after having exported all raster
layers.
"""
if layer in self.exportedLayers.keys():
inputFilename = self.exportedLayers[layer]
else:
inputFilename = layer
destFilename = getTempFilename('sgrd')
self.exportedLayers[layer] = destFilename
saga208 = ProcessingConfig.getSetting(SagaUtils.SAGA_208)
if isWindows() or isMac() or not saga208:
s = 'grid_tools "Resampling" -INPUT "' + inputFilename \
+ '" -TARGET 0 -SCALE_UP_METHOD 0 -SCALE_DOWN_METHOD 0 -USER_XMIN ' \
+ str(self.xmin) + ' -USER_XMAX ' + str(self.xmax) \
+ ' -USER_YMIN ' + str(self.ymin) + ' -USER_YMAX ' \
+ str(self.ymax) + ' -USER_SIZE ' + str(self.cellsize) \
+ ' -USER_GRID "' + destFilename + '"'
else:
s = 'libgrid_tools "Resampling" -INPUT "' + inputFilename \
+ '" -TARGET 0 -SCALE_UP_METHOD 0 -SCALE_DOWN_METHOD 0 -USER_XMIN ' \
+ str(self.xmin) + ' -USER_XMAX ' + str(self.xmax) \
+ ' -USER_YMIN ' + str(self.ymin) + ' -USER_YMAX ' \
+ str(self.ymax) + ' -USER_SIZE ' + str(self.cellsize) \
+ ' -USER_GRID "' + destFilename + '"'
return s
def exportRasterLayer(self, source): def exportRasterLayer(self, source):
if source in sessionExportedLayers: if source in sessionExportedLayers:
@ -485,22 +370,33 @@ class SagaAlgorithm(GeoAlgorithm):
html = '<p>This algorithm requires SAGA to be run.Unfortunately, \ html = '<p>This algorithm requires SAGA to be run.Unfortunately, \
it seems that SAGA is not installed in your system, or it \ it seems that SAGA is not installed in your system, or it \
is not correctly configured to be used from QGIS</p>' is not correctly configured to be used from QGIS</p>'
html += '<p><a href= "http://docs.qgis.org/2.0/en/docs/user_manual/processing/3rdParty.html">Click here</a> to know more about how to install and configure SAGA to be used with QGIS</p>' html += '<p><a href= "http://docs.qgis.org/2.0/en/docs/user_manual/processing/3rdParty.html">\
Click here</a> to know more about how to install and configure SAGA to be used with QGIS</p>'
return html return html
def checkParameterValuesBeforeExecuting(self): def checkParameterValuesBeforeExecuting(self):
"""We check that there are no multiband layers, which are not
supported by SAGA.
""" """
We check that there are no multiband layers, which are not
supported by SAGA, and that raster layers have the same grid extent
"""
extent = None
for param in self.parameters: for param in self.parameters:
if isinstance(param, ParameterRaster): if isinstance(param, ParameterRaster):
value = param.value layer = dataobjects.getObjectFromUri(param.value)
layer = dataobjects.getObjectFromUri(value) if layer is None:
if layer is not None and layer.bandCount() > 1: continue
if layer.bandCount() > 1:
return 'Input layer ' + str(layer.name()) \ return 'Input layer ' + str(layer.name()) \
+ ' has more than one band.\n' \ + ' has more than one band.\n' \
+ 'Multiband layers are not supported by SAGA' + 'Multiband layers are not supported by SAGA'
if extent is None:
extent = (layer.extent(), layer.height(), layer.width())
else:
extent2 = (layer.extent(), layer.height(), layer.width())
if extent != extent2:
return "Input layers do not have the same grid extent."
def help(self): def help(self):
name = self.cmdname.lower() name = self.cmdname.lower()

View File

@ -51,48 +51,23 @@ class SagaAlgorithmProvider(AlgorithmProvider):
SagaUtils.sagaPath())) SagaUtils.sagaPath()))
ProcessingConfig.addSetting(Setting(self.getDescription(), ProcessingConfig.addSetting(Setting(self.getDescription(),
SagaUtils.SAGA_208, SagaUtils.SAGA_208,
'Enable SAGA 2.0.8 compatibility', True)) 'Use SAGA 2.0.8 syntax', True))
ProcessingConfig.addSetting(Setting(self.getDescription(), ProcessingConfig.addSetting(Setting(self.getDescription(),
SagaUtils.SAGA_IMPORT_EXPORT_OPTIMIZATION, SagaUtils.SAGA_IMPORT_EXPORT_OPTIMIZATION,
'Enable SAGA Import/Export optimizations', 'Enable SAGA Import/Export optimizations',
False)) False))
ProcessingConfig.addSetting(Setting(self.getDescription(),
SagaUtils.SAGA_AUTO_RESAMPLING,
'Use min covering grid system for resampling', True))
ProcessingConfig.addSetting(Setting(self.getDescription(), ProcessingConfig.addSetting(Setting(self.getDescription(),
SagaUtils.SAGA_LOG_COMMANDS, SagaUtils.SAGA_LOG_COMMANDS,
'Log execution commands', True)) 'Log execution commands', True))
ProcessingConfig.addSetting(Setting(self.getDescription(), ProcessingConfig.addSetting(Setting(self.getDescription(),
SagaUtils.SAGA_LOG_CONSOLE, SagaUtils.SAGA_LOG_CONSOLE,
'Log console output', True)) 'Log console output', True))
ProcessingConfig.addSetting(Setting(self.getDescription(),
SagaUtils.SAGA_RESAMPLING_REGION_XMIN,
'Resampling region min x', 0))
ProcessingConfig.addSetting(Setting(self.getDescription(),
SagaUtils.SAGA_RESAMPLING_REGION_YMIN,
'Resampling region min y', 0))
ProcessingConfig.addSetting(Setting(self.getDescription(),
SagaUtils.SAGA_RESAMPLING_REGION_XMAX,
'Resampling region max x', 1000))
ProcessingConfig.addSetting(Setting(self.getDescription(),
SagaUtils.SAGA_RESAMPLING_REGION_YMAX,
'Resampling region max y', 1000))
ProcessingConfig.addSetting(Setting(self.getDescription(),
SagaUtils.SAGA_RESAMPLING_REGION_CELLSIZE,
'Resampling region cellsize', 1))
def unload(self): def unload(self):
AlgorithmProvider.unload(self) AlgorithmProvider.unload(self)
if isWindows(): if isWindows():
ProcessingConfig.removeSetting(SagaUtils.SAGA_FOLDER) ProcessingConfig.removeSetting(SagaUtils.SAGA_FOLDER)
ProcessingConfig.removeSetting(SagaUtils.SAGA_AUTO_RESAMPLING)
ProcessingConfig.removeSetting(SagaUtils.SAGA_RESAMPLING_REGION_XMIN)
ProcessingConfig.removeSetting(SagaUtils.SAGA_RESAMPLING_REGION_YMIN)
ProcessingConfig.removeSetting(SagaUtils.SAGA_RESAMPLING_REGION_XMAX)
ProcessingConfig.removeSetting(SagaUtils.SAGA_RESAMPLING_REGION_YMAX)
ProcessingConfig.removeSetting(
SagaUtils.SAGA_RESAMPLING_REGION_CELLSIZE)
ProcessingConfig.removeSetting(SagaUtils.SAGA_LOG_CONSOLE) ProcessingConfig.removeSetting(SagaUtils.SAGA_LOG_CONSOLE)
ProcessingConfig.removeSetting(SagaUtils.SAGA_LOG_COMMANDS) ProcessingConfig.removeSetting(SagaUtils.SAGA_LOG_COMMANDS)

View File

@ -42,12 +42,6 @@ class SagaUtils:
SAGA_208 = 'SAGA_208' SAGA_208 = 'SAGA_208'
SAGA_LOG_COMMANDS = 'SAGA_LOG_COMMANDS' SAGA_LOG_COMMANDS = 'SAGA_LOG_COMMANDS'
SAGA_LOG_CONSOLE = 'SAGA_LOG_CONSOLE' SAGA_LOG_CONSOLE = 'SAGA_LOG_CONSOLE'
SAGA_AUTO_RESAMPLING = 'SAGA_AUTO_RESAMPLING'
SAGA_RESAMPLING_REGION_XMIN = 'SAGA_RESAMPLING_REGION_XMIN'
SAGA_RESAMPLING_REGION_YMIN = 'SAGA_RESAMPLING_REGION_YMIN'
SAGA_RESAMPLING_REGION_XMAX = 'SAGA_RESAMPLING_REGION_XMAX'
SAGA_RESAMPLING_REGION_YMAX = 'SAGA_RESAMPLING_REGION_YMAX'
SAGA_RESAMPLING_REGION_CELLSIZE = 'SAGA_RESAMPLING_REGION_CELLSIZE'
SAGA_FOLDER = 'SAGA_FOLDER' SAGA_FOLDER = 'SAGA_FOLDER'
SAGA_IMPORT_EXPORT_OPTIMIZATION = 'SAGA_IMPORT_EXPORT_OPTIMIZATION' SAGA_IMPORT_EXPORT_OPTIMIZATION = 'SAGA_IMPORT_EXPORT_OPTIMIZATION'

View File

@ -1,5 +1,6 @@
Raster calculator|Grid Calculator Raster calculator|Grid Calculator
grid_calculus grid_calculus
AllowUnmatching
ParameterMultipleInput|GRIDS|Raster layers|3|False ParameterMultipleInput|GRIDS|Raster layers|3|False
ParameterString|FORMULA|Formula| ParameterString|FORMULA|Formula|
OutputRaster|RESULT|Result OutputRaster|RESULT|Result

View File

@ -1,6 +1,6 @@
Merge raster layers|Merging Merge raster layers|Merging
grid_tools grid_tools
DontResample AllowUnmatching
ParameterMultipleInput|GRIDS|Grids to Merge|3|False ParameterMultipleInput|GRIDS|Grids to Merge|3|False
ParameterSelection|TYPE|Preferred data storage type|[0] 1 bit;[1] 1 byte unsigned integer;[2] 1 byte signed integer;[3] 2 byte unsigned integer;[4] 2 byte signed integer;[5] 4 byte unsigned integer;[6] 4 byte signed integer;[7] 4 byte floating point;[8] 8 byte floating point ParameterSelection|TYPE|Preferred data storage type|[0] 1 bit;[1] 1 byte unsigned integer;[2] 1 byte signed integer;[3] 2 byte unsigned integer;[4] 2 byte signed integer;[5] 4 byte unsigned integer;[6] 4 byte signed integer;[7] 4 byte floating point;[8] 8 byte floating point
ParameterSelection|INTERPOL|Interpolation|[0] Nearest Neighbor;[1] Bilinear Interpolation;[2] Inverse Distance Interpolation;[3] Bicubic Spline Interpolation;[4] B-Spline Interpolation ParameterSelection|INTERPOL|Interpolation|[0] Nearest Neighbor;[1] Bilinear Interpolation;[2] Inverse Distance Interpolation;[3] Bicubic Spline Interpolation;[4] B-Spline Interpolation