kopia lustrzana https://github.com/hholzgra/ocitysmap
Add an overview page in the multi-page renderer.
* 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 <etienne.loks@peacefrogs.net>stable
rodzic
a99fa35b03
commit
17298cd3fe
|
|
@ -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
|
||||
import pangocairo
|
||||
|
|
@ -41,6 +44,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
|
||||
|
||||
|
|
@ -133,7 +137,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 = \
|
||||
|
|
@ -186,8 +190,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):
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue