Check if stations are missing/differ in backward direction of some route
This commit is contained in:
parent
ed95c94aac
commit
6c796ac8c1
9 changed files with 2215 additions and 95 deletions
|
@ -12,27 +12,26 @@ ALLOWED_STATIONS_MISMATCH = 0.02 # part of total station count
|
|||
ALLOWED_TRANSFERS_MISMATCH = 0.07 # part of total interchanges count
|
||||
ALLOWED_ANGLE_BETWEEN_STOPS = 45 # in degrees
|
||||
DISALLOWED_ANGLE_BETWEEN_STOPS = 20 # in degrees
|
||||
SUGGEST_TRANSFER_MIN_DISTANCE = 100 # in meters
|
||||
|
||||
# If an object was moved not too far compared to previous script run,
|
||||
# it is likely the same object
|
||||
DISPLACEMENT_TOLERANCE = 300 # in meters
|
||||
|
||||
MODES_RAPID = set(("subway", "light_rail", "monorail", "train"))
|
||||
MODES_OVERGROUND = set(("tram", "bus", "trolleybus", "aerialway", "ferry"))
|
||||
DEFAULT_MODES_RAPID = set(("subway", "light_rail"))
|
||||
DEFAULT_MODES_OVERGROUND = set(("tram",)) # TODO: bus and trolleybus?
|
||||
MODES_RAPID = {"subway", "light_rail", "monorail", "train"}
|
||||
MODES_OVERGROUND = {"tram", "bus", "trolleybus", "aerialway", "ferry"}
|
||||
DEFAULT_MODES_RAPID = {"subway", "light_rail"}
|
||||
DEFAULT_MODES_OVERGROUND = {"tram"} # TODO: bus and trolleybus?
|
||||
ALL_MODES = MODES_RAPID | MODES_OVERGROUND
|
||||
RAILWAY_TYPES = set(
|
||||
(
|
||||
"rail",
|
||||
"light_rail",
|
||||
"subway",
|
||||
"narrow_gauge",
|
||||
"funicular",
|
||||
"monorail",
|
||||
"tram",
|
||||
)
|
||||
)
|
||||
RAILWAY_TYPES = {
|
||||
"rail",
|
||||
"light_rail",
|
||||
"subway",
|
||||
"narrow_gauge",
|
||||
"funicular",
|
||||
"monorail",
|
||||
"tram",
|
||||
}
|
||||
CONSTRUCTION_KEYS = (
|
||||
"construction",
|
||||
"proposed",
|
||||
|
@ -49,7 +48,7 @@ START_END_TIMES_RE = re.compile(r".*?(\d{2}):(\d{2})-(\d{2}):(\d{2}).*")
|
|||
def get_start_end_times(opening_hours):
|
||||
"""Very simplified method to parse OSM opening_hours tag.
|
||||
We simply take the first HH:MM-HH:MM substring which is the most probable
|
||||
opening hours interval for the most of weekdays.
|
||||
opening hours interval for the most of the weekdays.
|
||||
"""
|
||||
start_time, end_time = None, None
|
||||
m = START_END_TIMES_RE.match(opening_hours)
|
||||
|
@ -102,9 +101,9 @@ def el_center(el):
|
|||
if not el:
|
||||
return None
|
||||
if "lat" in el:
|
||||
return (el["lon"], el["lat"])
|
||||
return el["lon"], el["lat"]
|
||||
elif "center" in el:
|
||||
return (el["center"]["lon"], el["center"]["lat"])
|
||||
return el["center"]["lon"], el["center"]["lat"]
|
||||
return None
|
||||
|
||||
|
||||
|
@ -485,7 +484,7 @@ class StopArea:
|
|||
self.center[i] /= len(self.stops) + len(self.platforms)
|
||||
|
||||
def get_elements(self):
|
||||
result = set([self.id, self.station.id])
|
||||
result = {self.id, self.station.id}
|
||||
result.update(self.entrances)
|
||||
result.update(self.exits)
|
||||
result.update(self.stops)
|
||||
|
@ -1156,6 +1155,12 @@ class Route:
|
|||
|
||||
return tracks
|
||||
|
||||
def are_tracks_complete(self) -> bool:
|
||||
return (
|
||||
self.first_stop_on_rails_index == 0
|
||||
and self.last_stop_on_rails_index == len(self) - 1
|
||||
)
|
||||
|
||||
def get_tracks_geometry(self):
|
||||
tracks = self.get_extended_tracks()
|
||||
tracks = self.get_truncated_tracks(tracks)
|
||||
|
@ -1350,6 +1355,36 @@ class Route:
|
|||
]
|
||||
return True
|
||||
|
||||
def get_end_transfers(self) -> tuple[str, str]:
|
||||
"""Using transfer ids because a train can arrive at different
|
||||
stations within a transfer. But disregard transfer that may give
|
||||
an impression of a circular route (for example,
|
||||
Simonis / Elisabeth station and route 2 in Brussels).
|
||||
"""
|
||||
return (
|
||||
(self[0].stoparea.id, self[-1].stoparea.id)
|
||||
if (
|
||||
self[0].stoparea.transfer is not None
|
||||
and self[0].stoparea.transfer == self[-1].stoparea.transfer
|
||||
)
|
||||
else (
|
||||
self[0].stoparea.transfer or self[0].stoparea.id,
|
||||
self[-1].stoparea.transfer or self[-1].stoparea.id,
|
||||
)
|
||||
)
|
||||
|
||||
def get_transfers_sequence(self) -> list[str]:
|
||||
"""Return a list of stoparea or transfer (if not None) ids."""
|
||||
transfer_seq = [
|
||||
stop.stoparea.transfer or stop.stoparea.id for stop in self
|
||||
]
|
||||
if (
|
||||
self[0].stoparea.transfer is not None
|
||||
and self[0].stoparea.transfer == self[-1].stoparea.transfer
|
||||
):
|
||||
transfer_seq[0], transfer_seq[-1] = self.get_end_transfers()
|
||||
return transfer_seq
|
||||
|
||||
def __len__(self):
|
||||
return len(self.stops)
|
||||
|
||||
|
@ -1479,13 +1514,75 @@ class RouteMaster:
|
|||
else:
|
||||
self.interval = min(self.interval, route.interval)
|
||||
|
||||
# Choose minimal id for determinancy
|
||||
if not self.has_master and (not self.id or self.id > route.id):
|
||||
self.id = route.id
|
||||
|
||||
self.routes.append(route)
|
||||
if not self.best or len(route.stops) > len(self.best.stops):
|
||||
if (
|
||||
not self.best
|
||||
or len(route.stops) > len(self.best.stops)
|
||||
or (
|
||||
# Choose route with minimal id for determinancy
|
||||
len(route.stops) == len(self.best.stops)
|
||||
and route.element["id"] < self.best.element["id"]
|
||||
)
|
||||
):
|
||||
self.best = route
|
||||
|
||||
def get_meaningful_routes(self) -> list[Route]:
|
||||
return [route for route in self if len(route) >= 2]
|
||||
|
||||
def find_twin_routes(self) -> dict[Route, Route]:
|
||||
"""Two routes are twins if they have the same end stations
|
||||
and opposite directions, and the number of stations is
|
||||
the same or almost the same. We'll then find stops that are present
|
||||
in one direction and is missing in another direction - to warn.
|
||||
"""
|
||||
|
||||
twin_routes = {} # route => "twin" route
|
||||
|
||||
for route in self.get_meaningful_routes():
|
||||
if route.is_circular:
|
||||
continue # Difficult to calculate. TODO(?) in the future
|
||||
if route in twin_routes:
|
||||
continue
|
||||
if len(route) < 2:
|
||||
continue
|
||||
|
||||
route_transfer_ids = set(route.get_transfers_sequence())
|
||||
ends = route.get_end_transfers()
|
||||
ends_reversed = ends[::-1]
|
||||
|
||||
twin_candidates = [
|
||||
r
|
||||
for r in self
|
||||
if not r.is_circular
|
||||
and r not in twin_routes
|
||||
and r.get_end_transfers() == ends_reversed
|
||||
# If absolute or relative difference in station count is large,
|
||||
# possibly it's an express version of a route - skip it.
|
||||
and (
|
||||
abs(len(r) - len(route)) <= 2
|
||||
or abs(len(r) - len(route)) / max(len(r), len(route))
|
||||
<= 0.2
|
||||
)
|
||||
]
|
||||
|
||||
if not twin_candidates:
|
||||
continue
|
||||
|
||||
twin_route = min(
|
||||
twin_candidates,
|
||||
key=lambda r: len(
|
||||
route_transfer_ids ^ set(r.get_transfers_sequence())
|
||||
),
|
||||
)
|
||||
twin_routes[route] = twin_route
|
||||
twin_routes[twin_route] = route
|
||||
|
||||
return twin_routes
|
||||
|
||||
def stop_areas(self):
|
||||
"""Returns a list of all stations on all route variants."""
|
||||
seen_ids = set()
|
||||
|
@ -1521,6 +1618,7 @@ class City:
|
|||
self.errors = []
|
||||
self.warnings = []
|
||||
self.notices = []
|
||||
self.id = None
|
||||
self.try_fill_int_attribute(city_data, "id")
|
||||
self.name = city_data["name"]
|
||||
self.country = city_data["country"]
|
||||
|
@ -1555,7 +1653,7 @@ class City:
|
|||
else:
|
||||
self.modes = DEFAULT_MODES_RAPID
|
||||
else:
|
||||
self.modes = set([x.strip() for x in networks[0].split(",")])
|
||||
self.modes = {x.strip() for x in networks[0].split(",")}
|
||||
|
||||
# Reversing bbox so it is (xmin, ymin, xmax, ymax)
|
||||
bbox = city_data["bbox"].split(",")
|
||||
|
@ -1627,7 +1725,7 @@ class City:
|
|||
self.warnings.append(msg)
|
||||
|
||||
def error(self, message, el=None):
|
||||
"""Error if a critical problem that invalidates the city"""
|
||||
"""Error is a critical problem that invalidates the city."""
|
||||
msg = City.log_message(message, el)
|
||||
self.errors.append(msg)
|
||||
|
||||
|
@ -1914,37 +2012,18 @@ class City:
|
|||
f"relations: {format_elid_list(not_in_sa)}"
|
||||
)
|
||||
|
||||
def check_return_routes(self, rmaster):
|
||||
variants = {}
|
||||
have_return = set()
|
||||
for variant in rmaster:
|
||||
if len(variant) < 2:
|
||||
continue
|
||||
# Using transfer ids because a train can arrive at different
|
||||
# stations within a transfer. But disregard transfer that may give
|
||||
# an impression of a circular route (for example,
|
||||
# Simonis / Elisabeth station and route 2 in Brussels)
|
||||
if variant[0].stoparea.transfer == variant[-1].stoparea.transfer:
|
||||
t = (variant[0].stoparea.id, variant[-1].stoparea.id)
|
||||
else:
|
||||
t = (
|
||||
variant[0].stoparea.transfer or variant[0].stoparea.id,
|
||||
variant[-1].stoparea.transfer or variant[-1].stoparea.id,
|
||||
)
|
||||
if t in variants:
|
||||
continue
|
||||
variants[t] = variant.element
|
||||
tr = (t[1], t[0])
|
||||
if tr in variants:
|
||||
have_return.add(t)
|
||||
have_return.add(tr)
|
||||
def check_return_routes(self, rmaster: RouteMaster) -> None:
|
||||
"""Check if a route has return direction, and if twin routes
|
||||
miss stations.
|
||||
"""
|
||||
meaningful_routes = rmaster.get_meaningful_routes()
|
||||
|
||||
if len(variants) == 0:
|
||||
if len(meaningful_routes) == 0:
|
||||
self.error(
|
||||
"An empty route master {}. Please set construction:route "
|
||||
"if it is under construction".format(rmaster.id)
|
||||
f"An empty route master {rmaster.id}. "
|
||||
"Please set construction:route if it is under construction"
|
||||
)
|
||||
elif len(variants) == 1:
|
||||
elif len(meaningful_routes) == 1:
|
||||
log_function = (
|
||||
self.error if not rmaster.best.is_circular else self.notice
|
||||
)
|
||||
|
@ -1954,9 +2033,144 @@ class City:
|
|||
rmaster.best.element,
|
||||
)
|
||||
else:
|
||||
for t, rel in variants.items():
|
||||
if t not in have_return:
|
||||
self.notice("Route does not have a return direction", rel)
|
||||
all_ends = {
|
||||
route.get_end_transfers(): route for route in meaningful_routes
|
||||
}
|
||||
for route in meaningful_routes:
|
||||
ends = route.get_end_transfers()
|
||||
if ends[::-1] not in all_ends:
|
||||
self.notice(
|
||||
"Route does not have a return direction", route.element
|
||||
)
|
||||
|
||||
twin_routes = rmaster.find_twin_routes()
|
||||
for route1, route2 in twin_routes.items():
|
||||
if route1.id > route2.id:
|
||||
continue # to process a pair of routes only once
|
||||
# and to ensure the order of routes in the pair
|
||||
self.alert_twin_routes_differ(route1, route2)
|
||||
|
||||
def alert_twin_routes_differ(self, route1: Route, route2: Route) -> None:
|
||||
"""Arguments are that route1.id < route2.id"""
|
||||
(
|
||||
stops_missing_from_route1,
|
||||
stops_missing_from_route2,
|
||||
stops_that_dont_match,
|
||||
) = self.calculate_twin_routes_diff(route1, route2)
|
||||
|
||||
for st in stops_missing_from_route1:
|
||||
if (
|
||||
not route1.are_tracks_complete()
|
||||
or (
|
||||
projected_point := project_on_line(
|
||||
st.stoparea.center, route1.tracks
|
||||
)["projected_point"]
|
||||
)
|
||||
is not None
|
||||
and distance(st.stoparea.center, projected_point)
|
||||
<= MAX_DISTANCE_STOP_TO_LINE
|
||||
):
|
||||
self.notice(
|
||||
f"Stop {st.stoparea.station.name} {st.stop} is included "
|
||||
f"into the {route2.id} but not included into {route1.id}",
|
||||
route1.element,
|
||||
)
|
||||
|
||||
for st in stops_missing_from_route2:
|
||||
if (
|
||||
not route2.are_tracks_complete()
|
||||
or (
|
||||
projected_point := project_on_line(
|
||||
st.stoparea.center, route2.tracks
|
||||
)["projected_point"]
|
||||
)
|
||||
is not None
|
||||
and distance(st.stoparea.center, projected_point)
|
||||
<= MAX_DISTANCE_STOP_TO_LINE
|
||||
):
|
||||
self.notice(
|
||||
f"Stop {st.stoparea.station.name} {st.stop} is included "
|
||||
f"into the {route1.id} but not included into {route2.id}",
|
||||
route2.element,
|
||||
)
|
||||
|
||||
for st1, st2 in stops_that_dont_match:
|
||||
if (
|
||||
st1.stoparea.station == st2.stoparea.station
|
||||
or distance(st1.stop, st2.stop) < SUGGEST_TRANSFER_MIN_DISTANCE
|
||||
):
|
||||
self.notice(
|
||||
"Should there be one stoparea or a transfer between "
|
||||
f"{st1.stoparea.station.name} {st1.stop} and "
|
||||
f"{st2.stoparea.station.name} {st2.stop}?",
|
||||
route1.element,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def calculate_twin_routes_diff(route1: Route, route2: Route) -> tuple:
|
||||
"""Wagner–Fischer algorithm for stops diff in two twin routes."""
|
||||
|
||||
stops1 = route1.stops
|
||||
stops2 = route2.stops[::-1]
|
||||
|
||||
def stops_match(stop1: RouteStop, stop2: RouteStop) -> bool:
|
||||
return (
|
||||
stop1.stoparea == stop2.stoparea
|
||||
or stop1.stoparea.transfer is not None
|
||||
and stop1.stoparea.transfer == stop2.stoparea.transfer
|
||||
)
|
||||
|
||||
d = [[0] * (len(stops2) + 1) for _ in range(len(stops1) + 1)]
|
||||
d[0] = list(range(len(stops2) + 1))
|
||||
for i in range(len(stops1) + 1):
|
||||
d[i][0] = i
|
||||
|
||||
for i in range(1, len(stops1) + 1):
|
||||
for j in range(1, len(stops2) + 1):
|
||||
d[i][j] = (
|
||||
d[i - 1][j - 1]
|
||||
if stops_match(stops1[i - 1], stops2[j - 1])
|
||||
else min((d[i - 1][j], d[i][j - 1], d[i - 1][j - 1])) + 1
|
||||
)
|
||||
|
||||
stops_missing_from_route1: list[RouteStop] = []
|
||||
stops_missing_from_route2: list[RouteStop] = []
|
||||
stops_that_dont_match: list[tuple[RouteStop, RouteStop]] = []
|
||||
|
||||
i = len(stops1)
|
||||
j = len(stops2)
|
||||
while not (i == 0 and j == 0):
|
||||
action = None
|
||||
if i > 0 and j > 0:
|
||||
match = stops_match(stops1[i - 1], stops2[j - 1])
|
||||
if match and d[i - 1][j - 1] == d[i][j]:
|
||||
action = "no"
|
||||
elif not match and d[i - 1][j - 1] + 1 == d[i][j]:
|
||||
action = "change"
|
||||
if not action and i > 0 and d[i - 1][j] + 1 == d[i][j]:
|
||||
action = "add_2"
|
||||
if not action and j > 0 and d[i][j - 1] + 1 == d[i][j]:
|
||||
action = "add_1"
|
||||
|
||||
match action:
|
||||
case "add_1":
|
||||
stops_missing_from_route1.append(stops2[j - 1])
|
||||
j -= 1
|
||||
case "add_2":
|
||||
stops_missing_from_route2.append(stops1[i - 1])
|
||||
i -= 1
|
||||
case _:
|
||||
if action == "change":
|
||||
stops_that_dont_match.append(
|
||||
(stops1[i - 1], stops2[j - 1])
|
||||
)
|
||||
i -= 1
|
||||
j -= 1
|
||||
return (
|
||||
stops_missing_from_route1,
|
||||
stops_missing_from_route2,
|
||||
stops_that_dont_match,
|
||||
)
|
||||
|
||||
def validate_lines(self):
|
||||
self.found_light_lines = len(
|
||||
|
|
527
tests/assets/route_masters.osm
Normal file
527
tests/assets/route_masters.osm
Normal file
|
@ -0,0 +1,527 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<osm version='0.6' generator='JOSM'>
|
||||
<node id='1' visible='true' version='1' lat='0.5' lon='0.0'>
|
||||
<tag k='name' v='Station 1' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='2' visible='true' version='1' lat='0.5' lon='1.0'>
|
||||
<tag k='name' v='Station 2' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='3' visible='true' version='1' lat='0.5' lon='2.0'>
|
||||
<tag k='name' v='Station 3' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='5' visible='true' version='1' lat='2.0' lon='1.0'>
|
||||
<tag k='name' v='Station 5' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='8' visible='true' version='1' lat='-2.0' lon='1.5'>
|
||||
<tag k='name' v='Station 8' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='21' visible='true' version='1' lat='0.0' lon='0.0'>
|
||||
<tag k='name' v='Station 1' />
|
||||
<tag k='public_transport' v='stop_position' />
|
||||
<tag k='subway' v='yes' />
|
||||
</node>
|
||||
<node id='22' visible='true' version='1' lat='0.0' lon='1.0'>
|
||||
<tag k='name' v='Station 2' />
|
||||
<tag k='public_transport' v='stop_position' />
|
||||
<tag k='subway' v='yes' />
|
||||
</node>
|
||||
<node id='23' visible='true' version='1' lat='0.0' lon='2.0'>
|
||||
<tag k='name' v='Station 3' />
|
||||
<tag k='public_transport' v='stop_position' />
|
||||
<tag k='subway' v='yes' />
|
||||
</node>
|
||||
<node id='24' visible='true' version='1' lat='0.0' lon='3.0'>
|
||||
<tag k='name' v='Station 4' />
|
||||
<tag k='public_transport' v='stop_position' />
|
||||
<tag k='subway' v='yes' />
|
||||
</node>
|
||||
<node id='31' visible='true' version='1' lat='0.0003' lon='0.0'>
|
||||
<tag k='name' v='Station 1' />
|
||||
<tag k='public_transport' v='stop_position' />
|
||||
<tag k='subway' v='yes' />
|
||||
</node>
|
||||
<node id='32' visible='true' version='1' lat='0.0003' lon='1.0'>
|
||||
<tag k='name' v='Station 2' />
|
||||
<tag k='public_transport' v='stop_position' />
|
||||
<tag k='subway' v='yes' />
|
||||
</node>
|
||||
<node id='33' visible='true' version='1' lat='0.0003' lon='2.0'>
|
||||
<tag k='name' v='Station 3' />
|
||||
<tag k='public_transport' v='stop_position' />
|
||||
<tag k='subway' v='yes' />
|
||||
</node>
|
||||
<node id='34' visible='true' version='1' lat='0.0003' lon='3.0'>
|
||||
<tag k='name' v='Station 4' />
|
||||
<tag k='public_transport' v='stop_position' />
|
||||
<tag k='subway' v='yes' />
|
||||
</node>
|
||||
<node id='101' visible='true' version='1' lat='0.00015' lon='0.0'>
|
||||
<tag k='name' v='Station 1' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='102' visible='true' version='1' lat='0.00015' lon='1.0'>
|
||||
<tag k='name' v='Station 2' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='103' visible='true' version='1' lat='0.00015' lon='2.0'>
|
||||
<tag k='name' v='Station 3' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='104' visible='true' version='1' lat='0.00015' lon='3.0'>
|
||||
<tag k='name' v='Station 4' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='10001' visible='true' version='1' lat='0.0' lon='3.0003' />
|
||||
<node id='10002' visible='true' version='1' lat='0.0' lon='-0.0003' />
|
||||
<way id='1' visible='true' version='1'>
|
||||
<nd ref='21' />
|
||||
<nd ref='22' />
|
||||
<nd ref='23' />
|
||||
<nd ref='24' />
|
||||
<tag k='railway' v='subway' />
|
||||
</way>
|
||||
<way id='2' visible='true' version='1'>
|
||||
<nd ref='34' />
|
||||
<nd ref='33' />
|
||||
<nd ref='32' />
|
||||
<nd ref='31' />
|
||||
<tag k='railway' v='subway' />
|
||||
</way>
|
||||
<way id='3' visible='true' version='1'>
|
||||
<nd ref='24' />
|
||||
<nd ref='8' />
|
||||
<nd ref='21' />
|
||||
<tag k='railway' v='subway' />
|
||||
</way>
|
||||
<way id='4' visible='true' version='1'>
|
||||
<nd ref='34' />
|
||||
<nd ref='10001' />
|
||||
<nd ref='8' />
|
||||
<nd ref='10002' />
|
||||
<nd ref='31' />
|
||||
<tag k='railway' v='subway' />
|
||||
</way>
|
||||
<relation id='102' visible='true' version='1'>
|
||||
<member type='node' ref='102' role='' />
|
||||
<member type='node' ref='32' role='stop' />
|
||||
<member type='node' ref='22' role='stop' />
|
||||
<tag k='public_transport' v='stop_area' />
|
||||
<tag k='type' v='public_transport' />
|
||||
</relation>
|
||||
<relation id='103' visible='true' version='1'>
|
||||
<member type='node' ref='103' role='' />
|
||||
<member type='node' ref='23' role='stop' />
|
||||
<tag k='public_transport' v='stop_area' />
|
||||
<tag k='type' v='public_transport' />
|
||||
</relation>
|
||||
<relation id='104' visible='true' version='1'>
|
||||
<member type='node' ref='104' role='' />
|
||||
<member type='node' ref='24' role='stop' />
|
||||
<tag k='public_transport' v='stop_area' />
|
||||
<tag k='type' v='public_transport' />
|
||||
</relation>
|
||||
<relation id='107' visible='true' version='1'>
|
||||
<member type='node' ref='101' role='' />
|
||||
<member type='node' ref='21' role='stop' />
|
||||
<member type='node' ref='31' role='stop' />
|
||||
<tag k='public_transport' v='stop_area' />
|
||||
<tag k='type' v='public_transport' />
|
||||
</relation>
|
||||
<relation id='113' visible='true' version='1'>
|
||||
<member type='node' ref='103' role='' />
|
||||
<member type='node' ref='33' role='stop' />
|
||||
<tag k='public_transport' v='stop_area' />
|
||||
<tag k='type' v='public_transport' />
|
||||
</relation>
|
||||
<relation id='114' visible='true' version='1'>
|
||||
<member type='node' ref='104' role='' />
|
||||
<member type='node' ref='34' role='stop' />
|
||||
<tag k='public_transport' v='stop_area' />
|
||||
<tag k='type' v='public_transport' />
|
||||
</relation>
|
||||
<relation id='151' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<tag k='name' v='01: 1-2-3' />
|
||||
<tag k='ref' v='01' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='153' visible='true' version='1'>
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<tag k='name' v='01: 3-2-1' />
|
||||
<tag k='ref' v='01' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='155' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<tag k='name' v='02: 1-2-3' />
|
||||
<tag k='ref' v='02' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='158' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<tag k='name' v='02: 1-3 (2)' />
|
||||
<tag k='ref' v='02' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='159' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<tag k='name' v='C: 1-3-5-1' />
|
||||
<tag k='note' v='Circular route without backward' />
|
||||
<tag k='ref' v='C' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='160' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<tag k='name' v='C2: 1-5-3-1' />
|
||||
<tag k='note' v='Circular route with backward' />
|
||||
<tag k='ref' v='C2' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='161' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<tag k='name' v='C2: 1-3-5-1' />
|
||||
<tag k='note' v='Circular route with backward' />
|
||||
<tag k='ref' v='C2' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='162' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<tag k='name' v='03: 1-2-3' />
|
||||
<tag k='note' v='Route without backward variants and without route_master' />
|
||||
<tag k='ref' v='03' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='163' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<tag k='name' v='04: 1-2-3' />
|
||||
<tag k='ref' v='04' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='164' visible='true' version='1'>
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<tag k='name' v='04: 2-1' />
|
||||
<tag k='ref' v='04' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='165' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<tag k='name' v='05: 1-2-3' />
|
||||
<tag k='note' v='No route_master. Will find twin by ref.' />
|
||||
<tag k='ref' v='05' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='166' visible='true' version='1'>
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<tag k='name' v='05: 3-2-1' />
|
||||
<tag k='note' v='No route_master. Will find twin by ref.' />
|
||||
<tag k='ref' v='05' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='167' visible='true' version='1'>
|
||||
<tag k='note' v='Empty route_master, so that it cannot be assigned to any city' />
|
||||
<tag k='ref' v='06' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='201' visible='true' version='1'>
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='node' ref='22' role='' />
|
||||
<member type='node' ref='23' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<tag k='name' v='1: 1-2-3' />
|
||||
<tag k='ref' v='1' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='202' visible='true' version='1'>
|
||||
<member type='node' ref='33' role='' />
|
||||
<member type='node' ref='32' role='' />
|
||||
<member type='node' ref='31' role='' />
|
||||
<member type='way' ref='2' role='' />
|
||||
<tag k='name' v='1: 3-2-1' />
|
||||
<tag k='ref' v='1' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='203' visible='true' version='1'>
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='node' ref='22' role='' />
|
||||
<member type='node' ref='23' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<tag k='name' v='2: 1-2-3' />
|
||||
<tag k='ref' v='2' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='204' visible='true' version='1'>
|
||||
<member type='node' ref='33' role='' />
|
||||
<member type='node' ref='31' role='' />
|
||||
<member type='way' ref='2' role='' />
|
||||
<tag k='name' v='2: 3-1' />
|
||||
<tag k='ref' v='2' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='205' visible='true' version='1'>
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='node' ref='22' role='' />
|
||||
<member type='node' ref='23' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<tag k='name' v='3: 1-2-3' />
|
||||
<tag k='ref' v='3' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='206' visible='true' version='1'>
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='node' ref='22' role='' />
|
||||
<member type='node' ref='23' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<tag k='name' v='3: 1-2-3' />
|
||||
<tag k='ref' v='3' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='207' visible='true' version='1'>
|
||||
<member type='node' ref='34' role='' />
|
||||
<member type='node' ref='33' role='' />
|
||||
<member type='node' ref='32' role='' />
|
||||
<member type='node' ref='31' role='' />
|
||||
<member type='way' ref='2' role='' />
|
||||
<tag k='name' v='4: 4-3-2-1' />
|
||||
<tag k='ref' v='4' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='208' visible='true' version='1'>
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='node' ref='22' role='' />
|
||||
<member type='node' ref='23' role='' />
|
||||
<member type='node' ref='24' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<tag k='name' v='4: 1-2-3-4' />
|
||||
<tag k='ref' v='4' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='209' visible='true' version='1'>
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='node' ref='22' role='' />
|
||||
<member type='node' ref='23' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<tag k='name' v='5: 1-2-3' />
|
||||
<tag k='ref' v='5' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='210' visible='true' version='1'>
|
||||
<member type='node' ref='32' role='' />
|
||||
<member type='node' ref='31' role='' />
|
||||
<member type='way' ref='2' role='' />
|
||||
<tag k='name' v='5: 2-1' />
|
||||
<tag k='ref' v='5' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='211' visible='true' version='1'>
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='node' ref='22' role='' />
|
||||
<member type='node' ref='23' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<member type='way' ref='3' role='' />
|
||||
<tag k='name' v='C4: 1-2-3-8-1' />
|
||||
<tag k='ref' v='C4' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='212' visible='true' version='1'>
|
||||
<member type='node' ref='33' role='' />
|
||||
<member type='node' ref='32' role='' />
|
||||
<member type='node' ref='31' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='33' role='' />
|
||||
<member type='way' ref='2' role='' />
|
||||
<member type='way' ref='4' role='' />
|
||||
<tag k='name' v='C4: 3-2-1-8-3' />
|
||||
<tag k='ref' v='C4' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='213' visible='true' version='1'>
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='node' ref='22' role='' />
|
||||
<member type='node' ref='23' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<member type='way' ref='3' role='' />
|
||||
<tag k='name' v='C3: 1-2-3-8-1' />
|
||||
<tag k='note' v='Circular route without backward' />
|
||||
<tag k='ref' v='C3' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='1003' visible='true' version='1'>
|
||||
<member type='relation' ref='103' role='' />
|
||||
<member type='relation' ref='113' role='' />
|
||||
<tag k='public_transport' v='stop_area_group' />
|
||||
<tag k='type' v='public_transport' />
|
||||
</relation>
|
||||
<relation id='10001' visible='true' version='1'>
|
||||
<member type='relation' ref='201' role='' />
|
||||
<member type='relation' ref='202' role='' />
|
||||
<tag k='note' v='Ideal twins. One end is one stop_area, another - two stop_areas combined into a transfer' />
|
||||
<tag k='ref' v='1' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='10002' visible='true' version='1'>
|
||||
<member type='relation' ref='203' role='' />
|
||||
<member type='relation' ref='204' role='' />
|
||||
<tag k='note' v='Routes with matching ends that differ in station count' />
|
||||
<tag k='ref' v='2' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='10003' visible='true' version='1'>
|
||||
<member type='relation' ref='205' role='' />
|
||||
<member type='relation' ref='206' role='' />
|
||||
<tag k='note' v='Two routes with the same ends AND with the same direction' />
|
||||
<tag k='ref' v='3' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='10004' visible='true' version='1'>
|
||||
<member type='relation' ref='208' role='' />
|
||||
<member type='relation' ref='207' role='' />
|
||||
<tag k='note' v='Two routes one end of which belongs to different stop_areas without transfer' />
|
||||
<tag k='ref' v='4' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='10005' visible='true' version='1'>
|
||||
<member type='relation' ref='209' role='' />
|
||||
<member type='relation' ref='210' role='' />
|
||||
<tag k='note' v='Almost twins, but end stations are different' />
|
||||
<tag k='ref' v='5' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='10006' visible='true' version='1'>
|
||||
<member type='relation' ref='211' role='' />
|
||||
<member type='relation' ref='212' role='' />
|
||||
<tag k='note' v='Circular route with forward and backward directions' />
|
||||
<tag k='ref' v='C4' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='10007' visible='true' version='1'>
|
||||
<member type='relation' ref='163' role='' />
|
||||
<member type='relation' ref='164' role='' />
|
||||
<tag k='note' v='Bad: end stations are different' />
|
||||
<tag k='ref' v='04' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='10021' visible='true' version='1'>
|
||||
<member type='relation' ref='151' role='' />
|
||||
<member type='relation' ref='153' role='' />
|
||||
<tag k='note' v='Good route master with full twin routes' />
|
||||
<tag k='ref' v='01' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='10022' visible='true' version='1'>
|
||||
<member type='relation' ref='155' role='' />
|
||||
<member type='relation' ref='158' role='' />
|
||||
<tag k='note' v='Good master, but backward route omits inner stations' />
|
||||
<tag k='ref' v='02' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='10023' visible='true' version='1'>
|
||||
<member type='relation' ref='161' role='' />
|
||||
<member type='relation' ref='160' role='' />
|
||||
<tag k='note' v='Circular route with both directions' />
|
||||
<tag k='ref' v='C2' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='10024' visible='true' version='1'>
|
||||
<member type='node' ref='2' role='' />
|
||||
<tag k='note' v='Empty route_master, but center can be calculated due to a spurious member' />
|
||||
<tag k='ref' v='07' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
</osm>
|
578
tests/assets/twin_routes.osm
Normal file
578
tests/assets/twin_routes.osm
Normal file
|
@ -0,0 +1,578 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<osm version='0.6' generator='JOSM'>
|
||||
<node id='1' visible='true' version='1' lat='0.5' lon='0.0'>
|
||||
<tag k='name' v='Station 1' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='2' visible='true' version='1' lat='0.5' lon='1.0'>
|
||||
<tag k='name' v='Station 2' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='3' visible='true' version='1' lat='0.5' lon='2.0'>
|
||||
<tag k='name' v='Station 3' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='4' visible='true' version='1' lat='0.5' lon='3.0'>
|
||||
<tag k='name' v='Station 4' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='5' visible='true' version='1' lat='2.0' lon='1.5'>
|
||||
<tag k='name' v='Station 5' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='8' visible='true' version='1' lat='-3.5' lon='3.0'>
|
||||
<tag k='name' v='Station 8' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='21' visible='true' version='1' lat='0.0' lon='0.0'>
|
||||
<tag k='name' v='Station 1' />
|
||||
<tag k='public_transport' v='stop_position' />
|
||||
<tag k='subway' v='yes' />
|
||||
</node>
|
||||
<node id='22' visible='true' version='1' lat='0.0' lon='1.0'>
|
||||
<tag k='name' v='Station 2' />
|
||||
<tag k='public_transport' v='stop_position' />
|
||||
<tag k='subway' v='yes' />
|
||||
</node>
|
||||
<node id='23' visible='true' version='1' lat='0.0' lon='2.0'>
|
||||
<tag k='name' v='Station 3' />
|
||||
<tag k='public_transport' v='stop_position' />
|
||||
<tag k='subway' v='yes' />
|
||||
</node>
|
||||
<node id='24' visible='true' version='1' lat='0.0' lon='3.0'>
|
||||
<tag k='name' v='Station 4' />
|
||||
<tag k='public_transport' v='stop_position' />
|
||||
<tag k='subway' v='yes' />
|
||||
</node>
|
||||
<node id='25' visible='true' version='1' lat='0.0' lon='4.0' />
|
||||
<node id='26' visible='true' version='1' lat='0.0' lon='5.0'>
|
||||
<tag k='name' v='Station 6' />
|
||||
<tag k='public_transport' v='stop_position' />
|
||||
<tag k='subway' v='yes' />
|
||||
</node>
|
||||
<node id='27' visible='true' version='1' lat='0.0' lon='6.0' />
|
||||
<node id='31' visible='true' version='1' lat='0.0003' lon='0.0'>
|
||||
<tag k='name' v='Station 1' />
|
||||
<tag k='public_transport' v='stop_position' />
|
||||
<tag k='subway' v='yes' />
|
||||
</node>
|
||||
<node id='32' visible='true' version='1' lat='0.0003' lon='1.0'>
|
||||
<tag k='name' v='Station 2' />
|
||||
<tag k='public_transport' v='stop_position' />
|
||||
<tag k='subway' v='yes' />
|
||||
</node>
|
||||
<node id='33' visible='true' version='1' lat='0.0003' lon='2.0'>
|
||||
<tag k='name' v='Station 3' />
|
||||
<tag k='public_transport' v='stop_position' />
|
||||
<tag k='subway' v='yes' />
|
||||
</node>
|
||||
<node id='34' visible='true' version='1' lat='0.0003' lon='3.0'>
|
||||
<tag k='name' v='Station 4' />
|
||||
<tag k='public_transport' v='stop_position' />
|
||||
<tag k='subway' v='yes' />
|
||||
</node>
|
||||
<node id='35' visible='true' version='1' lat='0.0003' lon='4.0' />
|
||||
<node id='36' visible='true' version='1' lat='0.0003' lon='5.0'>
|
||||
<tag k='name' v='Station 6' />
|
||||
<tag k='public_transport' v='stop_position' />
|
||||
<tag k='subway' v='yes' />
|
||||
</node>
|
||||
<node id='37' visible='true' version='1' lat='0.0003' lon='6.0' />
|
||||
<node id='101' visible='true' version='1' lat='0.00015' lon='0.0'>
|
||||
<tag k='name' v='Station 1' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='102' visible='true' version='1' lat='0.00015' lon='1.0'>
|
||||
<tag k='name' v='Station 2' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='103' visible='true' version='1' lat='0.00015' lon='2.0'>
|
||||
<tag k='name' v='Station 3' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='104' visible='true' version='1' lat='0.00015' lon='3.0'>
|
||||
<tag k='name' v='Station 4' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='105' visible='true' version='1' lat='0.00015' lon='4.0'>
|
||||
<tag k='name' v='Station 5' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='106' visible='true' version='1' lat='0.00015' lon='5.0'>
|
||||
<tag k='name' v='Station 6' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='107' visible='true' version='1' lat='0.00015' lon='6.0'>
|
||||
<tag k='name' v='Station 7' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='10001' visible='true' version='1' lat='0.0' lon='6.0003' />
|
||||
<node id='10002' visible='true' version='1' lat='0.0' lon='-0.0003' />
|
||||
<way id='1' visible='true' version='1'>
|
||||
<nd ref='21' />
|
||||
<nd ref='22' />
|
||||
<nd ref='23' />
|
||||
<nd ref='24' />
|
||||
<nd ref='25' />
|
||||
<nd ref='26' />
|
||||
<nd ref='27' />
|
||||
<tag k='railway' v='subway' />
|
||||
</way>
|
||||
<way id='2' visible='true' version='1'>
|
||||
<nd ref='37' />
|
||||
<nd ref='36' />
|
||||
<nd ref='35' />
|
||||
<nd ref='34' />
|
||||
<nd ref='33' />
|
||||
<nd ref='32' />
|
||||
<nd ref='31' />
|
||||
<tag k='railway' v='subway' />
|
||||
</way>
|
||||
<way id='3' visible='true' version='1'>
|
||||
<nd ref='27' />
|
||||
<nd ref='8' />
|
||||
<nd ref='21' />
|
||||
<tag k='railway' v='subway' />
|
||||
</way>
|
||||
<way id='4' visible='true' version='1'>
|
||||
<nd ref='37' />
|
||||
<nd ref='10001' />
|
||||
<nd ref='8' />
|
||||
<nd ref='10002' />
|
||||
<nd ref='31' />
|
||||
<tag k='railway' v='subway' />
|
||||
</way>
|
||||
<relation id='102' visible='true' version='1'>
|
||||
<member type='node' ref='102' role='' />
|
||||
<member type='node' ref='32' role='stop' />
|
||||
<member type='node' ref='22' role='stop' />
|
||||
<tag k='public_transport' v='stop_area' />
|
||||
<tag k='type' v='public_transport' />
|
||||
</relation>
|
||||
<relation id='103' visible='true' version='1'>
|
||||
<member type='node' ref='103' role='' />
|
||||
<member type='node' ref='23' role='stop' />
|
||||
<tag k='public_transport' v='stop_area' />
|
||||
<tag k='type' v='public_transport' />
|
||||
</relation>
|
||||
<relation id='104' visible='true' version='1'>
|
||||
<member type='node' ref='104' role='' />
|
||||
<member type='node' ref='24' role='stop' />
|
||||
<tag k='public_transport' v='stop_area' />
|
||||
<tag k='type' v='public_transport' />
|
||||
</relation>
|
||||
<relation id='106' visible='true' version='1'>
|
||||
<member type='node' ref='36' role='stop' />
|
||||
<member type='node' ref='106' role='' />
|
||||
<tag k='public_transport' v='stop_area' />
|
||||
<tag k='type' v='public_transport' />
|
||||
</relation>
|
||||
<relation id='107' visible='true' version='1'>
|
||||
<member type='node' ref='101' role='' />
|
||||
<member type='node' ref='21' role='stop' />
|
||||
<member type='node' ref='31' role='stop' />
|
||||
<tag k='public_transport' v='stop_area' />
|
||||
<tag k='type' v='public_transport' />
|
||||
</relation>
|
||||
<relation id='113' visible='true' version='1'>
|
||||
<member type='node' ref='103' role='' />
|
||||
<member type='node' ref='33' role='stop' />
|
||||
<tag k='public_transport' v='stop_area' />
|
||||
<tag k='type' v='public_transport' />
|
||||
</relation>
|
||||
<relation id='114' visible='true' version='1'>
|
||||
<member type='node' ref='104' role='' />
|
||||
<member type='node' ref='34' role='stop' />
|
||||
<tag k='public_transport' v='stop_area' />
|
||||
<tag k='type' v='public_transport' />
|
||||
</relation>
|
||||
<relation id='116' visible='true' version='1'>
|
||||
<member type='node' ref='106' role='' />
|
||||
<member type='node' ref='26' role='stop' />
|
||||
<tag k='public_transport' v='stop_area' />
|
||||
<tag k='type' v='public_transport' />
|
||||
</relation>
|
||||
<relation id='151' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<tag k='name' v='01: 1-2-3' />
|
||||
<tag k='ref' v='01' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='152' visible='true' version='1'>
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<tag k='name' v='01: 3-1' />
|
||||
<tag k='ref' v='01' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='153' visible='true' version='1'>
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<tag k='name' v='01: 3-2-1' />
|
||||
<tag k='ref' v='01' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='154' visible='true' version='1'>
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<tag k='name' v='02: 4-3' />
|
||||
<tag k='ref' v='02' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='155' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<tag k='name' v='02: 1-3' />
|
||||
<tag k='ref' v='02' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='156' visible='true' version='1'>
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<tag k='name' v='02: 2-4' />
|
||||
<tag k='ref' v='02' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='157' visible='true' version='1'>
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<tag k='name' v='02: 4-1' />
|
||||
<tag k='ref' v='02' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='158' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<tag k='name' v='02: 1-3 (2)' />
|
||||
<tag k='note' v='This should not be recognized as twin for route "2: 1-3"' />
|
||||
<tag k='ref' v='02' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='159' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='name' v='C: 1-2-3-4-5-1' />
|
||||
<tag k='note' v='Circular route without backward' />
|
||||
<tag k='ref' v='C' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='160' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<tag k='name' v='C2: 1-5-4-3-2-1' />
|
||||
<tag k='note' v='Circular route with backward' />
|
||||
<tag k='ref' v='C2' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='161' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<tag k='name' v='C2: 1-2-3-4-5-1' />
|
||||
<tag k='note' v='Circular route with backward' />
|
||||
<tag k='ref' v='C2' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='201' visible='true' version='1'>
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='node' ref='22' role='' />
|
||||
<member type='node' ref='23' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<tag k='name' v='1: 1-2-3' />
|
||||
<tag k='ref' v='1' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='202' visible='true' version='1'>
|
||||
<member type='node' ref='33' role='' />
|
||||
<member type='node' ref='32' role='' />
|
||||
<member type='node' ref='31' role='' />
|
||||
<member type='way' ref='2' role='' />
|
||||
<tag k='name' v='1: 3-2-1' />
|
||||
<tag k='ref' v='1' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='203' visible='true' version='1'>
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='node' ref='22' role='' />
|
||||
<member type='node' ref='23' role='' />
|
||||
<member type='node' ref='105' role='' />
|
||||
<member type='node' ref='26' role='' />
|
||||
<member type='node' ref='107' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<tag k='name' v='2: 1-2-3-5-6-7' />
|
||||
<tag k='ref' v='2' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='204' visible='true' version='1'>
|
||||
<member type='node' ref='107' role='' />
|
||||
<member type='node' ref='36' role='' />
|
||||
<member type='node' ref='31' role='' />
|
||||
<member type='way' ref='2' role='' />
|
||||
<tag k='name' v='2: 7-6-1' />
|
||||
<tag k='ref' v='2' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='205' visible='true' version='1'>
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='node' ref='22' role='' />
|
||||
<member type='node' ref='23' role='' />
|
||||
<member type='node' ref='24' role='' />
|
||||
<member type='node' ref='105' role='' />
|
||||
<member type='node' ref='26' role='' />
|
||||
<member type='node' ref='107' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<tag k='name' v='3: 1-2-3-4-5-6-7' />
|
||||
<tag k='ref' v='3' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='206' visible='true' version='1'>
|
||||
<member type='node' ref='107' role='' />
|
||||
<member type='node' ref='36' role='' />
|
||||
<member type='node' ref='105' role='' />
|
||||
<member type='node' ref='33' role='' />
|
||||
<member type='node' ref='32' role='' />
|
||||
<member type='node' ref='31' role='' />
|
||||
<member type='way' ref='2' role='' />
|
||||
<tag k='name' v='3: 7-6-5-3-2-1' />
|
||||
<tag k='ref' v='3' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='207' visible='true' version='1'>
|
||||
<member type='node' ref='34' role='' />
|
||||
<member type='node' ref='33' role='' />
|
||||
<member type='node' ref='32' role='' />
|
||||
<member type='node' ref='31' role='' />
|
||||
<member type='way' ref='2' role='' />
|
||||
<tag k='name' v='4: 4-3-2-1' />
|
||||
<tag k='ref' v='4' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='208' visible='true' version='1'>
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='node' ref='22' role='' />
|
||||
<member type='node' ref='23' role='' />
|
||||
<member type='node' ref='24' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<tag k='name' v='4: 1-2-3-4' />
|
||||
<tag k='ref' v='4' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='209' visible='true' version='1'>
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='node' ref='22' role='' />
|
||||
<member type='node' ref='23' role='' />
|
||||
<member type='node' ref='105' role='' />
|
||||
<member type='node' ref='26' role='' />
|
||||
<member type='node' ref='107' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<tag k='name' v='5: 1-2-3-5-6-7' />
|
||||
<tag k='ref' v='5' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='210' visible='true' version='1'>
|
||||
<member type='node' ref='36' role='' />
|
||||
<member type='node' ref='105' role='' />
|
||||
<member type='node' ref='33' role='' />
|
||||
<member type='node' ref='32' role='' />
|
||||
<member type='node' ref='31' role='' />
|
||||
<member type='way' ref='2' role='' />
|
||||
<tag k='name' v='5: 6-5-3-2-1' />
|
||||
<tag k='ref' v='5' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='211' visible='true' version='1'>
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='node' ref='22' role='' />
|
||||
<member type='node' ref='23' role='' />
|
||||
<member type='node' ref='105' role='' />
|
||||
<member type='node' ref='26' role='' />
|
||||
<member type='node' ref='107' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<member type='way' ref='3' role='' />
|
||||
<tag k='name' v='C4: 1-2-3-5-6-7-8-1' />
|
||||
<tag k='ref' v='C4' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='212' visible='true' version='1'>
|
||||
<member type='node' ref='107' role='' />
|
||||
<member type='node' ref='36' role='' />
|
||||
<member type='node' ref='105' role='' />
|
||||
<member type='node' ref='33' role='' />
|
||||
<member type='node' ref='32' role='' />
|
||||
<member type='node' ref='31' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='107' role='' />
|
||||
<member type='way' ref='2' role='' />
|
||||
<member type='way' ref='4' role='' />
|
||||
<tag k='name' v='C4: 7-6-5-3-2-1-8-7' />
|
||||
<tag k='ref' v='C4' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='213' visible='true' version='1'>
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='node' ref='22' role='' />
|
||||
<member type='node' ref='23' role='' />
|
||||
<member type='node' ref='105' role='' />
|
||||
<member type='node' ref='26' role='' />
|
||||
<member type='node' ref='107' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<member type='way' ref='3' role='' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='name' v='C3: 1-2-3-5-6-7-8-1' />
|
||||
<tag k='note' v='Circular route without backward' />
|
||||
<tag k='ref' v='C3' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='1003' visible='true' version='1'>
|
||||
<member type='relation' ref='103' role='' />
|
||||
<member type='relation' ref='113' role='' />
|
||||
<tag k='public_transport' v='stop_area_group' />
|
||||
<tag k='type' v='public_transport' />
|
||||
</relation>
|
||||
<relation id='1006' visible='true' version='1'>
|
||||
<member type='relation' ref='116' role='' />
|
||||
<member type='relation' ref='106' role='' />
|
||||
<tag k='public_transport' v='stop_area_group' />
|
||||
<tag k='type' v='public_transport' />
|
||||
</relation>
|
||||
<relation id='10001' visible='true' version='1'>
|
||||
<member type='relation' ref='201' role='' />
|
||||
<member type='relation' ref='202' role='' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='note' v='Ideal twins. One end is one stop_area, another - two stop_areas combined into a transfer' />
|
||||
<tag k='ref' v='1' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='10002' visible='true' version='1'>
|
||||
<member type='relation' ref='203' role='' />
|
||||
<member type='relation' ref='204' role='' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='note' v='Twin candidates that differ by 50% in station count' />
|
||||
<tag k='ref' v='2' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='10003' visible='true' version='1'>
|
||||
<member type='relation' ref='205' role='' />
|
||||
<member type='relation' ref='206' role='' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='note' v='Twins that differ by 15% in station count' />
|
||||
<tag k='ref' v='3' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='10004' visible='true' version='1'>
|
||||
<member type='relation' ref='207' role='' />
|
||||
<member type='relation' ref='208' role='' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='note' v='Two routes one end of which belongs to different stop_areas without transfer' />
|
||||
<tag k='ref' v='4' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='10005' visible='true' version='1'>
|
||||
<member type='relation' ref='209' role='' />
|
||||
<member type='relation' ref='210' role='' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='note' v='Almost twins, but end stations are different' />
|
||||
<tag k='ref' v='5' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='10006' visible='true' version='1'>
|
||||
<member type='relation' ref='211' role='' />
|
||||
<member type='relation' ref='212' role='' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='ref' v='C4' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='10021' visible='true' version='1'>
|
||||
<member type='relation' ref='151' role='' />
|
||||
<member type='relation' ref='152' role='' />
|
||||
<member type='relation' ref='153' role='' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='note' v='There is a Forward 1 route (1-2-3) and two backward (3-1 and 3-2-1). Twin for forward should be 3-station backward variant.' />
|
||||
<tag k='ref' v='01' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='10022' visible='true' version='1'>
|
||||
<member type='relation' ref='154' role='' />
|
||||
<member type='relation' ref='155' role='' />
|
||||
<member type='relation' ref='156' role='' />
|
||||
<member type='relation' ref='157' role='' />
|
||||
<member type='relation' ref='158' role='' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='note' v='At least two routes in each direction, but no twins. Duplicated route is not a twin.' />
|
||||
<tag k='ref' v='02' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='10023' visible='true' version='1'>
|
||||
<member type='relation' ref='161' role='' />
|
||||
<member type='relation' ref='160' role='' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='note' v='Circular route with both directions' />
|
||||
<tag k='ref' v='C2' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
</osm>
|
680
tests/assets/twin_routes_with_divergence.osm
Normal file
680
tests/assets/twin_routes_with_divergence.osm
Normal file
|
@ -0,0 +1,680 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<osm version='0.6' generator='JOSM'>
|
||||
<node id='1' visible='true' version='1' lat='0.0' lon='0.0'>
|
||||
<tag k='name' v='Station 1' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='2' visible='true' version='1' lat='0.0' lon='0.01'>
|
||||
<tag k='name' v='Station 2' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='3' visible='true' version='1' lat='0.0' lon='0.02'>
|
||||
<tag k='name' v='Station 3' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='4' visible='true' version='1' lat='0.0' lon='0.03'>
|
||||
<tag k='name' v='Station 4' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='5' visible='true' version='1' lat='0.0' lon='0.04'>
|
||||
<tag k='name' v='Station 5' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='6' visible='true' version='1' lat='0.0' lon='0.05'>
|
||||
<tag k='name' v='Station 6' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='7' visible='true' version='1' lat='0.0' lon='0.06'>
|
||||
<tag k='name' v='Station 7' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='8' visible='true' version='1' lat='0.0' lon='0.07'>
|
||||
<tag k='name' v='Station 8' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='9' visible='true' version='1' lat='0.0' lon='0.08'>
|
||||
<tag k='name' v='Station 9' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='10' visible='true' version='1' lat='0.0' lon='0.09'>
|
||||
<tag k='name' v='Station 10' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='11' visible='true' version='1' lat='0.0' lon='0.1'>
|
||||
<tag k='name' v='Station 11' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='12' visible='true' version='1' lat='0.0' lon='0.11'>
|
||||
<tag k='name' v='Station 12' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='13' visible='true' version='1' lat='0.0' lon='0.12'>
|
||||
<tag k='name' v='Station 13' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='14' visible='true' version='1' lat='0.0' lon='0.13'>
|
||||
<tag k='name' v='Station 14' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='15' visible='true' version='1' lat='0.0' lon='0.14'>
|
||||
<tag k='name' v='Station 15' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='16' visible='true' version='1' lat='0.0' lon='0.15'>
|
||||
<tag k='name' v='Station 16' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='17' visible='true' version='1' lat='0.0' lon='0.16'>
|
||||
<tag k='name' v='Station 17' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='18' visible='true' version='1' lat='0.0' lon='0.17'>
|
||||
<tag k='name' v='Station 18' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='19' visible='true' version='1' lat='0.0' lon='0.18'>
|
||||
<tag k='name' v='Station 19' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='20' visible='true' version='1' lat='0.0' lon='0.19'>
|
||||
<tag k='name' v='Station 20' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='21' visible='true' version='1' lat='0.0003' lon='0.09'>
|
||||
<tag k='name' v='Station 10(1)' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='22' visible='true' version='1' lat='0.0003' lon='0.1'>
|
||||
<tag k='name' v='Station 11(1)' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='23' visible='true' version='1' lat='0.004' lon='0.09'>
|
||||
<tag k='name' v='Station 10(2)' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<node id='24' visible='true' version='1' lat='0.004' lon='0.1'>
|
||||
<tag k='name' v='Station 11(2)' />
|
||||
<tag k='railway' v='station' />
|
||||
<tag k='station' v='subway' />
|
||||
</node>
|
||||
<way id='1' visible='true' version='1'>
|
||||
<nd ref='1' />
|
||||
<nd ref='2' />
|
||||
<nd ref='3' />
|
||||
<nd ref='4' />
|
||||
<nd ref='5' />
|
||||
<nd ref='6' />
|
||||
<nd ref='7' />
|
||||
<nd ref='8' />
|
||||
<nd ref='9' />
|
||||
<tag k='railway' v='subway' />
|
||||
</way>
|
||||
<way id='2' visible='true' version='1'>
|
||||
<nd ref='9' />
|
||||
<nd ref='10' />
|
||||
<nd ref='11' />
|
||||
<nd ref='12' />
|
||||
<tag k='railway' v='subway' />
|
||||
</way>
|
||||
<way id='3' visible='true' version='1'>
|
||||
<nd ref='12' />
|
||||
<nd ref='13' />
|
||||
<nd ref='14' />
|
||||
<nd ref='15' />
|
||||
<nd ref='16' />
|
||||
<nd ref='17' />
|
||||
<nd ref='18' />
|
||||
<nd ref='19' />
|
||||
<nd ref='20' />
|
||||
<tag k='railway' v='subway' />
|
||||
</way>
|
||||
<way id='4' visible='true' version='1'>
|
||||
<nd ref='9' />
|
||||
<nd ref='21' />
|
||||
<nd ref='22' />
|
||||
<nd ref='12' />
|
||||
<tag k='railway' v='subway' />
|
||||
</way>
|
||||
<way id='5' visible='true' version='1'>
|
||||
<nd ref='9' />
|
||||
<nd ref='23' />
|
||||
<nd ref='24' />
|
||||
<nd ref='12' />
|
||||
<tag k='railway' v='subway' />
|
||||
</way>
|
||||
<relation id='101' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='6' role='' />
|
||||
<member type='node' ref='7' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='9' role='' />
|
||||
<member type='node' ref='10' role='' />
|
||||
<member type='node' ref='11' role='' />
|
||||
<member type='node' ref='12' role='' />
|
||||
<member type='node' ref='13' role='' />
|
||||
<member type='node' ref='14' role='' />
|
||||
<member type='node' ref='15' role='' />
|
||||
<member type='node' ref='16' role='' />
|
||||
<member type='node' ref='17' role='' />
|
||||
<member type='node' ref='18' role='' />
|
||||
<member type='node' ref='19' role='' />
|
||||
<member type='node' ref='20' role='' />
|
||||
<tag k='name' v='1: 1-...-9-10-11-...-20' />
|
||||
<tag k='ref' v='1' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='102' visible='true' version='1'>
|
||||
<member type='node' ref='20' role='' />
|
||||
<member type='node' ref='19' role='' />
|
||||
<member type='node' ref='18' role='' />
|
||||
<member type='node' ref='17' role='' />
|
||||
<member type='node' ref='16' role='' />
|
||||
<member type='node' ref='15' role='' />
|
||||
<member type='node' ref='14' role='' />
|
||||
<member type='node' ref='13' role='' />
|
||||
<member type='node' ref='12' role='' />
|
||||
<member type='node' ref='22' role='' />
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='node' ref='9' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='7' role='' />
|
||||
<member type='node' ref='6' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<tag k='name' v='1: 20-...12-11(1)-10(1)-9-...-1' />
|
||||
<tag k='ref' v='1' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='103' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='6' role='' />
|
||||
<member type='node' ref='7' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='9' role='' />
|
||||
<member type='node' ref='10' role='' />
|
||||
<member type='node' ref='11' role='' />
|
||||
<member type='node' ref='12' role='' />
|
||||
<member type='node' ref='13' role='' />
|
||||
<member type='node' ref='14' role='' />
|
||||
<member type='node' ref='15' role='' />
|
||||
<member type='node' ref='16' role='' />
|
||||
<member type='node' ref='17' role='' />
|
||||
<member type='node' ref='18' role='' />
|
||||
<member type='node' ref='19' role='' />
|
||||
<member type='node' ref='20' role='' />
|
||||
<tag k='name' v='2: 1-...-9-10-11-...-20' />
|
||||
<tag k='ref' v='2' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='104' visible='true' version='1'>
|
||||
<member type='node' ref='20' role='' />
|
||||
<member type='node' ref='19' role='' />
|
||||
<member type='node' ref='18' role='' />
|
||||
<member type='node' ref='17' role='' />
|
||||
<member type='node' ref='16' role='' />
|
||||
<member type='node' ref='15' role='' />
|
||||
<member type='node' ref='14' role='' />
|
||||
<member type='node' ref='13' role='' />
|
||||
<member type='node' ref='12' role='' />
|
||||
<member type='node' ref='24' role='' />
|
||||
<member type='node' ref='23' role='' />
|
||||
<member type='node' ref='9' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='7' role='' />
|
||||
<member type='node' ref='6' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<tag k='name' v='2: 20-...12-11(2)-10(2)-9-...-1' />
|
||||
<tag k='ref' v='2' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='105' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='6' role='' />
|
||||
<member type='node' ref='7' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='9' role='' />
|
||||
<member type='node' ref='10' role='' />
|
||||
<member type='node' ref='11' role='' />
|
||||
<member type='node' ref='12' role='' />
|
||||
<member type='node' ref='13' role='' />
|
||||
<member type='node' ref='14' role='' />
|
||||
<member type='node' ref='15' role='' />
|
||||
<member type='node' ref='16' role='' />
|
||||
<member type='node' ref='17' role='' />
|
||||
<member type='node' ref='18' role='' />
|
||||
<member type='node' ref='19' role='' />
|
||||
<member type='node' ref='20' role='' />
|
||||
<tag k='name' v='3: 1-...-9-10-11-...-20' />
|
||||
<tag k='ref' v='3' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='106' visible='true' version='1'>
|
||||
<member type='node' ref='20' role='' />
|
||||
<member type='node' ref='19' role='' />
|
||||
<member type='node' ref='18' role='' />
|
||||
<member type='node' ref='17' role='' />
|
||||
<member type='node' ref='16' role='' />
|
||||
<member type='node' ref='15' role='' />
|
||||
<member type='node' ref='14' role='' />
|
||||
<member type='node' ref='13' role='' />
|
||||
<member type='node' ref='12' role='' />
|
||||
<member type='node' ref='22' role='' />
|
||||
<member type='node' ref='9' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='7' role='' />
|
||||
<member type='node' ref='6' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<tag k='name' v='3: 20-...-12-11(1)-9-...-1' />
|
||||
<tag k='note' v='Miss Station 10(1) compared to the twin route' />
|
||||
<tag k='ref' v='3' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='107' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='6' role='' />
|
||||
<member type='node' ref='7' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='9' role='' />
|
||||
<member type='node' ref='10' role='' />
|
||||
<member type='node' ref='11' role='' />
|
||||
<member type='node' ref='12' role='' />
|
||||
<member type='node' ref='13' role='' />
|
||||
<member type='node' ref='14' role='' />
|
||||
<member type='node' ref='15' role='' />
|
||||
<member type='node' ref='16' role='' />
|
||||
<member type='node' ref='17' role='' />
|
||||
<member type='node' ref='18' role='' />
|
||||
<member type='node' ref='19' role='' />
|
||||
<member type='node' ref='20' role='' />
|
||||
<tag k='name' v='4: 1-...-9-10-11-...-20' />
|
||||
<tag k='ref' v='4' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='108' visible='true' version='1'>
|
||||
<member type='node' ref='20' role='' />
|
||||
<member type='node' ref='19' role='' />
|
||||
<member type='node' ref='18' role='' />
|
||||
<member type='node' ref='17' role='' />
|
||||
<member type='node' ref='16' role='' />
|
||||
<member type='node' ref='15' role='' />
|
||||
<member type='node' ref='14' role='' />
|
||||
<member type='node' ref='13' role='' />
|
||||
<member type='node' ref='12' role='' />
|
||||
<member type='node' ref='24' role='' />
|
||||
<member type='node' ref='9' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='7' role='' />
|
||||
<member type='node' ref='6' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<tag k='name' v='4: 20-...12-11(2)-9-...-1' />
|
||||
<tag k='note' v='Miss Station 10(2) compared to the twin route' />
|
||||
<tag k='ref' v='4' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='201' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='6' role='' />
|
||||
<member type='node' ref='7' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='9' role='' />
|
||||
<member type='node' ref='10' role='' />
|
||||
<member type='node' ref='11' role='' />
|
||||
<member type='node' ref='12' role='' />
|
||||
<member type='node' ref='13' role='' />
|
||||
<member type='node' ref='14' role='' />
|
||||
<member type='node' ref='15' role='' />
|
||||
<member type='node' ref='16' role='' />
|
||||
<member type='node' ref='17' role='' />
|
||||
<member type='node' ref='18' role='' />
|
||||
<member type='node' ref='19' role='' />
|
||||
<member type='node' ref='20' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<member type='way' ref='2' role='' />
|
||||
<member type='way' ref='3' role='' />
|
||||
<tag k='name' v='11: 1-...-9-10-11-...-20' />
|
||||
<tag k='ref' v='11' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='202' visible='true' version='1'>
|
||||
<member type='node' ref='20' role='' />
|
||||
<member type='node' ref='19' role='' />
|
||||
<member type='node' ref='18' role='' />
|
||||
<member type='node' ref='17' role='' />
|
||||
<member type='node' ref='16' role='' />
|
||||
<member type='node' ref='15' role='' />
|
||||
<member type='node' ref='14' role='' />
|
||||
<member type='node' ref='13' role='' />
|
||||
<member type='node' ref='12' role='' />
|
||||
<member type='node' ref='22' role='' />
|
||||
<member type='node' ref='21' role='' />
|
||||
<member type='node' ref='9' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='7' role='' />
|
||||
<member type='node' ref='6' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='way' ref='3' role='' />
|
||||
<member type='way' ref='4' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<tag k='name' v='11: 20-...-12-11(1)-10(1)-9-...-1' />
|
||||
<tag k='ref' v='11' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='203' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='6' role='' />
|
||||
<member type='node' ref='7' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='9' role='' />
|
||||
<member type='node' ref='10' role='' />
|
||||
<member type='node' ref='11' role='' />
|
||||
<member type='node' ref='12' role='' />
|
||||
<member type='node' ref='13' role='' />
|
||||
<member type='node' ref='14' role='' />
|
||||
<member type='node' ref='15' role='' />
|
||||
<member type='node' ref='16' role='' />
|
||||
<member type='node' ref='17' role='' />
|
||||
<member type='node' ref='18' role='' />
|
||||
<member type='node' ref='19' role='' />
|
||||
<member type='node' ref='20' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<member type='way' ref='2' role='' />
|
||||
<member type='way' ref='3' role='' />
|
||||
<tag k='name' v='12: 1-...-9-10-11-...-20' />
|
||||
<tag k='ref' v='12' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='204' visible='true' version='1'>
|
||||
<member type='node' ref='20' role='' />
|
||||
<member type='node' ref='19' role='' />
|
||||
<member type='node' ref='18' role='' />
|
||||
<member type='node' ref='17' role='' />
|
||||
<member type='node' ref='16' role='' />
|
||||
<member type='node' ref='15' role='' />
|
||||
<member type='node' ref='14' role='' />
|
||||
<member type='node' ref='13' role='' />
|
||||
<member type='node' ref='12' role='' />
|
||||
<member type='node' ref='24' role='' />
|
||||
<member type='node' ref='23' role='' />
|
||||
<member type='node' ref='9' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='7' role='' />
|
||||
<member type='node' ref='6' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='way' ref='3' role='' />
|
||||
<member type='way' ref='5' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<tag k='name' v='12: 20-...12-11(2)-10(2)-9-...-1' />
|
||||
<tag k='ref' v='12' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='205' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='6' role='' />
|
||||
<member type='node' ref='7' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='9' role='' />
|
||||
<member type='node' ref='10' role='' />
|
||||
<member type='node' ref='11' role='' />
|
||||
<member type='node' ref='12' role='' />
|
||||
<member type='node' ref='13' role='' />
|
||||
<member type='node' ref='14' role='' />
|
||||
<member type='node' ref='15' role='' />
|
||||
<member type='node' ref='16' role='' />
|
||||
<member type='node' ref='17' role='' />
|
||||
<member type='node' ref='18' role='' />
|
||||
<member type='node' ref='19' role='' />
|
||||
<member type='node' ref='20' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<member type='way' ref='2' role='' />
|
||||
<member type='way' ref='3' role='' />
|
||||
<tag k='name' v='13: 1-...-9-10-11-...-20' />
|
||||
<tag k='ref' v='13' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='206' visible='true' version='1'>
|
||||
<member type='node' ref='20' role='' />
|
||||
<member type='node' ref='19' role='' />
|
||||
<member type='node' ref='18' role='' />
|
||||
<member type='node' ref='17' role='' />
|
||||
<member type='node' ref='16' role='' />
|
||||
<member type='node' ref='15' role='' />
|
||||
<member type='node' ref='14' role='' />
|
||||
<member type='node' ref='13' role='' />
|
||||
<member type='node' ref='12' role='' />
|
||||
<member type='node' ref='22' role='' />
|
||||
<member type='node' ref='9' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='7' role='' />
|
||||
<member type='node' ref='6' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='way' ref='3' role='' />
|
||||
<member type='way' ref='4' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<tag k='name' v='13: 20-...-12-11(1)-9-...-1' />
|
||||
<tag k='note' v='Miss Station 10(1) compared to the twin route' />
|
||||
<tag k='ref' v='13' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='207' visible='true' version='1'>
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='6' role='' />
|
||||
<member type='node' ref='7' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='9' role='' />
|
||||
<member type='node' ref='10' role='' />
|
||||
<member type='node' ref='11' role='' />
|
||||
<member type='node' ref='12' role='' />
|
||||
<member type='node' ref='13' role='' />
|
||||
<member type='node' ref='14' role='' />
|
||||
<member type='node' ref='15' role='' />
|
||||
<member type='node' ref='16' role='' />
|
||||
<member type='node' ref='17' role='' />
|
||||
<member type='node' ref='18' role='' />
|
||||
<member type='node' ref='19' role='' />
|
||||
<member type='node' ref='20' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<member type='way' ref='2' role='' />
|
||||
<member type='way' ref='3' role='' />
|
||||
<tag k='name' v='14: 1-...-9-10-11-...-20' />
|
||||
<tag k='ref' v='14' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='208' visible='true' version='1'>
|
||||
<member type='node' ref='20' role='' />
|
||||
<member type='node' ref='19' role='' />
|
||||
<member type='node' ref='18' role='' />
|
||||
<member type='node' ref='17' role='' />
|
||||
<member type='node' ref='16' role='' />
|
||||
<member type='node' ref='15' role='' />
|
||||
<member type='node' ref='14' role='' />
|
||||
<member type='node' ref='13' role='' />
|
||||
<member type='node' ref='12' role='' />
|
||||
<member type='node' ref='24' role='' />
|
||||
<member type='node' ref='9' role='' />
|
||||
<member type='node' ref='8' role='' />
|
||||
<member type='node' ref='7' role='' />
|
||||
<member type='node' ref='6' role='' />
|
||||
<member type='node' ref='5' role='' />
|
||||
<member type='node' ref='4' role='' />
|
||||
<member type='node' ref='3' role='' />
|
||||
<member type='node' ref='2' role='' />
|
||||
<member type='node' ref='1' role='' />
|
||||
<member type='way' ref='3' role='' />
|
||||
<member type='way' ref='5' role='' />
|
||||
<member type='way' ref='1' role='' />
|
||||
<tag k='name' v='14: 20-...12-11(2)-9-...-1' />
|
||||
<tag k='note' v='Miss Station 10(2) compared to the twin route' />
|
||||
<tag k='ref' v='14' />
|
||||
<tag k='route' v='subway' />
|
||||
<tag k='type' v='route' />
|
||||
</relation>
|
||||
<relation id='1101' visible='true' version='1'>
|
||||
<member type='relation' ref='101' role='' />
|
||||
<member type='relation' ref='102' role='' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='note' v='No rails, no omitted stations, close paths' />
|
||||
<tag k='ref' v='1' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='1102' visible='true' version='1'>
|
||||
<member type='relation' ref='103' role='' />
|
||||
<member type='relation' ref='104' role='' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='note' v='No rails, no omitted stations, distant paths' />
|
||||
<tag k='ref' v='2' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='1103' visible='true' version='1'>
|
||||
<member type='relation' ref='105' role='' />
|
||||
<member type='relation' ref='106' role='' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='note' v='No rails, close paths, one route is missing a station inside a divergent rail span' />
|
||||
<tag k='ref' v='3' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='1104' visible='true' version='1'>
|
||||
<member type='relation' ref='107' role='' />
|
||||
<member type='relation' ref='108' role='' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='note' v='No rails, distant paths, one route is missing a station inside a divergent rail span' />
|
||||
<tag k='ref' v='4' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='1201' visible='true' version='1'>
|
||||
<member type='relation' ref='201' role='' />
|
||||
<member type='relation' ref='202' role='' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='note' v='Rails, no omitted stations, close paths' />
|
||||
<tag k='ref' v='11' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='1202' visible='true' version='1'>
|
||||
<member type='relation' ref='203' role='' />
|
||||
<member type='relation' ref='204' role='' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='note' v='Rails, no omitted stations, distant paths' />
|
||||
<tag k='ref' v='12' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='1203' visible='true' version='1'>
|
||||
<member type='relation' ref='205' role='' />
|
||||
<member type='relation' ref='206' role='' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='note' v='Rails, close paths, one route is missing a station inside a divergent rail span' />
|
||||
<tag k='ref' v='13' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
<relation id='1204' visible='true' version='1'>
|
||||
<member type='relation' ref='207' role='' />
|
||||
<member type='relation' ref='208' role='' />
|
||||
<tag k='colour' v='gray' />
|
||||
<tag k='note' v='Rails, distant paths, one route is missing a station inside a divergent rail span' />
|
||||
<tag k='ref' v='14' />
|
||||
<tag k='route_master' v='subway' />
|
||||
<tag k='type' v='route_master' />
|
||||
</relation>
|
||||
</osm>
|
|
@ -42,11 +42,11 @@ metro_samples = [
|
|||
"cities_info": [
|
||||
{
|
||||
"num_stations": 2,
|
||||
"num_lines": 1,
|
||||
"num_light_lines": 0,
|
||||
"num_interchanges": 0,
|
||||
},
|
||||
],
|
||||
"num_lines": 1,
|
||||
"num_light_lines": 0,
|
||||
"num_interchanges": 0,
|
||||
"errors": [],
|
||||
"warnings": [],
|
||||
"notices": [],
|
||||
|
@ -110,14 +110,9 @@ metro_samples = [
|
|||
"num_stations": 4,
|
||||
},
|
||||
],
|
||||
"num_lines": 1,
|
||||
"num_light_lines": 0,
|
||||
"num_interchanges": 0,
|
||||
"errors": [
|
||||
'Angle between stops around "Station 3" (2.0, 0.0) '
|
||||
'is too narrow, 0 degrees (relation 1, "Forward")',
|
||||
'Angle between stops around "Station 2" (1.0, 0.0) '
|
||||
'is too narrow, 0 degrees (relation 1, "Forward")',
|
||||
'Angle between stops around "Station 3" (2.0, 0.0) is too narrow, 0 degrees (relation 1, "Forward")', # noqa: E501
|
||||
'Angle between stops around "Station 2" (1.0, 0.0) is too narrow, 0 degrees (relation 1, "Forward")', # noqa: E501
|
||||
],
|
||||
"warnings": [],
|
||||
"notices": [],
|
||||
|
@ -175,14 +170,9 @@ metro_samples = [
|
|||
"num_stations": 3,
|
||||
},
|
||||
],
|
||||
"num_lines": 1,
|
||||
"num_light_lines": 0,
|
||||
"num_interchanges": 0,
|
||||
"errors": [
|
||||
'Angle between stops around "Station 2" (1.0, 0.0) '
|
||||
'is too narrow, 11 degrees (relation 1, "Forward")',
|
||||
'Angle between stops around "Station 2" (1.0, 0.0) '
|
||||
'is too narrow, 11 degrees (relation 2, "Backward")',
|
||||
'Angle between stops around "Station 2" (1.0, 0.0) is too narrow, 11 degrees (relation 1, "Forward")', # noqa: E501
|
||||
'Angle between stops around "Station 2" (1.0, 0.0) is too narrow, 11 degrees (relation 2, "Backward")', # noqa: E501
|
||||
],
|
||||
"warnings": [],
|
||||
"notices": [],
|
||||
|
@ -240,16 +230,11 @@ metro_samples = [
|
|||
"num_stations": 3,
|
||||
},
|
||||
],
|
||||
"num_lines": 1,
|
||||
"num_light_lines": 0,
|
||||
"num_interchanges": 0,
|
||||
"errors": [],
|
||||
"warnings": [],
|
||||
"notices": [
|
||||
'Angle between stops around "Station 2" (1.0, 0.0) '
|
||||
'is too narrow, 27 degrees (relation 1, "Forward")',
|
||||
'Angle between stops around "Station 2" (1.0, 0.0) '
|
||||
'is too narrow, 27 degrees (relation 2, "Backward")',
|
||||
'Angle between stops around "Station 2" (1.0, 0.0) is too narrow, 27 degrees (relation 1, "Forward")', # noqa: E501
|
||||
'Angle between stops around "Station 2" (1.0, 0.0) is too narrow, 27 degrees (relation 2, "Backward")', # noqa: E501
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -326,16 +311,45 @@ metro_samples = [
|
|||
"num_stations": 4,
|
||||
},
|
||||
],
|
||||
"num_lines": 1,
|
||||
"num_light_lines": 0,
|
||||
"num_interchanges": 0,
|
||||
"errors": [
|
||||
'Stops on tracks are unordered near "Station 2" (1.0, 0.0) '
|
||||
'(relation 1, "Forward")',
|
||||
'Stops on tracks are unordered near "Station 3" (0.0, 0.5) '
|
||||
'(relation 2, "Backward")',
|
||||
'Stops on tracks are unordered near "Station 2" (1.0, 0.0) (relation 1, "Forward")', # noqa: E501
|
||||
'Stops on tracks are unordered near "Station 3" (0.0, 0.5) (relation 2, "Backward")', # noqa: E501
|
||||
],
|
||||
"warnings": [],
|
||||
"notices": [],
|
||||
},
|
||||
{
|
||||
"name": (
|
||||
"Many different route masters, both on naked stations and "
|
||||
"stop_positions/stop_areas/transfers, both linear and circular"
|
||||
),
|
||||
"xml_file": "assets/route_masters.osm",
|
||||
"cities_info": [
|
||||
{
|
||||
"num_stations": (3 + 3 + 3 + 5 + 3 + 3 + 4)
|
||||
+ (3 + 3 + 3 + 3 + 3 + 3 + 4),
|
||||
"num_lines": 7 + 7,
|
||||
"num_interchanges": 0 + 1,
|
||||
},
|
||||
],
|
||||
"errors": [
|
||||
'Only one route in route_master. Please check if it needs a return route (relation 162, "03: 1-2-3")' # noqa: E501
|
||||
],
|
||||
"warnings": [],
|
||||
"notices": [
|
||||
'Route does not have a return direction (relation 155, "02: 1-2-3")', # noqa: E501
|
||||
'Route does not have a return direction (relation 158, "02: 1-3 (2)")', # noqa: E501
|
||||
'Only one route in route_master. Please check if it needs a return route (relation 159, "C: 1-3-5-1")', # noqa: E501
|
||||
'Route does not have a return direction (relation 163, "04: 1-2-3")', # noqa: E501
|
||||
'Route does not have a return direction (relation 164, "04: 2-1")', # noqa: E501
|
||||
'Stop Station 2 (1.0, 0.0) is included into the r203 but not included into r204 (relation 204, "2: 3-1")', # noqa: E501
|
||||
'Route does not have a return direction (relation 205, "3: 1-2-3")', # noqa: E501
|
||||
'Route does not have a return direction (relation 206, "3: 1-2-3")', # noqa: E501
|
||||
'Route does not have a return direction (relation 207, "4: 4-3-2-1")', # noqa: E501
|
||||
'Route does not have a return direction (relation 208, "4: 1-2-3-4")', # noqa: E501
|
||||
'Route does not have a return direction (relation 209, "5: 1-2-3")', # noqa: E501
|
||||
'Route does not have a return direction (relation 210, "5: 2-1")', # noqa: E501
|
||||
'Only one route in route_master. Please check if it needs a return route (relation 213, "C3: 1-2-3-8-1")', # noqa: E501
|
||||
],
|
||||
},
|
||||
]
|
||||
|
|
|
@ -6,25 +6,17 @@ metro_samples = [
|
|||
{
|
||||
"id": 1,
|
||||
"name": "Intersecting 2 metro lines",
|
||||
"country": "World",
|
||||
"continent": "Africa",
|
||||
"num_stations": 6,
|
||||
"num_stations": 4 + 2,
|
||||
"num_lines": 2,
|
||||
"num_light_lines": 0,
|
||||
"num_interchanges": 1,
|
||||
"bbox": "-179, -89, 179, 89",
|
||||
"networks": "network-1",
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "One light rail line",
|
||||
"country": "World",
|
||||
"continent": "Africa",
|
||||
"num_stations": 2,
|
||||
"num_lines": 0,
|
||||
"num_light_lines": 1,
|
||||
"num_interchanges": 0,
|
||||
"bbox": "-179, -89, 179, 89",
|
||||
"networks": "network-2",
|
||||
},
|
||||
],
|
||||
|
|
78
tests/sample_data_for_twin_routes.py
Normal file
78
tests/sample_data_for_twin_routes.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
metro_samples = [
|
||||
{
|
||||
"name": (
|
||||
"Many different routes, both on naked stations and stop_positions/stop_areas/transfers, both linear and circular" # noqa: E501
|
||||
),
|
||||
"xml_file": "assets/twin_routes.osm",
|
||||
"cities_info": [
|
||||
{
|
||||
"num_stations": (3 + 4 + 5 + 5) + (3 + 6 + 7 + 5 + 6 + 7 + 7),
|
||||
"num_lines": 4 + 7,
|
||||
"num_interchanges": 0 + 2,
|
||||
},
|
||||
],
|
||||
"twin_routes": { # route master => twin routes
|
||||
"r10021": {"r151": "r153", "r153": "r151"},
|
||||
"r10022": {},
|
||||
"r10023": {},
|
||||
"C": {},
|
||||
"r10001": {"r201": "r202", "r202": "r201"},
|
||||
"r10002": {},
|
||||
"r10003": {"r205": "r206", "r206": "r205"},
|
||||
"r10004": {},
|
||||
"r10005": {},
|
||||
"r10006": {},
|
||||
"C3": {},
|
||||
},
|
||||
"errors": [],
|
||||
"warnings": [],
|
||||
"notices": [
|
||||
'Route does not have a return direction (relation 154, "02: 4-3")',
|
||||
'Route does not have a return direction (relation 155, "02: 1-3")',
|
||||
'Route does not have a return direction (relation 156, "02: 2-4")',
|
||||
'Route does not have a return direction (relation 157, "02: 4-1")',
|
||||
'Route does not have a return direction (relation 158, "02: 1-3 (2)")', # noqa: E501
|
||||
'Only one route in route_master. Please check if it needs a return route (relation 159, "C: 1-2-3-4-5-1")', # noqa: E501
|
||||
'Stop Station 4 (3.0, 0.0) is included into the r205 but not included into r206 (relation 206, "3: 7-6-5-3-2-1")', # noqa: E501
|
||||
'Route does not have a return direction (relation 207, "4: 4-3-2-1")', # noqa: E501
|
||||
'Route does not have a return direction (relation 208, "4: 1-2-3-4")', # noqa: E501
|
||||
'Route does not have a return direction (relation 209, "5: 1-2-3-5-6-7")', # noqa: E501
|
||||
'Route does not have a return direction (relation 210, "5: 6-5-3-2-1")', # noqa: E501
|
||||
'Only one route in route_master. Please check if it needs a return route (relation 213, "C3: 1-2-3-5-6-7-8-1")', # noqa: E501
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Twin routes diverging for some extent",
|
||||
"xml_file": "assets/twin_routes_with_divergence.osm",
|
||||
"cities_info": [
|
||||
{
|
||||
"num_stations": (22 + 22 + 21 + 21) * 2,
|
||||
"num_lines": 4 * 2,
|
||||
"num_interchanges": 0,
|
||||
},
|
||||
],
|
||||
"twin_routes": { # route master => twin routes
|
||||
"r1101": {"r101": "r102", "r102": "r101"},
|
||||
"r1102": {"r103": "r104", "r104": "r103"},
|
||||
"r1103": {"r105": "r106", "r106": "r105"},
|
||||
"r1104": {"r107": "r108", "r108": "r107"},
|
||||
"r1201": {"r201": "r202", "r202": "r201"},
|
||||
"r1202": {"r203": "r204", "r204": "r203"},
|
||||
"r1203": {"r205": "r206", "r206": "r205"},
|
||||
"r1204": {"r207": "r208", "r208": "r207"},
|
||||
},
|
||||
"errors": [],
|
||||
"warnings": [],
|
||||
"notices": [
|
||||
'Should there be one stoparea or a transfer between Station 11 (0.1, 0.0) and Station 11(1) (0.1, 0.0003)? (relation 101, "1: 1-...-9-10-11-...-20")', # noqa: E501
|
||||
'Should there be one stoparea or a transfer between Station 10 (0.09, 0.0) and Station 10(1) (0.09, 0.0003)? (relation 101, "1: 1-...-9-10-11-...-20")', # noqa: E501
|
||||
'Stop Station 10 (0.09, 0.0) is included into the r105 but not included into r106 (relation 106, "3: 20-...-12-11(1)-9-...-1")', # noqa: E501
|
||||
'Should there be one stoparea or a transfer between Station 11 (0.1, 0.0) and Station 11(1) (0.1, 0.0003)? (relation 105, "3: 1-...-9-10-11-...-20")', # noqa: E501
|
||||
'Stop Station 10 (0.09, 0.0) is included into the r107 but not included into r108 (relation 108, "4: 20-...12-11(2)-9-...-1")', # noqa: E501
|
||||
'Should there be one stoparea or a transfer between Station 11 (0.1, 0.0) and Station 11(1) (0.1, 0.0003)? (relation 201, "11: 1-...-9-10-11-...-20")', # noqa: E501
|
||||
'Should there be one stoparea or a transfer between Station 10 (0.09, 0.0) and Station 10(1) (0.09, 0.0003)? (relation 201, "11: 1-...-9-10-11-...-20")', # noqa: E501
|
||||
'Stop Station 10 (0.09, 0.0) is included into the r205 but not included into r206 (relation 206, "13: 20-...-12-11(1)-9-...-1")', # noqa: E501
|
||||
'Should there be one stoparea or a transfer between Station 11 (0.1, 0.0) and Station 11(1) (0.1, 0.0003)? (relation 205, "13: 1-...-9-10-11-...-20")', # noqa: E501
|
||||
],
|
||||
},
|
||||
]
|
|
@ -1,4 +1,11 @@
|
|||
from tests.sample_data_for_error_messages import metro_samples
|
||||
import itertools
|
||||
|
||||
from tests.sample_data_for_error_messages import (
|
||||
metro_samples as metro_samples_error,
|
||||
)
|
||||
from tests.sample_data_for_twin_routes import (
|
||||
metro_samples as metro_samples_route_masters,
|
||||
)
|
||||
from tests.util import TestCase
|
||||
|
||||
|
||||
|
@ -20,6 +27,10 @@ class TestValidationMessages(TestCase):
|
|||
)
|
||||
|
||||
def test_validation_messages(self) -> None:
|
||||
for sample in metro_samples:
|
||||
for sample in itertools.chain(
|
||||
metro_samples_error, metro_samples_route_masters
|
||||
):
|
||||
if "errors" not in sample:
|
||||
continue
|
||||
with self.subTest(msg=sample["name"]):
|
||||
self._test_validation_messages_for_network(sample)
|
||||
|
|
26
tests/test_route_master.py
Normal file
26
tests/test_route_master.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
from tests.util import TestCase
|
||||
|
||||
from tests.sample_data_for_twin_routes import metro_samples
|
||||
|
||||
|
||||
class TestRouteMaster(TestCase):
|
||||
def _test_find_twin_routes_for_network(self, metro_sample: dict) -> None:
|
||||
cities, transfers = self.prepare_cities(metro_sample)
|
||||
city = cities[0]
|
||||
|
||||
self.assertTrue(city.is_good)
|
||||
|
||||
for route_master_id, expected_twin_ids in metro_sample[
|
||||
"twin_routes"
|
||||
].items():
|
||||
route_master = city.routes[route_master_id]
|
||||
calculated_twins = route_master.find_twin_routes()
|
||||
calculated_twin_ids = {
|
||||
r1.id: r2.id for r1, r2 in calculated_twins.items()
|
||||
}
|
||||
self.assertDictEqual(expected_twin_ids, calculated_twin_ids)
|
||||
|
||||
def test_find_twin_routes(self) -> None:
|
||||
for sample in metro_samples:
|
||||
with self.subTest(msg=sample["name"]):
|
||||
self._test_find_twin_routes_for_network(sample)
|
Loading…
Add table
Reference in a new issue