maposmatic-dev
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]