Calculating intersects for map layers and map extent dynamically in QGIS
Posted by: Admire Nyakudya | in Python, QGIS | 1 year, 11 months ago | Comments

Recently we have been working on a project that involves simulating the 1 in 50k topographic maps in South Africa. Since we are using QGIS Server to print the map all the logic is set up in print composer. All  maps generated are dynamic (users can select a specific area within South Africa to print) and QGIS Server will use the map template to generate the map. 

Print Area

On each topographic map is printed map sheets that correspond to the printed area as depicted below

map sheets

In order to generate the list as above, I had to do an intersection between the map extent and map layer in QGIS. Since the attributes of layers are not exposed I could not use in built expressions.

Getting extent of a map  using QGIS expressions

map_get(item_variables('main_map'), 'map_extent')

Where main_map is the Item ID of a map. This will return a QGIS Geometry which can then be used to intersect the map layer.

Item ID

Writing a custom function in QGIS

In order to achieve what I needed, I had to write a custom QGIS function to do the map intersects with the layer features.

from qgis.core import *
from qgis.gui import *
@qgsfunction(args='auto', group='Custom')
def map_index(source_layer, map_extent, source_attribute, feature, parent):
    map_layer = QgsProject.instance().mapLayersByName(source_layer)[0]
    map_extent_bounds = map_extent.boundingBox()
    records = []
    for f in map_layer.getFeatures():
        f_bounds = f.geometry().boundingBox()
        if map_extent_bounds.intersects(f_bounds):
            field_name_idx = f.fieldNameIndex(source_attribute)
            field_value = f.attributes()[field_name_idx]
    result = ','.join(records)  
    return result

In the map composer, I then added a text box so that I could use the custom function.

replace( map_index( 'index1in50k',map_get(item_variables('main_map'), 'map_extent'),"sh_no"), ',', ' \n')

This will give us the list of map sheets intersecting the layer index1in50k using the attribute sh_no

Currently unrated


Have any questions? Contact us.
We would love to hear from you!
Subscribe to our Mailing list (spam-free, industry-relevant occasional emails)

Subscribe to our mailing list

* indicates required