[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Maposmatic-dev] [PATCH 13/22] multi-page: add in dex rendering with a n
From: |
Thomas Petazzoni |
Subject: |
[Maposmatic-dev] [PATCH 13/22] multi-page: add in dex rendering with a new MultiPageStreetIndexRenderer cl ass |
Date: |
Fri, 30 Mar 2012 13:00:30 +0200 |
Signed-off-by: Thomas Petazzoni <address@hidden>
---
ocitysmap2/indexlib/multi_page_renderer.py | 219 +++++++++++++++++++++++++++
ocitysmap2/layoutlib/multi_page_renderer.py | 14 ++-
2 files changed, 232 insertions(+), 1 deletions(-)
create mode 100644 ocitysmap2/indexlib/multi_page_renderer.py
diff --git a/ocitysmap2/indexlib/multi_page_renderer.py
b/ocitysmap2/indexlib/multi_page_renderer.py
new file mode 100644
index 0000000..c48f972
--- /dev/null
+++ b/ocitysmap2/indexlib/multi_page_renderer.py
@@ -0,0 +1,219 @@
+# -*- coding: utf-8 -*-
+
+# ocitysmap, city map and street index generator from OpenStreetMap data
+# Copyright (C) 2012 David Mentré
+# Copyright (C) 2012 Thomas Petazzoni
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import cairo
+import ocitysmap2.layoutlib.commons as UTILS
+import pango
+import pangocairo
+
+class MultiPageStreetIndexRenderer:
+ """
+ The MultiPageStreetIndexRenderer class encapsulates all the logic
+ related to the rendering of the street index on multiple pages
+ """
+
+ # ctx: Cairo context
+ # surface: Cairo surface
+ def __init__(self, i18n, ctx, surface, index_categories, rendering_area):
+ self._i18n = i18n
+ self.ctx = ctx
+ self.surface = surface
+ self.index_categories = index_categories
+ self.rendering_area_x = rendering_area[0]
+ self.rendering_area_y = rendering_area[1]
+ self.rendering_area_w = rendering_area[2]
+ self.rendering_area_h = rendering_area[3]
+
+ def _create_layout_with_font(self, pc, font_desc):
+ layout = pc.create_layout()
+ layout.set_font_description(font_desc)
+ font = layout.get_context().load_font(font_desc)
+ font_metric = font.get_metrics()
+
+ fascent = float(font_metric.get_ascent()) / pango.SCALE
+ fheight = float((font_metric.get_ascent() + font_metric.get_descent())
+ / pango.SCALE)
+ em = float(font_metric.get_approximate_char_width()) / pango.SCALE
+
+ return layout, fascent, fheight, em
+
+ def render(self, dpi = UTILS.PT_PER_INCH):
+ print self.index_categories
+ self.ctx.save()
+
+ # Draw a filled rectangle as the background (to be removed,
+ # only for debugging purposes)
+ self.ctx.save()
+ self.ctx.set_source_rgb(.98,.98,.98)
+ self.ctx.rectangle(UTILS.convert_pt_to_dots(self.rendering_area_x,
dpi),
+ UTILS.convert_pt_to_dots(self.rendering_area_y,
dpi),
+ self.rendering_area_w,
+ self.rendering_area_h)
+ self.ctx.fill()
+ self.ctx.restore()
+
+ # Create a PangoCairo context for drawing to Cairo
+ pc = pangocairo.CairoContext(self.ctx)
+
+ header_fd = pango.FontDescription("Georgia Bold 14")
+ label_fd = pango.FontDescription("DejaVu 10")
+
+ header_layout, header_fascent, header_fheight, header_em = \
+ self._create_layout_with_font(pc, header_fd)
+ label_layout, label_fascent, label_fheight, label_em = \
+ self._create_layout_with_font(pc, label_fd)
+
+ # By OCitysmap's convention, the default resolution is 72 dpi,
+ # which maps to the default pangocairo resolution (96 dpi
+ # according to pangocairo docs). If we want to render with
+ # another resolution (different from 72), we have to scale the
+ # pangocairo resolution accordingly:
+ pangocairo.context_set_resolution(label_layout.get_context(),
+ 96.*dpi/UTILS.PT_PER_INCH)
+ pangocairo.context_set_resolution(header_layout.get_context(),
+ 96.*dpi/UTILS.PT_PER_INCH)
+
+ margin = label_em
+
+ # We have three columns
+ COLUMNS_COUNT = 3
+ column_width = self.rendering_area_w / COLUMNS_COUNT
+
+ label_layout.set_width(int(UTILS.convert_pt_to_dots(
+ (column_width - margin) * pango.SCALE, dpi)))
+ header_layout.set_width(int(UTILS.convert_pt_to_dots(
+ (column_width - margin) * pango.SCALE, dpi)))
+
+ if not self._i18n.isrtl():
+ orig_offset_x = offset_x = margin/2.
+ orig_delta_x = delta_x = column_width
+ else:
+ orig_offset_x = offset_x = self.rendering_area_w - column_width +
margin/2.
+ orig_delta_x = delta_x = - column_width
+
+ actual_n_cols = 0
+ offset_y = margin/2.
+
+ for category in self.index_categories:
+ if ( offset_y + header_fheight + label_fheight
+ + margin/2. > self.rendering_area_h ):
+ offset_y = margin/2.
+ offset_x += delta_x
+ actual_n_cols += 1
+
+ if actual_n_cols == COLUMNS_COUNT:
+ actual_n_cols = 0
+ offset_y = margin / 2.
+ offset_x = orig_offset_x
+ delta_x = orig_delta_x
+ self.surface.show_page()
+
+ category.draw(self._i18n.isrtl(), self.ctx, pc, header_layout,
+ UTILS.convert_pt_to_dots(header_fascent, dpi),
+ UTILS.convert_pt_to_dots(header_fheight, dpi),
+ UTILS.convert_pt_to_dots(self.rendering_area_x
+ + offset_x, dpi),
+ UTILS.convert_pt_to_dots(self.rendering_area_y
+ + offset_y
+ + header_fascent, dpi))
+
+ offset_y += header_fheight
+
+ for street in category.items:
+ if ( offset_y + label_fheight + margin/2.
+ > self.rendering_area_h ):
+ offset_y = margin/2.
+ offset_x += delta_x
+ actual_n_cols += 1
+
+ if actual_n_cols == COLUMNS_COUNT:
+ actual_n_cols = 0
+ offset_y = margin / 2.
+ offset_x = orig_offset_x
+ delta_x = orig_delta_x
+ self.surface.show_page()
+
+ print street.label
+ street.draw(self._i18n.isrtl(), self.ctx, pc, label_layout,
+ UTILS.convert_pt_to_dots(label_fascent, dpi),
+ UTILS.convert_pt_to_dots(label_fheight, dpi),
+ UTILS.convert_pt_to_dots(self.rendering_area_x
+ + offset_x, dpi),
+ UTILS.convert_pt_to_dots(self.rendering_area_y
+ + offset_y
+ + label_fascent, dpi))
+
+ offset_y += label_fheight
+
+
+ self.ctx.restore()
+ pass
+
+if __name__ == '__main__':
+ import random
+ import string
+ import commons
+
+ width = 72*21./2.54
+ height = 72*29.7/2.54
+
+ surface = cairo.PDFSurface('/tmp/myindex_render.pdf', width, height)
+
+ random.seed(42)
+
+ def rnd_str(max_len, letters = string.letters):
+ return ''.join(random.choice(letters)
+ for i in xrange(random.randint(1, max_len)))
+
+ class i18nMock:
+ def __init__(self, rtl):
+ self.rtl = rtl
+ def isrtl(self):
+ return self.rtl
+
+ streets = []
+ for i in ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'Schools', 'Public buildings']:
+ items = []
+ for label, location_str in [(rnd_str(20).capitalize(),
+ '%s%d-%s%d' \
+ % (rnd_str(2,
+ string.ascii_uppercase),
+ random.randint(1,19),
+ rnd_str(2,
+ string.ascii_uppercase),
+ random.randint(1,19),
+ ))]*random.randint(1, 20):
+ item = commons.IndexItem(label, None, None)
+ item.location_str = location_str
+ item.page_number = random.randint(1, 100)
+ items.append(item)
+ streets.append(commons.IndexCategory(i, items))
+
+ ctxtmp = cairo.Context(surface)
+
+ rendering_area = \
+ (15, 15, width - 2 * 15, height - 2 * 15)
+
+ mpsir = MultiPageStreetIndexRenderer(i18nMock(False), ctxtmp, surface,
+ streets, rendering_area)
+ mpsir.render()
+
+ surface.finish()
diff --git a/ocitysmap2/layoutlib/multi_page_renderer.py
b/ocitysmap2/layoutlib/multi_page_renderer.py
index c214f60..7a046e3 100644
--- a/ocitysmap2/layoutlib/multi_page_renderer.py
+++ b/ocitysmap2/layoutlib/multi_page_renderer.py
@@ -39,6 +39,7 @@ from abstract_renderer import Renderer
from ocitysmap2.maplib.map_canvas import MapCanvas
from ocitysmap2.maplib.grid import Grid
from indexlib.indexer import StreetIndex
+from indexlib.multi_page_renderer import MultiPageStreetIndexRenderer
import ocitysmap2
import commons
@@ -227,7 +228,7 @@ class MultiPageRenderer(Renderer):
indexes.append(index)
self.pages.append((map_canvas, map_grid))
- self.index_data = self._merge_page_indexes(indexes)
+ self.index_categories = self._merge_page_indexes(indexes)
def _merge_page_indexes(self, indexes):
# First, we split street categories and "other" categories,
@@ -354,6 +355,17 @@ class MultiPageRenderer(Renderer):
ctx.restore()
cairo_surface.show_page()
+
+ mpsir = MultiPageStreetIndexRenderer(self.rc.i18n,
+ ctx, cairo_surface,
+ self.index_categories,
+ (Renderer.PRINT_SAFE_MARGIN_PT,
+ Renderer.PRINT_SAFE_MARGIN_PT,
+ self._usable_area_width_pt,
+ self._usable_area_height_pt))
+
+ mpsir.render()
+
cairo_surface.flush()
print "I'm rendering"
pass
--
1.7.4.1
- [Maposmatic-dev] [PATCH 06/22] multi-page: add grid and grid labels, (continued)
- [Maposmatic-dev] [PATCH 06/22] multi-page: add grid and grid labels, Thomas Petazzoni, 2012/03/30
- [Maposmatic-dev] [PATCH 05/22] multi-page: differentiate overlap margin and grayed margin, Thomas Petazzoni, 2012/03/30
- [Maposmatic-dev] [PATCH 04/22] multi-page: show page number at the bottom of each page, Thomas Petazzoni, 2012/03/30
- [Maposmatic-dev] [PATCH 07/22] indexlib: add page_number to IndexItem, Thomas Petazzoni, 2012/03/30
- [Maposmatic-dev] [PATCH 02/22] coords: add BoundingBox::as_javascript() method, Thomas Petazzoni, 2012/03/30
- [Maposmatic-dev] [PATCH 08/22] indexlib: do not raise exception when index is empty, Thomas Petazzoni, 2012/03/30
- [Maposmatic-dev] [PATCH 09/22] indexlib: villages section is not of street type, Thomas Petazzoni, 2012/03/30
- [Maposmatic-dev] [PATCH 10/22] renderers: pass the db connection to the Renderer class constructor, Thomas Petazzoni, 2012/03/30
- [Maposmatic-dev] [PATCH 12/22] indexlib: render page number as part of the street/amenity location, Thomas Petazzoni, 2012/03/30
- [Maposmatic-dev] [PATCH 15/22] indexlib: properly differentiate the page_number=None and page_number=0 cases, Thomas Petazzoni, 2012/03/30
- [Maposmatic-dev] [PATCH 13/22] multi-page: add in dex rendering with a new MultiPageStreetIndexRenderer cl ass,
Thomas Petazzoni <=
- [Maposmatic-dev] [PATCH 11/22] multi-page: prepare data for index generation, Thomas Petazzoni, 2012/03/30
- [Maposmatic-dev] [PATCH 14/22] multi-page: remove multiple debugging outputs, Thomas Petazzoni, 2012/03/30
- [Maposmatic-dev] [PATCH 18/22] indexlib: add min_drawing_width() method, Thomas Petazzoni, 2012/03/30
- [Maposmatic-dev] [PATCH 19/22] MultiPageStreetIndexRenderer: remove debugging background rectangle, Thomas Petazzoni, 2012/03/30
- [Maposmatic-dev] [PATCH 16/22] multi-page: in the street index, start page numbering at 1, Thomas Petazzoni, 2012/03/30
- [Maposmatic-dev] [PATCH 21/22] MultiPageStreetIndexRenderer: automatically compute the number of columns, Thomas Petazzoni, 2012/03/30
- [Maposmatic-dev] [PATCH 20/22] MultiPageStreetIndexRenderer: reduce size of default font, Thomas Petazzoni, 2012/03/30
- [Maposmatic-dev] [PATCH 22/22] multi-page: minor fixups for compatibility with Gaël's work to remo ve the scaling, Thomas Petazzoni, 2012/03/30
- [Maposmatic-dev] [PATCH 17/22] index for multi-page: improve page_number handling, Thomas Petazzoni, 2012/03/30
- Re: [Maposmatic-dev] Implementation of a multi-page renderer, Jeroen van Rijn, 2012/03/30