def coastlines(self): ''' Draws coastlines on the map. TODO: fill map with sea color if no coastline intersects the map but the area actually is no land mass ''' coastlines = session.query(OSMLine).filter(and_( BBOX_QUERY_COND % ((OSMLine.__table__, ) + self.mapobj.bbox.bounds), OSMLine.natural=='coastline' )).all() coastpolygons = session.query(OSMPolygon).filter(and_( BBOX_QUERY_COND % ((OSMPolygon.__table__, ) + self.mapobj.bbox.bounds), OSMPolygon.natural=='coastline' )).all() # only fill map with sea color if there is a at least one coastline if coastlines or coastpolygons: lines = tuple(wkb.loads(str(cl.geom.geom_wkb)) for cl in coastlines) merged = utils.merge_lines(lines) islands = [] shorelines = [] for line in merged: #: closed rings are islands and must be filled with map background if line.is_ring: islands.append(line) else: inter = line.intersection(self.mapobj.bbox) points = line.intersection(self.mapobj.bbox.exterior) #: only add line to closing process if number of intersections #: with bbox is even. Otherwise we have a incomplete coastline #: which ends in the visible map if points.geom_type == 'MultiPoint' and len(points) % 2 == 0 \ and len(points) > 0: if inter.geom_type == 'LineString': shorelines.append(inter) else: shorelines.extend(inter) #: save all polygon coordinates as numpy arrays and add to islands for island in coastpolygons: islands.append(numpy.array(wkb.loads(str(island.geom.geom_wkb)).exterior)) #: fill water with sea background shore = None for shore in utils.close_coastlines(shorelines, self.mapobj.bbox): self.mapobj.draw_polygon( exterior=numpy.array(shore), background_color=self.stylesheet.sea_background ) #: fill map with sea background if there is no shoreline if shore is None and islands: self.mapobj.draw_background(self.stylesheet.sea_background) #: fill land filled area with map background for island in islands: self.mapobj.draw_polygon( exterior=numpy.array(island), background_color=self.stylesheet.map_background )
def query_objects(self, geom_type): ''' Returns all objects for current scale/geom_type as a 2-dimensional sorted list (according to z-index specified in stylesheet) and sets style as attribute to db objects. :param geom_type: one of ``'point'``, ``'line'`` or ``'polygon'`` :returns: 2-dimensional list containing sorted objects ''' # create 2-dimensional list so objects can be sorted (may be too many # sublists as there probably won't be as many z-index's defined as # MAX_Z_INDEX) results = [list() for _ in xrange(self.stylesheet.MAX_Z_INDEX)] # determine database model class db_class = GEOM_TYPES[geom_type] counter = 0 # iterate over all visible tags and names for tags, columns, conditions in self.iter_query_conditions(geom_type): # simple st_intersects() does not work because this operation # raises an InternalError exception because of invalid geometries # in the OSM database bbox_condition = BBOX_QUERY_COND % ( (db_class.__table__, ) + self.bbox.bounds) objects = session.query( # only get necessary columns to increase performance db_class.geom, *[getattr(db_class, c) for c in tuple(tags) + tuple(columns)] ).filter(and_(bbox_condition, *conditions)).all() #: set style attr to obj and sort according to z-index for obj in objects: counter += 1 tag_value = dict((tag, getattr(obj, tag)) for tag in tags) obj.style = self.stylesheet.get(self.mapobj.scale, geom_type, tag_value) results[obj.style.get('z-index', 0)].append(obj) self.verbose_print('> %s %ss' % (counter, geom_type)) return results