Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/contributed/sumopy/plugins/prt/wxgui.py
169689 views
1
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
2
# Copyright (C) 2016-2025 German Aerospace Center (DLR) and others.
3
# SUMOPy module
4
# Copyright (C) 2012-2021 University of Bologna - DICAM
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 wxgui.py
16
# @author Joerg Schweizer
17
# @date 2012
18
19
import os
20
import wx
21
import numpy as np
22
23
from agilepy.lib_wx.modulegui import ModuleGui
24
from agilepy.lib_wx.ogleditor import *
25
from agilepy.lib_base.processes import Process
26
from agilepy.lib_wx.processdialog import ProcessDialog, ProcessDialogInteractive
27
28
from coremodules.network import routing
29
from coremodules.demand import demand
30
from coremodules.simulation import sumo, results
31
import prt
32
33
try:
34
import results_mpl as results_mpl
35
is_mpl = True # we have matplotlib support
36
except:
37
print "WARNING: python matplotlib package not installed, no matplotlib plots."
38
is_mpl = False
39
40
41
class AddPrtCompressorTool(SelectTool):
42
"""
43
Public transport toolfor OGL canvas.
44
"""
45
46
def __init__(self, parent, mainframe=None):
47
"""
48
To be overridden by specific tool.
49
"""
50
self.init_common('prtcompressoradder', parent, 'Add PRT compressor/decompressor',
51
info="""Tool to add a PRT compressor/decompressor
52
1. Select compressor/decompressor and edit parameters in the options panel.
53
2. Click on a sequence of PRT edges that become shunt-lines of the compressor/decompressor. (Cycle overlapping edges with <SHIFT>+<LEFT MOUSE>, <LEFT MOUSE> to set final)
54
3. Click the Add button to add the compressor/decompressor.
55
""",
56
is_textbutton=False,
57
)
58
59
self._init_select(is_show_selected=False)
60
61
tooltypechoices = ['Add compressor', 'Add decompressor']
62
self.add(cm.AttrConf('tooltype', tooltypechoices[0],
63
groupnames=['options'],
64
choices=tooltypechoices,
65
perm='rw',
66
name='Tool type',
67
info="""Type of tool/action used.""",
68
))
69
70
# self.add_options_common()
71
# make options
72
self.add(cm.AttrConf('ids_edge', [],
73
perm='r',
74
groupnames=['options'],
75
name='Shunt edge IDs',
76
info='Sequence of edge IDs used as shunt lines.',
77
xmltag='edges',
78
))
79
80
def set_button_info(self, bsize=(32, 32)):
81
# print 'set_button_info select tool' self.get_icon("icon_sumo_24px.png")
82
iconpath = os.path.join(os.path.dirname(__file__), 'images')
83
self._bitmap = wx.Bitmap(os.path.join(iconpath, 'icon_compressor.png'), wx.BITMAP_TYPE_PNG)
84
self._bitmap_sel = self._bitmap
85
86
def set_cursor(self):
87
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
88
if self._canvas is not None:
89
self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_RIGHT_ARROW))
90
91
def activate(self, canvas=None):
92
"""
93
This call by metacanvas??TooldsPallet signals that the tool has been
94
activated and can now interact with metacanvas.
95
"""
96
# print 'activate'
97
SelectTool.activate(self, canvas)
98
99
# make lanes invisible, because they disturb
100
lanedraws = self.get_drawobj_by_ident('lanedraws')
101
self._is_lane_visible_before = None
102
if lanedraws:
103
self._is_lane_visible_before = lanedraws.is_visible()
104
lanedraws.set_visible(False)
105
106
#vtypechoices = self.get_scenario().demand.vtypes.ids_sumo.get_indexmap()
107
# print ' vtypechoices',vtypechoices
108
# self.id_vtype.set_value(vtypechoices.get('bus',0))
109
#self.id_vtype.choices = vtypechoices
110
canvas.draw()
111
112
def deactivate(self):
113
"""
114
This call by metacanvas signals that the tool has been
115
deactivated and can now interact with metacanvas.
116
"""
117
118
self._is_active = False
119
# self.unhighlight()
120
121
# reset lane visibility
122
if self._is_lane_visible_before is not None:
123
lanedraws = self.get_drawobj_by_ident('lanedraws')
124
if lanedraws:
125
lanedraws.set_visible(self._is_lane_visible_before)
126
self._canvas.draw()
127
128
self.deactivate_select()
129
130
def on_left_down_select(self, event):
131
# same as on select tool but avoid deselection after execution
132
133
# print 'on_left_down_select'
134
is_draw = False
135
136
if len(self) > 0:
137
if event.ShiftDown():
138
139
self.iterate_selection()
140
self.on_change_selection(event)
141
is_draw = True
142
else:
143
# print ' on_execute_selection 1'
144
is_draw |= self.on_execute_selection(event)
145
# attention: on_execute_selection must take care of selected
146
# objects in list with self.unselect_all()
147
#is_draw |= self.unselect_all()
148
149
if self.is_show_selected:
150
self.parent.refresh_optionspanel(self)
151
152
else:
153
is_draw |= self.pick_all(event)
154
self.highlight_current()
155
156
if not event.ShiftDown():
157
if self.is_preselected():
158
self.coord_last = self._canvas.unproject(event.GetPosition())
159
# print ' on_execute_selection 2'
160
is_draw |= self.on_execute_selection(event)
161
# attention: on_execute_selection must take care of selected
162
# objects in list with self.unselect_all()
163
164
else:
165
self.coord_last = self._canvas.unproject(event.GetPosition())
166
167
if self.is_show_selected:
168
self.parent.refresh_optionspanel(self)
169
170
return is_draw
171
172
def on_execute_selection(self, event):
173
"""
174
Definively execute operation on currently selected drawobjects.
175
"""
176
# print 'AddTurnflowTool.on_execute_selection',self.get_netelement_current(),len(self)
177
# self.set_objbrowser()
178
# self.highlight_current()
179
self.unhighlight_current()
180
# self.unhighlight()
181
netelement_current = self.get_netelement_current()
182
if netelement_current is not None:
183
(elem, id_elem) = netelement_current
184
if elem.get_ident() == 'edges':
185
# print ' check',self.id_fromedge.get_value()
186
self.ids_edge.get_value().append(id_elem)
187
188
# add potential to-edges to selection
189
#edgedraws = self.get_drawobj_by_ident('edgedraws')
190
# self.unselect_all()
191
# for id_edge in edges.get_outgoing(self.id_fromedge.value):
192
# self.add_selection(edgedraws, id_edge)
193
194
# self.unselect_all()# includes unhighlight
195
# self.highlight()
196
self.parent.refresh_optionspanel(self)
197
198
else:
199
self.unselect_all()
200
201
return True
202
203
def on_change_selection(self, event):
204
"""
205
Called after selection has been changed with SHIFT-click
206
Do operation on currently selected drawobjects.
207
"""
208
# self.set_objbrowser()
209
# self.parent.refresh_optionspanel(self)
210
return False
211
212
def get_netelement_current(self):
213
mainframe = self.parent.get_mainframe()
214
if mainframe is not None:
215
drawobj, _id = self.get_current_selection()
216
if drawobj is not None:
217
obj = drawobj.get_netelement()
218
return obj, _id
219
else:
220
return None
221
else:
222
return None
223
224
def get_scenario(self):
225
# get net and scenario via netdrawing
226
return self.get_drawing().get_net().parent
227
228
def get_edges(self):
229
return self.get_scenario().net.edges
230
231
def on_add_compressor(self, event=None):
232
self._optionspanel.apply()
233
#edges = self.get_edges().ids_sumo
234
235
#['Add compressor','Add decompressor']
236
mainframe = self.parent.get_mainframe()
237
if self.tooltype.get_value() == 'Add compressor':
238
compressors = self.get_scenario().simulation.prtservice.compressors
239
id_line = compressors.make(ids_shuntedge=self.ids_edge.get_value())
240
if mainframe is not None:
241
mainframe.browse_obj(compressors)
242
else:
243
decompressors = self.get_scenario().simulation.prtservice.decompressors
244
id_line = decompressors.make(ids_shuntedge=self.ids_edge.get_value())
245
if mainframe is not None:
246
mainframe.browse_obj(decompressors)
247
248
# self.ids_stop.set_value([])
249
self.ids_edge.set_value([])
250
# self.highlight()
251
self.parent.refresh_optionspanel(self)
252
# self._canvas.draw()
253
254
def on_clear_edges(self, event=None):
255
# self.unhighlight()
256
self.ids_edge.set_value([]) # set empty
257
self.unselect_all()
258
259
self.parent.refresh_optionspanel(self)
260
self._canvas.draw()
261
262
def get_optionspanel(self, parent, size=wx.DefaultSize):
263
"""
264
Return tool option widgets on given parent
265
"""
266
size = (200, -1)
267
buttons = [('Add', self.on_add_compressor, 'Add PRT compressor or decompressor.'),
268
('Clear edges', self.on_clear_edges, 'Clear shunt edges from selection.'),
269
]
270
defaultbuttontext = 'Add'
271
self._optionspanel = ObjPanel(parent, obj=self,
272
attrconfigs=None,
273
groupnames=['options'],
274
func_change_obj=None,
275
show_groupnames=False, show_title=True, is_modal=False,
276
mainframe=self.parent.get_mainframe(),
277
pos=wx.DefaultPosition, size=size, style=wx.MAXIMIZE_BOX | wx.RESIZE_BORDER,
278
immediate_apply=True, panelstyle='default', # 'instrumental'
279
buttons=buttons, defaultbutton=defaultbuttontext,
280
standartbuttons=[], # standartbuttons=['restore']
281
)
282
283
return self._optionspanel
284
285
286
class ResultDialog(ProcessDialog):
287
def _get_buttons(self):
288
buttons = [('Plot and close', self.on_run, 'Plot in matplotlib window and close this window thereafter.'),
289
('Plot', self.on_show, 'Plot in matplotlib window.'),
290
]
291
defaultbutton = 'Plot and close'
292
standartbuttons = ['cancel', ]
293
294
return buttons, defaultbutton, standartbuttons
295
296
def on_show(self, event):
297
self.process.show()
298
299
300
class WxGui(ModuleGui):
301
"""Contains functions that communicate between PRT plugin and the widgets of the main wx gui
302
and the functions of the plugin.
303
"""
304
305
def __init__(self, ident):
306
self._prtservice = None
307
self._demand = None
308
self._simulation = None
309
self._init_common(ident, priority=100002,
310
icondirpath=os.path.join(os.path.dirname(__file__), 'images'))
311
312
def get_module(self):
313
return self._prtservice
314
315
def get_scenario(self):
316
return self._mainframe.get_modulegui('coremodules.scenario').get_scenario()
317
318
def get_neteditor(self):
319
return self._mainframe.get_modulegui('coremodules.network').get_neteditor()
320
321
def init_widgets(self, mainframe):
322
"""
323
Set mainframe and initialize widgets to various places.
324
"""
325
self._mainframe = mainframe
326
#self._neteditor = mainframe.add_view("Network", Neteditor)
327
328
# mainframe.browse_obj(self._module)
329
self.make_menu()
330
self.make_toolbar()
331
332
def refresh_widgets(self):
333
"""
334
Check through mainframe what the state of the application is
335
and reset widgets. For exampe enable/disable widgets
336
dependent on the availability of data.
337
"""
338
scenario = self.get_scenario()
339
print 'prtgui.refresh_widgets', self._simulation != scenario.simulation
340
341
is_refresh = False
342
if self._simulation != scenario.simulation:
343
del self._demand
344
del self._prtservice
345
del self._simulation
346
self._demand = scenario.demand
347
self._simulation = scenario.simulation
348
self._prtservice = self._simulation.add_simobject(ident='prtservice', SimClass=prt.PrtService)
349
is_refresh = True
350
neteditor = self.get_neteditor()
351
neteditor.get_toolbox().add_toolclass(AddPrtCompressorTool)
352
# if (self._prtservice is not None)&(self._simulation is not None):
353
# print ' self._simulation.results,self._prtservice._results:', self._simulation.results,self._prtservice.get_results(),id(self._simulation.results), id(self._prtservice.get_results())
354
# print ' self._simulation.results',id(self._simulation.results)
355
356
def make_menu(self):
357
menubar = self._mainframe.menubar
358
menubar.append_menu('plugins/prt', bitmap=self.get_icon('icon_prt.png'),)
359
if sumo.traci is not None:
360
menubar.append_item('plugins/prt/browse',
361
self.on_browse_obj, # common function in modulegui
362
info='View and browse PRT in object panel.',
363
bitmap=self.get_agileicon('icon_browse_24px.png'), # ,
364
)
365
366
menubar.append_item('plugins/prt/make stops',
367
self.on_make_stops,
368
info='Make PRT stops from PT stops with PRT access ("custom1").',
369
# bitmap = self.get_icon('icon_sumo.png'),#,
370
)
371
372
menubar.append_item('plugins/prt/clear stops',
373
self.on_clear_stops,
374
bitmap=wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_MENU),
375
)
376
377
menubar.append_item('plugins/prt/update compressors',
378
self.on_update_compressors,
379
# bitmap = self.get_icon('icon_sumo.png'),#,
380
)
381
menubar.append_item('plugins/prt/clear compressors',
382
self.on_clear_compressors,
383
bitmap=wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_MENU),
384
)
385
menubar.append_item('plugins/prt/update decompressors',
386
self.on_update_decompressors,
387
# bitmap = self.get_icon('icon_sumo.png'),#,
388
)
389
menubar.append_item('plugins/prt/clear decompressors',
390
self.on_clear_decompressors,
391
bitmap=wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_MENU),
392
)
393
394
menubar.append_item('plugins/prt/make merge nodes',
395
self.on_make_merges,
396
info='Make PRT merge nodes.',
397
# bitmap = self.get_icon('icon_sumo.png'),#,
398
)
399
400
menubar.append_item('plugins/prt/clear merge nodes',
401
self.on_clear_merges,
402
bitmap=wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_MENU),
403
)
404
405
menubar.append_item('plugins/prt/calculate stop to stop times',
406
self.on_make_times_stop_to_stop,
407
# bitmap = self.get_icon('icon_sumo.png'),#,
408
)
409
410
menubar.append_item('plugins/prt/add vehicles...',
411
self.on_add_vehicles,
412
info='Add PRT vehicles to network.',
413
# bitmap = self.get_icon('icon_sumo.png'),#,
414
)
415
416
menubar.append_item('plugins/prt/clear vehicles.',
417
self.on_clear_vehicles,
418
info='Clear all PRT vehicles from network.',
419
bitmap=wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_MENU),
420
)
421
422
menubar.append_menu('plugins/prt/results',
423
bitmap=self.get_icon('icon_results_24px.png'), # ,
424
)
425
if is_mpl:
426
menubar.append_item('plugins/prt/results/stopresults with matplotlib',
427
self.on_mpl_stopresults,
428
bitmap=self.get_icon('icon_mpl.png'), # ,
429
)
430
431
def on_make_stops(self, event=None):
432
self._prtservice.prtstops.make_from_net()
433
self._mainframe.browse_obj(self._prtservice.prtstops)
434
435
def on_clear_stops(self, event=None):
436
"""Delete all stope"""
437
self._prtservice.prtstops.clear()
438
self._mainframe.browse_obj(self._prtservice.prtstops)
439
440
def on_update_compressors(self, event=None):
441
"""Update all compressors (determine detector edge)"""
442
self._prtservice.compressors.update_all()
443
self._mainframe.browse_obj(self._prtservice.compressors)
444
445
def on_clear_compressors(self, event=None):
446
"""Delete all compressors"""
447
self._prtservice.compressors.clear()
448
self._mainframe.browse_obj(self._prtservice.compressors)
449
450
def on_update_decompressors(self, event=None):
451
"""Update all decompressors (determine detector edge)"""
452
self._prtservice.decompressors.update_all()
453
self._mainframe.browse_obj(self._prtservice.decompressors)
454
455
def on_clear_decompressors(self, event=None):
456
"""Delete all decompressors"""
457
self._prtservice.decompressors.clear()
458
self._mainframe.browse_obj(self._prtservice.decompressors)
459
460
def on_make_merges(self, event=None):
461
462
self._prtservice.mergenodes.make_from_net()
463
self._mainframe.browse_obj(self._prtservice.mergenodes)
464
465
def on_clear_merges(self, event=None):
466
"""Delete all merges"""
467
self._prtservice.mergenodes.clear()
468
self._mainframe.browse_obj(self._prtservice.mergenodes)
469
470
def on_make_times_stop_to_stop(self, event=None):
471
"""Determine stop to sto time matrix"""
472
473
self._prtservice.make_times_stop_to_stop()
474
self._mainframe.browse_obj(self._prtservice)
475
476
def on_add_vehicles(self, event=None):
477
p = prt.VehicleAdder(self._prtservice.prtvehicles, logger=self._mainframe.get_logger())
478
dlg = ProcessDialog(self._mainframe, p, immediate_apply=True)
479
480
dlg.CenterOnScreen()
481
482
# this does not return until the dialog is closed.
483
val = dlg.ShowModal()
484
# print ' val,val == wx.ID_OK',val,wx.ID_OK,wx.ID_CANCEL,val == wx.ID_CANCEL
485
# print ' status =',dlg.get_status()
486
if dlg.get_status() != 'success': # val == wx.ID_CANCEL:
487
# print ">>>>>>>>>Unsuccessful\n"
488
dlg.Destroy()
489
490
if dlg.get_status() == 'success':
491
# print ">>>>>>>>>successful\n"
492
# apply current widget values to scenario instance
493
dlg.apply()
494
dlg.Destroy()
495
self._mainframe.browse_obj(self._prtservice.prtvehicles)
496
497
def on_clear_vehicles(self, event=None):
498
self._prtservice.prtvehicles.clear()
499
self._mainframe.browse_obj(self._prtservice.prtvehicles)
500
501
def on_mpl_stopresults(self, event=None):
502
print 'on_mpl_stopresults', id(self._simulation.results) # ,id(self._prtservice.get_results())
503
if self._prtservice is not None:
504
if self._simulation is not None:
505
resultplotter = results_mpl.StopresultsPlotter(self._simulation.results, # self._prtservice.get_results(),
506
logger=self._mainframe.get_logger())
507
dlg = ResultDialog(self._mainframe, resultplotter)
508
509
dlg.CenterOnScreen()
510
511
# this does not return until the dialog is closed.
512
val = dlg.ShowModal()
513
if dlg.get_status() != 'success': # val == wx.ID_CANCEL:
514
dlg.Destroy()
515
516
elif dlg.get_status() == 'success':
517
# apply current widget values to scenario instance
518
dlg.apply()
519
dlg.Destroy()
520
521