[QGIS Commit] r13036 - trunk/qgis/python/plugins/fTools/tools
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Tue Mar 9 19:49:24 EST 2010
Author: cfarmer
Date: 2010-03-09 19:49:23 -0500 (Tue, 09 Mar 2010)
New Revision: 13036
Modified:
trunk/qgis/python/plugins/fTools/tools/doSpatialJoin.py
Log:
Uses spatial index to select intersecting features (used selections before). Tool should run faster and with fewer map canvas glitches.
Modified: trunk/qgis/python/plugins/fTools/tools/doSpatialJoin.py
===================================================================
--- trunk/qgis/python/plugins/fTools/tools/doSpatialJoin.py 2010-03-10 00:16:03 UTC (rev 13035)
+++ trunk/qgis/python/plugins/fTools/tools/doSpatialJoin.py 2010-03-10 00:49:23 UTC (rev 13036)
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
#-----------------------------------------------------------
#
# Spatial Join
@@ -40,222 +41,177 @@
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.toolOut, SIGNAL("clicked()"), self.outFile)
- self.setWindowTitle( self.tr("Join attributes by location") )
- # populate layer list
- self.progressBar.setValue(0)
- mapCanvas = self.iface.mapCanvas()
- for i in range(mapCanvas.layerCount()):
- layer = mapCanvas.layer(i)
- if layer.type() == layer.VectorLayer:
- self.inShape.addItem(layer.name())
- self.joinShape.addItem(layer.name())
-
- def accept(self):
- if self.inShape.currentText() == "":
- QMessageBox.information(self, self.tr("Spatial Join"), self.tr("Please specify target vector layer") )
- elif self.outShape.text() == "":
- QMessageBox.information(self, self.tr("Spatial Join"), self.tr("Please specify output shapefile") )
- elif self.joinShape.currentText() == "":
- QMessageBox.information(self, self.tr("Spatial Join"), self.tr("Please specify join vector layer") )
- elif self.rdoSummary.isChecked() and not (self.chkMean.isChecked() or self.chkSum.isChecked() or self.chkMin.isChecked() or self.chkMax.isChecked() or self.chkMean.isChecked()):
- QMessageBox.information(self, self.tr("Spatial Join"), self.tr("Please specify at least one summary statistic") )
- else:
- inName = self.inShape.currentText()
- joinName = self.joinShape.currentText()
- outPath = self.outShape.text()
- if self.rdoSummary.isChecked():
- summary = True
- sumList = []
- if self.chkSum.isChecked(): sumList.append("SUM")
- if self.chkMean.isChecked(): sumList.append("MEAN")
- if self.chkMin.isChecked(): sumList.append("MIN")
- if self.chkMax.isChecked(): sumList.append("MAX")
- else:
- summary = False
- sumList = ["all"]
- if self.rdoKeep.isChecked(): keep = True
- else: keep = False
- if outPath.contains("\\"):
- outName = outPath.right((outPath.length() - outPath.lastIndexOf("\\")) - 1)
- else:
- outName = outPath.right((outPath.length() - outPath.lastIndexOf("/")) - 1)
- if outName.endsWith(".shp"):
- outName = outName.left(outName.length() - 4)
- self.compute(inName, joinName, outPath, summary, sumList, keep, self.progressBar)
- self.outShape.clear()
- addToTOC = QMessageBox.question(self, self.tr("Spatial Join"), self.tr("Created output shapefile:\n%1\n\nWould you like to add the new layer to the TOC?").arg(unicode(outPath)), QMessageBox.Yes, QMessageBox.No, QMessageBox.NoButton)
- if addToTOC == QMessageBox.Yes:
- self.vlayer = QgsVectorLayer(outPath, unicode(outName), "ogr")
- QgsMapLayerRegistry.instance().addMapLayer(self.vlayer)
- self.progressBar.setValue(0)
+ def __init__(self, iface):
+ QDialog.__init__(self)
+ self.iface = iface
+ # Set up the user interface from Designer.
+ self.setupUi(self)
+ QObject.connect(self.toolOut, SIGNAL("clicked()"), self.outFile)
+ self.setWindowTitle( self.tr("Join attributes by location") )
+ # populate layer list
+ self.progressBar.setValue(0)
+ mapCanvas = self.iface.mapCanvas()
+ layers = ftools_utils.getLayerNames([QGis.Point, QGis.Line, QGis.Polygon])
+ self.inShape.addItems(layers)
+ self.joinShape.addItems(layers)
+
+ def accept(self):
+ if self.inShape.currentText() == "":
+ QMessageBox.information(self, self.tr("Spatial Join"), self.tr("Please specify target vector layer") )
+ elif self.outShape.text() == "":
+ QMessageBox.information(self, self.tr("Spatial Join"), self.tr("Please specify output shapefile") )
+ elif self.joinShape.currentText() == "":
+ QMessageBox.information(self, self.tr("Spatial Join"), self.tr("Please specify join vector layer") )
+ elif self.rdoSummary.isChecked() and not (self.chkMean.isChecked() or self.chkSum.isChecked() or self.chkMin.isChecked() or self.chkMax.isChecked() or self.chkMean.isChecked()):
+ QMessageBox.information(self, self.tr("Spatial Join"), self.tr("Please specify at least one summary statistic") )
+ else:
+ inName = self.inShape.currentText()
+ joinName = self.joinShape.currentText()
+ outPath = self.outShape.text()
+ if self.rdoSummary.isChecked():
+ summary = True
+ sumList = []
+ if self.chkSum.isChecked(): sumList.append("SUM")
+ if self.chkMean.isChecked(): sumList.append("MEAN")
+ if self.chkMin.isChecked(): sumList.append("MIN")
+ if self.chkMax.isChecked(): sumList.append("MAX")
+ else:
+ summary = False
+ sumList = ["all"]
+ if self.rdoKeep.isChecked(): keep = True
+ else: keep = False
+ if outPath.contains("\\"):
+ outName = outPath.right((outPath.length() - outPath.lastIndexOf("\\")) - 1)
+ else:
+ outName = outPath.right((outPath.length() - outPath.lastIndexOf("/")) - 1)
+ if outName.endsWith(".shp"):
+ outName = outName.left(outName.length() - 4)
+ self.compute(inName, joinName, outPath, summary, sumList, keep, self.progressBar)
+ self.outShape.clear()
+ addToTOC = QMessageBox.question(self, self.tr("Spatial Join"), self.tr("Created output shapefile:\n%1\n\nWould you like to add the new layer to the TOC?").arg(unicode(outPath)), QMessageBox.Yes, QMessageBox.No, QMessageBox.NoButton)
+ if addToTOC == QMessageBox.Yes:
+ self.vlayer = QgsVectorLayer(outPath, unicode(outName), "ogr")
+ QgsMapLayerRegistry.instance().addMapLayer(self.vlayer)
+ self.progressBar.setValue(0)
- 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( QString( self.shapefileName ) )
+ 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( QString( self.shapefileName ) )
- def compute(self, inName, joinName, outName, summary, sumList, keep, progressBar):
- layer1 = self.getVectorLayerByName(inName)
- provider1 = layer1.dataProvider()
- allAttrs = provider1.attributeIndexes()
- provider1.select(allAttrs)
- fieldList1 = self.getFieldList(layer1).values()
+ def compute(self, inName, joinName, outName, summary, sumList, keep, progressBar):
+ layer1 = ftools_utils.getVectorLayerByName(inName)
+ provider1 = layer1.dataProvider()
+ allAttrs = provider1.attributeIndexes()
+ provider1.select(allAttrs)
+ fieldList1 = ftools_utils.getFieldList(layer1).values()
- layer2 = self.getVectorLayerByName(joinName)
- provider2 = layer2.dataProvider()
- allAttrs = provider2.attributeIndexes()
- provider2.select(allAttrs)
- fieldList2 = self.getFieldList(layer2)
- fieldList = []
- if provider1.crs() <> provider2.crs():
- QMessageBox.warning(self, self.tr("CRS warning!"), self.tr("Warning: Input layers have non-matching CRS.\nThis may cause unexpected results."))
- if not summary:
- fieldList2 = self.testForUniqueness(fieldList1, fieldList2.values())
- seq = range(0, len(fieldList1) + len(fieldList2))
- fieldList1.extend(fieldList2)
- fieldList1 = dict(zip(seq, fieldList1))
- else:
- numFields = {}
- for j in fieldList2.keys():
- if fieldList2[j].type() == QVariant.Int or fieldList2[j].type() == QVariant.Double:
- numFields[j] = []
- for i in sumList:
- field = QgsField(i + unicode(fieldList2[j].name()), QVariant.Double, "real", 24, 16, self.tr("Summary field") )
- fieldList.append(field)
- field = QgsField("COUNT", QVariant.Double, "real", 24, 16, self.tr("Summary field") )
- fieldList.append(field)
- fieldList2 = self.testForUniqueness(fieldList1, fieldList)
- fieldList1.extend(fieldList)
- seq = range(0, len(fieldList1))
- fieldList1 = dict(zip(seq, fieldList1))
+ layer2 = ftools_utils.getVectorLayerByName(joinName)
+ provider2 = layer2.dataProvider()
+ allAttrs = provider2.attributeIndexes()
+ provider2.select(allAttrs)
+ fieldList2 = ftools_utils.getFieldList(layer2)
+ fieldList = []
+ if provider1.crs() <> provider2.crs():
+ QMessageBox.warning(self, self.tr("CRS warning!"), self.tr("Warning: Input layers have non-matching CRS.\nThis may cause unexpected results."))
+ if not summary:
+ fieldList2 = ftools_utils.testForUniqueness(fieldList1, fieldList2.values())
+ seq = range(0, len(fieldList1) + len(fieldList2))
+ fieldList1.extend(fieldList2)
+ fieldList1 = dict(zip(seq, fieldList1))
+ else:
+ numFields = {}
+ for j in fieldList2.keys():
+ if fieldList2[j].type() == QVariant.Int or fieldList2[j].type() == QVariant.Double:
+ numFields[j] = []
+ for i in sumList:
+ field = QgsField(i + unicode(fieldList2[j].name()), QVariant.Double, "real", 24, 16, self.tr("Summary field") )
+ fieldList.append(field)
+ field = QgsField("COUNT", QVariant.Double, "real", 24, 16, self.tr("Summary field") )
+ fieldList.append(field)
+ fieldList2 = ftools_utils.testForUniqueness(fieldList1, fieldList)
+ fieldList1.extend(fieldList)
+ seq = range(0, len(fieldList1))
+ fieldList1 = dict(zip(seq, fieldList1))
- sRs = provider1.crs()
- progressBar.setValue(13)
- check = QFile(self.shapefileName)
- if check.exists():
- if not QgsVectorFileWriter.deleteShapeFile(self.shapefileName):
- return
- writer = QgsVectorFileWriter(self.shapefileName, self.encoding, fieldList1, provider1.geometryType(), sRs)
- #writer = QgsVectorFileWriter(outName, "UTF-8", fieldList1, provider1.geometryType(), sRs)
- inFeat = QgsFeature()
- outFeat = QgsFeature()
- joinFeat = QgsFeature()
- inGeom = QgsGeometry()
- progressBar.setValue(15)
- start = 15.00
- add = 85.00 / provider1.featureCount()
- provider1.rewind()
-
- while provider1.nextFeature(inFeat):
- inGeom = inFeat.geometry()
- atMap1 = inFeat.attributeMap()
- outFeat.setGeometry(inGeom)
- none = True
- joinList = []
- if inGeom.type() == QGis.Point:
- #(check, joinList) = layer2.featuresInRectangle(inGeom.buffer(10,2).boundingBox(), True, True)
- layer2.select(inGeom.buffer(10,2).boundingBox(), False)
- joinList = layer2.selectedFeatures()
- if len(joinList) > 0: check = 0
- else: check = 1
- else:
- #(check, joinList) = layer2.featuresInRectangle(inGeom.boundingBox(), True, True)
- layer2.select(inGeom.boundingBox(), False)
- joinList = layer2.selectedFeatures()
- if len(joinList) > 0: check = 0
- else: check = 1
- if check == 0:
- count = 0
- for i in joinList:
- tempGeom = i.geometry()
- if inGeom.intersects(tempGeom):
- count = count + 1
- none = False
- atMap2 = i.attributeMap()
- if not summary:
- atMap = atMap1.values()
- atMap2 = atMap2.values()
- atMap.extend(atMap2)
- atMap = dict(zip(seq, atMap))
- break
- else:
- for j in numFields.keys():
- numFields[j].append(atMap2[j].toDouble()[0])
- if summary and not none:
- atMap = atMap1.values()
- for j in numFields.keys():
- for k in sumList:
- if k == "SUM": atMap.append(QVariant(sum(numFields[j])))
- elif k == "MEAN": atMap.append(QVariant(sum(numFields[j]) / count))
- elif k == "MIN": atMap.append(QVariant(min(numFields[j])))
- else: atMap.append(QVariant(max(numFields[j])))
- numFields[j] = []
- atMap.append(QVariant(count))
- atMap = dict(zip(seq, atMap))
- if none:
- outFeat.setAttributeMap(atMap1)
- else:
- outFeat.setAttributeMap(atMap)
- if keep: # keep all records
- writer.addFeature(outFeat)
- else: # keep only matching records
- if not none:
- writer.addFeature(outFeat)
- start = start + add
- progressBar.setValue(start)
- del writer
-
- def testForUniqueness(self, fieldList1, fieldList2):
- changed = True
- while changed:
- changed = False
- for i in fieldList1:
- for j in fieldList2:
- if j.name() == i.name():
- j = self.createUniqueFieldName(j)
- changed = True
- return fieldList2
-
- def createUniqueFieldName(self, field):
- check = field.name().right(2)
- if check.startsWith("_"):
- (val,test) = check.right(1).toInt()
- if test:
- if val < 2:
- val = 2
- else:
- val = val + 1
- field.setName(field.name().left(len(field.name())-1) + unicode(val))
- else:
- field.setName(field.name() + "_2")
- else:
- field.setName(field.name() + "_2")
- return field
-
- 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("Spatial Join"), 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
+ sRs = provider1.crs()
+ progressBar.setValue(13)
+ check = QFile(self.shapefileName)
+ if check.exists():
+ if not QgsVectorFileWriter.deleteShapeFile(self.shapefileName):
+ return
+ writer = QgsVectorFileWriter(self.shapefileName, self.encoding, fieldList1, provider1.geometryType(), sRs)
+ #writer = QgsVectorFileWriter(outName, "UTF-8", fieldList1, provider1.geometryType(), sRs)
+ inFeat = QgsFeature()
+ outFeat = QgsFeature()
+ inFeatB = QgsFeature()
+ inGeom = QgsGeometry()
+ progressBar.setValue(15)
+ start = 15.00
+ add = 85.00 / provider1.featureCount()
+ provider1.rewind()
+ index = ftools_utils.createIndex(provider2)
+ while provider1.nextFeature(inFeat):
+ inGeom = inFeat.geometry()
+ atMap1 = inFeat.attributeMap()
+ outFeat.setGeometry(inGeom)
+ none = True
+ joinList = []
+ if inGeom.type() == QGis.Point:
+ #(check, joinList) = layer2.featuresInRectangle(inGeom.buffer(10,2).boundingBox(), True, True)
+ #layer2.select(inGeom.buffer(10,2).boundingBox(), False)
+ #joinList = layer2.selectedFeatures()
+ joinList = index.intersects( inGeom.buffer(10,2).boundingBox() )
+ if len(joinList) > 0: check = 0
+ else: check = 1
+ else:
+ #(check, joinList) = layer2.featuresInRectangle(inGeom.boundingBox(), True, True)
+ #layer2.select(inGeom.boundingBox(), False)
+ #joinList = layer2.selectedFeatures()
+ joinList = index.intersects( inGeom.boundingBox() )
+ if len(joinList) > 0: check = 0
+ else: check = 1
+ if check == 0:
+ count = 0
+ for i in joinList:
+ #tempGeom = i.geometry()
+ provider2.featureAtId(int(i), inFeatB , True, allAttrs)
+ tmpGeom = QgsGeometry( inFeatB.geometry() )
+ if inGeom.intersects(tmpGeom):
+ count = count + 1
+ none = False
+ atMap2 = inFeatB.attributeMap()
+ if not summary:
+ atMap = atMap1.values()
+ atMap2 = atMap2.values()
+ atMap.extend(atMap2)
+ atMap = dict(zip(seq, atMap))
+ break
+ else:
+ for j in numFields.keys():
+ numFields[j].append(atMap2[j].toDouble()[0])
+ if summary and not none:
+ atMap = atMap1.values()
+ for j in numFields.keys():
+ for k in sumList:
+ if k == "SUM": atMap.append(QVariant(sum(numFields[j])))
+ elif k == "MEAN": atMap.append(QVariant(sum(numFields[j]) / count))
+ elif k == "MIN": atMap.append(QVariant(min(numFields[j])))
+ else: atMap.append(QVariant(max(numFields[j])))
+ numFields[j] = []
+ atMap.append(QVariant(count))
+ atMap = dict(zip(seq, atMap))
+ if none:
+ outFeat.setAttributeMap(atMap1)
+ else:
+ outFeat.setAttributeMap(atMap)
+ if keep: # keep all records
+ writer.addFeature(outFeat)
+ else: # keep only matching records
+ if not none:
+ writer.addFeature(outFeat)
+ start = start + add
+ progressBar.setValue(start)
+ del writer
More information about the QGIS-commit
mailing list