Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/game/runner.py
169674 views
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
4
# Copyright (C) 2010-2025 German Aerospace Center (DLR) and others.
5
# This program and the accompanying materials are made available under the
6
# terms of the Eclipse Public License 2.0 which is available at
7
# https://www.eclipse.org/legal/epl-2.0/
8
# This Source Code may also be made available under the following Secondary
9
# Licenses when the conditions for such availability set forth in the Eclipse
10
# Public License 2.0 are satisfied: GNU General Public License, version 2
11
# or later which is available at
12
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
13
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
14
15
# @file runner.py
16
# @author Michael Behrisch
17
# @author Jakob Erdmann
18
# @author Mirko Barthauer
19
# @date 2010-01-30
20
21
"""
22
This script runs the gaming GUI for the LNdW traffic light game.
23
It checks for possible scenarios in the current working directory
24
and lets the user start them as a game. Furthermore it
25
saves highscores to local disc and to the central highscore server.
26
"""
27
from __future__ import absolute_import
28
from __future__ import print_function
29
import os
30
import subprocess
31
import sys
32
import re
33
import pickle
34
import glob
35
import time
36
try:
37
import Tkinter
38
except ImportError:
39
import tkinter as Tkinter
40
from xml.dom import pulldom
41
from collections import defaultdict
42
43
_THIS_DIR = os.path.dirname(os.path.abspath(__file__))
44
SUMO_HOME = os.environ.get('SUMO_HOME', os.path.join(_THIS_DIR, '..', '..'))
45
sys.path.append(os.path.join(SUMO_HOME, 'tools'))
46
import sumolib # noqa
47
from sumolib.translation import addLanguageOption, setLanguage, TL # noqa
48
49
_UPLOAD = "noupload" not in sys.argv
50
_SCOREFILE = "scores.pkl"
51
REFSCOREFILE = "refscores.pkl"
52
if _UPLOAD:
53
_TIMEOUT = 5
54
_SCORESERVER = "sumo.dlr.de"
55
_SCORESCRIPT = "/scores.php?game=TLS&"
56
_DEBUG = "debug" in sys.argv
57
_SCORES = 30
58
BASE = os.path.dirname(sys.argv[0])
59
_LANGUAGE_CAPTIONS = {}
60
if not os.path.exists(sumolib.translation.LOCALEDIR) and os.path.exists(os.path.join(_THIS_DIR, 'locale')):
61
# monkey patch locale dir for the SUMO game
62
sumolib.translation.LOCALEDIR = os.path.join(_THIS_DIR, 'locale')
63
64
65
def updateLocalMessages():
66
global _LANGUAGE_CAPTIONS
67
_LANGUAGE_CAPTIONS = {'title': TL('Interactive Traffic Light'),
68
'rail': TL('Railway Control'),
69
'rail_demo': TL('Railway Control (Demo)'),
70
'fokr_bs_demo': TL('Research intersection Braunschweig (Demo)'),
71
'fkk_in': TL('Research intersection Ingolstadt'),
72
'cross': TL('Simple Junction'),
73
'cross_demo': TL('Simple Junction (Demo)'),
74
'square': TL('Four Junctions'),
75
'grid6': TL('Six Junctions'),
76
'kuehne': TL('Prof. Kühne'),
77
'bs3d': TL('3D Junction Virtual World'),
78
'bs3Dosm': TL('3D Junction OpenStreetMap'),
79
'highway': TL('Highway Ramp'),
80
'ramp': TL('Combined Highway On and Off Ramp'),
81
'corridor': TL('Corridor'),
82
'A10KW': TL('Highway Ramp A10'),
83
'DRT': TL('Demand Responsive Transport (new)'),
84
'DRT2': TL('DRT - Advanced (new)'),
85
'DRT_demo': TL('DRT - Demo'),
86
'high': TL('Highscore'),
87
'reset': TL('Reset Highscore'),
88
'german': TL('German'),
89
'english': TL('English'),
90
'italian': TL('Italian'),
91
'spanish': TL('Spanish'),
92
'french': TL('French'),
93
'chinese (simplified)': TL('Chinese (simplified)'),
94
'chinese (traditional)': TL('Chinese (traditional)'),
95
'quit': TL("Quit"),
96
'Highscore': TL("Highscore"),
97
'Congratulations': TL("Congratulations!"),
98
'your score': TL('Your Score'),
99
'Continue': TL('Continue'),
100
}
101
102
103
def printDebug(*args):
104
if _DEBUG:
105
print("DEBUG:", end=" ")
106
for message in args:
107
print(message, end=" ")
108
print()
109
110
111
if _UPLOAD:
112
printDebug("import http.client...")
113
try:
114
import http.client as httplib # noqa
115
import socket # noqa
116
host = socket.gethostbyname(_SCORESERVER)
117
s = socket.create_connection((host, 80), 2)
118
s.close()
119
printDebug("SUCCESS")
120
except Exception:
121
printDebug("FAILED - disabling upload...")
122
_UPLOAD = False
123
124
125
def computeScoreFromWaitingTime(gamename, maxScore=10000):
126
totalArrived = 0
127
totalWaitingTime = 0
128
for s in sumolib.xml.parse(os.path.join(BASE, "output", gamename + ".stats.xml"),
129
("performance", "vehicleTripStatistics")):
130
if s.name == "performance":
131
if float(s.end) != parseEndTime(os.path.join(BASE, gamename + ".sumocfg")):
132
return 0, 0, False
133
else:
134
totalWaitingTime = float(s.waitingTime) * float(s.count)
135
totalArrived = float(s.count)
136
score = maxScore - totalWaitingTime
137
return score, totalArrived, True
138
139
140
def computeScoreFromTimeLoss(gamename, maxScore=10000):
141
totalArrived = 0
142
timeLoss = None
143
departDelay = None
144
departDelayWaiting = None
145
inserted = None
146
running = None
147
waiting = None
148
completed = False
149
150
for line in open(os.path.join(BASE, "output", gamename + ".log")):
151
if "Reason: The final simulation step has been reached." in line:
152
completed = True
153
m = re.search('Inserted: ([0-9]*)', line)
154
if m:
155
inserted = float(m.group(1))
156
m = re.search('Running: (.*)', line)
157
if m:
158
running = float(m.group(1))
159
m = re.search('Waiting: (.*)', line)
160
if m:
161
waiting = float(m.group(1))
162
m = re.search('TimeLoss: (.*)', line)
163
if m:
164
timeLoss = float(m.group(1))
165
m = re.search('DepartDelay: (.*)', line)
166
if m:
167
departDelay = float(m.group(1))
168
m = re.search('DepartDelayWaiting: (.*)', line)
169
if m:
170
departDelayWaiting = float(m.group(1))
171
if not completed or timeLoss is None:
172
return 0, totalArrived, False
173
else:
174
totalArrived = inserted - running
175
if _DEBUG:
176
print("timeLoss=%s departDelay=%s departDelayWaiting=%s inserted=%s running=%s waiting=%s" % (
177
timeLoss, departDelay, departDelayWaiting, inserted, running, waiting))
178
179
score = maxScore - int(100 * ((timeLoss + departDelay) * inserted +
180
departDelayWaiting * waiting) / (inserted + waiting))
181
return score, totalArrived, True
182
183
184
def computeScoreDRT(gamename):
185
rideWaitingTime = 0
186
rideDuration = 0
187
rideStarted = 0
188
rideFinished = 0
189
rideCount = 0
190
for ride in sumolib.xml.parse(os.path.join(BASE, "output", gamename + ".tripinfos.xml"), 'ride'):
191
if float(ride.waitingTime) < 0:
192
if _DEBUG:
193
print("negative waitingTime")
194
ride.waitingTime = 10000
195
rideWaitingTime += float(ride.waitingTime)
196
if float(ride.duration) >= 0:
197
rideDuration += float(ride.duration)
198
rideStarted += 1
199
if float(ride.arrival) >= 0:
200
rideFinished += 1
201
202
rideCount += 1
203
204
if rideCount == 0:
205
return 0, 0, False
206
else:
207
avgWT = rideWaitingTime / rideCount
208
avgDur = 0 if rideStarted == 0 else rideDuration / rideStarted
209
score = 5000 - int(avgWT + avgDur)
210
if _DEBUG:
211
print("rideWaitingTime=%s rideDuration=%s persons=%s started=%s finished=%s avgWT=%s avgDur=%s" % (
212
rideWaitingTime, rideDuration, rideCount, rideStarted, rideFinished, avgWT, avgDur))
213
return score, rideCount, True
214
215
216
def computeScoreRail(gamename):
217
expectedMeanWait = 360
218
rideCount = 0
219
score = 0
220
for ride in sumolib.xml.parse(os.path.join(BASE, "output", gamename + ".tripinfos.xml"), 'ride'):
221
wt = float(ride.waitingTime)
222
if wt < 0:
223
if _DEBUG:
224
print("negative waitingTime")
225
wt = 1000
226
factor = min(1, expectedMeanWait / wt)
227
if float(ride.arrival) >= 0:
228
score += 100 * factor
229
elif float(ride.duration) >= 0:
230
score += 50 * factor
231
rideCount += 1
232
if rideCount == 0:
233
return 0, 0, False
234
else:
235
return int(score), rideCount, True
236
237
238
def computeScoreSquare(gamename):
239
maxScore = 1000.0
240
expectedVehCount = 142
241
timeLoss = 0
242
tripCount = 0
243
arrived = 0
244
for trip in sumolib.xml.parse(os.path.join(BASE, "output", gamename + ".tripinfos.xml"), 'tripinfo'):
245
timeLoss += float(trip.timeLoss) + float(trip.departDelay)
246
tripCount += 1
247
if float(trip.arrival) > 0:
248
arrived += 1
249
250
if tripCount == 0:
251
return 0, 0, False
252
else:
253
# early-abort score is close to 0, do-nothing timeLoss is ~8000
254
earlyEndPenalty = (expectedVehCount - tripCount) * (maxScore / expectedVehCount)
255
score = int(1000 - earlyEndPenalty - timeLoss / 10.0)
256
if _DEBUG:
257
print("tripCount=%s arrived=%s timeLoss=%s avtTimeLoss=%s earlyEndPenalty=%s" % (
258
tripCount, arrived, timeLoss, timeLoss / tripCount, earlyEndPenalty))
259
return score, arrived, True
260
261
262
_SCORING_FUNCTION = defaultdict(lambda: computeScoreFromWaitingTime)
263
_SCORING_FUNCTION.update({
264
'A10KW': lambda name: computeScoreFromTimeLoss(name, 20000),
265
'corridor': lambda name: computeScoreFromWaitingTime(name, 30000),
266
'highway': lambda name: computeScoreFromTimeLoss(name, 13000),
267
'DRT': computeScoreDRT,
268
'DRT2': computeScoreDRT,
269
'DRT_demo': computeScoreDRT,
270
'square': computeScoreSquare,
271
'rail': computeScoreRail,
272
'rail_demo': computeScoreRail,
273
})
274
275
276
def computeScore(gamename):
277
return _SCORING_FUNCTION[gamename](gamename)
278
279
280
def parseEndTime(cfg):
281
cfg_doc = pulldom.parse(cfg)
282
for event, parsenode in cfg_doc:
283
if event == pulldom.START_ELEMENT and parsenode.localName == 'end':
284
return float(parsenode.getAttribute('value'))
285
286
287
class IMAGE:
288
pass
289
290
291
class StartDialog(Tkinter.Frame):
292
293
def __init__(self, parent, lang, langCode):
294
Tkinter.Frame.__init__(self, parent)
295
# variables for changing language
296
self.parent = parent
297
self._language_text = lang
298
self.buttons = []
299
# misc variables
300
self.name = ''
301
# setup gui
302
self.parent.title(self._language_text['title'])
303
self.parent.minsize(250, 50)
304
self.category = None
305
self.highscoreLocation = Tkinter.StringVar(value="local")
306
self.high = self.loadHighscore(self.highscoreLocation.get())
307
308
# we use a grid layout with 4 columns
309
COL_DLRLOGO, COL_START, COL_HIGH, COL_SUMOLOGO = range(4)
310
# there is one column for every config, +2 more columns for control
311
# buttons
312
configs = sorted(glob.glob(os.path.join(BASE, "*.sumocfg")))
313
demos = [cfg for cfg in configs if "demo" in cfg]
314
numButtons = len(configs) + 3 - len(demos)
315
# button dimensions
316
bWidth_start = 40
317
bWidth_high = 10
318
319
self.gametime = 0
320
self.ret = 0
321
haveOSG = "OSG" in subprocess.check_output(sumolib.checkBinary("sumo"), universal_newlines=True)
322
323
# 2 button for each config (start, highscore)
324
325
demo = 0
326
row = 0
327
for cfg in configs:
328
if "bs3" in cfg and not haveOSG:
329
continue
330
category = self.category_name(cfg)
331
# lambda must make a copy of cfg argument
332
button = Tkinter.Button(self, width=bWidth_start,
333
command=lambda cfg=cfg: self.start_cfg(cfg))
334
self.addButton(button, category)
335
if cfg in demos:
336
button.grid(row=numButtons - demo, column=COL_SUMOLOGO)
337
demo += 1
338
continue
339
340
button.grid(row=row, column=COL_START)
341
342
button = Tkinter.Button(self, width=bWidth_high,
343
command=lambda cfg=cfg: ScoreDialog(self, [], None, self.category_name(cfg),
344
self._language_text, self.high)
345
) # .grid(row=row, column=COL_HIGH)
346
self.addButton(button, 'high')
347
button.grid(row=row, column=COL_HIGH)
348
row += 1
349
350
# some pretty images
351
Tkinter.Label(self, image=IMAGE.dlrLogo).grid(row=0, rowspan=numButtons-3, column=COL_DLRLOGO)
352
Tkinter.Label(self, image=IMAGE.sumoLogo).grid(row=0, rowspan=numButtons-3, column=COL_SUMOLOGO)
353
354
# control buttons
355
if _UPLOAD:
356
r1 = Tkinter.Radiobutton(self, text='Local Highscores', value='local', variable=self.highscoreLocation)
357
r1.grid(row=numButtons-3, column=COL_DLRLOGO)
358
r2 = Tkinter.Radiobutton(self, text='Global Highscores', value='global', variable=self.highscoreLocation)
359
r2.grid(row=numButtons-2, column=COL_DLRLOGO)
360
button = Tkinter.Button(self, width=bWidth_start, command=self.clear)
361
self.addButton(button, 'reset')
362
button.grid(row=numButtons - 1, column=COL_DLRLOGO)
363
364
# language selection
365
self.langChoices = {
366
"de": 'german',
367
"en": 'english',
368
"es": 'spanish',
369
"it": 'italian',
370
"fr": 'french',
371
"zh": 'chinese (simplified)',
372
"zh-Hant": 'chinese (traditional)',
373
}
374
self._langCode = langCode
375
self.langDrop = Tkinter.Listbox(self, height=len(demos), selectmode=Tkinter.SINGLE, width=bWidth_high)
376
self.langDrop.bind('<<ListboxSelect>>', self.change_language)
377
self.scrollbar = Tkinter.Scrollbar(self, orient=Tkinter.VERTICAL)
378
self.scrollbar.config(command=self.langDrop.yview)
379
self.langDrop.config(yscrollcommand=self.scrollbar.set)
380
self.updateLanguageMenu()
381
self.langDrop.grid(row=numButtons - len(demos) + 1, column=COL_HIGH, rowspan=len(demos), sticky="nsew")
382
self.scrollbar.grid(row=numButtons - len(demos) + 1, column=COL_SUMOLOGO, rowspan=len(demos), sticky="nsw")
383
384
button = Tkinter.Button(self, width=bWidth_start, command=sys.exit)
385
self.addButton(button, 'quit')
386
button.grid(row=numButtons, column=COL_START)
387
388
self.grid()
389
# The following three commands are needed so the window pops
390
# up on top on Windows...
391
self.parent.iconify()
392
self.parent.update()
393
self.parent.deiconify()
394
395
def updateLanguageMenu(self):
396
self.langDrop.delete(0, Tkinter.END)
397
langChoices = [self._language_text.get(longName, longName) for longName in self.langChoices.values()]
398
scrollPos = self.scrollbar.get()
399
self.langDrop.insert(0, *langChoices)
400
self.langDrop.activate(list(self.langChoices.keys()).index(self._langCode))
401
self.langDrop.yview_moveto(scrollPos[0])
402
403
def addButton(self, button, text, key=None):
404
button["text"] = self._language_text.get(text, text)
405
if key is None:
406
key = text
407
self.buttons.append((key, button))
408
409
def change_language(self, *args):
410
selection = self.langDrop.curselection()
411
if len(selection) == 0:
412
return
413
chosenLang = self.langDrop.get(selection[0])
414
for code, longName in self.langChoices.items():
415
if self._language_text[longName] == chosenLang:
416
self._langCode = code
417
break
418
setLanguage(self._langCode)
419
updateLocalMessages()
420
self._language_text = _LANGUAGE_CAPTIONS
421
422
# update language menu
423
self.updateLanguageMenu()
424
425
for key, button in self.buttons:
426
button["text"] = self._language_text[key]
427
self.parent.title(self._language_text['title'])
428
429
def category_name(self, cfg):
430
return os.path.basename(cfg)[:-8]
431
432
def loadHighscore(self, location):
433
if location == "global":
434
printDebug("try to load highscore from scoreserver...")
435
try:
436
conn = httplib.HTTPConnection(_SCORESERVER, timeout=_TIMEOUT)
437
conn.request("GET", _SCORESCRIPT + "top=" + str(_SCORES))
438
response = conn.getresponse()
439
if response.status == httplib.OK:
440
scores = {}
441
for line in response.read().splitlines():
442
category, values = line.split()
443
scores[category] = _SCORES * [("", "", -1.)]
444
for idx, item in enumerate(values.split(':')):
445
name, game, score = item.split(',')
446
scores[category][idx] = (name, game, int(float(score)))
447
printDebug("SUCCESS")
448
return scores
449
except Exception:
450
printDebug("FAILED")
451
try:
452
with open(_SCOREFILE, 'rb') as sf:
453
return pickle.load(sf)
454
except Exception as e:
455
print(e)
456
pass
457
if os.path.exists(REFSCOREFILE):
458
with open(REFSCOREFILE, 'rb') as sf:
459
return pickle.load(sf)
460
return {}
461
462
def clear(self):
463
self.high.clear()
464
if os.path.exists(REFSCOREFILE):
465
with open(REFSCOREFILE, 'rb') as sf:
466
self.high.update(pickle.load(sf))
467
468
def start_cfg(self, cfg):
469
# remember which cfg was launched
470
self.category = self.category_name(cfg)
471
if _DEBUG:
472
print("starting", cfg)
473
self.gametime = parseEndTime(cfg)
474
binary = sumolib.checkBinary("sumo-gui", BASE)
475
if binary == "sumo-gui": # fallback in case SUMO_HOME env is not defined
476
binary = sumolib.checkBinary("sumo-gui", os.path.join(SUMO_HOME, "bin"))
477
os.makedirs(os.path.join(BASE, "output"), exist_ok=True)
478
self.ret = subprocess.call(
479
[binary, "-S", "-G", "-Q", "-c", cfg, '-l', 'log',
480
'--output-prefix', os.path.join("output", self.category + "."), '--language', self._langCode,
481
'--duration-log.statistics', '--statistic-output', 'stats.xml',
482
'--tripinfo-output.write-unfinished'], stderr=sys.stderr)
483
484
if _DEBUG:
485
print("ended", cfg)
486
# ensure files are fully written
487
time.sleep(1)
488
489
# compute score
490
score, totalArrived, complete = _SCORING_FUNCTION[self.category](self.category)
491
492
# parse switches
493
switch = []
494
lastProg = {}
495
tlsfile = os.path.join(BASE, self.category, "tlsstate.xml")
496
if os.path.exists(tlsfile):
497
for line in open(tlsfile):
498
m = re.search(r'tlsstate time="(\d+(.\d+)?)" id="([^"]*)" programID="([^"]*)"', line)
499
if m:
500
tls = m.group(3)
501
program = m.group(4)
502
if tls not in lastProg or lastProg[tls] != program:
503
lastProg[tls] = program
504
switch += [m.group(3), m.group(1)]
505
506
lang = self._language_text
507
if _DEBUG:
508
print(switch, score, totalArrived, complete)
509
if complete:
510
ScoreDialog(self, switch, score, self.category, lang, self.high)
511
512
# if ret != 0:
513
# quit on error
514
# sys.exit(start.ret)
515
516
517
class ScoreDialog:
518
519
def __init__(self, parent, switch, score, category, lang, high):
520
self.root = Tkinter.Toplevel(parent)
521
# self.root.transient(parent)
522
self.name = None
523
self.switch = switch
524
self.score = score
525
self.category = category
526
self.root.title("%s%s" % (lang["Highscore"], ": " + lang[self.category] if self.category in lang else ""))
527
self.root.minsize(250, 50)
528
self.high = high
529
530
haveHigh = False
531
532
if category not in self.high:
533
self.high[category] = _SCORES * [("", "", -1.)]
534
if len(self.high[category]) < _SCORES:
535
self.high[category] += (_SCORES - len(self.high[category])) * [("", "", -1.)]
536
idx = 0
537
for n, g, p in self.high[category]:
538
if not haveHigh and score is not None and p < score:
539
Tkinter.Label(self.root, text=(str(idx + 1) + '. ')).grid(row=idx)
540
self.name = Tkinter.Entry(self.root)
541
self.name.grid(row=idx, sticky=Tkinter.W, column=1)
542
self.scoreLabel = Tkinter.Label(self.root, text="%.2f" % score,
543
bg="pale green").grid(row=idx, column=2)
544
self.idx = idx
545
haveHigh = True
546
self.root.title(lang["Congratulations"])
547
idx += 1
548
if p == -1 or idx == _SCORES:
549
break
550
Tkinter.Label(self.root, text=(str(idx + 1) + '. ')).grid(row=idx)
551
Tkinter.Label(self.root, text=n, padx=5).grid(
552
row=idx, sticky=Tkinter.W, column=1)
553
Tkinter.Label(self.root, text="%.2f" % p).grid(row=idx, column=2)
554
idx += 1
555
if not haveHigh:
556
if score is not None: # not called from the main menue
557
Tkinter.Label(self.root, text=lang['your score'], padx=5,
558
bg="indian red").grid(row=idx, sticky=Tkinter.W, column=1)
559
Tkinter.Label(self.root, text="%.2f" % score,
560
bg="indian red").grid(row=idx, column=2)
561
idx += 1
562
Tkinter.Button(self.root, text=lang["Continue"], command=self.save).grid(
563
row=idx, column=2)
564
565
# add QR-code for LNDW
566
Tkinter.Label(self.root, image=IMAGE.qrCode).grid(
567
row=1, column=3, rowspan=22)
568
569
self.root.grid()
570
self.root.bind("<Return>", self.save)
571
# self.root.wait_visibility()
572
# self.root.grab_set()
573
if self.name:
574
self.name.focus_set()
575
# The following three commands are needed so the window pops
576
# up on top on Windows...
577
# self.root.iconify()
578
# self.root.update()
579
# self.root.deiconify()
580
# self.root.mainloop()
581
582
def save(self, event=None):
583
if self.name and self.name.get():
584
name = self.name.get()
585
self.high[self.category].insert(self.idx, (name, self.switch, self.score))
586
self.high[self.category].pop()
587
self.name.destroy()
588
self.name = None
589
Tkinter.Label(self.root, text=name, padx=5,
590
bg="pale green").grid(row=self.idx, sticky=Tkinter.W, column=1)
591
try:
592
f = open(_SCOREFILE, 'wb')
593
pickle.dump(self.high, f)
594
f.close()
595
except Exception as e:
596
print(e)
597
pass
598
599
if _UPLOAD:
600
printDebug("try to upload score...")
601
try:
602
conn = httplib.HTTPConnection(_SCORESERVER, timeout=_TIMEOUT)
603
conn.request("GET", _SCORESCRIPT + "category=%s&name=%s&instance=%s&points=%s" % (
604
self.category, name, "_".join(self.switch), self.score))
605
if _DEBUG:
606
r1 = conn.getresponse()
607
print(r1.status, r1.reason, r1.read())
608
printDebug("SUCCESS")
609
except BaseException:
610
printDebug("FAILED")
611
self.quit()
612
613
def quit(self, event=None):
614
self.root.destroy()
615
616
617
def main():
618
stereoModes = ('ANAGLYPHIC', 'QUAD_BUFFER', 'VERTICAL_SPLIT', 'HORIZONTAL_SPLIT')
619
optParser = sumolib.options.ArgumentParser()
620
optParser.add_option("-s", "--stereo", metavar="OSG_STEREO_MODE",
621
help=("Defines the stereo mode to use for 3D output; unique prefix of %s" % (
622
", ".join(stereoModes))))
623
optParser.add_option("add", nargs="*", help="additional flags: {debug|noupload}")
624
625
addLanguageOption(optParser)
626
options = optParser.parse_args()
627
setLanguage(options.language)
628
updateLocalMessages()
629
630
if options.stereo:
631
for m in stereoModes:
632
if m.lower().startswith(options.stereo.lower()):
633
os.environ["OSG_STEREO_MODE"] = m
634
os.environ["OSG_STEREO"] = "ON"
635
break
636
637
if "OSG_FILE_PATH" in os.environ:
638
os.environ["OSG_FILE_PATH"] += os.pathsep + \
639
os.path.join(os.environ.get("SUMO_HOME", ""), "data", "3D")
640
else:
641
os.environ["OSG_FILE_PATH"] = os.path.join(
642
os.environ.get("SUMO_HOME", ""), "data", "3D")
643
644
root = Tkinter.Tk()
645
IMAGE.dlrLogo = Tkinter.PhotoImage(file=os.path.join(BASE, 'dlr.gif'))
646
IMAGE.sumoLogo = Tkinter.PhotoImage(file=os.path.join(BASE, 'sumo_logo.gif'))
647
IMAGE.qrCode = Tkinter.PhotoImage(file=os.path.join(BASE, 'qr_sumo.dlr.de.gif'))
648
StartDialog(root, _LANGUAGE_CAPTIONS, options.language)
649
root.mainloop()
650
651
652
if __name__ == "__main__":
653
main()
654
655