[QGIS Commit] r13019 - trunk/qgis/python/plugins/fTools/tools

svn_qgis at osgeo.org svn_qgis at osgeo.org
Sun Mar 7 21:01:34 EST 2010


Author: cfarmer
Date: 2010-03-07 21:01:33 -0500 (Sun, 07 Mar 2010)
New Revision: 13019

Modified:
   trunk/qgis/python/plugins/fTools/tools/doPointDistance.py
Log:
Updates distance matrix tool to allow non ascii characters in id fields. This is based on a workaround (from http://docs.python.org/library/csv.html), as the default Python csv function(s) do not support nonascii characters. Fixes #2496

Modified: trunk/qgis/python/plugins/fTools/tools/doPointDistance.py
===================================================================
--- trunk/qgis/python/plugins/fTools/tools/doPointDistance.py	2010-03-08 00:24:35 UTC (rev 13018)
+++ trunk/qgis/python/plugins/fTools/tools/doPointDistance.py	2010-03-08 02:01:33 UTC (rev 13019)
@@ -1,4 +1,5 @@
-#-----------------------------------------------------------
+# -*- coding: utf-8 -*-
+#-----------------------------------------------------------
 # 
 # Create Point Distance Matrix
 #
@@ -37,198 +38,233 @@
 
 from qgis.core import *
 from ui_frmPointDistance import Ui_Dialog
-import csv
+import csv, codecs, cStringIO
 from math import *
+
+class UnicodeWriter:
+    """
+    A CSV writer which will write rows to CSV file "f",
+    which is encoded in the given encoding.
+    Taken from http://docs.python.org/library/csv.html
+    to allow handling of nonascii output
+    """
+
+    def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
+        # Redirect output to a queue
+        self.queue = cStringIO.StringIO()
+        self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
+        self.stream = f
+        self.encoder = codecs.getincrementalencoder(encoding)()
+
+    def writerow(self, row):
+        try:
+            self.writer.writerow([s.encode("utf-8") for s in row])
+        except:
+            self.writer.writerow(row)
+        # Fetch UTF-8 output from the queue ...
+        data = self.queue.getvalue()
+        data = data.decode("utf-8")
+        # ... and reencode it into the target encoding
+        data = self.encoder.encode(data)
+        # write to the target stream
+        self.stream.write(data)
+        # empty queue
+        self.queue.truncate(0)
+
+    def writerows(self, rows):
+        for row in rows:
+            self.writerow(row)
+
 class Dialog(QDialog, Ui_Dialog):
-	def __init__(self, iface):
-		QDialog.__init__(self)
-		self.iface = iface
-		# Set up the user interface from Designer.
-		self.setupUi(self)
-		QObject.connect(self.btnFile, SIGNAL("clicked()"), self.saveFile)
-		QObject.connect(self.inPoint1, SIGNAL("currentIndexChanged(QString)"), self.update1)
-		QObject.connect(self.inPoint2, SIGNAL("currentIndexChanged(QString)"), self.update2)
-		# populate layer list
-		self.setWindowTitle(self.tr("Distance matrix"))
-		self.progressBar.setValue(0)
-		mapCanvas = self.iface.mapCanvas()
-		for i in range(mapCanvas.layerCount()):
-			layer = mapCanvas.layer(i)
-			if layer.type() == layer.VectorLayer:
-				if layer.geometryType() == QGis.Point:
-					self.inPoint1.addItem(layer.name())
-					self.inPoint2.addItem(layer.name())
+    def __init__(self, iface):
+        QDialog.__init__(self)
+        self.iface = iface
+        # Set up the user interface from Designer.
+        self.setupUi(self)
+        QObject.connect(self.btnFile, SIGNAL("clicked()"), self.saveFile)
+        QObject.connect(self.inPoint1, SIGNAL("currentIndexChanged(QString)"), self.update1)
+        QObject.connect(self.inPoint2, SIGNAL("currentIndexChanged(QString)"), self.update2)
+        # populate layer list
+        self.setWindowTitle(self.tr("Distance matrix"))
+        self.progressBar.setValue(0)
+        mapCanvas = self.iface.mapCanvas()
+        for i in range(mapCanvas.layerCount()):
+            layer = mapCanvas.layer(i)
+            if layer.type() == layer.VectorLayer:
+                if layer.geometryType() == QGis.Point:
+                    self.inPoint1.addItem(layer.name())
+                    self.inPoint2.addItem(layer.name())
 
-	def update1(self, inputLayer):
-		changedLayer = self.getVectorLayerByName(unicode(inputLayer))
-		changedField = self.getFieldList(changedLayer)
-		for i in changedField:
-			if changedField[i].type() == QVariant.Int or changedField[i].type() == QVariant.String:
-				self.inField1.addItem(unicode(changedField[i].name()))
+    def update1(self, inputLayer):
+        changedLayer = self.getVectorLayerByName(unicode(inputLayer))
+        changedField = self.getFieldList(changedLayer)
+        for i in changedField:
+            if changedField[i].type() == QVariant.Int or changedField[i].type() == QVariant.String:
+                self.inField1.addItem(unicode(changedField[i].name()))
 
-	def update2(self, inputLayer):
-		changedLayer = self.getVectorLayerByName(unicode(inputLayer))
-		changedField = self.getFieldList(changedLayer)
-		for i in changedField:
-			if changedField[i].type() == QVariant.Int or changedField[i].type() == QVariant.String:
-				self.inField2.addItem(unicode(changedField[i].name()))
+    def update2(self, inputLayer):
+        changedLayer = self.getVectorLayerByName(unicode(inputLayer))
+        changedField = self.getFieldList(changedLayer)
+        for i in changedField:
+            if changedField[i].type() == QVariant.Int or changedField[i].type() == QVariant.String:
+                self.inField2.addItem(unicode(changedField[i].name()))
 
-	def accept(self):
-		if self.inPoint1.currentText() == "":
-			QMessageBox.information(self, self.tr("Create Point Distance Matrix"), self.tr("Please specify input point layer"))
-		elif self.outFile.text() == "":
-			QMessageBox.information(self, self.tr("Create Point Distance Matrix"), self.tr("Please specify output file"))
-		elif self.inPoint2.currentText() == "":
-			QMessageBox.information(self, self.tr("Create Point Distance Matrix"), self.tr("Please specify target point layer"))
-		elif self.inField1.currentText() == "":
-			QMessageBox.information(self, self.tr("Create Point Distance Matrix"), self.tr("Please specify input unique ID field"))
-		elif self.inField2.currentText() == "":
-			QMessageBox.information(self, self.tr("Create Point Distance Matrix"), self.tr("Please specify target unique ID field"))
-		else:
-			point1 = self.inPoint1.currentText()
-			point2 = self.inPoint2.currentText()
-			field1 = self.inField1.currentText()
-			field2 = self.inField2.currentText()
-			outPath = self.outFile.text()
-			if self.rdoLinear.isChecked(): matType = "Linear"
-			elif self.rdoStandard.isChecked(): matType = "Standard"
-			else: matType = "Summary"
-			if self.chkNearest.isChecked(): nearest = self.spnNearest.value()
-			else: nearest = nearest = 0
-			if outPath.contains("\\"):
-				outName = outPath.right((outPath.length() - outPath.lastIndexOf("\\")) - 1)
-			else:
-				outName = outPath.right((outPath.length() - outPath.lastIndexOf("/")) - 1)
-			if outName.endsWith(".csv"):
-				outName = outName.left(outName.length() - 4)
-			self.outFile.clear()
-			self.compute(point1, point2, field1, field2, outPath, matType, nearest, self.progressBar)
-			self.progressBar.setValue(100)
-			addToTOC = QMessageBox.information(self, "Create Point Distance Matrix", self.tr("Created output matrix:\n") + outPath)
-		self.progressBar.setValue(0)
+    def accept(self):
+        if self.inPoint1.currentText() == "":
+            QMessageBox.information(self, self.tr("Create Point Distance Matrix"), self.tr("Please specify input point layer"))
+        elif self.outFile.text() == "":
+            QMessageBox.information(self, self.tr("Create Point Distance Matrix"), self.tr("Please specify output file"))
+        elif self.inPoint2.currentText() == "":
+            QMessageBox.information(self, self.tr("Create Point Distance Matrix"), self.tr("Please specify target point layer"))
+        elif self.inField1.currentText() == "":
+            QMessageBox.information(self, self.tr("Create Point Distance Matrix"), self.tr("Please specify input unique ID field"))
+        elif self.inField2.currentText() == "":
+            QMessageBox.information(self, self.tr("Create Point Distance Matrix"), self.tr("Please specify target unique ID field"))
+        else:
+            point1 = self.inPoint1.currentText()
+            point2 = self.inPoint2.currentText()
+            field1 = self.inField1.currentText()
+            field2 = self.inField2.currentText()
+            outPath = self.outFile.text()
+            if self.rdoLinear.isChecked(): matType = "Linear"
+            elif self.rdoStandard.isChecked(): matType = "Standard"
+            else: matType = "Summary"
+            if self.chkNearest.isChecked(): nearest = self.spnNearest.value()
+            else: nearest = nearest = 0
+            if outPath.contains("\\"):
+                outName = outPath.right((outPath.length() - outPath.lastIndexOf("\\")) - 1)
+            else:
+                outName = outPath.right((outPath.length() - outPath.lastIndexOf("/")) - 1)
+            if outName.endsWith(".csv"):
+                outName = outName.left(outName.length() - 4)
+            self.outFile.clear()
+            self.compute(point1, point2, field1, field2, outPath, matType, nearest, self.progressBar)
+            self.progressBar.setValue(100)
+            addToTOC = QMessageBox.information(self, "Create Point Distance Matrix", self.tr("Created output matrix:\n") + outPath)
+        self.progressBar.setValue(0)
 
-	def saveFile(self):
-		self.outFile.clear()
-		fileDialog = QFileDialog()
-		outName = fileDialog.getSaveFileName(self, "Output Distance Matrix",".", "Delimited txt file (*.csv)")
-		fileCheck = QFile(outName)
-		filePath = QFileInfo(outName).absoluteFilePath()
-		if filePath.right(4) != ".csv": filePath = filePath + ".csv"
-		if not outName.isEmpty():
-			self.outFile.insert(filePath)
+    def saveFile(self):
+        self.outFile.clear()
+        fileDialog = QFileDialog()
+        outName = fileDialog.getSaveFileName(self, "Output Distance Matrix",".", "Delimited txt file (*.csv)")
+        fileCheck = QFile(outName)
+        filePath = QFileInfo(outName).absoluteFilePath()
+        if filePath.right(4) != ".csv": filePath = filePath + ".csv"
+        if not outName.isEmpty():
+            self.outFile.insert(filePath)
 
-	def compute(self, line1, line2, field1, field2, outPath, matType, nearest, progressBar):
-		layer1 = self.getVectorLayerByName(line1)
-		layer2 = self.getVectorLayerByName(line2)
-		provider1 = layer1.dataProvider()
-		provider2 = layer2.dataProvider()
-		allAttrs = provider1.attributeIndexes()
-		provider1.select(allAttrs)
-		allAttrs = provider2.attributeIndexes()
-		provider2.select(allAttrs)
-		sindex = QgsSpatialIndex()
-		inFeat = QgsFeature()
-		while provider2.nextFeature(inFeat):
-			sindex.insertFeature(inFeat)
-		provider2.rewind()
-		if nearest < 1: nearest = layer2.featureCount()
-		else: nearest = nearest + 1
-		index1 = provider1.fieldNameIndex(field1)
-		index2 = provider2.fieldNameIndex(field2)
-		sRs = provider1.crs()
-		distArea = QgsDistanceArea()
-		#use srs of the first layer (users should ensure that they are both in the same projection)
-		#distArea.setSourceSRS(sRs)
+    def compute(self, line1, line2, field1, field2, outPath, matType, nearest, progressBar):
+        layer1 = self.getVectorLayerByName(line1)
+        layer2 = self.getVectorLayerByName(line2)
+        provider1 = layer1.dataProvider()
+        provider2 = layer2.dataProvider()
+        allAttrs = provider1.attributeIndexes()
+        provider1.select(allAttrs)
+        allAttrs = provider2.attributeIndexes()
+        provider2.select(allAttrs)
+        sindex = QgsSpatialIndex()
+        inFeat = QgsFeature()
+        while provider2.nextFeature(inFeat):
+            sindex.insertFeature(inFeat)
+        provider2.rewind()
+        if nearest < 1: nearest = layer2.featureCount()
+        else: nearest = nearest + 1
+        index1 = provider1.fieldNameIndex(field1)
+        index2 = provider2.fieldNameIndex(field2)
+        sRs = provider1.crs()
+        distArea = QgsDistanceArea()
+        #use srs of the first layer (users should ensure that they are both in the same projection)
+        #distArea.setSourceSRS(sRs)
 
-		f = open(unicode(outPath), "wb")
-		writer = csv.writer(f)
-		if matType <> "Standard":
-			if matType == "Linear":
-				writer.writerow(["InputID", "TargetID", "Distance"])
-			else:
-				writer.writerow(["InputID", "MEAN", "STDDEV", "MIN", "MAX"])
-			self.linearMatrix(writer, provider1, provider2, index1, index2, nearest, distArea, matType, sindex, progressBar)
-		else:
-			self.regularMatrix(writer, provider1, provider2, index1, index2, nearest, distArea, sindex, progressBar)
-		f.close()
+        f = open(unicode(outPath), "wb")
+        writer = UnicodeWriter(f)
+        if matType <> "Standard":
+            if matType == "Linear":
+                writer.writerow(["InputID", "TargetID", "Distance"])
+            else:
+                writer.writerow(["InputID", "MEAN", "STDDEV", "MIN", "MAX"])
+            self.linearMatrix(writer, provider1, provider2, index1, index2, nearest, distArea, matType, sindex, progressBar)
+        else:
+            self.regularMatrix(writer, provider1, provider2, index1, index2, nearest, distArea, sindex, progressBar)
+        f.close()
 
-	def regularMatrix(self, writer, provider1, provider2, index1, index2, nearest, distArea, sindex, progressBar):
-		inFeat = QgsFeature()
-		outFeat = QgsFeature()
-		inGeom = QgsGeometry()
-		outGeom = QgsGeometry()
-		first = True
-		start = 15.00
-		add = 85.00 / provider1.featureCount()
-		while provider1.nextFeature(inFeat):
-			inGeom = inFeat.geometry()
-			inID = inFeat.attributeMap()[index1].toString()
-			if first:
-				featList = sindex.nearestNeighbor(inGeom.asPoint(), nearest)
-				first = False
-				data = ["ID"]
-				for i in featList:
-					provider2.featureAtId(int(i), outFeat, True, [index2])
-					data.append(unicode(outFeat.attributeMap()[index2].toString()))
-				writer.writerow(data)
-			data = [unicode(inID)]
-			for j in featList:
-				provider2.featureAtId(int(j), outFeat, True)
-				outGeom = outFeat.geometry()
-				dist = distArea.measureLine(inGeom.asPoint(), outGeom.asPoint())
-				data.append(float(dist))
-			writer.writerow(data)
-			start = start + add
-			progressBar.setValue(start)
-		del writer
+    def regularMatrix(self, writer, provider1, provider2, index1, index2, nearest, distArea, sindex, progressBar):
+        inFeat = QgsFeature()
+        outFeat = QgsFeature()
+        inGeom = QgsGeometry()
+        outGeom = QgsGeometry()
+        first = True
+        start = 15.00
+        add = 85.00 / provider1.featureCount()
+        while provider1.nextFeature(inFeat):
+            inGeom = inFeat.geometry()
+            inID = inFeat.attributeMap()[index1].toString()
+            if first:
+                featList = sindex.nearestNeighbor(inGeom.asPoint(), nearest)
+                first = False
+                data = ["ID"]
+                for i in featList:
+                    provider2.featureAtId(int(i), outFeat, True, [index2])
+                    data.append(unicode(outFeat.attributeMap()[index2].toString()))
+                writer.writerow(data)
+            data = [unicode(inID)]
+            for j in featList:
+                provider2.featureAtId(int(j), outFeat, True)
+                outGeom = outFeat.geometry()
+                dist = distArea.measureLine(inGeom.asPoint(), outGeom.asPoint())
+                data.append(str(float(dist)))
+            writer.writerow(data)
+            start = start + add
+            progressBar.setValue(start)
+        del writer
 
-	def linearMatrix(self, writer, provider1, provider2, index1, index2, nearest, distArea, matType, sindex, progressBar):
-		inFeat = QgsFeature()
-		outFeat = QgsFeature()
-		inGeom = QgsGeometry()
-		outGeom = QgsGeometry()
-		start = 15.00
-		add = 85.00 / provider1.featureCount()
-		while provider1.nextFeature(inFeat):
-			inGeom = inFeat.geometry()
-			inID = inFeat.attributeMap()[index1].toString()
-			featList = sindex.nearestNeighbor(inGeom.asPoint(), nearest)
-			distList = []
-			vari = 0.00
-			for i in featList:
-				provider2.featureAtId(int(i), outFeat, True, [index2])
-				outID = outFeat.attributeMap()[index2].toString()
-				outGeom = outFeat.geometry()
-				dist = distArea.measureLine(inGeom.asPoint(), outGeom.asPoint())
-				if dist > 0:
-					if matType == "Linear": writer.writerow([unicode(inID), unicode(outID), float(dist)])
-					else: distList.append(float(dist))
-			if matType == "Summary":
-				mean = sum(distList) / len(distList)
-				for i in distList:
-					vari = vari + ((i - mean)*(i - mean))
-				vari = sqrt(vari / len(distList))
-				writer.writerow([unicode(inID), float(mean), float(vari), float(min(distList)), float(max(distList))])
-			start = start + add
-			progressBar.setValue(start)
-		del writer
+    def linearMatrix(self, writer, provider1, provider2, index1, index2, nearest, distArea, matType, sindex, progressBar):
+        inFeat = QgsFeature()
+        outFeat = QgsFeature()
+        inGeom = QgsGeometry()
+        outGeom = QgsGeometry()
+        start = 15.00
+        add = 85.00 / provider1.featureCount()
+        while provider1.nextFeature(inFeat):
+            inGeom = inFeat.geometry()
+            inID = inFeat.attributeMap()[index1].toString()
+            featList = sindex.nearestNeighbor(inGeom.asPoint(), nearest)
+            distList = []
+            vari = 0.00
+            for i in featList:
+                provider2.featureAtId(int(i), outFeat, True, [index2])
+                outID = outFeat.attributeMap()[index2].toString()
+                outGeom = outFeat.geometry()
+                dist = distArea.measureLine(inGeom.asPoint(), outGeom.asPoint())
+                if dist > 0:
+                    if matType == "Linear": writer.writerow([unicode(inID), unicode(outID), float(dist)])
+                    else: distList.append(float(dist))
+            if matType == "Summary":
+                mean = sum(distList) / len(distList)
+                for i in distList:
+                    vari = vari + ((i - mean)*(i - mean))
+                vari = sqrt(vari / len(distList))
+                writer.writerow([unicode(inID), float(mean), float(vari), float(min(distList)), float(max(distList))])
+            start = start + add
+            progressBar.setValue(start)
+        del writer
 
-	def getVectorLayerByName(self, myName):
-		mc = self.iface.mapCanvas()
-		nLayers = mc.layerCount()
-		for l in range(nLayers):
-			layer = mc.layer(l)
-			if layer.name() == unicode(myName):
-				vlayer = QgsVectorLayer(unicode(layer.source()),  unicode(myName),  unicode(layer.dataProvider().name()))
-				if vlayer.isValid():
-					return vlayer
-				else:
-					QMessageBox.information(self, self.tr("Locate Line Intersections"), self.tr("Vector layer is not valid"))
+    def getVectorLayerByName(self, myName):
+        mc = self.iface.mapCanvas()
+        nLayers = mc.layerCount()
+        for l in range(nLayers):
+            layer = mc.layer(l)
+            if layer.name() == unicode(myName):
+                vlayer = QgsVectorLayer(unicode(layer.source()),  unicode(myName),  unicode(layer.dataProvider().name()))
+                if vlayer.isValid():
+                    return vlayer
+                else:
+                    QMessageBox.information(self, self.tr("Locate Line Intersections"), self.tr("Vector layer is not valid"))
 
-	def getFieldList(self, vlayer):
-		fProvider = vlayer.dataProvider()
-		feat = QgsFeature()
-		allAttrs = fProvider.attributeIndexes()
-		fProvider.select(allAttrs)
-		myFields = fProvider.fields()
-		return myFields
+    def getFieldList(self, vlayer):
+        fProvider = vlayer.dataProvider()
+        feat = QgsFeature()
+        allAttrs = fProvider.attributeIndexes()
+        fProvider.select(allAttrs)
+        myFields = fProvider.fields()
+        return myFields



More information about the QGIS-commit mailing list