Path: blob/main/tools/contributed/sumopy/coremodules/landuse/wxgui.py
169689 views
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo1# Copyright (C) 2016-2025 German Aerospace Center (DLR) and others.2# SUMOPy module3# Copyright (C) 2012-2021 University of Bologna - DICAM4# This program and the accompanying materials are made available under the5# terms of the Eclipse Public License 2.0 which is available at6# https://www.eclipse.org/legal/epl-2.0/7# This Source Code may also be made available under the following Secondary8# Licenses when the conditions for such availability set forth in the Eclipse9# Public License 2.0 are satisfied: GNU General Public License, version 210# or later which is available at11# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html12# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later1314# @file wxgui.py15# @author Joerg Schweizer16# @date 20121718import os19import wx20import numpy as np21import shutil22import tempfile2324from agilepy.lib_wx.modulegui import ModuleGui25from agilepy.lib_wx.ogleditor import *26from agilepy.lib_wx.processdialog import ProcessDialog, ProcessDialogInteractive27import landuse28import maps2930from coremodules.misc import shapeformat313233class ParkingDrawings(Lines):34def __init__(self, ident, parking, parent, **kwargs):3536Lines.__init__(self, ident, parent,37name='Parking drawings',38linewidth=3,39**kwargs)4041self.delete('vertices')4243self.add(cm.AttrConf('color_default', np.array([0.0, 0.0, 0.7, 1.0], np.float32),44groupnames=['options'],45perm='wr',46metatype='color',47name='Default color',48info='Default color.',49))5051self.set_parking(parking)5253def get_netelement(self):54return self._parking5556def get_vertices_array(self):57# print 'get_vertices_array'58# print ' vertices',self._parking.vertices.value59return self._parking.vertices[self.get_ids()] # .value[self._inds_map]6061def set_netelement(self, element):62self.set_parking(element)6364def set_parking(self, parking):65# print '\nset_parking',len(parking)66self._parking = parking67if len(self) > 0:68self.clear_rows() # self.del_rows(1*self.get_ids())6970ids = self._parking.get_ids()71#self._inds_map = self._parking.get_inds(ids)72self.add_rows(ids=ids)73self.update()7475def update(self, is_update=True):76# assumes that arrsy structure did not change77# print 'FacilityDrawings.update'78n = len(self)79self.colors.value[:] = np.ones((n, 4), np.float32)*self.color_default.get_value()80self.colors_highl.value[:] = self._get_colors_highl(self.colors.value)8182if is_update:83self._update_vertexvbo()84self._update_colorvbo()858687class ZoneDrawings(Polygons):88def __init__(self, ident, zones, parent, **kwargs):8990Polygons.__init__(self, ident, parent,91name='Transport assignment zone drawings',92linewidth=4,93**kwargs)9495self.delete('vertices')9697self.add(cm.AttrConf('color_zone', np.array([0.3, 0.9, 0.5, 0.8], dtype=np.float32),98groupnames=['options'],99perm='wr',100metatype='color',101name='TAZ color',102info='Default color of traffic assignment zone.',103))104105self.set_netelement(zones)106107def get_netelement(self):108return self._zones109110def get_vertices_array(self):111# if self._is_not_synched:112# self._inds_map = self._zones.get_inds(self._zones.get_ids())113# self._is_not_synched = False114return self._zones.shapes[self.get_ids()] # .value[self._inds_map]115116def set_netelement(self, zones):117# print '\nset_facilities',facilities.get_ids()118self._zones = zones119if len(self) > 0:120self.clear_rows() # self.del_rows(self.get_ids())121122ids = self._zones.get_ids()123#self._inds_map = self._zones.get_inds(ids)124self.add_rows(ids=ids)125126# plugins to keep grapgics syncronized with netelements127zones.unplug()128zones.shapes.plugin.add_event(cm.EVTADDITEM, self.on_add_element)129zones.plugin.add_event(cm.EVTDELITEM, self.on_del_element)130131self._id_target = -1132self.update()133134def update(self, is_update=True):135# assumes that arrsy structure did not change136self.update_colours(is_update=False)137138if is_update:139self.update_internal()140141def update_colours(self, ids=None, is_update=True):142if ids is None:143ids = self.get_ids()144145inds = self._zones.get_inds(ids)146# print 'update_colours',ids, inds, type(inds)147# print ' ids_landusetype',self._zones.ids_landusetype.value148landusetypes = self._zones.parent.landusetypes149for id_landusetype in landusetypes.get_ids():150# print ' is=',id_landusetype,self._zones.ids_landusetype.value[inds]==id_landusetype,ids151ids_zone = ids[self._zones.ids_landusetype.value[inds] == id_landusetype]152self.colors[ids_zone] = np.ones((len(ids_zone), 4), np.float32)*landusetypes.colors[id_landusetype]153154self.colors_highl.value[:] = self._get_colors_highl(self.colors.value)155if is_update:156self._update_colorvbo()157158def update_internal(self):159# print 'update_internal'160# print ' len(self),len(self._zones)',len(self),len(self._zones)161#self._is_not_synched = True162self._update_vertexvbo()163self._update_colorvbo()164165def make_zone(self, shape, zonename='', id_landusetype=-1):166# print 'make_zone shape',shape,type(shape)167# print ' id_landusetype',id_landusetype168return self._zones.make(zonename=zonename, shape=shape,169id_landusetype=id_landusetype)170171def on_add_element(self, shapes, ids):172print 'on_add_element', shapes.attrname, ids173if shapes == self._zones.shapes:174self._id_target = ids[0]175self.add_row(_id=self._id_target,176colors=self.color_zone.value,177colors_highl=self._get_colors_highl(self.color_zone.value)178)179180#self._inds_map = self._zones.get_inds(self._zones.get_ids())181# self._update_vertexvbo()182# self._update_colorvbo()183184def begin_animation(self, id_target):185# print 'ZoneDrawings.begin_animation zones.shapes=\n',id_target,self._id_target, self._zones.shapes[id_target]186if self._id_target == -1:187self._id_target = id_target188self._drawobj_anim = self.parent.get_drawobj_by_ident(self._ident_drawobj_anim)189self.id_anim = self._drawobj_anim.add_drawobj(np.array(self._zones.shapes[self._id_target], np.float32).tolist(),190self.color_anim.value,191)192# print 'begin_animation',self.ident,_id,self._drawobj_anim193return True194195def end_animation(self, is_del_last_vert=False):196# print 'ZoneDrawings.end_animation',self.ident,self._id_target,self.id_anim197198# print ' verices =',self._drawobj_anim.vertices[self.id_anim]199# print ' self._drawobj_anim.vertices[self.id_anim]=',self._drawobj_anim.vertices[self.id_anim]200shape = self._drawobj_anim.vertices[self.id_anim]201self._zones.shapes[self._id_target] = shape202self._zones.coords[self._id_target] = self._zones.get_coords_from_shape(shape)203self.update_colours(ids=np.array([self._id_target])) # must pass np array204self.del_animation()205# print ' self.get_vertices_array()=\n',self.get_vertices_array()206# self._drawobj_anim.del_drawobj(self.id_anim)207208self.update_internal()209#self._inds_map = self._zones.get_inds(self._zones.get_ids())210# self._update_vertexvbo()211# self._update_colorvbo()212return True213214def del_elem(self, id_zone):215"""216Deletes an element from network and then in on canvas217through callback on_del_element218"""219# print 'del_elem'220# print ' len(self),len(self._zones)',len(self),len(self._zones)221222self._zones.del_element(id_zone)223224def on_del_element(self, obj, ids):225"""226callback from netelement227"""228if len(ids) != 1:229return False230# print 'on_del_element',obj,ids,self._id_target231# print ' len(self),len(self._zones)',len(self),len(self._zones)232# print ' verices =',self._drawobj_anim.vertices[self.id_anim]233self._is_not_synched = True234self.del_drawobj(ids[0])235# print ' len(self),len(self._zones)',len(self),len(self._zones)236# wx.CallAfter(self.update_internal)237# self.update_internal()238# print ' after CallAfter'239# print ' len(self),len(self._zones)',len(self),len(self._zones)240return True241242def del_animation(self, is_del_main=False):243# print 'end_animation',self.ident,_id,self._drawobj_anim244self._drawobj_anim.del_drawobj(self.id_anim)245self._drawobj_anim = None246247if is_del_main:248# self.del_drawobj(self._id_target)249# delete first element from net, which will250# call back on_del_netelement where the main drawobj is deleted251self.del_elem(self._id_target)252253self._id_target = -1254self.id_anim = -1255return True256257258class AddZoneTool(AddPolygonTool):259"""260Mixin for Selection tools for OGL canvas.261"""262263def __init__(self, parent, mainframe=None):264self.init_common('add_zone', parent, 'Add zone tool',265info='Click on canvas to add a zone. Add a vertex with a single click, double click to finish, right click to aboard.',266is_textbutton=False,267)268self.init_options()269270def init_options(self):271self.add(cm.AttrConf('zonename', '',272groupnames=['options'],273perm='rw',274name='Zone name',275info='Name of zone. Must be unique. If left blanc, a zone number will be automatically assigned.',276))277278self.add(cm.AttrConf('id_landusetype', '',279groupnames=['options'],280choices={'': -1},281perm='rw',282name='Type',283info='Landusetype of this zone. Use Mixed when unknown or ambiguous.',284))285286def activate(self, canvas=None):287"""288This call by metacanvas??TooldsPallet signals that the tool has been289activated and can now interact with metacanvas.290"""291# print 'activate'292AddPolygonTool.activate(self, canvas)293294landusetypes = self.get_landusetypes()295typekeychoice = landusetypes.typekeys.get_indexmap().copy()296typekeychoice[''] = -1297# print ' typekeys',landusetypes.typekeys.value298# print ' typekeychoice',typekeychoice299self.id_landusetype.choices = typekeychoice300self.id_landusetype.set_value(typekeychoice['mixed'])301canvas.draw()302303def get_scenario(self):304# get net and scenario via netdrawing305return self.get_drawing().get_net().parent306307def get_landusetypes(self):308return self.get_scenario().landuse.landusetypes309310def get_optionspanel(self, parent, size=(200, -1)):311"""312Return tool option widgets on given parent313"""314self._optionspanel = ObjPanel(parent, obj=self,315id=None,316attrconfigs=None,317#tables = None,318# table = None, id=None, ids=None,319groupnames=['options'],320func_change_obj=None,321show_groupnames=False, show_title=True, is_modal=False,322mainframe=self.parent.get_mainframe(),323pos=wx.DefaultPosition, size=size, style=wx.MAXIMIZE_BOX | wx.RESIZE_BORDER,324func_apply=self.on_apply_option,325immediate_apply=False, panelstyle='default', # 'instrumental'326standartbuttons=['apply', 'restore'])327328return self._optionspanel329330def set_button_info(self, bsize=(32, 32)):331# print 'set_button_info select tool' self.get_icon("icon_sumo_24px.png")332iconpath = os.path.join(os.path.dirname(__file__), 'images')333self._bitmap = wx.Bitmap(os.path.join(iconpath, 'fig_zone_24px.png'), wx.BITMAP_TYPE_PNG)334self._bitmap_sel = self._bitmap335336def begin_animation(self, event):337# print 'AddLineTool.begin_animation'338#self.drawobj_anim, _id, self.ind_vert = self.get_current_vertexselection()339self._optionspanel.apply()340self.drawobj_anim = self._canvas.get_drawing().get_drawobj_by_ident('zonedraws')341self.coord_last = self._canvas.unproject(event.GetPosition())342#vertices = [list(self.coord_last),list(self.coord_last) ]343vertices = [1.0*self.coord_last, 1.0*self.coord_last, ] # attention, we need copies here!!344# print ' vertices ',vertices#,self.width.get_value(),self.color.get_value(),345346# make drawobj make a zone347if self.id_landusetype.get_value() >= 0:348_id = self.drawobj_anim.make_zone(vertices,349zonename=self.zonename.get_value(),350id_landusetype=self.id_landusetype.get_value(),351)352self.ind_vert = 1353self.drawobj_anim.begin_animation(_id)354355# http://www.wxpython.org/docs/api/wx.Cursor-class.html356self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))357self.is_animated = True358359self.parent.refresh_optionspanel(self)360return True # True for redrawing361else:362# option values not valid363return False364365366class FacilityDrawings(ZoneDrawings):367def __init__(self, ident, facilities, parent, **kwargs):368369Polygons.__init__(self, ident, parent,370name='Facility drawings',371linewidth=1,372**kwargs)373374self.delete('vertices')375376self.add(cm.AttrConf('color_facility_default', np.array([0.921875, 0.78125, 0.4375, 1.0], np.float32),377groupnames=['options'],378perm='wr',379metatype='color',380name='Default color',381info='Default facility color.',382))383384self.set_facilities(facilities)385386# def is_tool_allowed(self, tool, id_drawobj = -1):387# """388# Returns True if this tool can be applied to this drawobj.389# Optionally a particular drawobj can be specified with id_drawobj.390# """391# # basic tools:392# #return tool.ident not in ['configure','select_handles','delete','move','stretch']393# return tool.ident not in ['delete',]394395def get_netelement(self):396return self._facilities397398def get_vertices_array(self):399return self._facilities.shapes[self.get_ids()] # .value[self._inds_map]400401def get_vertices(self, ids):402return self._facilities.shapes[ids]403404def set_vertices(self, ids, vertices, is_update=True):405self._facilities.set_shapes(ids, vertices)406if is_update:407self._update_vertexvbo()408409def set_netelement(self, element):410self.set_facilities(element)411412def set_facilities(self, facilities):413# print '\nset_facilities'#,facilities.get_ids()414415self._facilities = facilities416# print ' vertices ',self.get_vertices(facilities.get_ids())417if len(self) > 0:418self.clear_rows() # del_rows(self.get_ids())419420ids = self._facilities.get_ids()421#self._inds_map = self._facilities.get_inds(ids)422self.add_rows(ids=ids)423self._id_target = -1424425# plugins to keep grapgics syncronized with netelements426facilities.unplug()427facilities.shapes.plugin.add_event(cm.EVTADDITEM, self.on_add_element)428facilities.plugin.add_event(cm.EVTDELITEM, self.on_del_element)429430self.update()431432def update(self, is_update=True):433# assumes that arrsy structure did not change434# print 'FacilityDrawings.update'435n = len(self)436437# if n==0:return# causes problems with drawing the first houses438439self.colors.value[:] = np.ones((n, 4), np.float32)*self.color_facility_default.value440self.colors_highl.value[:] = self._get_colors_highl(self.colors.value)441442landusetypes = self._facilities.get_landusetypes()443ids_landusetype = self._facilities.ids_landusetype444for id_landusetype in landusetypes.get_ids():445#inds = np.flatnonzero(ids_landusetype == id_landusetype)446#color = landusetypes.colors[id_landusetype]447#self.colors.value[self._inds_map[inds]] = color448#self.colors.value[self._inds_map[np.flatnonzero(ids_landusetype == id_landusetype)]] = landusetypes.colors[id_landusetype]449self.colors[self._facilities.select_ids(450ids_landusetype.value == id_landusetype)] = landusetypes.colors[id_landusetype]451if is_update:452self._update_vertexvbo()453self._update_colorvbo()454455def update_colours(self, ids=None, is_update=True):456if ids is None:457ids = self.get_ids()458459inds = self._facilities.get_inds(ids)460# print 'update_colours',ids, inds, type(inds)461# print ' self.colors.value',self.colors.value462landusetypes = self._facilities.parent.landusetypes463# print ' ids_landusetype',self._facilities.ids_landusetype.value[inds]464for id_landusetype in landusetypes.get_ids():465# print ' is=',id_landusetype,self._zones.ids_landusetype.value[inds]==id_landusetype,ids466ids_fac = ids[self._facilities.ids_landusetype.value[inds] == id_landusetype]467# print ' ids_fac',ids_fac468469self.colors[ids_fac] = np.ones((len(ids_fac), 4), np.float32)*landusetypes.colors[id_landusetype]470471self.colors_highl.value[:] = self._get_colors_highl(self.colors.value)472if is_update:473self._update_colorvbo()474475def make(self, shape, id_sumo=None, osmkey='', id_landusetype=-1):476# print 'make_zone shape',shape,type(shape)477# print ' id_landusetype',id_landusetype478if id_sumo == '':479id_sumo = None480return self._facilities.make(id_sumo=id_sumo,481osmkey=osmkey, shape=shape,482id_landusetype=id_landusetype)483484def on_add_element(self, shapes, ids):485# print 'on_add_element',shapes.attrname,ids486if shapes == self._facilities.shapes:487self._id_target = ids[0]488id_target = self.add_row(_id=self._id_target,489colors=self.color_facility_default.get_value(),490colors_highl=self._get_colors_highl(self.color_facility_default.get_value())491)492# print ' self.colors.value',self.colors.value, id_target,self._id_target493#self._inds_map = self._zones.get_inds(self._zones.get_ids())494# self._update_vertexvbo()495# self._update_colorvbo()496497def begin_animation(self, id_target):498# print 'ZoneDrawings.begin_animation zones.shapes=\n',id_target,self._id_target, self._zones.shapes[id_target]499if self._id_target == -1:500self._id_target = id_target501self._drawobj_anim = self.parent.get_drawobj_by_ident(self._ident_drawobj_anim)502self.id_anim = self._drawobj_anim.add_drawobj(np.array(self._facilities.shapes[self._id_target], np.float32).tolist(),503self.color_anim.value,504)505# print 'begin_animation',self.ident,_id,self._drawobj_anim506return True507508def end_animation(self, is_del_last_vert=False):509# print 'ZoneDrawings.end_animation',self.ident,self._id_target,self.id_anim510511# print ' verices =',self._drawobj_anim.vertices[self.id_anim]512# print ' self._drawobj_anim.vertices[self.id_anim]=',self._drawobj_anim.vertices[self.id_anim]513shape = self._drawobj_anim.vertices[self.id_anim]514self._facilities.set_shape(self._id_target, shape)515#self._facilities.coords[self._id_target] = self._zones.get_coords_from_shape(shape)516self.update_colours(ids=np.array([self._id_target])) # must pass np array517self.del_animation()518# print ' self.get_vertices_array()=\n',self.get_vertices_array()519# self._drawobj_anim.del_drawobj(self.id_anim)520521# self.update_internal()522#self._inds_map = self._zones.get_inds(self._zones.get_ids())523self._update_vertexvbo()524self._update_colorvbo()525return True526527def del_elem(self, id_fac):528"""529Deletes an element from network and then in on canvas530through callback on_del_element531"""532# print 'del_elem'533534self._facilities.del_element(id_fac)535536537class AddFacilityTool(AddZoneTool):538"""539Mixin for Selection tools for OGL canvas.540"""541542def __init__(self, parent, mainframe=None):543self.init_common('add_facility', parent, 'Add buildings tool',544info='Click on canvas to add a building or facility. Add a vertex with a single click, double click to finish, right click to aboard.',545is_textbutton=False,546)547self.init_options()548549def init_options(self):550551self.add(cm.AttrConf('id_sumo', '',552groupnames=['options'],553perm='rw',554name='Unique name',555info='Unique name. When left blanc, a number will be assigned automatically.',556))557558self.add(cm.AttrConf('id_landusetype', '',559groupnames=['options'],560choices={'': -1},561perm='rw',562name='Type',563info='Landusetype of this facility. Use Mixed when unknown or ambiguous.',564))565566self.add(cm.AttrConf('osmkey', '',567groupnames=['options'],568perm='rw',569name='OSM key',570info='OSM key of facility.',571))572573def set_button_info(self, bsize=(32, 32)):574# print 'set_button_info select tool' self.get_icon("icon_sumo_24px.png")575iconpath = os.path.join(os.path.dirname(__file__), 'images')576self._bitmap = wx.Bitmap(os.path.join(iconpath, 'city-icon_24px.png'), wx.BITMAP_TYPE_PNG)577self._bitmap_sel = self._bitmap578579def begin_animation(self, event):580# print 'AddLineTool.begin_animation'581#self.drawobj_anim, _id, self.ind_vert = self.get_current_vertexselection()582self._optionspanel.apply()583self.drawobj_anim = self._canvas.get_drawing().get_drawobj_by_ident('facilitydraws')584self.coord_last = self._canvas.unproject(event.GetPosition())585#vertices = [list(self.coord_last),list(self.coord_last) ]586vertices = [1.0*self.coord_last, 1.0*self.coord_last, ] # attention, we need copies here!!587# print ' vertices ',vertices#,self.width.get_value(),self.color.get_value(),588589# make drawobj make a zone590if self.id_landusetype.get_value() >= 0:591_id = self.drawobj_anim.make(vertices, id_sumo=self.id_sumo.get_value(),592osmkey=self.osmkey.get_value(),593id_landusetype=self.id_landusetype.get_value(),594)595self.ind_vert = 1596self.drawobj_anim.begin_animation(_id)597self.id_sumo.set_value('')598599# http://www.wxpython.org/docs/api/wx.Cursor-class.html600self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))601self.is_animated = True602603self.parent.refresh_optionspanel(self)604return True # True for redrawing605else:606# option values not valid607return False608609610class WxGui(ModuleGui):611"""Contains functions that communicate between the widgets of the main wx gui612and the functions of the plugin.613"""614615def __init__(self, ident):616self._landuse = None617self._canvas = None618self._init_common(ident, priority=100,619icondirpath=os.path.join(os.path.dirname(__file__), 'images'))620621def get_module(self):622return self._landuse623624def get_scenario(self):625return self._mainframe.get_modulegui('coremodules.scenario').get_scenario()626627def get_neteditor(self):628return self._mainframe.get_modulegui('coremodules.network').get_neteditor()629630def get_canvas(self):631return self.get_neteditor().get_canvas()632633def get_drawing(self):634return self.get_canvas().get_drawing()635636def init_widgets(self, mainframe):637"""638Set mainframe and initialize widgets to various places.639"""640self._mainframe = mainframe641#self._neteditor = mainframe.add_view("Network", Neteditor)642643# mainframe.browse_obj(self._module)644self.make_menu()645self.make_toolbar()646647def refresh_widgets(self):648"""649Check through mainframe what the state of the application is650and reset widgets. For exampe enable/disable widgets651dependent on the availability of data.652"""653scenario = self.get_scenario()654# print 'landuse refresh_widgets',id(self._landuse),id(scenario.landuse),scenario.is_modified()655# if self._landuse:656# print ' self._landuse.is_modified',self._landuse.is_modified(),self._landuse == scenario.landuse657is_refresh = False658if self._landuse != scenario.landuse:659# print ' make new landuse instance'660del self._landuse661self._landuse = scenario.landuse662is_refresh = True663664elif self._landuse.is_modified():665# print ' self._landuse.is_modified',self._landuse.is_modified()666is_refresh = True667668elif self.get_canvas() != self._canvas:669is_refresh = True670671# print ' is_refresh',is_refresh672if is_refresh | self._is_needs_refresh:673self._is_needs_refresh = False674# print ' is_refresh',is_refresh,id(self._landuse)675neteditor = self.get_neteditor()676#canvas = self.get_canvas()677drawing = self.get_drawing() # canvas.get_drawing()678679# add or refresh facility drawing680drawing.set_element('facilitydraws', FacilityDrawings,681self._landuse.facilities, layer=5)682#drawobj = drawing.get_drawobj_by_ident('facilitydraws')683# if drawobj is not None:684# drawobj.set_facilities(self._landuse.facilities)685# else:686# facilitydrawings = FacilityDrawings(self._landuse.facilities, drawing)687# drawing.add_drawobj(facilitydrawings, layer = 5)688689# add or refresh zone drawing690drawing.set_element('zonedraws', ZoneDrawings,691self._landuse.zones, layer=100)692#drawobj = drawing.get_drawobj_by_ident('zonedraws')693# if drawobj is not None:694# drawobj.set_netelement(self._landuse.zones)695# else:696# zonedrawings = ZoneDrawings(self._landuse.zones, drawing)697# drawing.add_drawobj(zonedrawings, layer = 100)698699# add or refresh parking drawing700drawing.set_element('parkingdraws', ParkingDrawings,701self._landuse.parking, layer=50)702703#drawobj = drawing.get_drawobj_by_ident('parkingdraws')704# if drawobj is not None:705# drawobj.set_parking(self._landuse.parking)706# else:707# parkingdrawings = ParkingDrawings(self._landuse.parking, drawing)708# drawing.add_drawobj(parkingdrawings, layer = 50)709710neteditor.get_toolbox().add_toolclass(AddZoneTool) # will check if tool is already there711neteditor.get_toolbox().add_toolclass(AddFacilityTool)712neteditor.draw()713714self._canvas = self.get_canvas()715716def make_menu(self):717# print 'make_menu'718menubar = self._mainframe.menubar719menubar.append_menu('landuse')720721menubar.append_item('landuse/browse',722self.on_browse_obj, # common function in modulegui723info='View and browse landuse in object panel.',724bitmap=self.get_agileicon('icon_browse_24px.png'), # ,725)726727# wx.Bitmap(os.path.join(IMAGEDIR,'icon_sumo_24px.png'),wx.BITMAP_TYPE_PNG)728menubar.append_menu('landuse/maps',729bitmap=self.get_icon("map_24px.png"),730)731732menubar.append_item('landuse/maps/download...',733self.on_import_backgroundmaps,734info='Download backgroundmaps from the Intenet. Requires active Internet connection, and python packages pyproj and PIL.',735bitmap=self.get_icon('map_add_24px.png'),736)737738menubar.append_item('landuse/maps/clear',739self.on_clear_backgroundmaps,740info='Clear all background maps.',741bitmap=self.get_icon('map_del_24px.png'),742)743744menubar.append_item('landuse/maps/import elevations from csv',745self.on_import_elevations_from_csv,746#bitmap = wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE,wx.ART_MENU),747)748749menubar.append_menu('landuse/zones',750bitmap=self.get_icon("fig_zone_24px.png"),751)752753menubar.append_item('landuse/zones/import from shapefile...',754self.on_import_zones_from_shape,755#bitmap = self.get_icon('Files-Osm-icon_24.png'),#756)757menubar.append_item('landuse/zones/identify zone edges',758self.on_refresh_zoneedges,759info='Identify network edges that are located within each zone.',760#bitmap = self.get_icon('Files-Osm-icon_24.png'),#761)762menubar.append_item('landuse/zones/identify zone areas',763self.on_refresh_zoneareas,764info='Identify area of each zone in square kilometers.',765#bitmap = self.get_icon('Files-Osm-icon_24.png'),#766)767menubar.append_item('landuse/zones/export zone.kml',768self.on_export_zone_kml,769info='Export zones in .kml format.',770bitmap=self.get_agileicon("Document_Export_24px.png"),771)772menubar.append_item('landuse/zones/export to shape file...',773self.on_zones_to_shapefile,774#bitmap = wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE,wx.ART_MENU)775bitmap=self.get_agileicon("Document_Export_24px.png"),776)777menubar.append_item('landuse/zones/clear all',778self.on_clear_zones,779info='Delete all zones.',780bitmap=wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_MENU),781)782783menubar.append_menu('landuse/facilities',784bitmap=self.get_icon("city-icon_24px.png"),785)786787menubar.append_item('landuse/facilities/import from poly file...',788self.on_import_poly, info='Import SUMO poly xml file...',789#bitmap = wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE,wx.ART_MENU)790bitmap=self.get_agileicon("Document_Import_24px.png"),791)792793menubar.append_item('landuse/facilities/export to poly file...',794self.on_export_poly, info='Export facilities to SUMO poly xml file...',795#bitmap = wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE,wx.ART_MENU)796bitmap=self.get_agileicon("Document_Export_24px.png"),797)798menubar.append_item('landuse/facilities/export to shape file...',799self.on_facilities_to_shapefile,800#bitmap = wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE,wx.ART_MENU)801bitmap=self.get_agileicon("Document_Export_24px.png"),802)803menubar.append_item('landuse/facilities/export kml file...',804self.on_facilities_to_kml,805#bitmap = wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE,wx.ART_MENU)806bitmap=self.get_agileicon("Document_Export_24px.png"),807)808menubar.append_item('landuse/facilities/clean osm file...',809self.on_clean_osm,810info='Cleans OSM file from strange characters. Use if you have trouble importing from OSM.',811bitmap=self.get_icon('Files-Osm-icon_24.png'),812)813814menubar.append_item('landuse/facilities/import from osm...',815self.on_import_osm,816info='Import landuse from osm files.',817bitmap=self.get_icon('Files-Osm-icon_24.png'),818)819820menubar.append_item('landuse/facilities/generate facilities...',821self.on_generate_facilities,822)823824menubar.append_item('landuse/facilities/identify zone',825self.on_identify_taz,826info='Identify the traffic assignment zone for each facility.',827#bitmap = self.get_icon('Files-Osm-icon_24.png'),#828)829830menubar.append_item('landuse/facilities/find closest edge',831self.on_identify_closest_edge,832info='Find for each building the closes access to the network. This will be the point on the network where people access the facility.',833#bitmap = self.get_icon('Files-Osm-icon_24.png'),#834)835menubar.append_item('landuse/facilities/update all facilities',836self.on_update_facilities,837)838menubar.append_item('landuse/facilities/clear all facilities',839self.on_clear_facilities,840bitmap=wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_MENU),841)842843menubar.append_menu('landuse/parking',844#bitmap = self.get_icon("Document_Import_24px.png"),845)846menubar.append_item('landuse/parking/generate parking...',847self.on_make_parking,848#bitmap = self.get_icon('Files-Osm-icon_24.png'),#849)850menubar.append_item('landuse/parking/clear parking',851self.on_clear_parking,852info='Delete all parking.',853bitmap=wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_MENU),854)855856def on_import_elevations_from_csv(self, event=None):857"""858Import elevation from a csv file.859"""860p = landuse.maps.CsvElevationsImport(self.get_scenario().net, logger=self._mainframe.get_logger())861dlg = ProcessDialog(self._mainframe, p, immediate_apply=True)862863dlg.CenterOnScreen()864865# this does not return until the dialog is closed.866val = dlg.ShowModal()867# print ' val,val == wx.ID_OK',val,wx.ID_OK,wx.ID_CANCEL,val == wx.ID_CANCEL868# print ' status =',dlg.get_status()869if dlg.get_status() != 'success': # val == wx.ID_CANCEL:870# print ">>>>>>>>>Unsuccessful\n"871dlg.Destroy()872873if dlg.get_status() == 'success':874# print ">>>>>>>>>successful\n"875# apply current widget values to scenario instance876dlg.apply()877dlg.Destroy()878# self._mainframe.browse_obj(self.get_scenario().net.edges)879self._mainframe.refresh_moduleguis()880#self._is_needs_refresh = True881# self.refresh_widgets()882883def on_import_zones_from_shape(self, event=None):884"""885Import zones from shape file format.886"""887888proc = landuse.ZonesFromShapeImporter('shapeimporter', self._landuse.zones, logger=self._mainframe.get_logger())889dlg = ProcessDialog(self._mainframe, proc, immediate_apply=True)890891dlg.CenterOnScreen()892893# this does not return until the dialog is closed.894val = dlg.ShowModal()895# print ' val,val == wx.ID_OK',val,wx.ID_OK,wx.ID_CANCEL,val == wx.ID_CANCEL896# print ' status =',dlg.get_status()897if dlg.get_status() != 'success': # val == wx.ID_CANCEL:898# print ">>>>>>>>>Unsuccessful\n"899dlg.Destroy()900901if dlg.get_status() == 'success':902# print ">>>>>>>>>successful\n"903# apply current widget values to scenario instance904dlg.apply()905dlg.Destroy()906# self._landuse.zones.refresh_zoneedges()907self._mainframe.browse_obj(self._landuse.zones)908self._is_needs_refresh = True909self._mainframe.refresh_moduleguis()910911def on_refresh_zoneedges(self, event=None):912self._landuse.zones.refresh_zoneedges()913self._mainframe.browse_obj(self._landuse.zones)914915def on_refresh_zoneareas(self, event=None):916self._landuse.zones.refresh_zonearea()917self._mainframe.browse_obj(self._landuse.zones)918919def on_identify_taz(self, event=None):920self._landuse.facilities.identify_taz()921self._mainframe.browse_obj(self._landuse.facilities)922923def on_identify_closest_edge(self, event=None):924self._landuse.facilities.identify_closest_edge()925self._mainframe.browse_obj(self._landuse.facilities)926927def on_make_parking(self, event=None):928"""929Generate on road parking areas on the street network930"""931# self._landuse.parking.make_parking()932#self._canvas = canvas.draw()933#drawing = self.get_drawing().get_drawobj_by_ident('parkingdraws')934935# TODO: make a proper import mask that allows to set parameters936# self._landuse.maps.download()937proc = landuse.ParkingGenerator('parkinggenerator', self._landuse.parking, logger=self._mainframe.get_logger())938dlg = ProcessDialog(self._mainframe, proc, immediate_apply=True)939940dlg.CenterOnScreen()941942# this does not return until the dialog is closed.943val = dlg.ShowModal()944# print ' val,val == wx.ID_OK',val,wx.ID_OK,wx.ID_CANCEL,val == wx.ID_CANCEL945# print ' status =',dlg.get_status()946if dlg.get_status() != 'success': # val == wx.ID_CANCEL:947# print ">>>>>>>>>Unsuccessful\n"948dlg.Destroy()949950if dlg.get_status() == 'success':951# print ">>>>>>>>>successful\n"952# apply current widget values to scenario instance953dlg.apply()954dlg.Destroy()955self._mainframe.browse_obj(self._landuse.parking)956self._mainframe.refresh_moduleguis()957958def on_clear_parking(self, event=None):959self._landuse.parking.clear()960#self._canvas = canvas.draw()961#drawing = self.get_drawing().get_drawobj_by_ident('parkingdraws')962self._mainframe.browse_obj(self._landuse.parking)963self._mainframe.refresh_moduleguis()964965def on_clean_osm(self, event=None):966967scenario = self.get_scenario()968wildcards_all = "All files (*.*)|*.*"969wildcards_xml = "Poly xml files (*.osm.xml)|*.osm.xml|XML files (*.xml)|*.xml"970wildcards = wildcards_xml+"|"+wildcards_all971972# Finally, if the directory is changed in the process of getting files, this973# dialog is set up to change the current working directory to the path chosen.974dlg = wx.FileDialog(975self._mainframe, message="Choose one or more osm files to clean",976defaultDir=scenario.get_workdirpath(),977# defaultFile = os.path.join(scenario.get_workdirpath(), scenario.get_rootfilename()+'osm.xml'),978wildcard=wildcards,979style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR980)981982# Show the dialog and retrieve the user response. If it is the OK response,983# process the data.984if dlg.ShowModal() == wx.ID_OK:985# This returns a Python list of files that were selected.986paths = dlg.GetPaths()987# print 'You selected %d files:' % len(paths)988if len(paths) > 0:989990for path in paths:991# print ' %s' % path992path_temp = path+'.clean'993landuse.clean_osm(path, path_temp)994#shutil.copy (path_temp, path)995shutil.move(path_temp, path)996997self._mainframe.browse_obj(self._landuse)998self._mainframe.refresh_moduleguis()9991000# inform plugins10011002# Destroy the dialog. Don't do this until you are done with it!1003# BAD things can happen otherwise!1004dlg.Destroy()10051006def on_import_poly(self, event=None):1007# TODO: here we could make a nice dialog asking if1008# existing file should be overwritten.1009#self.write_to_statusbar('Import facilities', key='action')1010# Create the dialog. In this case the current directory is forced as the starting1011# directory for the dialog, and no default file name is forced. This can easilly1012# be changed in your program. This is an 'open' dialog, and allows multitple1013# file selections as well.1014#1015scenario = self.get_scenario()1016wildcards_all = "All files (*.*)|*.*"1017wildcards_xml = "Poly xml files (*.poly.xml)|*.poly.xml|XML files (*.xml)|*.xml"1018wildcards = wildcards_xml+"|"+wildcards_all10191020# Finally, if the directory is changed in the process of getting files, this1021# dialog is set up to change the current working directory to the path chosen.1022dlg = wx.FileDialog(1023self._mainframe, message="Choose one or more poly files",1024defaultDir=scenario.get_workdirpath(),1025# defaultFile = scenario.get_rootfilepath()+'.poly.xml',1026wildcard=wildcards,1027style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR1028)10291030# Show the dialog and retrieve the user response. If it is the OK response,1031# process the data.1032if dlg.ShowModal() == wx.ID_OK:1033# This returns a Python list of files that were selected.1034paths = dlg.GetPaths()1035# print 'You selected %d files:' % len(paths)1036if len(paths) > 0:10371038for path in paths:1039# print ' %s' % path1040#readNet(path, net = net)1041dirname = os.path.dirname(path)1042filename_raw = os.path.basename(path)1043filename = filename_raw.split('.')[0]1044self._landuse.import_polyxml(filename, dirname=dirname)10451046self._mainframe.browse_obj(self._landuse)1047self._is_needs_refresh = True1048self._mainframe.refresh_moduleguis()10491050# Destroy the dialog. Don't do this until you are done with it!1051# BAD things can happen otherwise!1052dlg.Destroy()10531054def on_zones_to_shapefile(self, event=None):1055"""1056Export facility data to shape file.1057"""1058# print 'on_edges_to_shapefile'10591060dirpath = self._landuse.parent.get_workdirpath()1061defaultFile = self._landuse.parent.get_rootfilename()+'.facil.shp'1062wildcards_all = 'All files (*.*)|*.*|SHP files (*.shp)|*.shp'1063dlg = wx.FileDialog(None, message='Export facilities to shapefile',1064defaultDir=dirpath,1065# defaultFile=defaultFile,1066wildcard=wildcards_all, style=wx.SAVE | wx.CHANGE_DIR)1067if dlg.ShowModal() == wx.ID_OK:1068filepath = dlg.GetPath()10691070else:1071return10721073shapeformat.zones_to_shapefile(self._landuse.zones,1074filepath,1075log=self._mainframe.get_logger())10761077def on_export_zone_kml(self, event=None):1078self._landuse.zones.export_sumokml()1079self._mainframe.browse_obj(self._landuse.zones)1080self._is_needs_refresh = True1081self._mainframe.refresh_moduleguis()10821083def on_clear_zones(self, event=None):1084self._landuse.zones.clear()1085self._mainframe.browse_obj(self._landuse.zones)1086self._is_needs_refresh = True1087self._mainframe.refresh_moduleguis()10881089def on_generate_facilities(self, event=None):1090"""1091Generates mobility plans using different strategies..1092"""1093self._landuse.facilities.unplug()1094self.proc = landuse.FacilityGenerator('facilitygenerator',1095self._landuse.facilities,1096logger=self._mainframe.get_logger()1097)10981099dlg = ProcessDialogInteractive(self._mainframe,1100self.proc,1101title=self.proc.get_name(),1102func_close=self.close_process_facilities,1103)11041105dlg.CenterOnScreen()11061107# this does not return until the dialog is closed.1108#val = dlg.ShowModal()1109dlg.Show()1110dlg.MakeModal(True)11111112def close_process_facilities(self, dlg):1113# called before destroying the process dialog1114print 'close_process_facilities', self.proc.status1115if self.proc.status == 'success':1116self._mainframe.browse_obj(self._landuse.facilities)1117self._is_needs_refresh = True11181119self._mainframe.refresh_moduleguis()11201121def on_clear_facilities(self, event=None):1122"""Delete all facilities."""1123self._landuse.facilities.clear()1124self._mainframe.browse_obj(self._landuse.facilities)1125self._is_needs_refresh = True1126self._mainframe.refresh_moduleguis()11271128def on_update_facilities(self, event=None):1129"""Update area and capacities of all facilities."""1130self._landuse.facilities.update()1131self._mainframe.browse_obj(self._landuse.facilities)1132#self._is_needs_refresh = True1133# self._mainframe.refresh_moduleguis()11341135def on_export_poly(self, event=None):1136scenario = self.get_scenario()1137wildcards_all = "All files (*.*)|*.*"1138wildcards_xml = "Poly xml files (*.poly.xml)|*.poly.xml|XML files (*.xml)|*.xml"1139wildcards = wildcards_xml+"|"+wildcards_all11401141# Finally, if the directory is changed in the process of getting files, this1142# dialog is set up to change the current working directory to the path chosen.1143dlg = wx.FileDialog(1144self._mainframe, message="Choose one or more poly files",1145defaultDir=scenario.get_workdirpath(),1146# defaultFile = scenario.get_rootfilepath()+'.poly.xml',1147wildcard=wildcards,1148style=wx.SAVE | wx.CHANGE_DIR1149)11501151# Show the dialog and retrieve the user response. If it is the OK response,1152# process the data.1153if dlg.ShowModal() == wx.ID_OK:1154# This returns a Python list of files that were selected.1155path = dlg.GetPath()1156# print 'You selected %d files:' % len(paths)1157if path is not "":1158self._landuse.export_polyxml(path)11591160dlg.Destroy()11611162def on_facilities_to_shapefile(self, event=None):1163"""1164Export facility data to shape file.1165"""1166# print 'on_edges_to_shapefile'11671168dirpath = self._landuse.parent.get_workdirpath()1169defaultFile = self._landuse.parent.get_rootfilename()+'.facil.shp'1170wildcards_all = 'All files (*.*)|*.*|SHP files (*.shp)|*.shp'1171dlg = wx.FileDialog(None, message='Export facilities to shapefile',1172defaultDir=dirpath,1173# defaultFile=defaultFile,1174wildcard=wildcards_all, style=wx.SAVE | wx.CHANGE_DIR)1175if dlg.ShowModal() == wx.ID_OK:1176filepath = dlg.GetPath()11771178else:1179return11801181shapeformat.facilities_to_shapefile(self._landuse.facilities,1182filepath,1183log=self._mainframe.get_logger())11841185def on_facilities_to_kml(self, event=None):1186"""1187Export facility data to kml file.1188"""1189# print 'on_edges_to_kml'11901191self._landuse.facilities.export_sumokml()1192self._mainframe.browse_obj(self._landuse.zones)1193self._is_needs_refresh = True1194self._mainframe.refresh_moduleguis()11951196def on_import_osm(self, event=None):1197importer = landuse.OsmPolyImporter(self._landuse, logger=self._mainframe.get_logger())1198dlg = ProcessDialog(self._mainframe, importer)11991200dlg.CenterOnScreen()12011202# this does not return until the dialog is closed.1203val = dlg.ShowModal()1204# print ' val,val == wx.ID_OK',val,wx.ID_OK,wx.ID_CANCEL,val == wx.ID_CANCEL1205# print ' status =',dlg.get_status()1206if dlg.get_status() != 'success': # val == wx.ID_CANCEL:1207dlg.Destroy()12081209if dlg.get_status() == 'success':1210dlg.apply()1211dlg.Destroy()1212self._mainframe.browse_obj(self._landuse)1213self._is_needs_refresh = True1214self._mainframe.refresh_moduleguis()12151216def on_clear_backgroundmaps(self, event=None):1217self._landuse.maps.clear_all()1218self._mainframe.browse_obj(self._landuse.maps)12191220def on_import_backgroundmaps(self, event=None):1221# TODO: make a proper import mask that allows to set parameters1222# self._landuse.maps.download()1223importer = maps.MapsImporter(self._landuse.maps, logger=self._mainframe.get_logger())1224dlg = ProcessDialog(self._mainframe, importer, immediate_apply=True)12251226dlg.CenterOnScreen()12271228# this does not return until the dialog is closed.1229val = dlg.ShowModal()1230# print ' val,val == wx.ID_OK',val,wx.ID_OK,wx.ID_CANCEL,val == wx.ID_CANCEL1231# print ' status =',dlg.get_status()1232if dlg.get_status() != 'success': # val == wx.ID_CANCEL:1233# print ">>>>>>>>>Unsuccessful\n"1234dlg.Destroy()12351236if dlg.get_status() == 'success':1237# print ">>>>>>>>>successful\n"1238# apply current widget values to scenario instance1239dlg.apply()1240dlg.Destroy()1241self._mainframe.browse_obj(self._landuse.maps)124212431244