Add OSM data downloading using API.

This commit is contained in:
Sergey Vartanov 2020-08-23 11:15:51 +03:00
parent f1a5c2244c
commit 945af54dc9
5 changed files with 73 additions and 89 deletions

View file

@ -22,25 +22,53 @@ There are simple Python renderer that generates SVG map from OpenStreetMap data.
You can run it using: You can run it using:
```bash ```bash
python3 roentgen.py -i ${INPUT_FILE_NAME} -o ${OUTPUT_FILE_NAME} python3 run.py \
-bbox ${LONGITUDE_1},${LATITUDE_1},${LONGITUDE_2},${LATITUDE_2} \
-o ${OUTPUT_FILE_NAME} \
-s ${WIDTH},${HEIGHT}
``` ```
### Options ### Example:
```bash
python3 run.py -bbox 2.284,48.86,2.29,48.865 -o map.svg -s 1000,1000
```
### Main arguments ###
#### Required ####
<table> <table>
<tr><td>Option</td><td>Value</td><td>Description</td></tr> <tr><td>Option</td><td>Value</td><td>Description</td></tr>
<tr> <tr>
<td><tt>-bbox</tt>, <tt>--boundary-box</tt></td> <td><tt>-bbox</tt>, <tt>--boundary-box</tt></td>
<td> <td>
<tt>&lt;longitude 1&gt;,&lt;latitude 1&gt;,&lt;longitude 2&gt;,&lt;latitude 2&gt;</tt> <tt>&lt;longitude 1&gt;,&lt;latitude 1&gt;,&lt;longitude
(decimal float) 2&gt;,&lt;latitude 2&gt;</tt>
</td> </td>
<td>Boundary box to draw</td> <td>Boundary box to draw.</td>
</tr> </tr>
<tr> <tr>
<td><tt>-s</tt>, <tt>--size</tt></td> <td><tt>-s</tt>, <tt>--size</tt></td>
<td><tt>&lt;width&gt;,&lt;height&gt;</tt> (pixels)</td> <td><tt>&lt;width&gt;,&lt;height&gt;</tt></td>
<td>Result image size</td> <td>Result image size in pixels.</td>
</tr>
<tr>
<td><tt>-o</tt></td>
<td><tt>&lt;path&gt;</tt></td>
<td>Path to output SVG file name.</td>
</tr>
</table>
#### Optional ####
<table>
<tr><td>Option</td><td>Value</td><td>Description</td></tr>
<tr>
<td><tt>-i</tt></td>
<td><tt>&lt;path&gt;</tt></td>
<td>Path to input XML file name. If this argument is not set, XML file
will be downloaded throung Openstreetmap API.</td>
</tr> </tr>
</table> </table>

View file

@ -16,6 +16,7 @@ from roentgen import ui
from roentgen import svg from roentgen import svg
from roentgen.flinger import GeoFlinger, Geo from roentgen.flinger import GeoFlinger, Geo
from roentgen.osm_reader import OSMReader, OSMWay from roentgen.osm_reader import OSMReader, OSMWay
from roentgen.osm_getter import get_osm
from datetime import datetime from datetime import datetime
from typing import List, Optional, Set from typing import List, Optional, Set
@ -1064,17 +1065,25 @@ def main():
if not options: if not options:
sys.exit(1) sys.exit(1)
background_color = "EEEEEE" # "DDDDDD" background_color = "EEEEEE"
if options.mode in ["user-coloring", "time"]: if options.mode in ["user-coloring", "time"]:
background_color = "111111" background_color = "111111"
outline_color = "111111"
if options.input_file_name:
input_file_name = options.input_file_name input_file_name = options.input_file_name
else:
content = get_osm(options.boundary_box)
if not content:
ui.error("cannot download OSM data")
input_file_name = os.path.join("map", options.boundary_box + ".osm")
if not os.path.isfile(input_file_name): if not os.path.isfile(input_file_name):
print("Fatal: no such file: " + input_file_name + ".") print("Fatal: no such file: " + input_file_name + ".")
sys.exit(1) sys.exit(1)
boundary_box = list(map(
lambda x: float(x.replace('m', '-')), options.boundary_box.split(',')))
full = False # Full keys getting full = False # Full keys getting
if options.mode in ["user-coloring", "time"]: if options.mode in ["user-coloring", "time"]:
@ -1095,10 +1104,8 @@ def main():
"<title>Rӧntgen</title><style>path:hover {stroke: #FF0000;}</style>\n") "<title>Rӧntgen</title><style>path:hover {stroke: #FF0000;}</style>\n")
output_file.rect(0, 0, w, h, color=background_color) output_file.rect(0, 0, w, h, color=background_color)
if "boundary_box" in options: min1 = Geo(boundary_box[1], boundary_box[0])
bb = options.boundary_box max1 = Geo(boundary_box[3], boundary_box[2])
min1 = Geo(bb[1], bb[0])
max1 = Geo(bb[3], bb[2])
authors = {} authors = {}
missed_tags = {} missed_tags = {}

View file

@ -25,7 +25,7 @@ def get_data(address: str, parameters: Dict[str, str], is_secure: bool=False, na
""" """
url = "http" + ("s" if is_secure else "") + "://" + address url = "http" + ("s" if is_secure else "") + "://" + address
if len(parameters) > 0: if len(parameters) > 0:
url += "?" + "&".join(parameters) # urllib.parse.urlencode(parameters) url += "?" + urllib.parse.urlencode(parameters)
if not name: if not name:
name = url name = url
print("getting " + name) print("getting " + name)
@ -36,51 +36,3 @@ def get_data(address: str, parameters: Dict[str, str], is_secure: bool=False, na
pool_manager.clear() pool_manager.clear()
time.sleep(2) time.sleep(2)
return result.data return result.data
def get_content(address, parameters, cache_file_name, kind, is_secure, name=None, exceptions=None, update_cache=False):
"""
Read content from URL or from cached file.
:param address: first part of URL without "http://"
:param parameters: URL parameters
:param cache_file_name: name of cache file
:param kind: type of content: "html" or "json"
:return: content if exist
"""
if exceptions and address in exceptions:
return None
if os.path.isfile(cache_file_name) and \
datetime(1, 1, 1).fromtimestamp(os.stat(cache_file_name).st_mtime) > \
datetime.now() - timedelta(days=90) and \
not update_cache:
with open(cache_file_name) as cache_file:
if kind == "json":
try:
return json.load(cache_file)
except ValueError:
return None
if kind == "html":
return cache_file.read()
else:
try:
data = get_data(address, parameters, is_secure=is_secure, name=name)
if kind == "json":
try:
obj = json.loads(data)
with open(cache_file_name, "w+") as cached:
cached.write(json.dumps(obj, indent=4))
return obj
except ValueError:
print("cannot get " + address + " " + str(parameters))
return None
if kind == "html":
with open(cache_file_name, "w+") as cached:
cached.write(data)
return data
except Exception as e:
print("during getting JSON from " + address + " with parameters " + str(parameters))
print(e)
if exceptions:
exceptions.append(address)
return None

View file

@ -1,48 +1,47 @@
import os
import re import re
import sys
from typing import Optional
from roentgen.ui import error from roentgen.ui import error
from roentgen import network from roentgen import network
USAGE: str = '<box coordinates: left,bottom,right,top>' def get_osm(boundary_box: str, to_update: bool = False) -> Optional[str]:
result_file_name = os.path.join("map", boundary_box + ".osm")
if not to_update and os.path.isfile(result_file_name):
return open(result_file_name).read()
def main(boundary_box: str): matcher = re.match("(?P<left>[0-9.-]*),(?P<bottom>[0-9.-]*)," +
result_file_name = 'map/' + boundary_box + '.xml' "(?P<right>[0-9.-]*),(?P<top>[0-9.-]*)", boundary_box)
matcher = re.match('(?P<left>[0-9\\.-]*),(?P<bottom>[0-9\\.-]*),' + \
'(?P<right>[0-9\\.-]*),(?P<top>[0-9\\.-]*)', boundary_box)
if not matcher: if not matcher:
error('invalid boundary box') error("invalid boundary box")
return return
try: try:
left = float(matcher.group('left')) left = float(matcher.group("left"))
bottom = float(matcher.group('bottom')) bottom = float(matcher.group("bottom"))
right = float(matcher.group('right')) right = float(matcher.group("right"))
top = float(matcher.group('top')) top = float(matcher.group("top"))
except Exception: except ValueError:
error('parsing boundary box') error("parsing boundary box")
return return
if left >= right: if left >= right:
error('negative horizontal boundary') error("negative horizontal boundary")
return return
if bottom >= top: if bottom >= top:
error('negative vertical boundary') error("negative vertical boundary")
return return
if right - left > 0.5 or top - bottom > 0.5: if right - left > 0.5 or top - bottom > 0.5:
error('box too big') error("box too big")
return return
network.get_content('api.openstreetmap.org/api/0.6/map',
{'bbox': boundary_box}, result_file_name, 'html', is_secure=True)
content = network.get_data("api.openstreetmap.org/api/0.6/map",
{"bbox": boundary_box}, is_secure=True)
if __name__ == "__main__": open(result_file_name, "w+").write(content.decode("utf-8"))
if len(sys.argv) < 2:
print('Usage: python ' + sys.argv[0] + ' ' + USAGE)
sys.exit(0)
main(sys.argv[1]) return content.decode("utf-8")

2
run.py
View file

@ -1,6 +1,4 @@
from roentgen.osm_getter import main
from roentgen.mapper import main from roentgen.mapper import main
if __name__ == "__main__": if __name__ == "__main__":
# main("2.374,48.843,2.378,48.846")
main() main()