Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/net/remap_renamed.py
169673 views
1
#!/usr/bin/env python
2
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
# Copyright (C) 2009-2025 German Aerospace Center (DLR) and others.
4
# This program and the accompanying materials are made available under the
5
# terms of the Eclipse Public License 2.0 which is available at
6
# https://www.eclipse.org/legal/epl-2.0/
7
# This Source Code may also be made available under the following Secondary
8
# Licenses when the conditions for such availability set forth in the Eclipse
9
# Public License 2.0 are satisfied: GNU General Public License, version 2
10
# or later which is available at
11
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
14
# @file remap_renamed.py
15
# @author Jakob Erdmann
16
# @date 2025-02-26
17
18
from __future__ import print_function
19
from __future__ import absolute_import
20
import os
21
import sys
22
from collections import defaultdict
23
24
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
25
import sumolib # noqa
26
from sumolib.xml import parse # noqa
27
from sumolib.net import lane2edge, lane2index # noqa
28
29
30
def get_options(args=None):
31
ap = sumolib.options.ArgumentParser(description="Remap infrastructure from one network to another")
32
# ap.add_argument("--orig-net", dest="origNet", required=False, category="input", type=ap.net_file,
33
# help="SUMO network for loading infrastructure", metavar="FILE")
34
ap.add_argument("-n", "--net-file", dest="targetNet", required=True, category="input", type=ap.net_file,
35
help="SUMO network with renamed ids", metavar="FILE")
36
gp = ap.add_mutually_exclusive_group(required=True)
37
gp.add_argument("-r", "--route-file", dest="routes", category="input", type=ap.route_file,
38
help="File for reading routes", metavar="FILE")
39
gp.add_argument("-a", "--additional-file", dest="addfile", category="input", type=ap.route_file,
40
help="File for reading additional elements", metavar="FILE")
41
gp.add_argument("-s", "--selection-file", dest="selfile", category="input", type=ap.file,
42
help="File for reading a selection file with edges, lanes or junctions", metavar="FILE")
43
ap.add_argument("-o", "--output-file", dest="output", required=True, category="output", type=ap.additional_file,
44
help="File for writing output", metavar="FILE")
45
ap.add_argument("-v", "--verbose", action="store_true", dest="verbose",
46
default=False, help="tell me what you are doing")
47
options = ap.parse_args()
48
return options
49
50
51
MISSING = defaultdict(lambda: 0)
52
MISSING_JUNCTIONS = defaultdict(lambda: 0)
53
54
55
def get_mapper(lookup_attr, missing):
56
def mapper(options, origID):
57
newID = getattr(options, lookup_attr).get(origID)
58
if not newID:
59
missing[origID] += 1
60
return newID
61
return mapper
62
63
64
remap_edge = get_mapper('lookup', MISSING)
65
remap_junction = get_mapper('junction_lookup', MISSING_JUNCTIONS)
66
67
68
def remap_lane(options, origID):
69
origEdge, index = origID.rsplit("_", 1)
70
newEdge = remap_edge(options, origEdge)
71
if newEdge:
72
return "%s_%s" % (newEdge, index)
73
else:
74
return None
75
76
77
def remap_edges(options, origIDs):
78
newEdges = [remap_edge(options, e) for e in origIDs.split()]
79
if None in newEdges:
80
return None
81
else:
82
return ' '.join(newEdges)
83
84
85
def remap_lanes(options, origIDs):
86
newLanes = [remap_lane(options, lane) for lane in origIDs.split()]
87
if None in newLanes:
88
return None
89
else:
90
return ' '.join(newLanes)
91
92
93
IDS = {
94
'edge': remap_edge,
95
'attr_from': remap_edge,
96
'to': remap_edge,
97
'edges': remap_edges,
98
'via': remap_edges,
99
'fromJunction': remap_junction,
100
'toJunction': remap_junction,
101
'lane': remap_lane,
102
'lanes': remap_lanes,
103
}
104
105
106
def remap(options, obj):
107
success = True
108
for attr, mapper in IDS.items():
109
if obj.hasAttribute(attr):
110
id1 = getattr(obj, attr)
111
id2 = mapper(options, id1)
112
if id2:
113
obj.setAttribute(attr, id2)
114
else:
115
print("Could not map %s attribute %s '%s'" % (
116
obj.name, attr, id1),
117
file=sys.stderr)
118
success = False
119
120
for child in obj.getChildList():
121
success &= remap(options, child)
122
return success
123
124
125
def addOrigId(lookup, origId, obj):
126
if origId is not None:
127
if " " in origId:
128
print("multi-part origId not supported (%s '%s' origId '%s')" % (
129
type(obj), obj.getID(), origId), file=sys.stderr)
130
else:
131
lookup[origId] = obj.getID()
132
133
134
def build_lookup(net):
135
lookup = {}
136
for edge in net.getEdges():
137
lane = edge.getLanes()[0]
138
origId = lane.getParam("origId")
139
addOrigId(lookup, origId, edge)
140
return lookup
141
142
143
def build_junction_lookup(net):
144
lookup = {}
145
for node in net.getNodes():
146
origId = node.getParam("origId")
147
addOrigId(lookup, origId, node)
148
return lookup
149
150
151
def mapSelection(options):
152
types = (("edge:", lambda x: options.lookup[x]),
153
("junction:", lambda x: options.junction_lookup[x]),
154
("lane:", lambda x: options.lookup[lane2edge(x)] + "_" + str(lane2index(x))))
155
with open(options.output, 'w') as fout, open(options.selfile) as infile:
156
for line in infile:
157
line = line.strip()
158
ignored = True
159
for prefix, fun in types:
160
if line.startswith(prefix):
161
fout.write(prefix + fun(line[len(prefix):]) + '\n')
162
ignored = False
163
break
164
if ignored:
165
print("Warning: Could not map '%s'" % line, file=sys.stderr)
166
167
168
def main(options):
169
if options.verbose:
170
print("Reading target-net '%s'" % options.targetNet)
171
options.net2 = sumolib.net.readNet(options.targetNet)
172
options.lookup = build_lookup(options.net2)
173
options.junction_lookup = build_junction_lookup(options.net2)
174
175
if options.selfile:
176
mapSelection(options)
177
else:
178
if options.routes:
179
infile = options.routes
180
tag = "routes"
181
else:
182
infile = options.addfile
183
tag = "additional"
184
185
with open(options.output, 'w') as fout:
186
sumolib.writeXMLHeader(fout, "$Id$", tag, options=options)
187
for obj in parse(infile):
188
if remap(options, obj):
189
fout.write(obj.toXML(initialIndent=" " * 4, withComments="inline"))
190
else:
191
fout.write(" <!--" + obj.toXML()[1:-2] + "-->\n")
192
fout.write("</%s>\n" % tag)
193
194
if MISSING:
195
print("Could not map %s edges (%s total occurences)" % (
196
len(MISSING), sum(MISSING.values())), file=sys.stderr)
197
vk = sorted([(v, k) for k, v in MISSING.items()], reverse=True)
198
print("Most frequent missing edges:")
199
print("\n".join(["%s %s" % (k, v) for (v, k) in vk]))
200
201
202
if __name__ == "__main__":
203
main(get_options())
204
205