27
27
28
28
from PyQt4 .QtCore import *
29
29
from qgis .core import *
30
+ from processing import interface
30
31
from processing .core .GeoAlgorithm import GeoAlgorithm
32
+ from processing .core .GeoAlgorithmExecutionException import \
33
+ GeoAlgorithmExecutionException
31
34
from processing .parameters .ParameterVector import ParameterVector
32
35
from processing .parameters .ParameterString import ParameterString
33
36
from processing .parameters .ParameterNumber import ParameterNumber
37
+ from processing .parameters .ParameterBoolean import ParameterBoolean
34
38
from processing .parameters .ParameterSelection import ParameterSelection
35
39
from processing .outputs .OutputVector import OutputVector
36
40
from processing .tools import dataobjects , vector
37
41
42
+ from processing .algs .ui .FieldsCalculatorDialog import FieldsCalculatorDialog
38
43
39
44
class FieldsCalculator (GeoAlgorithm ):
40
45
41
46
INPUT_LAYER = 'INPUT_LAYER'
47
+ NEW_FIELD = 'NEW_FIELD'
42
48
FIELD_NAME = 'FIELD_NAME'
43
49
FIELD_TYPE = 'FIELD_TYPE'
44
50
FIELD_LENGTH = 'FIELD_LENGTH'
45
51
FIELD_PRECISION = 'FIELD_PRECISION'
46
52
FORMULA = 'FORMULA'
47
53
OUTPUT_LAYER = 'OUTPUT_LAYER'
48
54
49
- TYPE_NAMES = ['Float' , 'Integer' , 'String' ]
50
- TYPES = [QVariant .Double , QVariant .Int , QVariant .String ]
55
+ TYPE_NAMES = ['Float' , 'Integer' , 'String' , 'Date' ]
56
+ TYPES = [QVariant .Double , QVariant .Int , QVariant .String , QVariant . Date ]
51
57
52
58
def defineCharacteristics (self ):
53
59
self .name = 'Field calculator'
@@ -61,58 +67,95 @@ def defineCharacteristics(self):
61
67
self .addParameter (ParameterNumber (self .FIELD_LENGTH , 'Field length' ,
62
68
1 , 255 , 10 ))
63
69
self .addParameter (ParameterNumber (self .FIELD_PRECISION ,
64
- 'Field precision' , 0 , 10 , 5 ))
70
+ 'Field precision' , 0 , 15 , 3 ))
71
+ self .addParameter (ParameterBoolean (self .NEW_FIELD ,
72
+ 'Create new field' , True ))
65
73
self .addParameter (ParameterString (self .FORMULA , 'Formula' ))
66
74
self .addOutput (OutputVector (self .OUTPUT_LAYER , 'Output layer' ))
67
75
68
76
def processAlgorithm (self , progress ):
77
+ layer = dataobjects .getObjectFromUri (
78
+ self .getParameterValue (self .INPUT_LAYER ))
69
79
fieldName = self .getParameterValue (self .FIELD_NAME )
70
- fieldType = self .getParameterValue (self .FIELD_TYPE )
71
- fieldLength = self .getParameterValue (self .FIELD_LENGTH )
72
- fieldPrecision = self .getParameterValue (self .FIELD_PRECISION )
80
+ fieldType = self .TYPES [self .getParameterValue (self .FIELD_TYPE )]
81
+ width = self .getParameterValue (self .FIELD_LENGTH )
82
+ precision = self .getParameterValue (self .FIELD_PRECISION )
83
+ newField = self .getParameterValue (self .NEW_FIELD )
73
84
formula = self .getParameterValue (self .FORMULA )
85
+
74
86
output = self .getOutputFromName (self .OUTPUT_LAYER )
75
87
76
- layer = dataobjects .getObjectFromUri (
77
- self .getParameterValue (self .INPUT_LAYER ))
78
88
provider = layer .dataProvider ()
79
- fields = provider .fields ()
80
- fields .append (QgsField (fieldName , self .TYPES [fieldType ], '' ,
81
- fieldLength , fieldPrecision ))
89
+ fields = layer .pendingFields ()
90
+ if newField :
91
+ fields .append (QgsField (fieldName , fieldType , '' , width , precision ))
92
+
82
93
writer = output .getVectorWriter (fields , provider .geometryType (),
83
- layer .crs ())
94
+ layer .crs ())
95
+
96
+ exp = QgsExpression (formula )
97
+
98
+ da = QgsDistanceArea ()
99
+ da .setSourceCrs (layer .crs ().srsid ())
100
+ canvas = interface .iface .mapCanvas ()
101
+ da .setEllipsoidalMode (canvas .mapRenderer ().hasCrsTransformEnabled ())
102
+ da .setEllipsoid (QgsProject .instance ().readEntry ('Measure' ,
103
+ '/Ellipsoid' ,
104
+ GEO_NONE )[0 ])
105
+ exp .setGeomCalculator (da )
106
+
107
+ if not exp .prepare (layer .pendingFields ()):
108
+ raise GeoAlgorithmExecutionException (
109
+ 'Evaluation error: ' + exp .evalErrorString ())
84
110
85
- outFeat = QgsFeature ()
86
- inGeom = QgsGeometry ()
87
- nFeat = provider .featureCount ()
88
- nElement = 0
111
+ outFeature = QgsFeature ()
112
+ outFeature .initAttributes (len (fields ))
113
+ outFeature .setFields (fields )
114
+
115
+ error = ''
116
+ calculationSuccess = True
117
+
118
+ current = 0
89
119
features = vector .features (layer )
120
+ total = 100.0 / len (features )
121
+
122
+ rownum = 1
123
+ for f in features :
124
+ exp .setCurrentRowNumber (rownum )
125
+ value = exp .evaluate (f )
126
+ if exp .hasEvalError ():
127
+ calculationSuccess = False
128
+ error = exp .evalErrorString ()
129
+ break
130
+ else :
131
+ outFeature .setGeometry (f .geometry ())
132
+ for fld in f .fields ():
133
+ outFeature [fld .name ()] = f [fld .name ()]
134
+ outFeature [fieldName ] = value
135
+ writer .addFeature (outFeature )
90
136
91
- fieldnames = [field .name () for field in provider .fields ()]
92
- fieldnames .sort (key = len , reverse = False )
93
- fieldidx = [fieldnames .index (field .name ()) for field in
94
- provider .fields ()]
95
- print fieldidx
96
- for inFeat in features :
97
- progress .setPercentage (int (100 * nElement / nFeat ))
98
- attrs = inFeat .attributes ()
99
- expression = formula
100
- for idx in fieldidx :
101
- expression = expression .replace (unicode (fields [idx ].name ()),
102
- unicode (attrs [idx ]))
103
- try :
104
- result = eval (expression )
105
- except Exception :
106
- result = None
107
- nElement += 1
108
- inGeom = inFeat .geometry ()
109
- outFeat .setGeometry (inGeom )
110
- attrs = inFeat .attributes ()
111
- attrs .append (result )
112
- outFeat .setAttributes (attrs )
113
- writer .addFeature (outFeat )
137
+ current += 1
138
+ progress .setPercentage (int (current * total ))
114
139
del writer
115
140
141
+ if not calculationSuccess :
142
+ raise GeoAlgorithmExecutionException (
143
+ 'An error occured while evaluating the calculation '
144
+ 'string:\n ' + error )
145
+
146
+
116
147
def checkParameterValuesBeforeExecuting (self ):
117
- # TODO check that formula is correct and fields exist
118
- pass
148
+ newField = self .getParameterValue (self .NEW_FIELD )
149
+ fieldName = self .getParameterValue (self .FIELD_NAME )
150
+ if newField and len (fieldName ) == 0 :
151
+ raise GeoAlgorithmExecutionException ('Field name is not set. '
152
+ 'Please enter a field name' )
153
+
154
+ outputName = self .getOutputValue (self .OUTPUT_LAYER )
155
+ if outputName == '' :
156
+ raise GeoAlgorithmExecutionException ('Output is not set. '
157
+ 'Please specify valid filename' )
158
+
159
+
160
+ def getCustomParametersDialog (self ):
161
+ return FieldsCalculatorDialog (self )
0 commit comments