Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
|
osmium [2026/04/02 10:17] admin [Buslinien extrahieren] |
osmium [2026/04/05 13:50] (aktuell) jango [Linux] |
||
|---|---|---|---|
| Zeile 1: | Zeile 1: | ||
| - | Osmium ist ein CLI-Tool für die Arbeit mit OSM-Daten und basiert auf der C-Bibliothek libosmium. Es kann mit mehreren OSM-Datenformaten arbeiten, vor allem: | + | Osmium ist ein CLI-Tool für die Arbeit mit [[OpenStreetMap|OSM]]-Daten und basiert auf der C-Bibliothek libosmium. Es kann mit mehreren OSM-Datenformaten arbeiten, vor allem: |
| * .osm.pbf → binäres [[PBF]]-Format | * .osm.pbf → binäres [[PBF]]-Format | ||
| Zeile 20: | Zeile 20: | ||
| n/ | n/ | ||
| r/route=bus \ | r/route=bus \ | ||
| + | -R \ | ||
| -o bus-relevant.osm.pbf -O | -o bus-relevant.osm.pbf -O | ||
| </ | </ | ||
| Zeile 30: | Zeile 31: | ||
| import xml.etree.ElementTree as ET | import xml.etree.ElementTree as ET | ||
| from collections import defaultdict | from collections import defaultdict | ||
| + | |||
| + | |||
| + | def fail(msg, code=1): | ||
| + | print(msg, file=sys.stderr) | ||
| + | sys.exit(code) | ||
| + | |||
| if len(sys.argv) != 3: | if len(sys.argv) != 3: | ||
| - | | + | |
| - | sys.exit(1) | + | |
| input_pbf = sys.argv[1] | input_pbf = sys.argv[1] | ||
| output_geojson = sys.argv[2] | output_geojson = sys.argv[2] | ||
| - | # OSM XML aus osmium cat streamen | + | try: |
| - | proc = subprocess.Popen( | + | proc = subprocess.run( |
| - | [" | + | [" |
| - | stdout=subprocess.PIPE, | + | capture_output=True, |
| - | | + | text=True, |
| - | | + | check=False, |
| - | ) | + | |
| + | except FileNotFoundError: | ||
| + | fail(" | ||
| + | |||
| + | if proc.returncode != 0: | ||
| + | fail(f" | ||
| + | |||
| + | if not proc.stdout.strip(): | ||
| + | fail(" | ||
| + | |||
| + | try: | ||
| + | root = ET.fromstring(proc.stdout) | ||
| + | except ET.ParseError as e: | ||
| + | fail(f" | ||
| + | |||
| + | # Haltestellen-Nodes sammeln | ||
| + | stops = {} | ||
| + | for node in root.findall(" | ||
| + | node_id = node.get(" | ||
| + | lat = node.get(" | ||
| + | lon = node.get(" | ||
| + | if node_id is None or lat is None or lon is None: | ||
| + | continue | ||
| + | |||
| + | tags = {tag.get(" | ||
| + | is_bus_stop = tags.get(" | ||
| + | is_platform = tags.get(" | ||
| + | |||
| + | if is_bus_stop or is_platform: | ||
| + | stops[node_id] = { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | |||
| + | # Routenrelationen -> Haltestellen mappen | ||
| + | routes_by_stop = defaultdict(list) | ||
| + | |||
| + | for rel in root.findall(" | ||
| + | | ||
| + | |||
| + | if rel_tags.get(" | ||
| + | continue | ||
| + | |||
| + | route_info = { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | | ||
| + | |||
| + | for member in rel.findall(" | ||
| + | if member.get(" | ||
| + | continue | ||
| + | |||
| + | ref = member.get(" | ||
| + | role = member.get(" | ||
| + | |||
| + | if ref in stops: | ||
| + | entry = dict(route_info) | ||
| + | entry[" | ||
| + | routes_by_stop[ref].append(entry) | ||
| + | |||
| + | features = [] | ||
| + | |||
| + | for stop_id, stop in stops.items(): | ||
| + | routes = routes_by_stop.get(stop_id, | ||
| + | |||
| + | # doppelte Routen vermeiden | ||
| + | seen = set() | ||
| + | unique_routes = [] | ||
| + | for r in routes: | ||
| + | key = ( | ||
| + | r.get(" | ||
| + | r.get(" | ||
| + | r.get(" | ||
| + | r.get(" | ||
| + | ) | ||
| + | if key not in seen: | ||
| + | seen.add(key) | ||
| + | unique_routes.append(r) | ||
| + | |||
| + | route_refs = sorted({r[" | ||
| + | route_names = sorted({r[" | ||
| + | |||
| + | properties = dict(stop[" | ||
| + | properties[" | ||
| + | properties[" | ||
| + | properties[" | ||
| + | properties[" | ||
| + | properties[" | ||
| + | |||
| + | features.append({ | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | " | ||
| + | }) | ||
| + | |||
| + | geojson = { | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | |||
| + | try: | ||
| + | with open(output_geojson, | ||
| + | json.dump(geojson, | ||
| + | except OSError as e: | ||
| + | fail(f" | ||
| + | |||
| + | print(f" | ||
| + | print(f" | ||
| + | print(f" | ||
| </ | </ | ||
| Zeile 53: | Zeile 177: | ||
| Die geojson hat dann so eine struktur | Die geojson hat dann so eine struktur | ||
| - | <code json>{ | + | <code json> |
| - | "name": "Hervicusgasse", | + | { |
| - | "public_transport": "platform", | + | "type": "Feature", |
| - | "bus_lines": ["16A", "63A"], | + | "geometry": |
| - | "bus_route_names": | + | |
| - | "Bus 16A: Alaudagasse => Südwestfriedhof, 2. und 8. Tor", | + | "coordinates": [16.3738, 48.2082] |
| - | "Bus 63A: Gesundheitszentrum Süd => Am Rosenhügel" | + | }, |
| - | ], | + | |
| - | "bus_routes": [ | + | " |
| - | { | + | |
| - | "route_id": | + | "osm_id": |
| - | "line_ref": "16A", | + | "route_refs" |
| - | "route_name": "Bus 16A: ...", | + | "route_names" |
| - | "role": " | + | |
| - | } | + | " |
| - | ] | + | |
| + | "routes": [ | ||
| + | { | ||
| + | "relation_id": | ||
| + | "ref": "13A", | ||
| + | "name": "13A: Alser Straße - Hauptbahnhof", | ||
| + | "from": "Alser Straße", | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | ] | ||
| + | } | ||
| } | } | ||
| </ | </ | ||
| Zeile 734: | Zeile 871: | ||
| =====Linux===== | =====Linux===== | ||
| - | < | + | < |
| sudo apt update | sudo apt update | ||
| sudo apt install osmium-tool | sudo apt install osmium-tool | ||
| osmium extract --bbox 16.20, | osmium extract --bbox 16.20, | ||
| + | |||
| osmium tags-filter wien.osm.pbf n/ | osmium tags-filter wien.osm.pbf n/ | ||
| + | |||
| osmium sort edited.osm.pbf -o edited-sorted.osm.pbf | osmium sort edited.osm.pbf -o edited-sorted.osm.pbf | ||
| + | |||
| osmium renumber edited-sorted.osm.pbf -o edited-renumbered.osm.pbf | osmium renumber edited-sorted.osm.pbf -o edited-renumbered.osm.pbf | ||
| + | |||
| osmium fileinfo -e edited-renumbered.osm.pbf | osmium fileinfo -e edited-renumbered.osm.pbf | ||
| osmium extract -b 16.36, | osmium extract -b 16.36, | ||
| </ | </ | ||
| + | Siehe [[https:// | ||
| + | < | ||
| + | # bbox | ||
| + | at - 9.54063, | ||
| + | vienna - 16.20, | ||
| + | </ | ||
| =====Python===== | =====Python===== | ||
| Zeile 985: | Zeile 1131: | ||
| * [[https:// | * [[https:// | ||
| * [[https:// | * [[https:// | ||
| + | * [[https:// | ||