Skip to content

Commit

Permalink
[processing] simplified saga algorithms
Browse files Browse the repository at this point in the history
Now it assumes matching grid extents and does not perform resampling
  • Loading branch information
volaya committed May 21, 2014
1 parent c1a2ac8 commit 202d331
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 161 deletions.
150 changes: 23 additions & 127 deletions python/plugins/processing/algs/saga/SagaAlgorithm.py
Expand Up @@ -63,34 +63,18 @@ class SagaAlgorithm(GeoAlgorithm):
OUTPUT_EXTENT = 'OUTPUT_EXTENT'

def __init__(self, descriptionfile):
# True if it should resample
self.resample = True
self.allowUnmatchingGridExtents = False

# In case several non-matching raster layers are used as input
GeoAlgorithm.__init__(self)
self.descriptionFile = descriptionfile
self.defineCharacteristicsFromFile()
if self.resample:
# Reconsider resampling policy now that we know the input
# parameters
self.resample = self.setResamplingPolicy()

def getCopy(self):
newone = SagaAlgorithm(self.descriptionFile)
newone.provider = self.provider
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):
return QIcon(os.path.dirname(__file__) + '/../../images/saga.png')

Expand All @@ -116,8 +100,8 @@ def defineCharacteristicsFromFile(self):
self.hardcodedStrings.append(line[len('Harcoded|') + 1:])
elif line.startswith('Parameter'):
self.addParameter(ParameterFactory.getFromString(line))
elif line.startswith('DontResample'):
self.resample = False
elif line.startswith('AllowUnmatching'):
self.allowUnmatchingGridExtents = True
elif line.startswith('Extent'):
# An extent parameter that wraps 4 SAGA numerical parameters
self.extentParamNames = line[6:].strip().split(' ')
Expand All @@ -128,71 +112,6 @@ def defineCharacteristicsFromFile(self):
line = lines.readline().strip('\n').strip()
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):
if isWindows():
Expand All @@ -208,8 +127,6 @@ def processAlgorithm(self, progress):

# 1: Export rasters to sgrd and vectors to shp
# Tables must be in dbf format. We check that.
if self.resample:
self.calculateResamplingExtent()
for param in self.parameters:
if isinstance(param, ParameterRaster):
if param.value is None:
Expand All @@ -219,8 +136,6 @@ def processAlgorithm(self, progress):
exportCommand = self.exportRasterLayer(value)
if exportCommand is not None:
commands.append(exportCommand)
if self.resample:
commands.append(self.resampleRasterLayer(value))
if isinstance(param, ParameterVector):
if param.value is None:
continue
Expand Down Expand Up @@ -253,9 +168,6 @@ def processAlgorithm(self, progress):
exportCommand = self.exportRasterLayer(layerfile)
if exportCommand is not None:
commands.append(exportCommand)
if self.resample:
commands.append(
self.resampleRasterLayer(layerfile))
elif param.datatype == ParameterMultipleInput.TYPE_VECTOR_ANY:
for layerfile in layers:
layer = dataobjects.getObjectFromUri(layerfile, False)
Expand Down Expand Up @@ -421,34 +333,7 @@ def getOutputCellsize(self):
cellsize = float(param.value)
break
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):
if source in sessionExportedLayers:
Expand Down Expand Up @@ -485,22 +370,33 @@ def checkBeforeOpeningParametersDialog(self):
html = '<p>This algorithm requires SAGA to be run.Unfortunately, \
it seems that SAGA is not installed in your system, or it \
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

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:
if isinstance(param, ParameterRaster):
value = param.value
layer = dataobjects.getObjectFromUri(value)
if layer is not None and layer.bandCount() > 1:
if isinstance(param, ParameterRaster):
layer = dataobjects.getObjectFromUri(param.value)
if layer is None:
continue
if layer.bandCount() > 1:
return 'Input layer ' + str(layer.name()) \
+ ' has more than one band.\n' \
+ '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):
name = self.cmdname.lower()
Expand Down
29 changes: 2 additions & 27 deletions python/plugins/processing/algs/saga/SagaAlgorithmProvider.py
Expand Up @@ -51,48 +51,23 @@ def initializeSettings(self):
SagaUtils.sagaPath()))
ProcessingConfig.addSetting(Setting(self.getDescription(),
SagaUtils.SAGA_208,
'Enable SAGA 2.0.8 compatibility', True))
'Use SAGA 2.0.8 syntax', True))
ProcessingConfig.addSetting(Setting(self.getDescription(),
SagaUtils.SAGA_IMPORT_EXPORT_OPTIMIZATION,
'Enable SAGA Import/Export optimizations',
False))
ProcessingConfig.addSetting(Setting(self.getDescription(),
SagaUtils.SAGA_AUTO_RESAMPLING,
'Use min covering grid system for resampling', True))
ProcessingConfig.addSetting(Setting(self.getDescription(),
SagaUtils.SAGA_LOG_COMMANDS,
'Log execution commands', True))
ProcessingConfig.addSetting(Setting(self.getDescription(),
SagaUtils.SAGA_LOG_CONSOLE,
'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):
AlgorithmProvider.unload(self)
if isWindows():
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_COMMANDS)

Expand Down
6 changes: 0 additions & 6 deletions python/plugins/processing/algs/saga/SagaUtils.py
Expand Up @@ -42,12 +42,6 @@ class SagaUtils:
SAGA_208 = 'SAGA_208'
SAGA_LOG_COMMANDS = 'SAGA_LOG_COMMANDS'
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_IMPORT_EXPORT_OPTIMIZATION = 'SAGA_IMPORT_EXPORT_OPTIMIZATION'

Expand Down
@@ -1,5 +1,6 @@
Raster calculator|Grid Calculator
grid_calculus
AllowUnmatching
ParameterMultipleInput|GRIDS|Raster layers|3|False
ParameterString|FORMULA|Formula|
OutputRaster|RESULT|Result
@@ -1,6 +1,6 @@
Merge raster layers|Merging
grid_tools
DontResample
AllowUnmatching
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|INTERPOL|Interpolation|[0] Nearest Neighbor;[1] Bilinear Interpolation;[2] Inverse Distance Interpolation;[3] Bicubic Spline Interpolation;[4] B-Spline Interpolation
Expand Down

0 comments on commit 202d331

Please sign in to comment.