Path: blob/main/tools/contributed/sumopy/plugins/prt/wxgui.py
169689 views
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo1# Copyright (C) 2016-2025 German Aerospace Center (DLR) and others.2# SUMOPy module3# Copyright (C) 2012-2021 University of Bologna - DICAM4# This program and the accompanying materials are made available under the5# terms of the Eclipse Public License 2.0 which is available at6# https://www.eclipse.org/legal/epl-2.0/7# This Source Code may also be made available under the following Secondary8# Licenses when the conditions for such availability set forth in the Eclipse9# Public License 2.0 are satisfied: GNU General Public License, version 210# or later which is available at11# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html12# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later1314# @file wxgui.py15# @author Joerg Schweizer16# @date 20121718import os19import wx20import numpy as np2122from agilepy.lib_wx.modulegui import ModuleGui23from agilepy.lib_wx.ogleditor import *24from agilepy.lib_base.processes import Process25from agilepy.lib_wx.processdialog import ProcessDialog, ProcessDialogInteractive2627from coremodules.network import routing28from coremodules.demand import demand29from coremodules.simulation import sumo, results30import prt3132try:33import results_mpl as results_mpl34is_mpl = True # we have matplotlib support35except:36print "WARNING: python matplotlib package not installed, no matplotlib plots."37is_mpl = False383940class AddPrtCompressorTool(SelectTool):41"""42Public transport toolfor OGL canvas.43"""4445def __init__(self, parent, mainframe=None):46"""47To be overridden by specific tool.48"""49self.init_common('prtcompressoradder', parent, 'Add PRT compressor/decompressor',50info="""Tool to add a PRT compressor/decompressor511. Select compressor/decompressor and edit parameters in the options panel.522. 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)533. Click the Add button to add the compressor/decompressor.54""",55is_textbutton=False,56)5758self._init_select(is_show_selected=False)5960tooltypechoices = ['Add compressor', 'Add decompressor']61self.add(cm.AttrConf('tooltype', tooltypechoices[0],62groupnames=['options'],63choices=tooltypechoices,64perm='rw',65name='Tool type',66info="""Type of tool/action used.""",67))6869# self.add_options_common()70# make options71self.add(cm.AttrConf('ids_edge', [],72perm='r',73groupnames=['options'],74name='Shunt edge IDs',75info='Sequence of edge IDs used as shunt lines.',76xmltag='edges',77))7879def set_button_info(self, bsize=(32, 32)):80# print 'set_button_info select tool' self.get_icon("icon_sumo_24px.png")81iconpath = os.path.join(os.path.dirname(__file__), 'images')82self._bitmap = wx.Bitmap(os.path.join(iconpath, 'icon_compressor.png'), wx.BITMAP_TYPE_PNG)83self._bitmap_sel = self._bitmap8485def set_cursor(self):86# http://www.wxpython.org/docs/api/wx.Cursor-class.html87if self._canvas is not None:88self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_RIGHT_ARROW))8990def activate(self, canvas=None):91"""92This call by metacanvas??TooldsPallet signals that the tool has been93activated and can now interact with metacanvas.94"""95# print 'activate'96SelectTool.activate(self, canvas)9798# make lanes invisible, because they disturb99lanedraws = self.get_drawobj_by_ident('lanedraws')100self._is_lane_visible_before = None101if lanedraws:102self._is_lane_visible_before = lanedraws.is_visible()103lanedraws.set_visible(False)104105#vtypechoices = self.get_scenario().demand.vtypes.ids_sumo.get_indexmap()106# print ' vtypechoices',vtypechoices107# self.id_vtype.set_value(vtypechoices.get('bus',0))108#self.id_vtype.choices = vtypechoices109canvas.draw()110111def deactivate(self):112"""113This call by metacanvas signals that the tool has been114deactivated and can now interact with metacanvas.115"""116117self._is_active = False118# self.unhighlight()119120# reset lane visibility121if self._is_lane_visible_before is not None:122lanedraws = self.get_drawobj_by_ident('lanedraws')123if lanedraws:124lanedraws.set_visible(self._is_lane_visible_before)125self._canvas.draw()126127self.deactivate_select()128129def on_left_down_select(self, event):130# same as on select tool but avoid deselection after execution131132# print 'on_left_down_select'133is_draw = False134135if len(self) > 0:136if event.ShiftDown():137138self.iterate_selection()139self.on_change_selection(event)140is_draw = True141else:142# print ' on_execute_selection 1'143is_draw |= self.on_execute_selection(event)144# attention: on_execute_selection must take care of selected145# objects in list with self.unselect_all()146#is_draw |= self.unselect_all()147148if self.is_show_selected:149self.parent.refresh_optionspanel(self)150151else:152is_draw |= self.pick_all(event)153self.highlight_current()154155if not event.ShiftDown():156if self.is_preselected():157self.coord_last = self._canvas.unproject(event.GetPosition())158# print ' on_execute_selection 2'159is_draw |= self.on_execute_selection(event)160# attention: on_execute_selection must take care of selected161# objects in list with self.unselect_all()162163else:164self.coord_last = self._canvas.unproject(event.GetPosition())165166if self.is_show_selected:167self.parent.refresh_optionspanel(self)168169return is_draw170171def on_execute_selection(self, event):172"""173Definively execute operation on currently selected drawobjects.174"""175# print 'AddTurnflowTool.on_execute_selection',self.get_netelement_current(),len(self)176# self.set_objbrowser()177# self.highlight_current()178self.unhighlight_current()179# self.unhighlight()180netelement_current = self.get_netelement_current()181if netelement_current is not None:182(elem, id_elem) = netelement_current183if elem.get_ident() == 'edges':184# print ' check',self.id_fromedge.get_value()185self.ids_edge.get_value().append(id_elem)186187# add potential to-edges to selection188#edgedraws = self.get_drawobj_by_ident('edgedraws')189# self.unselect_all()190# for id_edge in edges.get_outgoing(self.id_fromedge.value):191# self.add_selection(edgedraws, id_edge)192193# self.unselect_all()# includes unhighlight194# self.highlight()195self.parent.refresh_optionspanel(self)196197else:198self.unselect_all()199200return True201202def on_change_selection(self, event):203"""204Called after selection has been changed with SHIFT-click205Do operation on currently selected drawobjects.206"""207# self.set_objbrowser()208# self.parent.refresh_optionspanel(self)209return False210211def get_netelement_current(self):212mainframe = self.parent.get_mainframe()213if mainframe is not None:214drawobj, _id = self.get_current_selection()215if drawobj is not None:216obj = drawobj.get_netelement()217return obj, _id218else:219return None220else:221return None222223def get_scenario(self):224# get net and scenario via netdrawing225return self.get_drawing().get_net().parent226227def get_edges(self):228return self.get_scenario().net.edges229230def on_add_compressor(self, event=None):231self._optionspanel.apply()232#edges = self.get_edges().ids_sumo233234#['Add compressor','Add decompressor']235mainframe = self.parent.get_mainframe()236if self.tooltype.get_value() == 'Add compressor':237compressors = self.get_scenario().simulation.prtservice.compressors238id_line = compressors.make(ids_shuntedge=self.ids_edge.get_value())239if mainframe is not None:240mainframe.browse_obj(compressors)241else:242decompressors = self.get_scenario().simulation.prtservice.decompressors243id_line = decompressors.make(ids_shuntedge=self.ids_edge.get_value())244if mainframe is not None:245mainframe.browse_obj(decompressors)246247# self.ids_stop.set_value([])248self.ids_edge.set_value([])249# self.highlight()250self.parent.refresh_optionspanel(self)251# self._canvas.draw()252253def on_clear_edges(self, event=None):254# self.unhighlight()255self.ids_edge.set_value([]) # set empty256self.unselect_all()257258self.parent.refresh_optionspanel(self)259self._canvas.draw()260261def get_optionspanel(self, parent, size=wx.DefaultSize):262"""263Return tool option widgets on given parent264"""265size = (200, -1)266buttons = [('Add', self.on_add_compressor, 'Add PRT compressor or decompressor.'),267('Clear edges', self.on_clear_edges, 'Clear shunt edges from selection.'),268]269defaultbuttontext = 'Add'270self._optionspanel = ObjPanel(parent, obj=self,271attrconfigs=None,272groupnames=['options'],273func_change_obj=None,274show_groupnames=False, show_title=True, is_modal=False,275mainframe=self.parent.get_mainframe(),276pos=wx.DefaultPosition, size=size, style=wx.MAXIMIZE_BOX | wx.RESIZE_BORDER,277immediate_apply=True, panelstyle='default', # 'instrumental'278buttons=buttons, defaultbutton=defaultbuttontext,279standartbuttons=[], # standartbuttons=['restore']280)281282return self._optionspanel283284285class ResultDialog(ProcessDialog):286def _get_buttons(self):287buttons = [('Plot and close', self.on_run, 'Plot in matplotlib window and close this window thereafter.'),288('Plot', self.on_show, 'Plot in matplotlib window.'),289]290defaultbutton = 'Plot and close'291standartbuttons = ['cancel', ]292293return buttons, defaultbutton, standartbuttons294295def on_show(self, event):296self.process.show()297298299class WxGui(ModuleGui):300"""Contains functions that communicate between PRT plugin and the widgets of the main wx gui301and the functions of the plugin.302"""303304def __init__(self, ident):305self._prtservice = None306self._demand = None307self._simulation = None308self._init_common(ident, priority=100002,309icondirpath=os.path.join(os.path.dirname(__file__), 'images'))310311def get_module(self):312return self._prtservice313314def get_scenario(self):315return self._mainframe.get_modulegui('coremodules.scenario').get_scenario()316317def get_neteditor(self):318return self._mainframe.get_modulegui('coremodules.network').get_neteditor()319320def init_widgets(self, mainframe):321"""322Set mainframe and initialize widgets to various places.323"""324self._mainframe = mainframe325#self._neteditor = mainframe.add_view("Network", Neteditor)326327# mainframe.browse_obj(self._module)328self.make_menu()329self.make_toolbar()330331def refresh_widgets(self):332"""333Check through mainframe what the state of the application is334and reset widgets. For exampe enable/disable widgets335dependent on the availability of data.336"""337scenario = self.get_scenario()338print 'prtgui.refresh_widgets', self._simulation != scenario.simulation339340is_refresh = False341if self._simulation != scenario.simulation:342del self._demand343del self._prtservice344del self._simulation345self._demand = scenario.demand346self._simulation = scenario.simulation347self._prtservice = self._simulation.add_simobject(ident='prtservice', SimClass=prt.PrtService)348is_refresh = True349neteditor = self.get_neteditor()350neteditor.get_toolbox().add_toolclass(AddPrtCompressorTool)351# if (self._prtservice is not None)&(self._simulation is not None):352# print ' self._simulation.results,self._prtservice._results:', self._simulation.results,self._prtservice.get_results(),id(self._simulation.results), id(self._prtservice.get_results())353# print ' self._simulation.results',id(self._simulation.results)354355def make_menu(self):356menubar = self._mainframe.menubar357menubar.append_menu('plugins/prt', bitmap=self.get_icon('icon_prt.png'),)358if sumo.traci is not None:359menubar.append_item('plugins/prt/browse',360self.on_browse_obj, # common function in modulegui361info='View and browse PRT in object panel.',362bitmap=self.get_agileicon('icon_browse_24px.png'), # ,363)364365menubar.append_item('plugins/prt/make stops',366self.on_make_stops,367info='Make PRT stops from PT stops with PRT access ("custom1").',368# bitmap = self.get_icon('icon_sumo.png'),#,369)370371menubar.append_item('plugins/prt/clear stops',372self.on_clear_stops,373bitmap=wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_MENU),374)375376menubar.append_item('plugins/prt/update compressors',377self.on_update_compressors,378# bitmap = self.get_icon('icon_sumo.png'),#,379)380menubar.append_item('plugins/prt/clear compressors',381self.on_clear_compressors,382bitmap=wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_MENU),383)384menubar.append_item('plugins/prt/update decompressors',385self.on_update_decompressors,386# bitmap = self.get_icon('icon_sumo.png'),#,387)388menubar.append_item('plugins/prt/clear decompressors',389self.on_clear_decompressors,390bitmap=wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_MENU),391)392393menubar.append_item('plugins/prt/make merge nodes',394self.on_make_merges,395info='Make PRT merge nodes.',396# bitmap = self.get_icon('icon_sumo.png'),#,397)398399menubar.append_item('plugins/prt/clear merge nodes',400self.on_clear_merges,401bitmap=wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_MENU),402)403404menubar.append_item('plugins/prt/calculate stop to stop times',405self.on_make_times_stop_to_stop,406# bitmap = self.get_icon('icon_sumo.png'),#,407)408409menubar.append_item('plugins/prt/add vehicles...',410self.on_add_vehicles,411info='Add PRT vehicles to network.',412# bitmap = self.get_icon('icon_sumo.png'),#,413)414415menubar.append_item('plugins/prt/clear vehicles.',416self.on_clear_vehicles,417info='Clear all PRT vehicles from network.',418bitmap=wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_MENU),419)420421menubar.append_menu('plugins/prt/results',422bitmap=self.get_icon('icon_results_24px.png'), # ,423)424if is_mpl:425menubar.append_item('plugins/prt/results/stopresults with matplotlib',426self.on_mpl_stopresults,427bitmap=self.get_icon('icon_mpl.png'), # ,428)429430def on_make_stops(self, event=None):431self._prtservice.prtstops.make_from_net()432self._mainframe.browse_obj(self._prtservice.prtstops)433434def on_clear_stops(self, event=None):435"""Delete all stope"""436self._prtservice.prtstops.clear()437self._mainframe.browse_obj(self._prtservice.prtstops)438439def on_update_compressors(self, event=None):440"""Update all compressors (determine detector edge)"""441self._prtservice.compressors.update_all()442self._mainframe.browse_obj(self._prtservice.compressors)443444def on_clear_compressors(self, event=None):445"""Delete all compressors"""446self._prtservice.compressors.clear()447self._mainframe.browse_obj(self._prtservice.compressors)448449def on_update_decompressors(self, event=None):450"""Update all decompressors (determine detector edge)"""451self._prtservice.decompressors.update_all()452self._mainframe.browse_obj(self._prtservice.decompressors)453454def on_clear_decompressors(self, event=None):455"""Delete all decompressors"""456self._prtservice.decompressors.clear()457self._mainframe.browse_obj(self._prtservice.decompressors)458459def on_make_merges(self, event=None):460461self._prtservice.mergenodes.make_from_net()462self._mainframe.browse_obj(self._prtservice.mergenodes)463464def on_clear_merges(self, event=None):465"""Delete all merges"""466self._prtservice.mergenodes.clear()467self._mainframe.browse_obj(self._prtservice.mergenodes)468469def on_make_times_stop_to_stop(self, event=None):470"""Determine stop to sto time matrix"""471472self._prtservice.make_times_stop_to_stop()473self._mainframe.browse_obj(self._prtservice)474475def on_add_vehicles(self, event=None):476p = prt.VehicleAdder(self._prtservice.prtvehicles, logger=self._mainframe.get_logger())477dlg = ProcessDialog(self._mainframe, p, immediate_apply=True)478479dlg.CenterOnScreen()480481# this does not return until the dialog is closed.482val = dlg.ShowModal()483# print ' val,val == wx.ID_OK',val,wx.ID_OK,wx.ID_CANCEL,val == wx.ID_CANCEL484# print ' status =',dlg.get_status()485if dlg.get_status() != 'success': # val == wx.ID_CANCEL:486# print ">>>>>>>>>Unsuccessful\n"487dlg.Destroy()488489if dlg.get_status() == 'success':490# print ">>>>>>>>>successful\n"491# apply current widget values to scenario instance492dlg.apply()493dlg.Destroy()494self._mainframe.browse_obj(self._prtservice.prtvehicles)495496def on_clear_vehicles(self, event=None):497self._prtservice.prtvehicles.clear()498self._mainframe.browse_obj(self._prtservice.prtvehicles)499500def on_mpl_stopresults(self, event=None):501print 'on_mpl_stopresults', id(self._simulation.results) # ,id(self._prtservice.get_results())502if self._prtservice is not None:503if self._simulation is not None:504resultplotter = results_mpl.StopresultsPlotter(self._simulation.results, # self._prtservice.get_results(),505logger=self._mainframe.get_logger())506dlg = ResultDialog(self._mainframe, resultplotter)507508dlg.CenterOnScreen()509510# this does not return until the dialog is closed.511val = dlg.ShowModal()512if dlg.get_status() != 'success': # val == wx.ID_CANCEL:513dlg.Destroy()514515elif dlg.get_status() == 'success':516# apply current widget values to scenario instance517dlg.apply()518dlg.Destroy()519520521