|
| 1 | +# -*- coding: utf-8 -*- |
1 | 2 | #-----------------------------------------------------------
|
2 | 3 | #
|
3 | 4 | # Spatial Join
|
|
40 | 41 |
|
41 | 42 | class Dialog(QDialog, Ui_Dialog):
|
42 | 43 |
|
43 |
| - def __init__(self, iface): |
44 |
| - QDialog.__init__(self) |
45 |
| - self.iface = iface |
46 |
| - # Set up the user interface from Designer. |
47 |
| - self.setupUi(self) |
48 |
| - QObject.connect(self.toolOut, SIGNAL("clicked()"), self.outFile) |
49 |
| - self.setWindowTitle( self.tr("Join attributes by location") ) |
50 |
| - # populate layer list |
51 |
| - self.progressBar.setValue(0) |
52 |
| - mapCanvas = self.iface.mapCanvas() |
53 |
| - for i in range(mapCanvas.layerCount()): |
54 |
| - layer = mapCanvas.layer(i) |
55 |
| - if layer.type() == layer.VectorLayer: |
56 |
| - self.inShape.addItem(layer.name()) |
57 |
| - self.joinShape.addItem(layer.name()) |
58 |
| - |
59 |
| - def accept(self): |
60 |
| - if self.inShape.currentText() == "": |
61 |
| - QMessageBox.information(self, self.tr("Spatial Join"), self.tr("Please specify target vector layer") ) |
62 |
| - elif self.outShape.text() == "": |
63 |
| - QMessageBox.information(self, self.tr("Spatial Join"), self.tr("Please specify output shapefile") ) |
64 |
| - elif self.joinShape.currentText() == "": |
65 |
| - QMessageBox.information(self, self.tr("Spatial Join"), self.tr("Please specify join vector layer") ) |
66 |
| - 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()): |
67 |
| - QMessageBox.information(self, self.tr("Spatial Join"), self.tr("Please specify at least one summary statistic") ) |
68 |
| - else: |
69 |
| - inName = self.inShape.currentText() |
70 |
| - joinName = self.joinShape.currentText() |
71 |
| - outPath = self.outShape.text() |
72 |
| - if self.rdoSummary.isChecked(): |
73 |
| - summary = True |
74 |
| - sumList = [] |
75 |
| - if self.chkSum.isChecked(): sumList.append("SUM") |
76 |
| - if self.chkMean.isChecked(): sumList.append("MEAN") |
77 |
| - if self.chkMin.isChecked(): sumList.append("MIN") |
78 |
| - if self.chkMax.isChecked(): sumList.append("MAX") |
79 |
| - else: |
80 |
| - summary = False |
81 |
| - sumList = ["all"] |
82 |
| - if self.rdoKeep.isChecked(): keep = True |
83 |
| - else: keep = False |
84 |
| - if outPath.contains("\\"): |
85 |
| - outName = outPath.right((outPath.length() - outPath.lastIndexOf("\\")) - 1) |
86 |
| - else: |
87 |
| - outName = outPath.right((outPath.length() - outPath.lastIndexOf("/")) - 1) |
88 |
| - if outName.endsWith(".shp"): |
89 |
| - outName = outName.left(outName.length() - 4) |
90 |
| - self.compute(inName, joinName, outPath, summary, sumList, keep, self.progressBar) |
91 |
| - self.outShape.clear() |
92 |
| - 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) |
93 |
| - if addToTOC == QMessageBox.Yes: |
94 |
| - self.vlayer = QgsVectorLayer(outPath, unicode(outName), "ogr") |
95 |
| - QgsMapLayerRegistry.instance().addMapLayer(self.vlayer) |
96 |
| - self.progressBar.setValue(0) |
| 44 | + def __init__(self, iface): |
| 45 | + QDialog.__init__(self) |
| 46 | + self.iface = iface |
| 47 | + # Set up the user interface from Designer. |
| 48 | + self.setupUi(self) |
| 49 | + QObject.connect(self.toolOut, SIGNAL("clicked()"), self.outFile) |
| 50 | + self.setWindowTitle( self.tr("Join attributes by location") ) |
| 51 | + # populate layer list |
| 52 | + self.progressBar.setValue(0) |
| 53 | + mapCanvas = self.iface.mapCanvas() |
| 54 | + layers = ftools_utils.getLayerNames([QGis.Point, QGis.Line, QGis.Polygon]) |
| 55 | + self.inShape.addItems(layers) |
| 56 | + self.joinShape.addItems(layers) |
| 57 | + |
| 58 | + def accept(self): |
| 59 | + if self.inShape.currentText() == "": |
| 60 | + QMessageBox.information(self, self.tr("Spatial Join"), self.tr("Please specify target vector layer") ) |
| 61 | + elif self.outShape.text() == "": |
| 62 | + QMessageBox.information(self, self.tr("Spatial Join"), self.tr("Please specify output shapefile") ) |
| 63 | + elif self.joinShape.currentText() == "": |
| 64 | + QMessageBox.information(self, self.tr("Spatial Join"), self.tr("Please specify join vector layer") ) |
| 65 | + 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()): |
| 66 | + QMessageBox.information(self, self.tr("Spatial Join"), self.tr("Please specify at least one summary statistic") ) |
| 67 | + else: |
| 68 | + inName = self.inShape.currentText() |
| 69 | + joinName = self.joinShape.currentText() |
| 70 | + outPath = self.outShape.text() |
| 71 | + if self.rdoSummary.isChecked(): |
| 72 | + summary = True |
| 73 | + sumList = [] |
| 74 | + if self.chkSum.isChecked(): sumList.append("SUM") |
| 75 | + if self.chkMean.isChecked(): sumList.append("MEAN") |
| 76 | + if self.chkMin.isChecked(): sumList.append("MIN") |
| 77 | + if self.chkMax.isChecked(): sumList.append("MAX") |
| 78 | + else: |
| 79 | + summary = False |
| 80 | + sumList = ["all"] |
| 81 | + if self.rdoKeep.isChecked(): keep = True |
| 82 | + else: keep = False |
| 83 | + if outPath.contains("\\"): |
| 84 | + outName = outPath.right((outPath.length() - outPath.lastIndexOf("\\")) - 1) |
| 85 | + else: |
| 86 | + outName = outPath.right((outPath.length() - outPath.lastIndexOf("/")) - 1) |
| 87 | + if outName.endsWith(".shp"): |
| 88 | + outName = outName.left(outName.length() - 4) |
| 89 | + self.compute(inName, joinName, outPath, summary, sumList, keep, self.progressBar) |
| 90 | + self.outShape.clear() |
| 91 | + 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) |
| 92 | + if addToTOC == QMessageBox.Yes: |
| 93 | + self.vlayer = QgsVectorLayer(outPath, unicode(outName), "ogr") |
| 94 | + QgsMapLayerRegistry.instance().addMapLayer(self.vlayer) |
| 95 | + self.progressBar.setValue(0) |
97 | 96 |
|
98 |
| - def outFile(self): |
99 |
| - self.outShape.clear() |
100 |
| - ( self.shapefileName, self.encoding ) = ftools_utils.saveDialog( self ) |
101 |
| - if self.shapefileName is None or self.encoding is None: |
102 |
| - return |
103 |
| - self.outShape.setText( QString( self.shapefileName ) ) |
| 97 | + def outFile(self): |
| 98 | + self.outShape.clear() |
| 99 | + ( self.shapefileName, self.encoding ) = ftools_utils.saveDialog( self ) |
| 100 | + if self.shapefileName is None or self.encoding is None: |
| 101 | + return |
| 102 | + self.outShape.setText( QString( self.shapefileName ) ) |
104 | 103 |
|
105 |
| - def compute(self, inName, joinName, outName, summary, sumList, keep, progressBar): |
106 |
| - layer1 = self.getVectorLayerByName(inName) |
107 |
| - provider1 = layer1.dataProvider() |
108 |
| - allAttrs = provider1.attributeIndexes() |
109 |
| - provider1.select(allAttrs) |
110 |
| - fieldList1 = self.getFieldList(layer1).values() |
| 104 | + def compute(self, inName, joinName, outName, summary, sumList, keep, progressBar): |
| 105 | + layer1 = ftools_utils.getVectorLayerByName(inName) |
| 106 | + provider1 = layer1.dataProvider() |
| 107 | + allAttrs = provider1.attributeIndexes() |
| 108 | + provider1.select(allAttrs) |
| 109 | + fieldList1 = ftools_utils.getFieldList(layer1).values() |
111 | 110 |
|
112 |
| - layer2 = self.getVectorLayerByName(joinName) |
113 |
| - provider2 = layer2.dataProvider() |
114 |
| - allAttrs = provider2.attributeIndexes() |
115 |
| - provider2.select(allAttrs) |
116 |
| - fieldList2 = self.getFieldList(layer2) |
117 |
| - fieldList = [] |
118 |
| - if provider1.crs() <> provider2.crs(): |
119 |
| - QMessageBox.warning(self, self.tr("CRS warning!"), self.tr("Warning: Input layers have non-matching CRS.\nThis may cause unexpected results.")) |
120 |
| - if not summary: |
121 |
| - fieldList2 = self.testForUniqueness(fieldList1, fieldList2.values()) |
122 |
| - seq = range(0, len(fieldList1) + len(fieldList2)) |
123 |
| - fieldList1.extend(fieldList2) |
124 |
| - fieldList1 = dict(zip(seq, fieldList1)) |
125 |
| - else: |
126 |
| - numFields = {} |
127 |
| - for j in fieldList2.keys(): |
128 |
| - if fieldList2[j].type() == QVariant.Int or fieldList2[j].type() == QVariant.Double: |
129 |
| - numFields[j] = [] |
130 |
| - for i in sumList: |
131 |
| - field = QgsField(i + unicode(fieldList2[j].name()), QVariant.Double, "real", 24, 16, self.tr("Summary field") ) |
132 |
| - fieldList.append(field) |
133 |
| - field = QgsField("COUNT", QVariant.Double, "real", 24, 16, self.tr("Summary field") ) |
134 |
| - fieldList.append(field) |
135 |
| - fieldList2 = self.testForUniqueness(fieldList1, fieldList) |
136 |
| - fieldList1.extend(fieldList) |
137 |
| - seq = range(0, len(fieldList1)) |
138 |
| - fieldList1 = dict(zip(seq, fieldList1)) |
| 111 | + layer2 = ftools_utils.getVectorLayerByName(joinName) |
| 112 | + provider2 = layer2.dataProvider() |
| 113 | + allAttrs = provider2.attributeIndexes() |
| 114 | + provider2.select(allAttrs) |
| 115 | + fieldList2 = ftools_utils.getFieldList(layer2) |
| 116 | + fieldList = [] |
| 117 | + if provider1.crs() <> provider2.crs(): |
| 118 | + QMessageBox.warning(self, self.tr("CRS warning!"), self.tr("Warning: Input layers have non-matching CRS.\nThis may cause unexpected results.")) |
| 119 | + if not summary: |
| 120 | + fieldList2 = ftools_utils.testForUniqueness(fieldList1, fieldList2.values()) |
| 121 | + seq = range(0, len(fieldList1) + len(fieldList2)) |
| 122 | + fieldList1.extend(fieldList2) |
| 123 | + fieldList1 = dict(zip(seq, fieldList1)) |
| 124 | + else: |
| 125 | + numFields = {} |
| 126 | + for j in fieldList2.keys(): |
| 127 | + if fieldList2[j].type() == QVariant.Int or fieldList2[j].type() == QVariant.Double: |
| 128 | + numFields[j] = [] |
| 129 | + for i in sumList: |
| 130 | + field = QgsField(i + unicode(fieldList2[j].name()), QVariant.Double, "real", 24, 16, self.tr("Summary field") ) |
| 131 | + fieldList.append(field) |
| 132 | + field = QgsField("COUNT", QVariant.Double, "real", 24, 16, self.tr("Summary field") ) |
| 133 | + fieldList.append(field) |
| 134 | + fieldList2 = ftools_utils.testForUniqueness(fieldList1, fieldList) |
| 135 | + fieldList1.extend(fieldList) |
| 136 | + seq = range(0, len(fieldList1)) |
| 137 | + fieldList1 = dict(zip(seq, fieldList1)) |
139 | 138 |
|
140 |
| - sRs = provider1.crs() |
141 |
| - progressBar.setValue(13) |
142 |
| - check = QFile(self.shapefileName) |
143 |
| - if check.exists(): |
144 |
| - if not QgsVectorFileWriter.deleteShapeFile(self.shapefileName): |
145 |
| - return |
146 |
| - writer = QgsVectorFileWriter(self.shapefileName, self.encoding, fieldList1, provider1.geometryType(), sRs) |
147 |
| - #writer = QgsVectorFileWriter(outName, "UTF-8", fieldList1, provider1.geometryType(), sRs) |
148 |
| - inFeat = QgsFeature() |
149 |
| - outFeat = QgsFeature() |
150 |
| - joinFeat = QgsFeature() |
151 |
| - inGeom = QgsGeometry() |
152 |
| - progressBar.setValue(15) |
153 |
| - start = 15.00 |
154 |
| - add = 85.00 / provider1.featureCount() |
155 |
| - provider1.rewind() |
156 |
| - |
157 |
| - while provider1.nextFeature(inFeat): |
158 |
| - inGeom = inFeat.geometry() |
159 |
| - atMap1 = inFeat.attributeMap() |
160 |
| - outFeat.setGeometry(inGeom) |
161 |
| - none = True |
162 |
| - joinList = [] |
163 |
| - if inGeom.type() == QGis.Point: |
164 |
| - #(check, joinList) = layer2.featuresInRectangle(inGeom.buffer(10,2).boundingBox(), True, True) |
165 |
| - layer2.select(inGeom.buffer(10,2).boundingBox(), False) |
166 |
| - joinList = layer2.selectedFeatures() |
167 |
| - if len(joinList) > 0: check = 0 |
168 |
| - else: check = 1 |
169 |
| - else: |
170 |
| - #(check, joinList) = layer2.featuresInRectangle(inGeom.boundingBox(), True, True) |
171 |
| - layer2.select(inGeom.boundingBox(), False) |
172 |
| - joinList = layer2.selectedFeatures() |
173 |
| - if len(joinList) > 0: check = 0 |
174 |
| - else: check = 1 |
175 |
| - if check == 0: |
176 |
| - count = 0 |
177 |
| - for i in joinList: |
178 |
| - tempGeom = i.geometry() |
179 |
| - if inGeom.intersects(tempGeom): |
180 |
| - count = count + 1 |
181 |
| - none = False |
182 |
| - atMap2 = i.attributeMap() |
183 |
| - if not summary: |
184 |
| - atMap = atMap1.values() |
185 |
| - atMap2 = atMap2.values() |
186 |
| - atMap.extend(atMap2) |
187 |
| - atMap = dict(zip(seq, atMap)) |
188 |
| - break |
189 |
| - else: |
190 |
| - for j in numFields.keys(): |
191 |
| - numFields[j].append(atMap2[j].toDouble()[0]) |
192 |
| - if summary and not none: |
193 |
| - atMap = atMap1.values() |
194 |
| - for j in numFields.keys(): |
195 |
| - for k in sumList: |
196 |
| - if k == "SUM": atMap.append(QVariant(sum(numFields[j]))) |
197 |
| - elif k == "MEAN": atMap.append(QVariant(sum(numFields[j]) / count)) |
198 |
| - elif k == "MIN": atMap.append(QVariant(min(numFields[j]))) |
199 |
| - else: atMap.append(QVariant(max(numFields[j]))) |
200 |
| - numFields[j] = [] |
201 |
| - atMap.append(QVariant(count)) |
202 |
| - atMap = dict(zip(seq, atMap)) |
203 |
| - if none: |
204 |
| - outFeat.setAttributeMap(atMap1) |
205 |
| - else: |
206 |
| - outFeat.setAttributeMap(atMap) |
207 |
| - if keep: # keep all records |
208 |
| - writer.addFeature(outFeat) |
209 |
| - else: # keep only matching records |
210 |
| - if not none: |
211 |
| - writer.addFeature(outFeat) |
212 |
| - start = start + add |
213 |
| - progressBar.setValue(start) |
214 |
| - del writer |
215 |
| - |
216 |
| - def testForUniqueness(self, fieldList1, fieldList2): |
217 |
| - changed = True |
218 |
| - while changed: |
219 |
| - changed = False |
220 |
| - for i in fieldList1: |
221 |
| - for j in fieldList2: |
222 |
| - if j.name() == i.name(): |
223 |
| - j = self.createUniqueFieldName(j) |
224 |
| - changed = True |
225 |
| - return fieldList2 |
226 |
| - |
227 |
| - def createUniqueFieldName(self, field): |
228 |
| - check = field.name().right(2) |
229 |
| - if check.startsWith("_"): |
230 |
| - (val,test) = check.right(1).toInt() |
231 |
| - if test: |
232 |
| - if val < 2: |
233 |
| - val = 2 |
234 |
| - else: |
235 |
| - val = val + 1 |
236 |
| - field.setName(field.name().left(len(field.name())-1) + unicode(val)) |
237 |
| - else: |
238 |
| - field.setName(field.name() + "_2") |
239 |
| - else: |
240 |
| - field.setName(field.name() + "_2") |
241 |
| - return field |
242 |
| - |
243 |
| - def getVectorLayerByName(self, myName): |
244 |
| - mc = self.iface.mapCanvas() |
245 |
| - nLayers = mc.layerCount() |
246 |
| - for l in range(nLayers): |
247 |
| - layer = mc.layer(l) |
248 |
| - if layer.name() == unicode(myName): |
249 |
| - vlayer = QgsVectorLayer(unicode(layer.source()), unicode(myName), unicode(layer.dataProvider().name())) |
250 |
| - if vlayer.isValid(): |
251 |
| - return vlayer |
252 |
| - else: |
253 |
| - QMessageBox.information(self, self.tr("Spatial Join"), self.tr("Vector layer is not valid")) |
254 |
| - |
255 |
| - def getFieldList(self, vlayer): |
256 |
| - fProvider = vlayer.dataProvider() |
257 |
| - feat = QgsFeature() |
258 |
| - allAttrs = fProvider.attributeIndexes() |
259 |
| - fProvider.select(allAttrs) |
260 |
| - myFields = fProvider.fields() |
261 |
| - return myFields |
| 139 | + sRs = provider1.crs() |
| 140 | + progressBar.setValue(13) |
| 141 | + check = QFile(self.shapefileName) |
| 142 | + if check.exists(): |
| 143 | + if not QgsVectorFileWriter.deleteShapeFile(self.shapefileName): |
| 144 | + return |
| 145 | + writer = QgsVectorFileWriter(self.shapefileName, self.encoding, fieldList1, provider1.geometryType(), sRs) |
| 146 | + #writer = QgsVectorFileWriter(outName, "UTF-8", fieldList1, provider1.geometryType(), sRs) |
| 147 | + inFeat = QgsFeature() |
| 148 | + outFeat = QgsFeature() |
| 149 | + inFeatB = QgsFeature() |
| 150 | + inGeom = QgsGeometry() |
| 151 | + progressBar.setValue(15) |
| 152 | + start = 15.00 |
| 153 | + add = 85.00 / provider1.featureCount() |
| 154 | + provider1.rewind() |
| 155 | + index = ftools_utils.createIndex(provider2) |
| 156 | + while provider1.nextFeature(inFeat): |
| 157 | + inGeom = inFeat.geometry() |
| 158 | + atMap1 = inFeat.attributeMap() |
| 159 | + outFeat.setGeometry(inGeom) |
| 160 | + none = True |
| 161 | + joinList = [] |
| 162 | + if inGeom.type() == QGis.Point: |
| 163 | + #(check, joinList) = layer2.featuresInRectangle(inGeom.buffer(10,2).boundingBox(), True, True) |
| 164 | + #layer2.select(inGeom.buffer(10,2).boundingBox(), False) |
| 165 | + #joinList = layer2.selectedFeatures() |
| 166 | + joinList = index.intersects( inGeom.buffer(10,2).boundingBox() ) |
| 167 | + if len(joinList) > 0: check = 0 |
| 168 | + else: check = 1 |
| 169 | + else: |
| 170 | + #(check, joinList) = layer2.featuresInRectangle(inGeom.boundingBox(), True, True) |
| 171 | + #layer2.select(inGeom.boundingBox(), False) |
| 172 | + #joinList = layer2.selectedFeatures() |
| 173 | + joinList = index.intersects( inGeom.boundingBox() ) |
| 174 | + if len(joinList) > 0: check = 0 |
| 175 | + else: check = 1 |
| 176 | + if check == 0: |
| 177 | + count = 0 |
| 178 | + for i in joinList: |
| 179 | + #tempGeom = i.geometry() |
| 180 | + provider2.featureAtId(int(i), inFeatB , True, allAttrs) |
| 181 | + tmpGeom = QgsGeometry( inFeatB.geometry() ) |
| 182 | + if inGeom.intersects(tmpGeom): |
| 183 | + count = count + 1 |
| 184 | + none = False |
| 185 | + atMap2 = inFeatB.attributeMap() |
| 186 | + if not summary: |
| 187 | + atMap = atMap1.values() |
| 188 | + atMap2 = atMap2.values() |
| 189 | + atMap.extend(atMap2) |
| 190 | + atMap = dict(zip(seq, atMap)) |
| 191 | + break |
| 192 | + else: |
| 193 | + for j in numFields.keys(): |
| 194 | + numFields[j].append(atMap2[j].toDouble()[0]) |
| 195 | + if summary and not none: |
| 196 | + atMap = atMap1.values() |
| 197 | + for j in numFields.keys(): |
| 198 | + for k in sumList: |
| 199 | + if k == "SUM": atMap.append(QVariant(sum(numFields[j]))) |
| 200 | + elif k == "MEAN": atMap.append(QVariant(sum(numFields[j]) / count)) |
| 201 | + elif k == "MIN": atMap.append(QVariant(min(numFields[j]))) |
| 202 | + else: atMap.append(QVariant(max(numFields[j]))) |
| 203 | + numFields[j] = [] |
| 204 | + atMap.append(QVariant(count)) |
| 205 | + atMap = dict(zip(seq, atMap)) |
| 206 | + if none: |
| 207 | + outFeat.setAttributeMap(atMap1) |
| 208 | + else: |
| 209 | + outFeat.setAttributeMap(atMap) |
| 210 | + if keep: # keep all records |
| 211 | + writer.addFeature(outFeat) |
| 212 | + else: # keep only matching records |
| 213 | + if not none: |
| 214 | + writer.addFeature(outFeat) |
| 215 | + start = start + add |
| 216 | + progressBar.setValue(start) |
| 217 | + del writer |
0 commit comments