diff options
Diffstat (limited to 'chimere/utils.py')
-rw-r--r-- | chimere/utils.py | 112 |
1 files changed, 96 insertions, 16 deletions
diff --git a/chimere/utils.py b/chimere/utils.py index a5772d7..607ec36 100644 --- a/chimere/utils.py +++ b/chimere/utils.py @@ -39,7 +39,7 @@ import zipfile from osgeo import ogr, osr from osmapi import OsmApi -import overpass +import overpy from lxml import etree from django.conf import settings @@ -964,7 +964,7 @@ RE_HOOK = re.compile('\[([^\]]*)\]') # TODO: manage deleted item from OSM -class OSMManager(JsonManager): +class OSMManager(ImportManager): """ OSM importer/exporter The source url is a path to an OSM file or a Overpass url @@ -972,27 +972,107 @@ class OSMManager(JsonManager): """ default_source = settings.CHIMERE_OVERPASS_URL + def _get_attributes(self, item, filtr): + dct = {} + for k in filtr: + value = item.tags.get(filtr[k], None) + if value: + dct[k] = value + return dct + def parse_overpass(self): - api = overpass.API(endpoint=self.default_source, - timeout=600) - response = api.get(self.importer_instance.source) + from chimere.models import Marker, Route, Polygon + + new_item, updated_item, msg = 0, 0, '' + + api = overpy.Overpass(url=self.default_source) - if not response or "features" not in response: + if not self.importer_instance.source: + return ( + new_item, updated_item, + _("Bad configuration: a source query must be defined")) + + try: + result = api.query(self.importer_instance.source) + except overpy.exception.OverpassBadRequest as e: + return ( + 0, 0, + str( + _("Bad overpass query: {}.") + ).format(e) + ) + except overpy.exception.OverPyException as e: return ( 0, 0, str( - _("Bad response from OSM server: {}. Check your overpass " - "string and that overpass servre is up.") - ).format(self.default_source) + _("Request error from OSM Overpass server: {}.") + ).format(e) ) - default_filtr = { - 'coordinates': {'geometry': 'coordinates'}, - 'id': 'id', - 'name': {'properties': 'name'}, - 'geom_type': {'geometry': 'type'} - } - return self._parse_json(response['features'], default_filtr) + filtr = {} + if self.importer_instance.filtr: + try: + filtr = json.JSONDecoder().decode(self.importer_instance.filtr) + except ValueError: + return ( + new_item, updated_item, + _("Bad configuration: filter field must be a valid " + "JSON string")) + + filtr['name'] = "name" + + default_dct = {'origin': self.importer_instance.origin, + 'license': self.importer_instance.license, + 'description': ""} + + if 'prefix_name' in filtr: + default_dct['name'] = filtr.pop('prefix_name') + if 'prefix_description' in filtr: + default_dct['description'] = filtr.pop('prefix_description') + + for way in result.ways: + dct = deepcopy(default_dct) + dct.update(self._get_attributes(way, filtr)) + pl_id = "OSM-way-{}".format(node.id) + + if not way.nodes or len(way.nodes) == 1: + # not a real way + continue + + if way.nodes[0].id == way.nodes[-1].id: + # is a closed way + if len(way.nodes) == 2: + # not a real way + continue + cls = Polygon + wkt_base = "SRID=4326;POLYGON((%s))" + else: + cls = Route + wkt_base = "SRID=4326;LINESTRING(%s)" + + dct[cls.geom_attr] = wkt_base % ",".join( + ["{} {}".format(node.lon, node.lat) + for node in way.get_nodes(resolve_missing=True)] + ) + it, updated, created = self.create_or_update_item(cls, dct, pl_id) + if updated: + updated_item += 1 + if created: + new_item += 1 + + for node in result.nodes: + cls = Marker + dct = deepcopy(default_dct) + dct.update(self._get_attributes(node, filtr)) + pl_id = "OSM-node-{}".format(node.id) + dct['point'] = 'SRID=4326;POINT({} {})'.format(node.lon, node.lat) + it, updated, created = self.create_or_update_item(cls, dct, pl_id) + if updated: + updated_item += 1 + if created: + new_item += 1 + + return new_item, updated_item, msg def get(self): """ |