QGIS Geometry – How to Copy Geometry from One Layer to Attributes of Another

fields-attributesgeometryqgis

I have two polygon layers, A and B, that have the same features but totally different attributes. I want to use the attributes from layer A, but I want them to have the more accurate geometry from layer B. How can I copy the geometry from a feature in layer B and paste it onto the attributes of the same feature in layer A?

Best Answer

I propose two different ways.

  1. Using processing tools: see my answer to another question. It is not difficult to adapt it to your problem, since it is about polygon overlays

  2. A Python script to copy&paste into Python console or to run from Python editor

The script get 2 layers A, B. Replace them with the names of your layers. B is the one providing the additional attributes. The resulting features go to a new memory layer with all attributes from both layers. Then it loops over all features from A searching for features from B, that contain the centroid of the A features. If such a B is found, take the geometry from A, and attributes from A and B , and write it to memory layer AB.

# get layers
a_layer = QgsMapLayerRegistry.instance().mapLayersByName('A')[0]
b_layer = QgsMapLayerRegistry.instance().mapLayersByName('B')[0]

# prepare result layer
ab_layer = QgsVectorLayer('Polygon?crs=epsg:4326', 'AB', 'memory')
ab_fields = a_layer.dataProvider().fields()
ab_fields.extend( b_layer.dataProvider().fields())
ab_prov = ab_layer.dataProvider()
ab_layer.startEditing()
ab_prov.addAttributes(ab_fields)
ab_layer.commitChanges()

ab_feats = []
# replace with a_layer.selectedFeatures() if you want seleted features only
for feat in a_layer.getFeatures():
    # to increase performance filter possible candidates 
    beefs = b_layer.getFeatures(QgsFeatureRequest().setFilterRect(feat.geometry().boundingBox()))
    for beef in beefs:
        # check if centroid of A is in B
        if feat.geometry().centroid().within(beef.geometry()):
            ab_feat = QgsFeature(ab_fields)
            ab_attrib = feat.attributes()
            ab_attrib.extend(beef.attributes())
            ab_feat.setAttributes(ab_attrib)
            ab_feat.setGeometry(beef.geometry())
            ab_feats.append(ab_feat)
            break

# add features to layer
ab_prov.addFeatures(ab_feats)
QgsMapLayerRegistry.instance().addMapLayers([ab_layer])

The script could be used as a template for other topological related feature comparisons as well.

Related Question