From ebedee01b48657426a00c9f38195ab82c33cf3d9 Mon Sep 17 00:00:00 2001 From: "Michael H. Arnold" Date: Sun, 2 Nov 2014 20:14:51 -0800 Subject: [PATCH 1/2] First crack at geoJSON output TODO: retrieve missing nodes referenced in ways to get their coords. --- .gitignore | 10 +++++++--- overpass/api.py | 52 ++++++++++++++++++++++++++++++++++++++++++------ requirements.txt | 1 - setup.py | 2 +- test_api.py | 21 +++++++++++++++++-- 5 files changed, 73 insertions(+), 13 deletions(-) delete mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore index e7817f364fd..803a5409b8e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,8 @@ +*~ +*.swp +.DS_Store *.pyc -build -dist -overpass.egg-info \ No newline at end of file + +/build/ +/dist/ +/*.egg-info diff --git a/overpass/api.py b/overpass/api.py index b305581aa11..80e3b6f2914 100644 --- a/overpass/api.py +++ b/overpass/api.py @@ -1,7 +1,8 @@ import sys import requests import json -from shapely.geometry import mapping, Point +import geojson +#from shapely.geometry import mapping, Point class API(object): @@ -96,10 +97,47 @@ def _GetFromOverpass(self, query): return r.text def _asGeoJSON(self, elements): - """construct geoJSON from elements""" + """ + Construct geoJSON from elements + TODO: Add secondary overpass call to get coords for ways for nodes not included in elements. + """ + node_elements_by_id = {} + + # index node elements by id + for elem in elements: + if elem["type"] == "node": + node_elements_by_id[elem["id"]] = elem + + features = [] + for elem in elements: + elem_type = elem["type"] + if elem["type"] == "node": + geometry=geojson.Point((elem["lon"], elem["lat"])) + elif elem["type"] == "way": + points = [] + for node_id in elem["nodes"]: + node_elem = node_elements_by_id.get(node_id) + if node_elem: + point = (node_elem["lon"], node_elem["lat"]) + points.append(point) + else + print 'WARNING _asGeoJson skipping missing node ref in way + geometry = geojson.LineString(points) + else: + continue + + feature = geojson.Feature( + id=elem["id"], + geometry=geometry, + properties=elem.get("tags")) + features.append(feature) + + return geojson.FeatureCollection(features) + +''' nodes = [{ "id": elem.get("id"), - "tags": elem.get("tags"), + "tags": elem.get("tags") "geom": Point(elem["lon"], elem["lat"])} for elem in elements if elem["type"] == "node"] ways = [{ @@ -107,12 +145,14 @@ def _asGeoJSON(self, elements): "tags": elem.get("tags"), "nodes": elem.get("nodes")} for elem in elements if elem["type"] == "way"] - print nodes - print ways +''' + + + class OverpassException(Exception): def __init__(self, status_code, message): self.status_code = status_code self.message = message def __str__(self): - return json.dumps({'status': self.status_code, 'message': self.message}) \ No newline at end of file + return json.dumps({'status': self.status_code, 'message': self.message}) diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 44e68c921ec..00000000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -requests>=2.3.0 \ No newline at end of file diff --git a/setup.py b/setup.py index 941fd05a30e..00169660516 100644 --- a/setup.py +++ b/setup.py @@ -11,5 +11,5 @@ download_url='https://github.com/mvexel/overpass-api-python-wrapper/tarball/0.0.1', keywords=['openstreetmap', 'overpass', 'wrapper'], classifiers=[], - install_requires=['requests>=2.3.0', 'shapely>=1.4.3'], + install_requires=['requests>=2.3.0', 'geojson>=1.0.9'], ) diff --git a/test_api.py b/test_api.py index 2154f6c8f62..3e02230651a 100644 --- a/test_api.py +++ b/test_api.py @@ -1,9 +1,26 @@ +import geojson import overpass - class TestAPI: def test_initialize_api(self): api = overpass.API() assert isinstance(api, overpass.API) - assert api.debug == False \ No newline at end of file + assert api.debug == False + + def test_geojson(self): + api = overpass.API() + osm_elements = api.Get(overpass.MapQuery(37.86517,-122.31851,37.86687,-122.31635)) + osm_geo = api.Get(overpass.MapQuery(37.86517,-122.31851,37.86687,-122.31635), asGeoJSON=True) + #print 'DEB osm_elements:', geojson.dumps(osm_elements,sort_keys=True,indent=2) + print 'DEB osm_geo:', geojson.dumps(osm_geo,sort_keys=True,indent=2) + assert len(osm_geo['features']>1) + + def run_tests(): + self.test_initialize_api() + self.test_geojson() + +if __name__ == '__main__': + tapi = TestAPI() + tapi.test_geojson() + print "overpass PASS" From 20c1582c67e892bdefcf215a265f87384829f861 Mon Sep 17 00:00:00 2001 From: "Michael H. Arnold" Date: Mon, 10 Nov 2014 21:42:20 -0800 Subject: [PATCH 2/2] Setting 'out geometry;' on asGeoJSON=True queries - geoJSON output generation is now straight forward, and results look good. --- overpass/api.py | 51 +++++++++++++------------------------------------ test_api.py | 13 +++++++------ 2 files changed, 20 insertions(+), 44 deletions(-) diff --git a/overpass/api.py b/overpass/api.py index 80e3b6f2914..0c4135047af 100644 --- a/overpass/api.py +++ b/overpass/api.py @@ -2,8 +2,6 @@ import requests import json import geojson -#from shapely.geometry import mapping, Point - class API(object): """A simple Python wrapper for the OpenStreetMap Overpass API""" @@ -16,6 +14,7 @@ class API(object): _bbox = [-180.0, -90.0, 180.0, 90.0] _QUERY_TEMPLATE = "[out:{responseformat}];{query}out body;" + _GEOJSON_QUERY_TEMPLATE = "[out:json];{query}out body geom;" def __init__(self, *args, **kwargs): self.endpoint = kwargs.get("endpoint", self._endpoint) @@ -43,7 +42,7 @@ def Get(self, query, asGeoJSON=False): try: response = json.loads(self._GetFromOverpass( - self._ConstructQLQuery(query))) + self._ConstructQLQuery(query, asGeoJSON=asGeoJSON))) except OverpassException as oe: print oe sys.exit(1) @@ -61,12 +60,18 @@ def Search(self, feature_type, regex=False): """Search for something.""" pass - def _ConstructQLQuery(self, userquery): + def _ConstructQLQuery(self, userquery, asGeoJSON=False): raw_query = str(userquery) if not raw_query.endswith(";"): raw_query += ";" - complete_query = self._QUERY_TEMPLATE.format(responseformat=self.responseformat, query=raw_query) + if asGeoJSON: + template = self._GEOJSON_QUERY_TEMPLATE + else: + template = self._QUERY_TEMPLATE + + complete_query = template.format(responseformat=self.responseformat, query=raw_query) + if self.debug: print complete_query return complete_query @@ -97,16 +102,7 @@ def _GetFromOverpass(self, query): return r.text def _asGeoJSON(self, elements): - """ - Construct geoJSON from elements - TODO: Add secondary overpass call to get coords for ways for nodes not included in elements. - """ - node_elements_by_id = {} - - # index node elements by id - for elem in elements: - if elem["type"] == "node": - node_elements_by_id[elem["id"]] = elem + #print 'DEB _asGeoJson elements:', elements features = [] for elem in elements: @@ -115,13 +111,8 @@ def _asGeoJSON(self, elements): geometry=geojson.Point((elem["lon"], elem["lat"])) elif elem["type"] == "way": points = [] - for node_id in elem["nodes"]: - node_elem = node_elements_by_id.get(node_id) - if node_elem: - point = (node_elem["lon"], node_elem["lat"]) - points.append(point) - else - print 'WARNING _asGeoJson skipping missing node ref in way + for coords in elem["geometry"]: + points.append((coords["lon"], coords["lat"])) geometry = geojson.LineString(points) else: continue @@ -134,22 +125,6 @@ def _asGeoJSON(self, elements): return geojson.FeatureCollection(features) -''' - nodes = [{ - "id": elem.get("id"), - "tags": elem.get("tags") - "geom": Point(elem["lon"], elem["lat"])} - for elem in elements if elem["type"] == "node"] - ways = [{ - "id": elem.get("id"), - "tags": elem.get("tags"), - "nodes": elem.get("nodes")} - for elem in elements if elem["type"] == "way"] -''' - - - - class OverpassException(Exception): def __init__(self, status_code, message): self.status_code = status_code diff --git a/test_api.py b/test_api.py index 3e02230651a..4b0ee7b6e0a 100644 --- a/test_api.py +++ b/test_api.py @@ -10,17 +10,18 @@ def test_initialize_api(self): def test_geojson(self): api = overpass.API() - osm_elements = api.Get(overpass.MapQuery(37.86517,-122.31851,37.86687,-122.31635)) - osm_geo = api.Get(overpass.MapQuery(37.86517,-122.31851,37.86687,-122.31635), asGeoJSON=True) + #osm_elements = api.Get(overpass.MapQuery(37.86517,-122.31851,37.86687,-122.31635)) #print 'DEB osm_elements:', geojson.dumps(osm_elements,sort_keys=True,indent=2) - print 'DEB osm_geo:', geojson.dumps(osm_geo,sort_keys=True,indent=2) - assert len(osm_geo['features']>1) + osm_geo = api.Get(overpass.MapQuery(37.86517,-122.31851,37.86687,-122.31635), asGeoJSON=True) + #with open('test.geojson','w') as f: + # geojson.dump(osm_geo,f,indent=2,sort_keys=True) + assert len(osm_geo['features'])>1 - def run_tests(): + def run_tests(self): self.test_initialize_api() self.test_geojson() if __name__ == '__main__': tapi = TestAPI() - tapi.test_geojson() + tapi.run_tests() print "overpass PASS"