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