1# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo 2# Copyright (C) 2016-2019 German Aerospace Center (DLR) and others. 3# SUMOPy module 4# Copyright (C) 2012-2017 University of Bologna - DICAM 5# This program and the accompanying materials 6# are made available under the terms of the Eclipse Public License v2.0 7# which accompanies this distribution, and is available at 8# http://www.eclipse.org/legal/epl-v20.html 9# SPDX-License-Identifier: EPL-2.0 10 11# @file wxgui.py 12# @author Joerg Schweizer 13# @date 14# @version $Id$ 15 16import os 17import wx 18import numpy as np 19 20from agilepy.lib_wx.modulegui import ModuleGui 21from agilepy.lib_wx.ogleditor import * 22from agilepy.lib_base.processes import Process 23from agilepy.lib_wx.processdialog import ProcessDialog, ProcessDialogInteractive 24 25from coremodules.network import routing 26from coremodules.demand import demand 27 28import mapmatching 29 30 31#import results_mpl as results_mpl 32try: 33 import results_mpl as results_mpl 34 is_mpl = True # we have matplotlib support 35except: 36 print "WARNING: python matplotlib package not installed, no matplotlib plots." 37 is_mpl = False 38 39 40class GpsPointsDrawings(Circles): 41 def __init__(self, ident, gpspoints, parent, **kwargs): 42 43 Circles.__init__(self, ident, parent, name='GPS points', 44 is_parentobj=False, 45 is_fill=True, # Fill objects, 46 is_outline=False, # show outlines 47 n_vert=11, # default number of vertex per circle 48 linewidth=3, 49 **kwargs) 50 51 self.delete('centers') 52 self.delete('radii') 53 54 self.add(cm.AttrConf('color_default', np.array([1.0, 0.8, 0.1, 0.5], np.float32), 55 groupnames=['options', 'colors'], 56 metatype='color', 57 perm='wr', 58 name='Default color', 59 info='Default point color.', 60 )) 61 62 self.set_netelement(gpspoints) 63 64 def get_netelement(self): 65 return self._gpspoints 66 67 def get_centers_array(self): 68 # return self._gpspoints.coords.value[self._inds_map] 69 return self._gpspoints.coords[self.get_ids()] 70 71 def get_radii_array(self): 72 return self._gpspoints.radii[self.get_ids()] 73 # return self._gpspoints.radii.value[self._inds_map] 74 75 def is_tool_allowed(self, tool, id_drawobj=-1): 76 """ 77 Returns True if this tool can be applied to this drawobj. 78 Optionally a particular drawobj can be specified with id_drawobj. 79 """ 80 # basic tools: 81 return tool.ident not in ['select_handles', 'delete', 'move', 'stretch'] # 'configure', 82 # return tool.ident not in ['delete','stretch'] 83 84 def set_netelement(self, gpspoints): 85 # print 'set_nodes' 86 self._gpspoints = gpspoints 87 # if len(self)>0: 88 # self.del_rows(self.get_ids()) 89 self.clear_rows() 90 91 ids = self._gpspoints.get_ids_selected() 92 n = len(ids) 93 94 #self._inds_map = self._gpspoints.get_inds(ids) 95 96 # print 'color_node_default',self.color_node_default.value 97 # print 'colors\n', np.ones((n,1),np.int32)*self.color_node_default.value 98 self.add_rows(ids=ids, 99 #colors = np.ones((n,1),np.int32)*self.color_default.value, 100 #colors_highl = self._get_colors_highl(np.ones((n,1),np.int32)*self.color_default.value), 101 colors_fill=np.ones((n, 1), np.int32)*self.color_default.value, 102 colors_highl_highl=self._get_colors_highl(np.ones((n, 1), np.int32)*self.color_default.value), 103 #centers = self._nodes.coords[ids], 104 #radii = self._nodes.radii[ids], 105 ) 106 107 self.update() 108 109 def update(self, is_update=True): 110 111 if is_update: 112 self._update_vertexvbo() 113 self._update_colorvbo() 114 115 116class GpsRoutesDrawings(Polylines): 117 def __init__(self, ident, edges, parent, **kwargs): 118 119 # joinstyle 120 # FLATHEAD = 0 121 # BEVELHEAD = 1 122 Polylines.__init__(self, ident, parent, name='GPS routes drawings', 123 is_lefthalf=True, 124 is_righthalf=True, 125 arrowstretch=1.5, 126 joinstyle=BEVELHEAD, # FLATHEAD,#BEVELHEAD is good for both halfs, 127 **kwargs) 128 129 # self.delete('vertices') 130 # self.delete('widths') 131 # self.delete('colors') 132 133 self.add(cm.AttrConf('width_default', 4.0, 134 groupnames=['options'], 135 perm='wr', 136 name='Default width', 137 info='Default route width of drawing.', 138 )) 139 140 self.add(cm.AttrConf('color_default', np.array([1.0, 0.4, 0.0, 0.6], np.float32), 141 groupnames=['options'], 142 perm='wr', 143 metatype='color', 144 name='Default color', 145 info='Default route color.', 146 )) 147 148 self.set_netelement(edges) 149 150 def get_netelement(self): 151 return self._routes 152 153 # def get_vertices_array(self): 154 # return self._routes.shapes[self.get_ids()]#.value[self._inds_map]#[self.get_ids()] 155 156 # def get_widths_array(self): 157 # # double because only the right half is shown 158 # # add a little bit to the width to make it a little wider than the lanes contained 159 # #return 2.2*self._edges.widths.value[self._inds_map] 160 # return 1.1*self._edges.widths[self.get_ids()]#.value[self._inds_map] 161 162 # def get_vertices(self, ids): 163 # return self._edges.shapes[ids] 164 165 # def set_vertices(self, ids, vertices, is_update = True): 166 # self._edges.set_shapes(ids, vertices) 167 # if is_update: 168 # self._update_vertexvbo() 169 # self.parent.get_drawobj_by_ident('lanedraws').update() 170 # self.parent.get_drawobj_by_ident('crossingsdraws').update() 171 # self.parent.get_drawobj_by_ident('connectiondraws').update() 172 173 # def get_widths(self, ids): 174 # return 1.1*self._edges.widths[ids] 175 176 # def set_widths(self, ids, values): 177 # #self._edges.widths[ids] = values/1.1 178 # pass 179 180 def is_tool_allowed(self, tool, id_drawobj=-1): 181 """ 182 Returns True if this tool can be applied to this drawobj. 183 Optionally a particular drawobj can be specified with id_drawobj. 184 """ 185 # basic tools: 186 return tool.ident not in ['configure', 'select_handles', 'delete', 'move', 'stretch'] 187 # return tool.ident not in ['delete',] 188 189 def set_netelement(self, routes): 190 191 self._routes = routes 192 #self._inds_edges = self._edges.get_inds() 193 self.clear_rows() 194 # if len(self)>0: 195 # self.del_rows(self.get_ids()) 196 197 ids = self._routes.parent.get_ids_route_selected() 198 #self._inds_map = self._edges.get_inds(ids) 199 n = len(ids) 200 #self.vertices = self._edges.shapes 201 #self.widths = self._edges.widths 202 # print '\n\nGpsRoutesDrawings.set_netelement',n 203 # print ' ids.dtype',ids.dtype 204 # print ' self._ids.dtype',self._ids.dtype 205 # print ' self._inds.dtype',self._inds.dtype 206 # print ' ids',ids 207 self.add_rows(ids=ids, 208 beginstyles=np.ones(n, dtype=np.float32)*FLATHEAD, 209 endstyles=np.ones(n, dtype=np.float32)*TRIANGLEHEAD, 210 widths=np.ones(n, dtype=np.float32)*self.width_default.get_value() 211 ) 212 self.vertices[ids] = self._routes.get_shapes(ids) 213 self.update() 214 215 def update(self, is_update=True): 216 """ 217 Update color, assume that there have not been structural changes of the arrays 218 """ 219 # assumes that edges have been set in set_edges 220 # print 'Edgedrawing.update' 221 #edgeinds = self._edges.get_inds() 222 n = len(self) 223 ids = self.get_ids() 224 225 self.colors_fill.value[:] = self._routes.colors[ids] 226 #self.colors_fill.value[:] = np.ones((n,1),np.float32)*self.color_default.value 227 self.colors_fill_highl.value[:] = self._get_colors_highl(self.colors_fill.value) 228 229 if is_update: 230 self._update_vertexvbo() 231 self._update_colorvbo() 232 233 234class WxGui(ModuleGui): 235 """Contains functions that communicate between the widgets of the main wx gui 236 and the functions of the plugin. 237 """ 238 239 def __init__(self, ident): 240 self._mapmatching = None 241 self._matchprocess = None 242 self._results = None 243 self._scenario = None 244 self._canvas = None 245 self._init_common(ident, priority=100001, 246 icondirpath=os.path.join(os.path.dirname(__file__), 'images')) 247 248 self._is_needs_refresh = False 249 250 def get_module(self): 251 return self._mapmatching 252 253 def get_scenario(self): 254 return self._mainframe.get_modulegui('coremodules.scenario').get_scenario() 255 256 def get_neteditor(self): 257 return self._mainframe.get_modulegui('coremodules.network').get_neteditor() 258 259 def get_canvas(self): 260 return self.get_neteditor().get_canvas() 261 262 def get_drawing(self): 263 return self.get_canvas().get_drawing() 264 265 def init_widgets(self, mainframe): 266 """ 267 Set mainframe and initialize widgets to various places. 268 """ 269 self._mainframe = mainframe 270 #self._neteditor = mainframe.add_view("Network", Neteditor) 271 272 # mainframe.browse_obj(self._module) 273 self.make_menu() 274 self.make_toolbar() 275 276 def refresh_widgets(self): 277 """ 278 Check through mainframe what the state of the application is 279 and reset widgets. For exampe enable/disable widgets 280 dependent on the availability of data. 281 """ 282 print 'MapmatchingWxGui.refresh_widgets' 283 scenario = self.get_scenario() 284 is_refresh = False 285 if self._scenario != scenario: 286 del self._scenario 287 del self._mapmatching 288 del self._results 289 self._scenario = scenario 290 self._mapmatching = scenario.demand.add_demandobject( 291 ident='mapmatching', DemandClass=mapmatching.Mapmatching) 292 #self._mapmatching = mapmatching.Mapmatching('mapmatching', scenario) 293 self._matchprocess = None 294 self._results = mapmatching.Matchresults('matchresults', 295 self._mapmatching, 296 ) 297 is_refresh = True 298 299 if is_refresh | self._is_needs_refresh: 300 self._is_needs_refresh = False 301 print ' is_refresh', is_refresh, self._is_needs_refresh 302 neteditor = self.get_neteditor() 303 #canvas = self.get_canvas() 304 drawing = self.get_drawing() # canvas.get_drawing() 305 306 # add or refresh facility drawing 307 drawing.set_element('gpspointsdraws', GpsPointsDrawings, 308 self._mapmatching.points, layer=150) 309 310 drawing.set_element('gpsroutesdraws', GpsRoutesDrawings, 311 self._mapmatching.trips.get_routes(), layer=149) 312 313 # neteditor.get_toolbox().add_toolclass(AddZoneTool)# will check if tool is already there 314 # neteditor.get_toolbox().add_toolclass(AddFacilityTool) 315 neteditor.draw() 316 317 self._canvas = self.get_canvas() 318 319 def make_menu(self): 320 menubar = self._mainframe.menubar 321 menubar.append_menu('plugins/mapmatching', 322 bitmap=self.get_icon("icon_gps.png"), 323 ) 324 menubar.append_item('plugins/mapmatching/browse', 325 self.on_browse, # common function in modulegui 326 info='View and browse mapmatching in object panel.', 327 bitmap=self.get_agileicon('icon_browse_24px.png'), # , 328 ) 329 330 # menubar.append_item( 'plugins/mapmatching/open...', 331 # self.on_open, 332 # bitmap = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN,wx.ART_MENU), 333 # ) 334 335 menubar.append_menu('plugins/mapmatching/import', 336 bitmap=self.get_agileicon("Document_Import_24px.png"), 337 ) 338 339 menubar.append_item('plugins/mapmatching/import/European cycling challange...', 340 self.on_import_ecc, 341 # info=self.on_import_ecc.__doc__.strip(), 342 bitmap=self.get_agileicon("Document_Import_24px.png"), 343 ) 344 345 menubar.append_item('plugins/mapmatching/import/GPX file...', 346 self.on_import_gpx, 347 # info=self.on_import_ecc.__doc__.strip(), 348 bitmap=self.get_agileicon("Document_Import_24px.png"), 349 ) 350 351 # menubar.append_item( 'plugins/mapmatching/project points', 352 # self.on_project_points, 353 # #bitmap = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS,wx.ART_MENU), 354 # ) 355 356 menubar.append_item('plugins/mapmatching/match with birgillito method...', 357 self.on_match_birgil, 358 #bitmap = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS,wx.ART_MENU), 359 ) 360 361 menubar.append_item('plugins/mapmatching/shortest path routing...', 362 self.on_route_shortest, 363 #bitmap = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS,wx.ART_MENU), 364 ) 365 366 menubar.append_item('plugins/mapmatching/fastest path routing...', 367 self.on_route_fastest, 368 #bitmap = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS,wx.ART_MENU), 369 ) 370 371 372# ------------------------------------------------------------------------------- 373 374 menubar.append_menu('plugins/mapmatching/person analysis', 375 bitmap=self.get_icon('icon_results_24px.png'), # , 376 info='Person analysis tools' 377 ) 378 379 menubar.append_item('plugins/mapmatching/person analysis/analyze', 380 self.on_analyze_persons, 381 #bitmap = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS,wx.ART_MENU), 382 ) 383 384 menubar.append_item('plugins/mapmatching/person analysis/save matched in csv...', 385 self.on_export_persons_csv, 386 info='Save persons with matched trips in a CSV file.', 387 bitmap=self.get_agileicon("Document_Export_24px.png"), 388 ) 389 390# ------------------------------------------------------------------------------- 391 392 menubar.append_menu('plugins/mapmatching/route analysis', 393 bitmap=self.get_icon('icon_results_24px.png'), # , 394 info='Route analysis tools' 395 ) 396 397 menubar.append_item('plugins/mapmatching/route analysis/browse', 398 self.on_browse_results, # common function in modulegui 399 bitmap=self.get_agileicon('icon_browse_24px.png'), # , 400 ) 401 402 menubar.append_item('plugins/mapmatching/route analysis/analyze...', 403 self.on_routeanalyze, # common function in modulegui 404 # bitmap = self.get_agileicon('icon_browse_24px.png'),#, 405 ) 406 407 if is_mpl: 408 menubar.append_item('plugins/mapmatching/route analysis/plot route results...', 409 self.on_plot_routeresults, 410 bitmap=results_mpl.get_mplicon(), # , 411 ) 412 menubar.append_item('plugins/mapmatching/route analysis/plot edge results...', 413 self.on_plot_edgeresults, 414 bitmap=results_mpl.get_mplicon(), # , 415 ) 416 menubar.append_item('plugins/mapmatching/route analysis/plot speed profiles...', 417 self.on_plot_speedprofiles, 418 bitmap=results_mpl.get_mplicon(), # , 419 ) 420 menubar.append_item('plugins/mapmatching/route analysis/plot node results...', 421 self.on_plot_noderesults, 422 bitmap=results_mpl.get_mplicon(), # , 423 ) 424 425 menubar.append_item('plugins/mapmatching/route analysis/safe as...', 426 self.on_save_results, 427 bitmap=wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS, wx.ART_MENU), 428 ) 429 430 menubar.append_item('plugins/mapmatching/route analysis/open...', 431 self.on_open_results, 432 bitmap=wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_MENU), 433 ) 434 435 menubar.append_item('plugins/mapmatching/route analysis/route results to shape...', 436 self.on_routes_to_shapefile, 437 bitmap=wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS, wx.ART_MENU), 438 ) 439 440 menubar.append_item('plugins/mapmatching/route analysis/edge results to shape...', 441 self.on_edgesresults_to_shapefile, 442 bitmap=wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS, wx.ART_MENU), 443 ) 444 445 menubar.append_item('plugins/mapmatching/route analysis/GPS points to shape...', 446 self.on_points_to_shapefile, 447 bitmap=wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS, wx.ART_MENU), 448 ) 449 450# ------------------------------------------------------------------------------- 451 452 menubar.append_menu('plugins/mapmatching/filter and select', 453 # bitmap = self.get_icon('icon_results_24px.png'),#, 454 info='Filter and select GPS trips.' 455 ) 456 457 menubar.append_item('plugins/mapmatching/filter and select/select traces by geometry...', 458 self.on_geomfilter_trips, 459 #bitmap = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS,wx.ART_MENU), 460 ) 461 462 menubar.append_item('plugins/mapmatching/filter and select/filter trips...', 463 self.on_postmatchfilter_trips, 464 #bitmap = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS,wx.ART_MENU), 465 ) 466 467 menubar.append_item('plugins/mapmatching/filter and select/select all trips', 468 self.on_select_all_trips, 469 ) 470 471 menubar.append_item('plugins/mapmatching/filter and select/unselect all trips', 472 self.on_unselect_all_trips, 473 ) 474 475 menubar.append_item('plugins/mapmatching/filter and select/invert selected trips', 476 self.on_invert_selected_trips, 477 ) 478# ------------------------------------------------------------------------------- 479 480 menubar.append_menu('plugins/mapmatching/delete', 481 bitmap=wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_MENU), 482 info='Delete tools.' 483 ) 484 485 menubar.append_item('plugins/mapmatching/delete/delete unselected trips', 486 self.on_delete_unselected, 487 bitmap=wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_MENU), 488 ) 489 490 menubar.append_item('plugins/mapmatching/delete/delete routes', 491 self.on_clear_routes, 492 bitmap=wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_MENU), 493 ) 494 495 menubar.append_item('plugins/mapmatching/delete/delete all', 496 self.on_clear_all, 497 bitmap=wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_MENU), 498 ) 499 500# ------------------------------------------------------------------------------- 501 502 menubar.append_item('plugins/mapmatching/redraw GPS data', 503 self.on_redraw, 504 ) 505 506 def on_plot_routeresults(self, event=None): 507 """ 508 Plot route results of route analysis in Matplotlib plotting envitonment. 509 """ 510 if is_mpl: 511 resultplotter = results_mpl.RouteresultPlotter(self._results, 512 logger=self._mainframe.get_logger() 513 ) 514 dlg = results_mpl.ResultDialog(self._mainframe, resultplotter) 515 516 dlg.CenterOnScreen() 517 518 # this does not return until the dialog is closed. 519 val = dlg.ShowModal() 520 # print ' val,val == wx.ID_OK',val,wx.ID_OK,wx.ID_CANCEL,val == wx.ID_CANCEL 521 # print ' status =',dlg.get_status() 522 if dlg.get_status() != 'success': # val == wx.ID_CANCEL: 523 # print ">>>>>>>>>Unsuccessful\n" 524 dlg.Destroy() 525 526 if dlg.get_status() == 'success': 527 # print ">>>>>>>>>successful\n" 528 # apply current widget values to scenario instance 529 dlg.apply() 530 dlg.Destroy() 531 532 def on_plot_edgeresults(self, event=None): 533 """ 534 Plot edge results of route analysis in Matplotlib plotting envitonment. 535 """ 536 if is_mpl: 537 resultplotter = results_mpl.EdgeresultPlotter(self._results, 538 logger=self._mainframe.get_logger() 539 ) 540 dlg = results_mpl.ResultDialog(self._mainframe, resultplotter) 541 542 dlg.CenterOnScreen() 543 544 # this does not return until the dialog is closed. 545 val = dlg.ShowModal() 546 # print ' val,val == wx.ID_OK',val,wx.ID_OK,wx.ID_CANCEL,val == wx.ID_CANCEL 547 # print ' status =',dlg.get_status() 548 if dlg.get_status() != 'success': # val == wx.ID_CANCEL: 549 # print ">>>>>>>>>Unsuccessful\n" 550 dlg.Destroy() 551 552 if dlg.get_status() == 'success': 553 # print ">>>>>>>>>successful\n" 554 # apply current widget values to scenario instance 555 dlg.apply() 556 dlg.Destroy() 557 558 def on_plot_noderesults(self, event=None): 559 """ 560 Plot node results of route analysis in Matplotlib plotting envitonment. 561 """ 562 if is_mpl: 563 resultplotter = results_mpl.NoderesultPlotter(self._results, 564 logger=self._mainframe.get_logger() 565 ) 566 dlg = results_mpl.ResultDialog(self._mainframe, resultplotter) 567 568 dlg.CenterOnScreen() 569 570 # this does not return until the dialog is closed. 571 val = dlg.ShowModal() 572 # print ' val,val == wx.ID_OK',val,wx.ID_OK,wx.ID_CANCEL,val == wx.ID_CANCEL 573 # print ' status =',dlg.get_status() 574 if dlg.get_status() != 'success': # val == wx.ID_CANCEL: 575 # print ">>>>>>>>>Unsuccessful\n" 576 dlg.Destroy() 577 578 if dlg.get_status() == 'success': 579 # print ">>>>>>>>>successful\n" 580 # apply current widget values to scenario instance 581 dlg.apply() 582 dlg.Destroy() 583 584 def on_plot_speedprofiles(self, event=None): 585 """ 586 Plot speedprofiles of route analysis in Matplotlib plotting envitonment. 587 """ 588 if is_mpl: 589 resultplotter = results_mpl.SpeedprofilePlotter(self._results, 590 logger=self._mainframe.get_logger() 591 ) 592 dlg = results_mpl.ResultDialog(self._mainframe, resultplotter) 593 594 dlg.CenterOnScreen() 595 596 # this does not return until the dialog is closed. 597 val = dlg.ShowModal() 598 # print ' val,val == wx.ID_OK',val,wx.ID_OK,wx.ID_CANCEL,val == wx.ID_CANCEL 599 # print ' status =',dlg.get_status() 600 if dlg.get_status() != 'success': # val == wx.ID_CANCEL: 601 # print ">>>>>>>>>Unsuccessful\n" 602 dlg.Destroy() 603 604 if dlg.get_status() == 'success': 605 # print ">>>>>>>>>successful\n" 606 # apply current widget values to scenario instance 607 dlg.apply() 608 dlg.Destroy() 609 610 def on_routes_to_shapefile(self, event=None): 611 """ 612 Export route results to shape file. 613 """ 614 # print 'on_routes_to_shapefile' 615 scenario = self._mapmatching.get_scenario() 616 dirpath = scenario.get_workdirpath() 617 defaultFile = scenario.get_rootfilename()+'.routeres.shp' 618 wildcards_all = 'All files (*.*)|*.*|SHP files (*.shp)|*.shp' 619 dlg = wx.FileDialog(None, message='Export route results to shapefile', 620 defaultDir=dirpath, defaultFile=defaultFile, 621 wildcard=wildcards_all, style=wx.SAVE | wx.CHANGE_DIR) 622 if dlg.ShowModal() == wx.ID_OK: 623 filepath = dlg.GetPath() 624 625 else: 626 return 627 628 mapmatching.routes_to_shapefile(self._mapmatching, 629 self._results, 630 filepath, 631 log=self._mainframe.get_logger()) 632 633 def on_edgesresults_to_shapefile(self, event=None): 634 """ 635 Export edge results to shape file. 636 """ 637 print 'on_nodes_to_shapefile' 638 scenario = self._mapmatching.get_scenario() 639 dirpath = scenario.get_workdirpath() 640 defaultFile = scenario.get_rootfilename()+'.edgeres.shp' 641 wildcards_all = 'All files (*.*)|*.*|SHP files (*.shp)|*.shp' 642 dlg = wx.FileDialog(None, message='Export edge results to shapefile', 643 defaultDir=dirpath, defaultFile=defaultFile, 644 wildcard=wildcards_all, style=wx.SAVE | wx.CHANGE_DIR) 645 if dlg.ShowModal() == wx.ID_OK: 646 filepath = dlg.GetPath() 647 648 else: 649 return 650 651 mapmatching.edgesresults_to_shapefile(self._mapmatching, 652 self._results, 653 filepath, 654 log=self._mainframe.get_logger()) 655 656 def on_points_to_shapefile(self, event=None): 657 """ 658 Export GPS points to shapefile. 659 """ 660 print 'on_points_to_shapefile' 661 scenario = self._mapmatching.get_scenario() 662 dirpath = scenario.get_workdirpath() 663 defaultFile = scenario.get_rootfilename()+'.points.shp' 664 wildcards_all = 'All files (*.*)|*.*|SHP files (*.shp)|*.shp' 665 dlg = wx.FileDialog(None, message='Export GPS points to shapefile', 666 defaultDir=dirpath, defaultFile=defaultFile, 667 wildcard=wildcards_all, style=wx.SAVE | wx.CHANGE_DIR) 668 if dlg.ShowModal() == wx.ID_OK: 669 filepath = dlg.GetPath() 670 671 else: 672 return 673 674 mapmatching.points_to_shapefile(self._mapmatching, 675 filepath, 676 log=self._mainframe.get_logger()) 677 678 def on_save_results(self, event=None): 679 """ 680 Save mapmatching analysis results to binary file. 681 """ 682 if self._results is None: 683 return 684 scenario = self.get_scenario() 685 wildcards_all = "All files (*.*)|*.*" 686 wildcards_obj = "Python binary mapmatch files (*.mmatch.obj)|*.mmatch.obj|Python binary files (*.obj)|*.obj" 687 wildcards = wildcards_obj+"|"+wildcards_all 688 689 # Finally, if the directory is changed in the process of getting files, this 690 # dialog is set up to change the current working directory to the path chosen. 691 dlg = wx.FileDialog( 692 self._mainframe, message="Save results to file", 693 defaultDir=scenario.get_workdirpath(), 694 defaultFile=scenario.get_rootfilepath()+'.mmatch.obj', 695 wildcard=wildcards, 696 style=wx.SAVE | wx.CHANGE_DIR 697 ) 698 val = dlg.ShowModal() 699 # Show the dialog and retrieve the user response. If it is the OK response, 700 # process the data. 701 if val == wx.ID_OK: 702 # This returns a Python list of files that were selected. 703 filepath = dlg.GetPath() 704 if len(filepath) > 0: 705 # now set new filename and workdir 706 self._results.save(filepath) 707 708 # Destroy the dialog. Don't do this until you are done with it! 709 # BAD things can happen otherwise! 710 dlg.Destroy() 711 712 def on_open_results(self, event=None): 713 714 wildcards_all = "All files (*.*)|*.*" 715 wildcards_obj = "Python binary mapmatch files (*.mmatch.obj)|*.mmatch.obj|Python binary files (*.obj)|*.obj" 716 wildcards = wildcards_obj+"|"+wildcards_all 717 718 # Finally, if the directory is changed in the process of getting files, this 719 # dialog is set up to change the current working directory to the path chosen. 720 dlg = wx.FileDialog( 721 self._mainframe, message="Open results file", 722 defaultDir=self.get_scenario().get_workdirpath(), 723 #defaultFile = os.path.join(scenario.get_workdirpath(), scenario.format_ident()+'.obj'), 724 wildcard=wildcards, 725 style=wx.OPEN | wx.CHANGE_DIR 726 ) 727 728 # Show the dialog and retrieve the user response. If it is the OK response, 729 # process the data. 730 is_newresults = False 731 if dlg.ShowModal() == wx.ID_OK: 732 # This returns a Python list of files that were selected. 733 filepath = dlg.GetPath() 734 if len(filepath) > 0: 735 if self._results is not None: 736 # browse away from results 737 # self._mainframe.browse_obj(self._results.get_scenario()) 738 del self._results 739 740 self._results = mapmatching.load_results(filepath, 741 parent=self._mapmatching, 742 logger=self._mainframe.get_logger() 743 ) 744 is_newresults = True 745 746 # Destroy the dialog. Don't do this until you are done with it! 747 # BAD things can happen otherwise! 748 dlg.Destroy() 749 750 if is_newresults: 751 # this should update all widgets for the new scenario!! 752 # print 'call self._mainframe.refresh_moduleguis()' 753 self._mainframe.browse_obj(self._results) 754 # self._mainframe.select_view(name = "Result viewer") #!!!!!!!!tricky, crashes without 755 self._is_needs_refresh = True 756 self.refresh_widgets() 757 # wx.CallAfter(self.refresh_widgets) 758 # self._mainframe.refresh_moduleguis() 759 #if event: event.Skip() 760 761 def on_select_all_trips(self, event=None): 762 """ 763 Select all GPS trips. 764 """ 765 self._mapmatching.trips.select_all() 766 self._mainframe.browse_obj(self._mapmatching.trips) 767 self._is_needs_refresh = True 768 self.refresh_widgets() 769 770 def on_unselect_all_trips(self, event=None): 771 """ 772 Unselect all GPS trips. 773 """ 774 self._mapmatching.trips.unselect_all() 775 self._mainframe.browse_obj(self._mapmatching.trips) 776 self._is_needs_refresh = True 777 self.refresh_widgets() 778 779 def on_invert_selected_trips(self, event=None): 780 """ 781 Invert selected GPS trips, all selected will be unselected and vice versa. 782 """ 783 self._mapmatching.trips.invert_selection() 784 self._mainframe.browse_obj(self._mapmatching.trips) 785 self._is_needs_refresh = True 786 self.refresh_widgets() 787 788 def on_clear_all(self, event=None): 789 """ 790 Clear all GPS points, routes and persons. 791 """ 792 self._mapmatching.clear_all() 793 self._mainframe.browse_obj(self._mapmatching) 794 self._is_needs_refresh = True 795 self.refresh_widgets() 796 797 def on_clear_routes(self, event=None): 798 """ 799 Clear matched routes and minimal distance routes. 800 """ 801 self._mapmatching.clear_routes() 802 self._mainframe.browse_obj(self._mapmatching) 803 self._is_needs_refresh = True 804 self.refresh_widgets() 805 806 def on_delete_unselected(self, event=None): 807 """ 808 Delete unselected trips. 809 """ 810 self._mapmatching.delete_unselected_trips() 811 self._mainframe.browse_obj(self._mapmatching.trips) 812 #self._is_needs_refresh = True 813 # self.refresh_widgets() 814 815 def is_matchprocess(self, ident): 816 if self._matchprocess is None: 817 return False 818 else: 819 return self._matchprocess.ident == ident 820 821 def on_match_birgil(self, event=None): 822 """ 823 Match selected traces with Birgillito's method. 824 """ 825 # self.prepare_results() 826 if not self.is_matchprocess('birgilmatcher'): 827 self._matchprocess = mapmatching.BirgilMatcher('birgilmatcher', 828 self._mapmatching, 829 logger=self._mainframe.get_logger(), 830 ) 831 832 dlg = ProcessDialogInteractive(self._mainframe, 833 self._matchprocess, 834 #title = 'Mapmatching with Birgillito method', 835 func_close=self.close_match_birgil, 836 ) 837 838 dlg.CenterOnScreen() 839 840 # this does not return until the dialog is closed. 841 #val = dlg.ShowModal() 842 # print 'open_sumodialog_interactive' 843 dlg.Show() 844 dlg.MakeModal(True) 845 # print ' val,val == wx.ID_OK',val,wx.ID_OK,wx.ID_CANCEL,val == wx.ID_CANCEL 846 # print ' status =',dlg.get_status() 847 # print 'returned to main window self.simulator.status',self.simulator.status 848 849 def close_match_birgil(self, dlg): 850 # called before destroying the dialog 851 if dlg.get_status() == 'success': 852 #p = self._mapmatchprocess 853 854 self._mainframe.browse_obj(self._mapmatching.trips) 855 self._is_needs_refresh = True 856 self.refresh_widgets() 857 858 def on_geomfilter_trips(self, event=None): 859 """ 860 Select GPS traces to satisfy geometric requirements. 861 This should be done before the mapmatching process. 862 """ 863 p = mapmatching.TripGeomfilter(self._mapmatching, logger=self._mainframe.get_logger()) 864 dlg = ProcessDialog(self._mainframe, p, immediate_apply=True) 865 866 dlg.CenterOnScreen() 867 868 # this does not return until the dialog is closed. 869 val = dlg.ShowModal() 870 # print ' val,val == wx.ID_OK',val,wx.ID_OK,wx.ID_CANCEL,val == wx.ID_CANCEL 871 # print ' status =',dlg.get_status() 872 if dlg.get_status() != 'success': # val == wx.ID_CANCEL: 873 # print ">>>>>>>>>Unsuccessful\n" 874 dlg.Destroy() 875 876 if dlg.get_status() == 'success': 877 # print ">>>>>>>>>successful\n" 878 # apply current widget values to scenario instance 879 dlg.apply() 880 dlg.Destroy() 881 self._mainframe.browse_obj(self._mapmatching.trips) 882 self._is_needs_refresh = True 883 self.refresh_widgets() 884 885 def on_postmatchfilter_trips(self, event=None): 886 """ 887 Select trips by different parameters to ensure the quality of the mapmatching results. 888 This should be done after the map-matching process. 889 """ 890 p = mapmatching.PostMatchfilter(self._mapmatching, logger=self._mainframe.get_logger()) 891 dlg = ProcessDialog(self._mainframe, p, immediate_apply=True) 892 893 dlg.CenterOnScreen() 894 895 # this does not return until the dialog is closed. 896 val = dlg.ShowModal() 897 # print ' val,val == wx.ID_OK',val,wx.ID_OK,wx.ID_CANCEL,val == wx.ID_CANCEL 898 # print ' status =',dlg.get_status() 899 if dlg.get_status() != 'success': # val == wx.ID_CANCEL: 900 # print ">>>>>>>>>Unsuccessful\n" 901 dlg.Destroy() 902 903 if dlg.get_status() == 'success': 904 # print ">>>>>>>>>successful\n" 905 # apply current widget values to scenario instance 906 dlg.apply() 907 dlg.Destroy() 908 self._mainframe.browse_obj(self._mapmatching.trips) 909 self._is_needs_refresh = True 910 self.refresh_widgets() 911 912 def on_route_shortest(self, event=None): 913 """ 914 Shortest path routing of matched routes. 915 """ 916 p = mapmatching.Shortestrouter('shortestpathrouter', self._mapmatching, logger=self._mainframe.get_logger()) 917 dlg = ProcessDialog(self._mainframe, p, immediate_apply=True) 918 919 dlg.CenterOnScreen() 920 921 # this does not return until the dialog is closed. 922 val = dlg.ShowModal() 923 # print ' val,val == wx.ID_OK',val,wx.ID_OK,wx.ID_CANCEL,val == wx.ID_CANCEL 924 # print ' status =',dlg.get_status() 925 if dlg.get_status() != 'success': # val == wx.ID_CANCEL: 926 # print ">>>>>>>>>Unsuccessful\n" 927 dlg.Destroy() 928 929 if dlg.get_status() == 'success': 930 # print ">>>>>>>>>successful\n" 931 # apply current widget values to scenario instance 932 dlg.apply() 933 dlg.Destroy() 934 self._mainframe.browse_obj(self._mapmatching.trips) 935 self._is_needs_refresh = True 936 self.refresh_widgets() 937 938 def on_route_fastest(self, event=None): 939 """ 940 Fastest path routing of matched routes. 941 """ 942 p = mapmatching.Fastestrouter('fastestpathrouter', self._mapmatching, 943 matchresults=self._results, 944 logger=self._mainframe.get_logger() 945 ) 946 dlg = ProcessDialog(self._mainframe, p, immediate_apply=True) 947 948 dlg.CenterOnScreen() 949 950 # this does not return until the dialog is closed. 951 val = dlg.ShowModal() 952 # print ' val,val == wx.ID_OK',val,wx.ID_OK,wx.ID_CANCEL,val == wx.ID_CANCEL 953 # print ' status =',dlg.get_status() 954 if dlg.get_status() != 'success': # val == wx.ID_CANCEL: 955 # print ">>>>>>>>>Unsuccessful\n" 956 dlg.Destroy() 957 958 if dlg.get_status() == 'success': 959 # print ">>>>>>>>>successful\n" 960 # apply current widget values to scenario instance 961 dlg.apply() 962 dlg.Destroy() 963 self._mainframe.browse_obj(self._mapmatching.trips) 964 self._is_needs_refresh = True 965 self.refresh_widgets() 966 967 def on_redraw(self, event=None): 968 self._mainframe.browse_obj(self._mapmatching) 969 self._is_needs_refresh = True 970 self.refresh_widgets() 971 972 def on_import_ecc(self, event=None): 973 """ 974 Import and filter data from a European cycling challange. 975 """ 976 p = mapmatching.EccTracesImporter(self._mapmatching, logger=self._mainframe.get_logger()) 977 dlg = ProcessDialog(self._mainframe, p, immediate_apply=True) 978 979 dlg.CenterOnScreen() 980 981 # this does not return until the dialog is closed. 982 val = dlg.ShowModal() 983 # print ' val,val == wx.ID_OK',val,wx.ID_OK,wx.ID_CANCEL,val == wx.ID_CANCEL 984 # print ' status =',dlg.get_status() 985 if dlg.get_status() != 'success': # val == wx.ID_CANCEL: 986 # print ">>>>>>>>>Unsuccessful\n" 987 dlg.Destroy() 988 989 if dlg.get_status() == 'success': 990 # print ">>>>>>>>>successful\n" 991 # apply current widget values to scenario instance 992 dlg.apply() 993 dlg.Destroy() 994 self._mainframe.browse_obj(self._mapmatching.trips) 995 self._is_needs_refresh = True 996 self.refresh_widgets() 997 998 def on_import_gpx(self, event=None): 999 """ 1000 Import and filter data from GPX file. 1001 """ 1002 p = mapmatching.GpxImporter(self._mapmatching, logger=self._mainframe.get_logger()) 1003 dlg = ProcessDialog(self._mainframe, p, immediate_apply=True) 1004 1005 dlg.CenterOnScreen() 1006 1007 # this does not return until the dialog is closed. 1008 val = dlg.ShowModal() 1009 # print ' val,val == wx.ID_OK',val,wx.ID_OK,wx.ID_CANCEL,val == wx.ID_CANCEL 1010 # print ' status =',dlg.get_status() 1011 if dlg.get_status() != 'success': # val == wx.ID_CANCEL: 1012 # print ">>>>>>>>>Unsuccessful\n" 1013 dlg.Destroy() 1014 1015 if dlg.get_status() == 'success': 1016 # print ">>>>>>>>>successful\n" 1017 # apply current widget values to scenario instance 1018 dlg.apply() 1019 dlg.Destroy() 1020 self._mainframe.browse_obj(self._mapmatching.trips) 1021 self._is_needs_refresh = True 1022 self.refresh_widgets() 1023 1024 def on_project_points(self, event=None): 1025 self._mapmatching.points.project() 1026 self._mainframe.browse_obj(self._mapmatching.points) 1027 1028 if event: 1029 event.Skip() 1030 1031 def on_browse(self, event=None): 1032 1033 self._mainframe.browse_obj(self._mapmatching) 1034 if event: 1035 event.Skip() 1036 1037 def on_browse_results(self, event=None): 1038 """ 1039 Browse mapmatching analyses results 1040 """ 1041 self._mainframe.browse_obj(self._results) 1042 if event: 1043 event.Skip() 1044 1045 def on_analyze_persons(self, event=None): 1046 """ 1047 Analyze the trips of each person in the database. 1048 Ensure that mapmatching and shortest trip routing 1049 has been previously executed. 1050 """ 1051 1052 self._mapmatching.persons.analyze() 1053 self._mainframe.browse_obj(self._mapmatching.persons) 1054 1055 def on_export_persons_csv(self, event=None): 1056 if self._results is None: 1057 return 1058 scenario = self._results.get_scenario() 1059 wildcards_all = "All files (*.*)|*.*" 1060 wildcards_obj = "CSV files (*.csv)|*.csv|Text file (*.txt)|*.txt" 1061 wildcards = wildcards_obj+"|"+wildcards_all 1062 1063 # Finally, if the directory is changed in the process of getting files, this 1064 # dialog is set up to change the current working directory to the path chosen. 1065 dlg = wx.FileDialog( 1066 self._mainframe, message="Export persons to CSV file", 1067 defaultDir=scenario.get_workdirpath(), 1068 defaultFile=scenario.get_rootfilepath()+'.gpspersons.csv', 1069 wildcard=wildcards, 1070 style=wx.SAVE | wx.CHANGE_DIR 1071 ) 1072 val = dlg.ShowModal() 1073 # Show the dialog and retrieve the user response. If it is the OK response, 1074 # process the data. 1075 if val == wx.ID_OK: 1076 # This returns a Python list of files that were selected. 1077 filepath = dlg.GetPath() 1078 if len(filepath) > 0: 1079 # now set new filename and workdir 1080 persons = self._mapmatching.persons 1081 ids_pers = persons.select_ids(persons.lengths_tot_route_matched.get_value() > 0) 1082 self._mapmatching.persons.export_csv(filepath, ids=ids_pers) 1083 1084 # Destroy the dialog. Don't do this until you are done with it! 1085 # BAD things can happen otherwise! 1086 dlg.Destroy() 1087 1088 def on_routeanalyze(self, event=None): 1089 """ 1090 Analyze attributes of matched and alternative routes. 1091 """ 1092 p = mapmatching.Routesanalyzer('routeanalyzer', 1093 self._mapmatching, 1094 self._results, 1095 logger=self._mainframe.get_logger()) 1096 1097 dlg = ProcessDialog(self._mainframe, p, immediate_apply=True) 1098 1099 dlg.CenterOnScreen() 1100 1101 # this does not return until the dialog is closed. 1102 val = dlg.ShowModal() 1103 # print ' val,val == wx.ID_OK',val,wx.ID_OK,wx.ID_CANCEL,val == wx.ID_CANCEL 1104 # print ' status =',dlg.get_status() 1105 if dlg.get_status() != 'success': # val == wx.ID_CANCEL: 1106 # print ">>>>>>>>>Unsuccessful\n" 1107 dlg.Destroy() 1108 1109 if dlg.get_status() == 'success': 1110 # print ">>>>>>>>>successful\n" 1111 # apply current widget values to scenario instance 1112 dlg.apply() 1113 dlg.Destroy() 1114 self._mainframe.browse_obj(self._results) 1115 self._is_needs_refresh = True 1116 self.refresh_widgets() 1117