I am making a document with descriptions of how to get to some points of interest. For each point I am making a document that contains two maps, one showing the general overview and the larger roads (Typically scale 1:50000 - 1:100000) and another map showing a more detailed map close to the point of interest and the smaller roads or paths to get there (typically scale > 1:10000)
As the exact area I want to use in each map depends on the way the road network is around the point, it i not possible to calculate the mapextent from the point, but I can draw two polygons for each point indiating the overview area and the local area for each point.
So my question is:
Is it possible to make an atlas where I am using two different data sets to define the area covered by two different maps on one page?
Or do I have to make two different atlas and combine the maps when I am making the final document?
Answer
I needed a bit more customisation than what Monticolo's answer would allow, so this is what I ended up doing. For each page in the atlas, defined by the detail map, find the corresponding polygon in the overview data set, set the extent of the overview map using the overview polygon. (And in case the overview polygon does not exist, use the same extent on both maps)
I do not want the shape of the overview map to change, therefore I am adjusting the bounding box to fit into the size of the defined overview map.
@qgsfunction(args='auto', group='Custom')
def getextent(feature,parent):
overviewlayername='punkt_oversikt'
layoutname='detaljkart-atlas'
searchfield='navn'
overviewmap='Hovedkart'
detailmap='Detaljkart'
projectInstance= QgsProject.instance()
projectLayoutManager = projectInstance.layoutManager()
layout=projectLayoutManager.layoutByName(layoutname)
atl=layout.atlas()
pg=atl.nameForPage(atl.currentFeatureNumber()) # The same as returned by @atlas_pagename
ovLayer = QgsProject.instance().mapLayersByName(overviewlayername)[0] # The one and only
xpr='"{}" = \'{}\''.format(searchfield,pg) # Search string - same format as used in filter
expr = QgsExpression(xpr)
it = ovLayer.getFeatures( QgsFeatureRequest( expr ) )
n=0
for item in it: # Only one item is to be expected
n+=1
bb=item.geometry().boundingBox()
if n==0:
# In case no items are found, use the same extent for both maps
detmap=layout.itemById(detailmap)
bb=detmap.extent()
xmax=bb.xMaximum()
ymax=bb.yMaximum()
xmin=bb.xMinimum()
ymin=bb.yMinimum()
aspect=bb.width()/bb.height()
ovmap=layout.itemById(overviewmap)
ovbb=ovmap.extent()
ovaspect=ovbb.width()/ovbb.height()
if ovaspect>aspect: # Want to put a map into an layoutitem that is too wide
fact=ovaspect/aspect
adj=bb.width()*(fact-1)/2
xmin=xmin-adj
xmax=xmax+adj
else: # Want to put a map into an layoutitem that is too high
fact=aspect/ovaspect
adj=bb.height()*(fact-1)/2
ymin=ymin-adj
ymax=ymax+adj
bbox=QgsRectangle(xmin,ymin,xmax,ymax)
ovmap.setExtent(bbox)
return "" # This is called from a textbox -
The function is being called by an invisible textbox. I have to look into a more elegant solution, but that is another question.
No comments:
Post a Comment