1#!/usr/local/bin/python3.8
2# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3# Copyright (C) 2009-2019 German Aerospace Center (DLR) and others.
4# This program and the accompanying materials
5# are made available under the terms of the Eclipse Public License v2.0
6# which accompanies this distribution, and is available at
7# http://www.eclipse.org/legal/epl-v20.html
8# SPDX-License-Identifier: EPL-2.0
9
10# @file    routes_Join.py
11# @author  Daniel Krajzewicz
12# @author  Michael Behrisch
13# @date    11.09.2009
14# @version $Id$
15
16"""
17Joins routes belonging to two networks.
18A map file with the following syntax is read first:
19 <EDGE_ID>-><EDGE_ID>
20It describes at which edges the networks overlapped and which edge
21 was kept in the resulting one.
22Vehicles from both given route files starting at the first of those
23 edges will be at first not regarded, but their routes are kept in memory.
24All other vehicles are kept, but if they pass one of the mapped edges, the
25 route is continued by choosing a random route from the list of previously
26 discarded ones which start at the corresponding edge.
27
28Attention! The routes are not sorted in time!
29"""
30from __future__ import absolute_import
31from __future__ import print_function
32import sys
33from xml.sax import make_parser, handler
34
35
36class Route:
37
38    def __init__(self, vPars, edges):
39        self._vPars = vPars
40        self._edges = edges
41
42    def encodeVehicle(self):
43        ret = "<vehicle"
44        for a in self._vPars:
45            ret = ret + " " + a + "=\"" + self._vPars[a] + "\""
46        ret = ret + ">"
47        return ret
48
49    def firstEdge(self):
50        return self._edges[0]
51
52
53class RoutesReader(handler.ContentHandler):
54
55    def __init__(self, prefix, replacements):
56        self._prefix = prefix
57        self._replacements = {}
58        for r in replacements:
59            rs = replacements[r].split(",")
60            for r2 in rs:
61                self._replacements[r2] = 1
62        self._routes = []
63        self._continuations = {}
64        self._continuationsSum = {}
65
66    def endDocument(self):
67        self._continuationsBackup = {}
68        self._continuationsSumBackup = {}
69        for e in self._continuations:
70            self._continuationsBackup[e] = []
71            self._continuationsBackup[e].extend(self._continuations[e])
72            self._continuationsSumBackup[e] = self._continuationsSum[e]
73
74    def startElement(self, name, attrs):
75        if name == "vehicle":
76            self._vPars = {}
77            for a in attrs.keys():
78                self._vPars[a] = attrs[a]
79        if name == "route":
80            edges = attrs["edges"].split(" ")
81            for i in range(0, len(edges)):
82                edges[i] = self._prefix + edges[i]
83            self._routes.append(Route(self._vPars, edges))
84            for i in range(0, len(edges)):
85                if edges[i] in self._replacements:
86                    if edges[i] not in self._continuations:
87                        self._continuations[edges[i]] = []
88                        self._continuationsSum[edges[i]] = 0
89                    self._continuations[edges[i]].append(edges[i:])
90                    self._continuationsSum[
91                        edges[i]] = self._continuationsSum[edges[i]] + 1
92
93    def getContinuation(self, beginEdge, replacements):
94        assert(beginEdge in replacements)
95        rEdge = replacements[beginEdge]
96        if rEdge.find(",") >= 0:
97            rEdge = rEdge.split(",")[0]
98        edges = self._continuations[rEdge][-1]
99        self._continuations[rEdge].pop()
100        self._continuationsSum[rEdge] = self._continuationsSum[rEdge] - 1
101        if self._continuationsSum[rEdge] == 0:
102            self._continuations[rEdge] = []
103            self._continuations[rEdge].extend(self._continuationsBackup[rEdge])
104            self._continuationsSum[rEdge] = self._continuationsSumBackup[rEdge]
105        return edges
106
107
108def writeRoute(fdo, edges, conts1, conts2, replacements):
109    replaceFrom = None
110    for e in edges:
111        if e in replacements:
112            if not replaceFrom:
113                replaceFrom = e
114            continue
115        fdo.write(e + " ")
116    if replaceFrom:
117        if replaceFrom[0] == conts2._prefix:
118            cont = conts1.getContinuation(replaceFrom, replacements)
119            writeRoute(fdo, cont, conts1, conts2, replacements)
120        else:
121            cont = conts2.getContinuation(replaceFrom, replacements)
122            writeRoute(fdo, cont, conts1, conts2, replacements)
123
124
125def writeVehicle(fdo, route, conts1, conts2, replacements):
126    fdo.write("    " + route.encodeVehicle() + "<route edges=\"")
127    writeRoute(fdo, route._edges, conts1, conts2, replacements)
128    fdo.write("\"></route></vehicle>\n")
129
130
131if len(sys.argv) < 6:
132    print("Usage: " +
133          sys.argv[0] + " <prefix#1> <routes#1> <prefix#2> <routes#2> <mapfile>")
134    sys.exit()
135# read mapping
136mmap = {}
137fd = open(sys.argv[5])
138for line in fd:
139    if line.find("->") < 0:
140        continue
141    (orig, dest) = line.strip().split("->")
142    mmap[orig] = dest
143fd.close()
144# read routes
145parser = make_parser()
146print("Reading routes#1")
147routes1 = RoutesReader(sys.argv[1], mmap)
148parser.setContentHandler(routes1)
149parser.parse(sys.argv[2])
150print("Reading routes#2")
151routes2 = RoutesReader(sys.argv[3], mmap)
152parser.setContentHandler(routes2)
153parser.parse(sys.argv[4])
154
155print("Processing routes#1")
156fdo = open("joined.rou.xml", "w")
157fdo.write("<routes>\n")
158for r in routes1._routes:
159    if r.firstEdge() in mmap:
160        continue
161        # skip, starts at a replaced edge
162    writeVehicle(fdo, r, routes1, routes2, mmap)
163print("Processing routes#2")
164for r in routes2._routes:
165    if r.firstEdge() in mmap:
166        continue
167        # skip, starts at a replaced edge
168    writeVehicle(fdo, r, routes1, routes2, mmap)
169fdo.write("</routes>\n")
170fdo.close()
171