Skip to content

Commit

Permalink
'Join by location' can now use the geometry from the joined layer as …
Browse files Browse the repository at this point in the history
…output.
  • Loading branch information
snorfalorpagus committed Oct 22, 2013
1 parent 8daf8c3 commit 4e57af6
Showing 1 changed file with 50 additions and 6 deletions.
56 changes: 50 additions & 6 deletions python/plugins/processing/algs/ftools/SpatialJoin.py
Expand Up @@ -53,6 +53,16 @@ def myself(L):
medianVal = L[ (nVal + 1) / 2 - 1]
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):
'''
Join attributes by location
Expand All @@ -64,13 +74,19 @@ class SpatialJoin(GeoAlgorithm):
INPUT2 = "INPUT2"
SUMMARY = "SUMMARY"
STATS = "STATS"
GEOMETRY = "GEOMETRY"
KEEP = "KEEP"
OUTPUT = "OUTPUT"

SUMMARYS = [
'Take attributes of the first located feature',
'Take summary of intersecting features'
]

GEOMETRYS = [
'Use geometry from target layer',
'Use geometry from joined layer (multipart if summary)'
]

KEEPS = [
'Only keep matching records',
Expand All @@ -88,7 +104,8 @@ def defineCharacteristics(self):
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(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.addOutput(OutputVector(SpatialJoin.OUTPUT, "Output layer"))

Expand All @@ -97,6 +114,7 @@ def processAlgorithm(self, progress):

summary = self.getParameterValue(self.SUMMARY) == 1
sumList = self.getParameterValue(self.STATS).upper().replace(' ','').split(',')
use_geom = self.getParameterValue(self.GEOMETRY)
keep = self.getParameterValue(self.KEEP) == 1

input1 = self.getParameterValue(self.INPUT1)
Expand Down Expand Up @@ -130,13 +148,25 @@ def processAlgorithm(self, progress):
seq = range(0, len(fieldList1))
fieldList1 = dict(zip(seq, fieldList1))

sRs = provider1.crs()
progress.setPercentage(13)
fields = QgsFields()
for f in fieldList1.values():
fields.append(f)
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()
outFeat = QgsFeature()
Expand All @@ -154,7 +184,8 @@ def processAlgorithm(self, progress):
while fit1.nextFeature(inFeat):
inGeom = inFeat.geometry()
atMap1 = inFeat.attributes()
outFeat.setGeometry(inGeom)
if use_geom == 0:
outFeat.setGeometry(inGeom)
none = True
joinList = []
if inGeom.type() == QGis.Point:
Expand All @@ -171,25 +202,38 @@ def processAlgorithm(self, progress):
provider2.getFeatures( QgsFeatureRequest().setFilterFid( int(i) ) ).nextFeature( inFeatB )
if inGeom.intersects(inFeatB.geometry()):
count = count + 1
none = False
atMap2 = inFeatB.attributes()
if not summary:
# first located feature
atMap = atMap1
atMap2 = atMap2
atMap.extend(atMap2)
atMap = dict(zip(seq, atMap))
if use_geom == 1:
outFeat.setGeometry(inFeatB.geometry())
none = False
break
else:
for j in numFields.keys():
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:
atMap = atMap1
for j in numFields.keys():
for k in sumList:
if k == "SUM": atMap.append(sum(numFields[j]))
elif k == "MEAN": atMap.append(sum(numFields[j]) / count)
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]))
numFields[j] = []
atMap.append(count)
Expand Down

0 comments on commit 4e57af6

Please sign in to comment.