QGIS/python/plugins/fTools/tools/doMeanCoords.py
2015-08-22 14:29:41 +02:00

211 lines
8.7 KiB
Python

# -*- coding: utf-8 -*-
#-----------------------------------------------------------
#
# fTools
# Copyright (C) 2008-2011 Carson Farmer
# EMAIL: carson.farmer (at) gmail.com
# WEB : http://www.ftools.ca/fTools.html
#
# A collection of data management and analysis tools for vector data
#
#-----------------------------------------------------------
#
# licensed under the terms of GNU GPL 2
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
#---------------------------------------------------------------------
from PyQt4.QtCore import QObject, SIGNAL, QVariant, QFile
from PyQt4.QtGui import QDialog, QDialogButtonBox, QMessageBox
import ftools_utils
from qgis.core import QGis, QgsFeature, QgsVectorFileWriter, QgsFields, QgsField, QgsGeometry, QgsPoint, QgsDistanceArea
from math import sqrt
from ui_frmMeanCoords import Ui_Dialog
class Dialog(QDialog, Ui_Dialog):
def __init__(self, iface, function):
QDialog.__init__(self, iface.mainWindow())
self.iface = iface
self.function = function
self.setupUi(self)
self.updateUi()
QObject.connect(self.toolOut, SIGNAL("clicked()"), self.outFile)
QObject.connect(self.inShape, SIGNAL("currentIndexChanged(QString)"), self.update)
self.buttonOk = self.buttonBox_2.button(QDialogButtonBox.Ok)
self.progressBar.setValue(0)
self.populateLayers()
def populateLayers(self):
layers = ftools_utils.getLayerNames([QGis.Point, QGis.Line, QGis.Polygon])
self.inShape.blockSignals(True)
self.inShape.clear()
self.inShape.blockSignals(False)
self.inShape.addItems(layers)
def updateUi(self):
if self.function == 1:
self.setWindowTitle(self.tr("Mean coordinates"))
self.sizeValue.setVisible(False)
self.label_size.setVisible(False)
elif self.function == 2:
self.setWindowTitle(self.tr("Standard distance"))
self.resize(381, 100)
def update(self, inputLayer):
self.weightField.clear()
self.uniqueField.clear()
self.weightField.addItem(self.tr("(Optional) Weight field"))
self.uniqueField.addItem(self.tr("(Optional) Unique ID field"))
self.changedLayer = ftools_utils.getVectorLayerByName(inputLayer)
changedField = ftools_utils.getFieldList(self.changedLayer)
for f in changedField:
if f.type() == QVariant.Int or f.type() == QVariant.Double:
self.weightField.addItem(unicode(f.name()))
self.uniqueField.addItem(unicode(f.name()))
def accept(self):
self.buttonOk.setEnabled(False)
if self.inShape.currentText() == "":
QMessageBox.information(self, self.tr("Coordinate statistics"), self.tr("No input vector layer specified"))
elif self.outShape.text() == "":
QMessageBox.information(self, self.tr("Coordinate statistics"), self.tr("Please specify output shapefile"))
else:
inName = self.inShape.currentText()
outPath = self.outShape.text()
self.compute(inName, self.weightField.currentText(), self.sizeValue.value(), self.uniqueField.currentText())
self.progressBar.setValue(100)
self.outShape.clear()
if self.addToCanvasCheck.isChecked():
addCanvasCheck = ftools_utils.addShapeToCanvas(unicode(outPath))
if not addCanvasCheck:
QMessageBox.warning(self, self.tr("Coordinate statistics"), self.tr("Error loading output shapefile:\n%s") % (unicode(outPath)))
self.populateLayers()
else:
QMessageBox.information(self, self.tr("Coordinate statistics"), self.tr("Created output shapefile:\n%s") % (unicode(outPath)))
self.progressBar.setValue(0)
self.buttonOk.setEnabled(True)
def outFile(self):
self.outShape.clear()
(self.shapefileName, self.encoding) = ftools_utils.saveDialog(self)
if self.shapefileName is None or self.encoding is None:
return
self.outShape.setText(self.shapefileName)
def compute(self, inName, weightField="", times=1, uniqueField=""):
vlayer = ftools_utils.getVectorLayerByName(inName)
provider = vlayer.dataProvider()
weightIndex = provider.fieldNameIndex(weightField)
uniqueIndex = provider.fieldNameIndex(uniqueField)
feat = QgsFeature()
sRs = provider.crs()
check = QFile(self.shapefileName)
if check.exists():
if not QgsVectorFileWriter.deleteShapeFile(self.shapefileName):
return
if uniqueIndex != -1:
uniqueValues = ftools_utils.getUniqueValues(provider, int(uniqueIndex))
single = False
else:
uniqueValues = [1]
single = True
if self.function == 2:
fieldList = QgsFields()
fieldList.append(QgsField("STD_DIST", QVariant.Double))
fieldList.append(QgsField("UID", QVariant.String))
writer = QgsVectorFileWriter(self.shapefileName, self.encoding, fieldList, QGis.WKBPolygon, sRs)
else:
fieldList = QgsFields()
fieldList.append(QgsField("MEAN_X", QVariant.Double))
fieldList.append(QgsField("MEAN_Y", QVariant.Double))
fieldList.append(QgsField("UID", QVariant.String))
writer = QgsVectorFileWriter(self.shapefileName, self.encoding, fieldList, QGis.WKBPoint, sRs)
outfeat = QgsFeature()
outfeat.setFields(fieldList)
points = []
weights = []
nFeat = provider.featureCount() * len(uniqueValues)
nElement = 0
self.progressBar.setValue(0)
self.progressBar.setRange(0, nFeat)
for j in uniqueValues:
cx = 0.00
cy = 0.00
points = []
weights = []
fit = provider.getFeatures()
while fit.nextFeature(feat):
nElement += 1
self.progressBar.setValue(nElement)
if single:
check = unicode(j).strip()
else:
check = unicode(feat[uniqueIndex]).strip()
if check == unicode(j).strip():
cx = 0.00
cy = 0.00
if weightIndex == -1:
weight = 1.00
else:
weight = float(feat[weightIndex])
geom = QgsGeometry(feat.geometry())
geom = ftools_utils.extractPoints(geom)
for i in geom:
cx += i.x()
cy += i.y()
points.append(QgsPoint((cx / len(geom)), (cy / len(geom))))
weights.append(weight)
sumWeight = sum(weights)
cx = 0.00
cy = 0.00
item = 0
for item, i in enumerate(points):
cx += i.x() * weights[item]
cy += i.y() * weights[item]
cx = cx / sumWeight
cy = cy / sumWeight
meanPoint = QgsPoint(cx, cy)
if self.function == 2:
values = []
md = 0.00
sd = 0.00
dist = QgsDistanceArea()
item = 0
for i in points:
tempDist = dist.measureLine(i, meanPoint)
values.append(tempDist)
item += 1
md += tempDist
md = md / item
for i in values:
sd += (i - md) * (i - md)
sd = sqrt(sd / item)
outfeat.setGeometry(QgsGeometry.fromPoint(meanPoint).buffer(sd * times, 10))
outfeat.setAttribute(0, sd)
outfeat.setAttribute(1, j)
else:
outfeat.setGeometry(QgsGeometry.fromPoint(meanPoint))
outfeat.setAttribute(0, cx)
outfeat.setAttribute(1, cy)
outfeat.setAttribute(2, j)
writer.addFeature(outfeat)
if single:
break
del writer