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 network.py 12# @author Joerg Schweizer 13# @date 14# @version $Id$ 15 16# size limit at 1280x1280 17# http://maps.googleapis.com/maps/api/staticmap?size=500x500&path=color:0x000000|weight:10|44.35789,11.3093|44.4378,11.3935&format=GIF&maptype=satellite&scale=2 18 19import os 20import sys 21import subprocess 22import platform 23 24from xml.sax import saxutils, parse, handler 25if __name__ == '__main__': 26 try: 27 APPDIR = os.path.dirname(os.path.abspath(__file__)) 28 except: 29 APPDIR = os.path.dirname(os.path.abspath(sys.argv[0])) 30 SUMOPYDIR = os.path.join(APPDIR, '..', '..') 31 sys.path.append(os.path.join(SUMOPYDIR)) 32 33import time 34import numpy as np 35from collections import OrderedDict 36import agilepy.lib_base.classman as cm 37import agilepy.lib_base.arrayman as am 38import agilepy.lib_base.xmlman as xm 39from agilepy.lib_base.misc import filepathlist_to_filepathstring, filepathstring_to_filepathlist 40 41from agilepy.lib_base.processes import Process, CmlMixin, P 42 43from agilepy.lib_base.geometry import * 44 45import netconvert 46import publictransportnet as pt 47 48 49MODES = OrderedDict([ 50 ("ignoring", 0), 51 ("pedestrian", 1), 52 ("bicycle", 2), 53 ("motorcycle", 3), 54 ("passenger", 4), 55 ("bus", 5), 56 ("tram", 6), 57 ("rail_urban", 7), 58 ("delivery", 8), 59 ("private", 9), 60 ("taxi", 10), 61 ("hov", 11), 62 ("evehicle", 12), 63 ("emergency", 13), 64 ("authority", 14), 65 ("army", 15), 66 ("vip", 16), 67 ("coach", 17), 68 ("truck", 18), 69 ("trailer", 19), 70 ("rail", 20), 71 ("rail_electric", 21), 72 ("moped", 22), 73 ("custom1", 23), 74 ("custom2", 24), 75 ("ship", 25), 76 ]) 77 78ID_MODE_PED = MODES['pedestrian'] 79ID_MODE_BIKE = MODES['bicycle'] 80ID_MODE_CAR = MODES['passenger'] 81 82OSMEDGETYPE_TO_MODES = {'highway.cycleway': ([MODES['bicycle']], 5.6), 83 'highway.pedestrian': ([MODES['pedestrian']], 0.8), 84 'highway.footway': ([MODES['pedestrian']], 0.8), 85 'highway.path': ([MODES['pedestrian'], MODES['bicycle']], 5.6), 86 'highway.service': ([MODES['delivery'], MODES['bicycle']], 13.8), 87 } 88 89 90class SumoIdsConf(am.ArrayConf): 91 """ 92 Sumo id array coniguration 93 """ 94 # def __init__(self, **attrs): 95 # print 'ColConf',attrs 96 97 def __init__(self, refname, name=None, info=None, perm='rw', xmltag='id'): 98 if name is None: 99 name = 'ID '+refname 100 if info is None: 101 info = refname + ' ID of SUMO network' 102 am.ArrayConf.__init__(self, attrname='ids_sumo', default='', 103 dtype='object', 104 perm=perm, 105 is_index=True, 106 name=name, 107 info=info, 108 xmltag=xmltag, 109 ) 110 111 112class Modes(am.ArrayObjman): 113 # http://www.sumo.dlr.de/userdoc/Networks/Building_Networks_from_own_XML-descriptions.html#Edge_Descriptions 114 def __init__(self, parent, **kwargs): 115 ident = 'modes' 116 self._init_objman(ident=ident, parent=parent, name='Transport Modes', 117 xmltag=('vClasses', 'vClass', 'names'), 118 version=0.1, 119 **kwargs) 120 121 self._init_attributes() 122 self.add_default() 123 124 def _init_attributes(self): 125 self.add_col(am.ArrayConf('names', '', 126 dtype=np.object, 127 perm='r', 128 is_index=True, 129 name='Name', 130 info='Name of mode. Used as key for implementing acces restrictions on edges as well as demand modelling.', 131 xmltag='vClass', 132 )) 133 134 self.add_col(am.ArrayConf('speeds_max', 50.0/3.6, 135 dtype=np.float32, 136 perm='rw', 137 name='Max. Speed', 138 unit='m/s', 139 info='Maximum possible speed for this mode. Speed is used to estimate free flow link travel times, mainly for routig purposes. Note that speeds are usully limited by the lane speed attribute', 140 )) 141 if self.get_version() < 0.1: 142 self.clear() 143 self.add_default() 144 self.set_version(0.1) 145 146 def get_id_mode(self, modename): 147 return self.names.get_id_from_index(modename) 148 149 def has_modename(self, modename): 150 return self.names.has_index(modename) 151 152 def format_ids(self, ids): 153 return ','.join(self.names[ids]) 154 155 def get_id_from_formatted(self, idstr): 156 return self.names.get_id_from_index(idstr) 157 158 def get_ids_from_formatted(self, idstrs): 159 return self.names.get_ids_from_indices_save(idstrs.split(',')) 160 161 def add_default(self): 162 """ 163 Sets the default maximum possible speed for certain modes. 164 """ 165 # print 'MODES.add_default' 166 self.add_rows(ids=MODES.values(), names=MODES.keys()) 167 168 # these speeds are used to estimate free flow link travel times 169 # mainly for routig purposes 170 # note that speed limits are usully limited by the lane speed attribute 171 speeds_max_kmph = OrderedDict([ 172 ("ignoring", 100.0), 173 ("pedestrian", 3.6), 174 ("bicycle", 25.0), 175 ("motorcycle", 130.0), 176 ("passenger", 160.0), 177 ("bus", 90.0), 178 ("tram", 50.0), 179 ("rail_urban", 160.0), 180 ("delivery", 100), 181 ("private", 160), 182 ("taxi", 160), 183 ("hov", 160), 184 ("evehicle", 160), 185 ("emergency", 160), 186 ("authority", 160), 187 ("army", 130), 188 ("vip", 160), 189 ("coach", 90), 190 ("truck", 90), 191 ("trailer", 90), 192 ("rail", 250), 193 ("rail_electric", 300), 194 ("moped", 25), 195 ("custom1", 100), 196 ("custom2", 160), 197 ("ship", 30), 198 ]) 199 200 for mode, speed_kmph in speeds_max_kmph.iteritems(): 201 self.speeds_max[self.get_id_mode(mode)] = float(speed_kmph)/3.6 202 203 # print ' self.speeds_max',self.speeds_max.get_value() 204 205 206class TrafficLightProgram(am.ArrayObjman): 207 def __init__(self, ident, parent, **kwargs): 208 self._init_objman(ident, parent=parent, 209 name='TLL Program', 210 info='Signale phases of a traffic light program.', 211 xmltag=('', 'phase', ''), **kwargs) 212 213 self.add_col(am.NumArrayConf('durations', 0, 214 dtype=np.int32, 215 name='Duration', 216 unit='s', 217 info='The duration of the phase.', 218 xmltag='duration', 219 )) 220 221 self.add_col(am.NumArrayConf('durations_min', 0, 222 dtype=np.int32, 223 name='Min. duration', 224 unit='s', 225 info='The minimum duration of the phase when using type actuated. Optional, defaults to duration.', 226 xmltag='minDur', 227 )) 228 229 self.add_col(am.NumArrayConf('durations_max', 0, 230 dtype=np.int32, 231 name='Max. duration', 232 unit='s', 233 info='The maximum duration of the phase when using type actuated. Optional, defaults to duration.', 234 xmltag='maxDur', 235 )) 236 237 self.add_col(am.ArrayConf('states', None, 238 dtype=np.object, 239 perm='rw', 240 name='State', 241 info="The traffic light states for this phase. Values can be one of these characters: 'r'=red, 'y'=yellow, 'g'=green give priority, 'G'=Green always priority, 'o'=blinking ,'O'=TLS switched off", 242 xmltag='state', 243 )) 244 245 def add_multi(self, **kwargs): 246 # print 'add_multi',self.ident 247 # print ' durations',kwargs.get('durations',None) 248 # print ' durations_min',kwargs.get('durations_min',None) 249 # print ' durations_max',kwargs.get('durations_max',None) 250 # print ' states',kwargs.get('states',None) 251 return self.add_rows(durations=kwargs.get('durations', None), 252 durations_min=kwargs.get('durations_min', None), 253 durations_max=kwargs.get('durations_max', None), 254 states=kwargs.get('states', None), 255 ) 256 257 # def write_xml(self, fd, indent, **kwargs): 258 # 259 # # never print begin-end tags 260 # # this could go into xml config 261 # if kwargs.has_key('is_print_begin_end'): 262 # del kwargs['is_print_begin_end'] 263 # am.ArrayObjman.write_xml(self, fd, indent,is_print_begin_end = False,**kwargs) 264 265 266class TrafficLightLogics(am.ArrayObjman): 267 def __init__(self, ident, tlss, **kwargs): 268 self._init_objman(ident, parent=tlss, 269 name='Traffic Light Logics', 270 info='Traffic light Logics (TLLs) for Trafic Light Systems (TLSs).', 271 xmltag=('tlLogics', 'tlLogic', 'ids_tls'), 272 **kwargs) 273 274 self.add_col(am.IdsArrayConf('ids_tls', tlss, 275 groupnames=['state'], 276 name='ID tls', 277 info='ID of traffic light system. Typically the id for a traffic light is identical with the junction id. The name may be obtained by right-clicking the red/green bars in front of a controlled intersection.', 278 xmltag='id', # this will be ID TLS tag used as ID in xml file 279 )) 280 281 self.add_col(am.ArrayConf('ids_prog', '', 282 dtype=np.object, 283 perm='rw', 284 name='Prog ID', 285 info='Sumo program ID, which is unique within the same traffic light system.', 286 xmltag='programID', 287 )) 288 289 self.add_col(am.ArrayConf('ptypes', 1, 290 choices={ 291 "static": 1, 292 "actuated": 2, 293 }, 294 dtype=np.int32, 295 perm='rw', 296 name='Prog. type', 297 info='The type of the traffic light program (fixed phase durations, phase prolongation based time gaps between vehicles).', 298 xmltag='type', 299 )) 300 301 self.add_col(am.NumArrayConf('offsets', 0, 302 dtype=np.int32, 303 perm='rw', 304 name='Offset', 305 unit='s', 306 info='The initial time offset of the program.', 307 #is_plugin = True, 308 xmltag='offset', 309 )) 310 311 self.add_col(cm.ObjsConf('programs', 312 name='program', 313 info='Tls program.', 314 )) 315 316 def make(self, id_tls, id_prog=None, ptype=None, offset=None, **kwargs_prog): 317 # print 'make',id_tls,id_prog 318 if id_prog is None: 319 id_prog = str(len(np.flatnonzero(self.ids_tls == id_tls))) 320 321 id_tll = self.add_row(ids_tls=id_tls, 322 ids_prog=id_prog, 323 ptypes=ptype, 324 offsets=offset, 325 ) 326 # init programme 327 program = TrafficLightProgram(('prog', id_tll), self) 328 self.programs[id_tll] = program 329 330 # add phases 331 program.add_multi(**kwargs_prog) 332 333 return id_tll 334 335 336class TrafficLightSystems(am.ArrayObjman): 337 # http://www.sumo.dlr.de/userdoc/Networks/Building_Networks_from_own_XML-descriptions.html#Traffic_Light_Program_Definition 338 339 def __init__(self, net, **kwargs): 340 341 self._init_objman(ident='tlss', parent=net, 342 name='Traffic Light Systems', 343 # actually tlls table is exported, but ids_sumo is required for ID 344 xmltag=('tlSystems', 'tlSystem', 'ids_sumo'), 345 **kwargs) 346 347 self.add_col(SumoIdsConf('TLS', info='SUMO ID of traffic light system.', 348 xmltag='id')) 349 350 self.add(cm.ObjConf(TrafficLightLogics('tlls', self))) 351 352 self.add_col(am.IdlistsArrayConf('ids_tlls', self.tlls.value, 353 groupnames=['state'], 354 name='IDs TLL', 355 info='ID list of available Traffic Light Logics (or programs) for the Traffic Light System.', 356 )) 357 358 self.add_col(am.IdlistsArrayConf('ids_cons', self.parent.connections, 359 groupnames=['state'], 360 name='IDs con.', 361 info='ID list of controlled connections. These connections corrispond to the elements of the state vector within the program-phases.', 362 )) 363 364 # def clear_tlss(self): 365 # #self.tlls.get_value().clear() 366 # self.clear() 367 368 def make(self, id_sumo, **kwargs): 369 370 if self.ids_sumo.has_index(id_sumo): 371 # recycle ID from existing 372 id_tls = self.ids_sumo.get_id_from_index(id_sumo) 373 else: 374 # make new TLS 375 id_tls = self.add_row(ids_sumo=id_sumo, ids_tlls=[]) 376 377 # make a new TL logic for this traffic light systems 378 id_tll = self.tlls.get_value().make(id_tls, **kwargs) 379 # append new logic to list 380 self.ids_tlls[id_tls].append(id_tll) 381 # print 'TLS.make',id_sumo,id_tls,self.ids_tlls[id_tls] 382 return id_tls 383 384 def clear_tlss(self): 385 """ 386 Delete all TLS systems of the network 387 """ 388 389 # this will clear the pointer from nodes to a tls 390 # but the node type tls will remain 391 self.parent.nodes.ids_tls.reset() 392 self.parent.connections.are_uncontrolled.reset() 393 self.clear() 394 395 def set_connections(self, id_tls, ids_con): 396 """ 397 Set connections, which represent the controlled links of TLD with id_tls 398 Called after connections in ttl file have been parsed. 399 """ 400 # print 'set_connections',id_tls,len(ids_con) 401 402 #id_tls = self.ids_sumo.get_id_from_index(id_sumo) 403 self.ids_cons[id_tls] = ids_con 404 405 # check whether the number of connections equals to the number of 406 # dignals in the states 407 # 408 # Attention: they are not equal because there is no connection for 409 # pedestrian crossings! Thos links are under crossins, 410 # but have no link index :(...so just be tolerant 411 # 412 #n_signals = len(ids_con) 413 # print ' ids',self.get_ids(), id_tls in self.get_ids() 414 #tlls = self.tlls.get_value() 415 # print ' self.ids_tlls[id_tls]:',self.ids_tlls[id_tls] 416 # for id_tll in self.ids_tlls[id_tls]: 417 # prog = tlls.programs[id_tll] 418 # states = prog.states.get_value() 419 # #print ' len(state0),n_signals',len(state0),n_signals 420 # if len(states[0]) != n_signals: 421 # print 'WARNING: tls %s has inconsistant program. \n Signals =%d, states=%d'%(self.ids_sumo[id_tls],n_signals,len(states[0])) 422 # print ' ids_con=',ids_con 423 # for state in states: 424 # print ' state',state 425 426 def change_states(self, state_current, state_new): 427 """ 428 Change traffic light state is all traffic light programms 429 from state_current to state_new 430 """ 431 tlls = self.tlls.get_value() 432 for program in tlls.programs[tlls.get_ids()]: 433 ids_phases = program.get_ids() 434 for id_phase, state in zip(ids_phases, program.states[ids_phases]): 435 program.states[id_phase] = state.replace(state_current, state_new) 436 437 def export_sumoxml(self, filepath=None, encoding='UTF-8'): 438 """ 439 Export traffic light systems to SUMO xml file. 440 """ 441 # here we export actually the traffic light logics table 442 # and the controlled connections table 443 tlls = self.tlls.get_value() 444 connections = self.parent.connections # self.ids_cons.get_linktab() 445 lanes = self.parent.lanes 446 edges = self.parent.edges 447 448 # this is the preferred way to specify default filepath 449 if filepath is None: 450 filepath = self.parent.get_rootfilepath()+'.tll.xml' 451 452 print 'export_sumoxml', filepath 453 try: 454 fd = open(filepath, 'w') 455 except: 456 print 'WARNING in export_sumoxml: could not open', filepath 457 return False 458 459 fd.write('<?xml version="1.0" encoding="%s"?>\n' % encoding) 460 xmltag_ttl, xmltag_id, attrconf_id = tlls.xmltag 461 fd.write(xm.begin(xmltag_ttl)) 462 indent = 2 463 464 #ids_modes_used = set(self.parent.vtypes.ids_mode[self.ids_vtype.get_value()]) 465 ids_tlls = tlls.get_ids() 466 tlls.write_xml(fd, indent=indent, 467 #xmltag_id = 'id', 468 #ids = ids_tlls, 469 #ids_xml = self.ids_sumo[tlls.ids_tls[ids_tlls]], 470 is_print_begin_end=False, 471 ) 472 # write controlled connections 473 ids_tls = self.get_ids() 474 xmltag_con = 'connection' 475 for ids_con, id_sumo_tls in zip(self.ids_cons[ids_tls], self.ids_sumo[ids_tls]): 476 ids_fromlane = connections.ids_fromlane[ids_con] 477 ids_tolane = connections.ids_tolane[ids_con] 478 inds_fromlane = lanes.indexes[ids_fromlane] 479 inds_tolane = lanes.indexes[ids_tolane] 480 ids_sumo_fromedge = edges.ids_sumo[lanes.ids_edge[ids_fromlane]] 481 ids_sumo_toedge = edges.ids_sumo[lanes.ids_edge[ids_tolane]] 482 483 ind_link = 0 484 for id_sumo_fromedge, id_sumo_toedge, ind_fromlane, ind_tolane in \ 485 zip(ids_sumo_fromedge, ids_sumo_toedge, inds_fromlane, inds_tolane): 486 487 fd.write(xm.start(xmltag_con, indent)) 488 fd.write(xm.num('from', id_sumo_fromedge)) 489 fd.write(xm.num('to', id_sumo_toedge)) 490 fd.write(xm.num('fromLane', ind_fromlane)) 491 fd.write(xm.num('toLane', ind_tolane)) 492 fd.write(xm.num('tl', id_sumo_tls)) 493 fd.write(xm.num('linkIndex', ind_link)) 494 495 fd.write(xm.stopit()) 496 497 ind_link += 1 498 499 fd.write(xm.end(xmltag_ttl)) 500 501 502class Crossings(am.ArrayObjman): 503 # http://www.sumo.dlr.de/userdoc/Networks/Building_Networks_from_own_XML-descriptions.html#Edge_Descriptions 504 def __init__(self, parent, **kwargs): 505 ident = 'crossings' 506 self._init_objman(ident=ident, parent=parent, name='Crossings', 507 xmltag=('crossings', 'crossing', ''), 508 is_plugin=True, 509 version=0.1, 510 **kwargs) 511 512 self._init_attributes() 513 514 def _init_attributes(self): 515 net = self.parent 516 517 self.add_col(am.IdsArrayConf('ids_node', net.nodes, 518 groupnames=['state'], 519 name='ID node', 520 info='ID of node where crossings are located.', 521 xmltag='node', 522 )) 523 524 self.add_col(am.IdlistsArrayConf('ids_edges', net.edges, 525 groupnames=['state'], 526 name='IDs Edge', 527 info='Edge IDs at specific node, where street crossing is possible.', 528 xmltag='edges', 529 )) 530 531 self.add_col(am.ArrayConf('widths', 4.0, 532 dtype=np.float32, 533 perm='rw', 534 unit='m', 535 name='Width', 536 info='Crossing width.', 537 xmltag='width', 538 )) 539 540 self.add_col(am.ArrayConf('are_priority', False, 541 dtype=np.bool, 542 perm='rw', 543 name='Priority', 544 info='Whether the pedestrians have priority over the vehicles (automatically set to true at tls-controlled intersections).', 545 xmltag='priority', 546 )) 547 548 self.add_col(am.ArrayConf('are_discard', False, 549 dtype=np.bool, 550 perm='rw', 551 name='Discard', 552 info='Whether the crossing with the given edges shall be discarded.', 553 xmltag='discard', 554 )) 555 556 if self.get_version() < 0.1: 557 self.init_plugin(True) 558 559 def multimake(self, ids_node=[], **kwargs): 560 n = len(ids_node) 561 return self.add_rows(n=n, 562 ids_node=ids_node, 563 **kwargs 564 ) 565 566 def make(self, **kwargs): 567 return self.add_row(ids_node=kwargs['id_node'], 568 ids_edges=kwargs['ids_edge'], 569 widths=kwargs.get('width', None), 570 are_priority=kwargs.get('is_priority', None), 571 are_discard=kwargs.get('is_discard', None), 572 ) 573 574 def del_element(self, _id): 575 # print 'del_element',id_zone 576 self.del_row(_id) 577 578 579class Connections(am.ArrayObjman): 580 # http://www.sumo.dlr.de/userdoc/Networks/Building_Networks_from_own_XML-descriptions.html#Edge_Descriptions 581 def __init__(self, parent, **kwargs): 582 ident = 'connections' 583 self._init_objman(ident=ident, parent=parent, name='Connections', 584 xmltag=('connections', 'connection', None), 585 **kwargs) 586 self._init_attributes() 587 588 def _init_attributes(self): 589 590 lanes = self.parent.lanes 591 self.add_col(am.IdsArrayConf('ids_fromlane', lanes, 592 groupnames=['state'], 593 name='ID from-lane', 594 info='ID of lane at the beginning of the connection.', 595 xmltag='fromLane', 596 )) 597 598 self.add_col(am.IdsArrayConf('ids_tolane', lanes, 599 name='ID to-lane', 600 info='ID of lane at the end of the connection.', 601 xmltag='toLane', 602 )) 603 604 self.add_col(am.ArrayConf('are_passes', False, 605 dtype=np.bool, 606 perm='rw', 607 name='Pass', 608 info=' if set, vehicles which pass this (lane-to-lane) connection will not wait.', 609 xmltag='pass', 610 )) 611 612 self.add_col(am.ArrayConf('are_keep_clear', True, 613 dtype=np.bool, 614 groupnames=['state'], 615 perm='rw', 616 name='keep clear', 617 info='if set to false, vehicles which pass this (lane-to-lane) connection will not worry about blocking the intersection.', 618 xmltag='keepClear', 619 )) 620 621 self.add_col(am.ArrayConf('positions_cont', 0.0, 622 dtype=np.float32, 623 perm='rw', 624 unit='m', 625 name='Cont. Pos.', 626 info='if set to 0, no internal junction will be built for this connection. If set to a positive value, an internal junction will be built at this position (in m) from the start of the internal lane for this connection. ', 627 xmltag='contPos', 628 )) 629 630 self.add_col(am.ArrayConf('are_uncontrolled', False, 631 dtype=np.bool, 632 perm='rw', 633 name='uncontrolled', 634 info='if set to true, This connection will not be TLS-controlled despite its node being controlled.', 635 xmltag='uncontrolled', 636 )) 637 638 def make(self, **kwargs): 639 return self.add_row(ids_fromlane=kwargs['id_fromlane'], 640 ids_tolane=kwargs['id_tolane'], 641 are_passes=kwargs.get('is_passes', None), 642 are_keep_clear=kwargs.get('is_keep_clear', None), 643 positions_cont=kwargs.get('position_cont', None), 644 are_uncontrolled=kwargs.get('is_uncontrolled', None), 645 ) 646 647 def multimake(self, ids_fromlane=[], ids_tolane=[], **kwargs): 648 649 n = len(ids_fromlane) 650 return self.add_rows(n=n, 651 ids_fromlane=ids_fromlane, 652 ids_tolane=ids_tolane, 653 **kwargs 654 ) 655 656 def get_id_from_sumoinfo(self, id_sumo_fromedge, id_sumo_toedge, ind_fromlane, ind_tolane): 657 get_id_lane = self.parent.edges.get_id_lane_from_sumoinfo 658 id_fromlane = get_id_lane(id_sumo_fromedge, ind_fromlane) 659 id_tolane = get_id_lane(id_sumo_toedge, ind_tolane) 660 ids_con = self.select_ids((self.ids_fromlane.value == id_fromlane) & (self.ids_tolane.value == id_tolane)) 661 if len(ids_con) == 1: 662 return ids_con[0] 663 else: 664 return -1 665 666 def export_sumoxml(self, filepath, encoding='UTF-8'): 667 try: 668 fd = open(filepath, 'w') 669 except: 670 print 'WARNING in export_sumoxml: could not open', filepath 671 return False 672 673 fd.write('<?xml version="1.0" encoding="%s"?>\n' % encoding) 674 indent = 0 675 self.write_xml(fd, indent) 676 677 fd.close() 678 679 def write_xml(self, fd, indent): 680 # print 'Connections.write_xml' 681 682 xmltag, xmltag_item, attrname_id = self.xmltag 683 #attrsman = self.get_attrsman() 684 #attrsman = self.get_attrsman() 685 #config_fromlane = attrsman.get_config('ids_fromlane') 686 #config_tolane = attrsman.get_config('ids_tolane') 687 colconfigs = self.get_colconfigs(is_all=True) 688 ids_sumoedges = self.parent.edges.ids_sumo 689 ids_laneedge = self.parent.lanes.ids_edge 690 # print ' header' 691 fd.write(xm.start(xmltag, indent)) 692 # print ' ', self.parent.get_attrsman().get_config('version').attrname,self.parent.get_attrsman().get_config('version').get_value() 693 #fd.write( self.parent.get_attrsman().get_config('version').write_xml(fd) ) 694 self.parent.get_attrsman().get_config('version').write_xml(fd) 695 fd.write(xm.stop()) 696 697 for _id in self.get_ids(): 698 fd.write(xm.start(xmltag_item, indent+2)) 699 700 # print ' make tag and id',_id 701 # fd.write(xm.num(xmltag_id,attrconfig_id[_id])) 702 703 # print ' write columns' 704 for attrconfig in colconfigs: 705 # print ' colconfig',attrconfig.attrname 706 if attrconfig == self.ids_fromlane: 707 fd.write(xm.num('from', ids_sumoedges[ids_laneedge[self.ids_fromlane[_id]]])) 708 attrconfig.write_xml(fd, _id) 709 710 elif attrconfig == self.ids_tolane: 711 fd.write(xm.num('to', ids_sumoedges[ids_laneedge[self.ids_tolane[_id]]])) 712 attrconfig.write_xml(fd, _id) 713 714 else: 715 attrconfig.write_xml(fd, _id) 716 fd.write(xm.stopit()) 717 718 self.parent.crossings.write_xml(fd, indent=indent+2, is_print_begin_end=False) 719 720 fd.write(xm.end(xmltag, indent)) 721 722 723class Lanes(am.ArrayObjman): 724 # http://www.sumo.dlr.de/userdoc/Networks/Building_Networks_from_own_XML-descriptions.html#Edge_Descriptions 725 def __init__(self, parent, **kwargs): 726 ident = 'lanes' 727 self._init_objman(ident=ident, parent=parent, name='Lanes', 728 is_plugin=True, 729 xmltag=('lanes', 'lane', 'indexes'), 730 version=0.1, 731 **kwargs) 732 733 self._init_attributes() 734 735 def _init_attributes(self): 736 modes = self.parent.modes 737 edges = self.parent.edges 738 739 self.add_col(am.ArrayConf('indexes', 0, 740 dtype=np.int32, 741 perm='r', 742 name='Lane index', 743 info='The enumeration index of the lane (0 is the rightmost lane, <NUMBER_LANES>-1 is the leftmost one).', 744 xmltag='index', 745 )) 746 747 self.add_col(am.ArrayConf('widths', 3.5, 748 dtype=np.float32, 749 perm='rw', 750 unit='m', 751 name='Width', 752 info='Lane width.', 753 is_plugin=True, 754 xmltag='width', 755 )) 756 757 self.add_col(am.NumArrayConf('speeds_max', 50.0/3.6, 758 dtype=np.float32, 759 groupnames=['state'], 760 perm='rw', 761 name='Max speed', 762 unit='m/s', 763 info='Maximum speed on lane.', 764 xmltag='speed', 765 )) 766 767 self.add_col(am.NumArrayConf('offsets_end', 0.0, 768 dtype=np.float32, 769 groupnames=['state'], 770 perm='r', 771 name='End offset', 772 unit='m', 773 info='Move the stop line back from the intersection by the given amount (effectively shortening the lane and locally enlarging the intersection).', 774 xmltag='endOffset', 775 )) 776 777 self.add_col(am.IdlistsArrayConf('ids_modes_allow', modes, 778 name='IDs allowed', 779 info='Allowed mode IDs on this lane.', 780 xmltag='allow', 781 )) 782 783 self.add_col(am.IdlistsArrayConf('ids_modes_disallow', modes, 784 name='IDs disallow', 785 info='Disallowed mode IDs on this lane.', 786 xmltag='disallow', 787 )) 788 789 # if self.get_version() < 0.1: 790 # self.ids_modes_allow.set_value(self.modes_allow.get_value().copy()) 791 # self.ids_modes_disallow.set_value(self.modes_disallow.get_value().copy()) 792 # self.delete('modes_allow') 793 # self.delete('modes_disallow') 794 795 self.add_col(am.IdsArrayConf('ids_mode', modes, 796 groupnames=['state'], 797 name='Main mode ID', 798 info='ID of main mode of this lane.', 799 is_plugin=True, 800 )) 801 802 self.add_col(am.IdsArrayConf('ids_edge', edges, 803 groupnames=['state'], 804 name='ID edge', 805 info='ID of edge in which the lane is contained.', 806 )) 807 808 self.add_col(am.ListArrayConf('shapes', 809 groupnames=['_private'], 810 perm='rw', 811 name='Shape', 812 unit='m', 813 info='List of 3D Shape coordinates to describe polyline.', 814 is_plugin=True, 815 )) 816 self.set_version(0.2) 817 # print 'Lanes._init_attributes ids_modes_allow',self.ids_modes_allow.get_value() 818 819 def get_edges(self): 820 return self.parent.edges 821 822 def get_id_sumo(self, id_lane): 823 return self.parent.edges.ids_sumo[self.ids_edge[id_lane]]+'_%d' % self.indexes[id_lane] 824 825 def get_lengths(self, ids_lane): 826 return self.parent.edges.lengths[self.ids_edge[ids_lane]] 827 828 def multimake(self, indexes=[], **kwargs): 829 830 n = len(indexes) 831 # print 'Lanes.make',kwargs 832 #width = kwargs.get('widths',None) 833 #speed_max = kwargs.get('speed_max',-1) 834 #modes_allow = kwargs.get('modes_allow',[]) 835 836 return self.add_rows(n=n, 837 indexes=indexes, 838 widths=kwargs['widths'], 839 speeds_max=kwargs['speeds_max'], 840 offsets_end=kwargs['offsets_end'], 841 ids_modes_allow=kwargs['ids_modes_allow'], 842 ids_modes_disallow=kwargs['ids_modes_disallow'], 843 ids_mode=kwargs['ids_mode'], 844 ids_edge=kwargs['ids_edge'], 845 # shapes = kwargs.get('shapes',[]), # if empty, then computation later from edge shape 846 ) 847 848 def make(self, **kwargs): 849 edges = self.get_edges() 850 id_edge = kwargs['id_edge'] 851 index = kwargs['index'] 852 # print 'Lanes.make',kwargs 853 width = kwargs.get('width', -1) 854 speed_max = kwargs.get('speed_max', -1) 855 ids_modes_allow = kwargs.get('ids_modes_allow', []) 856 857 is_sidewalk_edge = False 858 is_sidewalk = False 859 if len(ids_modes_allow) > 0: 860 id_mode = ids_modes_allow[0] # pick first as major mode 861 else: 862 id_mode = -1 # no mode specified 863 864 if index == 0: 865 width_sidewalk_edge = edges.widths_sidewalk[id_edge] 866 is_sidewalk_edge = width_sidewalk_edge > 0 867 is_sidewalk = (MODES['pedestrian'] in ids_modes_allow) # test for pedestrian sidewalk 868 869 if speed_max < 0: 870 if (index == 0) & is_sidewalk: 871 speed_max = 0.8 # default walk speed 872 else: 873 speed_max = edges.speeds_max[id_edge] 874 875 # print ' is_sidewalk_edge ,is_sidewalk',is_sidewalk_edge ,is_sidewalk 876 if width < 0: 877 width = edges.widths_lanes_default[id_edge] 878 879 if index == 0: 880 if is_sidewalk_edge: # edge wants sidewalks 881 width = width_sidewalk_edge 882 elif (not is_sidewalk_edge) & is_sidewalk: # edge does not want sidewalks, but actually there is a sidewalk 883 width = 0.9 # default sidewalk width 884 edges.widths_sidewalk[id_edge] = width 885 886 # if sidewalk, then the edge attribute widths_sidewalk 887 # should be set to actual lane width in case it is less than zero 888 elif index == 0: # width set for lane 0 889 if (not is_sidewalk_edge) & is_sidewalk: # edge does not want sidewalks, but actually there is a sidewalk 890 edges.widths_sidewalk[id_edge] = width 891 892 # if index == 0: 893 # edges.widths_sidewalk[id_edge]= width 894 895 return self.add_row(indexes=index, 896 widths=width, 897 speeds_max=speed_max, 898 offsets_end=kwargs.get('offset_end', None), 899 ids_modes_allow=ids_modes_allow, 900 ids_modes_disallow=kwargs.get('ids_modes_disallow', []), 901 ids_mode=id_mode, 902 ids_edge=id_edge, 903 shapes=kwargs.get('shapes', []), # if empty, then computation later from edge shape 904 ) 905 906 def reshape(self): 907 for id_edge in self.parent.edges.get_ids(): 908 self.reshape_edgelanes(id_edge) 909 910 def reshape_edgelanes(self, id_edge): 911 """ 912 Recalculate shape of all lanes contained in edge id_edge 913 based on the shape information of this edge. 914 """ 915 # 916 #lanes = self.get_lanes() 917 edges = self.parent.edges 918 ids_lane = edges.ids_lanes[id_edge] 919 920 shape = np.array(edges.shapes[id_edge], np.float32) 921 922 # print 'reshape: edgeshape id_edge,ids_lane=',id_edge,ids_lane 923 # print ' shape =',shape 924 n_lanes = len(ids_lane) 925 n_vert = len(shape) 926 927 angles_perb = get_angles_perpendicular(shape) 928 929 dxn = np.cos(angles_perb) 930 dyn = np.sin(angles_perb) 931 932 #laneshapes = np.zeros((n_lanes,n_vert,3), np.float32) 933 934 id_lane = ids_lane[0] 935 # np.ones(n_lanes,np.float32)#lanes.widths[ids_lane] 936 widths = self.widths[ids_lane] 937 widths_tot = np.sum(widths) 938 if edges.types_spread[id_edge] == 1: # center lane spread 939 widths2 = np.concatenate(([0.0], widths[:-1])) 940 # print ' widths',widths_tot,widths 941 # print ' widths2',widths2 942 displacement = np.cumsum(widths2) 943 displacement = 0.5*(widths_tot)-displacement-0.5*widths 944 # print ' displacement',displacement 945 else: 946 widths2 = np.concatenate(([0.0], widths[:-1])) 947 displacement = np.cumsum(widths2) 948 displacement = displacement[-1]-displacement-0.5*widths+widths[-1] 949 950 for i in range(n_lanes): 951 id_lane = ids_lane[i] 952 # print ' displacement[i] ',displacement[i]#, 953 954 # if 1:#len(self.shapes[id_lane])==0: # make only if not existant 955 laneshape = np.zeros(shape.shape, np.float32) 956 # print ' dx \n',dxn*displacement[i] 957 # print ' dy \n',dyn*displacement[i] 958 laneshape[:, 0] = dxn*displacement[i] + shape[:, 0] 959 laneshape[:, 1] = dyn*displacement[i] + shape[:, 1] 960 laneshape[:, 2] = shape[:, 2] 961 self.shapes[id_lane] = laneshape 962 963 self.shapes.set_modified(True) 964 965 def get_laneindex_allowed(self, ids_lane, id_mode): 966 # print 'get_laneindex_allowed',ids_lane, id_mode 967 # check ignoring mode and give it the first non pedestrian only lane 968 if id_mode == MODES["ignoring"]: 969 ind = 0 970 while is_cont & (ind < len(ids_lane)): 971 id_lane = ids_lane[ind] 972 if len(self.ids_modes_allow[id_lane]) > 0: 973 if MODES["pedestrian"] not in self.ids_modes_allow[id_lane]: 974 return ind 975 else: 976 ind += 1 977 978 else: 979 return ind 980 print 'WARNING: ignoring mode has no access on footpath' 981 return -1 982 983 # return len(ids_lane)-1 984 985 is_cont = True 986 ind = 0 987 while is_cont & (ind < len(ids_lane)): 988 # print ' ',ind,len(self.ids_modes_allow[id_lane]),len(self.ids_modes_disallow[id_lane]),id_mode in self.ids_modes_allow[id_lane],id_mode in self.ids_modes_disallow[id_lane] 989 id_lane = ids_lane[ind] 990 if len(self.ids_modes_allow[id_lane]) > 0: 991 if id_mode in self.ids_modes_allow[id_lane]: 992 return ind 993 else: 994 ind += 1 995 996 elif len(self.ids_modes_disallow[id_lane]) > 0: 997 if id_mode in self.ids_modes_disallow[id_lane]: 998 ind += 1 999 else: 1000 return ind 1001 else: 1002 # no restrictions 1003 return ind 1004 1005 # no unrestricted lane found 1006 return -1 # not allowed on either lane 1007 1008 def add_access(self, id_lane, id_mode): 1009 if len(self.ids_modes_allow[id_lane]) > 0: 1010 # there are restrictions 1011 self.ids_modes_allow[id_lane].append(id_mode) 1012 1013 # make sure id_mode is not disallowed 1014 if id_mode in self.ids_modes_disallow[id_lane]: 1015 self.ids_modes_disallow[id_lane].remove(id_lane) 1016 1017 def get_laneindex_allowed_old(self, ids_lane, id_mode): 1018 is_cont = True 1019 ind = 0 1020 n_lane = len(ids_lane) 1021 while is_cont & (ind < n_lane): 1022 id_lane = ids_lane[ind] 1023 if len(self.ids_modes_allow[id_lane]) > 0: 1024 if id_mode in self.ids_modes_allow[id_lane]: 1025 return ind 1026 else: 1027 ind += 1 1028 1029 elif len(self.ids_modes_disallow[id_lane]) > 0: 1030 if id_mode in self.ids_modes_disallow[id_lane]: 1031 ind += 1 1032 else: 1033 return ind 1034 else: 1035 # no restrictions 1036 return ind 1037 1038 # no unrestricted lane found 1039 return -1 # not allowed on either lane 1040 1041 def get_accesslevel(self, ids_lane, id_mode): 1042 """ 1043 Returns access level of mode on lanes ids_lane: 1044 -1 = No access 1045 0 = all modes can access 1046 1 = mode can access with a restricted number of other modes 1047 2 = exclusive access for id_mode 1048 """ 1049 # print 'get_accesslevel',ids_lane 1050 is_mode_only = False 1051 is_mode_mixed = False 1052 is_modes_all = False 1053 #is_blocked = False 1054 # print ' ids_modes_allow',self.ids_modes_allow.get_value() 1055 for id_lane, ids_modes_allow, ids_modes_disallow in zip(ids_lane, self.ids_modes_allow[ids_lane], self.ids_modes_disallow[ids_lane]): 1056 # print ' ids_modes_allow',ids_modes_allow,'ids_modes_disallow',ids_modes_disallow,'id_lane',id_lane 1057 if ids_modes_allow is None: 1058 ids_modes_allow = [] 1059 if ids_modes_disallow is None: 1060 ids_modes_disallow = [] 1061 1062 n_allow = len(ids_modes_allow) 1063 #n_disallow = len(ids_modes_disallow) 1064 1065 if n_allow == 0: 1066 is_mode_only = False 1067 is_modes_all = True 1068 is_blocked = id_mode in ids_modes_disallow 1069 1070 elif n_allow == 1: 1071 # if id_mode == ids_modes_allow[0]: 1072 # is_mode_only = True 1073 # else: 1074 # is_blocked = True 1075 # break 1076 is_mode_only = id_mode == ids_modes_allow[0] 1077 is_blocked = (id_mode in ids_modes_disallow) | (not(is_mode_only)) 1078 1079 else: 1080 is_mode_only = False 1081 #is_blocked &= id_mode in ids_modes_disallow 1082 is_blocked = (id_mode not in ids_modes_allow) | (id_mode in ids_modes_disallow) 1083 1084 # print ' is_blocked',is_blocked,'is_modes_all',is_modes_all,'is_mode_only',is_mode_only 1085 if not is_blocked: 1086 # means access has been found 1087 break 1088 1089 # print ' Final: is_blocked',is_blocked,'is_modes_all',is_modes_all,'is_mode_only',is_mode_only 1090 if is_blocked: # & (not is_mode_only)&(not is_modes_all): 1091 a = -1 1092 # print ' accesslevel=',a 1093 return a 1094 # return -1 1095 1096 if is_mode_only: 1097 a = 2 1098 # return 2 1099 1100 elif is_modes_all: 1101 a = 0 1102 # return 0 1103 1104 else: 1105 a = 1 1106 # return 1 1107 1108 # print ' accesslevel=',a 1109 return a 1110 1111 def get_coord_from_pos(self, id_lane, pos): 1112 return get_coord_on_polyline_from_pos(self.shapes[id_lane], pos) 1113 1114 def get_sumoinfo_from_id_lane(self, id_lane): 1115 id_sumo_edge = self.parent.edges.ids_sumo[self.ids_edge[id_lane]] 1116 return id_sumo_edge+'_'+str(self.indexes[id_lane]) 1117 1118 1119class Roundabouts(am.ArrayObjman): 1120 # http://www.sumo.dlr.de/userdoc/Networks/Building_Networks_from_own_XML-descriptions.html#Edge_Descriptions 1121 def __init__(self, parent, edges, nodes, **kwargs): 1122 ident = 'roundabouts' 1123 self._init_objman(ident=ident, parent=parent, 1124 name='Roundabouts', 1125 xmltag=('roundabouts', 'roundabout', ''), 1126 **kwargs) 1127 1128 self.add_col(am.IdlistsArrayConf('ids_edges', edges, 1129 groupnames=['state'], 1130 name='IDs edges', 1131 info='List with edges IDs.', 1132 xmltag='edges', 1133 )) 1134 1135 self.add_col(am.IdlistsArrayConf('ids_nodes', nodes, 1136 groupnames=['state'], 1137 name='IDs Nodes', 1138 info='List with node IDs.', 1139 xmltag='nodes', 1140 )) 1141 1142 def multimake(self, ids_nodes=[], **kwargs): 1143 n = len(ids_nodes) 1144 return self.add_rows(n=n, 1145 ids_nodes=ids_nodes, **kwargs 1146 ) 1147 1148 def make(self, **kwargs): 1149 return self.add_row(ids_nodes=kwargs['ids_node'], 1150 ids_edges=kwargs['ids_edge'], 1151 ) 1152 1153 1154class Edges(am.ArrayObjman): 1155 # http://www.sumo.dlr.de/userdoc/Networks/Building_Networks_from_own_XML-descriptions.html#Edge_Descriptions 1156 def __init__(self, parent, **kwargs): 1157 ident = 'edges' 1158 self._init_objman(ident=ident, parent=parent, 1159 name='Edges', 1160 xmltag=('edges', 'edge', 'ids_sumo'), 1161 version=0.2, 1162 **kwargs) 1163 1164 self._init_attributes() 1165 self._init_constants() 1166 1167 def _init_attributes(self): 1168 1169 self.add_col(SumoIdsConf('Edge')) 1170 1171 self.add_col(am.ArrayConf('types', '', 1172 dtype=np.object, 1173 perm='rw', 1174 name='Type', 1175 info='Edge reference OSM type.', 1176 xmltag='type', # should not be exported? 1177 )) 1178 1179 self.add_col(am.ArrayConf('nums_lanes', 1, 1180 dtype=np.int32, 1181 perm='r', 1182 name='# of lanes', 1183 info='Number of lanes.', 1184 xmltag='numLanes', 1185 )) 1186 1187 self.add_col(am.NumArrayConf('speeds_max', 50.0/3.6, 1188 dtype=np.float32, 1189 groupnames=['state'], 1190 perm='rw', 1191 name='Max speed', 1192 unit='m/s', 1193 info='Maximum speed on edge.', 1194 xmltag='speed', 1195 )) 1196 1197 self.add_col(am.ArrayConf('priorities', 1, 1198 dtype=np.int32, 1199 perm='rw', 1200 name='Priority', 1201 info='Road priority, 1 is lowest (local access road or footpath), 13 is highest (national motorway).', 1202 xmltag='priority', 1203 )) 1204 1205 self.add_col(am.NumArrayConf('lengths', 0.0, 1206 dtype=np.float32, 1207 groupnames=['state'], 1208 perm='r', 1209 name='Length', 1210 unit='m', 1211 info='Edge length.', 1212 xmltag='length ', 1213 )) 1214 if self.get_version() < 0.3: 1215 self.lengths.set_xmltag('length') 1216 # self.lengths.set_xmltag(None) 1217 1218 self.add_col(am.NumArrayConf('widths', 0.0, 1219 dtype=np.float32, 1220 groupnames=['state'], 1221 perm='r', 1222 name='Width', 1223 unit='m', 1224 info='Edge width.', 1225 is_plugin=True, 1226 #xmltag = 'width', 1227 )) 1228 1229 self.add_col(am.ListArrayConf('shapes', 1230 groupnames=['_private'], 1231 perm='rw', 1232 name='Shape', 1233 unit='m', 1234 info='Edge shape as list of 3D shape coordinates representing a polyline.', 1235 is_plugin=True, 1236 xmltag='shape', 1237 )) 1238 1239 self.add_col(am.ArrayConf('types_spread', 0, 1240 choices={ 1241 "right": 0, 1242 "center": 1, 1243 }, 1244 dtype=np.int32, 1245 perm='rw', 1246 name='Spread type', 1247 info='Determines how the lanes are spread with respect to main link coordinates.', 1248 xmltag='spreadType', 1249 )) 1250 1251 self.add_col(am.ArrayConf('names', '', 1252 dtype=np.object, 1253 perm='rw', 1254 name='Name', 1255 info='Road name, for visualization only.', 1256 xmltag='name', 1257 )) 1258 1259 self.add_col(am.NumArrayConf('offsets_end', 0.0, 1260 dtype=np.float32, 1261 groupnames=['state'], 1262 perm='r', 1263 name='End offset', 1264 unit='m', 1265 info='Move the stop line back from the intersection by the given amount (effectively shortening the edge and locally enlarging the intersection).', 1266 xmltag='endOffset', 1267 )) 1268 1269 self.add_col(am.NumArrayConf('widths_lanes_default', 3.5, 1270 dtype=np.float32, 1271 groupnames=['state'], 1272 perm='rw', 1273 name='Default lane width', 1274 unit='m', 1275 info='Default lane width for all lanes of this edge in meters (used for visualization).', 1276 #xmltag = '', 1277 )) 1278 1279 # move this to lane in future versions 1280 self.add_col(am.NumArrayConf('widths_sidewalk', -1.0, 1281 dtype=np.float32, 1282 groupnames=['state'], 1283 perm='rw', 1284 name='Sidewalk width', 1285 unit='m', 1286 info='Adds a sidewalk with the given width (defaults to -1 which adds nothing).', 1287 #xmltag = 'sidewalkWidth', 1288 )) 1289 1290 self.set_version(0.2) 1291 1292 def _init_constants(self): 1293 self._segvertices = None 1294 self._edgeinds = None 1295 self._seginds = None 1296 self._segvertexinds = None 1297 self.do_not_save_attrs(['_segvertices', '_edgeinds', '_seginds', '_segvertexinds']) 1298 1299 def set_nodes(self, nodes): 1300 # set ref to nodes table, once initialized 1301 self.add_col(am.IdsArrayConf('ids_fromnode', nodes, 1302 groupnames=['state'], 1303 name='ID from-node', 1304 info='ID of node at the beginning of the edge.', 1305 xmltag='from', 1306 )) 1307 1308 self.add_col(am.IdsArrayConf('ids_tonode', nodes, 1309 groupnames=['state'], 1310 name='ID to-node', 1311 info='ID of node at the end of the edge.', 1312 xmltag='to', 1313 )) 1314 1315 def set_lanes(self, lanes): 1316 self.add_col(am.IdlistsArrayConf('ids_lanes', lanes, 1317 groupnames=['state'], 1318 name='IDs Lanes', 1319 info='List with IDs of lanes.', 1320 xmltag='lanes', 1321 is_xml_include_tab=True, 1322 )) 1323 1324 def get_outgoing(self, id_edge): 1325 # print 'get_outgoing',id_edge,self.ids_tonode[id_edge],self.parent.nodes.ids_outgoing[self.ids_tonode[id_edge]] 1326 ids_edges = self.parent.nodes.ids_outgoing[self.ids_tonode[id_edge]] 1327 if ids_edges is None: # dead end 1328 return [] 1329 else: 1330 return ids_edges 1331 1332 def get_incoming(self, id_edge): 1333 # TODO: would be good to have [] as default instead of None!! 1334 ids_edges = self.parent.nodes.ids_incoming[self.ids_fromnode[id_edge]] 1335 if ids_edges is None: # dead end 1336 return [] 1337 else: 1338 return ids_edges 1339 1340 def get_lanes(self): 1341 return self.parent.lanes 1342 1343 def get_id_lane_from_sumoinfo_check(self, id_sumo_edge, ind_lane): 1344 if self.ids_sumo.has_index(id_sumo_edge): 1345 id_edge = self.ids_sumo.get_id_from_index(id_sumo_edge) 1346 if ind_lane < self.nums_lanes[id_edge]: 1347 return self.ids_lanes[id_edge][ind_lane] 1348 return -1 1349 1350 def get_id_lane_from_sumoinfo(self, id_sumo_edge, ind_lane): 1351 id_edge = self.ids_sumo.get_id_from_index(id_sumo_edge) 1352 return self.ids_lanes[id_edge][ind_lane] 1353 1354 def get_sumoinfo_from_id_lane(self, id_lane): 1355 return self.parent.lanes.get_sumoinfo_from_id_lane(id_lane) 1356 1357 def is_oneway(self, id_edge): 1358 ids_incoming = self.parent.nodes.ids_incoming[self.ids_fromnode[id_edge]] 1359 ids_outgoing = self.parent.nodes.ids_outgoing[self.ids_tonode[id_edge]] 1360 if (ids_incoming is None) | (ids_outgoing is None): 1361 return True 1362 else: 1363 return set(ids_incoming).isdisjoint(ids_outgoing) 1364 1365 def has_sidewalk(self, id_edge): 1366 return MODES["pedestrian"] in self.parent.lanes.ids_modes_allow[self.ids_lanes[id_edge][0]] 1367 1368 def get_fstar(self, is_return_lists=False, is_return_arrays=False, 1369 is_ignor_connections=False): 1370 """ 1371 Returns the forward star graph of the network as dictionary: 1372 fstar[id_fromedge] = set([id_toedge1, id_toedge2,...]) 1373 1374 if is_return_lists = True then a list of edges is the value 1375 of fstar 1376 1377 if is_return_arrays = True then a numpy array of edges is the value 1378 of fstar 1379 1380 if is_ignor_connections = True then all possible successive edges 1381 are considered, disregarding the actual connections 1382 1383 """ 1384 #ids_edge = self.get_ids() 1385 #fstar = np.array(np.zeros(np.max(ids_edge)+1, np.obj)) 1386 fstar = {} 1387 if is_ignor_connections: 1388 # here we ignore connections and look at the 1389 # outgoing edges of node database 1390 ids_outgoing = self.parent.nodes.ids_outgoing 1391 ids = self.get_ids() 1392 for id_edge, id_tonode in zip(ids, self.ids_tonode[ids]): 1393 ids_edge_outgoing = ids_outgoing[id_tonode] 1394 if ids_edge_outgoing is not None: 1395 fstar[id_edge] = set(ids_edge_outgoing) 1396 else: 1397 fstar[id_edge] = set() 1398 else: 1399 # here we check actual connections 1400 # this is important if correct turns are desired 1401 # for exampole in car routing 1402 connections = self.parent.connections 1403 lanes = self.parent.lanes 1404 inds_con = connections.get_inds() 1405 ids_fromedge = lanes.ids_edge[connections.ids_fromlane.get_value()[inds_con]] 1406 ids_toedge = lanes.ids_edge[connections.ids_tolane.get_value()[inds_con]] 1407 1408 for id_edge in self.get_ids(): 1409 fstar[id_edge] = set() 1410 1411 for id_fromedge, id_toedge in zip(ids_fromedge, ids_toedge): 1412 fstar[id_fromedge].add(id_toedge) 1413 1414 if is_return_lists | is_return_arrays: 1415 for id_edge in self.get_ids(): 1416 ids_toedges = list(fstar[id_edge]) 1417 if is_return_arrays: 1418 fstar[id_edge] = np.array(ids_toedges, dtype=np.int32) 1419 else: 1420 fstar[id_edge] = ids_toedges 1421 return fstar 1422 1423 def get_bstar(self, is_return_lists=False, is_return_arrays=False, 1424 is_ignor_connections=False): 1425 """ 1426 Returns the backward star graph of the network as dictionary: 1427 fstar[id_fromedge] = set([id_fromedge1, id_fromedge2,...]) 1428 1429 if is_return_lists = True then a list of edges is the value 1430 of bstar 1431 1432 if is_return_arrays = True then a numpy array of edges is the value 1433 of bstar 1434 1435 if is_ignor_connections = True then all possible preceding edges 1436 are considered, disregarding the actual connections 1437 1438 """ 1439 #ids_edge = self.get_ids() 1440 #fstar = np.array(np.zeros(np.max(ids_edge)+1, np.obj)) 1441 bstar = {} 1442 if is_ignor_connections: 1443 # here we ignore connections and look at the 1444 # outgoing edges of node database 1445 ids_incoming = self.parent.nodes.ids_incoming 1446 ids = self.get_ids() 1447 for id_edge, id_fromnode in zip(ids, self.ids_fromnode[ids]): 1448 ids_edge_incoming = ids_incoming[id_fromnode] 1449 if ids_edge_incoming is not None: 1450 bstar[id_edge] = set(ids_edge_incoming) 1451 else: 1452 bstar[id_edge] = set() 1453 else: 1454 # here we check actual connections 1455 # this is important if correct turns are desired 1456 # for exampole in car routing 1457 connections = self.parent.connections 1458 lanes = self.parent.lanes 1459 inds_con = connections.get_inds() 1460 ids_fromedge = lanes.ids_edge[connections.ids_fromlane.get_value()[inds_con]] 1461 ids_toedge = lanes.ids_edge[connections.ids_tolane.get_value()[inds_con]] 1462 1463 for id_edge in self.get_ids(): 1464 bstar[id_edge] = set() 1465 1466 for id_fromedge, id_toedge in zip(ids_fromedge, ids_toedge): 1467 bstar[id_toedge].add(id_fromedge) 1468 1469 if is_return_lists | is_return_arrays: 1470 for id_edge in self.get_ids(): 1471 ids_fromedges = list(bstar[id_edge]) 1472 if is_return_arrays: 1473 bstar[id_edge] = np.array(ids_fromedges, dtype=np.int32) 1474 else: 1475 bstar[id_edge] = ids_fromedges 1476 return bstar 1477 1478 def get_accesslevel(self, id_edge, id_mode): 1479 """ 1480 Returns access level of mode on edge id_edge: 1481 -1 = No access 1482 0 = all modes can access 1483 1 = mode can access with a restricted number of other modes 1484 2 = exclusive access for id_mode 1485 """ 1486 # print 'get_accesslevel',id_edge,self.ids_sumo[id_edge] 1487 return self.parent.lanes.get_accesslevel(self.ids_lanes[id_edge], id_mode) 1488 1489 def get_accesslevels(self, id_mode): 1490 """ 1491 The returned array represents the access levels that corresponds to 1492 edge IDs. 1493 1494 Access levels of mode on edge id_edge: 1495 -1 = No access 1496 0 = all modes can access 1497 1 = mode can access with a restricted number of other modes 1498 2 = exclusive access for id_mode 1499 """ 1500 get_accesslevel = self.parent.lanes.get_accesslevel 1501 ids_edge = self.get_ids() 1502 accesslevels = np.zeros(np.max(ids_edge)+1, np.int8) 1503 for id_edge, ids_lane in zip(ids_edge, self.ids_lanes[ids_edge]): 1504 accesslevels[id_edge] = get_accesslevel(ids_lane, id_mode) 1505 return accesslevels 1506 1507 def get_distances(self, id_mode=0, is_check_lanes=False): 1508 """ 1509 Returns distances for all edges. 1510 The returned array represents the distance that corresponds to 1511 edge IDs. 1512 1513 If is_check_lanes is True, then the lane speeds are considered where 1514 the respective mode is allowed. 1515 1516 If not allowed on a particular edge, 1517 then the respective edge distance is negative. 1518 """ 1519 # print 'get_distances id_mode,is_check_lanes,speed_max',id_mode,is_check_lanes,speed_max 1520 ids_edge = self.get_ids() 1521 dists = np.zeros(np.max(ids_edge)+1, np.float32) 1522 #speeds = self.speeds_max[ids_edge] 1523 1524 # if speed_max is not None: 1525 # speeds = np.clip(speeds, 0.0, speed_max) 1526 # 1527 # elif id_mode is not None: 1528 # # limit allowed speeds with max speeds of mode 1529 # speeds = np.clip(speeds, 0.0, self.parent.modes.speeds_max[id_mode]) 1530 1531 radii = self.ids_fromnode.get_linktab().radii 1532 dists[ids_edge] = radii[self.ids_fromnode[ids_edge]] + self.lengths[ids_edge] + radii[self.ids_tonode[ids_edge]] 1533 ids_lanes = self.ids_lanes 1534 if is_check_lanes & (id_mode > 0): # mode 0 can pass everywhere 1535 get_laneindex_allowed = self.parent.lanes.get_laneindex_allowed 1536 has_noaccess = -1 1537 for id_edge in ids_edge: 1538 if get_laneindex_allowed(ids_lanes[id_edge], id_mode) == has_noaccess: 1539 dists[id_edge] = has_noaccess 1540 1541 #ind = get_laneindex_allowed(ids_lanes[id_edge], id_mode) 1542 # print ' check id_edge, ind',id_edge, ind 1543 # if ind<0: 1544 # dists[id_edge] = ind # =-1 1545 1546 return dists 1547 1548 def get_times(self, id_mode=0, is_check_lanes=False, speed_max=None, 1549 modeconst_excl=0.0, modeconst_mix=0.0, ): 1550 """ 1551 Returns freeflow travel times for all edges..radii 1552 The returned array represents the travel time that corresponds to 1553 edge IDs. 1554 1555 If is_check_lanes is True, then the lane speeds are considered where 1556 the respective mode is allowed. 1557 1558 If not allowed on a particular edge, 1559 then the respective edge travel time is negative. 1560 1561 modeconst_excl and modeconst_mix are constants added to the 1562 time if the respective edge provides exclusive or reserver mixed 1563 access for the specifird mode 1564 1565 """ 1566 # print 'get_times id_mode,is_check_lanes,speed_max',id_mode,is_check_lanes,speed_max 1567 ids_edge = self.get_ids() 1568 times = np.zeros(np.max(ids_edge)+1, np.float32) 1569 speeds = self.speeds_max[ids_edge] 1570 1571 if speed_max is not None: 1572 speeds = np.clip(speeds, 0.0, speed_max) 1573 1574 elif id_mode is not None: 1575 # limit allowed speeds with max speeds of mode 1576 speeds = np.clip(speeds, 0.0, self.parent.modes.speeds_max[id_mode]) 1577 1578 times[ids_edge] = self.lengths[ids_edge]/speeds 1579 ids_lanes = self.ids_lanes 1580 if is_check_lanes & (id_mode > 0): # mode 0 can pass everywhere 1581 #get_laneindex_allowed = self.parent.lanes.get_laneindex_allowed 1582 get_accesslevel = self.parent.lanes.get_accesslevel 1583 invalid = -1 1584 #ids_edge = self.get_ids() 1585 #accesslevels = np.zeros(np.max(ids_edge)+1, np.int8) 1586 for id_edge, ids_lane in zip(ids_edge, self.ids_lanes[ids_edge]): 1587 #accesslevels[id_edge] = get_accesslevel(ids_lane, id_mode) 1588 accesslevel = get_accesslevel(ids_lane, id_mode) 1589 if accesslevel == invalid: 1590 times[id_edge] = invalid 1591 elif accesslevel == 2: 1592 times[id_edge] = max(times[id_edge] + modeconst_excl, 0) 1593 elif accesslevel == 1: 1594 times[id_edge] = max(times[id_edge] + modeconst_mix, 0) 1595 # here we could multiply with a factor 1596 #ind = get_laneindex_allowed(ids_lanes[id_edge], id_mode) 1597 # print ' check id_edge, ind',id_edge, ind 1598 # if ind<0: 1599 # # making times negative will prevent the router to use 1600 # # this edge 1601 # times[id_edge] = ind # =-1 1602 1603 return times 1604 1605 def select_accessible_mode(self, id_mode): 1606 """ 1607 Returns an array with all allowed edge ids for this mode 1608 and an array with the corrisponding lane index 1609 """ 1610 get_laneindex_allowed = self.parent.lanes.get_laneindex_allowed 1611 ids_lanes = self.ids_lanes 1612 ids_edges = self.get_ids() 1613 are_allowed = np.zeros(len(ids_edges), dtype=np.bool) 1614 inds_lane = np.zeros(len(ids_edges), dtype=np.int32) 1615 for i, id_edge in zip(xrange(len(ids_edges)), ids_edges): 1616 ind_lane = get_laneindex_allowed(ids_lanes[id_edge], id_mode) 1617 are_allowed[i] = ind_lane >= 0 1618 inds_lane[i] = ind_lane 1619 return ids_edges[are_allowed], inds_lane[are_allowed] 1620 1621 def get_laneindex_allowed(self, id_edge, id_mode): 1622 """ 1623 Returns first lane index of edge id_edge on which id_mode 1624 is allowed. 1625 -1 means not allowed on edge 1626 """ 1627 return self.parent.lanes.get_laneindex_allowed(self.ids_lanes[id_edge], id_mode) 1628 1629 def get_laneid_allowed(self, id_edge, id_mode): 1630 """ 1631 Returns first lane ID of edge id_edge on which id_mode 1632 is allowed. 1633 -1 means not allowed on edge 1634 """ 1635 ids_lane = self.ids_lanes[id_edge] 1636 laneind = self.parent.lanes.get_laneindex_allowed(ids_lane, id_mode) 1637 if laneind == -1: 1638 return -1 1639 else: 1640 return ids_lane[laneind] 1641 1642 def multimake(self, ids_sumo=[], **kwargs): 1643 # fixing of insufficient shape data in edge reader 1644 return self.add_rows(n=len(ids_sumo), ids_sumo=ids_sumo, **kwargs) 1645 1646 def add_reverse(self, id_edge): 1647 self.types_spread[id_edge] = self.types_spread.choices["right"] 1648 1649 id_edge_reverse = self.add_row(ids_sumo='-'+self.ids_sumo[id_edge], 1650 ids_fromnode=self.ids_tonode[id_edge], 1651 ids_tonode=self.ids_fromnode[id_edge], 1652 types=self.types[id_edge], 1653 nums_lanes=self.num_lanes[id_edge], 1654 speeds_max=self.speed_max[id_edge], 1655 priorities=self.priority[id_edge], 1656 #lengths = length, 1657 shapes=self.shapes[id_edge][::-1], 1658 types_spread=self.types_spread[id_edge], 1659 names=self.names[id_edge], 1660 offsets_end=self.offsets_end[id_edge], 1661 widths_lanes_default=self.widths_lanes_default[id_edge], 1662 widths_sidewalk=self.widths_sidewalk[id_edge], 1663 ) 1664 # TODO: add lanes and connections 1665 return id_edge_reverse 1666 1667 def make(self, id_fromnode=0, 1668 id_tonode=0, 1669 id_sumo='', 1670 type_edge='', 1671 num_lanes=1, 1672 speed_max=50.0/3.6, 1673 priority=1, 1674 #length = 0.0, 1675 shape=[], 1676 type_spread='right', 1677 name='', 1678 offset_end=0.0, 1679 width_lanes_default=None, 1680 width_sidewalk=-1, 1681 ): 1682 1683 if len(shape) < 2: # insufficient shape data 1684 #shape = np.array([ nodes.coords[id_fromnode], nodes.coords[id_tonode] ], np.float32) 1685 # shape should be a list of np array coords 1686 # ATTENTIOn: we need to copy here, otherwise the reference 1687 # to node coordinates will be kept!! 1688 coords = self.ids_tonode.get_linktab().coords 1689 shape = [1.0*coords[id_fromnode], 1.0*coords[id_tonode]] 1690 1691 # print 'Edges.make' 1692 # print ' shape',shape,type(shape) 1693 1694 return self.add_row(ids_sumo=id_sumo, 1695 ids_fromnode=id_fromnode, 1696 ids_tonode=id_tonode, 1697 types=type_edge, 1698 nums_lanes=num_lanes, 1699 speeds_max=speed_max, 1700 priorities=priority, 1701 #lengths = length, 1702 shapes=shape, 1703 types_spread=self.types_spread.choices[type_spread], 1704 names=name, 1705 offsets_end=offset_end, 1706 widths_lanes_default=width_lanes_default, 1707 widths_sidewalk=width_sidewalk, 1708 ) 1709 1710 def make_segment_edge_map(self, ids=None, is_laneshapes=True): 1711 """ 1712 Generates a vertex matrix with line segments of all edges 1713 and a map that maps each line segment to edge index. 1714 """ 1715 # TODO: _seginds not correctly constructed for given ids 1716 1717 # here we can make some selection on edge inds 1718 if ids is None: 1719 inds = self.get_inds() 1720 else: 1721 inds = self.get_inds(ids) 1722 print 'make_linevertices', len(inds) 1723 1724 linevertices = np.zeros((0, 2, 3), np.float32) 1725 vertexinds = np.zeros((0, 2), np.int32) 1726 polyinds = [] 1727 1728 lineinds = [] 1729 #linecolors = [] 1730 #linecolors_highl = [] 1731 linebeginstyles = [] 1732 lineendstyles = [] 1733 1734 i = 0 1735 ind_line = 0 1736 1737 if is_laneshapes: 1738 ids_lanes = self.ids_lanes.get_value() 1739 laneshapes = self.parent.lanes.shapes 1740 else: 1741 polylines = self.shapes.get_value() # [inds] 1742 1743 #polylines = self.shapes[inds] 1744 # print ' len(polylines)',len(polylines) 1745 for ind in inds: 1746 1747 if is_laneshapes: 1748 polyline = laneshapes[ids_lanes[ind][0]] 1749 else: 1750 polyline = polylines[ind] 1751 1752 n_seg = len(polyline) 1753 # print ' =======',n_seg#,polyline 1754 1755 if n_seg > 1: 1756 polyvinds = range(n_seg) 1757 # print ' polyvinds\n',polyvinds 1758 vi = np.zeros((2*n_seg-2), np.int32) 1759 vi[0] = polyvinds[0] 1760 vi[-1] = polyvinds[-1] 1761 1762 # Important type conversion!! 1763 v = np.zeros((2*n_seg-2, 3), np.float32) 1764 v[0] = polyline[0] 1765 v[-1] = polyline[-1] 1766 if len(v) > 2: 1767 1768 # print 'v[1:-1]',v[1:-1] 1769 # print 'v=\n',v 1770 #m = np.repeat(polyline[1:-1],2,0) 1771 # print 'm\n',m,m.shape,m.dtype 1772 #v[1:-1] = m 1773 v[1:-1] = np.repeat(polyline[1:-1], 2, 0) 1774 vi[1:-1] = np.repeat(polyvinds[1:-1], 2) 1775 #vadd = v.reshape((-1,2,3)) 1776 # print ' v\n',v 1777 # print ' vi\n',vi 1778 1779 n_lines = len(v)/2 1780 # print ' v\n',v 1781 polyinds += n_lines*[ind] 1782 lineinds.append(np.arange(ind_line, ind_line+n_lines)) 1783 ind_line += n_lines 1784 # print ' polyinds\n',polyinds,n_lines 1785 #linecolors += n_lines*[colors[ind]] 1786 #linecolors_highl += n_lines*[colors_highl[ind]] 1787 1788 # print ' linebeginstyle',linebeginstyle,beginstyles[ind] 1789 1790 else: 1791 # empty polygon treatment 1792 v = np.zeros((0, 3), np.float32) 1793 vi = np.zeros((0), np.int32) 1794 1795 linevertices = np.concatenate((linevertices, v.reshape((-1, 2, 3)))) 1796 vertexinds = np.concatenate((vertexinds, vi.reshape((-1, 2)))) 1797 # print ' linevertex\n',linevertices 1798 i += 1 1799 self._segvertices = linevertices 1800 1801 self._edgeinds = np.array(polyinds, np.int32) 1802 self._seginds = lineinds 1803 self._segvertexinds = np.array(vertexinds, np.int32) 1804 1805 def get_dist_point_to_edge(self, p, id_edge, 1806 is_detect_initial=False, 1807 is_detect_final=False, 1808 is_return_segment=False): 1809 """ 1810 Returns eucledian distance from a point p to a given edge. 1811 As a second argument it returns the coordinates of the 1812 line segment (x1,y1,x2,y2) which is closest to the point. 1813 """ 1814 inds_seg = self.get_inds_seg_from_id_edge(id_edge) 1815 vertices = self._segvertices 1816 x1 = vertices[inds_seg, 0, 0] 1817 y1 = vertices[inds_seg, 0, 1] 1818 1819 x2 = vertices[inds_seg, 1, 0] 1820 y2 = vertices[inds_seg, 1, 1] 1821 1822 dists2 = get_dist_point_to_segs(p[0:2], x1, y1, x2, y2, 1823 is_ending=True, 1824 is_detect_initial=is_detect_initial, 1825 is_detect_final=is_detect_final 1826 ) 1827 if is_detect_final | is_detect_initial: 1828 are_finals = np.isnan(dists2) 1829 # print ' dists2',dists2 1830 # print ' are_finals',are_finals 1831 if np.all(are_finals): # point outside all segments of edge 1832 if is_return_segment: 1833 return np.nan, [np.nan, np.nan, np.nan, np.nan] 1834 else: 1835 return np.nan 1836 else: 1837 dists2[are_finals] = np.inf 1838 1839 ind_min = np.argmin(dists2) 1840 if is_return_segment: 1841 return np.sqrt(dists2[ind_min]), (x1[ind_min], y1[ind_min], x2[ind_min], y2[ind_min]) 1842 else: 1843 return np.sqrt(dists2[ind_min]) 1844 1845 def get_closest_edge(self, p, is_get2=False): 1846 """ 1847 Returns edge id which is closest to point p. 1848 Requires execution of make_segment_edge_map 1849 """ 1850 # print 'get_closest_edge',p 1851 if len(self) == 0: 1852 return np.array([], np.int) 1853 1854 if self._segvertices is None: 1855 self.make_segment_edge_map() 1856 1857 vertices = self._segvertices 1858 x1 = vertices[:, 0, 0] 1859 y1 = vertices[:, 0, 1] 1860 1861 x2 = vertices[:, 1, 0] 1862 y2 = vertices[:, 1, 1] 1863 1864 # print ' x1', x1 1865 # print ' x2', x2 1866 #halfwidths = 0.5*self.get_widths_array()[self._polyinds] 1867 d2 = get_dist_point_to_segs(p[0:2], x1, y1, x2, y2, is_ending=True) 1868 # print ' min(d2)=',np.min(d2),'argmin=',np.argmin(d2),self.get_ids(self._edgeinds[np.argmin(d2)]) 1869 if not is_get2: 1870 return self.get_ids(self._edgeinds[np.argmin(d2)]) 1871 else: 1872 # return 2 best matches 1873 ind1 = np.argmin(d2) 1874 id_edge1 = self.get_ids(self._edgeinds[ind1]) 1875 d2[ind1] = np.inf 1876 id_edge2 = self.get_ids(self._edgeinds[np.argmin(d2)]) 1877 return [id_edge1, id_edge2] 1878 1879 def get_ids_edge_from_inds_seg(self, inds_seg): 1880 return self.get_ids(self._edgeinds[inds_seg]) 1881 1882 def get_inds_seg_from_id_edge(self, id_edge): 1883 # print 'get_inds_seg_from_id_edge id_edge, ind_edge',id_edge,self.get_ind(id_edge) 1884 return self._seginds[self.get_ind(id_edge)] 1885 1886 def get_segvertices_xy(self): 1887 if self._segvertices is None: 1888 self.make_segment_edge_map() 1889 1890 vertices = self._segvertices 1891 x1 = vertices[:, 0, 0] 1892 y1 = vertices[:, 0, 1] 1893 1894 x2 = vertices[:, 1, 0] 1895 y2 = vertices[:, 1, 1] 1896 return x1, y1, x2, y2 1897 1898 def get_closest_edge_fast(self, p, x1, y1, x2, y2): 1899 """ 1900 Returns edge id which is closest to point p. 1901 Requires execution of make_segment_edge_map 1902 and predetermined 2d segment coordinates with get_segvertices_xy 1903 """ 1904 d2 = get_dist_point_to_segs(p[0:2], x1, y1, x2, y2, is_ending=True) 1905 # print ' min(d2)=',np.min(d2),'argmin=',np.argmin(d2),self.get_ids(self._edgeinds[np.argmin(d2)]) 1906 return self.get_ids(self._edgeinds[np.argmin(d2)]) 1907 1908 def export_sumoxml(self, filepath, encoding='UTF-8'): 1909 try: 1910 fd = open(filepath, 'w') 1911 except: 1912 print 'WARNING in export_sumoxml: could not open', filepath 1913 return False 1914 fd.write('<?xml version="1.0" encoding="%s"?>\n' % encoding) 1915 1916 fd.write(xm.begin('edges')) 1917 indent = 2 1918 self.write_xml(fd, indent=indent, is_print_begin_end=False) 1919 self.parent.roundabouts.write_xml(fd, indent=indent, is_print_begin_end=False) 1920 fd.write(xm.end('edges')) 1921 fd.close() 1922 1923 def update(self, ids=None, is_update_lanes=False): 1924 print 'Edges.update' 1925 1926 if ids is None: 1927 self.widths.value = self.nums_lanes.value * self.widths_lanes_default.value \ 1928 + (self.widths_sidewalk.value >= 0) * (self.widths_sidewalk.value-self.widths_lanes_default.value) 1929 1930 # print ' self.widths.values = \n',self.widths.value 1931 #polylines = polypoints_to_polylines(self.shapes.value) 1932 # print ' polylines[0:4]=\n',polylines[0:4] 1933 # print ' polylines[3].shape',polylines[3].shape 1934 #self.lengths.value = get_length_polylines(polypoints_to_polylines(self.shapes.value)) 1935 # if len(self)>10: 1936 # print ' shapes',self.shapes[1:10] 1937 # print ' shapes.get_value',self.shapes.get_value()[0:9] 1938 # print ' shapes.value',self.shapes.value[0:9] 1939 # else: 1940 # print ' only len %d'%len(self) 1941 self.lengths.value = get_length_polypoints(self.shapes.value) 1942 ids = self.get_ids() 1943 else: 1944 self.widths[ids] = self.nums_lanes[ids] * self.widths_lanes_default[ids] \ 1945 + (self.widths_sidewalk[ids] >= 0) * (self.widths_sidewalk[ids]-self.widths_lanes_default[ids]) 1946 # print ' self.shapes[ids]',self.shapes[ids],type(self.shapes[ids]) 1947 self.lengths[ids] = get_length_polypoints(self.shapes[ids]) 1948 1949 self.widths.set_modified(True) 1950 self.lengths.set_modified(True) 1951 1952 if is_update_lanes: 1953 # print 'recalc laneshapes',ids 1954 lanes = self.get_lanes() 1955 for id_edge in ids: 1956 lanes.reshape_edgelanes(id_edge) 1957 self.make_segment_edge_map() 1958 1959 def set_shapes(self, ids, vertices, is_update_lanes=True): 1960 # print 'set_shapes',ids,vertices 1961 1962 self.shapes[ids] = vertices 1963 if not hasattr(ids, '__iter__'): 1964 ids = [ids] 1965 self.update(ids, is_update_lanes=is_update_lanes) 1966 1967 def get_coord_from_pos(self, id_edge, pos): 1968 """ 1969 Returns network coordinate on edge id_edge at position pos. 1970 """ 1971 return get_coord_on_polyline_from_pos(self.shapes[id_edge], pos) 1972 1973 def get_pos_from_coord(self, id_edge, coord): 1974 """ 1975 Returns position on edge id_edge with coord 1976 perpendicularly projected on edge. 1977 """ 1978 1979 return get_pos_on_polyline_from_coord(self.shapes[id_edge], coord) 1980 1981 def update_lanes(self, id_edge, ids_lane): 1982 # print 'update_lanes',id_edge,self.ids_sumo[id_edge] ,ids_lanes,self.nums_lanes[id_edge] 1983 # if self._is_laneshape: 1984 # laneshapes = edges.get_laneshapes(self._id_edge, ) 1985 # lanes.shapes[self._ids_lanes[0]] 1986 if len(ids_lane) == 0: 1987 # no lanes given...make some with default values 1988 ids_lane = [] 1989 lanes = self.get_lanes() 1990 for i in xrange(self.nums_lanes[id_edge]): 1991 id_lane = lanes.make(index=i, id_edge=id_edge) 1992 ids_lane.append(id_lane) 1993 1994 self.ids_lanes[id_edge] = ids_lane 1995 1996 def correct_endpoint(self): 1997 """ 1998 Corrects end-point for older versione. 1999 """ 2000 ids_sumo = self.ids_sumo.get_value() 2001 types_spread = self.types_spread.get_value() 2002 shapes = self.shapes.get_value() 2003 ids_fromnode = self.ids_fromnode.get_value() 2004 ids_tonode = self.ids_tonode.get_value() 2005 coords = self.parent.nodes.coords 2006 ind = 0 2007 is_corrected = False 2008 eps = 50.0 2009 for id_sumo, type_spread, shape, id_fromnode, id_tonode in zip(ids_sumo, types_spread, shapes, ids_fromnode, ids_tonode): 2010 2011 inds_oppo = np.flatnonzero((ids_tonode == id_fromnode) & (ids_fromnode == id_tonode)) 2012 if len(inds_oppo) >= 1: 2013 ind_oppo = inds_oppo[0] 2014 # print ' correct',id_sumo,ids_sumo[ind_oppo] 2015 2016 ind_oppo = inds_oppo[0] 2017 shape_oppo = list(shapes[ind_oppo]) 2018 shape_oppo.reverse() 2019 # print ' shape',shape 2020 # print ' shape',shape_oppo 2021 # print ' id_fromnode',id_fromnode,ids_tonode[ind_oppo] 2022 # print ' id_tomnode',id_tonode,ids_fromnode[ind_oppo] 2023 # print ' coords',coords[id_fromnode], coords[id_tonode] 2024 if len(shape_oppo) == len(shape): 2025 2026 shapes[ind][0] = coords[id_fromnode] 2027 shapes[ind_oppo][-1] = coords[id_fromnode] 2028 #types_spread[inds_oppo[0]] = 0 2029 #types_spread[ind] = 0 2030 is_corrected = True 2031 ind += 1 2032 2033 if is_corrected: 2034 self.update(is_update_lanes=True) 2035 2036 def correct_spread(self): 2037 """ 2038 Corrects spread type for older versione. 2039 """ 2040 ids_sumo = self.ids_sumo.get_value() 2041 types_spread = self.types_spread.get_value() 2042 shapes = self.shapes.get_value() 2043 ind = 0 2044 is_corrected = False 2045 eps = 50.0 2046 for id_sumo, type_spread, shape in zip(ids_sumo, types_spread, shapes): 2047 if type_spread == 1: 2048 if id_sumo[0] == '-': 2049 inds_oppo = np.flatnonzero(ids_sumo == id_sumo[1:]) 2050 if len(inds_oppo) == 1: 2051 ind_oppo = inds_oppo[0] 2052 shape_oppo = np.array(shapes[ind_oppo], np.float32) 2053 if len(shape_oppo) == len(shape): 2054 shape_oppo = list(shapes[ind_oppo]) 2055 shape_oppo.reverse() 2056 shape_oppo = np.array(shape_oppo, np.float32) 2057 dist = np.sum(np.abs(shape_oppo - np.array(shape, np.float32)))/float(len(shape)) 2058 # print ' id_sumo,dist',id_sumo,dist,eps 2059 if dist < eps: 2060 types_spread[inds_oppo[0]] = 0 2061 types_spread[ind] = 0 2062 is_corrected = True 2063 ind += 1 2064 2065 if is_corrected: 2066 self.update(is_update_lanes=True) 2067 2068 2069class Nodes(am.ArrayObjman): 2070 # http://www.sumo.dlr.de/userdoc/Networks/Building_Networks_from_own_XML-descriptions.html#Node_Descriptions 2071 def __init__(self, parent, 2072 **kwargs): 2073 ident = 'nodes' 2074 self._init_objman(ident=ident, parent=parent, name='Nodes', 2075 xmltag=('nodes', 'node', 'ids_sumo'), 2076 version=0.1, 2077 **kwargs) 2078 self._init_attributes() 2079 2080 def _init_attributes(self): 2081 2082 self.add_col(SumoIdsConf('Node')) 2083 2084 self.add_col(am.ArrayConf('coords', np.zeros(3, dtype=np.float32), 2085 dtype=np.float32, 2086 groupnames=['state'], 2087 perm='r', 2088 name='Coords', 2089 unit='m', 2090 info='Node center coordinates.', 2091 )) 2092 2093 self.add_col(am.ArrayConf('radii', 5.0, 2094 dtype=np.float32, 2095 groupnames=['state'], 2096 perm='rw', 2097 name='Radius', 2098 info='Node radius', 2099 )) 2100 2101 self.add_col(am.ListArrayConf('shapes', 2102 groupnames=['_private'], 2103 perm='rw', 2104 name='Shape', 2105 unit='m', 2106 info='Node shape as list of 3D shape coordinates representing a polyline.', 2107 is_plugin=True, 2108 xmltag='shape', 2109 )) 2110 2111 self.add_col(am.ArrayConf('are_costum_shape', False, 2112 dtype=np.bool, 2113 groupnames=['state'], 2114 perm='rw', 2115 name='costum shape', 2116 info='Node has a custom shape.', 2117 xmltag='customShape', 2118 )) 2119 2120 self.add(cm.AttrConf('radius_default', 3.0, 2121 groupnames=['options'], 2122 perm='rw', 2123 unit='m', 2124 name='Default radius', 2125 info='Default node radius.', 2126 )) 2127 2128 self.add_col(am.ArrayConf('types', 0, 2129 choices={ 2130 "priority": 0, 2131 "traffic_light": 1, 2132 "right_before_left": 2, 2133 "unregulated": 3, 2134 "priority_stop": 4, 2135 "traffic_light_unregulated": 5, 2136 "allway_stop": 6, 2137 "rail_signal": 7, 2138 "zipper": 8, 2139 "traffic_light_right_on_red": 9, 2140 "rail_crossing": 10, 2141 "dead_end": 11, 2142 }, 2143 dtype=np.int32, 2144 perm='rw', 2145 name='Type', 2146 info='Node type.', 2147 xmltag='type', 2148 )) 2149 2150 # this is actually a property defined in the TLS logic 2151 self.add_col(am.ArrayConf('types_tl', 0, 2152 dtype=np.int32, 2153 choices={ 2154 "none": 0, 2155 "static": 1, 2156 "actuated": 2, 2157 }, 2158 perm='rw', 2159 name='TL type', 2160 info='Traffic light type.', 2161 xmltag='tlType', 2162 )) 2163 2164 self.add_col(am.ArrayConf('turnradii', 1.5, 2165 dtype=np.float32, 2166 groupnames=['state'], 2167 perm='rw', 2168 name='Turn rad', 2169 unit='m', 2170 info='optional turning radius (for all corners) for that node.', 2171 xmltag='radius', 2172 )) 2173 2174 self.add_col(am.ArrayConf('are_keep_clear', True, 2175 dtype=np.bool, 2176 groupnames=['state'], 2177 perm='rw', 2178 name='keep clear', 2179 info='Whether the junction-blocking-heuristic should be activated at this node.', 2180 xmltag='keepClear', 2181 )) 2182 2183 def set_edges(self, edges): 2184 2185 self.add_col(am.IdlistsArrayConf('ids_incoming', edges, 2186 groupnames=['state'], 2187 name='ID incoming', 2188 info='ID list of incoming edges.', 2189 )) 2190 2191 self.add_col(am.IdlistsArrayConf('ids_outgoing', edges, 2192 groupnames=['state'], 2193 name='ID outgoing', 2194 info='ID list of outgoing edges.', 2195 )) 2196 2197 self.add_col(am.IdlistsArrayConf('ids_controlled', edges, 2198 groupnames=['state'], 2199 name='IDs controlled', 2200 info='ID list of controlled edges. Edges which shall be controlled by a joined TLS despite being incoming as well as outgoing to the jointly controlled nodes.', 2201 xmltag='controlledInner', 2202 )) 2203 if self.get_version() < 0.1: 2204 self.delete('ids_tl_prog') 2205 self.turnradii.xmltag = 'radius' 2206 self.are_keep_clear.xmltag = 'keepClear' 2207 self.types_tl.xmltag = 'tlType' 2208 self.add_col(am.IdlistsArrayConf('ids_controlled', edges, 2209 groupnames=['state'], 2210 name='IDs controlled', 2211 info='ID list of controlled edges. Edges which shall be controlled by a joined TLS despite being incoming as well as outgoing to the jointly controlled nodes.', 2212 )) 2213 2214 def set_tlss(self, tlss): 2215 2216 self.add_col(am.IdsArrayConf('ids_tls', tlss, 2217 groupnames=['state'], 2218 name='ID Tls', 2219 info='ID of traffic light system (TLS). Nodes with the same tls-value will be joined into a single traffic light system.', 2220 xmltag='tl', 2221 )) 2222 2223 def multimake(self, ids_sumo=[], **kwargs): 2224 return self.add_rows(n=len(ids_sumo), ids_sumo=ids_sumo, **kwargs) 2225 2226 def configure_tls(self, id_node, id_tls, typecode=None, tlstype=None, nodetype="traffic_light"): 2227 if typecode is None: 2228 self.types_tl[id_node] = self.types_tl.choices[tlstype] 2229 else: 2230 self.types_tl[id_node] = typecode 2231 2232 self.types[id_node] = self.types.choices[nodetype] 2233 self.ids_tls[id_node] = id_tls 2234 2235 def remove_tls(self, id_node=None, id_tls=None, nodetype="priority"): 2236 if id_tls is not None: 2237 ids_node = self.select_ids(self.ids_tls.get_value() == id_tls) 2238 2239 self.types_tl[ids_node] = self.types_tl.choices["none"] 2240 self.types[ids_node] = self.types.choices[nodetype] 2241 self.ids_tls[ids_node] = -1 2242 else: 2243 self.types_tl[id_node] = self.types_tl.choices["none"] 2244 self.types[id_node] = self.types.choices[nodetype] 2245 self.ids_tls[id_node] = -1 2246 2247 def make(self, id_sumo='', nodetype='priority', coord=[], 2248 type_tl='static', id_tl_prog=0, 2249 shape=[], 2250 is_costum_shape=False, 2251 turnradius=1.5, 2252 is_keep_clear=True): 2253 2254 return self.add_row(ids_sumo=id_sumo, 2255 types=self.types.choices[nodetype], 2256 coords=coord, 2257 are_costum_shape=is_costum_shape, 2258 shape=shape, 2259 types_tl=self.types_tl.choices[type_tl], 2260 ids_tl_prog=id_tl_prog, 2261 turnradii=turnradius, 2262 are_keep_clear=is_keep_clear, 2263 ) 2264 2265 def add_outgoing(self, id_node, id_edge): 2266 if self.ids_outgoing[id_node] is not None: 2267 if id_edge not in self.ids_outgoing[id_node]: 2268 self.ids_outgoing[id_node].append(id_edge) 2269 else: 2270 self.ids_outgoing[id_node] = [id_edge] 2271 2272 def add_incoming(self, id_node, id_edge): 2273 # print 'add_incoming id_node,id_edge',id_node,id_edge 2274 # print ' ids_incoming',self.ids_incoming[id_node],type(self.ids_incoming[id_node]) 2275 if self.ids_incoming[id_node] is not None: 2276 if id_edge not in self.ids_incoming[id_node]: 2277 self.ids_incoming[id_node].append(id_edge) 2278 else: 2279 self.ids_incoming[id_node] = [id_edge] 2280 2281 def export_sumoxml(self, filepath, encoding='UTF-8'): 2282 try: 2283 fd = open(filepath, 'w') 2284 except: 2285 print 'WARNING in export_sumoxml: could not open', filepath 2286 return False 2287 fd.write('<?xml version="1.0" encoding="%s"?>\n' % encoding) 2288 indent = 0 2289 self.write_xml(fd, indent) 2290 fd.close() 2291 2292 def write_xml(self, fd, indent): 2293 # print 'Nodes.write_xml' 2294 xmltag, xmltag_item, attrname_id = self.xmltag 2295 attrsman = self.get_attrsman() 2296 attrconfig_id = attrsman.get_config(attrname_id) # getattr(self.get_attrsman(), attrname_id) 2297 xmltag_id = attrconfig_id.xmltag 2298 #attrsman = self.get_attrsman() 2299 coordsconfig = attrsman.get_config('coords') 2300 shapesconfig = attrsman.get_config('shapes') 2301 colconfigs = attrsman.get_colconfigs(is_all=True) 2302 2303 # print ' header' 2304 fd.write(xm.start(xmltag, indent)) 2305 # print ' ', self.parent.get_attrsman().get_config('version').attrname,self.parent.get_attrsman().get_config('version').get_value() 2306 #fd.write( self.parent.get_attrsman().get_config('version').write_xml(fd) ) 2307 self.parent.get_attrsman().get_config('version').write_xml(fd) 2308 fd.write(xm.stop()) 2309 2310 fd.write(xm.start('location', indent+2)) 2311 # print ' groups:',self.parent.get_attrsman().get_groups() 2312 2313 for attrconfig in self.parent.get_attrsman().get_group('location'): 2314 # print ' locationconfig',attrconfig.attrname 2315 attrconfig.write_xml(fd) 2316 fd.write(xm.stopit()) 2317 2318 ids = self.get_ids() 2319 for _id, is_costum_shape in zip(ids, self.are_costum_shape[ids]): 2320 fd.write(xm.start(xmltag_item, indent+2)) 2321 2322 # print ' make tag and id',_id 2323 fd.write(xm.num(xmltag_id, attrconfig_id[_id])) 2324 2325 # print ' write columns' 2326 for attrconfig in colconfigs: 2327 # print ' colconfig',attrconfig.attrname 2328 if attrconfig == coordsconfig: 2329 x, y, z = attrconfig[_id] 2330 fd.write(xm.num('x', x)) 2331 fd.write(xm.num('y', y)) 2332 fd.write(xm.num('z', z)) 2333 2334 elif attrconfig == shapesconfig: 2335 # write only if customshaped 2336 if is_costum_shape: 2337 attrconfig.write_xml(fd, _id) 2338 2339 elif attrconfig != attrconfig_id: 2340 attrconfig.write_xml(fd, _id) 2341 2342 fd.write(xm.stopit()) 2343 2344 fd.write(xm.end(xmltag, indent)) 2345 2346 # def clean_node(self, id_node): 2347 2348 def clean(self, is_reshape_edgelanes=False, nodestretchfactor=1.2, n_min_nodeedges=2): 2349 # is_reshape_edgelanes = False, nodestretchfactor = 2.8 2350 print 'Nodes.clean', len(self), 'is_reshape_edgelanes', is_reshape_edgelanes 2351 2352 edges = self.parent.edges 2353 lanes = self.parent.lanes 2354 rad_min = self.radius_default.value 2355 2356 # print ' id(edges.shapes),id(edges.shapes.value)', id(edges.shapes),id(edges.shapes.value)#,edges.shapes.value 2357 # print ' id(self.coords),id(self.coords.value)', id(self.coords),id(self.coords.value)#,self.coords.value 2358 # print ' self.coords.value.shape',self.coords.value.shape 2359 # print ' len(self.coords),self.coords.shape',len(self.coords.value),self.coords.value 2360 for id_node in self.get_ids(): 2361 ind_node = self.get_inds(id_node) 2362 # if id_node in TESTNODES: 2363 # print 79*'_' 2364 # print ' node',id_node 2365 # print ' coords',self.coords[id_node] 2366 # print ' coords',TESTNODES[0],self.coords[TESTNODES[0]] 2367 # print ' coords',TESTNODES[1],self.coords[TESTNODES[1]] 2368 # print ' radii',self.radii[id_node] 2369 2370 # attention, this is s safe method in case 2371 # that ids_outgoing and ids_incoming are not yet defined 2372 ids_edge_out = edges.select_ids(edges.ids_fromnode.value == id_node) 2373 ids_edge_in = edges.select_ids(edges.ids_tonode.value == id_node) 2374 2375 if (len(ids_edge_out) > 0) | (len(ids_edge_in) > 0): 2376 # distanza ad altri nodi 2377 #d = np.sum(np.abs(self.coords[id_node]-self.coords.value),1) 2378 #d = np.linalg.norm(self.coords[id_node]-self.coords.value,1) 2379 coords = self.coords[id_node] 2380 d = get_norm_2d(coords-self.coords.value) 2381 d[ind_node] = np.inf 2382 d_min = np.min(d) 2383 # print ' d_min',d_min 2384 2385 # estimate circumference of junction and determine node radius 2386 n_edges = len(ids_edge_in) + len(ids_edge_out) 2387 width_av = np.mean(np.concatenate((edges.widths[ids_edge_in], edges.widths[ids_edge_out]))) 2388 2389 # here we assume a node with 6 entrance sides and a and 2 average width edges per side 2390 #circum = 2.0*max(6,n_edges)*width_av 2391 circum = nodestretchfactor*max(2, n_edges)*width_av 2392 2393 # print ' n_edges,width_av,radius',n_edges,width_av,max(6,n_edges)*width_av/(2*np.pi) 2394 radius = min(max(circum/(n_min_nodeedges*np.pi), rad_min), 0.4*d_min) 2395 self.radii[id_node] = radius 2396 2397 # if id_node in TESTNODES: 2398 # print ' AFTER change radius:'#OK 2399 # print ' coords',TESTNODES[0],self.coords[TESTNODES[0]] 2400 # print ' coords',TESTNODES[1],self.coords[TESTNODES[1]] 2401 2402 for id_edge in ids_edge_in: 2403 # print ' in edge',id_edge 2404 shape = edges.shapes[id_edge] 2405 n_shape = len(shape) 2406 # edges.shapes[id_edge][::-1]: 2407 for i in xrange(n_shape-1, -1, -1): 2408 d = get_norm_2d(np.array([shape[i]-coords]))[0] 2409 # print ' i,d,r',i , d, radius,d>radius 2410 if d > radius: 2411 # print ' **',i,d, radius 2412 break 2413 x, y = shape[i][:2] 2414 # print 'shape',shape, 2415 #dx,dy = shape[i+1][:2] - shape[i][:2] 2416 dx, dy = coords[:2] - shape[i][:2] 2417 dn = np.sqrt(dx*dx + dy*dy) 2418 x1 = x + (d-radius)*dx/dn 2419 y1 = y + (d-radius)*dy/dn 2420 2421 if i == n_shape-1: 2422 2423 shape[-1][:2] = [x1, y1] 2424 edges.shapes[id_edge] = shape 2425 2426 else: # elif i>0: 2427 shape[i+1][:2] = [x1, y1] 2428 edges.shapes[id_edge] = shape[:i+2] 2429 2430 # print ' x,y',x,y 2431 # print ' x1,y1',x1,y1 2432 # print ' shape[:i+2]',shape[:i+2] 2433 # print ' shapes[id_edge]',edges.shapes[id_edge] 2434 if is_reshape_edgelanes: 2435 lanes.reshape_edgelanes(id_edge) 2436 2437 for id_edge in ids_edge_out: 2438 # print ' out edge',id_edge 2439 shape = edges.shapes[id_edge] 2440 n_shape = len(shape) 2441 # edges.shapes[id_edge][::-1]: 2442 for i in xrange(n_shape): 2443 d = get_norm_2d(np.array([shape[i]-coords]))[0] 2444 # print ' i,d,r',i , d, radius,d>radius 2445 if d > radius: 2446 # print ' **',i,d, radius 2447 break 2448 x, y = coords[:2] # shape[i-1][:2] 2449 # print 'shape',shape, 2450 #dx,dy = shape[i][:2]- shape[i-1][:2] 2451 dx, dy = shape[i][:2] - coords[:2] 2452 dn = np.sqrt(dx*dx + dy*dy) 2453 x1 = x + (radius)*dx/dn 2454 y1 = y + (radius)*dy/dn 2455 if i == 0: 2456 shape[0][:2] = [x1, y1] 2457 edges.shapes[id_edge] = shape 2458 2459 elif i < n_shape: 2460 2461 shape[i-1][:2] = [x1, y1] 2462 edges.shapes[id_edge] = shape[i-1:] 2463 # print ' x,y',x,y 2464 # print ' x1,y1',x1,y1 2465 # print ' shape[:i+2]',shape[:i+2] 2466 # print ' shapes[id_edge]',edges.shapes[id_edge] 2467 if is_reshape_edgelanes: 2468 lanes.reshape_edgelanes(id_edge) 2469 2470 self.radii.set_modified(True) 2471 edges.shapes.set_modified(True) 2472 2473 2474class Network(cm.BaseObjman): 2475 def __init__(self, parent=None, name='Network', **kwargs): 2476 print 'Network.__init__', parent, name 2477 self._init_objman(ident='net', parent=parent, name=name, 2478 # xmltag = 'net',# no, done by netconvert 2479 version=0.1, 2480 **kwargs) 2481 attrsman = self.set_attrsman(cm.Attrsman(self)) 2482 # print ' Network.parent',self.parent 2483 self._init_attributes() 2484 2485 def _init_attributes(self): 2486 attrsman = self.get_attrsman() 2487 self.version = attrsman.add(cm.AttrConf('version', '0.25', 2488 groupnames=['aux'], 2489 perm='r', 2490 name='Network version', 2491 info='Sumo network version', 2492 xmltag='version' 2493 )) 2494 2495 self.modes = attrsman.add(cm.ObjConf(Modes(self))) 2496 self.modes.clear() 2497 self.modes.add_default() 2498 2499 # print 'Network.__init__' 2500 # print ' MODES.values()',MODES.values() 2501 # print ' MODES.keys()',MODES.keys() 2502 2503 # self.modes.print_attrs() 2504 ## 2505 2506 ## 2507 self.nodes = attrsman.add(cm.ObjConf(Nodes(self))) 2508 self.edges = attrsman.add(cm.ObjConf(Edges(self))) 2509 self.lanes = attrsman.add(cm.ObjConf(Lanes(self))) 2510 2511 self.edges.set_nodes(self.nodes) 2512 self.edges.set_lanes(self.lanes) 2513 self.nodes.set_edges(self.edges) 2514 self.roundabouts = attrsman.add(cm.ObjConf(Roundabouts(self, self.edges, self.nodes))) 2515 self.connections = attrsman.add(cm.ObjConf(Connections(self))) 2516 self.crossings = attrsman.add(cm.ObjConf(Crossings(self))) 2517 2518 self.tlss = attrsman.add(cm.ObjConf(TrafficLightSystems(self))) 2519 self.nodes.set_tlss(self.tlss) 2520 2521 self.ptstops = attrsman.add(cm.ObjConf(pt.PtStops(self))) 2522 2523 self._offset = attrsman.add(cm.AttrConf('_offset', np.array([0.0, 0.0], dtype=np.float32), 2524 groupnames=['location', ], 2525 perm='r', 2526 name='Offset', 2527 info='Network offset in WEP coordinates', 2528 xmltag='netOffset', 2529 xmlsep=',', 2530 )) 2531 2532 self._projparams = attrsman.add(cm.AttrConf('_projparams', "!", 2533 groupnames=['location', ], 2534 perm='r', 2535 name='Projection', 2536 info='Projection parameters', 2537 xmltag='projParameter', 2538 )) 2539 2540 self._boundaries = attrsman.add(cm.AttrConf('_boundaries', np.array([0.0, 0.0, 0.0, 0.0], dtype=np.float32), 2541 groupnames=['location', ], 2542 perm='r', 2543 name='Boundaries', 2544 unit='m', 2545 info='Network boundaries', 2546 xmltag='convBoundary', 2547 xmlsep=',', 2548 )) 2549 2550 self._boundaries_orig = attrsman.add(cm.AttrConf('_boundaries_orig', np.array([0.0, 0.0, 0.0, 0.0]), 2551 groupnames=['location', ], 2552 perm='r', 2553 name='Orig. boundaries', 2554 info='Original network boundaries', 2555 xmltag='origBoundary', 2556 xmlsep=',', 2557 )) 2558 2559 def _init_constants(self): 2560 pass 2561 #self._oldoffset = self._offset.copy() 2562 # print 'net._init_constants',self._offset,self._oldoffset 2563 # def set_oldoffset(self, offset): 2564 # """ 2565 # Set explicitely an old net offset, if existing. 2566 # This allows to update coordinates and shapes outside the network. 2567 # 2568 # """ 2569 # self._oldoffset = offset 2570 2571 def set_version(self, version): 2572 self.version = version 2573 2574 def get_version(self): 2575 return self.version 2576 2577 def is_empty(self): 2578 return (len(self.nodes) == 0) & (len(self.edges) == 0) 2579 2580 def set_offset(self, offset): 2581 # if (offset is not self._offset) : 2582 # self._oldoffset = self._offset.copy() 2583 self._offset = offset 2584 2585 def get_offset(self): 2586 return self._offset 2587 2588 # def is_offset_change(self): 2589 # """ 2590 # Returns true if offset changed be approx 1 mm after last net import 2591 # """ 2592 # return np.sum(abs(self._oldoffset - self._offset))>0.002 2593 2594 # def get_deltaoffset(self): 2595 # return self._offset - self._oldoffset 2596 2597 # def remove_oldoffset(self): 2598 # self._oldoffset = None 2599 2600 def set_boundaries(self, convBoundary, origBoundary=None): 2601 """ 2602 Format of Boundary box 2603 [MinX, MinY ,MaxX, MaxY ] 2604 2605 """ 2606 self._boundaries = convBoundary 2607 if origBoundary is None: 2608 self._boundaries_orig = self._boundaries 2609 else: 2610 self._boundaries_orig = origBoundary 2611 2612 def get_boundaries(self, is_netboundaries=False): 2613 if is_netboundaries: 2614 return self._boundaries 2615 else: 2616 return self._boundaries, self._boundaries_orig 2617 2618 def merge_boundaries(self, convBoundary, origBoundary=None): 2619 """ 2620 Format of Boundary box 2621 [MinX, MinY ,MaxX, MaxY ] 2622 2623 """ 2624 # print 'mergeBoundaries' 2625 self._boundaries = self.get_boundary_union(convBoundary, self._boundaries) 2626 if origBoundary is None: 2627 self._boundaries_orig = self._boundaries 2628 else: 2629 self._boundaries_orig = self.get_boundary_union(origBoundary, self._boundaries_orig) 2630 # print ' self._boundaries_orig =',self._boundaries_orig 2631 # print ' self._boundaries =',self._boundaries 2632 2633 def get_boundary_union(self, BB1, BB2): 2634 return [min(BB1[0], BB2[0]), min(BB1[1], BB2[1]), max(BB1[2], BB2[2]), max(BB1[3], BB2[3])] 2635 2636 def intersects_boundaries(self, BB): 2637 """ 2638 Tests if the given Bounding Box or line intersects with 2639 the network boundaries. 2640 2641 Returns True if it is partially inside, or touching the 2642 border. 2643 Format of Boundary box 2644 [MinX, MinY ,MaxX, MaxY ] 2645 0 1 2 3 2646 2647 Returns False otherwise 2648 """ 2649 # print 'intersects_boundaries' 2650 # print ' self',self._boundaries 2651 # print ' BB',BB 2652 # print ' return',( (self._boundaries[2] >= BB[0]) & (self._boundaries[0] <= BB[2]) & 2653 # (self._boundaries[3] >= BB[1]) & (self._boundaries[1] <= BB[3]) ) 2654 2655 return ((self._boundaries[2] >= BB[0]) & (self._boundaries[0] <= BB[2]) & 2656 (self._boundaries[3] >= BB[1]) & (self._boundaries[1] <= BB[3])) 2657 # if ( (self._boundaries[2] >= BB[0]) & (self._boundaries[0] <= BB[2]) & 2658 # (self._boundaries[3] >= BB[1]) & (self._boundaries[1] <= BB[3]) ): 2659 # return True 2660 # else: 2661 # return False 2662 2663 def get_projparams(self): 2664 return self._projparams 2665 2666 def set_projparams(self, projparams="!"): 2667 # print 'setprojparams',projparams 2668 self._projparams = projparams 2669 2670 def get_rootfilename(self): 2671 if self.parent is not None: # scenario exists 2672 return self.parent.get_rootfilename() 2673 else: 2674 return self.get_ident() 2675 2676 def get_rootfilepath(self): 2677 if self.parent is not None: 2678 return self.parent.get_rootfilepath() 2679 else: 2680 return os.path.join(os.getcwd(), self.get_rootfilename()) 2681 2682 def get_filepath(self): 2683 """ 2684 Default network filepath. 2685 """ 2686 return self.get_rootfilepath()+'.net.xml' 2687 2688 def get_addfilepath(self): 2689 """ 2690 Default filepath for additional files. 2691 """ 2692 return self.get_rootfilepath()+'.add.xml' 2693 2694 def clear_net(self): 2695 """ 2696 Remove all netelements. 2697 """ 2698 self.clear() 2699 self.modes.add_default() 2700 # do other cleanup jobs 2701 2702 def call_netedit(self, filepath=None, is_maps=False, is_poly=True): 2703 2704 #filepath = self.export_netxml(filepath) 2705 if filepath is None: 2706 filepath = self.get_filepath() 2707 2708 # remove old netfile, is exists 2709 if os.path.isfile(filepath): 2710 os.remove(filepath) 2711 2712 filepath_edges, filepath_nodes, filepath_connections, filepath_tlss = self.export_painxml(filepath=filepath) 2713 if filepath_edges != "": 2714 # print ' netconvert: success' 2715 names = os.path.basename(filepath).split('.') 2716 dirname = os.path.dirname(filepath) 2717 if len(names) >= 3: 2718 rootname = '.'.join(names[:-2]) 2719 elif len(names) <= 2: 2720 rootname = names[0] 2721 2722 addfilepath = self.export_addxml(is_ptstops=True, is_poly=False) 2723 if addfilepath is not False: 2724 option_addfiles_in = ' --sumo-additionals-file '+filepathlist_to_filepathstring(addfilepath) 2725 else: 2726 option_addfiles_in = '' 2727 2728 option_addfiles_out = ' --additionals-output ' + filepathlist_to_filepathstring(self.get_addfilepath()) 2729 2730 configfilepath = self.write_guiconfig(rootname, dirname, is_maps) 2731 2732 #+ ' --sumo-net-file ' + filepathlist_to_filepathstring(filepath) 2733 2734 cml = 'netedit --ignore-errors.edge-type'\ 2735 + ' --node-files '+filepathlist_to_filepathstring(filepath_nodes)\ 2736 + ' --edge-files '+filepathlist_to_filepathstring(filepath_edges)\ 2737 + ' --connection-files '+filepathlist_to_filepathstring(filepath_connections)\ 2738 + ' --output-file '+filepathlist_to_filepathstring(filepath)\ 2739 + ' --gui-settings-file ' + filepathlist_to_filepathstring(configfilepath)\ 2740 + option_addfiles_in + option_addfiles_out 2741 #+ ' --output-prefix '+ filepathlist_to_filepathstring(os.path.join(dirname,rootname)) 2742 2743 if len(self.tlss) > 0: 2744 cml += ' --tllogic-files '+filepathlist_to_filepathstring(filepath_tlss) 2745 2746 proc = subprocess.Popen(cml, shell=True) 2747 print ' run_cml cml=', cml 2748 # print ' pid = ',proc.pid 2749 proc.wait() 2750 if proc.returncode == 0: 2751 print ' netedit:success' 2752 2753 return self.import_netxml() 2754 # return self.import_xml() # use if netedit exports to plain xml files 2755 else: 2756 print ' netedit:error' 2757 return False 2758 else: 2759 print ' netconvert:error' 2760 return False 2761 2762 def call_sumogui(self, filepath=None, is_maps=True, is_poly=True): 2763 2764 if filepath is None: 2765 filepath = self.get_filepath() 2766 dirname = os.path.dirname(filepath) 2767 names = os.path.basename(filepath).split('.') 2768 dirname = os.path.dirname(filepath) 2769 if len(names) >= 3: 2770 rootname = '.'.join(names[:-2]) 2771 elif len(names) <= 2: 2772 rootname = names[0] 2773 2774 configfilepath = self.write_guiconfig(rootname, dirname, is_maps) 2775 2776 #addfilepath = self.export_addxml(is_ptstops = True, is_poly = True) 2777 2778 stopfilepath = self.ptstops.export_sumoxml() 2779 if is_poly: 2780 polyfilepath = self.parent.landuse.export_polyxml() 2781 else: 2782 polyfilepath = None 2783 2784 # print ' is_polystopfilepath,polyfilepath',is_poly,stopfilepath,polyfilepath 2785 addfilepathlist = [] 2786 if (stopfilepath is not None): 2787 addfilepathlist.append(stopfilepath) 2788 2789 if (polyfilepath is not None): 2790 addfilepathlist.append(polyfilepath) 2791 2792 if len(addfilepathlist) > 0: 2793 option_addfiles = ' --additional-files '+filepathlist_to_filepathstring(addfilepathlist) 2794 else: 2795 option_addfiles = '' 2796 2797 # if addfilepath is not False: 2798 # option_addfiles = ' --additional-files '+filepathlist_to_filepathstring(addfilepath) 2799 # else: 2800 # option_addfiles = '' 2801 2802 cml = 'sumo-gui '\ 2803 + ' --net-file '+filepathlist_to_filepathstring(filepath)\ 2804 + ' --gui-settings-file '+filepathlist_to_filepathstring(configfilepath)\ 2805 + option_addfiles 2806 2807 proc = subprocess.Popen(cml, shell=True) 2808 print ' run_cml cml=', cml 2809 print ' pid = ', proc.pid 2810 proc.wait() 2811 return proc.returncode 2812 2813 def write_guiconfig(self, rootname=None, dirname=None, is_maps=False): 2814 2815 # check if there are maps 2816 maps = None 2817 if is_maps: 2818 if self.parent is not None: 2819 maps = self.parent.landuse.maps 2820 2821 # write netedit configfile 2822 templatedirpath = os.path.dirname(os.path.abspath(__file__)) 2823 fd_template = open(os.path.join(templatedirpath, 'netedit_config.xml'), 'r') 2824 2825 if (rootname is not None) & (dirname is not None): 2826 configfilepath = os.path.join(dirname, rootname+'.netedit.xml') 2827 else: 2828 configfilepath = self.get_rootfilepath()+'.netedit.xml' 2829 2830 print 'write_guiconfig', configfilepath, is_maps & (maps is not None), maps 2831 fd_config = open(configfilepath, 'w') 2832 for line in fd_template.readlines(): 2833 if line.count('<decals>') == 1: 2834 fd_config.write(line) 2835 if is_maps & (maps is not None): 2836 maps.write_decals(fd_config, indent=12) 2837 else: 2838 fd_config.write(line) 2839 2840 fd_template.close() 2841 fd_config.close() 2842 2843 return configfilepath 2844 2845 def import_netxml(self, filepath=None, rootname=None, is_clean_nodes=False, is_remove_xmlfiles=False): 2846 print 'import_netxml', filepath 2847 2848 if rootname is None: 2849 rootname = self.get_rootfilename() 2850 2851 if filepath is None: 2852 filepath = self.get_filepath() 2853 2854 dirname = os.path.dirname(filepath) 2855 2856 if os.path.isfile(filepath): 2857 # print ' modes.names',self.modes.names 2858 cml = 'netconvert'\ 2859 + ' --sumo-net-file '+filepathlist_to_filepathstring(filepath)\ 2860 + ' --plain-output-prefix '+filepathlist_to_filepathstring(os.path.join(dirname, rootname)) 2861 proc = subprocess.Popen(cml, shell=True) 2862 print ' run_cml cml=', cml 2863 print ' pid = ', proc.pid 2864 proc.wait() 2865 if not proc.returncode: 2866 print ' modes.names', self.modes.names 2867 return self.import_xml(rootname, dirname) 2868 else: 2869 return False 2870 else: 2871 return False 2872 2873 def export_addxml(self, filepath=None, 2874 is_ptstops=True, is_poly=False, 2875 encoding='UTF-8'): 2876 """ 2877 Export additional file 2878 """ 2879 if filepath is None: 2880 filepath = self.get_addfilepath() 2881 2882 try: 2883 fd = open(filepath, 'w') 2884 2885 except: 2886 print 'WARNING in write_obj_to_xml: could not open', filepath 2887 return False 2888 2889 #xmltag, xmltag_item, attrname_id = self.xmltag 2890 fd.write('<?xml version="1.0" encoding="%s"?>\n' % encoding) 2891 indent = 0 2892 #fd.write(xm.begin('routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://sumo.sf.net/xsd/routes_file.xsd"',indent)) 2893 2894 fd.write(xm.begin('additional', indent)) 2895 2896 if is_ptstops: 2897 if len(self.ptstops) > 0: 2898 self.ptstops.write_xml(fd, indent=indent+2) 2899 2900 if is_poly: 2901 if self.parent is not None: 2902 facilities = self.parent.landuse.facilities 2903 if len(facilities) > 0: 2904 fd.write(xm.start('location', indent+2)) 2905 # print ' groups:',self.parent.net.get_attrsman().get_groups() 2906 for attrconfig in self.get_attrsman().get_group('location'): 2907 # print ' locationconfig',attrconfig.attrname 2908 attrconfig.write_xml(fd) 2909 fd.write(xm.stopit()) 2910 2911 facilities.write_xml(fd, indent=indent+2, is_print_begin_end=False) 2912 2913 fd.write(xm.end('additional', indent)) 2914 fd.close() 2915 return filepath 2916 2917 def export_painxml(self, filepath=None, is_export_tlss=True): 2918 # now create rootfilepath in order to export first 2919 # the various xml file , then call netconvert 2920 2921 if filepath is None: 2922 filepath = self.get_filepath() 2923 2924 names = os.path.basename(filepath).split('.') 2925 dirname = os.path.dirname(filepath) 2926 if len(names) >= 3: 2927 rootname = '.'.join(names[:-2]) 2928 elif len(names) <= 2: 2929 rootname = names[0] 2930 2931 filepath_edges = os.path.join(dirname, rootname+'.edg.xml') 2932 filepath_nodes = os.path.join(dirname, rootname+'.nod.xml') 2933 filepath_connections = os.path.join(dirname, rootname+'.con.xml') 2934 filepath_tlss = os.path.join(dirname, rootname+'.tll.xml') 2935 2936 self.edges.export_sumoxml(filepath_edges) 2937 self.nodes.export_sumoxml(filepath_nodes) 2938 self.connections.export_sumoxml(filepath_connections) 2939 2940 if (len(self.tlss) > 0) & is_export_tlss: 2941 self.tlss.export_sumoxml(filepath_tlss) 2942 2943 return filepath_edges, filepath_nodes, filepath_connections, filepath_tlss 2944 2945 def export_netxml(self, filepath=None, is_export_tlss=True, is_netconvert=True): 2946 2947 # now create rootfilepath in order to export first 2948 # the various xml file , then call netconvert 2949 if filepath is None: 2950 filepath = self.get_filepath() 2951 2952 print 'Net.export_netxml', filepath 2953 filepath_edges, filepath_nodes, filepath_connections, filepath_tlss = self.export_painxml( 2954 filepath=filepath, is_export_tlss=is_export_tlss) 2955 2956 #cml = 'netconvert --verbose --ignore-errors.edge-type' 2957 cml = 'netconvert --ignore-errors.edge-type'\ 2958 + ' --node-files '+filepathlist_to_filepathstring(filepath_nodes)\ 2959 + ' --edge-files '+filepathlist_to_filepathstring(filepath_edges)\ 2960 + ' --connection-files '+filepathlist_to_filepathstring(filepath_connections)\ 2961 + ' --output-file '+filepathlist_to_filepathstring(filepath) 2962 2963 if (len(self.tlss) > 0) & (is_export_tlss): 2964 cml += ' --tllogic-files '+filepathlist_to_filepathstring(filepath_tlss) 2965 2966 if is_netconvert: 2967 proc = subprocess.Popen(cml, shell=True) 2968 print 'run_cml cml=', cml 2969 print ' pid = ', proc.pid 2970 proc.wait() 2971 if proc.returncode == 0: 2972 print ' success' 2973 return filepath 2974 else: 2975 print ' success' 2976 return '' 2977 else: 2978 return '' 2979 2980 def import_xml(self, rootname=None, dirname=None, is_clean_nodes=False, is_remove_xmlfiles=False): 2981 2982 if not self.is_empty(): 2983 oldoffset = self.get_offset() 2984 else: 2985 oldoffset = None 2986 print 'Network.import_xml oldoffset', oldoffset 2987 # remove current network 2988 # print ' remove current network' 2989 self.clear_net() 2990 # reload default SUMO MODES (maybe should not be here) 2991 # self.modes.add_rows(ids = MODES.values(), names = MODES.keys()) 2992 2993 if rootname is None: 2994 rootname = self.get_rootfilename() 2995 2996 if dirname is None: 2997 dirname = os.path.dirname(self.get_rootfilepath()) 2998 2999 # print 'import_xml',dirname,rootname 3000 nodefilepath = os.path.join(dirname, rootname+'.nod.xml') 3001 edgefilepath = os.path.join(dirname, rootname+'.edg.xml') 3002 confilepath = os.path.join(dirname, rootname+'.con.xml') 3003 tlsfilepath = os.path.join(dirname, rootname+'.tll.xml') 3004 3005 if os.path.isfile(edgefilepath) & os.path.isfile(nodefilepath) & os.path.isfile(confilepath): 3006 nodereader = self.import_sumonodes(nodefilepath, is_remove_xmlfiles) 3007 edgereader = self.import_sumoedges(edgefilepath, is_remove_xmlfiles) 3008 if is_clean_nodes: 3009 # make edges and lanes end at the node boundaries 3010 # also recalculate lane shapes from edge shapes...if lane shapes are missing 3011 #self.lanes.reshape() # 3012 self.nodes.clean(is_reshape_edgelanes=True) 3013 else: 3014 # just recalculate lane shapes from edge shapes...if lane shapes are missing 3015 self.lanes.reshape() 3016 # #pass 3017 3018 self.import_sumoconnections(confilepath, is_remove_xmlfiles) 3019 3020 if os.path.isfile(tlsfilepath): 3021 self.import_sumotls(tlsfilepath, is_remove_xmlfiles) 3022 3023 # print ' check additionals',self.ptstops.get_stopfilepath(),os.path.isfile(self.ptstops.get_stopfilepath()) 3024 if os.path.isfile(self.ptstops.get_stopfilepath()): 3025 self.ptstops.import_sumostops(is_remove_xmlfiles=is_remove_xmlfiles) 3026 3027 # this fixes some references to edges and tls 3028 nodereader.write_to_net_post() 3029 3030 if oldoffset is not None: 3031 # check if offset changed 3032 # if self.is_offset_change(): 3033 deltaoffset = self.get_offset()-oldoffset 3034 # print ' check update_netoffset',deltaoffset,oldoffset,self.get_offset(),np.sum(abs(deltaoffset))>0.002 3035 if np.sum(abs(deltaoffset)) > 0.002: 3036 # communicate to scenario 3037 if self.parent is not None: 3038 self.parent.update_netoffset(deltaoffset) 3039 3040 # clean up ...should be done in each importer?? 3041 # if is_remove_xmlfiles: 3042 # os.remove(nodefilepath) 3043 # os.remove(edgefilepath) 3044 # os.remove(confilepath) 3045 3046 # if os.path.isfile(tlsfilepath): 3047 # os.remove(tlsfilepath) 3048 return True 3049 else: 3050 self.get_logger().w('import_sumonodes: files not found', key='message') 3051 return False 3052 3053 def import_sumonodes(self, filename, is_remove_xmlfiles=False, logger=None, **others): 3054 print 'import_sumonodes', filename 3055 # print ' parent',self.parent 3056 self.get_logger().w('import_sumonodes', key='message') 3057 3058 # timeit 3059 exectime_start = time.clock() 3060 3061 counter = SumoNodeCounter() 3062 3063 #reader = SumoEdgeReader(self, **others) 3064 # try: 3065 3066 parse(filename, counter) 3067 # print ' after: n_edge', counter.n_edge 3068 fastreader = SumoNodeReader(self, counter) 3069 parse(filename, fastreader) 3070 3071 fastreader.write_to_net() 3072 3073 # timeit 3074 print ' exec time=', time.clock() - exectime_start 3075 return fastreader 3076 3077 def import_sumoedges(self, filename, is_remove_xmlfiles=False, logger=None, **others): 3078 print 'import_sumoedges', filename 3079 logger = self.get_logger() 3080 logger.w('import_sumoedges', key='message') 3081 # timeit 3082 exectime_start = time.clock() 3083 3084 counter = SumoEdgeCounter() 3085 3086 #reader = SumoEdgeReader(self, **others) 3087 # try: 3088 3089 parse(filename, counter) 3090 # print ' after: n_edge', counter.n_edge 3091 fastreader = SumoEdgeReader(self, counter) 3092 parse(filename, fastreader) 3093 3094 fastreader.write_to_net() 3095 self.edges.update() 3096 3097 if is_remove_xmlfiles: 3098 os.remove(filename) 3099 # timeit 3100 print ' exec time=', time.clock() - exectime_start 3101 3102 # except KeyError: 3103 # print >> sys.stderr, "Please mind that the network format has changed in 0.16.0, you may need to update your network!" 3104 # raise 3105 return fastreader 3106 3107 def import_sumoconnections(self, filename, is_remove_xmlfiles=False, logger=None, **others): 3108 print 'import_sumoedges', filename 3109 logger = self.get_logger() 3110 logger.w('import_sumoconnections', key='message') 3111 3112 # timeit 3113 exectime_start = time.clock() 3114 3115 counter = SumoConnectionCounter() 3116 3117 parse(filename, counter) 3118 fastreader = SumoConnectionReader(self, counter) 3119 parse(filename, fastreader) 3120 3121 fastreader.write_to_net() 3122 3123 # timeit 3124 exectime_end = time.clock() 3125 print ' exec time=', exectime_end - exectime_start 3126 return fastreader 3127 3128 def import_sumotls(self, filename, is_remove_xmlfiles=False, logger=None, **others): 3129 """ 3130 Import traffic ligh signals from tll.xml file 3131 as part of a complete import net process. 3132 """ 3133 print 'import_sumotls', filename 3134 3135 if logger is None: 3136 logger = self.get_logger() 3137 logger.w('import_sumotls', key='message') 3138 3139 # timeit 3140 exectime_start = time.clock() 3141 3142 reader = SumoTllReader(self) 3143 parse(filename, reader) 3144 3145 # timeit 3146 exectime_end = time.clock() 3147 print ' exec time=', exectime_end - exectime_start 3148 return reader 3149 3150 def import_sumotls_to_net(self, filename, is_remove_xmlfiles=False, logger=None, **others): 3151 """ 3152 Import traffic ligh signals from tll.xml file into an existing network. 3153 """ 3154 print 'import_sumotls_to_net', filename 3155 3156 # associate nodes with sumo tls ID 3157 #map_id_node_to_id_tlss_sumo = {} 3158 3159 ids_node = self.nodes.select_ids(self.nodes.ids_tls.get_value() > -1) 3160 ids_tlss_sumo = self.tlss.ids_sumo[self.nodes.ids_tls[ids_node]].copy() 3161 # for id_node, id_tls_sumo in zip(ids_node, self.tlss.ids_sumo[self.nodes.ids_tls[ids_node]]): 3162 # map_id_node_to_id_tlss_sumo[id_node] = id_tls_sumo 3163 3164 # clear all TLSs 3165 self.tlss.clear() 3166 3167 if logger is None: 3168 logger = self.get_logger() 3169 logger.w('import_sumotls_to_net', key='message') 3170 3171 # timeit 3172 exectime_start = time.clock() 3173 3174 reader = SumoTllReader(self) 3175 parse(filename, reader) 3176 3177 # timeit 3178 exectime_end = time.clock() 3179 print ' exec time=', exectime_end - exectime_start 3180 3181 # reestablish TLS IDs of nodes 3182 3183 # for id_node, id_tls_sumo in 3184 # zip(ids_node, self.nodes.ids_tls[ids_node]): 3185 # map_id_node_to_id_tlss_sumo[id_node] = id_tls_sumo 3186 self.nodes.ids_tls[ids_node] = self.tlss.ids_sumo.get_ids_from_indices(ids_tlss_sumo) 3187 3188 def get_id_mode(self, modename): 3189 return self.modes.get_id_mode(modename) 3190 3191 def add_node(self, **kwargs): 3192 return self.nodes.make(**kwargs) 3193 3194 def add_nodes(self, **kwargs): 3195 # print 'add_nodes' 3196 return self.nodes.multimake(**kwargs) 3197 3198 def clean_nodes(self, **kwargs): 3199 self.nodes.clean(**kwargs) 3200 self.edges.update() 3201 3202 def add_edge(self, **kwargs): 3203 # print 'add_edge' 3204 return self.edges.make(**kwargs) 3205 3206 def add_edges(self, **kwargs): 3207 # print 'add_edges' 3208 return self.edges.multimake(**kwargs) 3209 3210 def add_roundabout(self, **kwargs): 3211 return self.roundabouts.make(**kwargs) 3212 3213 def add_roundabouts(self, **kwargs): 3214 return self.roundabouts.multimake(**kwargs) 3215 3216 def add_lane(self, **kwargs): 3217 # print 'add_lane\n', 3218 # for key, value in kwargs.iteritems(): 3219 # print ' ',key,type(value),value 3220 return self.lanes.make(**kwargs) 3221 3222 def add_lanes(self, **kwargs): 3223 # print 'add_lanes\n', 3224 # for key, value in kwargs.iteritems(): 3225 # print ' ',key,type(value),value 3226 return self.lanes.multimake(**kwargs) 3227 3228 def complete_connections(self): 3229 """ 3230 Extend connections also to pedestrian edges. 3231 """ 3232 edges = self.edges 3233 nodes = self.nodes 3234 for id_node in self.nodes.get_ids(): 3235 ids_outgoing = nodes.ids_outgoing[id_node] 3236 ids_incoming = nodes.ids_incoming[id_node] 3237 if ids_outgoing is None: 3238 ids_outgoing = set() 3239 else: 3240 ids_outgoing = set(ids_outgoing) 3241 3242 if ids_incoming is None: 3243 ids_incoming = set() 3244 else: 3245 ids_incoming = set(ids_incoming) 3246 3247 ids_outgoing_all = set(edges.select_ids(edges.ids_fromnode.get_value() == id_node)) 3248 ids_incoming_all = set(edges.select_ids(edges.ids_tonode.get_value() == id_node)) 3249 3250 for id_edge in ids_outgoing_all.difference(ids_outgoing): 3251 self.connect_edge_incoming(id_edge, ids_incoming_all) 3252 3253 for id_edge in ids_incoming_all.difference(ids_incoming): 3254 self.connect_edge_outgoing(id_edge, ids_outgoing_all) 3255 3256 def connect_edge_incoming(self, id_edge_to, ids_edge_from): 3257 """ 3258 Connect id_edge_to with edges in list ids_edge_from. 3259 Attention, only lane index 0 of edge id_edge_to is connected. 3260 """ 3261 # print 'connect_edge', ids_edge_from, id_edge_to 3262 for id_edge_from in ids_edge_from: 3263 ids_lane_from = self.edges.ids_lanes[id_edge_from] 3264 ids_lane_to = self.edges.ids_lanes[id_edge_to] 3265 if len(ids_lane_from) == 1: 3266 self.add_connection(id_fromlane=ids_lane_from[0], id_tolane=ids_lane_to[0]) 3267 3268 # TODO: make connections also to multi lane edge 3269 else: 3270 for id_lane_from in ids_lane_from: 3271 if not MODES["pedestrian"] in self.lanes.ids_modes_allow[id_lane_from]: 3272 self.add_connection(id_fromlane=id_lane_from, id_tolane=ids_lane_to[0]) 3273 break 3274 3275 def connect_edge_outgoing(self, id_edge, ids_edge_to): 3276 """ 3277 Connect id_edge with edges in list ids_edge_to. 3278 Attention, only lane index 0 of edge id_edge_from is connected. 3279 """ 3280 # print 'connect_edge', ids_edge_from, id_edge_to 3281 for id_edge_to in ids_edge_to: 3282 ids_lane_to = self.edges.ids_lanes[id_edge_to] 3283 ids_lane_from = self.edges.ids_lanes[id_edge] 3284 if len(ids_lane_to) == 1: 3285 self.add_connection(id_fromlane=ids_lane_from[0], id_tolane=ids_lane_to[0]) 3286 3287 # TODO: make connections also to multi lane edge 3288 else: 3289 for id_lane_to in ids_lane_to: 3290 if not MODES["pedestrian"] in self.lanes.ids_modes_allow[id_lane_to]: 3291 self.add_connection(id_fromlane=ids_lane_from[0], id_tolane=id_lane_to) 3292 break 3293 3294 def add_connection(self, id_fromlane=-1, id_tolane=-1, **kwargs): 3295 # print 'add_connections id_fromlane , id_tolane ',id_fromlane , id_tolane 3296 3297 # for key, value in kwargs.iteritems(): 3298 # print ' ',key,type(value),value 3299 3300 id_fromedge = self.lanes.ids_edge[id_fromlane] 3301 id_toedge = self.lanes.ids_edge[id_tolane] 3302 id_node = self.edges.ids_tonode[id_fromedge] 3303 self.nodes.add_incoming(id_node, id_fromedge) 3304 self.nodes.add_outgoing(id_node, id_toedge) 3305 3306 return self.connections.make(id_fromlane=id_fromlane, id_tolane=id_tolane, **kwargs) 3307 3308 def add_connections(self, ids_fromlane=[], ids_tolane=[], **kwargs): 3309 3310 # for key, value in kwargs.iteritems(): 3311 # print ' ',key,type(value),value 3312 3313 ids_fromedge = self.lanes.ids_edge[ids_fromlane] 3314 ids_toedge = self.lanes.ids_edge[ids_tolane] 3315 ids_node = self.edges.ids_tonode[ids_fromedge] 3316 add_incoming = self.nodes.add_incoming 3317 add_outgoing = self.nodes.add_outgoing 3318 for id_node, id_fromedge, id_toedge in zip(ids_node, ids_fromedge, ids_toedge): 3319 add_incoming(id_node, id_fromedge) 3320 add_outgoing(id_node, id_toedge) 3321 3322 return self.connections.multimake(ids_fromlane=ids_fromlane, ids_tolane=ids_tolane, **kwargs) 3323 3324 def add_crossing(self, **kwargs): 3325 # print 'add_crossing\n', 3326 return self.crossings.make(**kwargs) 3327 3328 def add_crossings(self, **kwargs): 3329 # print 'add_crossings\n', 3330 return self.crossings.multimake(**kwargs) 3331 3332 3333class SumoConnectionCounter(handler.ContentHandler): 3334 """Parses a SUMO edge XML file and counts edges and lanes.""" 3335 3336 def __init__(self): 3337 self.n_con = 0 3338 self.n_cross = 0 3339 3340 def startElement(self, name, attrs): 3341 if name == 'connection': 3342 if attrs.has_key('to'): 3343 self.n_con += 1 3344 3345 if name == 'crossing': 3346 self.n_cross += 1 3347 3348 3349class SumoConnectionReader(handler.ContentHandler): 3350 """Parses a SUMO connection XML file""" 3351 3352 def __init__(self, net, counter): 3353 self._net = net 3354 3355 # print 'SumoConnectionReader:n_con,n_cross',counter.n_con,counter.n_cross 3356 3357 # connections 3358 self._ind_con = -1 3359 self.ids_fromlane = np.zeros(counter.n_con, np.int32) 3360 self.ids_tolane = np.zeros(counter.n_con, np.int32) 3361 self.are_passes = np.zeros(counter.n_con, np.bool) 3362 self.are_keep_clear = np.zeros(counter.n_con, np.bool) 3363 self.positions_cont = np.zeros(counter.n_con, np.float32) 3364 self.are_uncontrolled = np.zeros(counter.n_con, np.bool) 3365 3366 # crossings 3367 self._ind_cross = -1 3368 self.ids_node = np.zeros(counter.n_cross, np.int32) 3369 self.ids_edges = np.zeros(counter.n_cross, np.object) 3370 self.widths = np.zeros(counter.n_cross, np.float32) 3371 self.are_priority = np.zeros(counter.n_cross, np.bool) 3372 self.are_discard = np.zeros(counter.n_cross, np.bool) 3373 3374 self._ids_node_sumo = self._net.nodes.ids_sumo 3375 self._ids_edge_sumo = self._net.edges.ids_sumo 3376 self._ids_edgelanes = self._net.edges.ids_lanes 3377 3378 def startElement(self, name, attrs): 3379 # print 'startElement',name 3380 3381 if name == 'connection': 3382 # <connection from="153009994" to="153009966#1" fromLane="0" toLane="0" pass="1"/> 3383 3384 if attrs.has_key('to'): 3385 self._ind_con += 1 3386 i = self._ind_con 3387 # print 'startElement',name,i 3388 id_fromedge = self._ids_edge_sumo.get_id_from_index(attrs['from']) 3389 id_toedge = self._ids_edge_sumo.get_id_from_index(attrs['to']) 3390 3391 #id_fromlane = self._ids_edgelanes[id_fromedge][int(attrs.get('fromLane',0))] 3392 #id_tolane = self._ids_edgelanes[id_toedge][int(attrs.get('toLane',0))] 3393 3394 # print ' id_sumo fromedge', attrs['from'],len(self._ids_edgelanes[id_fromedge]) , int(attrs['fromLane']) 3395 self.ids_fromlane[i] = self._ids_edgelanes[id_fromedge][int(attrs['fromLane'])] 3396 self.ids_tolane[i] = self._ids_edgelanes[id_toedge][int(attrs['toLane'])] 3397 self.are_passes[i] = int(attrs.get('pass', 0)) 3398 self.are_keep_clear[i] = int(attrs.get('keepClear ', 1)) 3399 self.positions_cont[i] = float(attrs.get('contPos ', 0.0)) 3400 self.are_uncontrolled[i] = int(attrs.get('uncontrolled', 0)) 3401 else: 3402 id_fromedge = self._ids_edge_sumo.get_id_from_index(attrs['from']) 3403 3404 if name == 'crossing': 3405 self._ind_cross += 1 3406 i = self._ind_cross 3407 # print 'startElement',name 3408 3409 self.ids_node[i] = self._ids_node_sumo.get_id_from_index(attrs['node']) 3410 self.ids_edges[i] = self._ids_edge_sumo.get_ids_from_indices(attrs['edges'].split(' ')) 3411 self.widths[i] = float(attrs.get('width ', 4.0)) 3412 self.are_priority[i] = int(attrs.get('priority ', 0)) 3413 self.are_discard[i] = int(attrs.get('discard', 0)) 3414 3415 def write_to_net(self): 3416 3417 # print 'write_to_net' 3418 ids_con = self._net.add_connections( 3419 ids_fromlane=self.ids_fromlane, 3420 ids_tolane=self.ids_tolane, 3421 sare_passes=self.are_passes, 3422 are_keep_clear=self.are_keep_clear, 3423 positions_cont=self.positions_cont, 3424 are_uncontrolled=self.are_uncontrolled, 3425 ) 3426 3427 ids_cross = self._net.add_crossings( 3428 ids_node=self.ids_node, 3429 ids_edges=self.ids_edges, 3430 widths=self.widths, 3431 are_priority=self.are_priority, 3432 are_discard=self.are_discard, 3433 ) 3434 3435 3436class SumoNodeCounter(handler.ContentHandler): 3437 """Parses a SUMO edge XML file and counts edges and lanes.""" 3438 3439 def __init__(self): 3440 self.n_node = 0 3441 3442 def startElement(self, name, attrs): 3443 # print 'startElement',name,self.n_edge,self.n_lane,self.n_roundabout 3444 if name == 'node': 3445 self.n_node += 1 3446 3447 3448class SumoNodeReader(handler.ContentHandler): 3449 """Parses a SUMO node XML file""" 3450 3451 def __init__(self, net, counter): 3452 self._net = net 3453 3454 # print 'SumoEdgeFastreader' 3455 3456 #self._ids_node_sumo = net.nodes.ids_sumo 3457 #self._nodecoords = net.nodes.coords 3458 3459 self._nodetypemap = self._net.nodes.types.choices 3460 self._tltypemap = self._net.nodes.types_tl.choices 3461 self.radius_default = self._net.nodes.radius_default.get_value() 3462 # node attrs 3463 self.ids_sumo = np.zeros(counter.n_node, np.object) 3464 self.types = np.zeros(counter.n_node, np.int32) 3465 self.coords = np.zeros((counter.n_node, 3), np.float32) 3466 self.types_tl = np.zeros(counter.n_node, np.int32) 3467 self.ids_sumo_tls = np.zeros(counter.n_node, np.object) 3468 self.turnradii = np.zeros(counter.n_node, np.float32) 3469 self.are_costum_shape = np.zeros(counter.n_node, np.bool) 3470 self.shapes = np.zeros(counter.n_node, np.object) 3471 self.are_keep_clear = np.zeros(counter.n_node, np.bool) 3472 self._ind_node = -1 3473 self.ids_sumo_controlled = np.zeros(counter.n_node, np.object) 3474 self.ids_sumo_controlled[:] = None 3475 self._offset_delta = np.array([0.0, 0.0]) 3476 self._isNew = len(self._net.nodes) == 0 3477 3478 def write_to_net(self): 3479 3480 # print 'write_to_net' 3481 self.ids_node = self._net.add_nodes( 3482 ids_sumo=self.ids_sumo, 3483 types=self.types, 3484 coords=self.coords, 3485 shapes=self.shapes, 3486 are_costum_shape=self.are_costum_shape, 3487 types_tl=self.types_tl, 3488 turnradii=self.turnradii, 3489 are_keep_clear=self.are_keep_clear, 3490 ) 3491 # attention: 3492 # attributes ids_sumo_tls and ids_sumo_controlled will be added later 3493 # when tls and edges are read 3494 # see write_to_net_post 3495 3496 def write_to_net_post(self): 3497 """ 3498 To be called after edges and tls are read. 3499 """ 3500 # print 'write_to_net_post' 3501 get_ids_edge = self._net.edges.ids_sumo.get_ids_from_indices 3502 ids_controlled = self._net.nodes.ids_controlled 3503 for id_node, ids_sumo_edge in zip(self.ids_node, self.ids_sumo_controlled): 3504 if ids_sumo_edge is not None: 3505 if len(ids_sumo_edge) == 0: 3506 ids_controlled[id_node] = [] 3507 else: 3508 ids_controlled[id_node] = get_ids_edge(ids_sumo_edge) 3509 3510 # convert sumo ids into internal ids and set to nodes 3511 # print ' self.ids_sumo_tls',self.ids_sumo_tls 3512 # print ' self._net.tlss.ids_sumo',self._net.tlss.ids_sumo.value 3513 self._net.nodes.ids_tls[self.ids_node] = self._net.tlss.ids_sumo.get_ids_from_indices_save(self.ids_sumo_tls) 3514 3515 def startElement(self, name, attrs): 3516 # print 'startElement',name 3517 # if attrs.has_key('id'): print attrs['id'] 3518 # elif (attrs.has_key('from')&attrs.has_key('to')): print 'from',attrs['from'],'to',attrs['to'] 3519 # elif (attrs.has_key('from')&attrs.has_key('to')): print 'from',attrs['from'],'to',attrs['to'] 3520 # else: print '.' 3521 3522 if name == 'nodes': 3523 version = self._net.get_version() 3524 if self._isNew | (version == attrs['version']): 3525 self._net.set_version(attrs['version']) 3526 else: 3527 print 'WARNING: merge with incompatible net versions %s versus %s.' % (version, attrs['version']) 3528 3529 elif name == 'location': # j.s 3530 # print 'startElement',name,self._isNew 3531 netOffsetStrings = attrs['netOffset'].strip().split(",") 3532 offset = np.array([float(netOffsetStrings[0]), float(netOffsetStrings[1])]) 3533 offset_prev = self._net.get_offset() 3534 if self._isNew: 3535 self._net.set_offset(offset) 3536 # print ' offset_prev,offset',offset_prev,offset,type(offset) 3537 else: 3538 3539 self._offset_delta = offset-offset_prev 3540 self._net.set_offset(offset) 3541 # print ' offset_prev,offset,self._offset_delta',offset_prev,offset,type(offset),self._offset_delta 3542 3543 convBoundaryStr = attrs['convBoundary'].strip().split(",") 3544 origBoundaryStr = attrs['origBoundary'].strip().split(",") 3545 # print ' convBoundaryStr',convBoundaryStr 3546 # print ' origBoundary',origBoundaryStr 3547 3548 if self._isNew: 3549 self._net.set_boundaries([float(convBoundaryStr[0]), 3550 float(convBoundaryStr[1]), 3551 float(convBoundaryStr[2]), 3552 float(convBoundaryStr[3])], 3553 [float(origBoundaryStr[0]), 3554 float(origBoundaryStr[1]), 3555 float(origBoundaryStr[2]), 3556 float(origBoundaryStr[3])] 3557 ) 3558 else: 3559 self._net.merge_boundaries([float(convBoundaryStr[0]), 3560 float(convBoundaryStr[1]), 3561 float(convBoundaryStr[2]), 3562 float(convBoundaryStr[3])], 3563 [float(origBoundaryStr[0]), 3564 float(origBoundaryStr[1]), 3565 float(origBoundaryStr[2]), 3566 float(origBoundaryStr[3])] 3567 ) 3568 if self._isNew: 3569 if attrs.has_key('projParameter'): 3570 self._net.set_projparams(attrs['projParameter']) 3571 else: 3572 if attrs.has_key('projParameter'): 3573 if self._net.get_projparams() != attrs['projParameter']: 3574 print 'WARNING: merge with incompatible projections %s versus %s.' % ( 3575 self._net.getprojparams(), attrs['projparams']) 3576 3577 elif name == 'node': 3578 if attrs['id'][0] != ':': # no internal node 3579 self._ind_node += 1 3580 i = self._ind_node 3581 x0, y0 = self._offset_delta 3582 3583 self.ids_sumo[i] = attrs['id'] 3584 sumotypes_node = str(attrs.get('type', 'priority')) 3585 3586 self.types[i] = self._nodetypemap[sumotypes_node] 3587 x, y, z = float(attrs['x'])-x0, float(attrs['y'])-y0, float(attrs.get('z', 0.0)) 3588 self.coords[i] = [x, y, z] 3589 3590 sumotype_tl = attrs.get('tlType', 'none') 3591 if sumotypes_node == 'traffic_light': 3592 if sumotype_tl == 'none': 3593 sumotype_tl = 'static' 3594 3595 self.types_tl[i] = self._tltypemap[sumotype_tl] 3596 self.ids_sumo_tls[i] = attrs.get('tl', None) 3597 self.turnradii[i] = attrs.get('radius', 1.5) 3598 3599 # not in nodes 3600 3601 shape = np.array(xm.process_shape(attrs.get('shape', ''), offset=self._offset_delta)) 3602 3603 if len(shape) < 3: # no or insufficient shape info 3604 # shape should be a list of np array coords 3605 3606 # generate some default shape 3607 r0 = self.radius_default 3608 shape = [np.array([x-r0, y-r0, z], dtype=np.float32), 3609 np.array([x+r0, y-r0, z], dtype=np.float32), 3610 np.array([x+r0, y+r0, z], dtype=np.float32), 3611 np.array([x-r0, y+r0, z], dtype=np.float32), 3612 ] 3613 self.are_costum_shape[i] = False 3614 3615 else: 3616 self.are_costum_shape[i] = True 3617 3618 self.shapes[i] = list(shape) 3619 3620 self.are_keep_clear[i] = bool(attrs.get('keepClear', True)) 3621 3622 # 'controlledInner' 3623 # Edges which shall be controlled by a joined TLS 3624 # despite being incoming as well as outgoing to 3625 # the jointly controlled nodes 3626 # problem: we do not know yet the edge IDs 3627 # 3628 if attrs.has_key('controlledInner'): 3629 self.ids_sumo_controlled[i] = attrs['controlledInner'].strip().split(' ') 3630 else: 3631 self.ids_sumo_controlled[i] = [] 3632 3633 3634# class SumoTllCounter(handler.ContentHandler): 3635# """Parses a SUMO tll XML file and counts edges and lanes.""" 3636# 3637# def __init__(self): 3638# self.n_tls = 0 3639# 3640# 3641# def startElement(self, name, attrs): 3642# #print 'startElement',name,self.n_tls 3643# if name == 'tlLogic': 3644# self.n_tls += 1 3645 3646class SumoTllReader(handler.ContentHandler): 3647 """Parses a SUMO tll XML file and reads it into net.""" 3648 3649 def __init__(self, net): 3650 self.net = net 3651 self.connections = net.connections 3652 self.tlss = net.tlss 3653 # print 'SumoEdgeFastreader' 3654 3655 self.get_id_tls = net.nodes.ids_sumo.get_id_from_index 3656 3657 #n_tls = counter.n_tls 3658 self.ptypes_choices = self.tlss.tlls.value.ptypes.choices 3659 self.ids_sumo_tls = self.tlss.ids_sumo 3660 3661 self.reset_prog() 3662 3663 self.tlsconnections = {} 3664 3665 def reset_prog(self): 3666 self.id_sumo_tls = None 3667 self.durations = [] 3668 self.durations_min = [] 3669 self.durations_max = [] 3670 self.states = [] 3671 3672 def startElement(self, name, attrs): 3673 3674 if name == 'tlLogic': 3675 # print '\n startElement',name,attrs['id'] 3676 self.id_sumo_tls = attrs['id'] 3677 self.ptype = self.ptypes_choices.get(attrs.get('type', None), 1) 3678 self.id_prog = attrs.get('programID', None) 3679 self.offset = attrs.get('offset', None) 3680 3681 elif name == 'phase': 3682 # print 'startElement',name,self.id_sumo_tls 3683 if self.id_sumo_tls is not None: 3684 # print ' append',attrs.get('duration',None),attrs.get('state',None),len(attrs.get('state','')) 3685 duration = int(attrs.get('duration', 0)) 3686 self.durations.append(duration) 3687 self.durations_min.append(int(attrs.get('minDur', duration))) 3688 self.durations_max.append(int(attrs.get('maxDur', duration))) 3689 self.states.append(attrs.get('state', None)) 3690 3691 # elif name == 'tlLogics': 3692 # pass 3693 3694 elif name == 'connection': 3695 id_sumo_tls = attrs['tl'] 3696 # print 'startElement',name,id_sumo_tls,int(attrs['linkIndex']) 3697 # print ' self.tlsconnections',self.tlsconnections 3698 3699 if not self.tlsconnections.has_key(id_sumo_tls): 3700 self.tlsconnections[id_sumo_tls] = {} 3701 3702 id_con = self.connections.get_id_from_sumoinfo(attrs['from'], 3703 attrs['to'], int(attrs['fromLane']), int(attrs['toLane'])) 3704 if id_con >= 0: 3705 self.tlsconnections[id_sumo_tls][int(attrs['linkIndex'])] = id_con 3706 3707 def endElement(self, name): 3708 #edges = self._net.edges 3709 #lanes = self._net.lanes 3710 if name == 'tlLogic': 3711 # print 'endElement',name,self.id_sumo_tls 3712 # print ' ptype',self.ptype 3713 # print ' durations',self.durations 3714 # print ' durations_min',self.durations_min 3715 # print ' durations_max',self.durations_max 3716 # print ' states',self.states 3717 # print ' self.id_prog='+self.id_prog+'=' 3718 self.tlss.make(self.id_sumo_tls, 3719 id_prog=self.id_prog, 3720 ptype=self.ptype, 3721 offset=self.offset, 3722 durations=self.durations, 3723 durations_min=self.durations_min, 3724 durations_max=self.durations_max, 3725 states=self.states, 3726 ) 3727 3728 self.reset_prog() 3729 3730 elif name == 'tlLogics': 3731 # print 'endElement',name,len(self.tlss) 3732 # end of scanning. Write controlled connections to tlss 3733 # print ' tlsconnections',self.tlsconnections 3734 3735 for id_sumo_tls, conmap in self.tlsconnections.iteritems(): 3736 3737 inds_con = np.array(conmap.keys(), dtype=np.int32) 3738 3739 ids_con = np.zeros(np.max(inds_con)+1, np.int32) 3740 # print ' cons for',id_sumo_tls,conmap 3741 # print ' inds',inds_con,len(ids_con) 3742 # print ' values',conmap.values(),len(ids_con) 3743 ids_con[inds_con] = conmap.values() # <<<<<<<<<<< 3744 3745 id_tls = self.tlss.ids_sumo.get_id_from_index(id_sumo_tls) 3746 self.tlss.set_connections(id_tls, ids_con) 3747 #self.tlss.set_connections(self.get_id_tls(id_sumo_tls), ids_con) 3748 3749 3750class SumoEdgeCounter(handler.ContentHandler): 3751 """Parses a SUMO edge XML file and counts edges and lanes.""" 3752 3753 def __init__(self): 3754 self.n_edge = 0 3755 self.n_lane = 0 3756 self.n_roundabout = 0 3757 self._n_edgelane = 0 3758 #self._net = net 3759 #self._ids_edge_sumo = net.edges.ids_sumo 3760 #self._ids_node_sumo = net.nodes.ids_sumo 3761 3762 def startElement(self, name, attrs): 3763 # print 'startElement',name,self.n_edge,self.n_lane,self.n_roundabout 3764 if name == 'edge': 3765 self.n_edge += 1 3766 self.n_lane += int(attrs['numLanes']) 3767 3768 elif name == 'roundabout': 3769 self.n_roundabout += 1 3770 3771 3772class SumoEdgeReader(handler.ContentHandler): 3773 """Parses a SUMO edge XML file and reads it into net.""" 3774 3775 def __init__(self, net, counter, offset_delta=np.array([0.0, 0.0])): 3776 self._net = net 3777 3778 # print 'SumoEdgeFastreader' 3779 3780 self._ids_node_sumo = net.nodes.ids_sumo 3781 self._nodecoords = net.nodes.coords 3782 self._modenames = net.modes.names 3783 self._offset_delta = offset_delta 3784 #self._isNew = len(self._net.nodes)==0 3785 3786 # edge attrs 3787 self._ind_edge = -1 3788 # print ' n_edge',counter.n_edge 3789 self.ids_edge_sumo = np.zeros(counter.n_edge, np.object) # net.edges.ids_sumo 3790 self.ids_edge_sumo[:] = None # ??needed 3791 3792 self.ids_fromnode = np.zeros(counter.n_edge, np.int32) 3793 self.ids_tonode = np.zeros(counter.n_edge, np.int32) 3794 self.types_edge = np.zeros(counter.n_edge, np.object) 3795 self.widths = np.zeros(counter.n_edge, np.float32) # used only for lane width if no lane data is given 3796 self.nums_lanes = np.zeros(counter.n_edge, np.int32) 3797 self.speeds_max = np.zeros(counter.n_edge, np.float32) 3798 self.priorities = np.zeros(counter.n_edge, np.int32) 3799 #length = 0.0, 3800 self.shapes = np.zeros(counter.n_edge, np.object) 3801 self.types_spread = np.zeros(counter.n_edge, np.int32) 3802 self.spread_choices = net.edges.types_spread.choices 3803 # "right": 0, 3804 # "center": 1, 3805 self.names = np.zeros(counter.n_edge, np.object) 3806 self.offsets_end = np.zeros(counter.n_edge, np.float32) 3807 self.widths_lanes_default = np.zeros(counter.n_edge, np.float32) 3808 self.widths_sidewalk = -1*np.ones(counter.n_edge, np.float32) 3809 self.inds_lanes_edges = np.zeros(counter.n_edge, np.object) 3810 #self.inds_lanes_edges[:] = None 3811 self._ind_lanes_edges = [] 3812 3813 #self.ids_sumoedge_to_ind = {} 3814 3815 # lane attrs 3816 # print ' n_lane',counter.n_lane 3817 self._ind_lane = -1 3818 self.index_lanes = np.zeros(counter.n_lane, np.int32) 3819 self.width_lanes = np.zeros(counter.n_lane, np.float32) 3820 self.speed_max_lanes = np.zeros(counter.n_lane, np.float32) 3821 self.offset_end_lanes = np.zeros(counter.n_lane, np.float32) 3822 self.ids_modes_allow = np.zeros(counter.n_lane, np.object) 3823 self.ids_modes_disallow = np.zeros(counter.n_lane, np.object) 3824 self.ids_mode_lanes = np.zeros(counter.n_lane, np.int32) 3825 self.inds_edge_lanes = np.zeros(counter.n_lane, np.int32) 3826 #self.shapes_lanes = np.zeros(counter.n_lane,np.object) 3827 3828 # roundabout attrs 3829 # print ' n_roundabout',counter.n_roundabout 3830 self._ind_ra = -1 3831 self.ids_sumoedges_ra = np.zeros(counter.n_roundabout, np.object) 3832 self.ids_nodes_ra = np.zeros(counter.n_roundabout, np.object) 3833 3834 ############################ 3835 3836 def startElement(self, name, attrs): 3837 # print 'startElement',name 3838 # if attrs.has_key('id'): print attrs['id'] 3839 # elif (attrs.has_key('from')&attrs.has_key('to')): print 'from',attrs['from'],'to',attrs['to'] 3840 # elif (attrs.has_key('from')&attrs.has_key('to')): print 'from',attrs['from'],'to',attrs['to'] 3841 # else: print '.' 3842 3843 if name == 'edge': 3844 # if not attrs.has_key('function') or attrs['function'] != 'internal': 3845 #id_fromnode = nodes.ids_sumo.get_id_from_index(id_fromnode_sumo) 3846 #id_tonode = nodes.ids_sumo.get_id_from_index(id_tonode_sumo) 3847 self._ind_edge += 1 3848 ind = self._ind_edge 3849 # print 'startElement edge',ind,attrs['id'] 3850 self.ids_edge_sumo[ind] = attrs['id'] 3851 3852 id_fromnode = self._ids_node_sumo.get_id_from_index(str(attrs['from'])) 3853 id_tonode = self._ids_node_sumo.get_id_from_index(str(attrs['to'])) 3854 self.ids_fromnode[ind] = id_fromnode 3855 self.ids_tonode[ind] = id_tonode 3856 3857 self.types_edge[ind] = str(attrs.get('type', '')) 3858 self.nums_lanes[ind] = int(attrs.get('numLanes', 1)) 3859 3860 # attention sumo width attribute is actually lane width!! 3861 # here we multiply with number of lanes 3862 # however, will be updated later as a sum of lanewidth 3863 self.widths[ind] = float(attrs.get('width', 3.5)) * self.nums_lanes[ind] 3864 3865 self.types_spread[ind] = self.spread_choices[str(attrs.get('spreadType', 'right'))] # usually center 3866 # print ' ',self.types_spread[ind] 3867 3868 #length = 0.0, 3869 shape = np.array(xm.process_shape(attrs.get('shape', ''), offset=self._offset_delta)) 3870 3871 if len(shape) < 2: # insufficient shape data 3872 # shape should be a list of np array coords 3873 # ATTENTIOn: we need to copy here, otherwise the reference 3874 # to node coordinates will be kept!! 3875 shape = np.array([1.0*self._nodecoords[id_fromnode], 1.0*self._nodecoords[id_tonode]]) 3876 3877 if self.types_spread[ind] == 1: # center 3878 angles_perb = get_angles_perpendicular(shape) 3879 halfwidth = self.widths[ind] 3880 shape[:, 0] += np.cos(angles_perb) * halfwidth 3881 shape[:, 1] += np.sin(angles_perb) * halfwidth 3882 3883 self.shapes[ind] = shape 3884 3885 self.speeds_max[ind] = float(attrs.get('speed', 13.888)) 3886 self.priorities[ind] = int(attrs.get('priority', 9)) 3887 self.names[ind] = unicode(attrs.get('name', '')) 3888 self.offsets_end[ind] = float(attrs.get('endOffset', 0.0)) 3889 3890 # this lanewidth will be used as default if no lane width attribute 3891 # is given 3892 self.widths_lanes_default[ind] = float(attrs.get('width', 3.0)) 3893 #self.widths_sidewalk[ind] = float(attrs.get('sidewalkWidth',-1.0)) 3894 3895 # check for some attributes that are actually lane attributes 3896 3897 self._allow_egdeattr = attrs.get('allow', None) 3898 self._disallow_egdeattr = attrs.get('disallow', None) 3899 #self._is_laneshape = True 3900 # print ' self._id_edge',self._id_edge 3901 3902 elif name == 'lane': 3903 self._ind_lane += 1 3904 ind = self._ind_lane 3905 ind_edge = self._ind_edge 3906 speed_max_default = -1 3907 3908 if attrs.has_key('allow'): 3909 ids_modes_allow = list(self._modenames.get_ids_from_indices(attrs['allow'].split(' '))) 3910 3911 # done in end element 3912 # elif self._allow_egdeattr is not None: 3913 # ids_modes_allow = list(self._modenames.get_ids_from_indices(self._allow_egdeattr.split(' '))) 3914 3915 else: 3916 edgetype = self.types_edge[self._ind_edge] 3917 3918 if OSMEDGETYPE_TO_MODES.has_key(edgetype): 3919 ids_modes_allow, speed_max_default = OSMEDGETYPE_TO_MODES[edgetype] 3920 else: 3921 ids_modes_allow = [] 3922 3923 if attrs.has_key('disallow'): 3924 ids_modes_disallow = list(self._modenames.get_ids_from_indices(attrs['disallow'].split(' '))) 3925 3926 # done in end element 3927 # elif self._disallow_egdeattr is not None: 3928 # ids_modes_allow = list(self._modenames.get_ids_from_indices(self._disallow_egdeattr.split(' '))) 3929 # 3930 else: 3931 ids_modes_disallow = [] 3932 3933 index = int(attrs.get('index', -1)) 3934 # use defaults from edge 3935 width = float(attrs.get('width', -1)) 3936 speed_max = float(attrs.get('speed', -1)) 3937 offset_end_lane = float(attrs.get('endOffset', -1)) 3938 3939 self.set_lane(ind, ind_edge, index, width, speed_max, 3940 ids_modes_allow, ids_modes_disallow, offset_end_lane) 3941 3942 elif name == 'roundabout': 3943 self._ind_ra += 1 3944 self.ids_sumoedges_ra[self._ind_ra] = attrs.get('edges', '').split(' ') 3945 self.ids_nodes_ra[self._ind_ra] = self._ids_node_sumo.get_ids_from_indices( 3946 attrs.get('nodes', '').split(' ')) 3947 3948 # def characters(self, content): 3949 # if self._currentLane is not None: 3950 # self._currentShape = self._currentShape + content 3951 3952 def endElement(self, name): 3953 #edges = self._net.edges 3954 #lanes = self._net.lanes 3955 if name == 'edge': 3956 # this is the number of lanes declared within the edge tag 3957 n_lane = self.nums_lanes[self._ind_edge] 3958 3959 # print 'SumoEdgeReader.endElement',self._ind_lane,n_lane 3960 3961 # this loop counts from the current number of pased lanes 3962 # (which may be zero) to the declared number of lanes. 3963 # This is necessary because it can happen that no lane 3964 # specifications are provided 3965 index = len(self._ind_lanes_edges) 3966 ind_edge = self._ind_edge 3967 while index < n_lane: 3968 # if len(self._ind_lanes_edges) ==0: 3969 # edge description provided no specific lane information 3970 # create n_lanes and us some properties from current edge 3971 self._ind_lane += 1 3972 ind = self._ind_lane 3973 3974 edgetype = self.types_edge[ind_edge] 3975 3976 if self._allow_egdeattr is not None: 3977 ids_modes_allow = list(self._modenames.get_ids_from_indices(self._allow_egdeattr.split(' '))) 3978 else: 3979 if OSMEDGETYPE_TO_MODES.has_key(edgetype): 3980 ids_modes_allow, speed_max_default = OSMEDGETYPE_TO_MODES[edgetype] 3981 else: 3982 ids_modes_allow = [] 3983 3984 if self._disallow_egdeattr is not None: 3985 ids_modes_disallow = list(self._modenames.get_ids_from_indices(self._disallow_egdeattr.split(' '))) 3986 else: 3987 ids_modes_disallow = [] 3988 3989 # figure main mode 3990 if len(ids_modes_allow) == 1: 3991 id_mode_main = ids_modes_allow[0] # pick as major mode 3992 else: 3993 id_mode_main = -1 # no major mode specified 3994 3995 self.index_lanes[ind] = index 3996 # derive lane attributes from edge attributes 3997 self.width_lanes[ind] = self.widths_lanes_default[ind_edge] # copy from edge attr 3998 self.speed_max_lanes[ind] = self.speeds_max[ind_edge] # copy from edge attr 3999 self.offset_end_lanes[ind] = self.offset_end_lanes[ind_edge] # copy from edge attr 4000 4001 self.ids_modes_allow[ind] = ids_modes_allow 4002 self.ids_modes_disallow[ind] = ids_modes_disallow 4003 self.inds_edge_lanes[ind] = ind_edge 4004 #self.shapes_lanes[ind] = self.getShape(attrs.get('shape',''), offset = self._offset_delta) 4005 self.ids_mode_lanes[ind] = id_mode_main 4006 self._ind_lanes_edges.append(ind) 4007 4008 index += 1 4009 4010 self.inds_lanes_edges[self._ind_edge] = self._ind_lanes_edges 4011 self._ind_lanes_edges = [] 4012 4013 def set_lane(self, ind, ind_edge, index, width, speed_max, ids_modes_allow, ids_modes_disallow, offset_end_lane): 4014 4015 if len(ids_modes_allow) == 1: 4016 id_mode_main = ids_modes_allow[0] # pick as major mode 4017 # elif len(ids_modes_allow) == 1: 4018 4019 else: 4020 id_mode_main = -1 # no major mode specified 4021 4022 is_sidewalk = False 4023 if index == 0: 4024 is_sidewalk = (MODES['pedestrian'] in ids_modes_allow) # test for pedestrian sidewalk 4025 4026 if speed_max < 0: 4027 if (index == 0) & is_sidewalk: 4028 speed_max = 0.8 # default walk speed 4029 else: 4030 speed_max = self.speeds_max[ind_edge] # copy from edge 4031 4032 if width < 0: 4033 if is_sidewalk: 4034 width = 1.0 4035 else: 4036 width = self.widths_lanes_default[ind_edge] # copy from edge 4037 4038 if is_sidewalk: 4039 self.widths_sidewalk[ind_edge] = width 4040 4041 if offset_end_lane < 0: 4042 offset_end_lane = self.offsets_end[ind_edge] 4043 4044 self.index_lanes[ind] = index 4045 self.width_lanes[ind] = width 4046 self.speed_max_lanes[ind] = speed_max 4047 self.offset_end_lanes[ind] = offset_end_lane 4048 self.ids_modes_allow[ind] = ids_modes_allow 4049 self.ids_modes_disallow[ind] = ids_modes_disallow 4050 self.ids_mode_lanes[ind] = id_mode_main 4051 self.inds_edge_lanes[ind] = ind_edge 4052 #self.shapes_lanes[ind] = self.getShape(attrs.get('shape',''), offset = self._offset_delta) 4053 4054 self._ind_lanes_edges.append(ind) 4055 # self._ids_lane.append(id_lane) 4056 4057 def write_to_net(self): 4058 4059 # print 'write_to_net' 4060 ids_edge = self._net.add_edges( 4061 ids_sumo=self.ids_edge_sumo, 4062 ids_fromnode=self.ids_fromnode, 4063 ids_tonode=self.ids_tonode, 4064 types=self.types_edge, 4065 nums_lanes=self.nums_lanes, 4066 speeds_max=self.speeds_max, 4067 priorities=self.priorities, 4068 #lengths = length, 4069 shapes=self.shapes, 4070 types_spread=self.types_spread, 4071 names=self.names, 4072 offsets_end=self.offsets_end, 4073 widths_lanes_default=self.widths_lanes_default, 4074 widths_sidewalk=self.widths_sidewalk, 4075 ) 4076 4077 # print ' self.inds_edge_lanes',self.inds_edge_lanes 4078 ids_lanes = self._net.add_lanes( 4079 indexes=self.index_lanes, 4080 widths=self.width_lanes, 4081 speeds_max=self.speed_max_lanes, 4082 offsets_end=self.offset_end_lanes, 4083 ids_modes_allow=self.ids_modes_allow, 4084 ids_modes_disallow=self.ids_modes_disallow, 4085 ids_mode=self.ids_mode_lanes, # main mode will be determined from other attributes 4086 ids_edge=ids_edge[self.inds_edge_lanes], 4087 # shapes = self.shapes_lanes, # lane shapes are not given -> must be derived from edge shape 4088 ) 4089 #edges.update_lanes(self._id_edge, self._ids_lane) 4090 ids_edgelanes = self._net.edges.ids_lanes 4091 ind = 0 4092 for inds_lane in self.inds_lanes_edges: 4093 ids_edgelanes[ids_edge[ind]] = ids_lanes[inds_lane] 4094 # print ' id_edge,ids_lanes[inds_lane]',ids_edge[ind],ids_lanes[inds_lane] 4095 ind += 1 4096 4097 # roundaboutS 4098 ids_edge_sumo = self._net.edges.ids_sumo 4099 ids_roundabout = self._net.add_roundabouts( 4100 ids_nodes=self.ids_nodes_ra, 4101 ) 4102 ids_edges_ra = self._net.roundabouts.ids_edges 4103 i = 0 4104 for id_roundabout in ids_roundabout: 4105 ids_edges_ra[id_roundabout] = ids_edge_sumo.get_ids_from_indices(self.ids_sumoedges_ra[i]) 4106 i += 1 4107 4108 4109class SumonetImporter(CmlMixin, Process): 4110 def __init__(self, net, rootname=None, rootdirpath=None, netfilepath=None, 4111 is_clean_nodes=False, logger=None, **kwargs): 4112 4113 self._init_common('sumonetimporter', name='SUMO net import', 4114 logger=logger, 4115 info='Converts a SUMO .net.xml file to nod.xml, edg.xml and con.xml file and reads into scenario.', 4116 ) 4117 self._net = net 4118 4119 self.init_cml('netconvert') 4120 4121 if rootname is None: 4122 rootname = net.parent.get_rootfilename() 4123 4124 if rootdirpath is None: 4125 if net.parent is not None: 4126 rootdirpath = net.parent.get_workdirpath() 4127 else: 4128 rootdirpath = os.getcwd() 4129 4130 if netfilepath is None: 4131 netfilepath = os.path.join(rootdirpath, rootname+'.net.xml') 4132 4133 attrsman = self.get_attrsman() 4134 self.add_option('netfilepath', netfilepath, 4135 groupnames=['options'], # this will make it show up in the dialog 4136 cml='--sumo-net-file', 4137 perm='rw', 4138 name='Net file', 4139 wildcards='Net XML files (*.net.xml)|*.net.xml', 4140 metatype='filepath', 4141 info='SUMO Net file in XML format.', 4142 ) 4143 4144 self.workdirpath = attrsman.add(cm.AttrConf('workdirpath', rootdirpath, 4145 groupnames=['_private'], # ['options'],#['_private'], 4146 perm='r', 4147 name='Workdir', 4148 metatype='dirpath', 4149 info='Working directory for this scenario.', 4150 )) 4151 4152 self.rootname = attrsman.add(cm.AttrConf('rootname', rootname, 4153 groupnames=['_private'], 4154 perm='r', 4155 name='Scenario shortname', 4156 info='Scenario shortname is also rootname of converted files.', 4157 )) 4158 4159 self.is_clean_nodes = attrsman.add(cm.AttrConf('is_clean_nodes', is_clean_nodes, 4160 groupnames=['options'], 4161 perm='rw', 4162 name='Clean Nodes', 4163 info='If set, then shapes around nodes are cleaned up.', 4164 )) 4165 4166 def update_params(self): 4167 """ 4168 Make all parameters consistent. 4169 example: used by import OSM to calculate/update number of tiles 4170 from process dialog 4171 """ 4172 pass 4173 #self.workdirpath = os.path.dirname(self.netfilepath) 4174 #bn = os.path.basename(self.netfilepath).split('.') 4175 # if len(bn)>0: 4176 # self.rootname = bn[0] 4177 4178 def do(self): 4179 self.update_params() 4180 cml = self.get_cml()+' --plain-output-prefix '+filepathlist_to_filepathstring(os.path.join(self.workdirpath, self.rootname)) 4181 # print 'SumonetImporter.do',cml 4182 #import_xml(self, rootname, dirname, is_clean_nodes = True) 4183 self.run_cml(cml) 4184 if self.status == 'success': 4185 self._net.import_xml(self.rootname, self.workdirpath, is_clean_nodes=self.is_clean_nodes) 4186 4187 # print 'do',self.newident 4188 # self._scenario = Scenario( self.newident, 4189 # parent = None, 4190 # workdirpath = self.workdirpath, 4191 # logger = self.get_logger(), 4192 # ) 4193 return True 4194 4195 def get_net(self): 4196 return self._net 4197 4198 4199class OsmImporter(netconvert.NetConvertMixin): 4200 def __init__(self, net=None, 4201 osmfilepaths=None, 4202 netfilepath=None, 4203 logger=None, 4204 **kwargs): 4205 4206 # All parameters and Default Values in NetconvertMixin 4207 4208 if net is None: 4209 self._net = Network() 4210 else: 4211 self._net = net 4212 4213 self.init_common_netconvert('osmimporter', net, name='OSM import', 4214 logger=logger, 4215 info='Converts a OSM file to SUMO nod.xml, edg.xml and con.xml file and reads into scenario.', 4216 ) 4217 4218 # osm specific options 4219 if osmfilepaths is None: 4220 if net.parent is not None: 4221 rootname = net.parent.get_rootfilename() 4222 rootdirpath = net.parent.get_workdirpath() 4223 else: 4224 rootname = net.get_ident() 4225 rootdirpath = os.getcwd() 4226 4227 osmfilepaths = os.path.join(rootdirpath, rootname+'.osm.xml') 4228 4229 self.add_option('osmfilepaths', osmfilepaths, 4230 groupnames=['options'], 4231 cml='--osm-files', 4232 perm='rw', 4233 name='OSM files', 4234 wildcards='OSM XML files (*.osm)|*.osm*', 4235 metatype='filepaths', 4236 info='Openstreetmap files to be imported.', 4237 ) 4238 4239 self.init_all(**kwargs) 4240 self.add_option('is_guess_signals_tls', kwargs.get('is_guess_signals_tls', False), 4241 groupnames=['options', 'traffic lights'], 4242 cml='--tls.guess-signals', 4243 perm='rw', 4244 name='Guess signals.', 4245 info='Interprets tls nodes surrounding an intersection as signal positions for a larger TLS. This is typical pattern for OSM-derived networks', 4246 is_enabled=lambda self: self.is_guess_tls, 4247 ) 4248 self.add_option('dist_guess_signal_tls', kwargs.get('dist_guess_signal_tls', 20.0), 4249 groupnames=['options', 'traffic lights'], 4250 cml='--tls.guess-signals.dist', 4251 perm='rw', 4252 unit='m', 4253 name='Signal guess dist.', 4254 info='Distance for interpreting nodes as signal locations', 4255 is_enabled=lambda self: self.is_guess_tls & self.is_guess_signals_tls, 4256 ) 4257 4258 4259if __name__ == '__main__': 4260 ############################################################################### 4261 # print 'sys.path',sys.path 4262 from agilepy.lib_wx.objpanel import objbrowser 4263 from agilepy.lib_base.logger import Logger 4264 #net = Network(logger = Logger()) 4265 net = Network(logger=Logger()) 4266 net.import_xml('facsp2', 'testnet') 4267 4268 objbrowser(net) 4269