Skip to content

Commit

Permalink
Merge pull request #5050 from nyalldawson/algs
Browse files Browse the repository at this point in the history
Port more QGIS algs to new API
  • Loading branch information
nyalldawson committed Aug 21, 2017
2 parents 2530d9e + bcc6627 commit 4c52607
Show file tree
Hide file tree
Showing 27 changed files with 995 additions and 756 deletions.
31 changes: 13 additions & 18 deletions python/plugins/processing/algs/qgis/DefineProjection.py
Expand Up @@ -28,15 +28,12 @@
import os import os
import re import re


from qgis.core import (QgsCoordinateReferenceSystem, from qgis.core import (QgsProcessing,
QgsApplication, QgsProcessingParameterVectorLayer,
QgsProcessingUtils) QgsProcessingParameterCrs,
from qgis.utils import iface QgsProcessingOutputVectorLayer)


from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterCrs
from processing.core.outputs import OutputVector


pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]


Expand All @@ -45,7 +42,6 @@ class DefineProjection(QgisAlgorithm):


INPUT = 'INPUT' INPUT = 'INPUT'
CRS = 'CRS' CRS = 'CRS'
OUTPUT = 'OUTPUT'


def group(self): def group(self):
return self.tr('Vector general tools') return self.tr('Vector general tools')
Expand All @@ -54,11 +50,11 @@ def __init__(self):
super().__init__() super().__init__()


def initAlgorithm(self, config=None): def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.INPUT, self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT,
self.tr('Input Layer'))) self.tr('Input Layer'), types=[QgsProcessing.TypeVectorAnyGeometry]))
self.addParameter(ParameterCrs(self.CRS, 'Output CRS')) self.addParameter(QgsProcessingParameterCrs(self.CRS, 'Output CRS'))
self.addOutput(OutputVector(self.OUTPUT, self.addOutput(QgsProcessingOutputVectorLayer(self.INPUT,
self.tr('Layer with projection'), True)) self.tr('Layer with projection')))


def name(self): def name(self):
return 'definecurrentprojection' return 'definecurrentprojection'
Expand All @@ -67,9 +63,8 @@ def displayName(self):
return self.tr('Define current projection') return self.tr('Define current projection')


def processAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
fileName = self.getParameterValue(self.INPUT) layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
layer = QgsProcessingUtils.mapLayerFromString(fileName, context) crs = self.parameterAsCrs(parameters, self.CRS, context)
crs = QgsCoordinateReferenceSystem(self.getParameterValue(self.CRS))


provider = layer.dataProvider() provider = layer.dataProvider()
ds = provider.dataSourceUri() ds = provider.dataSourceUri()
Expand All @@ -89,6 +84,6 @@ def processAlgorithm(self, parameters, context, feedback):
f.write(wkt) f.write(wkt)


layer.setCrs(crs) layer.setCrs(crs)
iface.mapCanvas().refresh() layer.triggerRepaint()


self.setOutputValue(self.OUTPUT, fileName) return {self.INPUT: layer}
100 changes: 44 additions & 56 deletions python/plugins/processing/algs/qgis/ExecuteSQL.py
Expand Up @@ -25,21 +25,18 @@


__revision__ = '$Format:%H$' __revision__ = '$Format:%H$'


from qgis.core import (QgsFeature, from qgis.core import (QgsVirtualLayerDefinition,
QgsVirtualLayerDefinition,
QgsVectorLayer, QgsVectorLayer,
QgsCoordinateReferenceSystem,
QgsWkbTypes, QgsWkbTypes,
QgsApplication, QgsProcessingParameterMultipleLayers,
QgsProcessingUtils) QgsProcessingParameterString,
QgsProcessingParameterEnum,
QgsProcessingParameterCrs,
QgsProcessingParameterFeatureSink,
QgsFeatureSink,
QgsProcessingException)


from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterString
from processing.core.parameters import ParameterMultipleInput
from processing.core.parameters import ParameterCrs
from processing.core.parameters import ParameterSelection
from processing.core.outputs import OutputVector




class ExecuteSQL(QgisAlgorithm): class ExecuteSQL(QgisAlgorithm):
Expand All @@ -54,7 +51,7 @@ class ExecuteSQL(QgisAlgorithm):
INPUT_GEOMETRY_FIELD = 'INPUT_GEOMETRY_FIELD' INPUT_GEOMETRY_FIELD = 'INPUT_GEOMETRY_FIELD'
INPUT_GEOMETRY_TYPE = 'INPUT_GEOMETRY_TYPE' INPUT_GEOMETRY_TYPE = 'INPUT_GEOMETRY_TYPE'
INPUT_GEOMETRY_CRS = 'INPUT_GEOMETRY_CRS' INPUT_GEOMETRY_CRS = 'INPUT_GEOMETRY_CRS'
OUTPUT_LAYER = 'OUTPUT_LAYER' OUTPUT = 'OUTPUT'


def group(self): def group(self):
return self.tr('Vector general tools') return self.tr('Vector general tools')
Expand All @@ -63,19 +60,19 @@ def __init__(self):
super().__init__() super().__init__()


def initAlgorithm(self, config=None): def initAlgorithm(self, config=None):
self.addParameter(ParameterMultipleInput(name=self.INPUT_DATASOURCES, self.addParameter(QgsProcessingParameterMultipleLayers(name=self.INPUT_DATASOURCES,
description=self.tr('Additional input datasources (called input1, .., inputN in the query)'), description=self.tr('Additional input datasources (called input1, .., inputN in the query)'),
optional=True)) optional=True))


self.addParameter(ParameterString(name=self.INPUT_QUERY, self.addParameter(QgsProcessingParameterString(name=self.INPUT_QUERY,
description=self.tr('SQL query'), description=self.tr('SQL query'),
multiline=True)) multiLine=True))


self.addParameter(ParameterString(name=self.INPUT_UID_FIELD, self.addParameter(QgsProcessingParameterString(name=self.INPUT_UID_FIELD,
description=self.tr('Unique identifier field'), optional=True)) description=self.tr('Unique identifier field'), optional=True))


self.addParameter(ParameterString(name=self.INPUT_GEOMETRY_FIELD, self.addParameter(QgsProcessingParameterString(name=self.INPUT_GEOMETRY_FIELD,
description=self.tr('Geometry field'), optional=True)) description=self.tr('Geometry field'), optional=True))


self.geometryTypes = [ self.geometryTypes = [
self.tr('Autodetect'), self.tr('Autodetect'),
Expand All @@ -86,13 +83,13 @@ def initAlgorithm(self, config=None):
'MultiPoint', 'MultiPoint',
'MultiLineString', 'MultiLineString',
'MultiPolygon'] 'MultiPolygon']
self.addParameter(ParameterSelection(self.INPUT_GEOMETRY_TYPE, self.addParameter(QgsProcessingParameterEnum(self.INPUT_GEOMETRY_TYPE,
self.tr('Geometry type'), self.geometryTypes, optional=True)) self.tr('Geometry type'), options=self.geometryTypes, optional=True))


self.addParameter(ParameterCrs(self.INPUT_GEOMETRY_CRS, self.addParameter(QgsProcessingParameterCrs(self.INPUT_GEOMETRY_CRS,
self.tr('CRS'), optional=True)) self.tr('CRS'), optional=True))


self.addOutput(OutputVector(self.OUTPUT_LAYER, self.tr('SQL Output'))) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('SQL Output')))


def name(self): def name(self):
return 'executesql' return 'executesql'
Expand All @@ -101,24 +98,19 @@ def displayName(self):
return self.tr('Execute SQL') return self.tr('Execute SQL')


def processAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
layers = self.getParameterValue(self.INPUT_DATASOURCES) layers = self.parameterAsLayerList(parameters, self.INPUT_DATASOURCES, context)
query = self.getParameterValue(self.INPUT_QUERY) query = self.parameterAsString(parameters, self.INPUT_QUERY, context)
uid_field = self.getParameterValue(self.INPUT_UID_FIELD) uid_field = self.parameterAsString(parameters, self.INPUT_UID_FIELD, context)
geometry_field = self.getParameterValue(self.INPUT_GEOMETRY_FIELD) geometry_field = self.parameterAsString(parameters, self.INPUT_GEOMETRY_FIELD, context)
geometry_type = self.getParameterValue(self.INPUT_GEOMETRY_TYPE) geometry_type = self.parameterAsEnum(parameters, self.INPUT_GEOMETRY_TYPE, context)
geometry_crs = self.getParameterValue(self.INPUT_GEOMETRY_CRS) geometry_crs = self.parameterAsCrs(parameters, self.INPUT_GEOMETRY_CRS, context)


df = QgsVirtualLayerDefinition() df = QgsVirtualLayerDefinition()
layerIdx = 1 for layerIdx, layer in enumerate(layers):
if layers: df.addSource('input{}'.format(layerIdx + 1), layer.id())
for layerSource in layers.split(';'):
layer = QgsProcessingUtils.mapLayerFromString(layerSource, context)
if layer:
df.addSource('input{}'.format(layerIdx), layer.id())
layerIdx += 1


if query == '': if query == '':
raise GeoAlgorithmExecutionException( raise QgsProcessingException(
self.tr('Empty SQL. Please enter valid SQL expression and try again.')) self.tr('Empty SQL. Please enter valid SQL expression and try again.'))
else: else:
df.setQuery(query) df.setQuery(query)
Expand All @@ -133,26 +125,22 @@ def processAlgorithm(self, parameters, context, feedback):
df.setGeometryField(geometry_field) df.setGeometryField(geometry_field)
if geometry_type > 1: if geometry_type > 1:
df.setGeometryWkbType(geometry_type - 1) df.setGeometryWkbType(geometry_type - 1)
if geometry_crs: if geometry_crs.isValid():
crs = QgsCoordinateReferenceSystem(geometry_crs) df.setGeometrySrid(geometry_crs.postgisSrid())
if crs.isValid():
df.setGeometrySrid(crs.postgisSrid())


vLayer = QgsVectorLayer(df.toString(), "temp_vlayer", "virtual") vLayer = QgsVectorLayer(df.toString(), "temp_vlayer", "virtual")
if not vLayer.isValid(): if not vLayer.isValid():
raise GeoAlgorithmExecutionException(vLayer.dataProvider().error().message()) raise QgsProcessingException(vLayer.dataProvider().error().message())


writer = self.getOutputFromName(self.OUTPUT_LAYER).getVectorWriter(vLayer.fields(), (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
vLayer.wkbType() if geometry_type != 1 else 1, vLayer.fields(), vLayer.wkbType() if geometry_type != 1 else 1, vLayer.crs())
vLayer.crs(), context)


features = QgsProcessingUtils.getFeatures(vLayer, context) features = vLayer.getFeatures()
total = 100.0 / vLayer.featureCount() if vLayer.featureCount() else 0 total = 100.0 / vLayer.featureCount() if vLayer.featureCount() else 0
outFeat = QgsFeature()
for current, inFeat in enumerate(features): for current, inFeat in enumerate(features):
outFeat.setAttributes(inFeat.attributes()) if feedback.isCanceled():
if geometry_type != 1: break
outFeat.setGeometry(inFeat.geometry())
writer.addFeature(outFeat, QgsFeatureSink.FastInsert) sink.addFeature(inFeat, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
del writer return {self.OUTPUT: dest_id}
100 changes: 50 additions & 50 deletions python/plugins/processing/algs/qgis/FieldPyculator.py
Expand Up @@ -29,30 +29,27 @@
import sys import sys


from qgis.PyQt.QtCore import QVariant from qgis.PyQt.QtCore import QVariant
from qgis.core import (QgsFeature, from qgis.core import (QgsProcessingException,
QgsField, QgsField,
QgsFeatureSink, QgsFeatureSink,
QgsApplication, QgsProcessingParameterFeatureSource,
QgsProcessingUtils) QgsProcessingParameterString,
QgsProcessingParameterEnum,
QgsProcessingParameterNumber,
QgsProcessingParameterFeatureSink)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterString
from processing.core.parameters import ParameterNumber
from processing.core.parameters import ParameterSelection
from processing.core.outputs import OutputVector




class FieldsPyculator(QgisAlgorithm): class FieldsPyculator(QgisAlgorithm):


INPUT_LAYER = 'INPUT_LAYER' INPUT = 'INPUT'
FIELD_NAME = 'FIELD_NAME' FIELD_NAME = 'FIELD_NAME'
FIELD_TYPE = 'FIELD_TYPE' FIELD_TYPE = 'FIELD_TYPE'
FIELD_LENGTH = 'FIELD_LENGTH' FIELD_LENGTH = 'FIELD_LENGTH'
FIELD_PRECISION = 'FIELD_PRECISION' FIELD_PRECISION = 'FIELD_PRECISION'
GLOBAL = 'GLOBAL' GLOBAL = 'GLOBAL'
FORMULA = 'FORMULA' FORMULA = 'FORMULA'
OUTPUT_LAYER = 'OUTPUT_LAYER' OUTPUT = 'OUTPUT'
RESULT_VAR_NAME = 'value' RESULT_VAR_NAME = 'value'


TYPES = [QVariant.Int, QVariant.Double, QVariant.String] TYPES = [QVariant.Int, QVariant.Double, QVariant.String]
Expand All @@ -68,21 +65,21 @@ def initAlgorithm(self, config=None):
self.tr('Float'), self.tr('Float'),
self.tr('String')] self.tr('String')]


self.addParameter(ParameterVector(self.INPUT_LAYER, self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer')))
self.tr('Input layer'))) self.addParameter(QgsProcessingParameterString(self.FIELD_NAME,
self.addParameter(ParameterString(self.FIELD_NAME, self.tr('Result field name'), defaultValue='NewField'))
self.tr('Result field name'), 'NewField')) self.addParameter(QgsProcessingParameterEnum(self.FIELD_TYPE,
self.addParameter(ParameterSelection(self.FIELD_TYPE, self.tr('Field type'), options=self.type_names))
self.tr('Field type'), self.type_names)) self.addParameter(QgsProcessingParameterNumber(self.FIELD_LENGTH,
self.addParameter(ParameterNumber(self.FIELD_LENGTH, self.tr('Field length'), minValue=1, maxValue=255, defaultValue=10))
self.tr('Field length'), 1, 255, 10)) self.addParameter(QgsProcessingParameterNumber(self.FIELD_PRECISION,
self.addParameter(ParameterNumber(self.FIELD_PRECISION, self.tr('Field precision'), minValue=0, maxValue=15, defaultValue=3))
self.tr('Field precision'), 0, 10, 0)) self.addParameter(QgsProcessingParameterString(self.GLOBAL,
self.addParameter(ParameterString(self.GLOBAL, self.tr('Global expression'), multiLine=True, optional=True))
self.tr('Global expression'), multiline=True, optional=True)) self.addParameter(QgsProcessingParameterString(self.FORMULA,
self.addParameter(ParameterString(self.FORMULA, self.tr('Formula'), defaultValue='value = ', multiLine=True))
self.tr('Formula'), 'value = ', multiline=True)) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
self.addOutput(OutputVector(self.OUTPUT_LAYER, self.tr('Calculated'))) self.tr('Calculated')))


def name(self): def name(self):
return 'advancedpythonfieldcalculator' return 'advancedpythonfieldcalculator'
Expand All @@ -91,33 +88,33 @@ def displayName(self):
return self.tr('Advanced Python field calculator') return self.tr('Advanced Python field calculator')


def processAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
fieldName = self.getParameterValue(self.FIELD_NAME) source = self.parameterAsSource(parameters, self.INPUT, context)
fieldType = self.getParameterValue(self.FIELD_TYPE) field_name = self.parameterAsString(parameters, self.FIELD_NAME, context)
fieldLength = self.getParameterValue(self.FIELD_LENGTH) field_type = self.TYPES[self.parameterAsEnum(parameters, self.FIELD_TYPE, context)]
fieldPrecision = self.getParameterValue(self.FIELD_PRECISION) width = self.parameterAsInt(parameters, self.FIELD_LENGTH, context)
code = self.getParameterValue(self.FORMULA) precision = self.parameterAsInt(parameters, self.FIELD_PRECISION, context)
globalExpression = self.getParameterValue(self.GLOBAL) code = self.parameterAsString(parameters, self.FORMULA, context)
output = self.getOutputFromName(self.OUTPUT_LAYER) globalExpression = self.parameterAsString(parameters, self.GLOBAL, context)


layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context) fields = source.fields()
fields = layer.fields() fields.append(QgsField(field_name, self.TYPES[field_type], '',
fields.append(QgsField(fieldName, self.TYPES[fieldType], '', width, precision))
fieldLength, fieldPrecision))
writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs(), context)
outFeat = QgsFeature()
new_ns = {} new_ns = {}


(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, source.wkbType(), source.sourceCrs())

# Run global code # Run global code
if globalExpression.strip() != '': if globalExpression.strip() != '':
try: try:
bytecode = compile(globalExpression, '<string>', 'exec') bytecode = compile(globalExpression, '<string>', 'exec')
exec(bytecode, new_ns) exec(bytecode, new_ns)
except: except:
raise GeoAlgorithmExecutionException( raise QgsProcessingException(
self.tr("FieldPyculator code execute error.Global code block can't be executed!\n{0}\n{1}").format(str(sys.exc_info()[0].__name__), str(sys.exc_info()[1]))) self.tr("FieldPyculator code execute error.Global code block can't be executed!\n{0}\n{1}").format(str(sys.exc_info()[0].__name__), str(sys.exc_info()[1])))


# Replace all fields tags # Replace all fields tags
fields = layer.fields() fields = source.fields()
num = 0 num = 0
for field in fields: for field in fields:
field_name = str(field.name()) field_name = str(field.name())
Expand All @@ -136,13 +133,17 @@ def processAlgorithm(self, parameters, context, feedback):
try: try:
bytecode = compile(code, '<string>', 'exec') bytecode = compile(code, '<string>', 'exec')
except: except:
raise GeoAlgorithmExecutionException( raise QgsProcessingException(
self.tr("FieldPyculator code execute error. Field code block can't be executed!\n{0}\n{1}").format(str(sys.exc_info()[0].__name__), str(sys.exc_info()[1]))) self.tr("FieldPyculator code execute error. Field code block can't be executed!\n{0}\n{1}").format(str(sys.exc_info()[0].__name__), str(sys.exc_info()[1])))


# Run # Run
features = QgsProcessingUtils.getFeatures(layer, context) features = source.getFeatures()
total = 100.0 / layer.featureCount() if layer.featureCount() else 0 total = 100.0 / source.featureCount() if source.featureCount() else 0

for current, feat in enumerate(features): for current, feat in enumerate(features):
if feedback.isCanceled():
break

feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
attrs = feat.attributes() attrs = feat.attributes()
feat_id = feat.id() feat_id = feat.id()
Expand All @@ -168,18 +169,17 @@ def processAlgorithm(self, parameters, context, feedback):


# Check result # Check result
if self.RESULT_VAR_NAME not in new_ns: if self.RESULT_VAR_NAME not in new_ns:
raise GeoAlgorithmExecutionException( raise QgsProcessingException(
self.tr("FieldPyculator code execute error\n" self.tr("FieldPyculator code execute error\n"
"Field code block does not return '{0}' variable! " "Field code block does not return '{0}' variable! "
"Please declare this variable in your code!").format(self.RESULT_VAR_NAME)) "Please declare this variable in your code!").format(self.RESULT_VAR_NAME))


# Write feature # Write feature
outFeat.setGeometry(feat.geometry())
attrs.append(new_ns[self.RESULT_VAR_NAME]) attrs.append(new_ns[self.RESULT_VAR_NAME])
outFeat.setAttributes(attrs) feat.setAttributes(attrs)
writer.addFeature(outFeat, QgsFeatureSink.FastInsert) sink.addFeature(feat, QgsFeatureSink.FastInsert)


del writer return {self.OUTPUT: dest_id}


def checkParameterValues(self, parameters, context): def checkParameterValues(self, parameters, context):
# TODO check that formula is correct and fields exist # TODO check that formula is correct and fields exist
Expand Down

0 comments on commit 4c52607

Please sign in to comment.