Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge branch 'master' of https://github.com/gbd-consult/QGIS into fto…
…ols-enhancements

Conflicts:
	python/plugins/fTools/tools/doPointsInPolygon.py
  • Loading branch information
alexbruy committed Apr 2, 2015
2 parents a844bfa + fe37600 commit f0053b8
Show file tree
Hide file tree
Showing 4 changed files with 292 additions and 63 deletions.
123 changes: 115 additions & 8 deletions python/plugins/fTools/tools/doPointsInPolygon.py
Expand Up @@ -28,12 +28,18 @@
#
#---------------------------------------------------------------------

import math

from PyQt4.QtCore import QObject, SIGNAL, QThread, QMutex, QVariant, QFile
from PyQt4.QtGui import QDialog, QDialogButtonBox, QMessageBox
import ftools_utils
from qgis.core import QGis, QgsFeatureRequest, QgsField, QgsVectorFileWriter, QgsFeature, QgsGeometry
import ftools_utils
from ui_frmPointsInPolygon import Ui_Dialog


typeInt = 1
typeDouble = 2

class Dialog(QDialog, Ui_Dialog):

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

QObject.connect(self.toolOut, SIGNAL("clicked()"), self.outFile)
QObject.connect(self.inPoint, SIGNAL("currentIndexChanged(QString)"), self.listPointFields)
QObject.connect(self.inPoint, SIGNAL("activated(QString)"), self.listPointFields)

self.progressBar.setValue(0)
self.populateLayers()

Expand All @@ -57,6 +66,26 @@ def populateLayers( self ):
self.inPoint.clear()
layers = ftools_utils.getLayerNames([QGis.Point])
self.inPoint.addItems(layers)

def listPointFields(self):
if self.inPoint.currentText() == "":
pass

inPnts = ftools_utils.getVectorLayerByName(self.inPoint.currentText())
if inPnts:
pointFieldList = ftools_utils.getFieldList(inPnts)

self.attributeList.clear()
for field in pointFieldList:
if field.type() == QVariant.Int or field.type() ==QVariant.Double:
if field.type() == QVariant.Int:
global typeInt
item = QListWidgetItem(str(field.name()), None, typeInt)
else:
global typeDouble
item = QListWidgetItem(str(field.name()), None, typeDouble)
item.setToolTip("Attribute <%s> of type %s"%(field.name(), field.typeName()))
self.attributeList.addItem(item)

def outFile(self):
self.outShape.clear()
Expand Down Expand Up @@ -90,7 +119,8 @@ def accept(self):

self.btnOk.setEnabled(False)

self.workThread = PointsInPolygonThread(inPoly, inPnts, self.lnField.text(), self.outShape.text(), self.encoding)
self.workThread = PointsInPolygonThread(self, inPoly, inPnts, self.lnField.text(), self.outShape.text(), self.encoding,
self.attributeList, self.statisticSelector)

QObject.connect(self.workThread, SIGNAL("rangeChanged(int)"), self.setProgressRange)
QObject.connect(self.workThread, SIGNAL("updateProgress()"), self.updateProgress)
Expand Down Expand Up @@ -141,7 +171,7 @@ def restoreGui(self):
self.btnOk.setEnabled(True)

class PointsInPolygonThread(QThread):
def __init__( self, inPoly, inPoints, fieldName, outPath, encoding ):
def __init__( self, widget, inPoly, inPoints, fieldName, outPath, encoding, attributeList, statisticSelector):
QThread.__init__( self, QThread.currentThread() )
self.mutex = QMutex()
self.stopMe = 0
Expand All @@ -152,6 +182,9 @@ def __init__( self, inPoly, inPoints, fieldName, outPath, encoding ):
self.fieldName = fieldName
self.outPath = outPath
self.encoding = encoding
self.attributeList = attributeList
self.statistics = statisticSelector.currentText()
self.widget = widget

def run(self):
self.mutex.lock()
Expand All @@ -163,12 +196,24 @@ def run(self):
polyProvider = self.layerPoly.dataProvider()
pointProvider = self.layerPoints.dataProvider()

fieldList = ftools_utils.getFieldList(self.layerPoly)
fieldList = ftools_utils.getFieldList(self.layerPoly)
index = polyProvider.fieldNameIndex(unicode(self.fieldName))
if index == -1:
index = polyProvider.fields().count()
fieldList.append( QgsField(unicode(self.fieldName), QVariant.Int, "int", 10, 0, self.tr("point count field")) )

# Add the selected vector fields to the output polygon vector layer
selectedItems = self.attributeList.selectedItems()
for item in selectedItems:
global typeDouble
columnName = unicode(item.text() + "_" + self.statistics)
index = polyProvider.fieldNameIndex(unicode(columnName))
if index == -1:
if item.type() == typeDouble or self.statistics == "mean" or self.statistics == "stddev":
fieldList.append( QgsField(columnName, QVariant.Double, "double", 24, 15, "Value") )
else:
fieldList.append( QgsField(columnName, QVariant.Int, "int", 10, 0, "Value") )

sRs = polyProvider.crs()
if QFile(self.outPath).exists():
if not QgsVectorFileWriter.deleteShapeFile(self.outPath):
Expand All @@ -189,7 +234,7 @@ def run(self):
while polyFit.nextFeature(polyFeat):
inGeom = polyFeat.geometry()
atMap = polyFeat.attributes()
outFeat.setAttributes(atMap)
outFeat.setAttributes(atMap)
outFeat.setGeometry(inGeom)

count = 0
Expand All @@ -202,23 +247,58 @@ def run(self):
hasIntersection = False

if hasIntersection:
valueList = {}
for item in selectedItems:
valueList[item.text()] = []
for p in pointList:
pointProvider.getFeatures( QgsFeatureRequest().setFilterFid( p ) ).nextFeature( pntFeat )
tmpGeom = QgsGeometry(pntFeat.geometry())
if inGeom.intersects(tmpGeom):
count += 1

for item in selectedItems:
valueList[item.text()].append(pntFeat.attribute(item.text()))

self.mutex.lock()
s = self.stopMe
self.mutex.unlock()
if s == 1:
interrupted = True
break

atMap.append(count)
atMap.append(count)

# Compute the statistical values for selected vector attributes
for item in selectedItems:
values = valueList[item.text()]
# Check if the input contains non-numeric values
non_numeric_values = False
for value in values:
if (isinstance(value, type(float())) != True) and (isinstance(value, type(int())) != True):
non_numeric_values = True
break
# Jump over invalid values
if non_numeric_values is True:
continue

if values and len(values) > 0:
if self.statistics == "sum":
value = reduce(myAdder, values)
elif self.statistics == "mean":
value = reduce(myAdder, values) / float(len(values))
elif self.statistics == "min":
values.sort()
value = values[0]
elif self.statistics == "max":
values.sort()
value = values[-1]
elif self.statistics == "stddev":
value = two_pass_variance(values)
value = math.sqrt(value)
atMap.append(value)

outFeat.setAttributes(atMap)
writer.addFeature(outFeat)

self.emit( SIGNAL( "updateProgress()" ) )

self.mutex.lock()
Expand All @@ -241,3 +321,30 @@ def stop(self):
self.mutex.unlock()

QThread.wait( self )

def myAdder(x,y):
return x+y

def two_pass_variance(data):
"""
Variance algorithm taken from Wikipedia:
https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
"""
n = 0.0
sum1 = 0.0
sum2 = 0.0

for x in data:
n = n + 1.0
sum1 = sum1 + float(x)

if (n < 2):
return 0

mean = sum1 / n

for x in data:
sum2 = sum2 + (x - mean)*(x - mean)

variance = sum2 / (n - 1)
return variance
56 changes: 56 additions & 0 deletions python/plugins/fTools/tools/doVectorGrid.py
Expand Up @@ -156,6 +156,9 @@ def accept(self):
def compute( self, bound, xOffset, yOffset, polygon ):
crs = None
layer = ftools_utils.getMapLayerByName(unicode(self.inShape.currentText()))

if self.angle.value() != 0.0:
bound = self.initRotation(bound)

if layer is None:
crs = self.iface.mapCanvas().mapRenderer().destinationCrs()
Expand Down Expand Up @@ -201,6 +204,11 @@ def compute( self, bound, xOffset, yOffset, polygon ):
while y >= bound.yMinimum():
pt1 = QgsPoint(bound.xMinimum(), y)
pt2 = QgsPoint(bound.xMaximum(), y)

if self.angle.value() != 0.0:
self.rotatePoint(pt1)
self.rotatePoint(pt2)

line = [pt1, pt2]
outFeat.setGeometry(outGeom.fromPolyline(line))
outFeat.setAttribute(0, idVar)
Expand All @@ -221,6 +229,11 @@ def compute( self, bound, xOffset, yOffset, polygon ):
while x <= bound.xMaximum():
pt1 = QgsPoint(x, bound.yMaximum())
pt2 = QgsPoint(x, bound.yMinimum())

if self.angle.value() != 0.0:
self.rotatePoint(pt1)
self.rotatePoint(pt2)

line = [pt1, pt2]
outFeat.setGeometry(outGeom.fromPolyline(line))
outFeat.setAttribute(0, idVar)
Expand All @@ -241,11 +254,20 @@ def compute( self, bound, xOffset, yOffset, polygon ):
while y >= bound.yMinimum():
x = bound.xMinimum()
while x <= bound.xMaximum():

pt1 = QgsPoint(x, y)
pt2 = QgsPoint(x + xOffset, y)
pt3 = QgsPoint(x + xOffset, y - yOffset)
pt4 = QgsPoint(x, y - yOffset)
pt5 = QgsPoint(x, y)

if self.angle.value() != 0.0:
self.rotatePoint(pt1)
self.rotatePoint(pt2)
self.rotatePoint(pt3)
self.rotatePoint(pt4)
self.rotatePoint(pt5)

polygon = [[pt1, pt2, pt3, pt4, pt5]]
outFeat.setGeometry(outGeom.fromPolygon(polygon))
outFeat.setAttribute(0, idVar)
Expand All @@ -264,6 +286,40 @@ def compute( self, bound, xOffset, yOffset, polygon ):
self.progressBar.setValue( 100 )
del writer

def initRotation(self, boundBox):
# calculate rotation parameters..interpreted from affine transformation plugin

anchorPoint = boundBox.center()
# We convert the angle from degree to radiant
rad = self.angle.value() * math.pi / 180.0

a = math.cos( rad );
b = -1 * math.sin( rad );
c = anchorPoint.x() - math.cos( rad ) * anchorPoint.x() + math.sin( rad ) * anchorPoint.y();
d = math.sin( rad );
e = math.cos( rad );
f = anchorPoint.y() - math.sin( rad ) * anchorPoint.x() - math.cos( rad ) * anchorPoint.y();

self.rotationParams = (a,b,c,d,e,f)

# Rotate the bounding box to set a new extent
ptMin = QgsPoint(boundBox.xMinimum(), boundBox.yMinimum())
ptMax = QgsPoint(boundBox.xMaximum(), boundBox.yMaximum())

self.rotatePoint(ptMin)
self.rotatePoint(ptMax)

newBoundBox = QgsRectangle(ptMin, ptMax)
newBoundBox.combineExtentWith(boundBox)

return newBoundBox

def rotatePoint(self, point):
x = self.rotationParams[0] * point.x() + self.rotationParams[1] * point.y() + self.rotationParams[2];
y = self.rotationParams[3] * point.x() + self.rotationParams[4] * point.y() + self.rotationParams[5];
point.setX(x)
point.setY(y)

def outFile(self):
self.outShape.clear()
( self.shapefileName, self.encoding ) = ftools_utils.saveDialog( self )
Expand Down

0 comments on commit f0053b8

Please sign in to comment.