diff --git a/ocitysmap2/__init__.py b/ocitysmap2/__init__.py index bb7b6cb..2815494 100644 --- a/ocitysmap2/__init__.py +++ b/ocitysmap2/__init__.py @@ -111,6 +111,9 @@ class RenderingConfiguration: self.paper_width_mm = None self.paper_height_mm = None + # Setup by Rendering routines from osmid and bounding_box fields: + self.polygon_wkt = None # str (WKT of interest) + class Stylesheet: """ A Stylesheet object defines how the map features will be rendered. It @@ -267,8 +270,9 @@ class OCitySMap: os.rmdir(tmpdir) def get_geographic_info(self, osmids): - """Returns the envelope and area, in 4002 projection, of all the - provided OSM IDs.""" + """Return a list of tuples (one tuple for each specified ID in + osmids) where each tuple contains (osmid, WKT_envelope, + WKT_buildarea)""" # Ensure all OSM IDs are integers, bust cast them back to strings # afterwards. @@ -348,40 +352,52 @@ class OCitySMap: l.info('Rendering with renderer %s in language: %s (rtl: %s).' % (renderer_name, self._i18n.language_code(), config.rtl)) - try: - osmid_geo_info = self.get_geographic_info([config.osmid])[0] - except IndexError: - raise AssertionError, 'OSM ID not found in the database!' + # Determine bounding box and WKT of interest + if config.osmid: + try: + osmid_geo_info = self.get_geographic_info([config.osmid])[0] + except IndexError: + raise AssertionError, 'OSM ID not found in the database!' + + # Define the bbox if not already defined + if not config.bounding_box: + config.bounding_box \ + = coords.BoundingBox.parse_wkt(osmid_geo_info[1]) + + # Update the polygon WKT of interest + config.polygon_wkt = osmid_geo_info[2] + else: + # No OSM ID provided => use specified bbox + config.polygon_wkt = config.bounding_box.as_wkt() # Make sure we have a bounding box - config.bounding_box = (config.bounding_box or - coords.BoundingBox.parse_wkt(osmid_geo_info[1])) + assert config.bounding_box is not None + assert config.polygon_wkt is not None + + # Prepare the index + street_index = index.indexer.StreetIndex(self._db, + config.polygon_wkt, + self._i18n) # Create a temporary directory for all our shape files tmpdir = tempfile.mkdtemp(prefix='ocitysmap') l.debug('Rendering in temporary directory %s' % tmpdir) + # Prepare the main renderer renderer_cls = renderers.get_renderer_class_by_name(renderer_name) renderer = renderer_cls(config, tmpdir) renderer.create_map_canvas() - if config.osmid: - polygon = osmid_geo_info[2] - if polygon: - shade_wkt = self._get_shade_wkt( - renderer.canvas.get_actual_bounding_box(), - polygon) - renderer.render_shade(shade_wkt) - else: - polygon = None + shade_wkt = self._get_shade_wkt( + renderer.canvas.get_actual_bounding_box(), + config.polygon_wkt) + renderer.add_shade(shade_wkt) renderer.canvas.render() - street_index = index.indexer.StreetIndex(self._db, config.osmid, - renderer.canvas.get_actual_bounding_box(), - self._i18n, renderer.grid, polygon) - street_index_renderer = index.StreetIndexRenderer(self._i18n, - street_index.categories) + street_index_renderer = index.StreetIndexRenderer( + self._i18n, + street_index.categories) try: for output_format in output_formats: diff --git a/ocitysmap2/index/__init__.py b/ocitysmap2/index/__init__.py index 358acb3..ed40d3d 100644 --- a/ocitysmap2/index/__init__.py +++ b/ocitysmap2/index/__init__.py @@ -58,7 +58,7 @@ if __name__ == '__main__': host='localhost', database='maposmatic') - street_index = StreetIndex(db, None, None, i18n, None, bbox.as_wkt()) + street_index = StreetIndex(db, bbox.as_wkt(), i18n) print street_index.categories # Render the items diff --git a/ocitysmap2/index/indexer.py b/ocitysmap2/index/indexer.py index ad29d05..42f827c 100644 --- a/ocitysmap2/index/indexer.py +++ b/ocitysmap2/index/indexer.py @@ -44,18 +44,24 @@ l = logging.getLogger('ocitysmap') class StreetIndex: - def __init__(self, db, osmid, bounding_box, i18n, grid, polygon_wkt): - self._db = db - self._osmid = osmid - self._bounding_box = bounding_box + def __init__(self, db, polygon_wkt, i18n): + """ + Prepare the index of the streets inside the given WKT. This + constructor will perform all the SQL queries. + + Args: + db (psycopg2 DB): The GIS database + polygon_wkt (str): The WKT of the surrounding polygon of interest + i18n (i18n.i18n): Internationalization configuration + + Note: All the arguments have to be provided ! + """ self._i18n = i18n - self._grid = grid - self._polygon_wkt = polygon_wkt # Build the contents of the index self._categories = \ - (self._build_street_index_nogrid() - + self._build_amenities_index_nogrid()) + (self._list_streets(db, polygon_wkt) + + self._list_amenities(db, polygon_wkt)) if not self._categories: raise IndexEmptyError("Nothing to index") @@ -66,8 +72,8 @@ class StreetIndex: def apply_grid(self, grid): """ - Fix the label location_str field by mapping the streets to the - given grid. + Update the location_str field of the streets and amenities by + mapping them onto the given grid. Args: grid (ocitysmap2.Grid): the Grid object from which we @@ -120,12 +126,21 @@ class StreetIndex: fd.close() def _get_selected_amenities(self): - # Amenities to retrieve from DB, a list of string tuples: - # 1. Category, displayed headers in the final index - # 2. db_amenity, description string stored in the DB - # 3. Label, text to display in the index for this amenity + """ + Return the kinds of amenities to retrieve from DB as a list of + string tuples: + 1. Category, displayed headers in the final index + 2. db_amenity, description string stored in the DB + 3. Label, text to display in the index for this amenity + + Note: This has to be a function because gettext() has to be + called, which takes i18n into account... It cannot be + statically defined as a class attribute for example. + """ + selected_amenities = [ - (_(u"Places of worship"), "place_of_worship", _(u"Place of worship")), + (_(u"Places of worship"), "place_of_worship", + _(u"Place of worship")), (_(u"Education"), "kindergarten", _(u"Kindergarten")), (_(u"Education"), "school", _(u"School")), (_(u"Education"), "college", _(u"College")), @@ -194,16 +209,20 @@ class StreetIndex: return result - def _build_street_index_nogrid(self): - """Get the list of streets in the administrative area if city - is defined or in the bounding box otherwise. Don't try to map - these streets onto the grid of squares. + def _list_streets(self, db, polygon_wkt): + """Get the list of streets inside the given polygon. Don't + try to map them onto the grid of squares (there location_str + field remains undefined). + + Args: + db (psycopg2 DB): The GIS database + polygon_wkt (str): The WKT of the surrounding polygon of interest Returns a list of commons.IndexCategory objects, with their IndexItems having no specific grid square location """ - cursor = self._db.cursor() + cursor = db.cursor() l.info("Getting streets (no grid)...") # POstGIS >= 1.5.0 for this to work: @@ -223,7 +242,7 @@ from group by name ---, street_kind -- (optional) order by name) as foo; """ % dict(wkb_limits = ("st_transform(GeomFromText('%s', 4002), 900913)" - % (self._polygon_wkt or self._bounding_box.as_wkt()))) + % (polygon_wkt,))) l.debug("Street query (nogrid): %s" % query) @@ -234,8 +253,21 @@ from return self._convert_street_index(sl) - def _build_amenities_index_nogrid(self): - cursor = self._db.cursor() + + def _list_amenities(self, db, polygon_wkt): + """Get the list of amenities inside the given polygon. Don't + try to map them onto the grid of squares (there location_str + field remains undefined). + + Args: + db (psycopg2 DB): The GIS database + polygon_wkt (str): The WKT of the surrounding polygon of interest + + Returns a list of commons.IndexCategory objects, with their IndexItems + having no specific grid square location + """ + + cursor = db.cursor() result = [] for catname, db_amenity, label in self._get_selected_amenities(): @@ -269,7 +301,7 @@ from ( order by amenity_name""" \ % {'amenity': _sql_escape_unicode(db_amenity), 'wkb_limits': ("st_transform(GeomFromText('%s', 4002), 900913)" - % (self._polygon_wkt or self._bounding_box.as_wkt()))} + % (polygon_wkt,))} l.debug("Amenity query for for %s/%s (nogrid): %s" \ @@ -326,8 +358,7 @@ if __name__ == "__main__": # Paris bbox # limits_wkt = """POLYGON((2.22405964791711 48.8155243047565,2.22405964791711 48.9021584078545,2.46979772401737 48.9021584078545,2.46979772401737 48.8155243047565,2.22405964791711 48.8155243047565))""" - street_index = StreetIndex(db, None, None, i18n, None, - limits_wkt) + street_index = StreetIndex(db, limits_wkt, i18n) print "=> Got %d categories, total %d items" \ % (len(street_index.categories), diff --git a/ocitysmap2/renderers.py b/ocitysmap2/renderers.py index f12a95f..c19b430 100644 --- a/ocitysmap2/renderers.py +++ b/ocitysmap2/renderers.py @@ -211,7 +211,7 @@ class Renderer: ctx.restore() - def render_shade(self, shade_wkt): + def add_shade(self, shade_wkt): # Add the grey shade shade_shape = shapes.PolyShapeFile( self.canvas.get_actual_bounding_box(),