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 authored 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
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,12 @@
import os
import re

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

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]

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

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

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

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

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

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

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

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
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,18 @@

__revision__ = '$Format:%H$'

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

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):
Expand All @@ -54,7 +51,7 @@ class ExecuteSQL(QgisAlgorithm):
INPUT_GEOMETRY_FIELD = 'INPUT_GEOMETRY_FIELD'
INPUT_GEOMETRY_TYPE = 'INPUT_GEOMETRY_TYPE'
INPUT_GEOMETRY_CRS = 'INPUT_GEOMETRY_CRS'
OUTPUT_LAYER = 'OUTPUT_LAYER'
OUTPUT = 'OUTPUT'

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

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

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

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

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

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

self.addParameter(ParameterCrs(self.INPUT_GEOMETRY_CRS,
self.tr('CRS'), optional=True))
self.addParameter(QgsProcessingParameterCrs(self.INPUT_GEOMETRY_CRS,
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):
return 'executesql'
Expand All @@ -101,24 +98,19 @@ def displayName(self):
return self.tr('Execute SQL')

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

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

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

vLayer = QgsVectorLayer(df.toString(), "temp_vlayer", "virtual")
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(),
vLayer.wkbType() if geometry_type != 1 else 1,
vLayer.crs(), context)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
vLayer.fields(), vLayer.wkbType() if geometry_type != 1 else 1, vLayer.crs())

features = QgsProcessingUtils.getFeatures(vLayer, context)
features = vLayer.getFeatures()
total = 100.0 / vLayer.featureCount() if vLayer.featureCount() else 0
outFeat = QgsFeature()
for current, inFeat in enumerate(features):
outFeat.setAttributes(inFeat.attributes())
if geometry_type != 1:
outFeat.setGeometry(inFeat.geometry())
writer.addFeature(outFeat, QgsFeatureSink.FastInsert)
if feedback.isCanceled():
break

sink.addFeature(inFeat, QgsFeatureSink.FastInsert)
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
Original file line number Diff line number Diff line change
Expand Up @@ -29,30 +29,27 @@
import sys

from qgis.PyQt.QtCore import QVariant
from qgis.core import (QgsFeature,
from qgis.core import (QgsProcessingException,
QgsField,
QgsFeatureSink,
QgsApplication,
QgsProcessingUtils)
QgsProcessingParameterFeatureSource,
QgsProcessingParameterString,
QgsProcessingParameterEnum,
QgsProcessingParameterNumber,
QgsProcessingParameterFeatureSink)
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):

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

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

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

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

def processAlgorithm(self, parameters, context, feedback):
fieldName = self.getParameterValue(self.FIELD_NAME)
fieldType = self.getParameterValue(self.FIELD_TYPE)
fieldLength = self.getParameterValue(self.FIELD_LENGTH)
fieldPrecision = self.getParameterValue(self.FIELD_PRECISION)
code = self.getParameterValue(self.FORMULA)
globalExpression = self.getParameterValue(self.GLOBAL)
output = self.getOutputFromName(self.OUTPUT_LAYER)

layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)
fields = layer.fields()
fields.append(QgsField(fieldName, self.TYPES[fieldType], '',
fieldLength, fieldPrecision))
writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs(), context)
outFeat = QgsFeature()
source = self.parameterAsSource(parameters, self.INPUT, context)
field_name = self.parameterAsString(parameters, self.FIELD_NAME, context)
field_type = self.TYPES[self.parameterAsEnum(parameters, self.FIELD_TYPE, context)]
width = self.parameterAsInt(parameters, self.FIELD_LENGTH, context)
precision = self.parameterAsInt(parameters, self.FIELD_PRECISION, context)
code = self.parameterAsString(parameters, self.FORMULA, context)
globalExpression = self.parameterAsString(parameters, self.GLOBAL, context)

fields = source.fields()
fields.append(QgsField(field_name, self.TYPES[field_type], '',
width, precision))
new_ns = {}

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

# Run global code
if globalExpression.strip() != '':
try:
bytecode = compile(globalExpression, '<string>', 'exec')
exec(bytecode, new_ns)
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])))

# Replace all fields tags
fields = layer.fields()
fields = source.fields()
num = 0
for field in fields:
field_name = str(field.name())
Expand All @@ -136,13 +133,17 @@ def processAlgorithm(self, parameters, context, feedback):
try:
bytecode = compile(code, '<string>', 'exec')
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])))

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

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

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

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

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

del writer
return {self.OUTPUT: dest_id}

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

0 comments on commit 4c52607

Please sign in to comment.