Path: blob/main/tools/contributed/sumopy/coremodules/landuse/landuse.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 landuse.py15# @author Joerg Schweizer16# @date 20121718import maps19from agilepy.lib_base.processes import Process, CmlMixin20from collections import OrderedDict21from numpy import random22import numpy as np23from coremodules.misc.shapeformat import ShapefileImporter24from coremodules.network.network import SumoIdsConf, MODES25from agilepy.lib_base.misc import string_to_float26from agilepy.lib_base.geometry import *27import agilepy.lib_base.xmlman as xm28import agilepy.lib_base.arrayman as am29import agilepy.lib_base.classman as cm30from coremodules.modules_common import *31import os32import sys33import time34import shutil35from xml.sax import saxutils, parse, handler36if __name__ == '__main__':37try:38APPDIR = os.path.dirname(os.path.abspath(__file__))39except:40APPDIR = os.path.dirname(os.path.abspath(sys.argv[0]))41SUMOPYDIR = os.path.join(APPDIR, '..', '..')42sys.path.append(SUMOPYDIR)43try:44import pyproj45except:46from mpl_toolkits.basemap import pyproj4748#from coremodules.network.routing import get_mincostroute_edge2edges4950try:51from shapely.geometry import MultiPoint, Polygon52IS_SHAPELY = True53except:54IS_SHAPELY = False555657def clean_osm(filepath_in, filepath_out):58"""59Clean osm file from strange characters that compromize importing.60"""61#62substitutes = {""": "'", "&": "+"}63fd_in = open(filepath_in, 'r')64fd_out = open(filepath_out, 'w')65for line in fd_in.readlines():66for oldstr, newstr in substitutes.iteritems():67line = line.replace(oldstr, newstr)68fd_out.write(line)69fd_in.close()70fd_out.close()717273class LanduseTypes(am.ArrayObjman):74def __init__(self, parent, is_add_default=True, **kwargs):7576self._init_objman(ident='landusetypes',77parent=parent,78name='Landuse types',79info='Table with information on landuse types',80**kwargs)8182self._init_attributes()83if is_add_default:84self.add_types_default()8586def _init_attributes(self):87# landuse types table88self.add_col(am.ArrayConf('typekeys', '',89is_index=True,90dtype='object', # actually a string of variable length91perm='r',92name='Type',93info='Type of facility. Must be unique, because used as key.',94))9596# self.add_col(am.ArrayConf( 'osmid', '',97# dtype = 'object',# actually a string of variable length98# perm='rw',99# name = 'Name',100# info = 'Name of facility type used as reference in OSM.',101# ))102103self.add_col(am.ArrayConf('colors', np.ones(4, np.float32),104dtype=np.float32,105metatype='color',106perm='rw',107name='Colors',108info="Color corrispondig to landuse type as RGBA tuple with values from 0.0 to 1.0",109xmltag='color',110))111112self.add_col(am.ArrayConf('descriptions', '',113dtype='object', # actually a string of variable length114perm='r',115name='Info',116info='Information about this landuse.',117))118119self.add_col(am.ArrayConf('are_area', False,120perm='rw',121name='is area',122info='True if this is an area of particular use, instead of a single facility. An area can include several facilities. If False, then it is dealt with a single facility.',123))124125self.add_col(am.ListArrayConf('osmfilters',126perm='r',127name='OSM filter',128info='List of openstreetmap filters that allow to identify this facility type.',129))130131# this will remove all previous and setnw132if len(self) > 0:133self.clear()134self.add_types_default()135136def get_landusetype_facility_from_area(self, id_landuse_area):137# get typekey138typekey_area = self.typekeys[id_landuse_area]139typekey_info = typekey_area.split('_')140if len(typekey_info) == 2:141if typekey_info[1] == 'area':142return self.typekeys.get_id_from_index(typekey_info[0])143else:144# no area, return unchanged145return id_landuse_area146else:147# no area, return unchanged148return id_landuse_area149150def format_ids(self, ids):151return ','.join(self.typekeys[ids])152153def get_id_from_formatted(self, idstr):154return self.typekeys.get_id_from_index(idstr)155156def get_ids_from_formatted(self, idstrs):157return self.typekeys.get_ids_from_indices_save(idstrs.split(','))158159def add_types_default(self):160# default types161self.add_row(typekeys='leisure',162descriptions='Facilities which offer leasure type activities',163osmfilters=['historic.church', 'building.church', 'sport', 'sport.*'],164colors=(0.2, 0.5, 0.3, 0.7)165)166# leisure.nature_reserve is actually an area so remove 'leisure.*'167168self.add_row(typekeys='commercial',169descriptions='Facility with trade, offices, banks, shopping opportunitties, etc.',170osmfilters=['building.hospital', 'building.retail', 'building.shop',171'building.restaurant', 'building.cafe', 'restaurant', 'shop.*', 'building.commercial', ],172colors=(0.6171875, 0.6171875, 0.875, 0.7),173)174175self.add_row(typekeys='industrial',176descriptions='industrial production facilities.',177osmfilters=['building.industrial'],178colors=(0.89453125, 0.65625, 0.63671875, 0.7),179)180181self.add_row(typekeys='parking',182descriptions='Areas reserved for car parking. This can be either area or building.',183osmfilters=['building.parking', ],184colors=(0.52734375, 0.875, 0.875, 0.7),185)186187self.add_row(typekeys='residential',188descriptions='Facilities with residential use',189osmfilters=['building.house', 'building.apartments', 'building.*', 'building'],190colors=(0.921875, 0.78125, 0.4375, 0.7),191)192193self.add_row(typekeys='mixed',194descriptions='Facilities with mixed land use, which cannot be clearly assigned to one of the other landuse types.',195osmfilters=[],196colors=(0.5, 0.9, 0.5, 0.7),197)198199self.add_row(typekeys='sink',200descriptions='Areas where vehicles disappear (evaporate). These zones are used for turn-flow demand models in order to avoid the creation of routes with loops.',201osmfilters=[],202colors=(0.5, 0.0, 0.1, 1.0),203)204self.add_row(typekeys='education',205descriptions='Educational facilities such as schools, universities',206# with amenity and landuse, we should look inside and assign all buildings207osmfilters=['building.school', 'building.university'],208colors=(0.89453125, 0.65625, 0.89453125, 0.7),209)210211self.add_row(typekeys='leisure_area',212descriptions='Areas on which leasure type activitiesbare offered',213osmfilters=['leisure.park', 'park', 'amenity.park',214'landuse.park', 'amenity.sport', 'landuse.sport'],215are_area=True,216colors=(0.2, 0.5, 0.3, 0.7)217)218219self.add_row(typekeys='industrial_area',220descriptions='Area with industrial production facilities.',221osmfilters=['amenity.industrial', 'landuse.industrial', ],222are_area=True,223colors=(0.89453125, 0.65625, 0.63671875, 0.7),224)225226self.add_row(typekeys='commercial_area',227descriptions='Areas with trade, offices, banks, shopping opportunitties, or other customer services.',228osmfilters=['amenity.hospital', 'amenity.commercial', 'landuse.commercial', ],229colors=(0.6171875, 0.6171875, 0.875, 0.7),230are_area=True,231)232233self.add_row(typekeys='residential_area',234descriptions='Areas with residential facilities.',235osmfilters=['amenity.residential', 'landuse.residential'],236colors=(0.921875, 0.78125, 0.4375, 0.7),237are_area=True,238)239240self.add_row(typekeys='mixed_area',241descriptions='Facilities with mixed land use, which cannot be clearly assigned to one of the other landuse types.',242osmfilters=[],243colors=(0.5, 0.9, 0.5, 0.7),244are_area=True,245)246247self.add_row(typekeys='education_area',248descriptions='Educational facilities such as schools, universities',249osmfilters=['landuse.university', 'landuse.school', 'amenity.school', 'amenity.university'],250colors=(0.89453125, 0.65625, 0.89453125, 0.7),251are_area=True,252)253254self.add_row(typekeys='parking_area',255descriptions='Areas reserved for car parking. This can be either area or building.',256osmfilters=['amenity.parking'],257colors=(0.52734375, 0.875, 0.875, 0.7),258are_area=True,259)260261262class Zones(am.ArrayObjman):263def __init__(self, parent, edges, **kwargs):264self._init_objman(ident='zones', parent=parent,265name='Zones',266info='Traffic Zones which can be used for zone-to-zone traffic transport demand or to specify zones for traffic evaporation.',267is_plugin=True,268version=0.3,269**kwargs)270271self._init_attributes()272self._init_constants()273274def _init_attributes(self):275# print 'Zones._init_attributes',hasattr(self,'are_evaporate'),'version',self.get_version()276edges = self.parent.get_net().edges277self.add_col(SumoIdsConf('Zone', name='Name', perm='rw', info='Unique short name or ID to identify zone.'))278279self.add_col(am.ArrayConf('names_extended', '',280dtype=np.object,281groupnames=['parameter'],282perm='rw',283name='Extended name',284info='Extended, human readable name, no uniqueness required, not used as key.',285))286287self.add_col(am.IdsArrayConf('ids_landusetype', self.parent.landusetypes,288id_default=6,289#choices = self.parent.landusetypes.typekeys.get_indexmap(),290#choiceattrname = 'typekeys',291groupnames=['state'],292perm='rw',293name='Type',294info='Zone type. This is actually the landuse type.',295))296297self.add_col(am.ArrayConf('coords', np.zeros(3, dtype=np.float32),298groupnames=['state'],299perm='r',300name='Coords',301unit='m',302info='Zone center coordinates.',303is_plugin=True,304))305306self.add_col(am.ListArrayConf('shapes',307groupnames=['_private'],308perm='rw',309name='Shape',310unit='m',311info='List of 3D Shape coordinates delimiting a zone.',312is_plugin=True,313))314315self.add_col(am.ListArrayConf('areas',316groupnames=['state'],317perm='rw',318name='Area',319unit='km^2',320info='Area of the zone in square kilometers.',321is_plugin=True,322))323324# self.add_col(am.IdlistsArrayConf( 'ids_edges_orig', edges,325# groupnames = ['state'],326# name = 'IDs orig edges',327# info = 'List with IDs of network edges that can be used as origins for trips in this zone.',328# ))329330# self.add_col(am.IdlistsArrayConf( 'ids_edges_dest', edges,331# groupnames = ['state'],332# name = 'IDs dest edges',333# info = 'List with IDs of network edges that can be used as origins for trips in this zone.',334# ))335336if self.get_version() < 0.2:337self.delete('priority_max')338self.delete('speed_max')339self.delete('n_edges_min_length')340self.delete('n_edges_max_length')341342# self.add_col(am.ListArrayConf( 'probs_edges_orig',343# groupnames = ['_private'],344# #perm='rw',345# name = 'edge probs origin',346# info = 'Probabilities of edges to be at the origin of a trip departing from this zone.',347# ))348# self.add_col(am.ListArrayConf( 'probs_edges_dest',349# groupnames = ['_private'],350# #perm='rw',351# name = 'edge probs dest',352# info = 'Probabilities of edges to be a destination of a trip arriving at this zone.',353# ))354355self.add_col(am.IdlistsArrayConf('ids_edges_inside', edges,356groupnames=['state'],357name='Edge IDs inside',358info='List with IDs of network edges that are entirely inside each zone.',359))360361if self.get_version() < 0.3:362ids = self.get_ids()363self.ids_edges_inside[ids] = self.ids_edges_orig[ids]364self.delete('ids_edges_dest')365self.delete('ids_edges_orig')366self.delete('probs_edges_orig')367self.delete('probs_edges_dest')368369self.set_version(0.3)370371def _init_constants(self):372self._proj = None373self._offset = None374self._mode_to_edges_inside = {}375attrsman = self.get_attrsman()376attrsman.do_not_save_attrs(['_proj', '_offset', '_mode_to_edges_inside'])377# self.set_version(0.2)378379def make(self, zonename='',380coord=np.zeros(3, dtype=np.float32),381shape=[],382id_landusetype=-1):383"""384Add a zone385"""386# print 'Zone.make',coord387# print ' shape',type(shape),shape388389self.get_coords_from_shape(shape)390id_zone = self.add_row(coords=self.get_coords_from_shape(shape),391shapes=shape, areas=find_area(shape)/1000000.,392ids_landusetype=id_landusetype,393)394if zonename == '':395self.ids_sumo[id_zone] = str(id_zone)396else:397self.ids_sumo[id_zone] = zonename398399self.identify_zoneedges(id_zone)400# print ' shapes\n',self.shapes.value401# print ' zone.shapes[id_zone]\n',self.shapes[id_zone]402403return id_zone404405def format_ids(self, ids):406return ','.join(self.ids_sumo[ids])407408def get_id_from_formatted(self, idstr):409return self.ids_sumo.get_id_from_index(idstr)410411def get_ids_from_formatted(self, idstrs):412return self.ids_sumo.get_ids_from_indices_save(idstrs.split(','))413414def get_coords_from_shape(self, shape):415# print 'get_coords_from_shape',np.array(shape),np.mean(np.array(shape),0)416return np.mean(np.array(shape), 0)417418def del_element(self, id_zone):419# print 'del_element',id_zone420self.del_row(id_zone)421422def get_edges(self):423return self.ids_edges_inside.get_linktab()424425def update_zones(self):426"""Update all dependent attributes of all zones"""427ids = self.get_ids()428for id_zone, shape in zip(ids, self.shapes[ids]):429self.coords[id_zone] = self.get_coords_from_shape(shape)430self.areas[id_zone] = find_area(shape)/1000000.0431self.identify_zoneedges(id_zone)432433def refresh_zoneedges(self):434for _id in self.get_ids():435self.identify_zoneedges(_id)436# self.make_egdeprobs(_id)437self.coords[_id] = self.get_coords_from_shape(self.shapes[_id])438439def refresh_zonearea(self):440"""441Update the area of each zone442"""443ids_zone = self.get_ids()444for id_zone in ids_zone:445self.identify_zonearea(id_zone)446447def update_netoffset(self, deltaoffset):448"""449Called when network offset has changed.450Children may need to adjust theur coordinates.451"""452# self.zones.update_netoffset(deltaoffset)453self.coords.value[:, :2] = self.coords.value[:, :2] + deltaoffset454shapes = self.shapes.value455for i in xrange(len(shapes)):456s = np.array(shapes[i])457s[:, :2] = s[:, :2] + deltaoffset458shapes[i] = list(s)459460def identify_zonearea(self, id_zone):461# print 'identify_zonearea',id_zone462shape = self.shapes[id_zone]463self.areas[id_zone] = find_area(shape)/1000000.0464465def identify_zoneedges(self, id_zone):466print 'identify_zoneedges of id_zone', id_zone467468if len(self.shapes[id_zone]) >= 3:469# must have at least 3 vertices to be an area470471inds_within = []472ind = 0473# print ' self.shapes[id_zone]',self.shapes[id_zone]474if not IS_SHAPELY:475polygon = np.array(self.shapes[id_zone])[:, :2]476# print ' polygon',type(polygon)477for polyline in self.get_edges().shapes.get_value():478479# print ' np.array(polyline)[:,:2]',np.array(polyline)[:,:2],type(np.array(polyline)[:,:2])480if is_polyline_in_polygon(np.array(polyline)[:, :2], polygon):481inds_within.append(ind)482ind += 1483else:484polygon = Polygon(np.array(self.shapes[id_zone])[:, :2])485for polyline in self.get_edges().shapes.get_value():486if MultiPoint(np.array(polyline)[:, :2]).within(polygon):487inds_within.append(ind)488ind += 1489490# print ' inds_within',inds_within491492# select and determine weights493self.ids_edges_inside[id_zone] = self.get_edges().get_ids(inds_within)494print ' found', len(self.ids_edges_inside[id_zone]), 'edges'495if len(self.ids_edges_inside[id_zone]) == 0:496print 'WARNING in identify_zoneedges: no edges found in zone', id_zone497498def get_zoneedges_by_mode_fast(self, id_zone, id_mode, speed_max=None,499modeconst_excl=0.0, modeconst_mix=0.0,500weights=None, fstar=None):501"""502Returns a list of edge IDs which are connected and accessible by mode id_mode.503Uses cashed results, if possible.504505Optionally weights and fstar can be provided to improve computational speed.506Otherwise weights and fstar are calculated with the optional parameters507modeconst_excl and modeconst_mix508"""509510# print 'get_zoneedges_by_mode_fast id_zone',id_zone,'id_mode',id_mode511if not self._mode_to_edges_inside.has_key(id_mode):512self._mode_to_edges_inside[id_mode] = {}513514if not self._mode_to_edges_inside[id_mode].has_key(id_zone):515self._mode_to_edges_inside[id_mode][id_zone] = self.get_zoneedges_by_mode(516id_zone, id_mode, weights=weights, fstar=fstar)517# print ' found edges',len(self._mode_to_edges_inside[id_mode][id_zone])518return self._mode_to_edges_inside[id_mode][id_zone]519520def get_zoneedges_by_mode(self, id_zone, id_mode, speed_max=None,521modeconst_excl=0.0, modeconst_mix=0.0,522weights=None, fstar=None):523"""524Returns a list of edge IDs which are connected and accessible by mode id_mode.525The algorithm tries to maximize the number of reachabe edges.526527Optionally weights and fstar can be provided to improve computational speed.528Otherwise weights and fstar are calculated with the optional parameters529modeconst_excl and modeconst_mix530"""531# print 'get_zoneedges_by_mode id_zone',id_zone,'id_mode',id_mode532533return self.get_edges().get_max_connected(534ids_edge=self.ids_edges_inside[id_zone],535id_mode=id_mode, speed_max=speed_max,536modeconst_excl=modeconst_excl,537modeconst_mix=modeconst_mix,538weights=weights, fstar=fstar,539is_bidir=True)540541def get_egdeprobs(self, id_zone, n_edges_min_length, n_edges_max_length, priority_max, speed_max, is_normalize=True, is_dict=False):542"""543OBSOLETE!!!544Returns vectors ids_edge and edge_props545where ids_edge are the edge IDs of edges in id_zone and edge_props are546the respective probabilities to start/end a trip547548if is_dict is True then a dictionary is returnd with edge IDs as key549and arrival/departure probability as value550"""551# todo: rename ids_edges_orig to simply ids_edges552ids_edge_orig = self.ids_edges_orig[id_zone]553if ids_edge_orig is None:554print 'WARNING: no edges in zone', id_zone, '. Run edge detection first.'555if is_dict:556return {}557else:558return [], []559560n_edges_orig = len(ids_edge_orig)561562if n_edges_orig > 0:563weights = self.get_edgeweights(ids_edge_orig, n_edges_min_length,564n_edges_max_length, priority_max, speed_max)565if is_normalize:566weights = weights/np.sum(weights)567if is_dict:568probs = {}569for id_edge, prob in zip(ids_edge_orig, weights):570probs[id_edge] = prob571return probs572else:573return ids_edge_orig, weights574else:575if is_dict:576return {}577else:578return [], []579580def make_egdeprobs(self, id_zone, n_edges_min_length, n_edges_max_length, priority_max, speed_max, is_normalize=True):581"""582OBSOLETE!!! This funzione has moved to origin_to_destination583Update probs_edges_orig and probs_edges_dest distribution584one for departures and one for arrivals.585"""586587# print 'make_egdeprobs',id_zone588#zones = self.zones.value589#edgeweights_orig = {}590#edgeweights_dest = {}591592# for id_zone in zones.get_ids():593ids_edge_orig = self.ids_edges_orig[id_zone]594ids_edge_dest = self.ids_edges_dest[id_zone]595n_edges_orig = len(ids_edge_orig)596n_edges_dest = len(ids_edge_dest)597# da fare meglio...598if n_edges_orig > 0:599#self.probs_edges_orig[id_zone] = 1.0/float(n_edges_orig)*np.ones(n_edges_orig,np.float)600weights = self.get_edgeweights(ids_edge_orig, n_edges_min_length,601n_edges_max_length, priority_max, speed_max)602if is_normalize:603self.probs_edges_orig[id_zone] = weights/np.sum(weights)604else:605self.probs_edges_orig[id_zone] = weights606else:607self.probs_edges_orig[id_zone] = []608609if n_edges_dest > 0:610#self.probs_edges_dest[id_zone] = 1.0/float(n_edges_dest)*np.ones(n_edges_dest,np.float)611weights = self.get_edgeweights(ids_edge_dest, n_edges_min_length,612n_edges_max_length, priority_max, speed_max)613if is_normalize:614self.probs_edges_dest[id_zone] = weights/np.sum(weights)615else:616self.probs_edges_dest[id_zone] = weights617else:618self.probs_edges_dest[id_zone] = []619620def get_edgeweights(self, ids_edge, n_edges_min_length, n_edges_max_length, priority_max, speed_max):621# OBSOLETE!!! This funzione has moved to origin_to_destination622# print 'get_edgeweights ids_edge',ids_edge623edges = self.get_edges()624n_edges = len(ids_edge)625if (n_edges > n_edges_min_length) & (n_edges < n_edges_max_length):626return edges.lengths[ids_edge]*((edges.priorities[ids_edge] < priority_max) & (edges.speeds_max[ids_edge] < speed_max))627else:628return np.ones(n_edges, dtype=np.float32)*((edges.priorities[ids_edge] < priority_max) & (edges.speeds_max[ids_edge] < speed_max))629630def write_kml(self, fd=None, indent=0):631632ids_zone = self.get_ids()633for id_zone in ids_zone:634fd.write(xm.begin('Placemark', indent + 2))635fd.write((indent + 4)*' '+'<name>%s</name>\n' % self.names_extended[id_zone])636fd.write(xm.begin('LineString', indent + 4))637fd.write(xm.begin('coordinates', indent + 6))638639for point in self.shapes[id_zone]:640641projection = self.project(point[0], point[1])642fd.write((indent+8)*' '+'%f,%f\n' % (projection[0], projection[1]))643644fd.write(xm.end('coordinates', indent + 6))645fd.write(xm.end('LineString', indent + 4))646fd.write(xm.end('Placemark', indent + 2))647648def write_xml(self, fd=None, indent=0):649print 'Zones.write_xml'650net = self.parent.parent.net651ids_edge_sumo = net.edges.ids_sumo652ids_zone = self.get_ids()653fd.write(xm.begin('tazs', indent))654for id_zone_sumo, shape, id_edges_orig, id_edges_dest, probs_edge_orig, probs_edge_dest in zip(655self.ids_sumo[ids_zone], self.shapes[ids_zone],656self.ids_edges_orig[ids_zone], self.ids_edges_dest[ids_zone],657self.probs_edges_orig[ids_zone], self.probs_edges_dest[ids_zone]):658659if id_edges_orig is not None:660if len(id_edges_orig) > 0:661# print ' id_zone_sumo',id_zone_sumo,'id_edges_orig',id_edges_orig,'probs_edge_orig',probs_edge_orig662# <taz id="<TAZ_ID>">663# <tazSource id="<EDGE_ID>" weight="<PROBABILITY_TO_USE>"/>664# ... further source edges ...665#666# <tazSink id="<EDGE_ID>" weight="<PROBABILITY_TO_USE>"/>667# ... further destination edges ...668# </taz>669670fd.write(xm.start('taz', indent + 2))671fd.write(xm.num('id', id_zone_sumo))672fd.write(xm.mat('shape', shape))673fd.write(xm.stop())674# for id_edge_sumo, prob_edge in zip(ids_edge_sumo[id_edges_orig], probs_edge_orig):675# fd.write(xm.start('tazSource',indent + 4))676# fd.write(xm.num('id',id_edge_sumo))677# fd.write(xm.num('weight',prob_edge))678# fd.write(xm.stopit())679#680# for id_edge_sumo, prob_edge in zip(ids_edge_sumo[id_edges_dest], probs_edge_dest):681# fd.write(xm.start('tazSink',indent + 4))682# fd.write(xm.num('id',id_edge_sumo))683# fd.write(xm.num('weight',prob_edge))684# fd.write(xm.stopit())685686fd.write(xm.end('taz', indent + 2))687688fd.write(xm.end('tazs', indent))689690def project(self, x, y):691if self._proj is None:692self._proj, self._offset = self.get_proj_and_offset()693lons, lats = self._proj(x-self._offset[0], y-self._offset[1], inverse=True)694return np.transpose(np.concatenate(([lons], [lats]), axis=0))695696def get_proj_and_offset(self):697if self._proj is None:698net = self.parent.parent.net699proj_params = str(net.get_projparams())700# try:701self._proj = pyproj.Proj(proj_params)702# except:703# proj_params ="+proj=utm +zone=32 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"704# self._proj = pyproj.Proj(self.proj_params)705706self._offset = net.get_offset()707708return self._proj, self._offset709710def get_zonefilepath(self):711return self.parent.parent.get_rootfilepath()+'.taz'712713def export_kml(self, filepath=None, encoding='UTF-8'):714"""715Export zones to Google kml file formate.716"""717print 'export_sumoxml', filepath, len(self)718if len(self) == 0:719return None720721if filepath is None:722filepath = self.get_zonefilepath()+'.kml'723724try:725fd = open(filepath, 'w')726except:727print 'WARNING in write_obj_to_xml: could not open', filepath728return False729#xmltag, xmltag_item, attrname_id = self.xmltag730fd.write('<?xml version="1.0" encoding="%s"?>\n' % encoding)731fd.write('<kml xmlns="http://www.opengis.net/kml/2.2">\n')732indent = 0733#fd.write(xm.begin('routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.sf.net/xsd/routes_file.xsd"',indent))734735fd.write(xm.begin('Document', indent=0))736737self.write_kml(fd, indent=0)738739fd.write(xm.end('Document', indent=0))740fd.write(xm.end('kml', indent=0))741fd.close()742return filepath743744def export_sumoxml(self, filepath=None, encoding='UTF-8'):745"""746Export zones to SUMO xml file formate.747"""748print 'export_sumoxml', filepath, len(self)749if len(self) == 0:750return None751752if filepath is None:753filepath = self.get_zonefilepath()+'.xml'754755try:756fd = open(filepath, 'w')757except:758print 'WARNING in export_sumoxml: could not open', filepath759return False760#xmltag, xmltag_item, attrname_id = self.xmltag761#fd.write('<?xml version="1.0" encoding="%s"?>\n'%encoding)762#fd.write('<kml xmlns="http://www.opengis.net/kml/2.2">\n')763indent = 0764#fd.write(xm.begin('routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.sf.net/xsd/routes_file.xsd"',indent))765766self.write_xml(fd, indent=0)767768fd.close()769return filepath770771772class ZonesFromShapeImporter(ShapefileImporter):773def __init__(self, ident='zonesfromshapeimporter', zones=None,774name='Zones from Shapefile importer',775shapeattr_ids_zone='ID',776shapeattr_names_zone='',777shapeattr_names_landuse='',778filepath='', logger=None, **kwargs):779780net = zones.parent.parent.net781ShapefileImporter.__init__(self, ident, parent=zones,782name=name,783filepath=filepath,784coordsattr='shapes',785attrnames_to_shapeattrs={'ids_sumo': shapeattr_ids_zone,786'names_extended': shapeattr_names_zone,787'ids_landusetype': shapeattr_names_landuse},788projparams_target=net.get_projparams(),789offset=net.get_offset(),790boundaries=net.get_boundaries(is_netboundaries=True),791logger=logger,792**kwargs)793794def do(self):795ShapefileImporter.do(self)796797# update zones798self.parent.update_zones()799800801class FacilityTypeMixin(cm.BaseObjman):802def __init__(self, ident, parent,803name='Facility Type Mixin',804info='Provides methods to handle specific facility functions.',805**kwargs):806"""807To be overridden.808"""809# attention parent is the Strategies table810self._init_objman(ident, parent, **kwargs)811attrsman = self.set_attrsman(cm.Attrsman(self))812self._init_attributes()813self._init_constants()814815def _init_attributes(self):816self._init_attributes_common()817818def _init_attributes_common(self):819# print 'StrategyMixin._init_attributes'820attrsman = self.get_attrsman()821landusetypes = self.get_landuse().landusetypes822self.ids_landusetype = attrsman.add(cm.AttrConf('ids_landusetype',823[landusetypes.get_id_from_formatted('residential'), ],824groupnames=['parameters'],825perm='rw',826#choices = landusetypes.typekeys.get_indexmap(),827name='landuse',828info='Default landuse type of this facility.',829))830831self.osmkey = attrsman.add(cm.AttrConf('osmkey', 'building.yes',832groupnames=['parameters'],833perm='rw',834name='OSM key',835info='Default Open Street Map key for this facility.',836))837838self.length_min = attrsman.add(cm.AttrConf('length_min', 15.0,839groupnames=['parameters'],840perm='rw',841name='Min. length',842unit='m',843info='Minimum length of entire property.',844))845846self.length_max = attrsman.add(cm.AttrConf('length_max', 100.0,847groupnames=['parameters'],848perm='rw',849name='Max. length',850unit='m',851info='Maximum length of entire property.',852))853self.width_min = attrsman.add(cm.AttrConf('width_min', 20.0,854groupnames=['parameters'],855perm='rw',856name='Min. width',857unit='m',858info='Minimum width of entire property.',859))860861self.width_max = attrsman.add(cm.AttrConf('width_max', 80.0,862groupnames=['parameters'],863perm='rw',864name='Max. width',865unit='m',866info='Maximum width of entire property.',867))868869self.height_min = attrsman.add(cm.AttrConf('height_min', 15.0,870groupnames=['parameters'],871perm='rw',872name='Min. height',873unit='m',874info='Minimum height of facility.',875))876877self.height_max = attrsman.add(cm.AttrConf('height_max', 35.0,878groupnames=['parameters'],879perm='rw',880name='Max. height',881unit='m',882info='Maximum height of facility.',883))884885self.dist_road_min = attrsman.add(cm.AttrConf('dist_road_min', 1.0,886groupnames=['parameters'],887perm='rw',888name='Min. dist road',889unit='m',890info='Minimum distance from road.',891))892893self.dist_road_max = attrsman.add(cm.AttrConf('dist_road_max', 5.0,894groupnames=['parameters'],895perm='rw',896name='Max. dist road',897info='Maximum distance from road.',898))899900self.dist_prop_min = attrsman.add(cm.AttrConf('dist_prop_min', 1.0,901groupnames=['parameters'],902perm='rw',903name='Min. prop dist',904unit='m',905info='Minimum distance to other properties.',906))907908self.dist_prop_max = attrsman.add(cm.AttrConf('dist_prop_max', 4.0,909groupnames=['parameters'],910perm='rw',911name='Max. prop dist',912info='Maximum distance to other properties.',913))914915self.shape_default = attrsman.add(cm.AttrConf('shape_default', [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0]],916groupnames=['parameters'],917perm='r',918name='Defaut shape',919info='Basic facility shape.',920))921922self.unitvolume_default = attrsman.add(cm.AttrConf('unitvolume_default',923default=100.0,924dtype=np.float32,925perm='r',926name='Unit volume',927info='Default value of the volume necessary to store one person or container. Volume used to calculate capacity.',928))929930def _init_constants(self):931932# self.get_attrsman().do_not_save_attrs([933# '_id_mode_bike','_id_mode_auto','_id_mode_moto',934# ])935pass936937def get_id_type(self):938# print 'get_id_type from ',self.parent.get_ident_abs()939# print ' names',self.parent.names.get_value()940return self.parent.names.get_id_from_index(self.get_ident())941942def get_facilities(self):943return self.parent.parent944945def get_landuse(self):946return self.parent.parent.parent947948def get_scenario(self):949return self.parent.parent.get_scenario()950951def get_shape0(self, length_fac, width_fac, height_max, capacity):952"""953Returns facility shape in origin coordinate system954and height as a function of the capacity and available space955"""956# One could do some random operations on the default shape957# here just stretch default shape to fit area958shape = np.array(self.shape_default, dtype=np.float32) * [length_fac, width_fac, 0.0]959# y-axes must be flipped so that hoses grow960# to the right side of the road961shape[:, 1] *= -1962# Calculates height of the building in function of the963# required capacity and available space.964965# here just use a random number966# to be overridden967height = min(random.uniform(self.height_min, self.height_max), height_max)968969return shape, height970971def generate(self, offset=[0.0, 0.0, 0.0],972length=10.0,973width=10.0,974angle=0.0,975pos_edge=0.0,976capacity=None,977id_landusetype=None,978height_max=30.0,979id_edge=None,980width_edge=3.0,981):982n_shape = len(self.shape_default)983shape_fac = np.zeros((n_shape, 3), dtype=np.float32)984985# determine effecive land area986dist_edge = random.uniform(self.dist_road_min, self.dist_road_max) + width_edge987width_fac = width-dist_edge988989dist_prop = random.uniform(self.dist_prop_min, self.dist_prop_max)990length_fac = length-2*self.dist_prop_max991992# do offset993dxn = np.cos(angle-np.pi/2)994dyn = np.sin(angle-np.pi/2)995996offset_fac = offset\997+ np.array([dxn, dyn, 0.0], dtype=np.float32)*dist_edge\998+ np.array([dyn, dxn, 0.0], dtype=np.float32)*dist_prop9991000shape, height_fac = self.get_shape0(length_fac, width_fac, height_max, capacity)10011002# transform in to the right place1003shape_fac[:, 0] = shape[:, 0]*np.cos(angle) - shape[:, 1]*np.sin(angle)1004shape_fac[:, 1] = shape[:, 0]*np.sin(angle) + shape[:, 1]*np.cos(angle)1005shape_fac += offset_fac10061007if id_landusetype is None:1008id_landusetype = self.ids_landusetype[0]10091010id_fac = self.get_facilities().make(id_landusetype=id_landusetype,1011id_zone=None,1012id_facilitytype=self.get_id_type(),1013osmkey=self.osmkey,1014area=None,1015height=height_fac,1016centroid=None,1017shape=list(shape_fac),1018id_roadedge_closest=id_edge,1019position_roadedge_closest=pos_edge + 0.5 * length,1020)102110221023class FacilityTypeHouse(FacilityTypeMixin):1024def __init__(self, ident, parent,1025name='Single House',1026info='Parameters and methods for residential house.',1027**kwargs):10281029self._init_objman(ident, parent, name=name, info=info, **kwargs)1030attrsman = self.set_attrsman(cm.Attrsman(self))10311032self._init_attributes()1033self._init_constants()1034# specific init103510361037class FacilityTypes(am.ArrayObjman):1038def __init__(self, ident, facilities, is_add_default=True, **kwargs):1039self._init_objman(ident=ident,1040parent=facilities,1041name='Facility types',1042info='Table holding facility type specific parameters and an object with methods ',1043**kwargs)10441045self._init_attributes()1046if is_add_default:1047self.add_default()10481049def _init_attributes(self):1050# landuse types table1051self.add_col(am.ArrayConf('names',1052default='',1053dtype='object',1054perm='r',1055is_index=True,1056name='Short name',1057info='Strategy name. Must be unique, used as index.',1058))10591060self.add_col(am.ArrayConf('unitvolumes',1061default=100.0,1062dtype=np.float32,1063perm='rw',1064name='Unit volume',1065info='The volume necessary to store one person or container. Volume used to calculate capacity.',1066))10671068self.add_col(cm.ObjsConf('typeobjects',1069#groupnames = ['state'],1070name='Type objects',1071info='Facility type object.',1072))10731074self.add_default()10751076def format_ids(self, ids):1077return ','.join(self.names[ids])10781079def get_id_from_formatted(self, idstr):1080return self.names.get_id_from_index(idstr)10811082def get_ids_from_formatted(self, idstrs):1083return self.names.get_ids_from_indices_save(idstrs.split(','))10841085def add_default(self):1086self.clear()1087self.add_type('house', FacilityTypeHouse)10881089def get_typeobj(self, id_type):1090return self.typeobjects[id_type]10911092def add_type(self, ident, TypeClass, **kwargs):1093# print 'add_strategy', ident1094if not self.names.has_index(ident):1095factypeobj = TypeClass(ident, self)1096id_type = self.add_row(names=ident,1097typeobjects=factypeobj,1098unitvolumes=factypeobj.unitvolume_default1099)1100return id_type1101else:1102return self.get_id_from_formatted(id_type)110311041105class Facilities(am.ArrayObjman):1106def __init__(self, landuse, landusetypes, zones, net=None, **kwargs):1107# print 'Facilities.__init__',hasattr(self,'lanes')1108self._init_objman(ident='facilities',1109parent=landuse,1110name='Facilities',1111info='Information on buildings, their type of usage and access to the transport network.',1112xmltag=('polys', 'poly', 'ids_sumo'),1113is_plugin=True,1114**kwargs)11151116self._init_attributes()1117self._init_constants()11181119if net is not None:1120self.add_col(am.IdsArrayConf('ids_roadedge_closest', net.edges,1121groupnames=['landuse'],1122name='Road edge ID',1123info='ID of road edge which is closest to this facility.',1124))11251126self.add_col(am.ArrayConf('positions_roadedge_closest', 0.0,1127dtype=np.float32,1128groupnames=['landuse'],1129perm='r',1130name='Road edge pos',1131unit='m',1132info='Position on road edge which is closest to this facility',1133))11341135# self.ids_stop_closest = self.facilities.add(cm.ArrayConf( 'ids_stop_closest', None,1136# dtype = 'object',1137# name = 'ID stops',1138# perm='rw',1139# info = 'List of IDs of closest public transport stops.',1140# ))11411142def _init_constants(self):1143self._proj = None1144self._offset = None11451146attrsman = self.get_attrsman()1147attrsman.do_not_save_attrs(['_proj', '_offset'])11481149def _init_attributes(self):1150landusetypes = self.parent.landusetypes1151zones = self.parent.zones1152self.add(cm.ObjConf(FacilityTypes('facilitytypes', self,)))11531154self.add_col(SumoIdsConf('Facility', info='SUMO facility ID'))11551156self.add_col(am.ArrayConf('names', '',1157dtype='object', # actually a string of variable length1158perm='rw',1159name='Name',1160info='Name of facility.',1161is_plugin=True,1162))11631164self.add_col(am.IdsArrayConf('ids_landusetype', landusetypes,1165groupnames=['landuse'],1166perm='rw',1167name='ID landuse',1168info='ID of landuse.',1169is_plugin=True,1170))11711172self.add_col(am.IdsArrayConf('ids_zone', zones,1173groupnames=['landuse'],1174perm='r',1175name='ID zone',1176info='ID of traffic zone, where this facility is located.',1177))1178facilitytypes = self.get_facilitytypes()1179if len(facilitytypes) > 0:1180id_default = facilitytypes.get_ids()[0]1181else:1182id_default = -11183self.add_col(am.IdsArrayConf('ids_facilitytype', facilitytypes,1184id_default=id_default,1185groupnames=['landuse'],1186perm='rw',1187name='ID fac. type',1188info='ID of facility type (house, scycraper, factory, parking,...).',1189is_plugin=True,1190))11911192self.add_col(am.ArrayConf('osmkeys', 'building.yes',1193dtype='object', # actually a string of variable length1194perm='rw',1195name='OSM key',1196info='OSM key of facility.',1197xmltag='type',1198is_plugin=True,1199))12001201self.add_col(am.ArrayConf('capacities', 0,1202dtype=np.int32,1203groupnames=['landuse'],1204perm='r',1205name='Capacity',1206info='Person capacity of this facility. For example maximum number of adulds living in a building or number of people working in a factory.',1207))12081209self.add_col(am.ArrayConf('areas', 0.0,1210dtype=np.float32,1211groupnames=['landuse'],1212perm='r',1213name='Area',1214unit='m^2',1215info='Area of this facility.',1216))12171218self.add_col(am.ArrayConf('heights', 10.0,1219dtype=np.float32,1220groupnames=['landuse'],1221perm='r',1222name='Height',1223unit='m',1224info='Height above ground of this facility.',1225))12261227self.add_col(am.ArrayConf('centroids', np.zeros(3, dtype=np.float32),1228dtype=np.float32,1229groupnames=['state', '_private'],1230perm='r',1231name='Center',1232unit='m',1233info='Center coordinates of this facility.',1234))12351236self.add_col(am.ListArrayConf('shapes',1237groupnames=['_private'],1238perm='rw',1239name='Shape',1240unit='m',1241info='List of 3D Shape coordinates of facility.',1242xmltag='shape',1243is_plugin=True,1244))12451246# self.add_col(TabIdsArrayConf( 'ftypes',1247# name = 'Types',1248# info = 'Draw obj and ids',1249# ))12501251if self.plugin is None:1252self.init_plugin(True)1253self.shapes.init_plugin(True)1254self.osmkeys.init_plugin(True)1255self.ids_landusetype.init_plugin(True)1256# configure only if net is initialized12571258def make(self, id_sumo=None,1259id_landusetype=None,1260id_zone=None,1261id_facilitytype=None,1262osmkey=None,1263area=None,1264capacity=None,1265height=None,1266centroid=None,1267shape=[],1268id_roadedge_closest=None,1269position_roadedge_closest=None,1270):1271"""1272Adds a facilities1273"""1274id_fac = self.suggest_id()1275if id_sumo is None:1276id_sumo = str(id_fac)12771278# stuff with landusetype must be done later1279id_fac = self.add_row(_id=id_fac,1280ids_sumo=id_sumo,1281ids_landusetype=id_landusetype,1282ids_zone=id_zone,1283ids_facilitytype=id_facilitytype,1284osmkeys=osmkey,1285areas=area,1286capacities=capacity,1287heights=height,1288centroids=centroid,1289shapes=shape,1290ids_roadedge_closest=id_roadedge_closest,1291positions_roadedge_closest=position_roadedge_closest,1292)1293# do area calcs and other1294if area is None:1295self.update_area(id_fac)12961297if capacity is None:1298self.update_capacity(id_fac)12991300if centroid is None:1301self.update_centroid(id_fac)1302return id_fac13031304def generate(self, facilitytype, **kwargs):1305"""1306Generates a facility. The generation of the facility will be1307performed by the faciliy type instance.1308"""1309return facilitytype.generate(**kwargs)13101311def format_ids(self, ids):1312return ','.join(self.ids_sumo[ids])13131314def get_id_from_formatted(self, idstr):1315return self.ids_sumo.get_id_from_index(idstr)13161317def get_ids_from_formatted(self, idstrs):1318return self.ids_sumo.get_ids_from_indices_save(idstrs.split(','))13191320def del_element(self, id_fac):1321# print 'del_element',id_zone1322self.del_row(id_fac)13231324def write_xml(self, fd, indent=0, is_print_begin_end=True, delta=np.zeros(3, dtype=np.float32)):1325xmltag, xmltag_item, attrname_id = self.xmltag1326layer_default = -11327fill_default = 11328ids_landusetype = self.ids_landusetype1329landusecolors = self.get_landusetypes().colors13301331if is_print_begin_end:1332fd.write(xm.begin(xmltag, indent))13331334attrsconfigs_write = [self.ids_sumo, self.osmkeys]1335xmltag_shape = self.shapes.xmltag1336sep_shape = self.shapes.xmlsep1337for _id in self.get_ids():1338fd.write(xm.start(xmltag_item, indent+2))1339for attrsconfig in attrsconfigs_write:1340attrsconfig.write_xml(fd, _id)13411342fd.write(xm.mat(xmltag_shape, self.shapes[_id] - delta))13431344landusecolors.write_xml(fd, ids_landusetype[_id])1345fd.write(xm.num('layer', layer_default))1346fd.write(xm.num('fill', fill_default))13471348fd.write(xm.stopit())13491350if is_print_begin_end:1351fd.write(xm.end(xmltag, indent))13521353def get_landusetypes(self):1354return self.ids_landusetype.get_linktab()13551356def get_facilitytypes(self):1357return self.facilitytypes.get_value()13581359def get_net(self):1360# print 'get_net',self.ids_edge_closest_road.get_linktab(),self.ids_edge_closest_road.get_linktab().parent1361return self.ids_roadedge_closest.get_linktab().parent13621363def get_scenario(self):1364return self.ids_roadedge_closest.get_linktab().parent.parent13651366def update_netoffset(self, deltaoffset):1367"""1368Called when network offset has changed.1369Children may need to adjust theur coordinates.1370"""1371# self.zones.update_netoffset(deltaoffset)1372self.centroids.value[:, :2] = self.centroids.value[:, :2] + deltaoffset1373shapes = self.shapes.value1374for i in xrange(len(shapes)):1375s = np.array(shapes[i])1376s[:, :2] = s[:, :2] + deltaoffset1377shapes[i] = list(s)13781379def get_edges(self):1380return self.ids_roadedge_closest.get_linktab()13811382def identify_taz(self):1383"""1384Identifies id of traffic assignment zone for each facility.1385Note that not all facilities are within such a zone.1386"""1387zones = self.ids_zone.get_linktab()1388# self.get_demand().get_districts()1389for id_fac in self.get_ids():1390for id_zone in zones.get_ids():1391if is_polyline_in_polygon(self.shapes[id_fac], zones.shapes[id_zone]):1392self.ids_zone[id_fac] = id_zone1393break13941395def get_departure_probabilities(self):1396"""1397Returns a dictionary, where probabilities[id_zone]1398is a vector of departure probabilities for each facility1399of zone id_zone.1400"""1401zones = self.ids_zone.get_linktab()1402# print 'get_departure_probabilities in n_zones',len(zones)1403probabilities = {}14041405inds_fac = self.get_inds()1406for id_zone in zones.get_ids():1407# probabilities[id_zone]={}1408# for id_landusetype in set(self.ids_landusetype.value):1409# print ' id_zone',id_zone1410# print ' ids_landusetype',self.ids_landusetype.value[inds_fac]1411# print ' ids_zone',self.ids_zone.value[inds_fac]1412# print ''1413util = self.capacities.value[inds_fac].astype(np.float32)*(self.ids_zone.value[inds_fac] == id_zone)1414util_tot = np.sum(util)1415# print '\n\n [id_taz][ftype]',id_taz,ftype,util_tot,np.sum(util/np.sum(util))1416# print ' self.type==ftype',self.type==ftype1417# print ' self.id_taz==id_taz',self.id_taz==id_taz1418# print ' util',util1419if util_tot > 0.0:1420probabilities[id_zone] = util/util_tot1421else:1422probabilities[id_zone] = util # all zero prob14231424return probabilities, self.get_ids(inds_fac)14251426def get_departure_probabilities_landuse2(self, ids_landusetype):1427"""1428Returns a dictionary, where probabilities[id_zone]1429is a vector of departure probabilities for each facility1430of zone id_zone.1431Probabilities are proportional to the capacity attribute of the facility.14321433Only facilities with one of the landuse given in ids_landusetype1434have non-zero probabilities.14351436The ids_fac is an array that contains the facility ids in correspondence1437to the probability vector.1438"""1439print 'get_departure_probabilities_landuse2 ids_landusetype', ids_landusetype1440probabilities = {}1441zones = self.ids_zone.get_linktab()1442inds_fac = self.get_inds()1443n_frac = len(inds_fac)1444for id_zone in zones.get_ids():1445# probabilities[id_zone]={}1446utils = np.zeros(n_frac, dtype=np.float32)1447util_tot = 0.01448for id_landusetype in ids_landusetype:1449# print ' id_zone,id_landusetype',id_zone,id_landusetype1450# print ' ids_landusetype',self.ids_landusetype.value[inds_fac]1451# print ' ids_zone',self.ids_zone.value[inds_fac]1452# print ''1453utils_new = self.capacities.value[inds_fac].astype(1454np.float32)*np.logical_and((self.ids_landusetype.value[inds_fac] == id_landusetype), (self.ids_zone.value[inds_fac] == id_zone))1455utils += utils_new1456util_tot += np.sum(utils_new)1457# print '\n\n [id_taz][ftype]',id_taz,ftype,util_tot,np.sum(util/np.sum(util))1458# print ' self.type==ftype',self.type==ftype1459# print ' self.id_taz==id_taz',self.id_taz==id_taz1460# print ' util',np.sum(utils)14611462if util_tot > 0.0:1463probabilities[id_zone] = utils/util_tot1464else:1465probabilities[id_zone] = utils # all zero prob14661467if 0: # debug1468print ' sum(probs)', np.sum(probabilities[id_zone])1469if np.sum(probabilities[id_zone]) > 0:1470ids_fac = self.get_ids(inds_fac)1471for id_fac, id_landusetype, id_thiszone, prob in zip(ids_fac, self.ids_landusetype[ids_fac], self.ids_zone[ids_fac], probabilities[id_zone]):1472if (id_thiszone == id_zone): # & (id_landusetype in ids_landusetype):1473if prob > 0:1474print ' id_fac', id_fac, 'id_landusetype', id_landusetype, 'prob', prob14751476return probabilities, self.get_ids(inds_fac)14771478def get_departure_probabilities_landuse(self):1479"""1480Returns the dictionnary of dictionaries with departure (or arrival)1481probabilities where probabilities[id_zone][id_landusetype]1482is a probability distribution vector giving for each facility the1483probability to depart/arrive in zone id_zone with facility type ftype.14841485The ids_fac is an array that contains the facility ids in correspondence1486to the probability vector.1487"""1488print 'get_departure_probabilities_landuse'1489probabilities = {}1490zones = self.ids_zone.get_linktab()1491inds_fac = self.get_inds()1492for id_zone in zones.get_ids():1493probabilities[id_zone] = {}1494for id_landusetype in set(self.ids_landusetype.value):1495print ' id_zone,id_landusetype', id_zone, id_landusetype1496# print ' ids_landusetype',self.ids_landusetype.value[inds_fac]1497# print ' ids_zone',self.ids_zone.value[inds_fac]1498# print ''1499util = self.capacities.value[inds_fac].astype(1500np.float32)*((self.ids_landusetype.value[inds_fac] == id_landusetype) & (self.ids_zone.value[inds_fac] == id_zone))1501util_tot = np.sum(util)1502# print '\n\n [id_taz][ftype]',id_taz,ftype,util_tot,np.sum(util/np.sum(util))1503# print ' self.type==ftype',self.type==ftype1504# print ' self.id_taz==id_taz',self.id_taz==id_taz1505# print ' util',util1506if util_tot > 0.0:1507probabilities[id_zone][id_landusetype] = util/util_tot1508else:1509probabilities[id_zone][id_landusetype] = util # all zero prob15101511return probabilities, self.get_ids(inds_fac)15121513def update(self, ids=None):1514# print 'update',ids1515if ids is None:1516ids = self.get_ids()15171518for _id in ids:1519# print ' self.centroids[_id]',self.centroids[_id]1520# print ' self.shapes[_id]',self.shapes[_id],np.mean(self.shapes[_id],0)1521self.update_centroid(_id)1522#self.areas[_id] = find_area(np.array(self.shapes[_id],float)[:,:2])1523self.update_area(_id)1524#self.areas[_id] = get_polygonarea_fast(np.array(self.shapes[_id],float)[:,0], np.array(self.shapes[_id],float)[:,1])15251526self.identify_landuse_from_area(ids)1527self.update_capacities(ids)1528# self.identify_closest_edge(ids)15291530def get_ids_area(self, ids=None):1531if ids is None:1532ids = self.get_ids()1533return ids[self.get_landusetypes().are_area[self.ids_landusetype[ids]]]15341535def get_ids_building(self, ids=None):1536"""Returns all building type of facilities"""1537# print 'get_ids_building'1538if ids is None:1539ids = self.get_ids()1540# debug1541#landusetypes = self.get_landusetypes()1542# for id_fac in ids[self.get_landusetypes().are_area[self.ids_landusetype[ids]] == False]:1543# id_landusetype = self.ids_landusetype[id_fac]1544# print ' id_fac',id_fac,id_landusetype,'is_area',landusetypes.are_area[id_landusetype]15451546return ids[self.get_landusetypes().are_area[self.ids_landusetype[ids]] == False]15471548def identify_landuse_from_area(self, ids_fac=None):1549"""Determines the landuse of facilities from the landuse of areas in which their are located"""1550print 'identify_landuse_from_area', ids_fac1551# TODO:1552landusetypes = self.get_landusetypes()1553ids_area = self.get_ids_area(ids_fac)1554ids_build = self.get_ids_building(ids_fac)15551556for id_area, shape, id_landuse in zip(ids_area, self.shapes[ids_area], self.ids_landusetype[ids_area]):1557id_landusetype_fac = landusetypes.get_landusetype_facility_from_area(self.ids_landusetype[id_area])1558for id_fac, osmkey, coord in zip(ids_build, self.osmkeys[ids_build], self.centroids[ids_build]):15591560if osmkey == 'building.yes':1561if is_point_in_polygon(coord[:2], np.array(shape, dtype=np.float32)[:, :2], is_use_shapely=IS_SHAPELY):1562print ' found id_fac', id_fac, osmkey, 'in id_area', id_area1563print ' id_landusetype', self.ids_landusetype[id_fac], 'is_area', landusetypes.are_area[self.ids_landusetype[id_fac]], '->', id_landusetype_fac1564self.ids_landusetype[id_fac] = id_landusetype_fac15651566def update_centroid(self, _id):1567self.centroids[_id] = np.mean(self.shapes[_id], 0)15681569def update_area(self, _id):1570if IS_SHAPELY:1571self.areas[_id] = find_area(self.shapes[_id])1572else:1573self.areas[_id] = get_polygonarea_fast(np.array(self.shapes[_id], float)[1574:, 0], np.array(self.shapes[_id], float)[:, 1])15751576def update_capacity(self, id_fac):1577self.update_capacities([id_fac])15781579def update_capacities(self, ids):1580ids_fac = self.get_ids_building(ids)1581ids_area = self.get_ids_area(ids)1582volumes_unit = self.get_facilitytypes().unitvolumes[self.ids_facilitytype[ids_fac]]15831584self.capacities[ids_fac] = self.areas[ids_fac]*self.heights[ids_fac]/volumes_unit15851586# here we assume that pure areas do not have capacities1587# this will prevent that activities are assigned to areas1588# instead of facilities (buildings)1589# TODO: problem is for example parks with no buildings1590# fixed: parks etc. are areas1591self.capacities[ids_area] = 0.015921593def get_dists(self, ids_fac_from, ids_fac_to):1594"""1595Returns centroid to centroid distance from facilities in vector1596ids_fac_from to facilities in vector ids_fac_to.1597"""15981599return np.sqrt(np.sum((self.centroids[ids_fac_to]-self.centroids[ids_fac_from])**2))16001601def identify_closest_edge(self, ids=None, priority_max=5, has_sidewalk=True, n_best=10):1602"""1603Identifies edge ID and position on this edge that1604is closest to the centoid of each facility and the satisfies certain1605conditions.1606"""1607print 'identify_closest_edge'1608edges = self.get_edges()1609id_ped = self.get_net().modes.get_id_mode('pedestrian')1610# select edges...if (edges.priorities[id_edge]<=priority_max) & edges.has_sidewalk(id_edge):16111612# ids_edge = edges.select_ids((edges.priorities.get_value()<priority_max)\1613# & (edges.widths_sidewalk.get_value()>0.0))1614accesslevels = edges.get_accesslevels(id_ped)1615# edges.make_segment_edge_map()16161617for id_fac in self.get_ids():1618ids_edge, dists = edges.get_closest_edge(self.centroids[id_fac], n_best=n_best, accesslevels=accesslevels)16191620if len(ids_edge) > 0:1621id_edge = ids_edge[0]16221623# determin position on edeg where edge is closest to centroid1624# TODO: solve this faster with precalculated maps!!1625xc, yc, zc = self.centroids[id_fac]1626shape = edges.shapes[id_edge]1627n_segs = len(shape)16281629d_min = 10.0**81630x_min = 0.01631y_min = 0.01632j_min = 01633p_min = 0.01634pos = 0.01635x1, y1, z1 = shape[0]1636edgelength = edges.lengths[id_edge]1637for j in xrange(1, n_segs):1638x2, y2, z2 = shape[j]1639d, xp, yp = shortest_dist(x1, y1, x2, y2, xc, yc)1640# print ' x1,y1=(%d,%d)'%(x1,y1),',x2,y2=(%d,%d)'%(x2,y2),',xc,yc=(%d,%d)'%(xc,yc)1641# print ' d,x,y=(%d,%d,%d)'%shortest_dist(x1,y1, x2,y2, xc,yc)1642if d < d_min:1643d_min = d1644# print ' **d_min=',d_min,[xp,yp]1645x_min = xp1646y_min = yp1647j_min = j1648p_min = pos1649# print ' pos',pos,[x2-x1,y2-y1],'p_min',p_min1650pos += np.linalg.norm([x2-x1, y2-y1])1651x1, y1 = x2, y216521653x1, y1, z1 = shape[j_min-1]1654pos_min = p_min+np.linalg.norm([x_min-x1, y_min-y1])1655# print ' k=%d,d_min=%d, x1,y1=(%d,%d),xmin,ymin=(%d,%d),xc,yc=(%d,%d)'%(k,d_min,x1,y1,x_min,y_min,xc,yc)1656# print ' pos=%d,p_min=%d,pos_min=%d'%(pos,p_min,pos_min)16571658if pos_min > edgelength:1659pos_min = edgelength16601661if pos_min < 0:1662pos_min = 01663# print ' id_fac,id_edge',id_fac,id_edge,pos_min1664self.ids_roadedge_closest[id_fac] = id_edge1665self.positions_roadedge_closest[id_fac] = pos_min16661667def set_shape(self, id_fac, shape):1668# print 'set_shape',id_fac,shape1669self.shapes[id_fac] = shape1670self.update([id_fac])1671#self.areas[id_fac] = find_area(shape[:,:2])1672#self.centroids[id_fac] =np.mean(shape,0)16731674def add_polys(self, ids_sumo=[], **kwargs):1675"""1676Adds a facilities as used on sumo poly xml info1677"""1678# stuff with landusetype must be done later1679return self.add_rows(n=len(ids_sumo), ids_sumo=ids_sumo, **kwargs)16801681def add_poly(self, id_sumo, id_landusetype=None, osmkey=None, shape=np.array([], np.float32)):1682"""1683Adds a facility as used on sumo poly xml info1684"""1685# print 'add_poly',id_sumo,id_landusetype,osmkey16861687landusetypes = self.get_landusetypes()16881689if id_landusetype is None:1690# make default landuse1691id_landusetype = landusetypes.typekeys.get_id_from_index('residential')16921693if osmkey is None:1694# use first filter as key1695osmkey = landusetypes.osmfilters[id_landusetype][0]16961697id_fac = self.add_row(ids_sumo=id_sumo,1698ids_landusetype=id_landusetype,1699osmkeys=osmkey,1700)1701self.set_shape(id_fac, shape)1702return id_fac17031704def clear(self):1705# self.reset()1706self.clear_rows()17071708def set_shapes(self, ids, vertices):1709self.shapes[ids] = vertices1710if not hasattr(ids, '__iter__'):1711ids = [ids]1712self.update(ids)17131714def import_poly(self, polyfilepath, is_remove_xmlfiles=False, is_clear=True, **kwargs):1715print 'import_poly from %s ' % (polyfilepath,)1716if is_clear:1717self.clear()1718# let's read first the offset information, which are in the1719# comment area1720fd = open(polyfilepath, 'r')1721is_comment = False1722is_processing = False1723offset = self.get_net().get_offset() # default is offset from net1724# print ' offset,offset_delta',offset,type(offset)1725#offset = np.array([0,0],float)1726for line in fd.readlines():1727if line.find('<!--') >= 0:1728is_comment = True1729if is_comment & (line.find('<processing') >= 0):1730is_processing = True1731if is_processing & (line.find('<offset.x') >= 0):1732offset[0] = float(xm.read_keyvalue(line, 'value'))1733elif is_processing & (line.find('<offset.y') >= 0):1734offset[1] = float(xm.read_keyvalue(line, 'value'))1735break1736fd.close()1737offset_delta = offset - self.get_net().get_offset()17381739exectime_start = time.clock()17401741counter = SumoPolyCounter()1742parse(polyfilepath, counter)1743fastreader = SumoPolyReader(self, counter, offset_delta, **kwargs)1744parse(polyfilepath, fastreader)1745fastreader.finish()17461747# update ids_landuse...1748# self.update()17491750# timeit1751print ' exec time=', time.clock() - exectime_start17521753# print ' self.shapes',self.shapes.value17541755def write_kml(self, fd=None, indent=0):1756# <busStop id="busstop4" lane="1/0to2/0_0" startPos="20" endPos="40" lines="100 101"/>17571758ids_fac = self.get_ids()1759for id_fac in ids_fac:1760fd.write(xm.begin('Placemark', indent + 2))1761fd.write((indent+4)*' '+'<name>%s</name>\n' % id_fac)1762fd.write(xm.begin('Polygon', indent + 4))1763fd.write((indent+6)*' '+'<extrude>1</extrude>\n' % id_fac)1764fd.write((indent+6)*' '+'<altitudeMode>relativeToGround</altitudeMode>\n' % id_fac)1765fd.write(xm.begin('outerBoundaryIs', indent + 6))17661767fd.write(xm.begin('LinearRing', indent + 8))1768fd.write(xm.begin('coordinates', indent + 10))17691770for point in self.shapes[id_fac]:17711772projection = self.project(point[0], point[1])1773fd.write((indent+12)*' '+'%f,%f,%f\n' % (projection[0], projection[1], self.heights[id_fac]))17741775fd.write(xm.end('coordinates', indent + 10))1776fd.write(xm.end('LinearRing', indent + 8))1777fd.write(xm.end('outerBoundaryIs', indent + 6))1778fd.write(xm.end('Polygon', indent + 4))1779fd.write(xm.end('Placemark', indent + 2))17801781def project(self, x, y):1782if self._proj is None:1783self._proj, self._offset = self.get_proj_and_offset()1784lons, lats = self._proj(x-self._offset[0], y-self._offset[1], inverse=True)1785return np.transpose(np.concatenate(([lons], [lats]), axis=0))17861787def get_proj_and_offset(self):1788if self._proj is None:1789net = self.parent.parent.net1790proj_params = str(net.get_projparams())1791# try:1792self._proj = pyproj.Proj(proj_params)1793# except:1794# proj_params ="+proj=utm +zone=32 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"1795# self._proj = pyproj.Proj(self.proj_params)17961797self._offset = net.get_offset()17981799return self._proj, self._offset18001801def get_facfilepath(self):1802return self.parent.parent.get_rootfilepath()+'.fac.kml'18031804def export_sumokml(self, filepath=None, encoding='UTF-8'):1805"""1806Export stops to SUMO stop xml file.1807"""1808print 'export_sumoxml', filepath, len(self)1809if len(self) == 0:1810return None18111812if filepath is None:1813filepath = self.get_facfilepath()18141815try:1816fd = open(filepath, 'w')1817except:1818print 'WARNING in write_obj_to_xml: could not open', filepath1819return False1820#xmltag, xmltag_item, attrname_id = self.xmltag1821fd.write('<?xml version="1.0" encoding="%s"?>\n' % encoding)1822fd.write('<kml xmlns="http://www.opengis.net/kml/2.2">\n')1823indent = 01824#fd.write(xm.begin('routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.sf.net/xsd/routes_file.xsd"',indent))18251826fd.write(xm.begin('Document', indent=0))18271828self.write_kml(fd, indent=0)18291830fd.write(xm.end('Document', indent=0))1831fd.write(xm.end('kml', indent=0))1832fd.close()1833return filepath183418351836class SumoPolyCounter(handler.ContentHandler):1837"""Counts facilities from poly.xml file into facility structure"""18381839def __init__(self):1840self.n_fac = 018411842def startElement(self, name, attrs):1843# print 'startElement',name,len(attrs)1844if name == 'poly':1845self.n_fac += 1184618471848class SumoPolyReader(handler.ContentHandler):1849"""Reads facilities from poly.xml file into facility structure"""18501851def __init__(self, facilities, counter, offset_delta, type_default='building.yes', height_default=7.0):18521853self._type_default = type_default1854self._height_default = height_default1855self._facilities = facilities1856self._ids_landusetype_all = self._facilities.get_landusetypes().get_ids()1857self._osmfilters = self._facilities.get_landusetypes().osmfilters18581859self._ind_fac = -11860self.ids_sumo = np.zeros(counter.n_fac, np.object)1861self.ids_landusetype = -1*np.ones(counter.n_fac, np.int32)1862self.osmkeys = np.zeros(counter.n_fac, np.object)1863self.names = np.zeros(counter.n_fac, np.object)1864self.shape = np.zeros(counter.n_fac, np.object)1865self.areas = np.zeros(counter.n_fac, np.float32)1866self.heights = self._height_default * np.ones(counter.n_fac, np.float32)1867self.centroids = np.zeros((counter.n_fac, 3), np.float32)18681869#self._id_facility = None1870self._offset_delta = offset_delta18711872def startElement(self, name, attrs):18731874# print 'startElement', name, len(attrs)1875if name == 'poly':1876self._ind_fac += 11877i = self._ind_fac18781879osmkey = attrs.get('type', self._type_default)1880# print ' id_sumo=',attrs['id'],osmkey1881id_landuse = self.get_landuse(osmkey)1882if id_landuse >= 0: # land use is interesting1883shape = xm.process_shape(attrs.get('shape', ''), offset=self._offset_delta)1884shapearray = np.array(shape, np.float32)1885# print ' shapearray',shapearray1886self.ids_sumo[i] = attrs['id']1887self.ids_landusetype[i] = id_landuse1888self.osmkeys[i] = osmkey1889self.shape[i] = shape1890self.areas[i] = find_area(shapearray[:, :2])1891self.centroids[i] = np.mean(shapearray, 0)1892self.names[i] = ''18931894# print ' control id_sumo',self.ids_sumo[i]18951896elif name == 'param':1897i = self._ind_fac1898if attrs['key'] == 'height':1899self.heights[i] = string_to_float(attrs['value'])1900elif attrs['key'] == 'name':1901self.names[i] = attrs['value']19021903# color info in this file no longer used as it is defined in1904# facility types table1905# color = np.array(xm.parse_color(attrs['color']))*0.8,# make em darker!!19061907def get_landuse(self, osmkey):1908keyvec = osmkey.split('.')1909len_keyvec = len(keyvec)1910print 'get_landuse', len_keyvec, keyvec1911#is_match = False1912for id_landusetype in self._ids_landusetype_all:1913# print ' id_landusetype',id_landusetype1914# if fkeys==('building.industrial'): print ' check',facilitytype19151916# first filter only exact matches before wildcards1917for osmfilter in self._osmfilters[id_landusetype]:1918# print ' ?osmfiltervec',osmfilter,osmkey==osmfilter1919if osmkey == osmfilter: # exact match of filter1920print ' exact', osmkey1921return id_landusetype19221923# now check for wildcards1924for id_landusetype in self._ids_landusetype_all:1925# print ' *id_landusetype',id_landusetype19261927for osmfilter in self._osmfilters[id_landusetype]:1928osmfiltervec = osmfilter.split('.')1929# print ' ?osmfiltervec',osmfiltervec,(len(osmfiltervec)==2)&(len_keyvec==2)1930if (len(osmfiltervec) == 2) & (len_keyvec == 2):1931if osmfiltervec[0] == keyvec[0]:1932if osmfiltervec[1] == '*':1933print ' *', keyvec[0]1934return id_landusetype1935return -119361937def finish(self):19381939# print 'write_to_net'1940inds_valid = np.flatnonzero(self.ids_landusetype >= 0)1941ids_fac = self._facilities.add_polys(1942ids_sumo=self.ids_sumo[inds_valid],1943ids_landusetype=self.ids_landusetype[inds_valid],1944osmkeys=self.osmkeys[inds_valid],1945shapes=self.shape[inds_valid],1946areas=self.areas[inds_valid],1947centroids=self.centroids[inds_valid],1948heights=self.heights[inds_valid],1949names=self.names[inds_valid]1950)19511952# def characters(self, content):1953# if self._id is not None:1954# self._currentShape = self._currentShape + content19551956# def endElement(self, name):1957# pass195819591960class Parking(am.ArrayObjman):1961def __init__(self, landuse, lanes, **kwargs):1962# print 'Parking.__init__',lanes,hasattr(self,'lanes')1963self._init_objman(ident='parking', parent=landuse,1964name='Parking',1965info='Information on private car parking.',1966#is_plugin = True,1967# **kwargs1968)19691970self._init_attributes(lanes)19711972def _init_attributes(self, lanes=None):1973# print 'Parkin._init_attributes',lanes,hasattr(self,'lanes'),hasattr(self,'ids_lane')1974if lanes is None:1975# upgrade call1976# lanes exists already as link1977lanes = self.get_lanes()19781979# print ' lanes',lanes1980# --------------------------------------------------------------------1981# misc params...19821983# these are options for assignment procedure!!1984# self.add(AttrConf( 'length_noparking', kwargs.get('length_noparking',20.0),1985# groupnames = ['options'],1986# perm='wr',1987# unit = 'm',1988# name = 'Min Length',1989# info = 'Minimum edge length for assigning on-road parking space.' ,1990# #xmltag = 'pos',1991# ))1992#1993# self.add(AttrConf( 'length_space', kwargs.get('length_space',20.0),1994# groupnames = ['options'],1995# perm='wr',1996# unit = 'm',1997# name = 'Lot length',1998# info = 'Length of a standard parking lot.' ,1999# #xmltag = 'pos',2000# ))20012002self.add_col(am.IdsArrayConf('ids_lane', lanes,2003name='ID Lane',2004info='ID of lane for this parking position. ',2005))20062007self.add_col(am.ArrayConf('positions', 0.0,2008dtype=np.float32,2009perm='r',2010name='Pos',2011unit='m',2012info="Position on lane for this parking.",2013))20142015self.add_col(am.ArrayConf('lengths', 0.0,2016dtype=np.float32,2017#choices = OPTIONMAP_POS_DEPARTURE,2018perm='r',2019name='Length',2020unit='m',2021info="Length of parking lot in edge direction.",2022))20232024self.add_col(am.ArrayConf('angles', 0.0,2025dtype=np.float32,2026perm='rw',2027name='Angle',2028unit='deg',2029info="Parking angle with respect to lane direction.",2030))20312032self.add_col(am.ArrayConf('vertices', np.zeros((2, 3), dtype=np.float32),2033dtype=np.float32,2034groupnames=['_private'],2035perm='r',2036name='Coords',2037unit='m',2038info="Start and end vertices of right side of parking space.",2039))20402041self.add_col(am.ArrayConf('numbers_booking', 0, # ???2042dtype=np.int32,2043perm='r',2044name='booked',2045info="Number of vehicles booked for this parking.",2046))20472048# self.add_col(am.ArrayConf( 'durations', 0.0,# ???2049# dtype=np.float32,2050# perm='r',2051# name = 'Parking duration',2052# unit = 's',2053# info = "Default duration of car parking.",2054# ))20552056self.add(cm.ObjConf(lanes, is_child=False, groups=['_private']))20572058self.add(cm.ObjConf(lanes.parent.edges, is_child=False, groups=['_private']))20592060def get_edges(self):2061return self.edges.get_value()20622063def get_lanes(self):2064return self.lanes.get_value()20652066def link_vehiclefleet(self, vehicles):2067"""2068Links to table with vehicle info.2069"""2070self.add_col(am.IdsArrayConf('ids_bookedveh', vehicles,2071name='ID booked veh',2072info='ID of vehicle which has booked this parking position.',2073))20742075def update_netoffset(self, deltaoffset):2076"""2077Called when network offset has changed.2078Children may need to adjust their coordinates.2079"""2080pass20812082def get_parkinglane_from_edge(self, id_edge, id_mode, length_min=15.0, priority_max=8, n_freelanes_min=1):2083"""2084Check if edge can have on-road parking.2085Returns lane ID if parking is possible and -1 otherwise.2086"""2087edges = self.edges.get_value()2088lanes = self.lanes.get_value()2089id_mode_ped = edges.parent.modes.get_id_mode('pedestrian')2090# check access2091ids_lane = edges.ids_lanes[id_edge]2092edgelength = edges.lengths[id_edge]20932094if (len(ids_lane) >= 2):2095if (lanes.get_accesslevel([ids_lane[0]], id_mode_ped) > -1) & (lanes.get_accesslevel([ids_lane[1]], id_mode) > -1):2096# check size2097# laneindex =2098# print 'get_parkinglane_from_edge',id_edge, id_mode,priority_max,length_min2099# print ' check',(edges.priorities[id_edge]<=priority_max),(edges.lengths[id_edge]>length_min),(edges.widths_sidewalk[id_edge]>-1)21002101if (edges.priorities[id_edge] <= priority_max) & (edgelength > length_min) & (edges.widths_sidewalk[id_edge] > 0):21022103laneindex = 12104# print ' found',laneindex,edges.nums_lanes[id_edge]-laneindex > n_freelanes_min2105if (len(ids_lane)-laneindex >= n_freelanes_min):2106return ids_lane[laneindex]2107else:2108return -12109else:2110return -12111else:2112return -121132114return -1 # no parking possible by default21152116def get_edge_pos_parking(self, id_parking):2117lanes = self.lanes.get_value()2118return lanes.ids_edge[self.ids_lane[id_parking]], self.positions[id_parking]21192120# def get_edge_pos_parking(self, id_parking):2121# """2122# Retuens edge and position of parking with id_parking2123# """2124# ind = self.parking.get_ind(id_parking)2125#2126# return self.edges.get_value()(self.id_edge_parking[ind]),self.pos_edge_parking[ind]21272128def make_parking(self, id_mode=MODES['passenger'],2129length_min=42.0, length_noparking=15.0,2130length_lot=6.0, angle=0.0,2131is_clear=True,2132logger=None,2133**kwargs):2134print 'make_parking'2135if is_clear:2136self.clear()2137edges = self.edges.get_value()2138lanes = self.lanes.get_value()2139n_parking = 02140ids_parking = []2141ids_lane_current = self.ids_lane.get_value().copy()2142ii = 0.02143n_edges = len(edges.get_ids())2144for id_edge in edges.get_ids():2145ii += 12146if logger is not None:2147logger.progress(int(ii/n_edges*100))2148# check if edge is suitable...2149# print ' id_edge,length,n_lanes,',id_edge2150id_lane = self.get_parkinglane_from_edge(id_edge, id_mode, length_min, **kwargs)21512152is_eligible = id_lane >= 02153if not is_clear:2154if id_lane not in ids_lane_current:2155is_eligible = False21562157if is_eligible:2158n_spaces = int((edges.lengths[id_edge]-2*length_noparking)/length_lot)2159# print ' create',id_edge,lanes.indexes[id_lane],edges.lengths[id_edge],n_spaces2160# print ' delta',lanes.shapes[id_lane][0]-lanes.shapes[id_lane][-1]2161pos_offset = length_noparking2162pos = pos_offset2163if n_spaces > 0:2164for i in xrange(n_spaces):2165#id_park = self.suggest_id()2166# print ' pos=',pos,pos/edges.lengths[id_edge]21672168# print ' vertices',get_vec_on_polyline_from_pos(lanes.shapes[id_lane],pos, length_lot, angle = angle)2169n_parking += 121702171id_park = self.add_row(ids_lane=id_lane,2172positions=pos,2173lengths=length_lot,2174angles=angle,2175vertices=get_vec_on_polyline_from_pos(2176lanes.shapes[id_lane], pos, length_lot-0.5, angle=angle)2177)2178# print ' created id_park,pos', id_park,pos#,get_coord_on_polyline_from_pos(lanes.shapes[id_lane],pos),lanes.shapes[id_lane]2179ids_parking.append(id_park)2180pos = pos_offset+(i+1)*length_lot21812182print ' created %d parking spaces' % n_parking2183return ids_parking21842185def clear_booking(self):2186self.numbers_booking.reset()2187if hasattr(self, 'ids_bookedveh'):2188self.ids_bookedveh.reset()21892190def get_closest_parking(self, id_veh, coord, c_spread=2.0):2191"""2192Returns parking space for id_veh as close as possible to coord.2193"""21942195#inds_person = self.persons.get_inds(ids_person)2196print 'get_closest_parking'2197ind_parking_closest = self.get_inds()[np.argmin(2198np.sum((coord-self.vertices.value[:, 1, :])**2, 1) + c_spread*lengths*self.lengths.get_value())]2199self.numbers_booking.get_value()[ind_parking_closest] += 12200return self.get_ids(ind_parking_closest), ind_parking_closest22012202def get_closest_parkings(self, ids_veh, ids_mode, coords, dists_walk_max, c_spread=2.0,2203n_retrials=20, id_mode_fallback=None):2204"""2205Returns parking space for each vehicle in ids_veh as close as possible to coords.2206"""22072208# Used by virtualpop22092210lanes = self.ids_lane.get_linktab()2211ids_lane = self.ids_lane.get_value()2212#inds_person = self.persons.get_inds(ids_person)2213n = len(ids_veh)22142215# print 'get_closest_parking',n,len(self),'n_retrials',n_retrials2216if len(self) == 0:2217print 'WARNING in get_closest_parkings: there is no parking.'2218return [], []22192220#parking = self.get_landuse().parking2221#inds_parking = parking.get_inds()2222coord_parking = self.vertices.value[:, 1, :]2223# print ' coord_parking',coord_parking2224numbers_booking = self.numbers_booking.get_value()2225lengths = self.lengths.get_value()2226inds_vehparking = np.zeros(n, int)2227are_fallback = np.zeros(n, bool)22282229#inds_parking_avail = np.flatnonzero( self.ids_bookedveh.value == -1).tolist()2230inds_parking_avail = self.get_inds().copy()22312232#ids_veh = np.zeros(n,object)2233i = 02234for id_veh, id_mode, coord, dist_walk_max_sq in zip(ids_veh, ids_mode, coords, dists_walk_max**2):2235# print ' search parking for id_veh',id_veh2236# print ' landuse.id_bookedveh_parking',landuse.id_bookedveh_parking2237#22382239# print ' inds_parking_avail',inds_parking_avail2240# print ' dists',np.sum((coord-coord_parking[inds_parking_avail])**2,1),np.argmin(np.sum((coord-coord_parking[inds_parking_avail])**2,1))2241is_fallback = False2242penalties_inaccessible = np.ones(len(numbers_booking), dtype=np.float32)2243n_search = n_retrials2244is_search = True2245while (n_search > 0) & is_search:2246dists = np.sum((coord-coord_parking)**2, 1)2247ind_parking_closest = inds_parking_avail[np.argmin(2248dists + c_spread*lengths*numbers_booking*penalties_inaccessible)]2249# print ' ind_parking_closest,n_avail',ind_parking_closest,len(inds_parking_avail),'n_search',n_search,'is_search',is_search2250is_search = (not (lanes.get_accesslevel([ids_lane[ind_parking_closest]], id_mode) >= 0))\2251| (dists[ind_parking_closest] > dist_walk_max_sq)2252penalties_inaccessible[ind_parking_closest] = np.inf # prevent reselection of this parking2253n_search -= 12254# print ' n_search',n_search,'is_search',is_search22552256# print ' done with id_mode is_search',is_search2257if is_search & (id_mode_fallback is not None):2258# search mode means no parking has bee found for ordinary mode2259# now try with fallback mode22602261is_fallback = True2262penalties_inaccessible = np.ones(len(numbers_booking), dtype=np.float32)2263n_search = n_retrials2264while (n_search > 0) & is_search:2265dists = np.sum((coord-coord_parking)**2, 1)2266ind_parking_closest = inds_parking_avail[np.argmin(2267dists + c_spread*lengths*numbers_booking*penalties_inaccessible)]2268# print ' ind_parking_closest,n_avail',ind_parking_closest,len(inds_parking_avail)2269is_search = (not (lanes.get_accesslevel([ids_lane[ind_parking_closest]], id_mode_fallback) >= 0))\2270| (dists[ind_parking_closest] > dist_walk_max_sq)2271penalties_inaccessible[ind_parking_closest] = np.inf # prevent reselection of this parking2272n_search -= 12273# print ' fallback n_search',n_search,'is_search',is_search22742275if is_search:2276print 'WARNING: inaccessible parking for id_veh', id_veh, 'is_fallback', is_fallback2277print ' dist=%.1f' % (np.sqrt(dists[ind_parking_closest])), 'id_lane', ids_lane[ind_parking_closest], 'al', lanes.get_accesslevel([ids_lane[ind_parking_closest]], id_mode_fallback)22782279inds_vehparking[i] = ind_parking_closest2280are_fallback[i] = is_fallback2281# print ' coords_veh',coord2282# print ' coord_park',coord_parking[ind_parking_closest]2283numbers_booking[ind_parking_closest] += 122842285#id_parking = self.get_ids([ind_parking_closest])2286#id_edge, pos = self.get_edge_pos_parking(id_parking)2287# print ' id_veh=%s,id_parking_closest=%s, dist =%.2fm'%(id_veh,id_parking,np.sqrt(np.sum((coord-coord_parking[ind_parking_closest])**2)))2288# ids_bookedveh[ind_parking_closest]=id_veh # occupy parking2289# print ' id_edge, pos',id_edge, pos2290# inds_parking_avail.remove(ind_parking_closest)2291i += 122922293# print ' inds_vehparking', inds_vehparking2294# print ' ids_vehparking', self.get_ids(inds_vehparking)2295# print ' ids_veh',ids_veh2296#self.ids_bookedveh.value[inds_vehparking] = ids_veh2297# self.ids_bookedveh.[ids_parking] =ids_bookedveh2298return self.get_ids(inds_vehparking), are_fallback22992300def assign_parking(self, ids_veh, coords, is_overbook=False):2301"""2302Assigns a parking space to each vehicle as close as possible to coords.2303Only one vehicle can be assigned to a parking space.2304"""23052306#inds_person = self.persons.get_inds(ids_person)2307n = len(ids_veh)2308# print 'assign_parking',n23092310#parking = self.get_landuse().parking2311#inds_parking = parking.get_inds()2312coord_parking = self.vertices.value[:, 1, :]23132314inds_vehparking = np.zeros(n, int)23152316inds_parking_avail = np.flatnonzero(self.ids_bookedveh.value == -1).tolist()23172318#ids_veh = np.zeros(n,object)2319i = 02320for id_veh, coord in zip(ids_veh, coords):2321# print '\n id_veh,coord',id_veh,coord2322# print ' landuse.id_bookedveh_parking',landuse.id_bookedveh_parking2323#23242325# print ' inds_parking_avail',inds_parking_avail2326# print ' dists',np.sum((coord-coord_parking[inds_parking_avail])**2,1),np.argmin(np.sum((coord-coord_parking[inds_parking_avail])**2,1))2327ind_parking_closest = inds_parking_avail[np.argmin(np.sum((coord-coord_parking[inds_parking_avail])**2, 1))]2328# print ' ind_parking_closest,n_avail',ind_parking_closest,len(inds_parking_avail)2329inds_vehparking[i] = ind_parking_closest2330# print ' id_veh=%s,id_parking_closest=%s, dist =%.2fm'%(id_veh,self.get_ids([ind_parking_closest]),np.sqrt(np.sum((coord-coord_parking[ind_parking_closest])**2)))2331# ids_bookedveh[ind_parking_closest]=id_veh # occupy parking23322333inds_parking_avail.remove(ind_parking_closest)2334i += 123352336# print ' inds_vehparking', inds_vehparking2337# print ' ids_vehparking', self.get_ids(inds_vehparking)2338# print ' ids_veh',ids_veh2339self.ids_bookedveh.value[inds_vehparking] = ids_veh2340# self.ids_bookedveh.[ids_parking] =ids_bookedveh2341return self.get_ids(inds_vehparking), inds_vehparking234223432344class Landuse(cm.BaseObjman):2345def __init__(self, scenario=None, net=None, **kwargs):2346self._init_objman(ident='landuse', parent=scenario, name='Landuse', **kwargs)2347attrsman = self.set_attrsman(cm.Attrsman(self))23482349if scenario is not None:2350net = scenario.net2351# self.net = attrsman.add( cm.ObjConf( net, is_child = False ) )# link only23522353self.landusetypes = attrsman.add(cm.ObjConf(LanduseTypes(self)))2354self.zones = attrsman.add(cm.ObjConf(Zones(self, net.edges)))2355self.facilities = attrsman.add(cm.ObjConf(Facilities(self, self.landusetypes, self.zones, net=net)))2356self.parking = attrsman.add(cm.ObjConf(Parking(self, net.lanes)))2357self.maps = attrsman.add(cm.ObjConf(maps.Maps(self)))23582359def update_netoffset(self, deltaoffset):2360"""2361Called when network offset has changed.2362Children may need to adjust theur coordinates.2363"""2364self.zones.update_netoffset(deltaoffset)2365self.facilities.update_netoffset(deltaoffset)2366self.parking.update_netoffset(deltaoffset)2367self.maps.update_netoffset(deltaoffset)23682369def get_net(self):2370# parent of landuse must be scenario2371if self.parent is not None:2372return self.parent.net2373else:2374return None23752376def export_polyxml(self, filepath=None, encoding='UTF-8', delta=np.zeros(3, dtype=np.float32)):2377"""2378Export landuse facilities to SUMO poly.xml file.2379"""2380if len(self.facilities) == 0:2381return None23822383if filepath is None:2384if self.parent is not None:2385filepath = self.get_filepath()2386else:2387filepath = os.path.join(os.getcwd(), 'landuse.poly.xml')23882389print 'export_polyxml', filepath2390try:2391fd = open(filepath, 'w')2392except:2393print 'WARNING in export_poly_xml: could not open', filepath2394return None23952396#xmltag, xmltag_item, attrname_id = self.xmltag2397xmltag_poly = 'additional'2398fd.write('<?xml version="1.0" encoding="%s"?>\n' % encoding)2399fd.write(xm.begin(xmltag_poly))2400indent = 224012402fd.write(xm.start('location', indent+2))2403# print ' groups:',self.parent.net.get_attrsman().get_groups()2404for attrconfig in self.parent.net.get_attrsman().get_group('location'):2405# print ' locationconfig',attrconfig.attrname2406if attrconfig.attrname == '_boundaries':2407delta_bb = np.zeros(4, dtype=np.float32)2408delta_bb[0:2] = delta[:2]2409delta_bb[2:4] = delta[:2]2410fd.write(xm.arr('convBoundary', attrconfig.get_value()-delta_bb))2411else:2412attrconfig.write_xml(fd)2413fd.write(xm.stopit())24142415self.facilities.write_xml(fd, indent=indent+2, is_print_begin_end=False, delta=delta)24162417fd.write(xm.end(xmltag_poly))2418fd.close()2419return filepath24202421def get_filepath(self):2422return self.parent.get_rootfilepath() + '.poly.xml'24232424def import_polyxml(self, rootname=None, dirname='', filepath=None, is_clear=True, **kwargs):2425if filepath is None:2426if rootname is not None:2427filepath = os.path.join(dirname, rootname+'.poly.xml')2428else:2429filepath = self.get_filepath()24302431if os.path.isfile(filepath):2432self.facilities.import_poly(filepath, is_clear=is_clear, **kwargs)24332434else:2435self.get_logger().w('import_xml: files not found:'+filepath, key='message')24362437#2438# here may be other relevant imports2439#244024412442class FacilityGenerator(Process):2443def __init__(self, ident='facilitygenerator', facilities=None, logger=None, **kwargs):2444print 'FacilityGenerator.__init__'24452446# TODO: let this be independent, link to it or child??24472448self._init_common(ident,2449parent=facilities,2450name='Facility Generator',2451logger=logger,2452info='Generates facilities (buildigs, factories, parks, etc.) in a given street network.',2453)24542455attrsman = self.set_attrsman(cm.Attrsman(self))24562457# make for each possible pattern a field for prob24582459self.edgelength_min = attrsman.add(cm.AttrConf('edgelength_min', kwargs.get('edgelength_min', 50.0),2460groupnames=['options'],2461perm='rw',2462name='Minimum edge length',2463unit='m',2464info="""Minimum edge length for which houses are generated.""",2465))24662467self.priority_max = attrsman.add(cm.AttrConf('priority_max', kwargs.get('priority_max', 7),2468groupnames=['options'],2469perm='rw',2470name='Max. priority',2471info="""Maximum edge priority where facilities will be created.""",2472))24732474self.height_max = attrsman.add(cm.AttrConf('height_max', kwargs.get('height_max', 20.0),2475groupnames=['options'],2476perm='rw',2477unit='m',2478name='Max facility height',2479info="""Maximum height of facilities.""",2480))24812482self.capacity_max = attrsman.add(cm.AttrConf('capacity_max', kwargs.get('capacity_max', 1000),2483groupnames=['options'],2484perm='rw',2485name='Max. facility capacity',2486info="""Maximum capacity of a facility. Capacity is the number of adulds living in a house or working in a factory.""",2487))24882489self.n_retry = attrsman.add(cm.AttrConf('n_retry', kwargs.get('n_retry', 5),2490groupnames=['options'],2491perm='rw',2492name='Retry number',2493info="""Number of times the algorithm is trying to fit a facility in a road-gap.""",2494))24952496# self.id_facilitytype = attrsman.add(cm.AttrConf( 'id_facilitytype',kwargs.get('id_facilitytype',1),2497# groupnames = ['options'],2498# perm='rw',2499# choices = self.parent.facilities.facilitytypes.get_value().names.get_indexmap(),2500# name = 'Facility type',2501# info = """Facility type to be generated.""",2502# ))25032504def do(self):2505print self.get_name()+'.do'2506# links2507facilities = self.parent2508net = facilities.parent.get_net()2509edges = net.edges2510nodes = net.nodes2511#self._edges = edges25122513#self._segvertices = edges.get_segvertices_xy()2514x1, y1, x2, y2 = edges.get_segvertices_xy()25152516logger = self.get_logger()25172518ids_edge = edges.select_ids((edges.widths_sidewalk.get_value() > 0)2519& (edges.lengths.get_value() > self.edgelength_min)2520& (edges.priorities.get_value() < self.priority_max)2521)2522facilitytypes = facilities.facilitytypes.get_value()25232524# here we can make a selection2525facilitytypeobjs = facilitytypes.typeobjects[facilitytypes.get_ids()]25262527# print ' facilitytypes, facilitytypeobjs',facilitytypes,facilitytypeobjs2528n_factypes = len(facilitytypes)2529n_fac = 02530n_edges = len(ids_edge)2531#logger.w('Add facilities to %d edges')2532# print ' eligible edges =',ids_edge2533i = 0.02534for id_edge, edgelength, id_fromnode, id_tonode, shape, edgewidth\2535in zip(ids_edge, edges.lengths[ids_edge],2536edges.ids_fromnode[ids_edge],2537edges.ids_tonode[ids_edge],2538edges.shapes[ids_edge],2539edges.widths[ids_edge],2540):2541pos = 5.02542# print ' Build at edge',id_edge,edgelength2543#logger.w('Add facilities to %d edges')2544i += 12545logger.progress(i/n_edges*100)25462547# identify opposite edge, which needs to be excluded2548# from bulding overlapping check2549if (nodes.ids_incoming[id_fromnode] is not None)\2550& (nodes.ids_outgoing[id_tonode] is not None):2551ids_incoming_fomnode = set(nodes.ids_incoming[id_fromnode])2552ids_outgoing_tonode = set(nodes.ids_outgoing[id_tonode])25532554id_edge_opp_set = ids_incoming_fomnode.intersection(ids_outgoing_tonode)2555if len(id_edge_opp_set) > 0:2556id_edge_opp = id_edge_opp_set.pop()2557inds_seg_opp = edges.get_inds_seg_from_id_edge(id_edge_opp)2558else:2559# print ' no edge in opposite direction'2560id_edge_opp = -12561inds_seg_opp = None2562else:2563id_edge_opp = -12564inds_seg_opp = None2565#ids_tonode_outgoing = edges.ids_tonode[nodes.ids_outgoing[id_tonode]]2566# net.get_ids_edge_from_inds_seg(inds_seg)2567# net.get_inds_seg_from_id_edge(id_edge)25682569while pos < edgelength:2570facilitytype = facilitytypeobjs[0] # could be according to statistics2571# print ' next position',pos2572n_trials = self.n_retry2573is_success = False2574while (n_trials > 0) & (not is_success):2575length_fac = random.uniform(facilitytype.length_min, facilitytype.length_max)2576width_fac = random.uniform(facilitytype.width_min, facilitytype.width_max)25772578# fix from to positions2579pos11 = pos2580pos21 = pos + length_fac2581if pos21 < edgelength:2582# print ' try place',n_trials,facilitytype,'id_edge',id_edge,pos11,pos21,edgelength25832584coord11, angle = get_coord_angle_on_polyline_from_pos(shape, pos11)2585dxn = np.cos(angle-np.pi/2)2586dyn = np.sin(angle-np.pi/2)2587coord12 = [coord11[0]+width_fac*dxn, coord11[1]+width_fac*dyn, coord11[2]]25882589coord21, angle = get_coord_angle_on_polyline_from_pos(shape, pos21)2590dxn = np.cos(angle-np.pi/2)2591dyn = np.sin(angle-np.pi/2)2592coord22 = [coord21[0]+width_fac*dxn, coord21[1]+width_fac*dyn, coord21[2]]25932594id_edge1 = edges.get_ids_edge_from_inds_seg(self.get_segind_closest_edge(2595coord12, x1, y1, x2, y2, inds_seg_exclude=inds_seg_opp))25962597#id_edge2 = edges.get_ids_edge_from_inds_seg(self.get_segind_closest_edge(coord22, x1,y1,x2,y2, inds_seg_exclude = inds_seg_opp))2598# print ' id_edge,id_edge1,id_edge2',id_edge,id_edge1,id_edge22599# print ' shape =',np.array([coord11, coord12, coord22, coord21,], dtype = np.float32)2600if id_edge1 == id_edge:2601id_edge2 = edges.get_ids_edge_from_inds_seg(self.get_segind_closest_edge(2602coord22, x1, y1, x2, y2, inds_seg_exclude=inds_seg_opp))26032604if id_edge2 == id_edge:2605id_fac = facilities.generate(facilitytype,2606offset=coord11, # offset2607length=length_fac,2608width=width_fac,2609#bbox = [coord11, coord12, coord22, coord21,],2610id_landusetype=None,2611angle=angle,2612pos_edge=pos11,2613capacity=self.capacity_max, # could be function of dist to center/pop2614height_max=self.height_max, # could be function of dist to center2615id_edge=id_edge,2616width_edge=edgewidth,2617)26182619if id_fac != -1:2620# print ' ****generation successful id_fac=',id_fac2621is_success = True2622n_fac += 126232624n_trials -= 126252626pos = pos212627# print ' update with pos',pos2628# generate a parallel shape with distance width_fac2629#angles_perb = get_angles_perpendicular(shape)2630#dxn = np.cos(angles_perb)2631#dyn = np.sin(angles_perb)2632#shape2 = np.zeros(shape.shape, np.float32)2633#shape2[:,0] = dxn*width_fac + shape[:,0]2634#shape2[:,1] = dyn*width_fac + shape[:,1]2635#shape2[:,2] = shape[:,2]26362637# check if positions on parallel shape are closest to2638# this edge or closer to another edge2639print ' Done, generated %d facilities' % n_fac2640return True26412642def get_segind_closest_edge(self, p, x1, y1, x2, y2, inds_seg_exclude=None):2643d2 = get_dist_point_to_segs(p[0:2], x1, y1, x2, y2, is_ending=True)2644if inds_seg_exclude is not None:2645d2[inds_seg_exclude] = np.inf2646# print ' min(d2)=',np.min(d2),'argmin=',np.argmin(d2),self.get_ids(self._edgeinds[np.argmin(d2)])2647return np.argmin(d2)264826492650class ParkingGenerator(Process):2651def __init__(self, ident='parkinggenerator', parking=None, logger=None, **kwargs):2652print 'ParkingGenerator.__init__'26532654# TODO: let this be independent, link to it or child??26552656self._init_common(ident,2657parent=parking,2658name='On Road parking generator',2659logger=logger,2660info='Generates on road parking.',2661)26622663attrsman = self.set_attrsman(cm.Attrsman(self))2664scenario = parking.parent.parent26652666self.id_mode = attrsman.add(cm.AttrConf('id_mode', kwargs.get('id_mode', MODES['passenger']),2667groupnames=['options'],2668choices=scenario.net.modes.names.get_indexmap(),2669perm='rw',2670name='Mode ID',2671info="""Mode of parked vehicles. This is to select lanes which must be accessible for this mode.""",2672))26732674self.length_min = attrsman.add(cm.AttrConf('length_min', kwargs.get('length_min', 42.0),2675groupnames=['options'],2676perm='rw',2677unit='m',2678name='Min. edge length',2679info="""Minimum edge length in order to qualify for parking.""",2680))26812682self.length_noparking = attrsman.add(cm.AttrConf('length_noparking', kwargs.get('length_noparking', 15.0),2683groupnames=['options'],2684perm='rw',2685unit='m',2686name='No parking length',2687info="""Length from junction to the first or last parking on an edge.""",2688))26892690self.length_lot = attrsman.add(cm.AttrConf('length_lot', kwargs.get('length_lot', 6.0),2691groupnames=['options'],2692perm='rw',2693unit='m',2694name='Lot length',2695info="""Length of a single parking lot.""",2696))26972698self.angle = attrsman.add(cm.AttrConf('angle', kwargs.get('angle', 0.0),2699groupnames=['options'],2700perm='rw',2701name='Angle',2702info="""Angle of parking with respect ti lane direction. Currently only 0.0 is possible.""",2703))27042705self.priority_max = attrsman.add(cm.AttrConf('priority_max', kwargs.get('priority_max', 7),2706groupnames=['options'],2707perm='rw',2708name='Max. priority',2709info="""Maximum edge priority where parkings will be created.""",2710))27112712self.n_freelanes_min = attrsman.add(cm.AttrConf('n_freelanes_min', kwargs.get('n_freelanes_min', 1),2713groupnames=['options'],2714perm='rw',2715name='Min. free lanes',2716info="""Minimum number of free lanes on the edge. These is the minimum number of lanes excluding the parking lane.""",2717))2718self.is_clear = attrsman.add(cm.AttrConf('is_clear', kwargs.get('is_clear', True),2719groupnames=['options'],2720perm='rw',2721name='Clear',2722info="""Clear previous parking areas from ntework.""",2723))27242725def do(self):2726print self.get_name()+'.do'2727# links2728# print ' self.id_mode',self.id_mode2729# print ' self.get_kwoptions()',self.get_kwoptions()2730logger = self.get_logger()27312732self.parent.make_parking(logger=logger, **self.get_kwoptions())2733return True273427352736class OsmPolyImporter(CmlMixin, Process):2737def __init__(self, landuse=None,2738osmfilepaths=None,2739typefilepath=None,2740polyfilepath=None,2741projparams=None,2742offset_x=None,2743offset_y=None,2744is_keep_full_type=True,2745is_import_all_attributes=True,2746is_use_name_for_id=False,2747polytypefilepath='',2748is_clean_osmfile=True,2749is_merge=False,2750logger=None, **kwargs):2751print 'OsmPolyImporter.__init__', landuse, landuse.parent.get_rootfilename()2752self._init_common('osmpolyimporter', name='OSM Poly import',2753logger=logger,2754info='Converts a OSM file to a SUMO Poly file and read facilities into scenario.',2755)2756if landuse is None:2757self._landuse = Landuse()2758else:2759self._landuse = landuse27602761self.init_cml('polyconvert') # pass main shell command27622763if landuse.parent is not None:2764scenario = landuse.parent2765rootname = scenario.get_rootfilename()2766rootdirpath = scenario.get_workdirpath()2767if hasattr(scenario, 'net'):2768if projparams is None:2769projparams = scenario.net.get_projparams()2770if (offset_x is None) & (offset_y is None):2771offset_x, offset_y = scenario.net.get_offset()2772else:2773rootname = landuse.get_ident()2774rootdirpath = os.getcwd()27752776if polyfilepath is None:2777polyfilepath = os.path.join(rootdirpath, rootname+'.poly.xml')27782779if osmfilepaths is None:2780osmfilepaths = os.path.join(rootdirpath, rootname+'.osm.xml')27812782if typefilepath is None:2783if 'SUMO_HOME' in os.environ:2784typemapdir = os.path.join(os.environ['SUMO_HOME'], 'data', 'typemap')2785typefilepath = os.path.join(typemapdir, 'osmPolyconvert.typ.xml')2786else:2787print("No poly typemaps found. Please declare environment variable 'SUMO_HOME'")2788typefilepath = ''27892790attrsman = self.get_attrsman()27912792self.rootdirpath = rootdirpath27932794self.rootname = rootname27952796self.add_option('osmfilepaths', osmfilepaths,2797groupnames=['options'],2798cml='--osm-files',2799perm='rw',2800name='OSM files',2801wildcards='OSM XML files (*.osm)|*.osm*',2802metatype='filepaths',2803info='Openstreetmap files to be imported.',2804)28052806self.is_merge = attrsman.add(cm.AttrConf('is_merge', is_merge,2807groupnames=['options'],2808perm='rw',2809name='Merge',2810info='If set, imported polygons are merged with existing.',2811))28122813self.is_clean_osmfile = attrsman.add(cm.AttrConf('is_clean_osmfile', is_clean_osmfile,2814groupnames=['options'],2815perm='rw',2816name='Clean OSM files',2817info='If set, OSM files are cleaned from strange characters prior to import (recommended).',2818))28192820self.height_default = attrsman.add(cm.AttrConf('height_default', kwargs.get('height_default', 7.0),2821groupnames=['options'],2822perm='rw',2823name='Default height',2824info='Default height of facilities in case no height information is available.',2825))28262827self.type_default = attrsman.add(cm.AttrConf('type_default', kwargs.get('type_default', 'building.yes'),2828groupnames=['options'],2829perm='rw',2830name='Default facility type',2831info='Default type of facilities in case no type information is available.',2832))28332834self.add_option('polyfilepath', polyfilepath,2835groupnames=['_private'],2836cml='--output-file',2837perm='r',2838name='Poly file',2839wildcards='Poly XML files (*.poly.xml)|*.poly.xml',2840metatype='filepath',2841info='SUMO Poly file in XML format.',2842)28432844self.add_option('typefilepath', typefilepath,2845groupnames=['options'],2846cml='--type-file',2847perm='rw',2848name='Type file',2849wildcards='Typemap XML files (*.typ.xml)|*.typ.xml',2850metatype='filepath',2851info="""Typemap XML files. In these file,2852OSM building types are mapped to specific facility parameters, is not explicitely set by OSM attributes.""",2853)28542855# --net-file <FILE> Loads SUMO-network FILE as reference to offset and projection2856self.add_option('projparams', projparams,2857groupnames=['options'],2858cml='--proj',2859perm='rw',2860name='projection',2861info='Uses STR as proj.4 definition for projection. Default is the projection of the network, better do not touch!',2862is_enabled=lambda self: self.projparams is not None,2863)28642865self.add_option('offset_x', offset_x,2866groupnames=['options', 'geometry'],2867cml='--offset.x ',2868perm='rw',2869unit='m',2870name='X-Offset',2871info='Adds offset to net x-positions; default: 0.0',2872is_enabled=lambda self: self.offset_x is not None,2873)2874self.add_option('offset_y', offset_y,2875groupnames=['options', 'geometry'],2876cml='--offset.y ',2877perm='rw',2878unit='m',2879name='Y-Offset',2880info='Adds offset to net x-positions; default: 0.0',2881is_enabled=lambda self: self.offset_y is not None,2882)28832884self.add_option('is_keep_full_type', is_keep_full_type,2885groupnames=['options'],2886cml='--osm.keep-full-type',2887perm='rw',2888name='keep full OSM type',2889info='The type will be made of the key-value - pair.',2890)28912892self.add_option('is_import_all_attributes', is_keep_full_type,2893groupnames=['options'],2894cml='--all-attributes',2895perm='rw',2896name='import all attributes',2897info='Imports all OSM attributes.',2898)28992900self.add_option('is_use_name_for_id', is_use_name_for_id,2901groupnames=['options'],2902cml='--osm.use-name',2903perm='rw',2904name='use OSM name for id',2905info=' The OSM id (not internal ID) will be set from the given OSM name attribute.',2906)29072908self.add_option('polytypefilepath', polytypefilepath,2909groupnames=[], # ['_private'],#2910cml='--type-file',2911perm='rw',2912name='Poly type file',2913wildcards='Net XML files (*.xml)|*.xml',2914metatype='filepath',2915info='SUMO Poly type file in XML format.',2916is_enabled=lambda self: self.polytypefilepath != '',2917)29182919def update_params(self):2920"""2921Make all parameters consistent.2922example: used by import OSM to calculate/update number of tiles2923from process dialog2924"""2925pass2926#self.workdirpath = os.path.dirname(self.netfilepath)2927#bn = os.path.basename(self.netfilepath).split('.')2928# if len(bn)>0:2929# self.rootname = bn[0]29302931def do(self):2932self.update_params()2933cml = self.get_cml()29342935if self.is_clean_osmfile:2936for path in self.osmfilepaths.split(','):2937path_temp = path+'.clean'2938clean_osm(path, path_temp)2939#shutil.copy (path_temp, path)2940shutil.move(path_temp, path)29412942# print 'SumonetImporter.do',cml2943#import_xml(self, rootname, dirname, is_clean_nodes = True)2944self.run_cml(cml)2945if self.status == 'success':2946if os.path.isfile(self.polyfilepath):2947print ' OSM->poly.xml successful, start importing xml files'2948self._landuse.import_polyxml(self.rootname, self.rootdirpath,2949is_clear=not self.is_merge,2950type_default=self.type_default,2951height_default=self.height_default)2952print ' import poly in sumopy done.'2953return True2954return False2955else:2956return False29572958def get_landuse(self):2959# used to het landuse in case landuse has been created2960return self._landuse296129622963if __name__ == '__main__':2964###############################################################################2965# print 'sys.path',sys.path2966from agilepy.lib_wx.objpanel import objbrowser2967from agilepy.lib_base.logger import Logger2968#from coremodules.scenario import scenario2969from coremodules.network import network2970logger = Logger()2971NETPATH = os.path.join(SUMOPYDIR, 'coremodules', 'network', 'testnet')2972net = network.Network(logger=logger)2973rootname = 'facsp2'2974net.import_xml(rootname, NETPATH)2975# net.read_sumonodes(os.path.join(NETPATH,'facsp2.nod.xml'))2976# net.read_sumoedges(os.path.join(NETPATH,'facsp2.edg.xml'))2977landuse = Landuse(net=net, logger=logger)29782979# landuse.facilities.import_poly(os.path.join(NETPATH,'facsp2.poly.xml'))2980landuse.import_xml(rootname, NETPATH)2981objbrowser(landuse)298229832984