def __init__(self, db, rc, tmpdir, dpi): """ Create the renderer. Args: rc (RenderingConfiguration): rendering parameters. tmpdir (os.path): Path to a temp dir that can hold temp files. street_index (StreetIndex): None or the street index object. """ # Note: street_index may be None self.db = db self.rc = rc self.tmpdir = tmpdir self.grid = None # The implementation is in charge of it self.paper_width_pt = \ commons.convert_mm_to_pt(self.rc.paper_width_mm) self.paper_height_pt = \ commons.convert_mm_to_pt(self.rc.paper_height_mm)
self.path = "/mnt/data1/common/home/d2/Downloads/svn/mapnik-osm/osm.xml" self.grid_line_color = "black" self.grid_line_alpha = 0.9 self.grid_line_width = 2 self.shade_color = "black" self.shade_alpha = 0.7 class RenderingConfigurationMock: def __init__(self): self.stylesheet = StylesheetMock() self.bounding_box = bbox self.paper_width_mm = papers[0][1] self.paper_height_mm = papers[0][2] self.i18n = i18n.i18n() self.title = "Au Kremlin-Bycêtre" self.polygon_wkt = bbox.as_wkt() config = RenderingConfigurationMock() plain = renderer_cls(config, "/tmp", None) surface = cairo.PDFSurface( "/tmp/plain.pdf", commons.convert_mm_to_pt(config.paper_width_mm), commons.convert_mm_to_pt(config.paper_height_mm), ) plain.render(surface, commons.PT_PER_INCH) surface.finish() print "Generated /tmp/plain.pdf"
def __init__(self): # self.path = '/home/sam/src/python/maposmatic/mapnik-osm/osm.xml' self.path = '/mnt/data1/common/home/d2/Downloads/svn/mapnik-osm/osm.xml' self.grid_line_color = 'black' self.grid_line_alpha = 0.9 self.grid_line_width = 2 self.shade_color = 'black' self.shade_alpha = 0.7 class RenderingConfigurationMock: def __init__(self): self.stylesheet = StylesheetMock() self.bounding_box = bbox self.paper_width_mm = papers[0][1] self.paper_height_mm = papers[0][2] self.i18n = i18n.i18n() self.title = 'Au Kremlin-Bycêtre' self.polygon_wkt = bbox.as_wkt() config = RenderingConfigurationMock() plain = renderer_cls(config, '/tmp', None) surface = cairo.PDFSurface('/tmp/plain.pdf', commons.convert_mm_to_pt(config.paper_width_mm), commons.convert_mm_to_pt(config.paper_height_mm)) plain.render(surface, commons.PT_PER_INCH) surface.finish() print "Generated /tmp/plain.pdf"
def __init__(self, db, rc, tmpdir, dpi, file_prefix): Renderer.__init__(self, db, rc, tmpdir, dpi) self._grid_legend_margin_pt = \ min(Renderer.GRID_LEGEND_MARGIN_RATIO * self.paper_width_pt, Renderer.GRID_LEGEND_MARGIN_RATIO * self.paper_height_pt) # Compute the usable area per page self._usable_area_width_pt = (self.paper_width_pt - (2 * Renderer.PRINT_SAFE_MARGIN_PT)) self._usable_area_height_pt = (self.paper_height_pt - (2 * Renderer.PRINT_SAFE_MARGIN_PT)) scale_denom = Renderer.DEFAULT_SCALE # the mapnik scale depends on the latitude. However we are # always using Mapnik conversion functions (lat,lon <-> # mercator_meters) so we don't need to take into account # latitude in following computations # by convention, mapnik uses 90 ppi whereas cairo uses 72 ppi scale_denom *= float(72) / 90 GRAYED_MARGIN_MM = 10 OVERLAP_MARGIN_MM = 20 # Debug: show original bounding box as JS code # print self.rc.bounding_box.as_javascript("original", "#00ff00") # Convert the original Bounding box into Mercator meters self._proj = mapnik.Projection(coords._MAPNIK_PROJECTION) orig_envelope = self._project_envelope(self.rc.bounding_box) # Extend the bounding box to take into account the lost outter # margin off_x = orig_envelope.minx - (GRAYED_MARGIN_MM * scale_denom) / 1000 off_y = orig_envelope.miny - (GRAYED_MARGIN_MM * scale_denom) / 1000 width = orig_envelope.width() + (2 * GRAYED_MARGIN_MM * scale_denom) / 1000 height = orig_envelope.height() + (2 * GRAYED_MARGIN_MM * scale_denom) / 1000 # Calculate the total width and height of paper needed to # render the geographical area at the current scale. total_width_pt = commons.convert_mm_to_pt( float(width) * 1000 / scale_denom) total_height_pt = commons.convert_mm_to_pt( float(height) * 1000 / scale_denom) self.grayed_margin_pt = commons.convert_mm_to_pt(GRAYED_MARGIN_MM) overlap_margin_pt = commons.convert_mm_to_pt(OVERLAP_MARGIN_MM) # Calculate the number of pages needed in both directions if total_width_pt < self._usable_area_width_pt: nb_pages_width = 1 else: nb_pages_width = \ (float(total_width_pt - self._usable_area_width_pt) / \ (self._usable_area_width_pt - overlap_margin_pt)) + 1 if total_height_pt < self._usable_area_height_pt: nb_pages_height = 1 else: nb_pages_height = \ (float(total_height_pt - self._usable_area_height_pt) / \ (self._usable_area_height_pt - overlap_margin_pt)) + 1 # Round up the number of pages needed so that we have integer # number of pages self.nb_pages_width = int(math.ceil(nb_pages_width)) self.nb_pages_height = int(math.ceil(nb_pages_height)) # Calculate the entire paper area available total_width_pt_after_extension = self._usable_area_width_pt + \ (self._usable_area_width_pt - overlap_margin_pt) * (self.nb_pages_width - 1) total_height_pt_after_extension = self._usable_area_height_pt + \ (self._usable_area_height_pt - overlap_margin_pt) * (self.nb_pages_height - 1) # Convert this paper area available in the number of Mercator # meters that can be rendered on the map total_width_merc = \ commons.convert_pt_to_mm(total_width_pt_after_extension) * scale_denom / 1000 total_height_merc = \ commons.convert_pt_to_mm(total_height_pt_after_extension) * scale_denom / 1000 # Extend the geographical boundaries so that we completely # fill the available paper size. We are careful to extend the # boundaries evenly on all directions (so the center of the # previous boundaries remain the same as the new one) off_x -= (total_width_merc - width) / 2 width = total_width_merc off_y -= (total_height_merc - height) / 2 height = total_height_merc # Calculate what is the final global bounding box that we will render envelope = mapnik.Box2d(off_x, off_y, off_x + width, off_y + height) self._geo_bbox = self._inverse_envelope(envelope) # Debug: show transformed bounding box as JS code # print self._geo_bbox.as_javascript("extended", "#0f0f0f") # Convert the usable area on each sheet of paper into the # amount of Mercator meters we can render in this area. usable_area_merc_m_width = commons.convert_pt_to_mm( self._usable_area_width_pt) * scale_denom / 1000 usable_area_merc_m_height = commons.convert_pt_to_mm( self._usable_area_height_pt) * scale_denom / 1000 grayed_margin_merc_m = (GRAYED_MARGIN_MM * scale_denom) / 1000 overlap_margin_merc_m = (OVERLAP_MARGIN_MM * scale_denom) / 1000 # Calculate all the bounding boxes that correspond to the # geographical area that will be rendered on each sheet of # paper. area_polygon = shapely.wkt.loads(self.rc.polygon_wkt) bboxes = [] self.page_disposition, map_number = {}, 0 for j in reversed(range(0, self.nb_pages_height)): col = self.nb_pages_height - j - 1 self.page_disposition[col] = [] for i in range(0, self.nb_pages_width): cur_x = off_x + i * (usable_area_merc_m_width - overlap_margin_merc_m) cur_y = off_y + j * (usable_area_merc_m_height - overlap_margin_merc_m) envelope = mapnik.Box2d(cur_x, cur_y, cur_x + usable_area_merc_m_width, cur_y + usable_area_merc_m_height) envelope_inner = mapnik.Box2d( cur_x + grayed_margin_merc_m, cur_y + grayed_margin_merc_m, cur_x + usable_area_merc_m_width - grayed_margin_merc_m, cur_y + usable_area_merc_m_height - grayed_margin_merc_m) inner_bb = self._inverse_envelope(envelope_inner) if not area_polygon.disjoint( shapely.wkt.loads(inner_bb.as_wkt())): self.page_disposition[col].append(map_number) map_number += 1 bboxes.append((self._inverse_envelope(envelope), inner_bb)) else: self.page_disposition[col].append(None) # Debug: show per-page bounding boxes as JS code # for i, (bb, bb_inner) in enumerate(bboxes): # print bb.as_javascript(name="p%d" % i) self.pages = [] # Create an overview map overview_bb = self._geo_bbox.create_expanded(0.001, 0.001) # Create the overview grid self.overview_grid = OverviewGrid( overview_bb, [bb_inner for bb, bb_inner in bboxes], self.rc.i18n.isrtl()) grid_shape = self.overview_grid.generate_shape_file( os.path.join(self.tmpdir, 'grid_overview.shp')) # Create a canvas for the overview page self.overview_canvas = MapCanvas(self.rc.stylesheet, overview_bb, self._usable_area_width_pt, self._usable_area_height_pt, dpi, extend_bbox_to_ratio=True) # Create the gray shape around the overview map exterior = shapely.wkt.loads(self.overview_canvas.get_actual_bounding_box()\ .as_wkt()) interior = shapely.wkt.loads(self.rc.polygon_wkt) shade_wkt = exterior.difference(interior).wkt shade = maplib.shapes.PolyShapeFile( self.rc.bounding_box, os.path.join(self.tmpdir, 'shape_overview.shp'), 'shade-overview') shade.add_shade_from_wkt(shade_wkt) self.overview_canvas.add_shape_file(shade) self.overview_canvas.add_shape_file(grid_shape, self.rc.stylesheet.grid_line_color, 1, self.rc.stylesheet.grid_line_width) self.overview_canvas.render() # Create the map canvas for each page indexes = [] for i, (bb, bb_inner) in enumerate(bboxes): # Create the gray shape around the map exterior = shapely.wkt.loads(bb.as_wkt()) interior = shapely.wkt.loads(bb_inner.as_wkt()) shade_wkt = exterior.difference(interior).wkt shade = maplib.shapes.PolyShapeFile( bb, os.path.join(self.tmpdir, 'shade%d.shp' % i), 'shade%d' % i) shade.add_shade_from_wkt(shade_wkt) # Create the contour shade # Area to keep visible interior_contour = shapely.wkt.loads(self.rc.polygon_wkt) # Determine the shade WKT shade_contour_wkt = interior.difference(interior_contour).wkt # Prepare the shade SHP shade_contour = maplib.shapes.PolyShapeFile( bb, os.path.join(self.tmpdir, 'shade_contour%d.shp' % i), 'shade_contour%d' % i) shade_contour.add_shade_from_wkt(shade_contour_wkt) # Create one canvas for the current page map_canvas = MapCanvas(self.rc.stylesheet, bb, self._usable_area_width_pt, 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( os.path.join(self.tmpdir, 'grid%d.shp' % i)) map_canvas.add_shape_file(shade) map_canvas.add_shape_file(shade_contour, self.rc.stylesheet.shade_color_2, self.rc.stylesheet.shade_alpha_2) map_canvas.add_shape_file(grid_shape, self.rc.stylesheet.grid_line_color, self.rc.stylesheet.grid_line_alpha, self.rc.stylesheet.grid_line_width) map_canvas.render() 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 index = StreetIndex(self.db, inside_contour_wkt, self.rc.i18n, page_number=(i + 4)) index.apply_grid(map_grid) indexes.append(index) # Merge all indexes self.index_categories = self._merge_page_indexes(indexes) # Prepare the small map for the front page self._front_page_map = self._prepare_front_page_map(dpi)
def __init__(self, db, rc, tmpdir, dpi, file_prefix): Renderer.__init__(self, db, rc, tmpdir, dpi) self._grid_legend_margin_pt = \ min(Renderer.GRID_LEGEND_MARGIN_RATIO * self.paper_width_pt, Renderer.GRID_LEGEND_MARGIN_RATIO * self.paper_height_pt) # Compute the usable area per page self._usable_area_width_pt = (self.paper_width_pt - (2 * Renderer.PRINT_SAFE_MARGIN_PT)) self._usable_area_height_pt = (self.paper_height_pt - (2 * Renderer.PRINT_SAFE_MARGIN_PT)) scale_denom = Renderer.DEFAULT_SCALE # the mapnik scale depends on the latitude. However we are # always using Mapnik conversion functions (lat,lon <-> # mercator_meters) so we don't need to take into account # latitude in following computations # by convention, mapnik uses 90 ppi whereas cairo uses 72 ppi scale_denom *= float(72) / 90 GRAYED_MARGIN_MM = 10 OVERLAP_MARGIN_MM = 20 # Debug: show original bounding box as JS code # print self.rc.bounding_box.as_javascript("original", "#00ff00") # Convert the original Bounding box into Mercator meters self._proj = mapnik.Projection(coords._MAPNIK_PROJECTION) orig_envelope = self._project_envelope(self.rc.bounding_box) # Extend the bounding box to take into account the lost outter # margin off_x = orig_envelope.minx - (GRAYED_MARGIN_MM * scale_denom) / 1000 off_y = orig_envelope.miny - (GRAYED_MARGIN_MM * scale_denom) / 1000 width = orig_envelope.width() + (2 * GRAYED_MARGIN_MM * scale_denom) / 1000 height = orig_envelope.height() + (2 * GRAYED_MARGIN_MM * scale_denom) / 1000 # Calculate the total width and height of paper needed to # render the geographical area at the current scale. total_width_pt = commons.convert_mm_to_pt(float(width) * 1000 / scale_denom) total_height_pt = commons.convert_mm_to_pt(float(height) * 1000 / scale_denom) self.grayed_margin_pt = commons.convert_mm_to_pt(GRAYED_MARGIN_MM) overlap_margin_pt = commons.convert_mm_to_pt(OVERLAP_MARGIN_MM) # Calculate the number of pages needed in both directions if total_width_pt < self._usable_area_width_pt: nb_pages_width = 1 else: nb_pages_width = \ (float(total_width_pt - self._usable_area_width_pt) / \ (self._usable_area_width_pt - overlap_margin_pt)) + 1 if total_height_pt < self._usable_area_height_pt: nb_pages_height = 1 else: nb_pages_height = \ (float(total_height_pt - self._usable_area_height_pt) / \ (self._usable_area_height_pt - overlap_margin_pt)) + 1 # Round up the number of pages needed so that we have integer # number of pages self.nb_pages_width = int(math.ceil(nb_pages_width)) self.nb_pages_height = int(math.ceil(nb_pages_height)) # Calculate the entire paper area available total_width_pt_after_extension = self._usable_area_width_pt + \ (self._usable_area_width_pt - overlap_margin_pt) * (self.nb_pages_width - 1) total_height_pt_after_extension = self._usable_area_height_pt + \ (self._usable_area_height_pt - overlap_margin_pt) * (self.nb_pages_height - 1) # Convert this paper area available in the number of Mercator # meters that can be rendered on the map total_width_merc = \ commons.convert_pt_to_mm(total_width_pt_after_extension) * scale_denom / 1000 total_height_merc = \ commons.convert_pt_to_mm(total_height_pt_after_extension) * scale_denom / 1000 # Extend the geographical boundaries so that we completely # fill the available paper size. We are careful to extend the # boundaries evenly on all directions (so the center of the # previous boundaries remain the same as the new one) off_x -= (total_width_merc - width) / 2 width = total_width_merc off_y -= (total_height_merc - height) / 2 height = total_height_merc # Calculate what is the final global bounding box that we will render envelope = mapnik.Box2d(off_x, off_y, off_x + width, off_y + height) self._geo_bbox = self._inverse_envelope(envelope) # Debug: show transformed bounding box as JS code # print self._geo_bbox.as_javascript("extended", "#0f0f0f") # Convert the usable area on each sheet of paper into the # amount of Mercator meters we can render in this area. usable_area_merc_m_width = commons.convert_pt_to_mm(self._usable_area_width_pt) * scale_denom / 1000 usable_area_merc_m_height = commons.convert_pt_to_mm(self._usable_area_height_pt) * scale_denom / 1000 grayed_margin_merc_m = (GRAYED_MARGIN_MM * scale_denom) / 1000 overlap_margin_merc_m = (OVERLAP_MARGIN_MM * scale_denom) / 1000 # Calculate all the bounding boxes that correspond to the # geographical area that will be rendered on each sheet of # paper. area_polygon = shapely.wkt.loads(self.rc.polygon_wkt) bboxes = [] self.page_disposition, map_number = {}, 0 for j in reversed(range(0, self.nb_pages_height)): col = self.nb_pages_height - j - 1 self.page_disposition[col] = [] for i in range(0, self.nb_pages_width): cur_x = off_x + i * (usable_area_merc_m_width - overlap_margin_merc_m) cur_y = off_y + j * (usable_area_merc_m_height - overlap_margin_merc_m) envelope = mapnik.Box2d(cur_x, cur_y, cur_x+usable_area_merc_m_width, cur_y+usable_area_merc_m_height) envelope_inner = mapnik.Box2d(cur_x + grayed_margin_merc_m, cur_y + grayed_margin_merc_m, cur_x + usable_area_merc_m_width - grayed_margin_merc_m, cur_y + usable_area_merc_m_height - grayed_margin_merc_m) inner_bb = self._inverse_envelope(envelope_inner) if not area_polygon.disjoint(shapely.wkt.loads( inner_bb.as_wkt())): self.page_disposition[col].append(map_number) map_number += 1 bboxes.append((self._inverse_envelope(envelope), inner_bb)) else: self.page_disposition[col].append(None) # Debug: show per-page bounding boxes as JS code # for i, (bb, bb_inner) in enumerate(bboxes): # print bb.as_javascript(name="p%d" % i) self.pages = [] # Create an overview map overview_bb = self._geo_bbox.create_expanded(0.001, 0.001) # Create the overview grid self.overview_grid = OverviewGrid(overview_bb, [bb_inner for bb, bb_inner in bboxes], self.rc.i18n.isrtl()) grid_shape = self.overview_grid.generate_shape_file( os.path.join(self.tmpdir, 'grid_overview.shp')) # Create a canvas for the overview page self.overview_canvas = MapCanvas(self.rc.stylesheet, overview_bb, self._usable_area_width_pt, self._usable_area_height_pt, dpi, extend_bbox_to_ratio=True) # Create the gray shape around the overview map exterior = shapely.wkt.loads(self.overview_canvas.get_actual_bounding_box()\ .as_wkt()) interior = shapely.wkt.loads(self.rc.polygon_wkt) shade_wkt = exterior.difference(interior).wkt shade = maplib.shapes.PolyShapeFile(self.rc.bounding_box, os.path.join(self.tmpdir, 'shape_overview.shp'), 'shade-overview') shade.add_shade_from_wkt(shade_wkt) self.overview_canvas.add_shape_file(shade) self.overview_canvas.add_shape_file(grid_shape, self.rc.stylesheet.grid_line_color, 1, self.rc.stylesheet.grid_line_width) self.overview_canvas.render() # Create the map canvas for each page indexes = [] for i, (bb, bb_inner) in enumerate(bboxes): # Create the gray shape around the map exterior = shapely.wkt.loads(bb.as_wkt()) interior = shapely.wkt.loads(bb_inner.as_wkt()) shade_wkt = exterior.difference(interior).wkt shade = maplib.shapes.PolyShapeFile( bb, os.path.join(self.tmpdir, 'shade%d.shp' % i), 'shade%d' % i) shade.add_shade_from_wkt(shade_wkt) # Create the contour shade # Area to keep visible interior_contour = shapely.wkt.loads(self.rc.polygon_wkt) # Determine the shade WKT shade_contour_wkt = interior.difference(interior_contour).wkt # Prepare the shade SHP shade_contour = maplib.shapes.PolyShapeFile(bb, os.path.join(self.tmpdir, 'shade_contour%d.shp' % i), 'shade_contour%d' % i) shade_contour.add_shade_from_wkt(shade_contour_wkt) # Create one canvas for the current page map_canvas = MapCanvas(self.rc.stylesheet, 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( os.path.join(self.tmpdir, 'grid%d.shp' % i)) map_canvas.add_shape_file(shade) map_canvas.add_shape_file(shade_contour, self.rc.stylesheet.shade_color_2, self.rc.stylesheet.shade_alpha_2) map_canvas.add_shape_file(grid_shape, self.rc.stylesheet.grid_line_color, self.rc.stylesheet.grid_line_alpha, self.rc.stylesheet.grid_line_width) map_canvas.render() self.pages.append((map_canvas, map_grid)) # Create the index for the current page inside_contour_wkt = interior_contour.intersection(interior).wkt index = StreetIndex(self.db, inside_contour_wkt, self.rc.i18n, page_number=(i + 4)) index.apply_grid(map_grid) indexes.append(index) # Merge all indexes self.index_categories = self._merge_page_indexes(indexes) # Prepare the small map for the front page self._front_page_map = self._prepare_front_page_map(dpi)