Showing with 491 additions and 236 deletions.
  1. +2 −5 python/plugins/sextante/SextantePlugin.py
  2. +95 −0 python/plugins/sextante/algs/Polygonize.py
  3. +2 −1 python/plugins/sextante/algs/QGISAlgorithmProvider.py
  4. +5 −1 python/plugins/sextante/core/LayerExporter.py
  5. +4 −3 python/plugins/sextante/gui/TestTools.py
  6. +22 −11 python/plugins/sextante/modeler/ModelerAlgorithm.py
  7. +0 −49 python/plugins/sextante/modeler/models/contour_from_points.model
  8. +45 −0 python/plugins/sextante/modeler/models/contours.model
  9. 0 python/plugins/sextante/modeler/models/{fieldextent.mode.model → fieldextent.model}
  10. +0 −86 python/plugins/sextante/modeler/models/habitat_selection_model.model
  11. +26 −0 python/plugins/sextante/modeler/models/modelscript.model
  12. +25 −0 python/plugins/sextante/modeler/models/noinputs.model
  13. +12 −12 python/plugins/sextante/modeler/models/watersheds.model
  14. +45 −0 python/plugins/sextante/r/DeleteRScriptAction.py
  15. +2 −1 python/plugins/sextante/r/RAlgorithmProvider.py
  16. +12 −5 python/plugins/sextante/saga/SagaAlgorithm.py
  17. +1 −1 python/plugins/sextante/saga/SagaAlgorithmProvider.py
  18. +4 −11 python/plugins/sextante/saga/description/CutShapesLayer.txt
  19. +2 −2 python/plugins/sextante/saga/description/TransformShapes.txt
  20. +4 −0 python/plugins/sextante/script/scripts/A_script_that_returns_a_number.py
  21. +3 −0 python/plugins/sextante/script/scripts/Load_test_data.py
  22. +22 −4 python/plugins/sextante/tests/ModelerAlgorithmTest.py
  23. +8 −3 python/plugins/sextante/tests/ParametersTest.py
  24. +1 −1 python/plugins/sextante/tests/RunAlgTest.py
  25. +81 −0 python/plugins/sextante/tests/SagaTest.py
  26. +6 −0 python/plugins/sextante/tests/ScriptTest.py
  27. +4 −0 python/plugins/sextante/tests/TestData.py
  28. +10 −0 python/plugins/sextante/tests/data/polygons.geojson
  29. +0 −16 python/plugins/sextante/tests/runtests.sh
  30. +18 −2 python/plugins/sextante/ui/DlgModeler.ui
  31. +30 −22 python/plugins/sextante/ui/ui_DlgModeler.py
7 changes: 2 additions & 5 deletions python/plugins/sextante/SextantePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
* *
***************************************************************************
"""
import shutil

__author__ = 'Victor Olaya'
__date__ = 'August 2012'
__copyright__ = '(C) 2012, Victor Olaya'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'

import shutil
import os, sys
import inspect
from PyQt4.QtCore import *
Expand All @@ -32,19 +32,16 @@
from sextante.core.Sextante import Sextante
from sextante.core.QGisLayers import QGisLayers
from sextante.core.SextanteUtils import SextanteUtils

from sextante.gui.SextanteToolbox import SextanteToolbox
from sextante.gui.HistoryDialog import HistoryDialog
from sextante.gui.ConfigDialog import ConfigDialog
from sextante.gui.ResultsDialog import ResultsDialog

from sextante.modeler.ModelerDialog import ModelerDialog

import sextante.resources_rc

cmd_folder = os.path.split(inspect.getfile( inspect.currentframe() ))[0]
if cmd_folder not in sys.path:
sys.path.insert(0, cmd_folder)
sys.path.insert(0, cmd_folder)

class SextantePlugin:

Expand Down
95 changes: 95 additions & 0 deletions python/plugins/sextante/algs/Polygonize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# -*- coding: utf-8 -*-

"""
***************************************************************************
Polygonize.py
---------------------
Date : March 2013
Copyright : (C) 2013 by Piotr Pociask
Email : ppociask at o2 dot pl
***************************************************************************
* *
* 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__ = 'Piotr Pociask'
__date__ = 'March 2013'
__copyright__ = '(C) 2013, Piotr Pociask'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'

from sextante.core.GeoAlgorithm import GeoAlgorithm
from PyQt4.QtCore import QVariant
from qgis.core import QgsFeature, QgsField, QgsFields, QgsGeometry, QGis
from sextante.parameters.ParameterVector import ParameterVector
from sextante.parameters.ParameterBoolean import ParameterBoolean
from sextante.core.QGisLayers import QGisLayers
from sextante.outputs.OutputVector import OutputVector
from sextante.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException

class Polygonize(GeoAlgorithm):
INPUT = "INPUT"
OUTPUT = "OUTPUT"
FIELDS = "FIELDS"
GEOMETRY = "GEOMETRY"

def processAlgorithm(self, progress):
try:
from shapely.ops import polygonize
from shapely.geometry import Point,MultiLineString
except ImportError:
raise GeoAlgorithmExecutionException('Polygonize algorithm requires shapely module!')
vlayer = QGisLayers.getObjectFromUri(self.getParameterValue(self.INPUT))
output = self.getOutputFromName(self.OUTPUT)
vprovider = vlayer.dataProvider()
if self.getParameterValue(self.FIELDS):
fields = vprovider.fields()
else:
fields = QgsFields()
if self.getParameterValue(self.GEOMETRY):
fieldsCount = fields.count()
fields.append(QgsField("area",QVariant.Double,"double",16,2))
fields.append(QgsField("perimeter",QVariant.Double,"double",16,2))
allLinesList = []
features = QGisLayers.features(vlayer)
current = 0
total = 40.0 / float(len(features))
for inFeat in features:
inGeom = inFeat.geometry()
if inGeom.isMultipart():
allLinesList.extend(inGeom.asMultiPolyline())
else:
allLinesList.append(inGeom.asPolyline())
current += 1
progress.setPercentage(int(current * total))
progress.setPercentage(40)
allLines = MultiLineString(allLinesList)
allLines = allLines.union(Point(0,0))
progress.setPercentage(45)
polygons = list(polygonize([allLines]))
progress.setPercentage(50)
writer = output.getVectorWriter(fields, QGis.WKBPolygon, vlayer.crs() )
outFeat = QgsFeature()
current = 0
total = 50.0 / float(len(polygons))
for polygon in polygons:
outFeat.setGeometry(QgsGeometry.fromWkt( polygon.wkt ))
if self.getParameterValue(self.GEOMETRY):
outFeat.setAttributes([None]*fieldsCount + [ QVariant(polygon.area), QVariant(polygon.length)])
writer.addFeature(outFeat)
current += 1
progress.setPercentage(50+int(current * total))
del writer

def defineCharacteristics(self):
self.name = "Polygonize"
self.group = "Vector geometry tools"
self.addParameter(ParameterVector(self.INPUT, "Input layer",ParameterVector.VECTOR_TYPE_LINE))
self.addParameter(ParameterBoolean(self.FIELDS, "Keep table structure of line layer", False))
self.addParameter(ParameterBoolean(self.GEOMETRY, "Create geometry columns", True))
self.addOutput(OutputVector(self.OUTPUT, "Output layer"))
3 changes: 2 additions & 1 deletion python/plugins/sextante/algs/QGISAlgorithmProvider.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* *
***************************************************************************
"""
from sextante.algs.Polygonize import Polygonize

__author__ = 'Victor Olaya'
__date__ = 'December 2012'
Expand Down Expand Up @@ -130,7 +131,7 @@ def __init__(self):
# ------ native algs ------
AddTableField(), FieldsCalculator(), SaveSelectedFeatures(), JoinAttributes(),
AutoincrementalField(), Explode(), FieldsPyculator(), EquivalentNumField(),
PointsLayerFromTable(), StatisticsByCategories(),
PointsLayerFromTable(), StatisticsByCategories(), Polygonize(),
# ------ raster ------
CreateConstantRaster(), RasterLayerStatistics()
# ------ graphics ------
Expand Down
6 changes: 5 additions & 1 deletion python/plugins/sextante/core/LayerExporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ def exportVectorLayer(layer):
It also export to a new file if the original one contains non-ascii characters'''
settings = QSettings()
systemEncoding = settings.value( "/UI/encoding", "System" ).toString()
output = SextanteUtils.getTempFilenameInTempFolder(os.path.basename(unicode(layer.source())) + ".shp")
filename = os.path.basename(unicode(layer.source()))
idx = filename.rfind(".")
if idx != -1:
filename = filename[:idx]
output = SextanteUtils.getTempFilenameInTempFolder(filename + ".shp")
#output = SextanteUtils.getTempFilename("shp")
provider = layer.dataProvider()
useSelection = SextanteConfig.getSetting(SextanteConfig.USE_SELECTED)
Expand Down
7 changes: 4 additions & 3 deletions python/plugins/sextante/gui/TestTools.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,12 @@ def createTest(text):
i = -1 * len(alg.outputs)
for out in alg.outputs:
filename = tokens[i][1:-1]
if (filename == str(None)):
raise Exception("Cannot create unit test for that algorithm execution.\nThe output cannot be a temporary file")
if (tokens[i] == str(None)):
QtGui.QMessageBox.critical(None, "Error", "Cannot create unit test for that algorithm execution.\nThe output cannot be a temporary file")
return
s+="\toutput=outputs['" + out.name + "']\n"
if isinstance(out, (OutputNumber, OutputString)):
s+="self.assertTrue(" + str(out) + ", output)\n"
s+="self.assertTrue(" + str(out) + ", output.value)\n"
if isinstance(out, OutputRaster):
dataset = gdal.Open(filename, GA_ReadOnly)
strhash = hash(str(dataset.ReadAsArray(0).tolist()))
Expand Down
33 changes: 22 additions & 11 deletions python/plugins/sextante/modeler/ModelerAlgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@
* *
***************************************************************************
"""

__author__ = 'Victor Olaya'
__date__ = 'August 2012'
__copyright__ = '(C) 2012, Victor Olaya'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'

import traceback
import copy
import os.path
import codecs
Expand Down Expand Up @@ -121,7 +123,7 @@ def openModel(self, filename):
if param:
self.parameters.append(param)
else:
raise WrongModelException("Error in line: " + line)
raise WrongModelException("Error in parameter line: " + line)
line = lines.readline().strip("\n")
tokens = line.split(",")
self.paramPos.append(QtCore.QPointF(float(tokens[0]), float(tokens[1])))
Expand All @@ -138,7 +140,7 @@ def openModel(self, filename):
algOutputs={}
algLine = line[len("ALGORITHM:"):]
alg = ModelerUtils.getAlgorithm(algLine)
if alg:
if alg is not None:
posline = lines.readline().strip("\n")
tokens = posline.split(",")
self.algPos.append(QtCore.QPointF(float(tokens[0]), float(tokens[1])))
Expand All @@ -147,7 +149,10 @@ def openModel(self, filename):
dependencies = [];
if dependenceline != str(None):
for index in dependenceline.split(","):
dependencies.append(int(index))
try:
dependencies.append(int(index))
except:
pass #a quick fix fwhile I figure out how to solve problems when parsing this
for param in alg.parameters:
line = lines.readline().strip("\n")
if line==str(None):
Expand All @@ -172,10 +177,13 @@ def openModel(self, filename):
self.dependencies.append(dependencies)
iAlg += 1
else:
raise WrongModelException("Error in line: " + line)
raise WrongModelException("Error in algorithm name: " + algLine)
line = lines.readline().strip("\n")
except:
raise WrongModelException("Error in line: " + line)
except Exception, e:
if isinstance (e, WrongModelException):
raise e
else:
raise WrongModelException("Error in model definition line:" + line.strip() + " : " + traceback.format_exc())

def addParameter(self, param):
self.parameters.append(param)
Expand Down Expand Up @@ -204,6 +212,7 @@ def updateAlgorithm(self, algIndex, parametersMap, valuesMap, outputsMap, depend


def removeAlgorithm(self, index):
'''returns true if the algorithm could be removed, false if others depend on it and could not be removed'''
if self.hasDependencies(self.algs[index], index):
return False
for out in self.algs[index].outputs:
Expand Down Expand Up @@ -233,6 +242,7 @@ def removeAlgorithm(self, index):
return True

def removeParameter(self, index):
'''returns true if the parameter could be removed, false if others depend on it and could not be removed'''
if self.hasDependencies(self.parameters[index], index):
return False
del self.parameters[index]
Expand Down Expand Up @@ -292,13 +302,13 @@ def getDependsOnAlgorithms(self, algIndex):
'''This method returns a list with the indexes of algorithms a given one depends on'''
algs = []
algs.extend(self.dependencies[algIndex])
index = -1
index = -1
for aap in self.algParameters[algIndex].values():
index += 1
if aap is not None:
if aap.alg != AlgorithmAndParameter.PARENT_MODEL_ALGORITHM and aap.alg not in algs:
algs.append(index)
dep = self.getDependsOnAlgorithms(index)
algs.append(aap.alg)
dep = self.getDependsOnAlgorithms(aap.alg)
for alg in dep:
if alg not in algs:
algs.append(alg)
Expand Down Expand Up @@ -496,7 +506,7 @@ def processAlgorithm(self, progress):
canExecute = True
required = self.getDependsOnAlgorithms(iAlg)
for requiredAlg in required:
if requiredAlg not in executed:
if requiredAlg != iAlg and requiredAlg not in executed:
canExecute = False
break
if canExecute:
Expand All @@ -523,7 +533,8 @@ def processAlgorithm(self, progress):
progress.setDebugInfo("Failed")
raise GeoAlgorithmExecutionException("Error executing algorithm " + str(iAlg) + "\n" + e.msg)
else:
progress.setDebugInfo("Algorithm %s deactivated (or already executed)" % alg.name)
pass
#progress.setDebugInfo("Algorithm %s deactivated (or already executed)" % alg.name)
iAlg += 1
progress.setDebugInfo("Model processed ok. Executed %i algorithms total" % iAlg)

Expand Down
49 changes: 0 additions & 49 deletions python/plugins/sextante/modeler/models/contour_from_points.model

This file was deleted.

45 changes: 45 additions & 0 deletions python/plugins/sextante/modeler/models/contours.model
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
NAME:Contour lines from points
GROUP:[Example models]
PARAMETER:ParameterVector|VECTORLAYER_SHAPES|Shapes|-1|False
120.0,60.0
PARAMETER:ParameterNumber|NUMBER_INTERVAL|Interval|0.0|None|10.0
633.0,163.0
PARAMETER:ParameterNumber|NUMBER_CELLSIZEFORINTERMEDIATELAYER|Cellsize for intermediate layer|0.0|None|10.0
411.0,84.0
PARAMETER:ParameterTableField|TABLEFIELD_FIELD|Field|VECTORLAYER_SHAPES|-1
104.0,202.0
VALUE:HARDCODEDPARAMVALUE_LINE_TYPE_0===0
VALUE:HARDCODEDPARAMVALUE_ZMAX_2===10000.0
VALUE:HARDCODEDPARAMVALUE_USER_SIZE_0===1.0
VALUE:HARDCODEDPARAMVALUE_ZMIN_2===0.0
VALUE:HARDCODEDPARAMVALUE_THRESHOLD_1===0.1
VALUE:HARDCODEDPARAMVALUE_MULTIPLE_0===0
VALUE:HARDCODEDPARAMVALUE_GRID_TYPE_0===3
VALUE:HARDCODEDPARAMVALUE_TARGET_0===0
ALGORITHM:saga:shapestogrid
348.0,211.0
None
-1|VECTORLAYER_SHAPES
-1|TABLEFIELD_FIELD
-1|HARDCODEDPARAMVALUE_MULTIPLE_0
-1|HARDCODEDPARAMVALUE_LINE_TYPE_0
-1|HARDCODEDPARAMVALUE_GRID_TYPE_0
-1|HARDCODEDPARAMVALUE_TARGET_0
None
-1|NUMBER_CELLSIZEFORINTERMEDIATELAYER
None
ALGORITHM:saga:closegaps
450.0,379.0
None
0|USER_GRID
None
-1|HARDCODEDPARAMVALUE_THRESHOLD_1
None
ALGORITHM:saga:contourlinesfromgrid
630.0,279.0
None
1|RESULT
-1|HARDCODEDPARAMVALUE_ZMIN_2
-1|HARDCODEDPARAMVALUE_ZMAX_2
-1|NUMBER_INTERVAL
Contour lines
Loading