maposmatic-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Maposmatic-dev] [PATCH 1/5] Add an overview page in the multi-page rend


From: Étienne Loks
Subject: [Maposmatic-dev] [PATCH 1/5] Add an overview page in the multi-page renderer.
Date: Fri, 30 Mar 2012 18:51:17 +0200

 * get the right bounding box
 * create the overview canvas
 * draw the map and the appropriate shade
 * draw boxes for each pages (OverwiewGrid)
 * add the overview to the list of pages to be rendered

Signed-off-by: Étienne Loks <address@hidden>
---
 ocitysmap2/layoutlib/multi_page_renderer.py |   47 +++++++++++-
 ocitysmap2/maplib/overview_grid.py          |  103 +++++++++++++++++++++++++++
 ocitysmap2/maplib/shapes.py                 |   29 ++++++++
 3 files changed, 176 insertions(+), 3 deletions(-)
 create mode 100644 ocitysmap2/maplib/overview_grid.py

diff --git a/ocitysmap2/layoutlib/multi_page_renderer.py 
b/ocitysmap2/layoutlib/multi_page_renderer.py
index 7645ed1..288f956 100644
--- a/ocitysmap2/layoutlib/multi_page_renderer.py
+++ b/ocitysmap2/layoutlib/multi_page_renderer.py
@@ -28,7 +28,10 @@ import tempfile
 import math
 import sys
 import cairo
-import mapnik
+try:
+    import mapnik2 as mapnik
+except ImportError:
+    import mapnik
 import coords
 import locale
 
@@ -38,6 +41,7 @@ from abstract_renderer import Renderer
 
 from ocitysmap2.maplib.map_canvas import MapCanvas
 from ocitysmap2.maplib.grid import Grid
+from ocitysmap2.maplib.overview_grid import OverviewGrid
 from indexlib.indexer import StreetIndex
 from indexlib.multi_page_renderer import MultiPageStreetIndexRenderer
 
@@ -130,7 +134,7 @@ class MultiPageRenderer(Renderer):
             self._usable_area_height_pt + (self._usable_area_height_pt - 
overlap_margin_pt) * (nb_pages_height - 1)
 
         # Convert this paper area available in the number of Mercator
-        # meters that can we rendered on the map
+        # 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 = \
@@ -183,8 +187,45 @@ class MultiPageRenderer(Renderer):
         # for i, (bb, bb_inner) in enumerate(bboxes):
         #    print bb.as_javascript(name="p%d" % i)
 
-        # Create the map canvas for each page
         self.pages = []
+        # Create an overview map
+
+        # Create the gray shape around the map
+        first_bbox, last_bbox = bboxes[0][0], bboxes[-1][0]
+        overview_coord = list(first_bbox.get_top_left()) + \
+                         list(last_bbox.get_bottom_right())
+        overview_bb = coords.BoundingBox(*overview_coord
+                           ).create_expanded(0.001, 0.001)
+
+        exterior = shapely.wkt.loads(overview_bb.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)
+
+        # Create the grid
+        map_grid = OverviewGrid(overview_bb,
+                     [bb for bb, bb_inner in bboxes], self.rc.i18n.isrtl())
+
+        grid_shape = map_grid.generate_shape_file(
+                    os.path.join(self.tmpdir, 'grid_overview.shp'))
+
+        # Create one canvas for the current page
+        map_canvas = MapCanvas(self.rc.stylesheet,
+                               overview_bb, graphical_ratio=None)
+
+        map_canvas.add_shape_file(shade)
+        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 map canvas for each page
         indexes = []
         for i, (bb, bb_inner) in enumerate(bboxes):
 
diff --git a/ocitysmap2/maplib/overview_grid.py 
b/ocitysmap2/maplib/overview_grid.py
new file mode 100644
index 0000000..d196036
--- /dev/null
+++ b/ocitysmap2/maplib/overview_grid.py
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+
+# ocitysmap, city map and street index generator from OpenStreetMap data
+
+import logging
+import math
+
+import shapes
+
+l = logging.getLogger('ocitysmap')
+
+class OverviewGrid:
+    """
+    The OverviewGrid class draw the grid overlayed on the overview map of a
+    multi-page render.
+    """
+
+    def __init__(self, bounding_box, pages_bounding_boxes, rtl=False):
+        """Creates a new grid for the given bounding boxes.
+
+        Args:
+            bounding_box (coords.BoundingBox): the map bounding box.
+            bounding_box (list of coords.BoundingBox): bounding boxes of the
+                pages.
+            rtl (boolean): whether the map is rendered in right-to-left mode or
+                not. Defaults to False.
+        """
+
+        self._bbox = bounding_box
+        self._pages_bbox = pages_bounding_boxes
+        self.rtl   = rtl
+        self._height_m, self._width_m = bounding_box.spheric_sizes()
+
+        l.info('Laying out of overview grid on %.1fx%.1fm area...' %
+               (self._width_m, self._height_m))
+
+        self._pages_wkt = [bb.as_wkt() for bb in self._pages_bbox]
+
+        self.horiz_count = 1
+        self.vert_count = 1
+        self.horizontal_labels = ['plouf']
+        self.vertical_labels = ['plouf']
+
+    def generate_shape_file(self, filename):
+        """Generates the grid shapefile with all the horizontal and
+        vertical lines added.
+
+        Args:
+            filename (string): path to the temporary shape file that will be
+                generated.
+        Returns the ShapeFile object.
+        """
+
+        # Use a slightly larger bounding box for the shape file to accomodate
+        # for the small imprecisions of re-projecting.
+        g = shapes.BoxShapeFile(self._bbox.create_expanded(0.001, 0.001),
+                                 filename, 'grid')
+        map(g.add_box, self._pages_bbox)
+        return g
+
+    def _gen_horizontal_square_label(self, x):
+        """Generates a human-readable label for the given horizontal square
+        number. For example:
+             1 -> A
+             2 -> B
+            26 -> Z
+            27 -> AA
+            28 -> AB
+            ...
+        """
+        if self.rtl:
+            x = len(self._vertical_lines) - x
+
+        label = ''
+        while x != -1:
+            label = chr(ord('A') + x % 26) + label
+            x = x/26 - 1
+        return label
+
+    def _gen_vertical_square_label(self, x):
+        """Generate a human-readable label for the given vertical square
+        number. Since we put numbers verticaly, this is simply x+1."""
+        return str(x + 1)
+
+    def get_location_str(self, lattitude, longitude):
+        """
+        Translate the given lattitude/longitude (EPSG:4326) into a
+        string of the form "CA42"
+        """
+        hdelta = min(abs(longitude - self._bbox.get_top_left()[1]),
+                     self._horiz_angle_span)
+        hlabel = self.horizontal_labels[int(hdelta / self._horiz_unit_angle)]
+
+        vdelta = min(abs(lattitude - self._bbox.get_top_left()[0]),
+                     self._vert_angle_span)
+        vlabel = self.vertical_labels[int(vdelta / self._vert_unit_angle)]
+
+        return "%s%s" % (hlabel, vlabel)
+
+
+if __name__ == "__main__":
+    logging.basicConfig(level=logging.DEBUG)
+    pass
diff --git a/ocitysmap2/maplib/shapes.py b/ocitysmap2/maplib/shapes.py
index a4739f1..fe915fd 100644
--- a/ocitysmap2/maplib/shapes.py
+++ b/ocitysmap2/maplib/shapes.py
@@ -125,6 +125,35 @@ class LineShapeFile(_ShapeFile):
         self._add_feature(line)
         return self
 
+class BoxShapeFile(LineShapeFile):
+    """
+    Shape file for Box geometries.
+    """
+
+    def add_box(self, box):
+        top_left, bottom_right = box.get_top_left(), box.get_bottom_right()
+
+        line = ogr.Geometry(type = ogr.wkbLineString)
+        line.AddPoint_2D(*list(reversed(top_left)))
+        line.AddPoint_2D(bottom_right[1], top_left[0])
+        self._add_feature(line)
+
+        line = ogr.Geometry(type = ogr.wkbLineString)
+        line.AddPoint_2D(bottom_right[1], top_left[0])
+        line.AddPoint_2D(*list(reversed(bottom_right)))
+        self._add_feature(line)
+
+        line = ogr.Geometry(type = ogr.wkbLineString)
+        line.AddPoint_2D(*list(reversed(bottom_right)))
+        line.AddPoint_2D(top_left[1], bottom_right[0])
+        self._add_feature(line)
+
+        line = ogr.Geometry(type = ogr.wkbLineString)
+        line.AddPoint_2D(top_left[1], bottom_right[0])
+        line.AddPoint_2D(*list(reversed(top_left)))
+        self._add_feature(line)
+        return self
+
 class PolyShapeFile(_ShapeFile):
     """
     Shape file for Polygon geometries.
-- 
1.7.9.1




reply via email to

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