En un curso de capacitación reciente me preguntaron si QGIS podía calcular automáticamente los números de página siguiente / anterior y superior / inferior para un libro de mapas creado usando el generador de atlas. Logré elaborar una expresión de etiqueta bastante razonable para una cuadrícula regular si conoces el ancho y la altura de la cuadrícula.
Pero luego comenzamos a pensar en ejemplos realistas en los que no queremos dibujar páginas que no contengan nuestro distrito de interés, como este de mi condado de origen:
Así que esta tarde jugué en un script de Python para resolver los 4 vecinos que me interesaban para cada celda de la cuadrícula y agregué esos valores a mi cuadrícula (esto se basa en gran medida en el tutorial de Ujaval Gandhi ):
for f in feature_dict.values():
print 'Working on %s' % f[_NAME_FIELD]
geom = f.geometry()
# Find all features that intersect the bounding box of the current feature.
# We use spatial index to find the features intersecting the bounding box
# of the current feature. This will narrow down the features that we need
# to check neighboring features.
intersecting_ids = index.intersects(geom.boundingBox())
# Initalize neighbors list and sum
neighbors = []
neighbors_sum = 0
for intersecting_id in intersecting_ids:
# Look up the feature from the dictionary
intersecting_f = feature_dict[intersecting_id]
int_geom = intersecting_f.geometry()
centroid = geom.centroid()
height = geom.boundingBox().height()
width = geom.boundingBox().width()
# For our purpose we consider a feature as 'neighbor' if it touches or
# intersects a feature. We use the 'disjoint' predicate to satisfy
# these conditions. So if a feature is not disjoint, it is a neighbor.
if (f != intersecting_f and
not int_geom.disjoint(geom)):
above_point = QgsGeometry.fromPoint(QgsPoint(centroid.asPoint().x(),
centroid.asPoint().y()+height))
below_point = QgsGeometry.fromPoint(QgsPoint(centroid.asPoint().x(),
centroid.asPoint().y()-height))
left_point = QgsGeometry.fromPoint(QgsPoint(centroid.asPoint().x()-width,
centroid.asPoint().y()))
right_point = QgsGeometry.fromPoint(QgsPoint(centroid.asPoint().x()+width,
centroid.asPoint().y()))
above = int_geom.contains(above_point)
below = int_geom.contains(below_point)
left = int_geom.contains(left_point)
right = int_geom.contains(right_point)
if above:
print "setting %d as above %d"%(intersecting_f['id'],f['id'])
f['above']=intersecting_f['id']
if below:
print "setting %d as below %d"%(intersecting_f['id'],f['id'])
f['below']=intersecting_f['id']
if left:
print "setting %d as left of %d"%(intersecting_f['id'],f['id'])
f['left']=intersecting_f['id']
if right:
print "setting %d as right of %d"%(intersecting_f['id'],f['id'])
f['right']=intersecting_f['id']
# Update the layer with new attribute values.
layer.updateFeature(f)
layer.commitChanges()
Esto funciona bien
Pero para ser honesto, la creación de un punto de prueba hacia el norte y luego probar todos los posibles vecinos parece estar mal. Sin embargo, después de una tarde de sacudir mi cerebro, no puedo pensar en una mejor manera de determinar cuál es el vecino del norte de una celda de red en particular.
Idealmente, me gustaría algo lo suficientemente simple como para ponerlo en un cuadro de texto del compositor de impresión, pero sospecho que es demasiado pedir.