def extent(self, identifiers=None): """Calculate extent using ogr GetExtent function """ layer = mapnik.Layer(self.layer_name, detect_prj(self.prj)) layer.datasource = mapnik.Shapefile( file=self.layer_filename) ds = osgeo.ogr.Open(self.layer_filename) lyr = ds.GetLayer() lyr.ResetReading() w, e, s, n = lyr.GetExtent() w, s = transform( Proj(detect_prj(self.prj)), google_projection, w, s) e, n = transform( Proj(detect_prj(self.prj)), google_projection, e, n) return { 'north': n, 'west': w, 'south': s, 'east': e}
def layer(self, layer_ids=None, request=None): """Return layer and styles for a shapefile. http://127.0.0.1:8000/map/workspace/1/wms/?LAYERS=basic&SERVICE= WMS&VERSION=1.1.1&REQUEST=GetMap&STYLES=&EXCEPTIONS=application% 2Fvnd.ogc.se_inimage&FORMAT=image%2Fjpeg&SRS=EPSG%3A900913&BBOX= 523838.00391791,6818214.5267836,575010.91942212,6869720.7532931& WIDTH=140&HEIGHT=140 """ layers = [] styles = {} layer = mapnik.Layer(self.layer_name, detect_prj(self.prj)) # TODO: ^^^ translation! logging.debug("Giving shapefile %s to a mapnik layer...", self.layer_filename) layer.datasource = mapnik.Shapefile( file=self.layer_filename) if self.legend_id is not None: legend = self._legend_object style = legend.mapnik_style( value_field=str(self.value_field)) else: # Show layer with default legend. style = self._default_mapnik_style() style_name = str('Area style %s::%s::%s' % ( self.layer_filename, self.legend_id, self.value_field)) styles[style_name] = style layer.styles.append(style_name) layers = [layer] logging.debug("Giving shapefile %s as layer to mapnik...", self.layer_filename) return layers, styles
def search(self, x, y, radius=None): """ Search area, line or point. Make sure that value_field, search_property_id, search_property_name are valid columns in your shapefile. x,y are google coordinates Note: due to mapnik #503 (http://trac.mapnik.org/ticket/503) the search does not work for lines and points. So the implementation was done with shapely. """ logger.debug("Searching coordinates (%0.2f, %0.2f) radius %r..." % (x, y, radius)) if not self.search_property_name: # We don't have anything to return, so don't search. return [] if radius is not None: # Manually make radius smaller # RG, way later: it used to say 0.2 on the line below, but # there were complaints saying that this was too # small. From some manual testing, 1 (the default) is too # large. I'll put 0.8. Obviously a very well argued value. logger.debug("Adjusting radius...") radius = radius * 0.8 transformed_x, transformed_y = transform( google_projection, Proj(detect_prj(self.prj)), x, y) query_point = Point(transformed_x, transformed_y) ds = osgeo.ogr.Open(self.layer_filename) try: lyr = ds.GetLayer() except AttributeError: # #3033 # This one occurs when the file does not exist. logger.error("The search function crashed. Probably due " "to a missing shapefile.") return [] if radius is not None: # The radius needs to be transformed as well, but how? # A transformed square will no longer be a square! # This needs further attention... transformed_x_radius, transformed_y_radius = transform( google_projection, Proj(detect_prj(self.prj)), x + radius, y + radius) radius = max(abs(transformed_x - transformed_x_radius), abs(transformed_y - transformed_y_radius)) lyr.SetSpatialFilterRect( transformed_x - radius, transformed_y - radius, transformed_x + radius, transformed_y + radius) lyr.ResetReading() feat = lyr.GetNextFeature() results = [] while feat is not None: geom = feat.GetGeometryRef() if geom: item = loads(geom.ExportToWkt()) distance = query_point.distance(item) feat_items = feat.items() if not radius or (radius is not None and distance < radius): # Add stripped keys, because column names can contain # spaces after the 'real' name. for key in feat_items.keys(): feat_items[key.strip()] = feat_items[key] # Found an item. if self.search_property_name not in feat_items: # This means that the search_property_name is not a # valid field in the shapefile dbf. logger.error( ('Search: The field "%s" cannot be found in ' 'shapefile "%s". Available fields: %r' 'Check your settings in ' 'lizard_shape.models.Shape.') % (self.search_property_name, self.layer_name, feat_items.keys())) break # You don't have to search other rows. name = str(feat_items[self.search_property_name]) if self.display_fields: if self.display_fields[0]['field'] not in feat_items: # This means that the value_field is not a # valid field in the shapefile dbf. logger.error( ('Search: The field "%s" cannot be found in ' 'shapefile "%s". Check display_fields. ' 'Options are: %s') % (self.display_fields[0]['field'], self.layer_name, feat_items.keys())) break # You don't have to search other rows. name += ' - %s=%s' % ( self.display_fields[0]['name'], str(float_to_string(feat_items[ self.display_fields[0]['field']]))) result = {'distance': distance, 'name': name, 'workspace_item': self.workspace_item} try: result.update( {'google_coords': transform(Proj(detect_prj(self.prj)), google_projection, *item.coords[0])}) except NotImplementedError: logger.warning( "Got a NotImplementedError while transforming " "coordinates from %s to google with pyproj " "for shapefile %s. Not returning google " "coordinates.", self.prj, self.shape) if (self.search_property_id and self.search_property_id in feat_items): result.update( {'identifier': {'id': feat_items[self.search_property_id]}}) else: logger.error("Problem with search_property_id: %s. " "List of available properties: %r" % (self.search_property_id, feat_items.keys())) results.append(result) feat = lyr.GetNextFeature() results = sorted(results, key=lambda a: a['distance']) if len(results) > MAX_SEARCH_RESULTS: logger.info('A lot of results found (%d), just taking top %s.', len(results), MAX_SEARCH_RESULTS) return results[:MAX_SEARCH_RESULTS]