'Join by location' can now use the geometry from the joined layer as output.

This commit is contained in:
Joshua Arnott 2013-10-22 23:49:08 +01:00
parent 8daf8c371a
commit 4e57af6931

View File

@ -53,6 +53,16 @@ def myself(L):
medianVal = L[ (nVal + 1) / 2 - 1] medianVal = L[ (nVal + 1) / 2 - 1]
return medianVal return medianVal
# translate single part to multi part geometry type
multipart = {
QGis.WKBPoint: QGis.WKBMultiPoint,
QGis.WKBLineString: QGis.WKBMultiLineString,
QGis.WKBPolygon: QGis.WKBMultiPolygon,
QGis.WKBPoint25D: QGis.WKBMultiPoint25D,
QGis.WKBLineString25D: QGis.WKBMultiLineString25D,
QGis.WKBPolygon25D: QGis.WKBMultiPolygon25D,
}
class SpatialJoin(GeoAlgorithm): class SpatialJoin(GeoAlgorithm):
''' '''
Join attributes by location Join attributes by location
@ -64,6 +74,7 @@ class SpatialJoin(GeoAlgorithm):
INPUT2 = "INPUT2" INPUT2 = "INPUT2"
SUMMARY = "SUMMARY" SUMMARY = "SUMMARY"
STATS = "STATS" STATS = "STATS"
GEOMETRY = "GEOMETRY"
KEEP = "KEEP" KEEP = "KEEP"
OUTPUT = "OUTPUT" OUTPUT = "OUTPUT"
@ -72,6 +83,11 @@ class SpatialJoin(GeoAlgorithm):
'Take summary of intersecting features' 'Take summary of intersecting features'
] ]
GEOMETRYS = [
'Use geometry from target layer',
'Use geometry from joined layer (multipart if summary)'
]
KEEPS = [ KEEPS = [
'Only keep matching records', 'Only keep matching records',
'Keep all records (including non-matching target records)' 'Keep all records (including non-matching target records)'
@ -88,7 +104,8 @@ class SpatialJoin(GeoAlgorithm):
self.addParameter(ParameterVector(SpatialJoin.INPUT1, "Target vector layer", [ParameterVector.VECTOR_TYPE_ANY])) self.addParameter(ParameterVector(SpatialJoin.INPUT1, "Target vector layer", [ParameterVector.VECTOR_TYPE_ANY]))
self.addParameter(ParameterVector(SpatialJoin.INPUT2, "Join vector layer", [ParameterVector.VECTOR_TYPE_ANY])) self.addParameter(ParameterVector(SpatialJoin.INPUT2, "Join vector layer", [ParameterVector.VECTOR_TYPE_ANY]))
self.addParameter(ParameterSelection(self.SUMMARY, "Attribute summary", self.SUMMARYS, 0)) self.addParameter(ParameterSelection(self.SUMMARY, "Attribute summary", self.SUMMARYS, 0))
self.addParameter(ParameterString(self.STATS, "Statistics for summary (comma separated)", "sum,mean,min,max,med")) self.addParameter(ParameterString(self.STATS, "Statistics for summary (comma separated)", "sum,mean,min,max,median"))
self.addParameter(ParameterSelection(self.GEOMETRY, "Output geometry", self.GEOMETRYS, 0))
self.addParameter(ParameterSelection(self.KEEP, "Output table", self.KEEPS, 0)) self.addParameter(ParameterSelection(self.KEEP, "Output table", self.KEEPS, 0))
self.addOutput(OutputVector(SpatialJoin.OUTPUT, "Output layer")) self.addOutput(OutputVector(SpatialJoin.OUTPUT, "Output layer"))
@ -97,6 +114,7 @@ class SpatialJoin(GeoAlgorithm):
summary = self.getParameterValue(self.SUMMARY) == 1 summary = self.getParameterValue(self.SUMMARY) == 1
sumList = self.getParameterValue(self.STATS).upper().replace(' ','').split(',') sumList = self.getParameterValue(self.STATS).upper().replace(' ','').split(',')
use_geom = self.getParameterValue(self.GEOMETRY)
keep = self.getParameterValue(self.KEEP) == 1 keep = self.getParameterValue(self.KEEP) == 1
input1 = self.getParameterValue(self.INPUT1) input1 = self.getParameterValue(self.INPUT1)
@ -130,13 +148,25 @@ class SpatialJoin(GeoAlgorithm):
seq = range(0, len(fieldList1)) seq = range(0, len(fieldList1))
fieldList1 = dict(zip(seq, fieldList1)) fieldList1 = dict(zip(seq, fieldList1))
sRs = provider1.crs()
progress.setPercentage(13) progress.setPercentage(13)
fields = QgsFields() fields = QgsFields()
for f in fieldList1.values(): for f in fieldList1.values():
fields.append(f) fields.append(f)
output = self.getOutputFromName(self.OUTPUT) output = self.getOutputFromName(self.OUTPUT)
writer = output.getVectorWriter(fields, provider1.geometryType(), sRs)
if use_geom == 0:
# from target layer
crs = provider1.crs()
geometry_type = provider1.geometryType()
else:
# from joined layer
crs = provider2.crs()
if summary:
geometry_type = multipart[provider2.geometryType()]
else:
geometry_type = provider2.geometryType()
writer = output.getVectorWriter(fields, geometry_type, crs)
inFeat = QgsFeature() inFeat = QgsFeature()
outFeat = QgsFeature() outFeat = QgsFeature()
@ -154,6 +184,7 @@ class SpatialJoin(GeoAlgorithm):
while fit1.nextFeature(inFeat): while fit1.nextFeature(inFeat):
inGeom = inFeat.geometry() inGeom = inFeat.geometry()
atMap1 = inFeat.attributes() atMap1 = inFeat.attributes()
if use_geom == 0:
outFeat.setGeometry(inGeom) outFeat.setGeometry(inGeom)
none = True none = True
joinList = [] joinList = []
@ -171,17 +202,30 @@ class SpatialJoin(GeoAlgorithm):
provider2.getFeatures( QgsFeatureRequest().setFilterFid( int(i) ) ).nextFeature( inFeatB ) provider2.getFeatures( QgsFeatureRequest().setFilterFid( int(i) ) ).nextFeature( inFeatB )
if inGeom.intersects(inFeatB.geometry()): if inGeom.intersects(inFeatB.geometry()):
count = count + 1 count = count + 1
none = False
atMap2 = inFeatB.attributes() atMap2 = inFeatB.attributes()
if not summary: if not summary:
# first located feature
atMap = atMap1 atMap = atMap1
atMap2 = atMap2 atMap2 = atMap2
atMap.extend(atMap2) atMap.extend(atMap2)
atMap = dict(zip(seq, atMap)) atMap = dict(zip(seq, atMap))
if use_geom == 1:
outFeat.setGeometry(inFeatB.geometry())
none = False
break break
else: else:
for j in numFields.keys(): for j in numFields.keys():
numFields[j].append(atMap2[j]) numFields[j].append(atMap2[j])
if none:
# first located feature in summary
outFeat.setGeometry(inFeatB.geometry())
else:
# combine (union) with existing geometry
existing = outFeat.geometry()
additional = inFeatB.geometry()
union = existing.combine(additional)
outFeat.setGeometry(union)
none = False
if summary and not none: if summary and not none:
atMap = atMap1 atMap = atMap1
for j in numFields.keys(): for j in numFields.keys():
@ -189,7 +233,7 @@ class SpatialJoin(GeoAlgorithm):
if k == "SUM": atMap.append(sum(numFields[j])) if k == "SUM": atMap.append(sum(numFields[j]))
elif k == "MEAN": atMap.append(sum(numFields[j]) / count) elif k == "MEAN": atMap.append(sum(numFields[j]) / count)
elif k == "MIN": atMap.append(min(numFields[j])) elif k == "MIN": atMap.append(min(numFields[j]))
elif k == "MED": atMap.append(myself(numFields[j])) elif k == "MEDIAN": atMap.append(myself(numFields[j]))
else: atMap.append(max(numFields[j])) else: atMap.append(max(numFields[j]))
numFields[j] = [] numFields[j] = []
atMap.append(count) atMap.append(count)