From 230e2ccda2c4fcb5cfa93886bbc8dec5c44dad73 Mon Sep 17 00:00:00 2001 From: David Decotigny Date: Thu, 2 Sep 2010 21:20:39 +0200 Subject: [PATCH] Updated doc and simpler object for StreetIndex objects This patch makes the ctor args minimal for the StreetIndex indexer objects, and also drops the ref to the DB after the object has been created. Also cleans up the rendering process a bit (WIP, still). --- ocitysmap2/__init__.py | 60 ++++++++++++++++---------- ocitysmap2/index/__init__.py | 2 +- ocitysmap2/index/indexer.py | 83 +++++++++++++++++++++++++----------- ocitysmap2/renderers.py | 2 +- 4 files changed, 97 insertions(+), 50 deletions(-) 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(),