28
28
#
29
29
#---------------------------------------------------------------------
30
30
31
+ import math
32
+
31
33
from PyQt4 .QtCore import QObject , SIGNAL , QThread , QMutex , QVariant , QFile
32
- from PyQt4 .QtGui import QDialog , QDialogButtonBox , QMessageBox
33
- import ftools_utils
34
+ from PyQt4 .QtGui import QDialog , QDialogButtonBox , QMessageBox , QListWidgetItem
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
@@ -58,6 +67,26 @@ def populateLayers( self ):
58
67
layers = ftools_utils .getLayerNames ([QGis .Point ])
59
68
self .inPoint .addItems (layers )
60
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 )
89
+
61
90
def outFile (self ):
62
91
self .outShape .clear ()
63
92
(self .shapefileName , self .encoding ) = ftools_utils .saveDialog (self )
@@ -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 (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 , 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,8 @@ 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 ()
155
187
156
188
def run (self ):
157
189
self .mutex .lock ()
@@ -169,6 +201,18 @@ def run(self):
169
201
index = polyProvider .fields ().count ()
170
202
fieldList .append ( QgsField (unicode (self .fieldName ), QVariant .Int , "int" , 10 , 0 , self .tr ("point count field" )) )
171
203
204
+ # Add the selected vector fields to the output polygon vector layer
205
+ selectedItems = self .attributeList .selectedItems ()
206
+ for item in selectedItems :
207
+ global typeDouble
208
+ columnName = unicode (item .text () + "_" + self .statistics )
209
+ index = polyProvider .fieldNameIndex (unicode (columnName ))
210
+ if index == - 1 :
211
+ if item .type () == typeDouble or self .statistics == "mean" or self .statistics == "stddev" :
212
+ fieldList .append ( QgsField (columnName , QVariant .Double , "double" , 24 , 15 , "Value" ) )
213
+ else :
214
+ fieldList .append ( QgsField (columnName , QVariant .Int , "int" , 10 , 0 , "Value" ) )
215
+
172
216
sRs = polyProvider .crs ()
173
217
if QFile (self .outPath ).exists ():
174
218
if not QgsVectorFileWriter .deleteShapeFile (self .outPath ):
@@ -202,11 +246,16 @@ def run(self):
202
246
hasIntersection = False
203
247
204
248
if hasIntersection :
249
+ valueList = {}
250
+ for item in selectedItems :
251
+ valueList [item .text ()] = []
205
252
for p in pointList :
206
253
pointProvider .getFeatures ( QgsFeatureRequest ().setFilterFid ( p ) ).nextFeature ( pntFeat )
207
254
tmpGeom = QgsGeometry (pntFeat .geometry ())
208
255
if inGeom .intersects (tmpGeom ):
209
256
count += 1
257
+ for item in selectedItems :
258
+ valueList [item .text ()].append (pntFeat .attribute (item .text ()))
210
259
211
260
self .mutex .lock ()
212
261
s = self .stopMe
@@ -215,7 +264,37 @@ def run(self):
215
264
interrupted = True
216
265
break
217
266
218
- atMap .append (count )
267
+ atMap .append (count )
268
+
269
+ # Compute the statistical values for selected vector attributes
270
+ for item in selectedItems :
271
+ values = valueList [item .text ()]
272
+ # Check if the input contains non-numeric values
273
+ non_numeric_values = False
274
+ for value in values :
275
+ if (isinstance (value , type (float ())) != True ) and (isinstance (value , type (int ())) != True ):
276
+ non_numeric_values = True
277
+ break
278
+ # Jump over invalid values
279
+ if non_numeric_values is True :
280
+ continue
281
+
282
+ if values and len (values ) > 0 :
283
+ if self .statistics == "sum" :
284
+ value = reduce (myAdder , values )
285
+ elif self .statistics == "mean" :
286
+ value = reduce (myAdder , values ) / float (len (values ))
287
+ elif self .statistics == "min" :
288
+ values .sort ()
289
+ value = values [0 ]
290
+ elif self .statistics == "max" :
291
+ values .sort ()
292
+ value = values [- 1 ]
293
+ elif self .statistics == "stddev" :
294
+ value = two_pass_variance (values )
295
+ value = math .sqrt (value )
296
+ atMap .append (value )
297
+
219
298
outFeat .setAttributes (atMap )
220
299
writer .addFeature (outFeat )
221
300
@@ -241,3 +320,30 @@ def stop(self):
241
320
self .mutex .unlock ()
242
321
243
322
QThread .wait ( self )
323
+
324
+ def myAdder (x ,y ):
325
+ return x + y
326
+
327
+ def two_pass_variance (data ):
328
+ """
329
+ Variance algorithm taken from Wikipedia:
330
+ https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
331
+ """
332
+ n = 0.0
333
+ sum1 = 0.0
334
+ sum2 = 0.0
335
+
336
+ for x in data :
337
+ n = n + 1.0
338
+ sum1 = sum1 + float (x )
339
+
340
+ if (n < 2 ):
341
+ return 0
342
+
343
+ mean = sum1 / n
344
+
345
+ for x in data :
346
+ sum2 = sum2 + (x - mean )* (x - mean )
347
+
348
+ variance = sum2 / (n - 1 )
349
+ return variance
0 commit comments