[processing] Fixes for field calculator and field mapper

- respect project distance, area and ellipsoid settings
- ensure expression variables are correctly evaluated
This commit is contained in:
Nyall Dawson 2016-02-28 12:45:43 +11:00
parent b2235938e6
commit d32c41a60e
3 changed files with 44 additions and 8 deletions

View File

@ -26,7 +26,7 @@ __copyright__ = '(C) 2012, Victor Olaya'
__revision__ = '$Format:%H$'
from PyQt4.QtCore import QVariant
from qgis.core import QgsExpression, QgsFeature, QgsField, QgsDistanceArea, QgsProject, GEO_NONE
from qgis.core import QgsExpression, QgsExpressionContext, QgsExpressionContextUtils, QgsFeature, QgsField, QgsDistanceArea, QgsProject, GEO_NONE
from qgis.utils import iface
from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
@ -111,8 +111,15 @@ class FieldsCalculator(GeoAlgorithm):
da.setEllipsoid(QgsProject.instance().readEntry(
'Measure', '/Ellipsoid', GEO_NONE)[0])
exp.setGeomCalculator(da)
exp.setDistanceUnits(QgsProject.instance().distanceUnits())
exp.setAreaUnits(QgsProject.instance().areaUnits())
if not exp.prepare(layer.pendingFields()):
exp_context = QgsExpressionContext()
exp_context.appendScope(QgsExpressionContextUtils.globalScope())
exp_context.appendScope(QgsExpressionContextUtils.projectScope())
exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer))
if not exp.prepare(exp_context):
raise GeoAlgorithmExecutionException(
self.tr('Evaluation error: %s' % exp.evalErrorString()))
@ -129,8 +136,9 @@ class FieldsCalculator(GeoAlgorithm):
rownum = 1
for current, f in enumerate(features):
rownum = current + 1
exp.setCurrentRowNumber(rownum)
value = exp.evaluate(f)
exp_context.setFeature(f)
exp_context.lastScope().setVariable("row_number", rownum)
value = exp.evaluate(exp_context)
if exp.hasEvalError():
calculationSuccess = False
error = exp.evalErrorString()

View File

@ -26,7 +26,8 @@ __copyright__ = '(C) 2014, Arnaud Morvan'
__revision__ = '$Format:%H$'
from qgis.core import QgsField, QgsExpression, QgsFeature
from qgis.core import QgsField, QgsExpression, QgsExpressionContext, QgsExpressionContextUtils, QgsDistanceArea, QgsProject, QgsFeature, GEO_NONE
from qgis.utils import iface
from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterVector
@ -68,6 +69,19 @@ class FieldsMapper(GeoAlgorithm):
provider = layer.dataProvider()
fields = []
expressions = []
da = QgsDistanceArea()
da.setSourceCrs(layer.crs().srsid())
da.setEllipsoidalMode(
iface.mapCanvas().mapSettings().hasCrsTransformEnabled())
da.setEllipsoid(QgsProject.instance().readEntry(
'Measure', '/Ellipsoid', GEO_NONE)[0])
exp_context = QgsExpressionContext()
exp_context.appendScope(QgsExpressionContextUtils.globalScope())
exp_context.appendScope(QgsExpressionContextUtils.projectScope())
exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer))
for field_def in mapping:
fields.append(QgsField(name=field_def['name'],
type=field_def['type'],
@ -75,12 +89,16 @@ class FieldsMapper(GeoAlgorithm):
prec=field_def['precision']))
expression = QgsExpression(field_def['expression'])
expression.setGeomCalculator(da)
expression.setDistanceUnits(QgsProject.instance().distanceUnits())
expression.setAreaUnits(QgsProject.instance().areaUnits())
if expression.hasParserError():
raise GeoAlgorithmExecutionException(
self.tr(u'Parser error in expression "{}": {}')
.format(unicode(field_def['expression']),
unicode(expression.parserErrorString())))
expression.prepare(provider.fields())
expression.prepare(exp_context)
if expression.hasEvalError():
raise GeoAlgorithmExecutionException(
self.tr(u'Evaluation error in expression "{}": {}')
@ -108,8 +126,9 @@ class FieldsMapper(GeoAlgorithm):
for i in xrange(0, len(mapping)):
field_def = mapping[i]
expression = expressions[i]
expression.setCurrentRowNumber(rownum)
value = expression.evaluate(inFeat)
exp_context.setFeature(inFeat)
exp_context.lastScope().setVariable("row_number", rownum)
value = expression.evaluate(exp_context)
if expression.hasEvalError():
calculationSuccess = False
error = expression.evalErrorString()

View File

@ -31,6 +31,7 @@ import re
from PyQt4 import uic
from PyQt4.QtCore import Qt, QSettings
from PyQt4.QtGui import QDialog, QFileDialog, QApplication, QCursor, QMessageBox
from qgis.core import QgsExpressionContext, QgsExpressionContextUtils
from qgis.gui import QgsEncodingFileDialog
from processing.core.ProcessingConfig import ProcessingConfig
@ -95,6 +96,14 @@ class FieldsCalculatorDialog(BASE, WIDGET):
self.builder.setLayer(self.layer)
self.builder.loadFieldNames()
exp_context = QgsExpressionContext()
exp_context.appendScope(QgsExpressionContextUtils.globalScope())
exp_context.appendScope(QgsExpressionContextUtils.projectScope())
exp_context.appendScope(QgsExpressionContextUtils.layerScope(self.layer))
exp_context.lastScope().setVariable("row_number", 1)
exp_context.setHighlightedVariables(["row_number"])
self.builder.setExpressionContext(exp_context)
self.populateFields()
def setupSpinboxes(self, index):