diff --git a/ocitysmap/__init__.py b/ocitysmap/__init__.py index 31b6f595..41fb8f0a 100644 --- a/ocitysmap/__init__.py +++ b/ocitysmap/__init__.py @@ -111,6 +111,7 @@ def __init__(self): self.language = None # str (locale) self.stylesheet = None # Obj Stylesheet + self.overlay = None # Obj Stylesheet self.paper_width_mm = None self.paper_height_mm = None @@ -181,11 +182,11 @@ def assign_if_present(key, cast_fn=str): return s @staticmethod - def create_all_from_config(parser): - styles = parser.get('rendering', 'available_stylesheets') - if not styles: - raise ValueError, \ - 'OCitySMap configuration does not contain any stylesheet!' + def create_all_from_config(parser, type='stylesheets'): + try: + styles = parser.get('rendering', 'available_'+type) + except (ConfigParser.NoOptionError, ValueError): + return [] return [Stylesheet.create_from_config_section(parser, name.strip()) for name in styles.split(',')] @@ -202,6 +203,8 @@ class OCitySMap: STYLESHEET_REGISTRY = [] + OVERLAY_REGISTRY = [] + def __init__(self, config_files=None): """Instanciate a new configured OCitySMap instance. @@ -229,8 +232,14 @@ def __init__(self, config_files=None): # Read stylesheet configuration self.STYLESHEET_REGISTRY = Stylesheet.create_all_from_config(self._parser) + if not self.STYLESHEET_REGISTRY: + raise ValueError, \ + 'OCitySMap configuration does not contain any stylesheet!' LOG.debug('Found %d Mapnik stylesheets.' % len(self.STYLESHEET_REGISTRY)) + self.OVERLAY_REGISTRY = Stylesheet.create_all_from_config(self._parser, "overlays") + LOG.debug('Found %d Mapnik overlay styles.' % len(self.OVERLAY_REGISTRY)) + @property def _db(self): if self.__db: @@ -391,6 +400,18 @@ def get_stylesheet_by_name(self, name): return style raise LookupError, 'The requested stylesheet %s was not found!' % name + def get_all_overlay_configurations(self): + """Returns the list of all available overlay stylesheet configurations + (list of overlay Stylesheet objects).""" + return self.OVERLAY_REGISTRY + + def get_overlay_by_name(self, name): + """Returns a overlay stylesheet by its key name.""" + for style in self.OVERLAY_REGISTRY: + if style.name == name: + return style + raise LookupError, 'The requested overlay stylesheet %s was not found!' % name + def get_all_renderers(self): """Returns the list of all available layout renderers (list of Renderer classes).""" diff --git a/ocitysmap/layoutlib/multi_page_renderer.py b/ocitysmap/layoutlib/multi_page_renderer.py index e22613a4..405b5b20 100644 --- a/ocitysmap/layoutlib/multi_page_renderer.py +++ b/ocitysmap/layoutlib/multi_page_renderer.py @@ -265,6 +265,14 @@ def __init__(self, db, rc, tmpdir, dpi, file_prefix): self._usable_area_height_pt, dpi, extend_bbox_to_ratio=False) + # Create canvas for overlay on current page + overla_canvas = None + if self.rc.overlay: + overlay_canvas = MapCanvas(self.rc.overlay, + bb, self._usable_area_width_pt, + self._usable_area_height_pt, dpi, + extend_bbox_to_ratio=False) + # Create the grid map_grid = Grid(bb_inner, map_canvas.get_actual_scale(), self.rc.i18n.isrtl()) grid_shape = map_grid.generate_shape_file( @@ -280,7 +288,11 @@ def __init__(self, db, rc, tmpdir, dpi, file_prefix): self.rc.stylesheet.grid_line_width) map_canvas.render() - self.pages.append((map_canvas, map_grid)) + + if overlay_canvas: + overlay_canvas.render() + + self.pages.append((map_canvas, map_grid, overlay_canvas)) # Create the index for the current page inside_contour_wkt = interior_contour.intersection(interior).wkt @@ -673,13 +685,17 @@ def render(self, cairo_surface, dpi, osm_date): self._render_overview_page(ctx, cairo_surface, dpi) - for map_number, (canvas, grid) in enumerate(self.pages): + for map_number, (canvas, grid, overlay) in enumerate(self.pages): rendered_map = canvas.get_rendered_map() LOG.debug('Mapnik scale: 1/%f' % rendered_map.scale_denominator()) LOG.debug('Actual scale: 1/%f' % canvas.get_actual_scale()) mapnik.render(rendered_map, ctx) + if overlay: + rendered_overlay = overlay.get_rendered_map() + mapnik.render(rendered_overlay, ctx) + # Place the vertical and horizontal square labels ctx.save() ctx.translate(commons.convert_pt_to_dots(self.grayed_margin_pt), diff --git a/ocitysmap/layoutlib/single_page_renderers.py b/ocitysmap/layoutlib/single_page_renderers.py index 48e5a626..84a2a643 100644 --- a/ocitysmap/layoutlib/single_page_renderers.py +++ b/ocitysmap/layoutlib/single_page_renderers.py @@ -41,6 +41,7 @@ from indexlib.indexer import StreetIndex from indexlib.commons import IndexDoesNotFitError, IndexEmptyError import draw_utils +from ocitysmap.maplib.map_canvas import MapCanvas LOG = logging.getLogger('ocitysmap') @@ -143,6 +144,14 @@ def __init__(self, db, rc, tmpdir, dpi, file_prefix, float(self._map_coords[3]), # H dpi ) + # Prepare map overlay + if self.rc.overlay: + self._overlay_canvas = MapCanvas(self.rc.overlay, + self.rc.bounding_box, + float(self._map_coords[2]), # W + float(self._map_coords[3]), # H + dpi) + # Prepare the grid self.grid = self._create_grid(self._map_canvas) @@ -157,6 +166,11 @@ def __init__(self, db, rc, tmpdir, dpi, file_prefix, # Commit the internal rendering stack of the map self._map_canvas.render() + if self.rc.overlay: + self._overlay_canvas.render() + + + def _create_index_rendering(self, on_the_side): """ @@ -402,11 +416,20 @@ def render(self, cairo_surface, dpi, osm_date): # Draw the rescaled Map ctx.save() rendered_map = self._map_canvas.get_rendered_map() + LOG.debug('Map:') LOG.debug('Mapnik scale: 1/%f' % rendered_map.scale_denominator()) LOG.debug('Actual scale: 1/%f' % self._map_canvas.get_actual_scale()) mapnik.render(rendered_map, ctx) ctx.restore() + # Draw the rescaled Overlay + if self.rc.overlay: + ctx.save() + rendered_overlay = self._overlay_canvas.get_rendered_map() + LOG.debug('Overlay:') + mapnik.render(rendered_overlay, ctx) + ctx.restore() + # Draw a rectangle around the map ctx.rectangle(0, 0, map_coords_dots[2], map_coords_dots[3]) ctx.stroke() diff --git a/render.py b/render.py index 4f681ea1..e7ca6781 100755 --- a/render.py +++ b/render.py @@ -83,6 +83,10 @@ def main(): metavar='NAME', help='specify which stylesheet to use. Defaults to the ' 'first specified in the configuration file.') + parser.add_option('--overlay', dest='overlay', + metavar='NAME', + help='specify which overlay stylesheet to use. ' + 'Defaults to none') parser.add_option('-l', '--layout', dest='layout', metavar='NAME', default=KNOWN_RENDERERS_NAMES[0].split()[0], @@ -156,6 +160,17 @@ def main(): % (ex, ', '.join(map(lambda s: s.name, mapper.STYLESHEET_REGISTRY)))) + # Parse overlay stylesheet (defaults to none) + if options.overlay is None: + overlay = None + else: + try: + overlay = mapper.get_overlay_by_name(options.overlay) + except LookupError, ex: + parser.error("%s. Available overlay stylesheets: %s." + % (ex, ', '.join(map(lambda s: s.name, + mapper.OVERLAY_REGISTRY)))) + # Parse rendering layout if options.layout is None: cls_renderer = ocitysmap.layoutlib.renderers.get_renderers()[0] @@ -226,6 +241,7 @@ def main(): rc.bounding_box = bbox rc.language = options.language rc.stylesheet = stylesheet + rc.overlay = overlay if options.orientation == 'portrait': rc.paper_width_mm = paper_descr[1] rc.paper_height_mm = paper_descr[2]