28
28
#
29
29
#---------------------------------------------------------------------
30
30
31
+ import math
32
+
31
33
from PyQt4 .QtCore import QObject , SIGNAL , QThread , QMutex , QVariant , QFile
32
34
from PyQt4 .QtGui import QDialog , QDialogButtonBox , QMessageBox
33
- import ftools_utils
34
35
from qgis .core import QGis , QgsFeatureRequest , QgsField , QgsVectorFileWriter , QgsFeature , QgsGeometry
36
+ import ftools_utils
35
37
from ui_frmPointsInPolygon import Ui_Dialog
36
38
39
+
40
+ typeInt = 1
41
+ typeDouble = 2
42
+
37
43
class Dialog (QDialog , Ui_Dialog ):
38
44
39
45
def __init__ (self , iface ):
@@ -46,6 +52,9 @@ def __init__(self, iface):
46
52
self .btnClose = self .buttonBox .button ( QDialogButtonBox .Close )
47
53
48
54
QObject .connect (self .toolOut , SIGNAL ("clicked()" ), self .outFile )
55
+ QObject .connect (self .inPoint , SIGNAL ("currentIndexChanged(QString)" ), self .listPointFields )
56
+ QObject .connect (self .inPoint , SIGNAL ("activated(QString)" ), self .listPointFields )
57
+
49
58
self .progressBar .setValue (0 )
50
59
self .populateLayers ()
51
60
@@ -57,6 +66,26 @@ def populateLayers( self ):
57
66
self .inPoint .clear ()
58
67
layers = ftools_utils .getLayerNames ([QGis .Point ])
59
68
self .inPoint .addItems (layers )
69
+
70
+ def listPointFields (self ):
71
+ if self .inPoint .currentText () == "" :
72
+ pass
73
+
74
+ inPnts = ftools_utils .getVectorLayerByName (self .inPoint .currentText ())
75
+ if inPnts :
76
+ pointFieldList = ftools_utils .getFieldList (inPnts )
77
+
78
+ self .attributeList .clear ()
79
+ for field in pointFieldList :
80
+ if field .type () == QVariant .Int or field .type () == QVariant .Double :
81
+ if field .type () == QVariant .Int :
82
+ global typeInt
83
+ item = QListWidgetItem (str (field .name ()), None , typeInt )
84
+ else :
85
+ global typeDouble
86
+ item = QListWidgetItem (str (field .name ()), None , typeDouble )
87
+ item .setToolTip ("Attribute <%s> of type %s" % (field .name (), field .typeName ()))
88
+ self .attributeList .addItem (item )
60
89
61
90
def outFile (self ):
62
91
self .outShape .clear ()
@@ -90,7 +119,8 @@ def accept(self):
90
119
91
120
self .btnOk .setEnabled (False )
92
121
93
- self .workThread = PointsInPolygonThread (inPoly , inPnts , self .lnField .text (), self .outShape .text (), self .encoding )
122
+ self .workThread = PointsInPolygonThread (self , inPoly , inPnts , self .lnField .text (), self .outShape .text (), self .encoding ,
123
+ self .attributeList , self .statisticSelector )
94
124
95
125
QObject .connect (self .workThread , SIGNAL ("rangeChanged(int)" ), self .setProgressRange )
96
126
QObject .connect (self .workThread , SIGNAL ("updateProgress()" ), self .updateProgress )
@@ -141,7 +171,7 @@ def restoreGui(self):
141
171
self .btnOk .setEnabled (True )
142
172
143
173
class PointsInPolygonThread (QThread ):
144
- def __init__ ( self , inPoly , inPoints , fieldName , outPath , encoding ):
174
+ def __init__ ( self , widget , inPoly , inPoints , fieldName , outPath , encoding , attributeList , statisticSelector ):
145
175
QThread .__init__ ( self , QThread .currentThread () )
146
176
self .mutex = QMutex ()
147
177
self .stopMe = 0
@@ -152,6 +182,9 @@ def __init__( self, inPoly, inPoints, fieldName, outPath, encoding ):
152
182
self .fieldName = fieldName
153
183
self .outPath = outPath
154
184
self .encoding = encoding
185
+ self .attributeList = attributeList
186
+ self .statistics = statisticSelector .currentText ()
187
+ self .widget = widget
155
188
156
189
def run (self ):
157
190
self .mutex .lock ()
@@ -163,12 +196,24 @@ def run(self):
163
196
polyProvider = self .layerPoly .dataProvider ()
164
197
pointProvider = self .layerPoints .dataProvider ()
165
198
166
- fieldList = ftools_utils .getFieldList (self .layerPoly )
199
+ fieldList = ftools_utils .getFieldList (self .layerPoly )
167
200
index = polyProvider .fieldNameIndex (unicode (self .fieldName ))
168
201
if index == - 1 :
169
202
index = polyProvider .fields ().count ()
170
203
fieldList .append ( QgsField (unicode (self .fieldName ), QVariant .Int , "int" , 10 , 0 , self .tr ("point count field" )) )
171
204
205
+ # Add the selected vector fields to the output polygon vector layer
206
+ selectedItems = self .attributeList .selectedItems ()
207
+ for item in selectedItems :
208
+ global typeDouble
209
+ columnName = unicode (item .text () + "_" + self .statistics )
210
+ index = polyProvider .fieldNameIndex (unicode (columnName ))
211
+ if index == - 1 :
212
+ if item .type () == typeDouble or self .statistics == "mean" or self .statistics == "stddev" :
213
+ fieldList .append ( QgsField (columnName , QVariant .Double , "double" , 24 , 15 , "Value" ) )
214
+ else :
215
+ fieldList .append ( QgsField (columnName , QVariant .Int , "int" , 10 , 0 , "Value" ) )
216
+
172
217
sRs = polyProvider .crs ()
173
218
if QFile (self .outPath ).exists ():
174
219
if not QgsVectorFileWriter .deleteShapeFile (self .outPath ):
@@ -189,7 +234,7 @@ def run(self):
189
234
while polyFit .nextFeature (polyFeat ):
190
235
inGeom = polyFeat .geometry ()
191
236
atMap = polyFeat .attributes ()
192
- outFeat .setAttributes (atMap )
237
+ outFeat .setAttributes (atMap )
193
238
outFeat .setGeometry (inGeom )
194
239
195
240
count = 0
@@ -202,23 +247,58 @@ def run(self):
202
247
hasIntersection = False
203
248
204
249
if hasIntersection :
250
+ valueList = {}
251
+ for item in selectedItems :
252
+ valueList [item .text ()] = []
205
253
for p in pointList :
206
254
pointProvider .getFeatures ( QgsFeatureRequest ().setFilterFid ( p ) ).nextFeature ( pntFeat )
207
255
tmpGeom = QgsGeometry (pntFeat .geometry ())
208
256
if inGeom .intersects (tmpGeom ):
209
257
count += 1
210
-
258
+ for item in selectedItems :
259
+ valueList [item .text ()].append (pntFeat .attribute (item .text ()))
260
+
211
261
self .mutex .lock ()
212
262
s = self .stopMe
213
263
self .mutex .unlock ()
214
264
if s == 1 :
215
265
interrupted = True
216
266
break
217
267
218
- atMap .append (count )
268
+ atMap .append (count )
269
+
270
+ # Compute the statistical values for selected vector attributes
271
+ for item in selectedItems :
272
+ values = valueList [item .text ()]
273
+ # Check if the input contains non-numeric values
274
+ non_numeric_values = False
275
+ for value in values :
276
+ if (isinstance (value , type (float ())) != True ) and (isinstance (value , type (int ())) != True ):
277
+ non_numeric_values = True
278
+ break
279
+ # Jump over invalid values
280
+ if non_numeric_values is True :
281
+ continue
282
+
283
+ if values and len (values ) > 0 :
284
+ if self .statistics == "sum" :
285
+ value = reduce (myAdder , values )
286
+ elif self .statistics == "mean" :
287
+ value = reduce (myAdder , values ) / float (len (values ))
288
+ elif self .statistics == "min" :
289
+ values .sort ()
290
+ value = values [0 ]
291
+ elif self .statistics == "max" :
292
+ values .sort ()
293
+ value = values [- 1 ]
294
+ elif self .statistics == "stddev" :
295
+ value = two_pass_variance (values )
296
+ value = math .sqrt (value )
297
+ atMap .append (value )
298
+
219
299
outFeat .setAttributes (atMap )
220
300
writer .addFeature (outFeat )
221
-
301
+
222
302
self .emit ( SIGNAL ( "updateProgress()" ) )
223
303
224
304
self .mutex .lock ()
@@ -241,3 +321,30 @@ def stop(self):
241
321
self .mutex .unlock ()
242
322
243
323
QThread .wait ( self )
324
+
325
+ def myAdder (x ,y ):
326
+ return x + y
327
+
328
+ def two_pass_variance (data ):
329
+ """
330
+ Variance algorithm taken from Wikipedia:
331
+ https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
332
+ """
333
+ n = 0.0
334
+ sum1 = 0.0
335
+ sum2 = 0.0
336
+
337
+ for x in data :
338
+ n = n + 1.0
339
+ sum1 = sum1 + float (x )
340
+
341
+ if (n < 2 ):
342
+ return 0
343
+
344
+ mean = sum1 / n
345
+
346
+ for x in data :
347
+ sum2 = sum2 + (x - mean )* (x - mean )
348
+
349
+ variance = sum2 / (n - 1 )
350
+ return variance
0 commit comments