Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/purgatory/0123to0130.py
169674 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 0123to0130.py
15
# @author Daniel Krajzewicz
16
# @author Jakob Erdmann
17
# @author Michael Behrisch
18
# @date 2007
19
20
from __future__ import absolute_import
21
from __future__ import print_function
22
import os
23
import sys
24
import glob
25
import xml
26
from xml.sax import parse, handler
27
from optparse import OptionParser
28
from collections import defaultdict
29
30
# attributes sorting lists
31
a = {}
32
a['net'] = ('version', )
33
a['edge'] = ('id', 'from', 'to', 'name', 'priority',
34
'type', 'function', 'spread_type', 'shape')
35
a['lane'] = ('id', 'index', 'vclasses', 'allow', 'disallow',
36
'maxspeed', 'maxSpeed', 'length', 'endOffset', 'width', 'shape')
37
a['junction'] = ('id', 'type', 'x', 'y', 'incLanes', 'intLanes', 'shape')
38
a['logicitem'] = ('response', 'foes', 'cont')
39
a['succlane'] = ('via', 'tl', 'linkno', 'dir', 'state')
40
a['connection'] = (
41
'from', 'to', 'fromLane', 'toLane', 'via', 'tl', 'linkIdx', 'dir', 'state')
42
a['row-logic'] = a['ROWLogic'] = ('id', 'requestSize')
43
a['tl-logic'] = a['tlLogic'] = ('id', 'type', 'programID', 'offset')
44
a['location'] = ('netOffset', 'convBoundary', 'origBoundary', 'projParameter')
45
a['phase'] = ('duration', 'state', 'min_dur', 'max_dur')
46
a['district'] = ('id', 'shape', 'edges')
47
a['dsink'] = ('id', 'weight')
48
a['dsource'] = ('id', 'weight')
49
a['taz'] = ('id', 'shape', 'edges')
50
a['tazSink'] = ('id', 'weight')
51
a['tazSource'] = ('id', 'weight')
52
a['roundabout'] = ('nodes', 'dummy')
53
a['request'] = ('index', 'response', 'foes', 'cont')
54
a['succ'] = ('edge', 'lane', 'junction')
55
56
# attributes which are optional
57
b = defaultdict(dict)
58
b['edge']['type'] = ''
59
b['edge']['function'] = 'normal'
60
b['succlane']['tl'] = ''
61
b['succlane']['linkno'] = ''
62
b['succlane']['linkIndex'] = ''
63
b['junction']['shape'] = ''
64
65
# elements which are single (not using opening/closing tag)
66
SINGLE = ('roundabout', 'logicitem', 'phase', 'succlane', 'dsource', 'dsink', 'location',
67
'lane', 'timed_event', 'connection', 'request')
68
69
# remove these
70
REMOVED = ('lanes', 'logic', 'succ', 'row-logic', 'ROWLogic', 'logicitem')
71
72
# renamed elements
73
RENAMED_TAGS = {'tl-logic': 'tlLogic',
74
'row-logic': 'ROWLogic',
75
'district': 'taz',
76
'dsource': 'tazSource',
77
'dsink': 'tazSink',
78
'succlane': 'connection'}
79
80
renamedAttrs = {'min_dur': 'minDur',
81
'max_dur': 'maxDur',
82
'spread_type': 'spreadType',
83
'maxspeed': 'speed',
84
'maxSpeed': 'speed',
85
'linkIdx': 'linkIndex',
86
'linkno': 'linkIndex'}
87
88
renamedValues = {'state': {'t': 'o'}, 'type': {'DEAD_END': 'dead_end'}}
89
90
91
def getBegin(file):
92
fd = open(file)
93
content = ""
94
for line in fd:
95
if '<net' in line or '<districts' in line or '<add' in line:
96
fd.close()
97
return content
98
if '<?xml version' in line:
99
continue
100
content = content + line
101
fd.close()
102
return ""
103
104
105
class NetConverter(handler.ContentHandler):
106
107
def __init__(self, outFileName, begin, has_no_destination):
108
self._out = open(outFileName, "w")
109
self._out.write('<?xml version="1.0" encoding="iso-8859-1"?>\n')
110
self._out.write(begin)
111
self._tree = []
112
self._content = ""
113
self._am_parsing_rowlogic = None # parsing old element
114
self._logicitems = defaultdict(list) # maps junction ids to items
115
self._laneCount = 0
116
self._has_no_destination = has_no_destination
117
118
def isSingle(self, name):
119
if name in SINGLE:
120
return True
121
if name == "junction" and self._single_junction:
122
return True
123
return False
124
125
def remove(self, name):
126
if name == "succ" and self._has_no_destination:
127
return False
128
if name in REMOVED:
129
return True
130
else:
131
return False
132
133
def rename(self, name):
134
if name == "succlane" and self._has_no_destination:
135
return False
136
if name in RENAMED_TAGS:
137
return True
138
else:
139
return False
140
141
def checkWrite(self, what):
142
self._out.write(what.encode('iso-8859-1'))
143
144
def indent(self):
145
self._out.write(" " * (4 * len(self._tree)))
146
147
def endDocument(self):
148
self.checkWrite("\n")
149
self._out.close()
150
151
def startElement(self, name, attrs):
152
# special preparations
153
if name == "succ":
154
self._succ_from = attrs["edge"]
155
self._succ_fromIdx = attrs["lane"].split('_')[-1]
156
if name == "row-logic" or name == "ROWLogic":
157
self._am_parsing_rowlogic = attrs["id"]
158
if name == "logicitem":
159
self._logicitems[self._am_parsing_rowlogic].append(attrs)
160
if name == "edge":
161
self._laneCount = 0
162
if name == "junction":
163
self._single_junction = (attrs["id"][0] == ":" or
164
attrs["type"] == 'DEAD_END' or
165
attrs["type"] == 'dead_end')
166
# skip removed
167
if self.remove(name):
168
return
169
# compress empty lines
170
if self._content.find("\n\n") >= 0:
171
self.checkWrite("\n")
172
self._content = ""
173
# open tag
174
self.indent()
175
if self.rename(name):
176
self.checkWrite("<" + RENAMED_TAGS[name])
177
else:
178
self.checkWrite("<" + name)
179
# special attribute handling
180
if name == "succlane":
181
if self._has_no_destination:
182
# keep original
183
self.checkWrite(' lane="%s"' % attrs["lane"])
184
else:
185
# upgrade
186
self.checkWrite(' from="%s"' % self._succ_from)
187
sepIndex = attrs['lane'].rindex('_')
188
toEdge = attrs['lane'][:sepIndex]
189
toIdx = attrs['lane'][sepIndex + 1:]
190
self.checkWrite(' to="%s"' % toEdge)
191
self.checkWrite(' fromLane="%s"' % self._succ_fromIdx)
192
self.checkWrite(' toLane="%s"' % toIdx)
193
# write attributes
194
if name == "net":
195
self.checkWrite(
196
' version="0.13" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
197
'xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/net_file.xsd"')
198
else:
199
if name in a:
200
for key in a[name]:
201
val = None
202
if key in renamedAttrs and renamedAttrs[key] in attrs:
203
key = renamedAttrs[key]
204
if key in attrs:
205
val = attrs[key]
206
if key in renamedValues:
207
val = renamedValues[key].get(val, val)
208
if name == "succlane" and (key == "linkno" or key == "linkIndex") and attrs["tl"] == '':
209
val = ''
210
if name not in b or key not in b[name] or val != b[name][key]:
211
self.checkWrite(
212
' ' + renamedAttrs.get(key, key) + '="%s"' % val)
213
elif name == "lane" and key == "index":
214
self.checkWrite(' %s="%s"' % (key, self._laneCount))
215
self._laneCount += 1
216
elif name == "connection" and key == "fromLane":
217
self.checkWrite(
218
' fromLane="%s" toLane="%s"' % tuple(attrs["lane"].split(":")))
219
# close tag
220
if self.isSingle(name):
221
self.checkWrite("/>\n")
222
else:
223
self.checkWrite(">\n")
224
self._tree.append(name)
225
# transfer items from removed element ROWLogic
226
if name == "junction":
227
for logicitem_attrs in self._logicitems[attrs["id"]]:
228
self.indent()
229
self.checkWrite("<request")
230
self.checkWrite(' index="%s"' % logicitem_attrs["request"])
231
for key in a["logicitem"]:
232
if key in logicitem_attrs: # cont is optional
233
self.checkWrite(' ' + key + '="%s"' %
234
logicitem_attrs[key])
235
self.checkWrite("/>\n")
236
237
def endElement(self, name):
238
# special preparations
239
if name == "row-logic" or name == "ROWLogic":
240
self._am_parsing_rowlogic = None
241
# skip removed
242
if self.remove(name):
243
return
244
# optionaly write closing tag
245
self._tree.pop()
246
if name == "net":
247
self.checkWrite("\n")
248
if not self.isSingle(name):
249
self.indent()
250
if self.rename(name):
251
self.checkWrite("</" + RENAMED_TAGS[name] + ">")
252
else:
253
self.checkWrite("</" + name + ">")
254
if name != "net":
255
self.checkWrite("\n")
256
257
def characters(self, content):
258
self._content += content
259
260
def processingInstruction(self, target, data):
261
self.checkWrite('<?%s %s?>' % (target, data))
262
263
264
def changeFile(fname):
265
if options.verbose:
266
print("Patching " + fname + " ...")
267
if (("_deprecated_" in fname and "net.netconvert" not in fname) or
268
(os.path.join('tools', 'net', '0') in fname)):
269
print(
270
"Skipping file (looks like intentionally deprecated input): " + fname)
271
return
272
has_no_destination = False
273
if "SUMO_NO_DESTINATION" in open(fname).read():
274
print(
275
"Partial conversion (cannot convert SUMO_NO_DESTINATION): " + fname)
276
has_no_destination = True
277
net = NetConverter(fname + ".chg", getBegin(fname), has_no_destination)
278
try:
279
parse(fname, net)
280
except xml.sax._exceptions.SAXParseException:
281
print("Could not parse '%s' maybe it contains non-ascii chars?" %
282
fname)
283
if options.inplace:
284
os.remove(fname)
285
os.rename(fname + ".chg", fname)
286
287
288
def changeEdgeFile(fname):
289
if options.verbose:
290
print("Patching " + fname + " ...")
291
out = open(fname + ".chg", 'w')
292
for line in open(fname):
293
if "<lane" in line:
294
line = line.replace(" id", " index")
295
if "<edge" in line:
296
line = line.replace(" fromnode", " from").replace(" tonode", " to")
297
line = line.replace(" spread_type", " spreadType").replace(
298
" maxspeed", " maxSpeed")
299
line = line.replace(" nolanes", " numLanes")
300
out.write(line)
301
out.close()
302
if options.inplace:
303
os.remove(fname)
304
os.rename(fname + ".chg", fname)
305
306
307
def changeConnectionFile(fname):
308
if options.verbose:
309
print("Patching " + fname + " ...")
310
out = open(fname + ".chg", 'w')
311
for line in open(fname):
312
if "<connection" in line and "lane" in line:
313
line = line.replace(" lane", " fromLane")
314
for i in range(10):
315
line = line.replace(':%s"' % i, '" toLane="%s"' % i)
316
out.write(line)
317
out.close()
318
if options.inplace:
319
os.remove(fname)
320
os.rename(fname + ".chg", fname)
321
322
323
def walkDir(srcRoot):
324
for root, dirs, files in os.walk(srcRoot):
325
for name in files:
326
if name.endswith(".net.xml") or name in ["net.netconvert", "net.netgen",
327
"tls.scenario", "net.scenario"]:
328
changeFile(os.path.join(root, name))
329
if options.edges and name.endswith(".edg.xml"):
330
changeEdgeFile(os.path.join(root, name))
331
elif options.connections and name.endswith(".con.xml"):
332
changeConnectionFile(os.path.join(root, name))
333
for ignoreDir in ['.svn', 'foreign']:
334
if ignoreDir in dirs:
335
dirs.remove(ignoreDir)
336
337
338
optParser = OptionParser()
339
optParser.add_option("-v", "--verbose", action="store_true",
340
default=False, help="tell me what you are doing")
341
optParser.add_option("-i", "--inplace", action="store_true",
342
default=False, help="replace original files")
343
optParser.add_option("-e", "--edges", action="store_true",
344
default=False, help="include edge XML files")
345
optParser.add_option("-c", "--connections", action="store_true",
346
default=False, help="include connection XML files")
347
(options, args) = optParser.parse_args()
348
349
if len(args) == 0:
350
print("Usage: " + sys.argv[0] + " <net>+")
351
sys.exit()
352
for arg in args:
353
for fname in glob.glob(arg):
354
if os.path.isdir(fname):
355
walkDir(fname)
356
else:
357
if options.edges and fname.endswith(".edg.xml"):
358
changeEdgeFile(fname)
359
elif options.connections and fname.endswith(".con.xml"):
360
changeConnectionFile(fname)
361
else:
362
changeFile(fname)
363
364