diff --git a/docs/source/api.rst b/docs/source/api.rst index a2ffb6d..81158bf 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -64,3 +64,17 @@ Helper .. automodule:: overpy.helper :members: + + +Format/Export +------------- + +.. warning:: + + This feature is in pre alpha stage. Please report any issues. + +.. automodule:: overpy.format.geojson + :members: + +.. automodule:: overpy.format.osm_xml + :members: diff --git a/overpy/format/__init__.py b/overpy/format/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/overpy/format/geojson.py b/overpy/format/geojson.py new file mode 100644 index 0000000..018bd33 --- /dev/null +++ b/overpy/format/geojson.py @@ -0,0 +1,63 @@ +import json +from typing import Any, Dict, Optional, TextIO + +import overpy + + +def dump(result: overpy.Result, fp: TextIO, nodes: bool = False, ways: bool = False, json_args: Optional[dict] = None): + """ + Use the result from the Overpass API to generate GeoJSON. + + More information: + + * http://geojson.org/ + + :param result: The result from the Overpass API + :param fp: Filepointer to use + :param nodes: Export nodes + :param ways: Export ways + :param json_args: Additional arguments passed to json.dump(...) + :return: + """ + features = [] + if nodes: + for node in result.nodes: + properties: Dict[str, Any] = {} + features.append({ + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + float(node.lon), + float(node.lat) + ] + }, + "properties": properties + }) + + if ways: + for way in result.ways: + properties = {} + coordinates = [] + for node in way.nodes: + coordinates.append([ + float(node.lon), + float(node.lat) + ]) + features.append({ + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": coordinates + }, + "properties": properties + }) + + geojson = { + "type": "FeatureCollection", + "features": features + } + + if json_args is None: + json_args = {} + json.dump(geojson, fp, **json_args) diff --git a/overpy/format/osm_xml.py b/overpy/format/osm_xml.py new file mode 100644 index 0000000..1e51d21 --- /dev/null +++ b/overpy/format/osm_xml.py @@ -0,0 +1,111 @@ +from typing import TextIO +from xml.sax.saxutils import escape + +import overpy + + +def dump(result: overpy.Result, fp: TextIO): + """ + Use the result from the Overpass API to generate OSM XML + + More information: + + * http://wiki.openstreetmap.org/wiki/OSM_XML + + :param result: The result from the Overpass API + :param fp: Filepointer to use + :return: + """ + fp.write('\n') + fp.write('\n'.format(overpy.__version__)) + lat_min = result.nodes[0].lat + lat_max = lat_min + lon_min = result.nodes[0].lon + lon_max = lon_min + for node in result.nodes: + if node.lat < lat_min: + lat_min = node.lat + elif node.lat > lat_max: + lat_max = node.lat + + if node.lon < lon_min: + lon_min = node.lon + elif node.lon > lon_max: + lon_max = node.lon + + fp.write( + '\n'.format( + lat_min, + lon_min, + lat_max, + lon_max + ) + ) + + for node in result.nodes: + fp.write( + '\n') + continue + fp.write('>\n') + for k, v in node.tags.items(): + fp.write( + '\n'.format( + escape(k), + escape(v) + ) + ) + fp.write('\n') + + for way in result.ways: + fp.write('\n') + continue + fp.write('>\n') + for node in way.nodes: + fp.write('\n'.format(node.id)) + + for k, v in way.tags.items(): + fp.write( + '\n'.format( + escape(k), + escape(v) + ) + ) + + fp.write('\n') + + for relation in result.relations: + fp.write('\n'.format( + member._type_value, + member.ref, + member.role + ) + ) + + for k, v in relation.tags.items(): + fp.write( + '\n'.format( + escape(k), + escape(v) + ) + ) + + fp.write('\n') + + fp.write('') diff --git a/tests/test_export.py b/tests/test_export.py new file mode 100644 index 0000000..867cc64 --- /dev/null +++ b/tests/test_export.py @@ -0,0 +1,22 @@ +import overpy +from overpy.format import geojson, osm_xml + +from tests import read_file + +from io import StringIO + + +class TestGeoJSON(object): + def test_node01(self): + api = overpy.Overpass() + result = api.parse_json(read_file("json/node-01.json")) + fp = StringIO() + geojson.dump(result, fp, nodes=True, ways=True) + + +class TestOSMXML(object): + def test_node01(self): + api = overpy.Overpass() + result = api.parse_json(read_file("json/node-01.json")) + fp = StringIO() + osm_xml.dump(result, fp)