Skip to content

Commit

Permalink
[processing] Fixes for field calculator and field mapper
Browse files Browse the repository at this point in the history
- respect project distance, area and ellipsoid settings
- ensure expression variables are correctly evaluated
  • Loading branch information
nyalldawson committed Feb 28, 2016
1 parent b223593 commit d32c41a
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 8 deletions.
16 changes: 12 additions & 4 deletions python/plugins/processing/algs/qgis/FieldsCalculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
__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
Expand Down Expand Up @@ -111,8 +111,15 @@ def processAlgorithm(self, progress):
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()))

Expand All @@ -129,8 +136,9 @@ def processAlgorithm(self, progress):
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()
Expand Down
27 changes: 23 additions & 4 deletions python/plugins/processing/algs/qgis/FieldsMapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
__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
Expand Down Expand Up @@ -68,19 +69,36 @@ def processAlgorithm(self, progress):
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'],
len=field_def['length'],
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 "{}": {}')
Expand Down Expand Up @@ -108,8 +126,9 @@ def processAlgorithm(self, progress):
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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
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
Expand Down Expand Up @@ -95,6 +96,14 @@ def updateLayer(self):
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):
Expand Down

2 comments on commit d32c41a

@nyalldawson
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexbruy what's the correct way to backport processing fixes to 2.14? just push it to the 2.14 branch?

@alexbruy
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, just puch them to the 2.14 branch and they will be included in the next point release

Please sign in to comment.