Bahnübergangsvergleich DB Netz vs. OpenStreetMap

Über den Bahnübergangsvergleich DB Netz vs. OpenStreetMap

Datenquellen und Lizenz

Auf dieser Karte sind die Ergebnisse eines Vergleichs der Bahnübergänge aus OpenStreetMap mit den Daten aus dem Open-Data-Portal der Deutschen Bahn zu sehen. Die OpenStreetMap-Daten sind vom 14. Dezember 2017, die DB-Daten vom Januar 2017.

Die Resultate dieses Vergleichs unterliegen ebenso wie die verwendeten OpenStreetMap-Daten den Bedingungen der Open Database License 1.0. Die Daten der Deutschen Bahn unterliegen den Bedingungen der CC-BY 4.0

Ablauf

Import der OpenStreetMap-Daten in eine PostgreSQL-Datenbank:

osm2pgsql -d gis --create --hstore --hstore-match-only --multi-geometry --number-processes 2 -l --style crossings.style --cache 5500 /home/michael/Downloads/osm/germany-latest.osm.pbf

Das verwendete spezielle Stylefile für osm2pgsql:

# OsmType  Tag          DataType     Flags
node,way   admin_level  text         linear
node,way   area         text         polygon # hard coded support for area=1/yes => polygon is in osm2pgsql
node,way   barrier      text         linear
node,way   bicycle      text         linear
node,way   bridge       text         linear
node,way   boundary     text         linear
node,way   construction text         linear
node,way   foot         text         linear
node,way   highway      text         linear
node,way   horse        text         linear
node,way   layer        text         linear
node,way   motorcar     text         linear
node,way   oneway       text         linear
node,way   operator     text         linear
node,way   public_transport text     polygon
node,way   railway      text         linear
node,way   service      text         linear
node,way   surface      text         linear
way        tracktype    text         linear
node,way   tunnel       text         linear
node,way   water        text         polygon
node,way   waterway     text         polygon
node,way   z_order      int4         linear # This is calculated during import
way        way_area     real         linear # This is calculated during import

Shapefiles mit Bahnübergängen und Strecken der DB importieren:

shp2pgsql -s 4326 -cDI bahnuebergaenge_point.shp crossings_db gis | psql -d gis; shp2pgsql -s 4326 -cDI strecken_polyline.shp strecken_db gis | psql -d gis

Bahnübergänge an DB-Strecken ermitteln:

SELECT p.osm_id AS osm_id, p.railway AS railway, p.tags AS tags, p.way AS geom
  INTO osm_bahnuebergaenge
  FROM planet_osm_point AS p, strecken_db AS s
  WHERE ST_DWithin(s.geom, p.way, 0.0002) AND p.railway IN ('level_crossing', 'crossing'); -- 1.7 Sek. 23810 INSERT

CREATE INDEX osm_bahnuebergaenge_geom_idx ON osm_bahnuebergaenge USING GIST(geom);

CREATE INDEX planet_osm_line_highway ON planet_osm_line USING GIST(way)
  WHERE highway IS NOT NULL AND tags->'access' IN ('private', 'no') AND osm_id > 0; -- 9 Sekunden
        

Dienstwege und nicht öffentliche Bahnübergänge (größtenteils Dienstwege in Bahnhöfen) löschen:

DELETE FROM osm_bahnuebergaenge AS o
  WHERE o.osm_id IN (
    SELECT a.osm_id AS osm_id
      FROM osm_bahnuebergaenge AS a, planet_osm_line AS p
      WHERE a.geom && a.geom AND ST_Covers(p.way, a.geom) AND p.highway IS NOT NULL AND p.tags->'access' IN ('private', 'no') AND p.osm_id > 0
  ); -- 2 Sekunden, 1094 DELETE

Bahnübergänge ausgeben, die nur in OSM sind

SELECT b.osm_id AS osm_id, b.railway AS railway, b.tags AS tags, b.geom AS geom
  INTO bahnuebergaenge_nur_osm
  FROM osm_bahnuebergaenge AS b
  WHERE b.osm_id NOT IN (
    SELECT c.osm_id AS osm_id
    FROM osm_bahnuebergaenge AS c
    JOIN crossings_db AS d
    ON (ST_DWithin(c.geom, d.geom, 0.0003))
  ); -- 0,3 Sekunden 2137 INSERT

Tabelle für Bahnsteige:

CREATE TABLE platforms (osm_id bigint, railway text, geom geometry(Geometry, 4326));
INSERT INTO platforms (osm_id, railway, geom)
  SELECT osm_id, railway, way
    FROM planet_osm_polygon
    WHERE railway = 'platform'; -- 1 Sekunde, 12157 Insert
INSERT INTO platforms (osm_id, railway, geom)
  SELECT osm_id, railway, way
    FROM planet_osm_line
    WHERE railway = 'platform'; -- 11 Sekungen, 7617 Insert
CREATE INDEX platforms_geom_idx ON platforms USING gist(geom);
        

Bahnübergänge in Bahnsteignähe entfernen, da das i.d.R. Reisendenübergänge sind und diese in den DB-Daten fehlen:

DELETE FROM bahnuebergaenge_nur_osm AS b
  WHERE b.osm_id IN (
    SELECT b.osm_id
      FROM bahnuebergaenge_nur_osm AS b
      JOIN platforms AS p
      ON (ST_DWithin(b.geom, p.geom, 0.0004))
    ); -- 1103 DELETE, < 1 Sekunde
        

Bahnübergänge, die in OSM nicht ordentlich erfasst sind

In OSM gibt es zahlreiche Bahnübergänge, bei denen das Tag railway=level_crossing oder railway=crossing fehlt und die nicht an Stellen liegen, wo Straßen/Wege und Gleise sich kreuzen.

SELECT *
    INTO highways
    FROM planet_osm_line
    WHERE highway IS NOT NULL AND osm_id > 0; -- 12 Sekunden
SELECT *
  INTO railways
  FROM planet_osm_line
  WHERE railway = 'rail' AND osm_id > 0; -- 2 Sekunden
CREATE INDEX highway_geom_idx ON highways USING GIST(way); -- 139 Sekunden
CREATE INDEX railway_geom_idx ON railways USING GIST(way); -- 1 Sekunde
UPDATE highways
  SET layer = '0'
  WHERE layer NOT SIMILAR TO '-?[0-9]+' OR layer IS NULL; -- 211 Sekunden
UPDATE railways
  SET layer = '0'
  WHERE layer NOT SIMILAR TO '-?[0-9]+' OR layer IS NULL; -- 3 Sekunden
ALTER TABLE highways ALTER COLUMN layer TYPE int USING layer::int; -- 164 Sekunden
ALTER TABLE railways ALTER COLUMN layer TYPE int USING layer::int; -- 2 Sekunden
SELECT DISTINCT ON (geom) osm_id, geom, highway, tags
  INTO crossings_by_intersection
  FROM (
    SELECT DISTINCT ON (l.osm_id) l.osm_id AS osm_id, ST_Intersection(l.way, r.way) AS geom, l.highway AS highway, l.tags AS tags
      FROM highways AS l
      JOIN railways AS r
      ON (l.way && r.way AND ST_Intersects(l.way, r.way) AND l.layer = r.layer)
  ) AS f; -- 37 Sekunden, 76964 INSERT
CREATE INDEX crossings_by_intersection_geom_idx ON crossings_by_intersection USING GIST(geom); -- < 1 Sekunde
ALTER TABLE crossings_by_intersection ADD COLUMN pkey serial primary key;
SELECT *
  INTO all_crossings
  FROM planet_osm_point
  WHERE railway IN ('level_crossing', 'crossing');
CREATE INDEX all_crossings_geom_idx ON all_crossings USING gist(way);
DELETE FROM crossings_by_intersection AS c
  WHERE pkey IN (
    SELECT d.pkey AS pkey
      FROM crossings_by_intersection AS d
      JOIN all_crossings AS o
      ON (ST_DWithin(o.way, d.geom, 0.00001))
    )
    OR ST_GeometryType(geom) IN ('ST_LineString', 'ST_MultiLineString'); -- 12974 DELETE 0,4 Sekunden

Und nun nur noch die, die an DB-Infrastruktur liegen:

SELECT a.osm_id AS osm_id, a.highway AS highway, a.geom AS geom
  INTO crossings_by_intersection_near_db
  FROM crossings_by_intersection AS a, strecken_db AS s
  WHERE ST_DWithin(a.geom, s.geom, 0.0001);

Bahnübergänge suchen, die nur die DB kennt

SELECT d.strecke_nr AS vzg_nr, d.richtung AS richtung, d.km_i AS km_i, d.km_l AS km_l, d.bezeichnun AS bezeichnung, d.techn_sich AS technische_sicherung, d.strassenar AS strassenart, d.geom AS geom
  INTO bahnuebergaenge_nur_db
  FROM crossings_db AS d
  WHERE d.gid NOT IN (
    SELECT e.gid AS gid
      FROM crossings_db AS e
      JOIN osm_bahnuebergaenge AS o
      ON (ST_DWithin(o.geom, e.geom, 0.0005))
  ); -- 1450 INSERT, 0,3 Sekunden
ALTER TABLE bahnuebergaenge_nur_db ADD COLUMN pkey serial primary key;
CREATE INDEX bahnuebergaenge_nur_db_geom_idx ON bahnuebergaenge_nur_db USING GIST(geom);
CREATE INDEX crossings_by_intersection_near_db_geom_idx ON crossings_by_intersection_near_db USING GIST(geom);
DELETE FROM bahnuebergaenge_nur_db
  WHERE pkey IN (
    SELECT b.pkey AS pkey FROM bahnuebergaenge_nur_db AS b, crossings_by_intersection_near_db AS c WHERE ST_DWithin(b.geom, c.geom, 0.0005)
  ); -- 220 DELETE