Skip to content

Commit ed4fe88

Browse files
committed
Merge branch 'ftools-enhancements'
2 parents a844bfa + 9b83b53 commit ed4fe88

File tree

4 files changed

+288
-60
lines changed

4 files changed

+288
-60
lines changed

python/plugins/fTools/tools/doPointsInPolygon.py

+111-5
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,18 @@
2828
#
2929
#---------------------------------------------------------------------
3030

31+
import math
32+
3133
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
3435
from qgis.core import QGis, QgsFeatureRequest, QgsField, QgsVectorFileWriter, QgsFeature, QgsGeometry
36+
import ftools_utils
3537
from ui_frmPointsInPolygon import Ui_Dialog
3638

39+
40+
typeInt = 1
41+
typeDouble = 2
42+
3743
class Dialog(QDialog, Ui_Dialog):
3844

3945
def __init__(self, iface):
@@ -46,6 +52,9 @@ def __init__(self, iface):
4652
self.btnClose = self.buttonBox.button( QDialogButtonBox.Close )
4753

4854
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+
4958
self.progressBar.setValue(0)
5059
self.populateLayers()
5160

@@ -58,6 +67,26 @@ def populateLayers( self ):
5867
layers = ftools_utils.getLayerNames([QGis.Point])
5968
self.inPoint.addItems(layers)
6069

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+
6190
def outFile(self):
6291
self.outShape.clear()
6392
(self.shapefileName, self.encoding) = ftools_utils.saveDialog(self)
@@ -90,7 +119,8 @@ def accept(self):
90119

91120
self.btnOk.setEnabled(False)
92121

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)
94124

95125
QObject.connect(self.workThread, SIGNAL("rangeChanged(int)"), self.setProgressRange)
96126
QObject.connect(self.workThread, SIGNAL("updateProgress()"), self.updateProgress)
@@ -141,7 +171,7 @@ def restoreGui(self):
141171
self.btnOk.setEnabled(True)
142172

143173
class PointsInPolygonThread(QThread):
144-
def __init__( self, inPoly, inPoints, fieldName, outPath, encoding ):
174+
def __init__( self, inPoly, inPoints, fieldName, outPath, encoding, attributeList, statisticSelector):
145175
QThread.__init__( self, QThread.currentThread() )
146176
self.mutex = QMutex()
147177
self.stopMe = 0
@@ -152,6 +182,8 @@ def __init__( self, inPoly, inPoints, fieldName, outPath, encoding ):
152182
self.fieldName = fieldName
153183
self.outPath = outPath
154184
self.encoding = encoding
185+
self.attributeList = attributeList
186+
self.statistics = statisticSelector.currentText()
155187

156188
def run(self):
157189
self.mutex.lock()
@@ -169,6 +201,18 @@ def run(self):
169201
index = polyProvider.fields().count()
170202
fieldList.append( QgsField(unicode(self.fieldName), QVariant.Int, "int", 10, 0, self.tr("point count field")) )
171203

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+
172216
sRs = polyProvider.crs()
173217
if QFile(self.outPath).exists():
174218
if not QgsVectorFileWriter.deleteShapeFile(self.outPath):
@@ -202,11 +246,16 @@ def run(self):
202246
hasIntersection = False
203247

204248
if hasIntersection:
249+
valueList = {}
250+
for item in selectedItems:
251+
valueList[item.text()] = []
205252
for p in pointList:
206253
pointProvider.getFeatures( QgsFeatureRequest().setFilterFid( p ) ).nextFeature( pntFeat )
207254
tmpGeom = QgsGeometry(pntFeat.geometry())
208255
if inGeom.intersects(tmpGeom):
209256
count += 1
257+
for item in selectedItems:
258+
valueList[item.text()].append(pntFeat.attribute(item.text()))
210259

211260
self.mutex.lock()
212261
s = self.stopMe
@@ -215,7 +264,37 @@ def run(self):
215264
interrupted = True
216265
break
217266

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+
219298
outFeat.setAttributes(atMap)
220299
writer.addFeature(outFeat)
221300

@@ -241,3 +320,30 @@ def stop(self):
241320
self.mutex.unlock()
242321

243322
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

python/plugins/fTools/tools/doVectorGrid.py

+56
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ def accept(self):
156156
def compute( self, bound, xOffset, yOffset, polygon ):
157157
crs = None
158158
layer = ftools_utils.getMapLayerByName(unicode(self.inShape.currentText()))
159+
160+
if self.angle.value() != 0.0:
161+
bound = self.initRotation(bound)
159162

160163
if layer is None:
161164
crs = self.iface.mapCanvas().mapRenderer().destinationCrs()
@@ -201,6 +204,11 @@ def compute( self, bound, xOffset, yOffset, polygon ):
201204
while y >= bound.yMinimum():
202205
pt1 = QgsPoint(bound.xMinimum(), y)
203206
pt2 = QgsPoint(bound.xMaximum(), y)
207+
208+
if self.angle.value() != 0.0:
209+
self.rotatePoint(pt1)
210+
self.rotatePoint(pt2)
211+
204212
line = [pt1, pt2]
205213
outFeat.setGeometry(outGeom.fromPolyline(line))
206214
outFeat.setAttribute(0, idVar)
@@ -221,6 +229,11 @@ def compute( self, bound, xOffset, yOffset, polygon ):
221229
while x <= bound.xMaximum():
222230
pt1 = QgsPoint(x, bound.yMaximum())
223231
pt2 = QgsPoint(x, bound.yMinimum())
232+
233+
if self.angle.value() != 0.0:
234+
self.rotatePoint(pt1)
235+
self.rotatePoint(pt2)
236+
224237
line = [pt1, pt2]
225238
outFeat.setGeometry(outGeom.fromPolyline(line))
226239
outFeat.setAttribute(0, idVar)
@@ -241,11 +254,20 @@ def compute( self, bound, xOffset, yOffset, polygon ):
241254
while y >= bound.yMinimum():
242255
x = bound.xMinimum()
243256
while x <= bound.xMaximum():
257+
244258
pt1 = QgsPoint(x, y)
245259
pt2 = QgsPoint(x + xOffset, y)
246260
pt3 = QgsPoint(x + xOffset, y - yOffset)
247261
pt4 = QgsPoint(x, y - yOffset)
248262
pt5 = QgsPoint(x, y)
263+
264+
if self.angle.value() != 0.0:
265+
self.rotatePoint(pt1)
266+
self.rotatePoint(pt2)
267+
self.rotatePoint(pt3)
268+
self.rotatePoint(pt4)
269+
self.rotatePoint(pt5)
270+
249271
polygon = [[pt1, pt2, pt3, pt4, pt5]]
250272
outFeat.setGeometry(outGeom.fromPolygon(polygon))
251273
outFeat.setAttribute(0, idVar)
@@ -264,6 +286,40 @@ def compute( self, bound, xOffset, yOffset, polygon ):
264286
self.progressBar.setValue( 100 )
265287
del writer
266288

289+
def initRotation(self, boundBox):
290+
# calculate rotation parameters..interpreted from affine transformation plugin
291+
292+
anchorPoint = boundBox.center()
293+
# We convert the angle from degree to radiant
294+
rad = self.angle.value() * math.pi / 180.0
295+
296+
a = math.cos( rad );
297+
b = -1 * math.sin( rad );
298+
c = anchorPoint.x() - math.cos( rad ) * anchorPoint.x() + math.sin( rad ) * anchorPoint.y();
299+
d = math.sin( rad );
300+
e = math.cos( rad );
301+
f = anchorPoint.y() - math.sin( rad ) * anchorPoint.x() - math.cos( rad ) * anchorPoint.y();
302+
303+
self.rotationParams = (a,b,c,d,e,f)
304+
305+
# Rotate the bounding box to set a new extent
306+
ptMin = QgsPoint(boundBox.xMinimum(), boundBox.yMinimum())
307+
ptMax = QgsPoint(boundBox.xMaximum(), boundBox.yMaximum())
308+
309+
self.rotatePoint(ptMin)
310+
self.rotatePoint(ptMax)
311+
312+
newBoundBox = QgsRectangle(ptMin, ptMax)
313+
newBoundBox.combineExtentWith(boundBox)
314+
315+
return newBoundBox
316+
317+
def rotatePoint(self, point):
318+
x = self.rotationParams[0] * point.x() + self.rotationParams[1] * point.y() + self.rotationParams[2];
319+
y = self.rotationParams[3] * point.x() + self.rotationParams[4] * point.y() + self.rotationParams[5];
320+
point.setX(x)
321+
point.setY(y)
322+
267323
def outFile(self):
268324
self.outShape.clear()
269325
( self.shapefileName, self.encoding ) = ftools_utils.saveDialog( self )

0 commit comments

Comments
 (0)