Skip to content

Commit

Permalink
Port geometry by expression to new API
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jul 20, 2017
1 parent c0669d4 commit 96cf661
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 127 deletions.
140 changes: 63 additions & 77 deletions python/plugins/processing/algs/qgis/GeometryByExpression.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,17 @@

from qgis.core import (QgsWkbTypes,
QgsExpression,
QgsFeatureSink,
QgsExpressionContext,
QgsExpressionContextUtils,
QgsGeometry,
QgsApplication,
QgsProcessingUtils)
QgsProcessingException,
QgsProcessingParameterBoolean,
QgsProcessingParameterEnum,
QgsProcessingParameterExpression)

from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterVector, ParameterSelection, ParameterBoolean, ParameterExpression
from processing.core.outputs import OutputVector
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm


class GeometryByExpression(QgisAlgorithm):
class GeometryByExpression(QgisFeatureBasedAlgorithm):

INPUT_LAYER = 'INPUT_LAYER'
OUTPUT_LAYER = 'OUTPUT_LAYER'
OUTPUT_GEOMETRY = 'OUTPUT_GEOMETRY'
WITH_Z = 'WITH_Z'
WITH_M = 'WITH_M'
Expand All @@ -54,83 +48,75 @@ def group(self):

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.INPUT_LAYER,
self.tr('Input layer')))

self.geometry_types = [self.tr('Polygon'),
'Line',
'Point']
self.addParameter(ParameterSelection(

def initParameters(self, config=None):
self.addParameter(QgsProcessingParameterEnum(
self.OUTPUT_GEOMETRY,
self.tr('Output geometry type'),
self.geometry_types, default=0))
self.addParameter(ParameterBoolean(self.WITH_Z,
self.tr('Output geometry has z dimension'), False))
self.addParameter(ParameterBoolean(self.WITH_M,
self.tr('Output geometry has m values'), False))
options=self.geometry_types, defaultValue=0))
self.addParameter(QgsProcessingParameterBoolean(self.WITH_Z,
self.tr('Output geometry has z dimension'), defaultValue=False))
self.addParameter(QgsProcessingParameterBoolean(self.WITH_M,
self.tr('Output geometry has m values'), defaultValue=False))

self.addParameter(ParameterExpression(self.EXPRESSION,
self.tr("Geometry expression"), '$geometry', parent_layer=self.INPUT_LAYER))

self.addOutput(OutputVector(self.OUTPUT_LAYER, self.tr('Modified geometry')))
self.addParameter(QgsProcessingParameterExpression(self.EXPRESSION,
self.tr("Geometry expression"), defaultValue='$geometry', parentLayerParameterName='INPUT'))

def name(self):
return 'geometrybyexpression'

def displayName(self):
return self.tr('Geometry by expression')

def processAlgorithm(self, parameters, context, feedback):
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)
def outputName(self):
return self.tr('Modified geometry')

geometry_type = self.getParameterValue(self.OUTPUT_GEOMETRY)
wkb_type = None
if geometry_type == 0:
wkb_type = QgsWkbTypes.Polygon
elif geometry_type == 1:
wkb_type = QgsWkbTypes.LineString
def prepareAlgorithm(self, parameters, context, feedback):
self.geometry_type = self.parameterAsEnum(parameters, self.OUTPUT_GEOMETRY, context)
self.wkb_type = None
if self.geometry_type == 0:
self.wkb_type = QgsWkbTypes.Polygon
elif self.geometry_type == 1:
self.wkb_type = QgsWkbTypes.LineString
else:
self.wkb_type = QgsWkbTypes.Point
if self.parameterAsBool(parameters, self.WITH_Z, context):
self.wkb_type = QgsWkbTypes.addZ(self.wkb_type)
if self.parameterAsBool(parameters, self.WITH_M, context):
self.wkb_type = QgsWkbTypes.addM(self.wkb_type)

self.expression = QgsExpression(self.parameterAsString(parameters, self.EXPRESSION, context))
if self.expression.hasParserError():
feedback.reportError(self.expression.parserErrorString())
return False

self.expression_context = self.createExpressionContext(parameters, context)

if not self.expression.prepare(self.expression_context):
feedback.reportErro(
self.tr('Evaluation error: {0}').format(self.expression.evalErrorString()))
return False

return True

def outputWkbType(self, input_wkb_type):
return self.wkb_type

def processFeature(self, feature, feedback):
self.expression_context.setFeature(feature)
value = self.expression.evaluate(self.expression_context)
if self.expression.hasEvalError():
raise QgsProcessingException(
self.tr('Evaluation error: {0}').format(self.expression.evalErrorString()))

if not value:
feature.setGeometry(QgsGeometry())
else:
wkb_type = QgsWkbTypes.Point
if self.getParameterValue(self.WITH_Z):
wkb_type = QgsWkbTypes.addZ(wkb_type)
if self.getParameterValue(self.WITH_M):
wkb_type = QgsWkbTypes.addM(wkb_type)

writer = self.getOutputFromName(
self.OUTPUT_LAYER).getVectorWriter(layer.fields(), wkb_type, layer.crs(), context)

expression = QgsExpression(self.getParameterValue(self.EXPRESSION))
if expression.hasParserError():
raise GeoAlgorithmExecutionException(expression.parserErrorString())

exp_context = QgsExpressionContext(QgsExpressionContextUtils.globalProjectLayerScopes(layer))

if not expression.prepare(exp_context):
raise GeoAlgorithmExecutionException(
self.tr('Evaluation error: {0}').format(expression.evalErrorString()))

features = QgsProcessingUtils.getFeatures(layer, context)
total = 100.0 / layer.featureCount() if layer.featureCount() else 0
for current, input_feature in enumerate(features):
output_feature = input_feature

exp_context.setFeature(input_feature)
value = expression.evaluate(exp_context)
if expression.hasEvalError():
raise GeoAlgorithmExecutionException(
self.tr('Evaluation error: {0}').format(expression.evalErrorString()))

if not value:
output_feature.setGeometry(QgsGeometry())
else:
if not isinstance(value, QgsGeometry):
raise GeoAlgorithmExecutionException(
self.tr('{} is not a geometry').format(value))
output_feature.setGeometry(value)

writer.addFeature(output_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))

del writer
if not isinstance(value, QgsGeometry):
raise QgsProcessingException(
self.tr('{} is not a geometry').format(value))
feature.setGeometry(value)
return feature
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
from .ExtentFromLayer import ExtentFromLayer
from .ExtractNodes import ExtractNodes
from .FixGeometry import FixGeometry
from .GeometryByExpression import GeometryByExpression
from .GridPolygon import GridPolygon
from .Heatmap import Heatmap
from .Hillshade import Hillshade
Expand Down Expand Up @@ -164,7 +165,6 @@
# from .IdwInterpolation import IdwInterpolation
# from .TinInterpolation import TinInterpolation
# from .ExtractSpecificNodes import ExtractSpecificNodes
# from .GeometryByExpression import GeometryByExpression
# from .RasterCalculator import RasterCalculator
# from .TruncateTable import TruncateTable
# from .Polygonize import Polygonize
Expand Down Expand Up @@ -221,7 +221,6 @@ def getAlgs(self):
# Relief(),
# IdwInterpolation(), TinInterpolation(),
# ExtractSpecificNodes(),
# GeometryByExpression(),
# RasterCalculator(),
# ShortestPathPointToPoint(), ShortestPathPointToLayer(),
# ShortestPathLayerToPoint(), ServiceAreaFromPoint(),
Expand Down Expand Up @@ -250,6 +249,7 @@ def getAlgs(self):
ExtentFromLayer(),
ExtractNodes(),
FixGeometry(),
GeometryByExpression(),
GridPolygon(),
Heatmap(),
Hillshade(),
Expand Down
96 changes: 48 additions & 48 deletions python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1416,54 +1416,54 @@ tests:
# compare:
# fields:
# fid: skip
#
# - algorithm: qgis:geometrybyexpression
# name: Geometry by expression (point)
# params:
# EXPRESSION: 'translate( $geometry,1,1)'
# INPUT_LAYER:
# name: points.gml
# type: vector
# OUTPUT_GEOMETRY: '0'
# WITH_M: false
# WITH_Z: false
# results:
# OUTPUT_LAYER:
# name: expected/geometry_by_expression_point.gml
# type: vector
#
# - algorithm: qgis:geometrybyexpression
# name: Geometry by expression (polygon)
# params:
# EXPRESSION: ' translate( centroid($geometry),1,1)'
# INPUT_LAYER:
# name: polys.gml
# type: vector
# OUTPUT_GEOMETRY: '2'
# WITH_M: false
# WITH_Z: false
# results:
# OUTPUT_LAYER:
# name: expected/geometry_by_expression_poly.gml
# type: vector
# compare:
# geometry:
# precision: 7
#
# - algorithm: qgis:geometrybyexpression
# name: Geometry by expression (line)
# params:
# EXPRESSION: ' translate( $geometry,1,1)'
# INPUT_LAYER:
# name: lines.gml
# type: vector
# OUTPUT_GEOMETRY: '1'
# WITH_M: false
# WITH_Z: false
# results:
# OUTPUT_LAYER:
# name: expected/geometry_by_expression_line.gml
# type: vector

- algorithm: qgis:geometrybyexpression
name: Geometry by expression (point)
params:
EXPRESSION: 'translate( $geometry,1,1)'
INPUT:
name: points.gml
type: vector
OUTPUT_GEOMETRY: '0'
WITH_M: false
WITH_Z: false
results:
OUTPUT:
name: expected/geometry_by_expression_point.gml
type: vector

- algorithm: qgis:geometrybyexpression
name: Geometry by expression (polygon)
params:
EXPRESSION: ' translate( centroid($geometry),1,1)'
INPUT:
name: polys.gml
type: vector
OUTPUT_GEOMETRY: '2'
WITH_M: false
WITH_Z: false
results:
OUTPUT:
name: expected/geometry_by_expression_poly.gml
type: vector
compare:
geometry:
precision: 7

- algorithm: qgis:geometrybyexpression
name: Geometry by expression (line)
params:
EXPRESSION: ' translate( $geometry,1,1)'
INPUT:
name: lines.gml
type: vector
OUTPUT_GEOMETRY: '1'
WITH_M: false
WITH_Z: false
results:
OUTPUT:
name: expected/geometry_by_expression_line.gml
type: vector

- algorithm: qgis:snapgeometries
name: Snap lines to lines
Expand Down

0 comments on commit 96cf661

Please sign in to comment.