1# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo 2# Copyright (C) 2016-2019 German Aerospace Center (DLR) and others. 3# SUMOPy module 4# Copyright (C) 2012-2017 University of Bologna - DICAM 5# This program and the accompanying materials 6# are made available under the terms of the Eclipse Public License v2.0 7# which accompanies this distribution, and is available at 8# http://www.eclipse.org/legal/epl-v20.html 9# SPDX-License-Identifier: EPL-2.0 10 11# @file mapmatching.py 12# @author Joerg Schweizer 13# @date 14# @version $Id$ 15 16""" 17This plugin provides methods to match GPS traces to a SUMO road network and to generate routes. 18 19The general structure is as follows: 20GPSPoints 21routes 22 23Traces 24 25""" 26import os 27import sys 28from xml.sax import saxutils, parse, handler 29 30import time 31import string 32import numpy as np 33from xml.sax import saxutils, parse, handler 34 35if __name__ == '__main__': 36 try: 37 APPDIR = os.path.dirname(os.path.abspath(__file__)) 38 except: 39 APPDIR = os.path.dirname(os.path.abspath(sys.argv[0])) 40 SUMOPYDIR = os.path.join(APPDIR, '..', '..') 41 sys.path.append(SUMOPYDIR) 42 43 44from coremodules.modules_common import * 45import agilepy.lib_base.classman as cm 46import agilepy.lib_base.arrayman as am 47import agilepy.lib_base.xmlman as xm 48#from agilepy.lib_base.misc import get_inversemap 49from agilepy.lib_base.geometry import get_dist_point_to_segs 50from agilepy.lib_base.processes import Process # ,CmlMixin,ff,call 51from coremodules.network.network import SumoIdsConf 52from coremodules.network import routing 53from coremodules.demand.demandbase import DemandobjMixin 54from coremodules.demand.demand import Trips, Routes 55from coremodules.misc import shapeformat 56try: 57 try: 58 import pyproj 59 except: 60 from mpl_toolkits.basemap import pyproj 61 try: 62 from shapely.geometry import Polygon, MultiPolygon, MultiLineString, Point, LineString, MultiPoint, asLineString, asMultiPoint 63 from shapely.ops import cascaded_union 64 except: 65 print 'Import error: No shapely module available.' 66except: 67 print 'Import error: in order to run the traces plugin please install the following modules:' 68 print ' mpl_toolkits.basemap and shapely' 69 print 'Please install these modules if you want to use it.' 70 print __doc__ 71 raise 72 73TRIPPUROPSES = {'unknown': -1, 74 'HomeToWork': 1, 75 'WorkToHome': 2, 76 'HomeToSchool': 3, 77 'SchoolToHome': 4, 78 'SchoolToHome': 5, 79 'Leisure': 6, 80 'Other': 7, 81 } 82 83OCCUPATIONS = {'unknown': -1, 84 'worker': 1, 85 'student': 2, 86 'employee': 3, 87 'public employee': 4, 88 'selfemployed': 5, 89 'pensioneer': 6, 90 'other': 7 91 } 92 93GENDERS = {'male': 0, 'female': 1, 'unknown': -1} 94 95DEVICES = {'unknown': -1, 96 'cy-android': 1, 97 'cy-windows': 2, 98 'cy-ios': 3, 99 'cy-web-gpx': 4, 100 'cy-web-manual': 5, 101 'Other': 7 102 } 103 104WEEKDAYCHOICES = {'Monday-Friday': [0, 1, 2, 3, 4], 105 'Monday-Saturday': [0, 1, 2, 3, 4, 5], 106 'Saturday, Sunday': [5, 6], 107 'all': [0, 1, 2, 3, 4, 5, 6], 108 } 109 110COLOR_SHORTEST_ROUTE = np.array([108, 183, 0, 0.6*255], np.float32)/255 111COLOR_MATCHED_ROUTE = np.array([255, 210, 2, 0.6*255], np.float32)/255 112COLOR_FASTEST_ROUTE = np.array([198, 0, 255, 0.6*255], np.float32)/255 113# Structure GPS traces 114 115 116# 2016 117 118# UserID TripID TimeStamp Start DT Distance ECC AvgSpeed TrackType Sex Year Profession Frequent User ZIP Source TypeOfBike TipeOfTrip Max Spd 119# 57249bcd88c537874f9fa1ae 57515edc88c537576ca3e16f 1464945480 2016-06-03T09:18:00.000Z 4.75 4.75 10.16 urban bicycle F 1999 Studente yes cy-web-gpx MyBike HomeToSchool 25.45 120# 5550800888c53765217661aa 574ec13788c537476aa3e122 1464797040 2016-06-01T16:04:00.000Z 2.93 2.93 5.87 urban bicycle F 1972 Worker yes 40136 cy-web-gpx -- -- 0 121# 5535586e88c53786637b23c6 574f3c3688c537c877a3e139 1464796080 2016-06-01T15:48:00.000Z 8.95 8.95 7.84 urban bicycle M 1973 Lavoratore yes 40133 cy-web-gpx MyBike HomeToWork 34.08 122# 5550800888c53765217661aa 574ec12b88c537812fa3e118 1464781800 2016-06-01T11:50:00.000Z 3.75 3.75 14.99 urban bicycle F 1972 Worker yes 40136 cy-web-gpx -- -- 0 123# 5550800888c53765217661aa 574ec11988c5370944a3e107 1464778980 2016-06-01T11:03:00.000Z 2.77 2.77 11.09 urban bicycle F 1972 Worker yes 40136 cy-web-gpx -- -- 0 124# 55e5edfc88c5374b4974fdbc 574e98c988c5378163a3e11f 1464765060 2016-06-01T07:11:00.000Z 11.09 11.14 15.63 urban bicycle 1982 SI cy-web-gpx MyBike HomeToWork 27.9 125 126 127# csv 2016 128# TripID, TimeStamp,Latitude, Longitude, Altitude, Distance, Speed, Type 129# 574e98c988c5378163a3e11f,1462347278,44.52606,11.27617,78,0.027255420500625783,5,<start|mid|end>, 130# 5741cdd388c537f10192ee97, 1463926725,44.50842,11.3604,101.0417,0.01615021486623964,3.483146,mid 131# timestamp: 1464160924 after 1970 132 133 134# 2015 csv 135 136# workouts 137# UserID TripID TimeStamp Start DT Distance AvgSpeed TrackType Sex Year Profession Frequent User ZIP 138# 54eb068de71f393530a9a74d 54eb0737e71f394c2fa9a74d 1424692504 Mon, 23 Feb 2015 11:55:04 GMT 0 0 urban bicycle M 1987 Developer no 139# 54eb9374e71f39f02fa9a750 5505cb04e71f39542e25e2d4 1426442994 Sun, 15 Mar 2015 18:09:54 GMT 0 0.7 urban bicycle M 1974 Worker yes 40128 140 141 142#TripID, TimeStamp,Date, Latitude, Longitude, Altitude, Distance, Speed, Type 143# 54eb0737e71f394c2fa9a74d,1424692509,"Mon, 23 Feb 2015 11:55:09 GMT",44.499096,11.361185,49.419395,0,0.000815,start 144 145 146# https://docs.python.org/2/library/time.html 147# >>> t = time.mktime((2017,03,07,13,46,0,0,0,0)) 148# >>> lt = time.localtime(t) 149# >>> time.strftime("%a, %d %b %Y %H:%M:%S +0000", lt) 150#'Tue, 07 Mar 2017 13:46:00 +0000' 151# >>> time.strftime("%a, %d %b %Y %H:%M:%S", lt) 152#'Tue, 07 Mar 2017 13:46:00' 153 154def load_results(filepath, parent=None, logger=None): 155 # typically parent is the scenario 156 results = cm.load_obj(filepath, parent=parent) 157 if logger is not None: 158 results.set_logger(logger) 159 return results 160 161 162def calc_seconds(t_data, 163 sep_date_clock=' ', sep_date='-', sep_clock=':', 164 is_float=False): 165 """ 166 Returns time in seconds after 1/1/1970. 167 Time format for time data string used: 168 2012-05-02 12:57:08.0 169 """ 170 171 if len(t_data.split(sep_date_clock)) != 2: 172 return -1 173 (date, clock) = t_data.split(sep_date_clock) 174 175 if (len(clock.split(sep_clock)) == 3) & (len(date.split(sep_date)) == 3): 176 177 (year_str, month_str, day_str) = date.split(sep_date) 178 # print ' year_str,month_str,day_str',year_str,month_str,day_str 179 (hours_str, minutes_str, seconds_str) = clock.split(sep_clock) 180 # print ' hours_str,minutes_str,seconds_str',hours_str,minutes_str,seconds_str 181 182 t = time.mktime((int(year_str), int(month_str), int(day_str), 183 int(hours_str), int(minutes_str), int(float(seconds_str)), -1, -1, -1)) 184 185 # print 'calc_seconds',t 186 # print ' t_data' 187 # print ' tupel',int(year_str),int(month_str),int(day_str), int(hours_str),int(minutes_str),int(float(seconds_str)),0,0,0 188 if is_float: 189 return t 190 else: 191 return int(t) 192 else: 193 return -1 194 195 196def get_routelinestring(route, edges): 197 # print 'get_routelinestring' 198 # TODO: we could make the np.sum of shapes if shapes where lists 199 shape = [] 200 for id_edge in route: 201 # print ' ',edges.shapes[id_edge ],type(edges.shapes[id_edge ]) 202 shape += list(edges.shapes[id_edge]) 203 # print ' ',shape 204 205 return LineString(shape) 206 207 208def get_boundary(coords): 209 # print 'get_boundary',len(coords),coords.shape 210 # print ' coords',coords 211 if len(coords) == 0: 212 return [0, 0, 0, 0] 213 else: 214 x_min, y_min = coords[:, :2].min(0) 215 x_max, y_max = coords[:, :2].max(0) 216 217 return [x_min, y_min, x_max, y_max] 218 219 220class BirgilMatcher(Process): 221 def __init__(self, ident, mapmatching, logger=None, **kwargs): 222 print 'BirgilMatcher.__init__' 223 224 # TODO: let this be independent, link to it or child?? 225 226 self._init_common(ident, 227 parent=mapmatching, 228 name='Birgillito Map matching', 229 logger=logger, 230 info='Birgillito Map matching.', 231 ) 232 233 attrsman = self.set_attrsman(cm.Attrsman(self)) 234 235 self.width_buffer_max = attrsman.add(cm.AttrConf('width_buffer_max', kwargs.get('width_buffer_max', 40.0), 236 groupnames=['options'], 237 perm='rw', 238 name='Max. buffer width', 239 unit='m', 240 info='GPS points are only valid if they are within the given maximum buffer width distant from a network edge.', 241 )) 242 243 self.n_points_min = attrsman.add(cm.AttrConf('n_points_min', kwargs.get('n_points_min', 5), 244 groupnames=['options'], 245 perm='rw', 246 name='Min. point number', 247 info='Minimum number of valid GPS points. Only if this minimum number is reached, a map-matching attempt is performed.', 248 )) 249 250 # self.dist_min = attrsman.add(cm.AttrConf( 'dist_min',kwargs.get('dist_min',3.0), 251 # groupnames = ['options'], 252 # name = 'Min. dist', 253 # unit = 'm', 254 # info = 'Minimum distance used in the calculation of the edge cost function.', 255 # )) 256 257 self.weight_cumlength = attrsman.add(cm.AttrConf('weight_cumlength', kwargs.get('weight_cumlength', 0.01), 258 groupnames=['options'], 259 name='Cumlength weight', 260 info='Cost function weight of cumulative length.', 261 )) 262 263 self.weight_angle = attrsman.add(cm.AttrConf('weight_angle', kwargs.get('weight_angle', 20.0), 264 groupnames=['options'], 265 name='Angle weight', 266 info='Cost function weight of angular coincidence.', 267 )) 268 269 self.weight_access = attrsman.add(cm.AttrConf('weight_access', kwargs.get('weight_access', 5.0), 270 groupnames=['options'], 271 name='Access weight', 272 info='Cost function weight of access level for matched mode.', 273 )) 274 275 self.n_routes_follow = attrsman.add(cm.AttrConf('n_routes_follow', kwargs.get('n_routes_follow', 20), 276 groupnames=['options'], 277 name='Followed routes', 278 info='Number of routes which are followed in parallel.', 279 )) 280 281 # print ' color_route',kwargs.get('color_route',COLOR_MATCHED_ROUTE),COLOR_MATCHED_ROUTE 282 self.color_route = attrsman.add(cm.AttrConf('color_route', kwargs.get('color_route', COLOR_MATCHED_ROUTE.copy()), 283 groupnames=['options'], 284 perm='wr', 285 metatype='color', 286 name='Route color', 287 info='Color of matched routes.', 288 )) 289 290 def do(self): 291 logger = self.get_logger() 292 timeconst = 0.95 293 294 trips = self.parent.trips 295 #routes = trips.get_routes() 296 edges = self.get_edges() 297 vtypes = self.parent.get_scenario().demand.vtypes 298 299 fstar = edges.get_fstar(is_return_arrays=True, is_ignor_connections=True) 300 times = edges.get_times(id_mode=2, is_check_lanes=False, speed_max=5.555) 301 ids_trip = trips.get_ids_selected() 302 303 ids_mode = vtypes.ids_mode[trips.ids_vtype[ids_trip]] 304 305 n_trips = len(ids_trip) 306 logger.w('Start mapmatching of %d GPS traces with Birgillito method' % n_trips) 307 308 distancesmap = self.parent.get_distancesmap() 309 accesslevelsmap = self.parent.get_accesslevelsmap() 310 311 n_trip_matched = 0 312 time_match_trace_av = 3.0 # initial guess of match time 313 314 # ,vtypes.speed_max[ids_vtype] 315 for id_trip, ids_point, id_mode in zip(ids_trip, trips.ids_points[ids_trip], ids_mode): 316 tick_before = time.time() 317 route, length_route, length_route_mixed, length_route_exclusive, duration_gps, lengthindex, err_dist, t_match, ids_point_edgeend, is_connected = \ 318 self.match_trip_birgil(id_trip, ids_point, fstar, distancesmap[id_mode], accesslevelsmap[id_mode]) 319 320 trips.set_matched_route(id_trip, route, 321 length_route, 322 length_route_mixed, 323 length_route_exclusive, 324 duration_gps, 325 lengthindex, 326 err_dist, 327 t_match, 328 is_connected=is_connected, 329 ids_point_edgeend=ids_point_edgeend) 330 n_trip_matched += 1 331 332 time_match_trace = time.time()-tick_before 333 334 time_match_trace_av = timeconst*time_match_trace_av + (1.0-timeconst)*time_match_trace 335 time_end_est = (n_trips-n_trip_matched)*time_match_trace_av 336 337 progress = 100.0*n_trip_matched/float(n_trips) 338 logger.w("Matched %d/%d traces, %.2f%% comleted. Avg match time = %.2fs, Terminated in %.1fh" % 339 (n_trip_matched, n_trips, progress, time_match_trace_av, float(time_end_est)/3600.0), key='message') 340 logger.w(progress, key='progress') 341 return True 342 343 def get_edges(self): 344 return self.parent.get_scenario().net.edges 345 346 def match_trip_birgil(self, id_trip, ids_point, fstar, costs, accesslevels): 347 # TODO: record time intervals 348 # calculate initial and final position on edge to get more precise 349 # triplength 350 print 79*'=' 351 print 'match_trip_birgil', id_trip 352 tick = time.time() 353 routes = [] 354 route = None 355 route_mindist = None 356 intervals_route = [] 357 length_route = -1.0 358 length_bikeway = -1.0 359 length_mindist = -1.0 360 matchindex = -1.0 361 lengthindex = -1.0 362 err_dist = -1.0 363 err_dist_alg = -1.0 364 t_match = -1.0 365 duration_gps = -1.0 366 duration_est = -1.0 367 368 points = self.parent.points 369 #trips = self.parent.trips 370 #ids_point = trips.ids_points[id_trip] 371 #pointset = self.pointsets.get(id_trip) 372 373 # create a multi point object with points of traces 374 # should no longer be necessary 375 #tracepoints = MultiPoint(pointset.get_coords().tolist()) 376 377 # make a array with time stamps of all points 378 pointtimes = points.timestamps[ids_point] 379 # segind_to_id_edge = self._segind_to_id_edge #<<<<<<<<<<< 380 coords = points.coords[ids_point][:, :2] 381 382 x1, y1, x2, y2 = self.parent.get_segvertices_xy() 383 edges = self.get_edges() 384 get_ids_edge_from_inds_seg = edges.get_ids_edge_from_inds_seg 385 get_dist_point_to_edge = edges.get_dist_point_to_edge 386 #edgehit_counts = np.zeros(len(self._net.getEdges()),int) 387 # segind_to_id_edge = self._segind_to_id_edge 388 # for p in pointset.get_coords(): 389 # print ' ',p 390 # hitinds = get_dist_point_to_segs(p,self._x1,self._y1,self._x2,self._y2, is_ending=True)< self.width_buffer**2 391 # edgehit_counts[segind_to_id_edge[hitinds]]+= 1 392 393 # --------------------------------------------------------------------- 394 # 1. initialization 395 396 # Set of initial edges 397 398 # create a list with lists for each point 399 # Each list contans the edges, where the point is in the edge buffer 400 #edges_containing_point = np.zeros(len(ids_points), object) 401 #edgedists_to_point = np.zeros(len(ids_points), object) 402 403 ids_edge_initial = [] 404 ids_edge_final = [] 405 dists_initial = [] 406 n_points = len(ids_point) 407 ind_point_initial = -1 408 ind_point_final = -1 409 t_point_initial = -1 410 t_point_final = -1 411 412 # print ' search initial edges' 413 ind_point = 0 414 for p in coords: 415 dists2 = get_dist_point_to_segs(p, x1, y1, x2, y2) 416 inds_hit = np.flatnonzero(dists2 < self.width_buffer_max**2) 417 # print ' id_point,inds_hit',ids_point[ind_point],inds_hit 418 #ids_edge = get_ids_edge_from_inds_seg(inds_hit) 419 420 if len(inds_hit) > 0: 421 if ind_point_initial < 0: 422 # print ' inds_hit',ind_point,inds_hit 423 ids_edge_initial = set(get_ids_edge_from_inds_seg(inds_hit)) 424 # print ' ids_edge_initial',ids_edge_initial 425 #dists_initial = np.sqrt(dists2[inds_hit]) 426 ind_point_initial = ind_point 427 t_point_initial = pointtimes[ind_point] 428 # print ' ind_point, inds_hit, ind_point_initial',ind_point,inds_hit,ind_point_initial,ids_edge_initial 429 else: 430 ids_edge_final = set(get_ids_edge_from_inds_seg(inds_hit)) 431 # print ' ids_edge_final',ids_edge_final 432 ind_point_final = ind_point 433 t_point_final = pointtimes[ind_point] 434 # print ' ind_point, inds_hit, ind_point_final',ind_point,inds_hit,ind_point_initial,ids_edge_final 435 436 ind_point += 1 437 438 n_points_eff = ind_point_final - ind_point_initial 439 440 duration_gps = pointtimes[ind_point_final] - pointtimes[ind_point_initial] 441 442 # if self._logger: 443 # self._logger.w( '>>match_trip_birgil : n_points_eff=%d, len(ids_edge_initial)=%d,len(ids_edge_final)=%d'%(n_points_eff, len(ids_edge_initial),len(ids_edge_final)) ) 444 # print ' completed init:' 445 print ' ids_edge_initial', ids_edge_initial 446 print ' ids_edge_final', ids_edge_final 447 448 # print ' ind_point_initial,ind_point_final,n_points_eff',ind_point_initial,ind_point_final,n_points_eff 449 print ' id_point_initial=%d,id_point_final=%d,n_points_eff=%d' % ( 450 ids_point[ind_point_initial], ids_point[ind_point_final], n_points_eff) 451 if (ind_point_initial < 0) | (ind_point_final < 0) | (n_points_eff < self.n_points_min): 452 print 'ABOARD: insufficient valid points' 453 return [], 0.0, 0.0, -1.0, -1.0, -1.0, -1.0, 0.0, [], False 454 455 # print ' coords',coords 456 # create initial routeset 457 routelist = [] 458 459 #id_edge_unique = [] 460 for id_edge in ids_edge_initial: 461 462 cost0 = get_dist_point_to_edge(coords[ind_point_initial], id_edge) 463 464 # print ' coords of initial point:',coords[ind_point_initial] 465 # print ' cost0, id_edge',cost0, id_edge 466 467 #get_ind_seg_from_id_edge(self, id_edge) 468 469 length_edge = edges.lengths[id_edge] 470 accesslevel = accesslevels[id_edge] 471 cost_tot = cost0+self.weight_cumlength * length_edge - self.weight_access * accesslevel 472 routelist.append([cost_tot, cost0, 0.0, length_edge, accesslevel, 473 length_edge, [id_edge], [ids_point[ind_point_initial]]]) 474 475 # print ' initial routelist',routelist 476 477 # --------------------------------------------------------------------- 478 # 2. main loop through rest of the points 479 480 # for i in xrange(ind_point+1, n_points):#coords[ind_point+1:]: 481 #is_connected = True 482 ind_point = ind_point_initial+1 483 length_gps = 0.0 484 while (ind_point < ind_point_final): # & is_connected: 485 point = coords[ind_point] 486 delta_point = point-coords[ind_point-1] 487 dist_interpoint = np.sqrt(np.sum(delta_point**2)) 488 phi_point = np.arctan2(delta_point[1], delta_point[0]) 489 length_gps += dist_interpoint 490 491 # print 79*'_' 492 # print ' check ID point %d, dist_interpoint=%.2fm, length_gps=%.2fm, phi_point %d deg'%(ids_point[ind_point],dist_interpoint,length_gps,phi_point/np.pi*180) 493 494 routelist_new = [] 495 ind_route = 0 496 for routeinfo in routelist: 497 costs_tot, cost, length_partial, length_cum, accesslevel, length_edge, ids_edge, ids_point_edgeend = routeinfo 498 499 if len(ids_edge) == 0: 500 break 501 502 length_partial += dist_interpoint 503 id_edge_last = ids_edge[-1] 504 # minimum distance point-edge 505 dist_point_edge = get_dist_point_to_edge(point, id_edge_last, 506 is_detect_initial=False, 507 is_detect_final=True,) 508 #dist_point_edge = self.get_dist_point_edge(coords[ind_point], id_edge_last, is_detect_final = True) 509 # if dist_point_edge is not a number (nan) the point is outside projection of edge 510 511 # print 79*'-' 512 # print ' route ',ind_route,'costs_tot',costs_tot,'dist_point_edge',dist_point_edge, len(ids_edge),id_edge_last 513 # print ' cost= %.3f, length_cum=%.3f'%(cost,length_cum,) 514 # print ' Xost= %.3f, Xength_cum=%.3f'%(cost,self.weight_cumlength *length_cum,) 515 # print ' ids_edge',ids_edge 516 # if length_partial > self.alpha * length_edge: 517 if (np.isnan(dist_point_edge)) | (dist_point_edge > self.width_buffer_max): 518 # point is beyond edge 519 520 # has reached end of edge 521 length_partial = length_partial-length_edge 522 523 # get FSTAR 524 # print ' fstar',id_edge_last,fstar[id_edge_last] 525 ids_edge_next_all = fstar[id_edge_last] 526 527 # filter allowed edges, by verifying positivness of 528 # travel costs 529 ids_edge_next = ids_edge_next_all[costs[ids_edge_next_all] >= 0] 530 # print ' parse ids_edge_next',ids_edge_next 531 532 if len(ids_edge_next) == 0: 533 # route not connected 534 cost_edge = np.Inf # punish route with infinite costs 535 length_edge = np.Inf 536 length_cum = np.Inf 537 accesslevel = -1 538 ids_edge_new = [] 539 ids_point_edgeend_new = [] 540 else: 541 542 id_edge = ids_edge_next[0] 543 accesslevel = accesslevels[id_edge] 544 length_edge = edges.lengths[id_edge] 545 length_cum += length_edge 546 cost_edge = self._get_cost_birgil(point, id_edge, phi_point, 547 accesslevel, get_dist_point_to_edge) 548 #self.get_dist_point_edge(coords[ind_point], ind_edge) 549 ids_edge_new = ids_edge + [id_edge] 550 ids_point_edgeend_new = ids_point_edgeend + [ids_point[ind_point]] 551 # print ' add to route id_edge',id_edge,ids_edge_new 552 553 # save updated data of current route 554 cost0 = cost+cost_edge 555 cost_tot = cost0+self.weight_cumlength * length_cum 556 routeinfo[:] = cost_tot, cost0, length_partial, length_cum, accesslevel, length_edge, ids_edge_new, ids_point_edgeend_new 557 558 # add new children if forward star greater 1 559 if len(ids_edge_next) > 1: 560 for id_edge in ids_edge_next[1:]: 561 #ind_edge = self._edge_to_id_edge[edge] 562 length_edge = edges.lengths[id_edge] 563 length_cum += length_edge 564 accesslevel = accesslevels[id_edge] 565 cost_edge = self._get_cost_birgil( 566 point, id_edge, phi_point, accesslevel, get_dist_point_to_edge) 567 ids_edge_new = ids_edge + [id_edge] 568 ids_point_edgeend_new = ids_point_edgeend + [ids_point[ind_point]] 569 # print ' new route id_edge',id_edge,ids_edge_new 570 cost0 = cost+cost_edge 571 cost_tot = cost0+self.weight_cumlength * length_cum 572 routelist_new.append([cost_tot, cost0, length_partial, length_cum, 573 accesslevel, length_edge, ids_edge_new, ids_point_edgeend_new]) 574 575 else: 576 # has not reached end of current edge 577 # save updated data of current route 578 if len(ids_edge) > 0: 579 #dist += self.get_dist_point_edge(coords[ind_point], ids_edge[-1]) 580 cost += self._get_cost_birgil(point, id_edge_last, phi_point, 581 accesslevel, get_dist_point_to_edge) 582 cost_tot = cost+self.weight_cumlength * length_cum 583 routeinfo[:] = cost_tot, cost, length_partial, length_cum, accesslevel, length_edge, ids_edge, ids_point_edgeend 584 585 ind_route += 1 586 587 routelist += routelist_new 588 # print ' routelist',routelist 589 routelist.sort() 590 591 # cut list to self.n_routes_follow 592 if len(routelist) > self.n_routes_follow+1: 593 routelist = routelist[:self.n_routes_follow+1] 594 595 ind_point += 1 596 597 # recover final edge objects of winner route! 598 costs_tot, cost, length_partial, length_cum, accesslevel, length_edge, ids_edge, ids_point_edgeend = routelist[ 599 0] 600 601 # print ' ids_edge[-1]',ids_edge[-1],ids_edge[-1] in ids_edge_final 602 # print ' ids_edge_final',ids_edge_final 603 t_match = time.time() - tick 604 605 # -------------------------------------------------------------------- 606 # post matching analisis 607 print '\n'+79*'-' 608 print ' matched route:', ids_edge 609 # print ' ids_point_edgeend',ids_point_edgeend 610 route = ids_edge 611 if len(route) == 0: 612 print 'ABOARD: route contains no edges ids_edge=', ids_edge 613 return [], 0.0, 0.0, -1.0, -1.0, -1.0, -1.0, 0.0, [], False 614 615 length_route = np.sum(costs[ids_edge]) 616 length_route_mixed = 0.0 617 length_route_exclusive = 0.0 618 for id_edge, length in zip(ids_edge, costs[ids_edge]): 619 accesslevel = accesslevels[id_edge] 620 if accesslevel == 1: 621 length_route_mixed += length 622 elif accesslevel == 2: 623 length_route_exclusive += length 624 625 if length_gps > 0: 626 lengthindex = length_route/length_gps 627 else: 628 lengthindex = -1.0 629 630 if ids_edge[-1] in ids_edge_final: # dist!=np.Inf: DID WE ARRIVE? 631 print 'SUCCESS: target', ids_edge[-1], 'reached' 632 is_connected = True 633 else: 634 print 'DISCONNECTED: last matched edge', ids_edge[-1], ' did not reach final edges', ids_edge_final 635 is_connected = False 636 637 # check dist error 638 inds_point = xrange(ind_point_initial, ind_point_final) 639 n_points = len(inds_point) 640 641 if (n_points >= 2) & (len(route) > 0): 642 # print ' initialize distance error measurement',len(route) 643 dist_points_tot = 0.0 644 routestring = get_routelinestring(route, edges) 645 # print ' routestring =',routestring 646 647 # print ' coords',coords[inds_point].tolist() 648 tracepoints = MultiPoint(coords[inds_point].tolist()) 649 650 # measure precision 651 #routeset = set(route) 652 #n_points_boundary = 0 653 ind_tracepoint = 0 654 for ind_point in inds_point: # xrange(n_points): 655 d = routestring.distance(tracepoints[ind_tracepoint]) 656 dist_points_tot += d 657 # print ' v distance measurement',d,tracepoints[ind_tracepoint],coords[ind_point]#,n_points#,n_points_eff 658 659 ind_tracepoint += 1 660 661 err_dist = dist_points_tot/float(n_points) 662 663 # print ' check',(lengthindex<self.lengthindex_max),(lengthindex >= self.lengthindex_min),(duration_gps>self.duration_min),(length_route>self.dist_min),(len(route)>0) 664 # print ' twice',(lengthindex<self.lengthindex_max)&(lengthindex >= self.lengthindex_min)&(duration_gps>self.duration_min)&(length_route>self.dist_min)&(len(route)>0) 665 666 return route, length_route, length_route_mixed, length_route_exclusive, duration_gps, lengthindex, err_dist, t_match, ids_point_edgeend, is_connected 667 668 def _get_cost_birgil(self, p, id_edge, phi_point, accesslevel, get_dist_point_to_edge): 669 # print '_get_cost_birgil p, id_edge',p, id_edge 670 671 dist, segment = get_dist_point_to_edge(p, id_edge, 672 is_return_segment=True) 673 x1, y1, x2, y2 = segment 674 675 # print ' x1,y1',x1,y1 676 # print ' p',p[0],p[1] 677 # print ' x2,y2',x2,y2 678 # print ' dist',dist 679 #seginds = self._id_edge_to_seginds[ind_edge] 680 #dists2 = get_dist_point_to_segs( p, self._x1[seginds], self._y1[seginds], self._x2[seginds], self._y2[seginds]) 681 682 #ind_segind = np.argmin(dists2) 683 #segind = seginds[ind_segind] 684 #x1,y1,x2,y2 = (self._x1[segind], self._y1[segind], self._x2[segind], self._y2[segind]) 685 phi_seg = np.arctan2(y2-y1, x2-x1) 686 #dist_ps = max(dist, self.dist_min) 687 # print ' x1,y1,x2,y2',x1,y1,x2,y2 688 # print ' dist =%.1f phi_point=%.2f,phi_seg=%.2f,phi_point-phi_seg=%.2f, delta_phi=%.2f'%(dist,phi_point/np.pi*180,phi_seg/np.pi*180,(phi_point-phi_seg)/np.pi*180,np.clip(phi_point-phi_seg,-np.pi/2,np.pi/2)/np.pi*180) 689 #cost = dist_ps*np.abs(np.sin(np.abs(phi_point-phi_seg))) 690 cost_angle = np.abs(np.sin(np.clip(phi_point-phi_seg, -np.pi/2, np.pi/2))) 691 cost = dist + self.weight_angle * cost_angle - self.weight_access * accesslevel 692 693 # print ' cost_birgil=%.3f, dist=%.3f, cost_angle=%.3f, accesslevel=%d'%(cost,dist,cost_angle,accesslevel) 694 # print ' cost_birgil=%.3f, Xist=%.3f, Xost_angle=%.3f, Xccesslevel=%.3f'%(cost,dist,self.weight_angle *cost_angle,self.weight_access*accesslevel) 695 # print ' cost_birgil=',cost 696 return cost 697 698 def get_dist_point_edge(self, p, ind_edge, is_detect_final=False): 699 seginds = self._id_edge_to_seginds[ind_edge] 700 dists2 = get_dist_point_to_segs(p, self._x1[seginds], self._y1[seginds], self._x2[seginds], 701 self._y2[seginds], is_ending=True, is_detect_final=is_detect_final) 702 if is_detect_final: 703 is_final = np.isnan(dists2) 704 if np.all(is_final): # point outside final segction of edge 705 return np.nan 706 else: 707 return np.sqrt(np.min(dists2[~is_final])) 708 709 return np.sqrt(np.min(dists2)) 710 711 def get_edge_info(self, id_trip, log=None): 712 """ 713 NOT IN USE!!?? 714 """ 715 # print 'get_edge_info for trace %s with c_length=%.6f'%(id_trip,self.c_length) 716 pointset = self.pointsets.get(id_trip) 717 718 # create a multi point object with points of traces 719 # should no longer be necessary 720 #tracepoints = MultiPoint(pointset.get_coords().tolist()) 721 722 # make a array with time stamps of all points 723 pointtimes = pointset.get_times() 724 ids_points = pointset.get_ids() 725 segind_to_id_edge = self._segind_to_id_edge 726 #edgehit_counts = np.zeros(len(self._net.getEdges()),int) 727 # segind_to_id_edge = self._segind_to_id_edge 728 # for p in pointset.get_coords(): 729 # print ' ',p 730 # hitinds = get_dist_point_to_segs(p,self._x1,self._y1,self._x2,self._y2, is_ending=True)< self.width_buffer**2 731 # edgehit_counts[segind_to_id_edge[hitinds]]+= 1 732 733 # create a list with lists for each point 734 # Each list contans the edges, where the point is in the edge buffer 735 edges_containing_point = np.zeros(len(ids_points), object) 736 edgedists_to_point = np.zeros(len(ids_points), object) 737 ind_point = 0 738 for p in pointset.get_coords(): 739 dists2 = get_dist_point_to_segs(p, self._x1, self._y1, self._x2, self._y2, is_ending=True) 740 inds_hit = np.nonzero(dists2 < self.width_buffer**2) 741 edges_containing_point[ind_point] = self._edges[segind_to_id_edge[inds_hit]] 742 edgedists_to_point[ind_point] = np.sqrt(dists2[inds_hit]) 743 744 # print ' ind_point,p,inds_hit',ind_point,p,len(np.nonzero(inds_hit)[0])#,edges_containing_point[ind_point] 745 ind_point += 1 746 747 # this is a dictionary with edge instance as key and 748 # the weight as value. 749 occurrences = {} 750 for edge in self._edges: 751 occurrences[edge] = 0.0 752 753 id_mode = self.id_mode 754 755 # 2. determine part of weight inversely proportional to the number 756 # of GPS points contained in the buffer 757 ind = 0 758 time_start = +10**10 759 time_end = -10**10 760 761 ind_point_start = -1 762 ind_point_end = -1 763 intervals = {} 764 for pointedges in edges_containing_point: 765 n_edges = len(pointedges) 766 if n_edges > 0: 767 t_point = pointtimes[ind] 768 if t_point < time_start: 769 time_start = t_point 770 ind_point_start = ind 771 772 elif t_point > time_end: 773 time_end = t_point 774 ind_point_end = ind 775 776 # compute partial weight for containing GPS points in edge buffer 777 wp = 1.0/n_edges 778 779 for edge in pointedges: 780 # assign weight component to edges 781 occurrences[edge] += wp 782 783 # determine intervals per edge 784 if intervals.has_key(edge): 785 t_edge_start, t_edge_end = intervals[edge] 786 if t_point < t_edge_start: 787 t_edge_start = t_point 788 elif t_point > t_edge_end: 789 t_edge_end = t_point 790 intervals[edge] = (t_edge_start, t_edge_end) 791 792 else: 793 intervals[edge] = (t_point, t_point) 794 795 ind += 1 796 797 edges_start = set(edges_containing_point[ind_point_start]) 798 edges_end = set(edges_containing_point[ind_point_end]) 799 800 # 1. calculate length proportional edge weight 801 c_length = float(self.c_length) 802 c_bike = float(self.c_bike) 803 weights = {} 804 805 for edge in self._edges: 806 len_edge = edge.getLength() 807 p_empty = c_length*len_edge 808 809 l = len_edge 810 allowed = edge.getLanes()[0].getAllowed() 811 if len(allowed) > 0: 812 if id_mode in allowed: 813 l *= c_bike # weight for dedicated lanes 814 815 if occurrences[edge] > 0.0: 816 # compute edge length proportional weight 817 weights[edge] = l/occurrences[edge] 818 819 else: 820 weights[edge] = l/p_empty 821 822 # if self._logger: 823 # self._logger.w( ' New: duration in network %d s from %ds to %ds'%(time_end-time_start,time_start,time_end)) 824 825 #log.w( ' Check dimensions len(weights)=%d,len(intervals)=%d'%(len(weights), len(intervals))) 826 # print ' intervals',intervals 827 #log.w( ' Possible start edges') 828 # for edge in edges_start: 829 # log.w( ' %s'%edge.getID()) 830 #log.w( ' Possible end edges') 831 # for edge in edges_end: 832 # log.w( ' %s'%edge.getID()) 833 # 834 #log.w('get_edge_info done.') 835 836 #self.intervals.set(id_trip, [ time_start,time_end]) 837 return weights, edges_start, edges_end, intervals, edges_containing_point, ind_point_start, ind_point_end 838 839 840def get_colvalue(val, default=0.0): 841 842 if (len(val) > 0) & (val != 'NULL'): 843 return float(val) 844 else: 845 return default 846 847 848class FilterMixin(Process): 849 def _init_filter_preview(self): 850 attrsman = self.get_attrsman() 851 trips = self.parent.trips 852 self.filterresults = attrsman.add(cm.FuncConf('filterresults', 853 'filterpreview', # function attribute of object 854 '%d/%d' % (len(trips.get_ids_selected()), len(trips)), 855 name='Preview selected trips', 856 groupnames=['options', 'results'], 857 )) 858 859 def filterpreview(self): 860 """ 861 Previews selected trips after filtering. 862 """ 863 trips = self.parent.trips 864 n_trips = len(trips) 865 n_sel_current = len(trips.get_ids_selected()) 866 n_sel_eliminate = len(self.filter_ids()) 867 n_sel_after = n_sel_current-n_sel_eliminate 868 return '%d/%d (currently %d/%d)' % (n_sel_after, n_trips, n_sel_current, n_trips) 869 870 def _init_traceoptions(self, **kwargs): 871 attrsman = self.get_attrsman() 872 self.dist_trip_min = attrsman.add(cm.AttrConf('dist_trip_min', kwargs.get('dist_trip_min', 100.0), 873 groupnames=['options'], 874 perm='rw', 875 name='Min. trip distance', 876 unit='m', 877 info='Minimum distance of one trip. Shorter trips will not be selected.', 878 )) 879 880 self.dist_trip_max = attrsman.add(cm.AttrConf('dist_trip_max', kwargs.get('dist_trip_max', 25000.0), 881 groupnames=['options'], 882 perm='rw', 883 name='Max. trip distance', 884 unit='m', 885 info='Maximum distance of one trip. Shorter trips will not be selected.', 886 )) 887 888 self.duration_trip_min = attrsman.add(cm.AttrConf('duration_trip_min', kwargs.get('duration_trip_min', 30.0), 889 groupnames=['options'], 890 perm='rw', 891 name='Min. trip duration', 892 unit='s', 893 info='Minimum duration of one trip. Trips with shorter duration will not be selected.', 894 )) 895 896 self.duration_trip_max = attrsman.add(cm.AttrConf('duration_trip_max', kwargs.get('duration_trip_max', 999999.0), 897 groupnames=['options'], 898 perm='rw', 899 name='Max. trip duration', 900 unit='s', 901 info='Maximum duration of one trip. Trips with longer duration will not be selected.', 902 )) 903 904 self.speed_trip_min = attrsman.add(cm.AttrConf('speed_trip_min', kwargs.get('speed_trip_min', 1.0), 905 groupnames=['options'], 906 perm='rw', 907 name='Min. av. trip speed', 908 unit='m/s', 909 info='Minimum average trip speed. Trips with lower average speed will not be selected.', 910 )) 911 912 self.speed_trip_max = attrsman.add(cm.AttrConf('speed_trip_max', kwargs.get('speed_trip_max', 14.0), 913 groupnames=['options'], 914 perm='rw', 915 name='Max. av. trip speed', 916 unit='m/s', 917 info='Maximum average trip speed. Trips with higher average speed will not be selected.', 918 )) 919 920 def _init_filter_time(self, **kwargs): 921 attrsman = self.get_attrsman() 922 923 self.hour_from_morning = attrsman.add(cm.AttrConf('hour_from_morning', kwargs.get('hour_from_morning', 0), 924 groupnames=['options'], 925 perm='rw', 926 name='From morning hour', 927 unit='h', 928 info='Keep only morning trips which start after this hour.', 929 )) 930 931 self.hour_to_morning = attrsman.add(cm.AttrConf('hour_to_morning', kwargs.get('hour_to_morning', 12), 932 groupnames=['options'], 933 perm='rw', 934 name='To morning hour', 935 unit='h', 936 info='Keep only morning trips which start before this hour.', 937 )) 938 939 self.hour_from_evening = attrsman.add(cm.AttrConf('hour_from_evening', kwargs.get('hour_from_evening', 12), 940 groupnames=['options'], 941 perm='rw', 942 name='From evening hour', 943 unit='h', 944 info='Keep only evening trips which start after this hour.', 945 )) 946 947 self.hour_to_evening = attrsman.add(cm.AttrConf('hour_to_evening', kwargs.get('hour_to_evening', 24), 948 groupnames=['options'], 949 perm='rw', 950 name='To evening hour', 951 unit='h', 952 info='Keep only evening trips which start before this hour.', 953 )) 954 955 self.weekdays = attrsman.add(cm.AttrConf('weekdays', kwargs.get('weekdays', WEEKDAYCHOICES['all']), 956 groupnames=['options'], 957 name='Weekdays', 958 choices=WEEKDAYCHOICES, 959 info='Keep only trips at the given weekdays.', 960 )) 961 962 def filter_time(self, timestamps): 963 """ 964 timestamps is an array with timestamps. 965 Function returns a binary array, with a True value for each 966 time stamp that does NOT SATISFY the specified time constrants. 967 """ 968 # print 'filter_time' 969 # print ' self.hour_from_morning,self.hour_to_morning',self.hour_from_morning,self.hour_to_morning 970 localtime = time.localtime 971 inds_elim = np.zeros(len(timestamps), dtype=np.bool) 972 i = 0 973 for timestamp in timestamps: 974 975 dt = localtime(timestamp) 976 is_keep = dt.tm_wday in self.weekdays 977 # print ' dt.tm_wday,self.weekdays',dt.tm_wday,self.weekdays 978 h = dt.tm_hour 979 is_keep &= (h > self.hour_from_morning) & (h < self.hour_to_morning)\ 980 | (h > self.hour_from_evening) & (h < self.hour_to_evening) 981 982 # print ' is_keep,w,h=',is_keep,dt.tm_wday,h 983 inds_elim[i] = not is_keep 984 i += 1 985 986 return inds_elim 987 988 def is_timestamp_ok(self, timestamp): 989 # if is_daytimesaving: 990 dt = time.localtime(timestamp) 991 # else: 992 # dt = time.gmtime(timestamp) 993 is_ok = dt.tm_wday in self.weekdays 994 h = dt.tm_hour 995 # print 'is_timestamp_ok h,dt.tm_wday',h,dt.tm_wday,is_ok, 996 997 is_ok &= (h >= self.hour_from_morning) & (h < self.hour_to_morning)\ 998 | (h >= self.hour_from_evening) & (h < self.hour_to_evening) 999 1000 # print is_ok 1001 return is_ok 1002 1003 def filter_ids(self): 1004 """ 1005 Returns an array of ids to be eliminated or deselected. 1006 To be overridden 1007 """ 1008 return [] 1009 1010 1011class PostMatchfilter(FilterMixin): 1012 def __init__(self, mapmatching, logger=None, **kwargs): 1013 print 'PostMatchfilter.__init__' 1014 self._init_common('postmatchfilter', 1015 parent=mapmatching, 1016 name='Post matchfilter', 1017 logger=logger, 1018 info='Removes matched tripe with defined characteristics from current selection.', 1019 ) 1020 1021 attrsman = self.set_attrsman(cm.Attrsman(self)) 1022 1023 info_lengthindex = "Length index is length of matched route divided by length of line interpolated GPS points in percent." 1024 self.lengthindex_min = attrsman.add(cm.AttrConf('lengthindex_min', kwargs.get('lengthindex_min', 80.0), 1025 groupnames=['options'], 1026 name='Min. length index', 1027 unit='%', 1028 info='Minimum allowed length index.'+info_lengthindex, 1029 )) 1030 self.lengthindex_max = attrsman.add(cm.AttrConf('lengthindex_max', kwargs.get('lengthindex_max', 110.0), 1031 groupnames=['options'], 1032 name='Min. length index', 1033 unit='%', 1034 info='Maximum allowed length index '+info_lengthindex, 1035 )) 1036 1037 info_error_dist = 'The distance error is the average distance between the GPS points and the matched route.' 1038 self.error_dist_max = attrsman.add(cm.AttrConf('error_dist_max', kwargs.get('error_dist_max', 10000.0), 1039 groupnames=['options'], 1040 name='Max. distance err.', 1041 unit='mm', 1042 info='Maximum allowed distance error. '+info_error_dist, 1043 )) 1044 1045 self._init_filter_time(**kwargs) 1046 # self._init_traceoptions(**kwargs) 1047 self.speed_trip_min = attrsman.add(cm.AttrConf('speed_trip_min', kwargs.get('speed_trip_min', 1.0), 1048 groupnames=['options'], 1049 perm='rw', 1050 name='Min. av. trip speed', 1051 unit='m/s', 1052 info='Minimum average trip speed. Trips with lower average speed will not be selected.', 1053 )) 1054 1055 self.speed_trip_max = attrsman.add(cm.AttrConf('speed_trip_max', kwargs.get('speed_trip_max', 14.0), 1056 groupnames=['options'], 1057 perm='rw', 1058 name='Max. av. trip speed', 1059 unit='m/s', 1060 info='Maximum average trip speed. Trips with higher average speed will not be selected.', 1061 )) 1062 1063 self._init_filter_preview() 1064 1065 def filter_ids(self): 1066 """ 1067 Returns an array of ids to be eliminated or deselected. 1068 """ 1069 # print 'filter_ids' 1070 trips = self.parent.trips 1071 ids_selected = trips.get_ids_selected() 1072 inds_eliminate = np.logical_or( 1073 trips.lengthindexes[ids_selected] < self.lengthindex_min, 1074 trips.lengthindexes[ids_selected] > self.lengthindex_max, 1075 trips.errors_dist[ids_selected] > self.error_dist_max, 1076 # (trips.lengths_route_matched[ids_selected]<1.0), # too many args?? 1077 ) 1078 1079 inds_eliminate = np.logical_or(inds_eliminate, 1080 trips.lengths_route_matched[ids_selected] < 1.0 1081 ) 1082 1083 inds_eliminate = np.logical_or(inds_eliminate, 1084 trips.speeds_average[ids_selected] < self.speed_trip_min, 1085 trips.speeds_average[ids_selected] > self.speed_trip_max 1086 ) 1087 1088 # dist > self.dist_trip_min)\ 1089 # & (dist < self.dist_trip_max)\ 1090 # & (duration > self.duration_trip_min)\ 1091 # & (speed_av > self.speed_trip_min)\ 1092 # & (speed_av < self.speed_trip_max) 1093 1094 # print ' lengths_route_matched',trips.lengths_route_matched[ids_selected] 1095 # print ' lengthindexes',self.lengthindex_min,self.lengthindex_max,trips.lengthindexes[ids_selected] 1096 # print ' errors_dist',self.error_dist_max,trips.errors_dist[ids_selected] 1097 # print ' lengthindex_min',trips.lengthindexes[ids_selected]<self.lengthindex_min 1098 # print ' lengthindex_max',trips.lengthindexes[ids_selected]>self.lengthindex_max 1099 # print ' lengths_route_matched',trips.errors_dist[ids_selected]>self.error_dist_max 1100 # print ' inds_eliminate',inds_eliminate 1101 1102 inds_eliminate = np.logical_or(inds_eliminate, self.filter_time(trips.timestamps[ids_selected])) 1103 # print ' inds_eliminate',inds_eliminate 1104 return ids_selected[inds_eliminate] 1105 1106 def do(self): 1107 1108 # execute filtering 1109 self.parent.trips.are_selected[self.filter_ids()] = False 1110 1111 return True 1112 1113 1114class TripGeomfilter(FilterMixin): 1115 def __init__(self, mapmatching, logger=None, **kwargs): 1116 print 'TripGeomfilter.__init__' 1117 self._init_common('tripGeomfilter', 1118 parent=mapmatching, 1119 name='Geometry trip filter', 1120 logger=logger, 1121 info='Removes trips with defined geometric characteristics from current selection.', 1122 ) 1123 1124 attrsman = self.set_attrsman(cm.Attrsman(self)) 1125 1126 self.dist_point_max = attrsman.add(cm.AttrConf('dist_point_max', kwargs.get('dist_point_max', 1000.0), 1127 groupnames=['options'], 1128 perm='rw', 1129 name='Max. point dist.', 1130 unit='m', 1131 info='Keep only traces where the distance between all successive points is below this maximal distance.', 1132 )) 1133 1134 self.duration_point_max = attrsman.add(cm.AttrConf('duration_point_max', kwargs.get('duration_point_max', 300.0), 1135 groupnames=['options'], 1136 perm='rw', 1137 name='Max. point duration.', 1138 unit='s', 1139 info='Keep only traces where the duration between all successive points is below this maximal duration.', 1140 )) 1141 1142 self.const_return_max = attrsman.add(cm.AttrConf('const_return_max', kwargs.get('const_return_max', 0.3), 1143 groupnames=['options'], 1144 perm='rw', 1145 name='Max. return const', 1146 info='Keep only traces where the user is not returning more than a share of this constant from the maximum (line of site) distance from the origin.', 1147 )) 1148 1149 self.is_eliminate_close_points = attrsman.add(cm.AttrConf('is_eliminate_close_points', kwargs.get('is_eliminate_close_points', False), 1150 groupnames=['options'], 1151 perm='rw', 1152 name='Eliminate close points', 1153 info='Eliminate points with a distance less then the minimum distance.', 1154 )) 1155 1156 self.dist_point_min_extr = attrsman.add(cm.AttrConf('dist_point_min_extr', kwargs.get('dist_point_min_extr', 9.0), 1157 groupnames=['options'], 1158 perm='rw', 1159 name='Min. extr. point dist.', 1160 unit='m', 1161 info='Keep only the point where the distance to the point at both extremities is more than a minimum distance.', 1162 )) 1163 1164 self.dist_point_min_inter = attrsman.add(cm.AttrConf('dist_point_min_inter', kwargs.get('dist_point_min_inter', 2.0), 1165 groupnames=['options'], 1166 perm='rw', 1167 name='Min. int. point dist.', 1168 unit='m', 1169 info='Keep only the point where the distance to the previous point is more than a minimum distance.', 1170 )) 1171 1172 self.speed_max = attrsman.add(cm.AttrConf('speed_max', kwargs.get('speed_max', 50.0/3.6), 1173 groupnames=['options'], 1174 perm='rw', 1175 name='Max. speed', 1176 unit='m', 1177 info='Keep only traces where this maximum speed is not reached. Maximum speed is reached if a consecutive number of Max. overspeed points is reached.', 1178 )) 1179 1180 self.n_overspeed_max = attrsman.add(cm.AttrConf('n_overspeed_max', kwargs.get('n_overspeed_max', 3), 1181 groupnames=['options'], 1182 perm='rw', 1183 name='Max. overspeed points', 1184 info='Trace gets eliminated if this consecutive number of points have speeds over the set maximum speed.', 1185 )) 1186 1187 self._init_filter_preview() 1188 1189 def do(self): 1190 1191 # execute filtering 1192 self.parent.trips.are_selected[self.filter_ids()] = False 1193 return True 1194 1195 def filter_ids(self): 1196 """ 1197 Returns an array of ids to be eliminated or deselected. 1198 """ 1199 c_cutoff = 1.0 - self.const_return_max 1200 print 'TripGeomfilter.do c_cutoff', c_cutoff 1201 dist_point_max = self.dist_point_max 1202 dist_point_min = self.dist_point_min_extr 1203 dist_point_min_inter = self.dist_point_min_inter 1204 duration_point_max = self.duration_point_max 1205 trips = self.parent.trips 1206 points = self.parent.points 1207 1208 ids_trips = trips.get_ids_selected() 1209 1210 ids_points = trips.ids_points[ids_trips] 1211 # print ' ids_trips',ids_trips 1212 # print ' ids_points',ids_points 1213 1214 intersects_boundaries = self.parent.get_scenario().net.intersects_boundaries 1215 1216 inds_elim = np.zeros(len(ids_trips), dtype=np.bool) 1217 j = 0 1218 ids_point_elim_perm = [] 1219 for id_trip, ids_point in zip(ids_trips, ids_points): 1220 1221 coords = points.coords[ids_point] 1222 times = points.timestamps[ids_point] 1223 # print 79*'-' 1224 # print ' check id_trip ',id_trip 1225 # print ' ids_point', ids_point 1226 # print ' times',times 1227 # print ' coords', coords 1228 # print ' duration_point_max',duration_point_max 1229 #dist = pointset.get_distance() 1230 1231 if ids_point is None: 1232 # this happens if the points of a trip in the workout file 1233 # have not been imported for some reason 1234 is_eliminate = True 1235 1236 elif not intersects_boundaries(get_boundary(coords)): 1237 is_eliminate = True 1238 1239 elif np.any(times < 0): 1240 is_eliminate = True 1241 else: 1242 dist_max = 0.0 1243 is_eliminate = False 1244 i = 0 1245 n = len(times) 1246 x, y, z = coords[0] 1247 ids_point_elim = [] 1248 coord_last = coords[0] 1249 coord_start = coords[0] 1250 coord_end = coords[-1] 1251 1252 while (not is_eliminate) & (i < (n-1)): 1253 i += 1 1254 1255 dist_point = np.sqrt((coords[i, 0]-coords[i-1, 0])**2 1256 + (coords[i, 1]-coords[i-1, 1])**2) 1257 # print ' ',times[i]-times[i-1],dist_point,coords[i,:2],coords[i-1,:2] 1258 if self.is_eliminate_close_points: 1259 1260 dist_start = np.sqrt((coords[i, 0]-coord_start[0])**2 1261 + (coords[i, 1]-coord_start[1])**2) 1262 1263 if dist_start < dist_point_min: 1264 # print ' eliminate',ids_point[i], dist_check 1265 ids_point_elim.append(ids_point[i]) 1266 else: 1267 dist_end = np.sqrt((coords[i, 0]-coord_end[0])**2 1268 + (coords[i, 1]-coord_end[1])**2) 1269 1270 if dist_end < dist_point_min: 1271 # print ' eliminate',ids_point[i], dist_check 1272 ids_point_elim.append(ids_point[i]) 1273 else: 1274 1275 dist_check = np.sqrt((coords[i, 0]-coord_last[0])**2 1276 + (coords[i, 1]-coord_last[1])**2) 1277 if dist_check < dist_point_min_inter: 1278 ids_point_elim.append(ids_point[i]) 1279 else: 1280 coord_last = coords[i] 1281 1282 if dist_point > dist_point_max: 1283 is_eliminate = True 1284 1285 # print ' times[i]-times[i-1]',times[i]-times[i-1] 1286 time_delta = times[i]-times[i-1] 1287 if time_delta > duration_point_max: 1288 is_eliminate = True 1289 1290 # test for return distance 1291 d = np.sqrt((x-coords[i, 0])**2 + (y-coords[i, 1])**2) 1292 if d > dist_max: 1293 dist_max = d 1294 1295 elif d < c_cutoff*dist_max: 1296 is_eliminate = True 1297 1298 if self.is_eliminate_close_points: 1299 if len(ids_point_elim) > 0: 1300 1301 ids_point2 = list(ids_point) 1302 # print ' before elim ids_point',ids_point2 1303 # print ' eliminate',ids_point_elim 1304 for id_point in ids_point_elim: 1305 ids_point2.remove(id_point) 1306 1307 trips.ids_points[id_trip] = ids_point2 1308 ids_point_elim_perm += ids_point_elim 1309 # print ' after elim ids_point',trips.ids_points[id_trip] 1310 1311 inds_elim[j] = is_eliminate 1312 j += 1 1313 1314 if len(ids_point_elim_perm) > 0: 1315 print ' permanently eliminate %d GPS points' % (len(ids_point_elim_perm)) 1316 points.del_rows(ids_point_elim_perm) 1317 1318 return ids_trips[inds_elim] 1319 1320 1321class EccTracesImporter(FilterMixin): 1322 def __init__(self, mapmatching, logger=None, **kwargs): 1323 print 'EccTracesImporter.__init__', mapmatching.get_ident() 1324 self._init_common('traceimporter', 1325 parent=mapmatching, 1326 name='ECC Trace Importer', 1327 logger=logger, 1328 info='Import workouts and GPS points of a European cycling challange.', 1329 ) 1330 1331 attrsman = self.set_attrsman(cm.Attrsman(self)) 1332 1333 scenario = mapmatching.get_scenario() 1334 rootfilepath = scenario.get_rootfilepath() 1335 1336 # here we ged classes not vehicle type 1337 # specific vehicle type within a class will be generated later 1338 modechoices = scenario.net.modes.names.get_indexmap() 1339 1340 # print ' modechoices',modechoices 1341 self.id_mode = attrsman.add(am.AttrConf('id_mode', modechoices['bicycle'], 1342 groupnames=['options'], 1343 choices=modechoices, 1344 name='Mode', 1345 info='Transport mode to be matched.', 1346 )) 1347 1348 self.workoutsfilepath = attrsman.add( 1349 cm.AttrConf('workoutsfilepath', kwargs.get('workoutsfilepath', rootfilepath+'.workouts.csv'), 1350 groupnames=['options'], 1351 perm='rw', 1352 name='Workout file', 1353 wildcards='CSV file (*.csv)|*.csv', 1354 metatype='filepath', 1355 info="""CSV text file with workout database.""", 1356 )) 1357 1358 self.pointsfilepath = attrsman.add(cm.AttrConf('pointsfilepath', kwargs.get('pointsfilepath', rootfilepath+'.points.csv'), 1359 groupnames=['options'], 1360 perm='rw', 1361 name='Points file', 1362 wildcards='CSV file (*.csv)|*.csv', 1363 metatype='filepath', 1364 info="CSV text file with GPS point database.", 1365 )) 1366 1367 self.year = attrsman.add(cm.AttrConf('year', kwargs.get('year', 2014), 1368 groupnames=['options'], 1369 choices={'2013': 2013, '2014': 2014, '2015': 2015, '2016': 2016}, 1370 perm='rw', 1371 name='Year of challange', 1372 info='Year of challange is used to identify the correct database format.', 1373 )) 1374 1375 self._init_traceoptions(**kwargs) 1376 1377 # self.sep_column_workout = attrsman.add(cm.AttrConf( 'sep_column_workout',kwargs.get('sep_column_workout',','), 1378 # groupnames = ['options'], 1379 # perm='rw', 1380 # name = 'Workoutdata seperator', 1381 # info = 'Workout column seperator of CSV file', 1382 # )) 1383 1384 # self.sep_column_points = attrsman.add(cm.AttrConf( 'sep_column_points',kwargs.get('sep_column_points',','), 1385 # groupnames = ['options'], 1386 # perm='rw', 1387 # name = 'Point data seperator', 1388 # info = 'Pointdata column seperator of CSV file', 1389 # )) 1390 1391 self._init_filter_time(**kwargs) 1392 1393 self._proj = None 1394 self._offset = None 1395 1396 def project(self, lons, lats): 1397 if self._proj is None: 1398 self._proj, self._offset = self.parent.get_proj_and_offset() 1399 x, y = self._proj(lons, lats) 1400 return np.transpose(np.concatenate(([x+self._offset[0]], [y+self._offset[1]]), axis=0)) 1401 1402 def validate_trip(self, dist, duration, speed_av=-1): 1403 if speed_av < 0: 1404 if duration > 1.0: 1405 speed_av = dist/duration 1406 else: 1407 speed_av = 0.0 1408 1409 return (dist > self.dist_trip_min)\ 1410 & (dist < self.dist_trip_max)\ 1411 & (duration > self.duration_trip_min)\ 1412 & (speed_av > self.speed_trip_min)\ 1413 & (speed_av < self.speed_trip_max) 1414 1415 def do(self): 1416 print 'TraceImporter.do' 1417 if self.year == 2014: 1418 self.import_workouts_2014() 1419 self.import_points_2014() 1420 1421 if self.year == 2015: 1422 self.import_workouts_2015() 1423 self.import_points_2015() 1424 1425 if self.year == 2016: 1426 self.import_workouts_2016() 1427 self.import_points_2016() 1428 1429 if self.year == 2013: 1430 self.import_points_2013() 1431 1432 self.parent.points.project() 1433 return True 1434 1435 def import_workouts_2016(self): 1436 # UserID TripID TimeStamp Start DT Distance ECC AvgSpeed TrackType Sex Year Profession Frequent User ZIP Source TypeOfBike TipeOfTrip Max Spd 1437 # 57249bcd88c537874f9fa1ae 57515edc88c537576ca3e16f 1464945480 2016-06-03T09:18:00.000Z 4.75 4.75 10.16 urban bicycle F 1999 Studente yes cy-web-gpx MyBike HomeToSchool 25.45 1438 1439 j_id_user, j_id_trip, j_timestamp, j_date, j_dist, j_dist_copy, j_speed_av, j_tracktype, j_sex, j_year, j_profession, j_frequent, j_zip, j_device, j_biketype, j_purpose, j_speedmax = range( 1440 17) 1441 n_cols = 17 1442 null = 'NULL' 1443 trips = self.parent.trips 1444 persons = self.parent.persons 1445 #exist_id_person_sumo = persons.ids_sumo.has_index 1446 ids_person_sumo = {} 1447 1448 #ids_trips = [] 1449 scenario = self.parent.get_scenario() 1450 1451 get_vtype_for_mode = scenario.demand.vtypes.get_vtype_for_mode 1452 id_type = get_vtype_for_mode(self.id_mode) 1453 1454 f = open(self.workoutsfilepath, 'r') 1455 if self._logger: 1456 self._logger.w('import_workouts_2016 %s' % os.path.basename(self.workoutsfilepath)) 1457 i_line = 0 1458 sep = ';' 1459 i_line = 0 1460 #self.get_logger().w(100.0*self.simtime/self.duration, key ='progress') 1461 for line in f.readlines()[1:]: 1462 # if True:#i_line>1: 1463 cols = line.split(sep) 1464 # print ' len(cols)',len(cols),n_cols 1465 # print ' cols',cols 1466 if len(cols) >= n_cols: 1467 # row is complete 1468 # print ' id_trip_sumo',cols[j_id_trip] 1469 # if cols[j_dist] != null: 1470 dist = get_colvalue(cols[j_dist])*1000.0 1471 speed_av = get_colvalue(cols[j_speed_av])/3.6 1472 if speed_av > 0: 1473 duration = dist/speed_av 1474 else: 1475 duration = 0.0 1476 1477 if self.validate_trip(dist, duration, speed_av): 1478 timestamp = get_colvalue(cols[j_timestamp]) 1479 1480 if timestamp is not None: 1481 # print ' valid time stamp',timestamp,self.is_timestamp_ok(timestamp) 1482 1483 if self.is_timestamp_ok(timestamp): 1484 id_trip = trips.make(id_sumo=cols[j_id_trip], 1485 id_vtype=id_type, 1486 timestamp=timestamp, 1487 distance_gps=dist, 1488 duration_gps=duration, 1489 speed_average=speed_av, 1490 speed_max=get_colvalue(cols[j_speedmax])/3.6, 1491 purpose=cols[j_purpose].strip(), 1492 device=cols[j_device].strip(), 1493 ) 1494 1495 # ids_trips.append(id_trip) 1496 #j_id_user, j_id_trip, j_timestamp, j_date, j_dist, j_speed_av, j_tracktype, j_sex, j_year, j_profession, j_frequent, j_zip 1497 1498 zip = cols[j_zip].strip() 1499 if zip == 'undefined': 1500 zip = '' 1501 1502 year = cols[j_year] 1503 if year.isdigit(): 1504 year_birth = int(year) 1505 else: 1506 year_birth = -1 1507 1508 id_pers = persons.make(id_sumo=cols[j_id_user].strip(), 1509 id_trip=id_trip, 1510 gender=cols[j_sex].strip(), 1511 year_birth=year_birth, 1512 occupation=cols[j_profession].strip(), 1513 is_frequent_user=cols[j_frequent].strip().lower() == 'yes', 1514 zip=zip, 1515 ) 1516 # print ' id_trip,id_trip_sumo,id_pers',id_trip,cols[j_id_trip], id_pers 1517 # print 1518 else: 1519 print 'WARNING: inconsistent number of columns (%d) in line %d, file %s' % ( 1520 len(cols), i_line, self.workoutsfilepath) 1521 print ' cols =', cols 1522 1523 i_line += 1 1524 1525 def import_points_2016(self): 1526 print 'import_points_2016' 1527 # 0 1 2 3 4 5 6 7 1528 # TripID, TimeStamp,Latitude, Longitude, Altitude, Distance, Speed, Type 1529 # 574e98c988c5378163a3e11f,1462347278,44.52606,11.27617,78,0.027255420500625783,5,<start|mid|end>, 1530 # 5741cdd388c537f10192ee97, 1463926725,44.50842,11.3604,101.0417,0.01615021486623964,3.483146,mid 1531 1532 ind_id_path = 0 1533 ind_time = 1 1534 ind_lat = 2 1535 ind_lon = 3 1536 ind_alt = 4 1537 ind_dist = 5 1538 ind_speed = 6 1539 ind_type = 7 1540 1541 n_cols = 8 1542 #TripID, TimeStamp,Date, Latitude, Longitude, Altitude, Distance, Speed, Type 1543 1544 trips = self.parent.trips 1545 points = self.parent.points 1546 1547 exist_id_trip_sumo = trips.ids_sumo.has_index 1548 get_id_trip = trips.ids_sumo.get_id_from_index 1549 1550 sep = ',' # self.sep_column_points 1551 1552 f = open(self.pointsfilepath, 'r') 1553 if self._logger: 1554 self._logger.w('import_points_2016 %s' % os.path.basename(self.pointsfilepath)) 1555 i_line = 0 1556 id_trip_sumo = None 1557 id_trip = -1 1558 is_valid_trip = False 1559 1560 n_points_imported = 0 1561 for line in f.readlines(): 1562 1563 cols = line.split(sep) 1564 # print ' len(cols)',len(cols),n_cols 1565 if len(cols) == n_cols: 1566 id_trip_sumo_current = cols[ind_id_path] 1567 # print ' id_trip_sumo_current,id_trip_sumo',id_trip_sumo_current,id_trip_sumo,is_valid_trip 1568 if id_trip_sumo_current != id_trip_sumo: 1569 # this point is part of new trip 1570 1571 if is_valid_trip: 1572 # print ' store past points for valid trip',id_trip 1573 ids_point = points.add_rows( 1574 timestamps=timestamps, 1575 ids_trip=id_trip*np.ones(len(timestamps), dtype=np.int32), 1576 longitudes=longitudes, 1577 latitudes=latitudes, 1578 altitudes=altitudes, 1579 ) 1580 1581 trips.set_points(id_trip, ids_point) 1582 # print ' timestamps',timestamps 1583 if len(timestamps) > 1: 1584 trips.durations_gps[id_trip] = timestamps[-1]-timestamps[0] 1585 # print ' durations_gps',timestamps[-1]-timestamps[0] 1586 # check if new trip is valid 1587 if exist_id_trip_sumo(id_trip_sumo_current): 1588 1589 is_valid_trip = True # start recording 1590 id_trip = get_id_trip(id_trip_sumo_current) 1591 # print ' found trip',id_trip,id_trip_sumo_current,' exisits-> record' 1592 1593 # ids_point_sumo = [] # useless? 1594 timestamps = [] 1595 ids_trip = [] 1596 longitudes = [] 1597 latitudes = [] 1598 altitudes = [] 1599 1600 else: 1601 # print ' trip',id_trip_sumo_current,'does not exisit' 1602 is_valid_trip = False 1603 id_trip = -1 1604 1605 id_trip_sumo = id_trip_sumo_current 1606 1607 if is_valid_trip: 1608 # print ' store point timestamp',cols[ind_time] 1609 # current point belongs to a valid trip 1610 # ids_point_sumo.append(cols[ind_id_point]) 1611 timestamps.append(get_colvalue(cols[ind_time])) 1612 # ids_trip.append(id_trip) 1613 longitudes.append(get_colvalue(cols[ind_lon])) 1614 latitudes.append(get_colvalue(cols[ind_lat])) 1615 altitudes.append(get_colvalue(cols[ind_alt])) 1616 1617 else: 1618 print 'WARNING: inconsistent number of columns (%d) in line %d, file %s' % ( 1619 len(cols), i_line, self.pointsfilepath) 1620 print ' cols =', cols 1621 1622 i_line += 1 1623 1624 # register points of last trip 1625 if is_valid_trip: 1626 # store past points for valid trip 1627 ids_point = points.add_rows( 1628 timestamps=timestamps, 1629 ids_trip=id_trip*np.ones(len(timestamps), dtype=np.int32), 1630 longitudes=longitudes, 1631 latitudes=latitudes, 1632 altitudes=altitudes, 1633 ) 1634 1635 trips.set_points(id_trip, ids_point) 1636 1637 if len(timestamps) > 1: 1638 trips.durations_gps[id_trip] = timestamps[-1]-timestamps[0] 1639 1640 # self.odtab.print_rows() 1641 1642 f.close() 1643 1644 def import_workouts_2015(self): 1645 1646 # 2015 csv 1647 # workouts 1648 # UserID TripID TimeStamp Start DT Distance AvgSpeed TrackType Sex Year Profession Frequent User ZIP 1649 # 54eb068de71f393530a9a74d 54eb0737e71f394c2fa9a74d 1424692504 Mon, 23 Feb 2015 11:55:04 GMT 0 0 urban bicycle M 1987 Developer no 1650 # 54eb9374e71f39f02fa9a750 5505cb04e71f39542e25e2d4 1426442994 Sun, 15 Mar 2015 18:09:54 GMT 0 0.7 urban bicycle M 1974 Worker yes 40128 1651 1652 j_id_user, j_id_trip, j_timestamp, j_date, j_dist, j_speed_av, j_tracktype, j_sex, j_year, j_profession, j_frequent, j_zip = range( 1653 12) 1654 n_cols = 12 1655 null = 'NULL' 1656 trips = self.parent.trips 1657 persons = self.parent.persons 1658 #exist_id_person_sumo = persons.ids_sumo.has_index 1659 ids_person_sumo = {} 1660 1661 #ids_trips = [] 1662 scenario = self.parent.get_scenario() 1663 1664 get_vtype_for_mode = scenario.demand.vtypes.get_vtype_for_mode 1665 id_type = get_vtype_for_mode(self.id_mode) 1666 1667 f = open(self.workoutsfilepath, 'r') 1668 if self._logger: 1669 self._logger.w('import_workouts_2015 %s' % os.path.basename(self.workoutsfilepath)) 1670 i_line = 0 1671 sep = ';' 1672 i_line = 1 1673 #self.get_logger().w(100.0*self.simtime/self.duration, key ='progress') 1674 for line in f.readlines()[1:]: 1675 # if True:#i_line>1: 1676 cols = line.split(sep) 1677 # print '\n len(cols)',len(cols),n_cols 1678 # print ' cols',cols 1679 if len(cols) >= n_cols: 1680 # row is complete 1681 # print ' id_trip_sumo "%s"'%cols[j_id_trip] 1682 # if cols[j_dist] != null: 1683 dist = get_colvalue(cols[j_dist])*1000.0 1684 speed_av = get_colvalue(cols[j_speed_av])/3.6 1685 #duration = get_colvalue(cols[j_duration]) 1686 # if duration>0: 1687 # speed_av = dist/duration 1688 # else: 1689 # speed_av = 0.0 1690 # print ' dist',dist,'speed_av',speed_av 1691 if speed_av > 0: 1692 duration = dist/speed_av 1693 else: 1694 duration = 0.0 1695 1696 if self.validate_trip(dist, duration, speed_av): 1697 # print ' parametric conditions verified' 1698 timestamp = get_colvalue(cols[j_timestamp]) 1699 if timestamp is not None: 1700 # print ' valid time stamp',timestamp#,self.is_timestamp_ok(timestamp) 1701 if self.is_timestamp_ok(timestamp): 1702 id_trip = trips.make(id_sumo=cols[j_id_trip], 1703 id_vtype=id_type, 1704 timestamp=timestamp, 1705 distance_gps=dist, 1706 duration_gps=duration, 1707 speed_average=speed_av, 1708 ) 1709 # ids_trips.append(id_trip) 1710 #j_id_user, j_id_trip, j_timestamp, j_date, j_dist, j_speed_av, j_tracktype, j_sex, j_year, j_profession, j_frequent, j_zip 1711 1712 zip = cols[j_zip].strip() 1713 if zip == 'undefined': 1714 zip = '' 1715 1716 year = cols[j_year] 1717 if year.isdigit(): 1718 year_birth = int(year) 1719 else: 1720 year_birth = -1 1721 1722 persons.make(id_sumo=cols[j_id_user].strip(), 1723 id_trip=id_trip, 1724 gender=cols[j_sex].strip(), 1725 year_birth=year_birth, 1726 occupation=cols[j_profession].strip(), 1727 is_frequent_user=cols[j_frequent].strip() == 'yes', 1728 zip=zip, 1729 ) 1730 else: 1731 print 'WARNING: inconsistent number of columns (%d) in line %d, file %s' % ( 1732 len(cols), i_line, self.workoutsfilepath) 1733 # print ' cols =',cols 1734 1735 i_line += 1 1736 1737 def import_points_2015(self): 1738 print 'import_points_2015' 1739 # 0 1 2 3 4 5 6 7 8 1740 #TripID, TimeStamp,Date, Latitude, Longitude, Altitude, Distance, Speed, Type 1741 # 54eb0737e71f394c2fa9a74d,1424692509,"Mon, 23 Feb 2015 11:55:09 GMT",44.499096,11.361185,49.419395,0,0.000815,start 1742 1743 ind_id_path = 0 1744 ind_time = 1 1745 ind_day = 2 1746 ind_date = 3 1747 ind_lat = 4 1748 ind_lon = 5 1749 ind_alt = 6 1750 ind_dist = 7 1751 ind_speed = 8 1752 ind_type = 9 1753 1754 n_cols = 10 1755 #TripID, TimeStamp,Date, Latitude, Longitude, Altitude, Distance, Speed, Type 1756 1757 trips = self.parent.trips 1758 points = self.parent.points 1759 1760 exist_id_trip_sumo = trips.ids_sumo.has_index 1761 get_id_trip = trips.ids_sumo.get_id_from_index 1762 1763 sep = ',' # self.sep_column_points 1764 1765 f = open(self.pointsfilepath, 'r') 1766 if self._logger: 1767 self._logger.w('import_points_2015 %s' % os.path.basename(self.pointsfilepath)) 1768 i_line = 0 1769 id_trip_sumo = None 1770 id_trip = -1 1771 is_valid_trip = False 1772 1773 n_points_imported = 0 1774 for line in f.readlines(): 1775 1776 cols = line.split(sep) 1777 # print ' len(cols)',len(cols),n_cols 1778 if len(cols) == n_cols: 1779 id_trip_sumo_current = cols[ind_id_path] 1780 # print ' id_trip_sumo_current,id_trip_sumo',id_trip_sumo_current,id_trip_sumo,is_valid_trip 1781 if id_trip_sumo_current != id_trip_sumo: 1782 # this point is part of new trip 1783 1784 if is_valid_trip: 1785 # print ' store past points for valid trip',id_trip 1786 ids_point = points.add_rows( 1787 timestamps=timestamps, 1788 ids_trip=id_trip*np.ones(len(timestamps), dtype=np.int32), 1789 longitudes=longitudes, 1790 latitudes=latitudes, 1791 altitudes=altitudes, 1792 ) 1793 1794 trips.set_points(id_trip, ids_point) 1795 # print ' timestamps',timestamps 1796 if len(timestamps) > 1: 1797 trips.durations_gps[id_trip] = timestamps[-1]-timestamps[0] 1798 # print ' durations_gps',timestamps[-1]-timestamps[0] 1799 # check if new trip is valid 1800 if exist_id_trip_sumo(id_trip_sumo_current): 1801 1802 is_valid_trip = True # start recording 1803 id_trip = get_id_trip(id_trip_sumo_current) 1804 # print ' found trip',id_trip,id_trip_sumo_current,' exisits-> record' 1805 1806 # ids_point_sumo = [] # useless? 1807 timestamps = [] 1808 ids_trip = [] 1809 longitudes = [] 1810 latitudes = [] 1811 altitudes = [] 1812 1813 else: 1814 # print ' trip',id_trip_sumo_current,'does not exisit' 1815 is_valid_trip = False 1816 1817 id_trip_sumo = id_trip_sumo_current 1818 1819 if is_valid_trip: 1820 # print ' store point timestamp',cols[ind_time] 1821 # current point belongs to a valid trip 1822 # ids_point_sumo.append(cols[ind_id_point]) 1823 timestamps.append(get_colvalue(cols[ind_time])) 1824 # ids_trip.append(id_trip) 1825 longitudes.append(get_colvalue(cols[ind_lon])) 1826 latitudes.append(get_colvalue(cols[ind_lat])) 1827 altitudes.append(get_colvalue(cols[ind_alt])) 1828 1829 else: 1830 print 'WARNING: inconsistent number of columns (%d) in line %d, file %s' % ( 1831 len(cols), i_line, self.pointsfilepath) 1832 # print ' cols =',cols 1833 1834 i_line += 1 1835 1836 # register points of last trip 1837 if is_valid_trip: 1838 # store past points for valid trip 1839 ids_point = points.add_rows( 1840 timestamps=timestamps, 1841 ids_trip=id_trip*np.ones(len(timestamps), dtype=np.int32), 1842 longitudes=longitudes, 1843 latitudes=latitudes, 1844 altitudes=altitudes, 1845 ) 1846 1847 trips.set_points(id_trip, ids_point) 1848 1849 if len(timestamps) > 1: 1850 trips.durations_gps[id_trip] = timestamps[-1]-timestamps[0] 1851 1852 f.close() 1853 1854 def import_workouts_2014(self): 1855 print 'import_workouts_2014' 1856 # 2014 ecomondo workouts 1857 # id pointDBNode pointPathId startTime distance duration sport calories maxSpeed altitudeMin altitudeMax metersAscent metersDescent 1858 # 329308466 7 37073516 2014-05-01 19:00:00 26 15600 1 1182.64 NULL NULL NULL NULL NULL 1859 # 0 1 2 3 4 5 6 7 8 9 10 11 12 1860 1861 j_id, j_node, j_id_trip, j_time, j_dist, j_duration = range(6) 1862 j_v_max = 8 1863 n_cols = 13 1864 null = 'NULL' 1865 trips = self.parent.trips 1866 # persons = self.parent.persons # no person data in 2014 :( 1867 ids_person_sumo = {} 1868 1869 ids_trips = [] 1870 scenario = self.parent.get_scenario() 1871 1872 #get_vtype_for_mode = scenario.demand.vtypes.get_vtype_for_mode 1873 id_vtype = scenario.demand.vtypes.get_vtype_for_mode(self.id_mode) 1874 1875 f = open(self.workoutsfilepath, 'r') 1876 #if self._logger: self._logger.w('import_workouts_2014 %s'%os.path.basename(self.workoutsfilepath)) 1877 i_line = 0 1878 sep = ',' # self.sep_column_workout 1879 1880 #self.get_logger().w(100.0*self.simtime/self.duration, key ='progress') 1881 for line in f.readlines()[1:]: 1882 # if True:#i_line>1: 1883 cols = line.split(sep) 1884 # print ' len(cols)',len(cols),n_cols 1885 if len(cols) == n_cols: 1886 # row is complete 1887 1888 # if cols[j_dist] != null: 1889 dist = get_colvalue(cols[j_dist])*1000.0 1890 duration = get_colvalue(cols[j_duration]) 1891 if duration > 0: 1892 speed_av = dist/duration 1893 else: 1894 speed_av = 0.0 1895 1896 if self.validate_trip(dist, duration, speed_av): 1897 # print 'parametric conditions verified' 1898 timestamp = calc_seconds(cols[j_time]) 1899 if timestamp is not None: 1900 # print ' valid time stamp',timestamp 1901 if self.is_timestamp_ok(timestamp): 1902 id_trip = trips.make(id_sumo=cols[j_id_trip], 1903 id_vtype=id_vtype, 1904 timestamp=timestamp, 1905 distance_gps=dist, 1906 duration_gps=duration, 1907 speed_average=speed_av, 1908 speed_max=get_colvalue(cols[j_v_max])/3.6, 1909 ) 1910 ids_trips.append(id_trip) 1911 1912 def import_points_2014(self): 1913 print 'import_points_2014' 1914 # csv2014 1915 # pointDBNode,pointPathId,id,timestamp,latitude,longitude,altitude,distance,heartRate,instruction,speed 1916 # 4,61565791,23648171762,2013-05-01 06:33:58,44.501085,11.372906,NULL,0,NULL,2,NULL 1917 1918 # pointDBNode,pointPathId,id,timestamp,latitude,longitude,altitude,distance,heartRate,instruction,speed 1919 # 7,37073516,15138524460,NULL,44.51579,11.36257,NULL,NULL,NULL,NULL,NULL 1920 1921 # pointDBNode,pointPathId,id,timestamp,latitude,longitude,altitude,distance,heartRate,instruction,speed 1922 # 7,37073516,15138524460,NULL,44.51579,11.36257,NULL,NULL,NULL,NULL,NULL 1923 1924 # Endomondo export format 1925 # pointDBNode,pointPathId,id,timestamp,latitude,longitude,altitude,distance,heartRate,instruction,speed 1926 # 0 1 2 3 4 5 6 7 8 9 10 1927 ind_id_path = 1 1928 ind_id_point = 2 1929 ind_time = 3 1930 ind_lat = 4 1931 ind_lon = 5 1932 ind_alt = 6 1933 ind_dist = 7 1934 ind_speed = 10 1935 1936 n_cols = 11 1937 #TripID, TimeStamp,Date, Latitude, Longitude, Altitude, Distance, Speed, Type 1938 1939 trips = self.parent.trips 1940 points = self.parent.points 1941 1942 exist_id_trip_sumo = trips.ids_sumo.has_index 1943 get_id_trip = trips.ids_sumo.get_id_from_index 1944 1945 sep = ',' # self.sep_column_points 1946 1947 f = open(self.pointsfilepath, 'r') 1948 if self._logger: 1949 self._logger.w('import_points_2014 %s' % os.path.basename(self.pointsfilepath)) 1950 i_line = 0 1951 id_trip_sumo = None 1952 id_trip = -1 1953 is_valid_trip = False 1954 1955 n_points_imported = 0 1956 for line in f.readlines(): 1957 1958 cols = line.split(sep) 1959 # print ' len(cols)',len(cols),n_cols 1960 if len(cols) == n_cols: 1961 id_trip_sumo_current = cols[ind_id_path] 1962 # print ' id_trip_sumo_current,id_trip_sumo',id_trip_sumo_current,id_trip_sumo,is_valid_trip 1963 if id_trip_sumo_current != id_trip_sumo: 1964 # this point is part of new trip 1965 1966 if is_valid_trip: 1967 # print ' store past points for valid trip',id_trip 1968 ids_point = points.add_rows( 1969 timestamps=timestamps, 1970 ids_trip=id_trip*np.ones(len(timestamps), dtype=np.int32), 1971 longitudes=longitudes, 1972 latitudes=latitudes, 1973 altitudes=altitudes, 1974 ) 1975 1976 trips.set_points(id_trip, ids_point) 1977 1978 # check if new trip is valid 1979 if exist_id_trip_sumo(id_trip_sumo_current): 1980 1981 is_valid_trip = True # start recording 1982 id_trip = get_id_trip(id_trip_sumo_current) 1983 # print ' found trip',id_trip,id_trip_sumo_current,' exisits-> record' 1984 1985 # ids_point_sumo = [] # useless? 1986 timestamps = [] 1987 ids_trip = [] 1988 longitudes = [] 1989 latitudes = [] 1990 altitudes = [] 1991 1992 else: 1993 # print ' trip',id_trip_sumo_current,'does not exisit' 1994 is_valid_trip = False 1995 1996 id_trip_sumo = id_trip_sumo_current 1997 1998 if is_valid_trip: 1999 # print ' store point timestamp',cols[ind_time] 2000 # current point belongs to a valid trip 2001 # ids_point_sumo.append(cols[ind_id_point]) 2002 timestamps.append(calc_seconds(cols[ind_time])) 2003 # ids_trip.append(id_trip) 2004 longitudes.append(get_colvalue(cols[ind_lon])) 2005 latitudes.append(get_colvalue(cols[ind_lat])) 2006 altitudes.append(get_colvalue(cols[ind_alt])) 2007 2008 else: 2009 print 'WARNING: inconsistent columns in line %d, file %s' % ( 2010 i_line, os.path.basename(self.pointsfilepath)) 2011 2012 i_line += 1 2013 2014 # register points of last trip 2015 if is_valid_trip: 2016 # store past points for valid trip 2017 ids_point = points.add_rows( 2018 timestamps=timestamps, 2019 ids_trip=id_trip*np.ones(len(timestamps), dtype=np.int32), 2020 longitudes=longitudes, 2021 latitudes=latitudes, 2022 altitudes=altitudes, 2023 ) 2024 2025 trips.set_points(id_trip, ids_point) 2026 2027 # self.odtab.print_rows() 2028 2029 f.close() 2030 2031 def import_points_2013(self): 2032 print 'import_points_2013' 2033 #pointDBNode, pointPathId, id, timestamp, latitude, longitude, altitude,distance, heartRate,instruction,speed 2034 # 4, 61565791, 23648171762,2013-05-01 06:33:58,44.501085, 11.372906, NULL, 0, NULL, 2, NULL 2035 # 0 1 2 3 4 5 6 7 8 9 10 2036 ind_id_path = 1 2037 ind_id_point = 2 2038 ind_time = 3 2039 ind_lat = 4 2040 ind_lon = 5 2041 ind_alt = 6 2042 ind_dist = 7 2043 ind_speed = 10 2044 2045 n_cols = 11 2046 #TripID, TimeStamp,Date, Latitude, Longitude, Altitude, Distance, Speed, Type 2047 2048 trips = self.parent.trips 2049 points = self.parent.points 2050 2051 exist_id_trip_sumo = trips.ids_sumo.has_index 2052 get_id_trip = trips.ids_sumo.get_id_from_index 2053 id_vtype = self.parent.get_scenario().demand.vtypes.get_vtype_for_mode(self.id_mode) 2054 sep = ',' # self.sep_column_points 2055 2056 f = open(self.pointsfilepath, 'r') 2057 if self._logger: 2058 self._logger.w('import_points_2013 %s' % os.path.basename(self.pointsfilepath)) 2059 i_line = 0 2060 id_trip_sumo = None 2061 id_trip = -1 2062 is_valid_trip = False 2063 timestamp_last = -1 2064 n_points_imported = 0 2065 timestamps = [] 2066 2067 for line in f.readlines(): 2068 2069 cols = line.split(sep) 2070 # print ' len(cols)',len(cols),n_cols 2071 if (len(cols) == n_cols) & (i_line > 0): 2072 id_trip_sumo_current = cols[ind_id_path] 2073 if timestamp_last < 0: 2074 timestamp_last = calc_seconds(cols[ind_time]) 2075 2076 # print ' id_trip_sumo_current,id_trip_sumo',id_trip_sumo_current,id_trip_sumo,is_valid_trip 2077 if id_trip_sumo_current != id_trip_sumo: 2078 # this point is part of new trip 2079 2080 # validate trip data 2081 if len(timestamps) == 0: 2082 is_valid_trip = False 2083 2084 else: 2085 coords = self.project(latitudes, longitudes) 2086 distance = np.sum(np.sqrt(np.sum((coords[1:, :]-coords[:-1, :])**2, 1))) 2087 duration = timestamps[-1]-timestamps[0] 2088 if duration > 0: 2089 speed_av = distance/duration 2090 else: 2091 speed_av = 0.0 2092 is_valid_trip = self.validate_trip(distance, duration, speed_av) 2093 2094 if is_valid_trip: 2095 # print ' store past points for valid trip',id_trip 2096 id_trip = trips.make(id_sumo=id_trip_sumo_current, 2097 id_vtype=id_vtype, 2098 timestamp=timestamp_last, 2099 distance_gps=distance, 2100 duration_gps=duration, 2101 speed_average=speed_av, 2102 ) 2103 2104 ids_point = points.add_rows( 2105 timestamps=timestamps, 2106 ids_trip=id_trip*np.ones(len(timestamps), dtype=np.int32), 2107 longitudes=longitudes, 2108 latitudes=latitudes, 2109 altitudes=altitudes, 2110 ) 2111 2112 trips.set_points(id_trip, ids_point) 2113 2114 # check if new trip is valid 2115 # if exist_id_trip_sumo(id_trip_sumo_current): 2116 2117 is_valid_trip = True # start recording 2118 #id_trip = get_id_trip(id_trip_sumo_current) 2119 # print ' found trip',id_trip,id_trip_sumo_current,' exisits-> record' 2120 2121 # ids_point_sumo = [] # useless? 2122 timestamp_last = calc_seconds(cols[ind_time]) 2123 timestamps = [] 2124 ids_trip = [] 2125 longitudes = [] 2126 latitudes = [] 2127 altitudes = [] 2128 2129 # else: 2130 # #print ' trip',id_trip_sumo_current,'does not exisit' 2131 # is_valid_trip = False 2132 2133 id_trip_sumo = id_trip_sumo_current 2134 2135 if is_valid_trip: 2136 # print ' store point timestamp',cols[ind_time] 2137 # current point belongs to a valid trip 2138 # ids_point_sumo.append(cols[ind_id_point]) 2139 timestamps.append(calc_seconds(cols[ind_time])) 2140 # ids_trip.append(id_trip) 2141 longitudes.append(get_colvalue(cols[ind_lon])) 2142 latitudes.append(get_colvalue(cols[ind_lat])) 2143 altitudes.append(get_colvalue(cols[ind_alt])) 2144 2145 else: 2146 print 'WARNING: inconsistent columns in line %d, file %s' % ( 2147 i_line, os.path.basename(self.pointsfilepath)) 2148 2149 i_line += 1 2150 2151 # register points of last trip 2152 if is_valid_trip: 2153 # store past points for valid trip 2154 ids_point = points.add_rows( 2155 timestamps=timestamps, 2156 ids_trip=id_trip*np.ones(len(timestamps), dtype=np.int32), 2157 longitudes=longitudes, 2158 latitudes=latitudes, 2159 altitudes=altitudes, 2160 ) 2161 2162 trips.set_points(id_trip, ids_point) 2163 2164 # self.odtab.print_rows() 2165 2166 f.close() 2167 2168 2169class GpxImporter(FilterMixin): 2170 def __init__(self, mapmatching, logger=None, **kwargs): 2171 print 'GpxImporter.__init__', mapmatching.get_ident() 2172 self._init_common('gpximporter', 2173 parent=mapmatching, 2174 name='GPX Importer', 2175 logger=logger, 2176 info='Import GPS traces from GPX files.', 2177 2178 ) 2179 2180 attrsman = self.set_attrsman(cm.Attrsman(self)) 2181 2182 scenario = mapmatching.get_scenario() 2183 rootfilepath = scenario.get_rootfilepath() 2184 2185 # here we ged classes not vehicle type 2186 # specific vehicle type within a class will be generated later 2187 modechoices = scenario.net.modes.names.get_indexmap() 2188 2189 # print ' modechoices',modechoices 2190 self.id_mode = attrsman.add(am.AttrConf('id_mode', modechoices['bicycle'], 2191 groupnames=['options'], 2192 choices=modechoices, 2193 name='Mode', 2194 info='Transport mode to be matched.', 2195 )) 2196 2197 self.filepaths = attrsman.add( 2198 cm.AttrConf('filepaths', kwargs.get('filepath', rootfilepath+'.gpx'), 2199 groupnames=['options'], 2200 perm='rw', 2201 name='filenames', 2202 wildcards='GPX file (*.gpx)|*.gpx|XML file (*.xml)|*.xml', 2203 metatype='filepaths', 2204 info="""Paths and file name of GPX file with GPS traces in XML format.""", 2205 )) 2206 self._init_traceoptions(**kwargs) 2207 2208 def do(self): 2209 """ 2210 Reads endomondo gpx xml file and stores point data in traces table. 2211 If there is no traces table, one will be initialized and returned 2212 """ 2213 print 'GpxImporter.do', self.filepaths 2214 mapmatching = self.parent 2215 #scenario = mapmatching.get_scenario() 2216 logger = self.get_logger() 2217 2218 get_vtype_for_mode = mapmatching.get_scenario().demand.vtypes.get_vtype_for_mode 2219 2220 parser = GpxParser(mapmatching.trips, mapmatching.points, 2221 logger=logger, 2222 id_vtype=get_vtype_for_mode(self.id_mode), 2223 dist_trip_min=self.dist_trip_min, 2224 dist_trip_max=self.dist_trip_max, 2225 duration_trip_min=self.speed_trip_min, 2226 duration_trip_max=self.duration_trip_max, 2227 speed_trip_min=self.speed_trip_min, 2228 speed_trip_max=self.speed_trip_max, 2229 ) 2230 for filepath in self.filepaths.split(','): 2231 print ' parse gpx file', filepath 2232 parse(filepath.strip(), parser) 2233 2234 ids_trips = parser.get_ids_trip() 2235 if logger: 2236 logger.w('imported %d traces, project coordinates...' % len(ids_trips)) 2237 2238 # recalculate projection for network in scenario 2239 # for id_trace in ids_traces: 2240 # traces.pointsets.get(id_trace).project( traces._proj, traces.offset) 2241 2242 mapmatching.points.project() 2243 2244 if logger: 2245 logger.w('imported %d trips done.' % len(ids_trips)) 2246 return True 2247 2248 2249class GpxParser(handler.ContentHandler): 2250 """Reads endomondo gpx xml file and parses lat,lon, ele and time. 2251 """ 2252 2253 def __init__(self, trips, points, logger=None, 2254 id_vtype=0, 2255 dist_trip_min=10.0, 2256 dist_trip_max=50000.0, 2257 duration_trip_min=0.5, 2258 duration_trip_max=999999.0, 2259 speed_trip_min=0.1, 2260 speed_trip_max=100.0, 2261 ): 2262 2263 self._logger = logger 2264 self._points = points 2265 self._trips = trips 2266 self._id_vtype = id_vtype 2267 self._dist_trip_min = dist_trip_min 2268 self._dist_trip_max = dist_trip_max 2269 self._duration_trip_min = speed_trip_min 2270 self._duration_trip_max = duration_trip_max 2271 self._speed_trip_min = speed_trip_min 2272 self._speed_trip_max = speed_trip_max 2273 2274 self.reset_trip() 2275 2276 def reset_trip(self): 2277 self._lons = [] 2278 self._lats = [] 2279 self._eles = [] 2280 self._times = [] 2281 self._is_record_segment = False 2282 self._is_record_point = False 2283 self._is_time = False 2284 self._is_ele = False 2285 2286 self._ids_trip = [] 2287 self._ids_point = [] 2288 2289 def get_ids_trip(self): 2290 return self._ids_trip 2291 2292 def get_ids_point(self): 2293 return self._ids_point 2294 2295 def startElement(self, name, attrs): 2296 # if self._pointset is None: 2297 2298 if name == 'trkpt': 2299 self._is_record_point = True 2300 self._lons.append(float(attrs['lon'])) 2301 self._lats.append(float(attrs['lat'])) 2302 2303 if name == 'time': 2304 self._is_time = True 2305 2306 if name == 'ele': 2307 self._is_ele = True 2308 2309 if name == 'trkseg': 2310 self._is_record_segment = True 2311 2312 if name == 'trk': 2313 self._is_record_trip = True 2314 2315 def characters(self, content): 2316 2317 if self._is_time: 2318 # print ' got time',content[:-1] 2319 2320 if self._is_record_point: 2321 # 2013-05-30T16:42:33Z 2014-01-26T12:32:21Z 2322 self._times.append(calc_seconds(content[:-1], 2323 sep_date_clock='T', 2324 sep_date='-', 2325 sep_clock=':', 2326 is_float=False)) 2327 2328 if self._is_ele: 2329 # print 'characters content',content 2330 self._eles.append(float(content)) 2331 2332 def endElement(self, name): 2333 if name == 'ele': 2334 self._is_ele = False 2335 2336 if name == 'time': 2337 self._is_time = False 2338 2339 if name == 'trkpt': 2340 # print 'endElement: point',self._lon,self._lat,self._ele,self._time 2341 #self._is_ele = False 2342 #self._is_time = False 2343 self._is_record_point = False 2344 2345 if name == 'trk': 2346 # here we could stop recording a segment 2347 # but currently we join all segments together 2348 pass 2349 2350 if name == 'trk': 2351 # print 'endElement',len(self._lons) 2352 2353 # print ' self._lons',self._lons 2354 # print ' self._lats',self._lats 2355 # print ' self._times',self._times 2356 2357 # trip recording ends 2358 n_points = len(self._lons) 2359 2360 if (n_points > 0): 2361 timestamp = self._times[0] 2362 duration = self._times[-1]-timestamp 2363 # print ' timestamp',timestamp 2364 # print ' duration',duration,self._duration_trip_min,self._duration_trip_max 2365 # TODO: make this filter a functin of filtermixin 2366 if (duration > self._duration_trip_min)\ 2367 & (duration < self._duration_trip_max): 2368 2369 id_trip = self._trips.make(id_vtype=self._id_vtype, 2370 timestamp=timestamp, 2371 #distance_gps = dist, 2372 duration_gps=duration 2373 #speed_average = speed_av, 2374 ) 2375 self._ids_trip.append(id_trip) 2376 2377 if len(self._eles) == n_points: 2378 altitudes = self._eles 2379 else: 2380 altitudes = np.zeros(n_points, dtype=np.float32) 2381 2382 ids_point = self._points.add_rows( 2383 timestamps=self._times, 2384 ids_trip=id_trip*np.ones(n_points, dtype=np.int32), 2385 longitudes=self._lons, 2386 latitudes=self._lats, 2387 altitudes=altitudes, 2388 ) 2389 2390 self._trips.set_points(id_trip, ids_point) 2391 self._trips.ids_sumo[id_trip] = str(id_trip) 2392 2393 self.reset_trip() 2394 2395 2396class GpsTrips(Trips): 2397 def __init__(self, ident, mapmatching, **kwargs): 2398 # print 'Trips.__init__' 2399 self._init_objman(ident=ident, 2400 parent=mapmatching, 2401 name='Trips', 2402 info='Table with GPS trips, matched routes and alternative routes.', 2403 xmltag=('trips', 'trip', 'ids_sumo'), 2404 version=0.0, 2405 **kwargs) 2406 2407 self._init_attributes() 2408 self._init_constants() 2409 2410 def _init_attributes(self): 2411 2412 self.add_col(SumoIdsConf('GPS Trip', xmltag='id', info='GPS trip data.')) 2413 2414 self.add_col(am.ArrayConf('are_selected', default=True, 2415 dtype=np.bool, 2416 groupnames=['parameters', ], 2417 name='selected', 2418 symbol='Sel.', 2419 info='Selected for being processed (example mapmatching, export, etc).', 2420 )) 2421 2422 self.add_col(am.ArrayConf('timestamps', default=0, 2423 dtype=np.int, 2424 perm='r', 2425 groupnames=['parameters', 'gps'], 2426 name='timestamp', 2427 unit='s', 2428 metatype='datetime', 2429 info='Timestamp when trip started in seconds after 01 January 1970.', 2430 )) 2431 2432 self.timestamps.metatype = 'datetime' 2433 self.timestamps.set_perm('r') 2434 2435 self.add_col(am.ArrayConf('durations_gps', default=0.0, 2436 dtype=np.float32, 2437 groupnames=['parameters', 'gps'], 2438 name='GPS duration', 2439 unit='s', 2440 info='Time duration measure with GPS points.', 2441 )) 2442 2443 self.add_col(am.ArrayConf('distances_gps', default=0.0, 2444 dtype=np.float32, 2445 groupnames=['parameters', 'gps'], 2446 name='GPS distance', 2447 unit='m', 2448 info='Distance measure with GPS points.', 2449 )) 2450 2451 self.add_col(am.ArrayConf('speeds_average', default=0.0, 2452 dtype=np.float32, 2453 groupnames=['parameters', 'gps'], 2454 name='Av. speed', 2455 unit='m/s', 2456 info='Average speed based on GPS info.', 2457 )) 2458 self.add_col(am.ArrayConf('speeds_max', default=0.0, 2459 dtype=np.float32, 2460 groupnames=['parameters', 'gps'], 2461 name='Max. speed', 2462 unit='m/s', 2463 info='Maximum speed based on GPS info.', 2464 )) 2465 2466 # Trips._init_attributes(self) 2467 self.add_col(am.IdsArrayConf('ids_vtype', self.get_obj_vtypes(), 2468 groupnames=['state'], 2469 name='Type', 2470 info='Vehicle type.', 2471 xmltag='type', 2472 )) 2473 2474 self.add_col(am.ArrayConf('ids_purpose', default=TRIPPUROPSES['unknown'], 2475 dtype=np.int32, 2476 groupnames=['parameters', 'gps'], 2477 choices=TRIPPUROPSES, 2478 name='Purpose', 2479 info='Trip purpose ID', 2480 )) 2481 2482 self.add_col(am.ArrayConf('ids_device', default=DEVICES['unknown'], 2483 dtype=np.int32, 2484 groupnames=['parameters', 'gps'], 2485 choices=DEVICES, 2486 name='Devices', 2487 info='Device ID', 2488 )) 2489 self.add(cm.ObjConf(Routes('routes', self, self.parent.get_scenario().net))) 2490 2491 self.add_col(am.IdsArrayConf('ids_route_matched', self.get_routes(), 2492 groupnames=['results'], 2493 name='ID matched route', 2494 info='Route ID of mached route.', 2495 )) 2496 2497 self.add_col(am.IdsArrayConf('ids_route_shortest', self.get_routes(), 2498 groupnames=['results'], 2499 name='ID shortest route', 2500 info='Route ID of shortest route.', 2501 )) 2502 2503 self.add_col(am.IdsArrayConf('ids_route_fastest', self.get_routes(), 2504 groupnames=['results'], 2505 name='ID fastest route', 2506 info='Route ID of fastest route.', 2507 )) 2508 2509 self.add_col(am.ArrayConf('lengths_gpsroute_matched', default=-1.0, 2510 dtype=np.float32, 2511 groupnames=['results'], 2512 name='Matched length', 2513 symbol='L match GPS', 2514 unit='m', 2515 info='Length of the matched part of the GPS trace, measured by linear interpolation of GPS points. Note the only a fraction of the GPS trace ma be within the given network.', 2516 )) 2517 2518 self.add_col(am.ArrayConf('lengths_route_matched', default=-1.0, 2519 dtype=np.float32, 2520 groupnames=['results'], 2521 name='Matched length', 2522 symbol='L match', 2523 unit='m', 2524 info='Length of the matched part of the GPS trace, measured by summing the length of edges of the matched route. Note the only a fraction of the GPS trace ma be within the given network.', 2525 )) 2526 2527 self.add_col(am.ArrayConf('durations_route_matched', default=-1.0, 2528 dtype=np.float32, 2529 groupnames=['results'], 2530 name='Matched duration', 2531 symbol='T match', 2532 unit='s', 2533 info='Duration of the matched part of the GPS trace. This is the difference in timestamps between last and first GPS point of the matched route. Note the only a fraction of the GPS trace ma be within the given network.', 2534 )) 2535 2536 self.add_col(am.ArrayConf('lengths_route_shortest', default=-1.0, 2537 dtype=np.float32, 2538 groupnames=['results'], 2539 name='Shortest length', 2540 symbol='L short', 2541 unit='m', 2542 info='Length of the shortest route. Shortest route is connecting the first matched edge and the final matched edge.', 2543 )) 2544 2545 self.add_col(am.ArrayConf('durations_route_fastest', default=-1.0, 2546 dtype=np.float32, 2547 groupnames=['results'], 2548 name='Fastest duration', 2549 symbol='T fast', 2550 unit='s', 2551 info='Durations of the fastest route. Fastest route is connecting the first matched edge and the final matched edge.', 2552 )) 2553 2554 self.add_col(am.ArrayConf('timelosses_route_fastest', default=-1.0, 2555 dtype=np.float32, 2556 groupnames=['results'], 2557 name='Fastest timeloss', 2558 symbol='dT fast', 2559 unit='s', 2560 info="""Time loss of matched route with respect to fastest route. Fastest route is connecting the first matched edge and the final matched edge. 2561 Note that in order to be comparable, this time loss is calculated for matched and fastest route with the same edge travel times. 2562 These edge travel times are an approximation and are not necessarily identical with the experienced edge travel times. 2563 """, 2564 )) 2565 2566 self.add_col(am.ArrayConf('lengths_route_fastest', default=-1.0, 2567 dtype=np.float32, 2568 groupnames=['results'], 2569 name='Shortest length', 2570 symbol='L fast', 2571 unit='m', 2572 info='Length of the fastest route. Fastest route is connecting the first matched edge and the final matched edge.', 2573 )) 2574 2575 self.add_col(am.ArrayConf('lengths_route_matched_mixed', default=-1.0, 2576 dtype=np.float32, 2577 groupnames=['results'], 2578 name='Matched length mixed access', 2579 symbol='L match mix', 2580 unit='m', 2581 info='Length of the matched part of the GPS trace. Note the only a fraction of the GPS trace ma be within the given network.', 2582 )) 2583 2584 self.add_col(am.ArrayConf('lengths_route_matched_exclusive', default=-1.0, 2585 dtype=np.float32, 2586 groupnames=['results'], 2587 name='Matched length exclusive access', 2588 symbol='L match excl', 2589 unit='m', 2590 info='Length of the matched part of the GPS trace. Note the only a fraction of the GPS trace ma be within the given network.', 2591 )) 2592 2593 self.add_col(am.ArrayConf('lengthindexes', default=-1.0, 2594 dtype=np.float32, 2595 groupnames=['results'], 2596 name='Length index', 2597 unit='%', 2598 info='Length index is the length of the matched route divided by length of line-interpolated GPS points.', 2599 )) 2600 2601 self.add_col(am.ArrayConf('errors_dist', default=-1.0, 2602 dtype=np.float32, 2603 groupnames=['results'], 2604 name='Distance error', 2605 unit='mm', 2606 info='The distance error is the average distance between the GPS points and the matched route.', 2607 )) 2608 2609 self.add_col(am.ArrayConf('times_computation', default=-1.0, 2610 dtype=np.float32, 2611 groupnames=['results'], 2612 name='Computation time', 2613 unit='ms', 2614 info='Computation time of the match algorithm.', 2615 )) 2616 2617 self.add_col(am.ArrayConf('are_match_connected', default=False, 2618 dtype=np.bool, 2619 groupnames=['results', ], 2620 name='Match connected', 2621 #symbol = 'Match conn.', 2622 info='The matched route connects first and last network edge where GPS points have been detected.', 2623 )) 2624 2625 self.add_col(am.IdlistsArrayConf('ids_points', self.parent.points, 2626 #groupnames = ['_private'], 2627 name='Point IDs', 2628 info="GPS point IDs.", 2629 )) 2630 2631 self.add_col(am.IdlistsArrayConf('ids_points_edgeend', self.parent.points, 2632 groupnames=['results', '_private'], 2633 name='Edge endpoint IDs', 2634 info="This is a list of GPS point IDs which represent the last point associated with each matched edge.", 2635 )) 2636 # update 2637 self.ids_points_edgeend.add_groupnames(['_private']) 2638 2639 def get_obj_vtypes(self): 2640 return self.parent.get_scenario().demand.vtypes 2641 2642 def get_routes(self): 2643 return self.routes.get_value() 2644 2645 def clear_routes(self): 2646 self.get_routes().clear() 2647 for attrconf in self.get_group('results'): 2648 attrconf.reset() 2649 2650 def select_all(self): 2651 self.are_selected.get_value()[:] = True 2652 2653 def unselect_all(self): 2654 self.are_selected.get_value()[:] = False 2655 2656 def invert_selection(self): 2657 self.are_selected.get_value()[:] = np.logical_not(self.are_selected.get_value()[:]) 2658 2659 def set_matched_route(self, id_trip, route, 2660 length_matched=0.0, 2661 length_route_mixed=0.0, 2662 length_route_exclusive=0.0, 2663 duration_matched=0.0, 2664 lengthindex=-1.0, 2665 error_dist=-1.0, 2666 comptime=0.0, 2667 is_connected=False, 2668 ids_point_edgeend=[], 2669 color=COLOR_MATCHED_ROUTE.copy(), 2670 ): 2671 2672 if len(route) > 0: 2673 id_route = self.ids_route_matched[id_trip] 2674 if id_route >= 0: 2675 # already a matched route existant 2676 self.get_routes().ids_edges[id_route] = route 2677 self.get_routes().colors[id_route] = color 2678 # self.get_routes().set_row( id_route, 2679 # ids_edges = route, 2680 # colors = COLOR_MATCHED_ROUTE, 2681 # ) 2682 2683 # self.get_routes().set_row( id_route, 2684 # ids_trip = id_trip, 2685 # ids_edges = route, 2686 # #costs = duration_matched, 2687 # #probabilities = 1.0, 2688 # ) 2689 else: 2690 id_route = self.get_routes().add_row(ids_trip=id_trip, 2691 ids_edges=route, 2692 #costs = duration_matched, 2693 #probabilities = 1.0, 2694 colors=color, 2695 ) 2696 else: 2697 id_route = -1 2698 2699 # print 'set_matched_route id_trip', id_trip,'id_route', id_route 2700 # print ' ids_point_edgeend',ids_point_edgeend 2701 #self.ids_route_matched[id_trip] = id_route 2702 2703 self.set_row(id_trip, 2704 ids_route_matched=id_route, 2705 lengths_gpsroute_matched=length_matched/lengthindex, 2706 durations_route_matched=duration_matched, 2707 lengths_route_matched=length_matched, 2708 lengths_route_matched_mixed=length_route_mixed, 2709 lengths_route_matched_exclusive=length_route_exclusive, 2710 lengthindexes=100*lengthindex, 2711 errors_dist=1000 * error_dist, 2712 times_computation=1000*comptime, 2713 are_match_connected=is_connected 2714 ) 2715 # TODO: do this extra! this is a bug!! 2716 # if included in set_row, only first value in list is taken!!! 2717 self.ids_points_edgeend[id_trip] = ids_point_edgeend 2718 2719 # print ' ids_points_edgeend[id_trip]',self.ids_points_edgeend[id_trip] 2720 2721 return id_route 2722 2723 def make(self, **kwargs): 2724 # if self.ids_sumo.has_index(id_sumo): 2725 # id_trip = self.ids_sumo.get_id_from_index(id_sumo) 2726 # #self.set_row(id_sumo, **kwargs) 2727 # return id_trip 2728 # else: 2729 2730 #purpose = cols[j_speed_av].strip(), 2731 #device = cols[j_device].strip(), 2732 device = kwargs.get('device', None) 2733 if device in DEVICES: 2734 id_device = DEVICES[device] 2735 else: 2736 id_device = DEVICES['unknown'] 2737 2738 purpose = kwargs.get('purpose', None) 2739 if purpose in TRIPPUROPSES: 2740 id_purpose = TRIPPUROPSES[purpose] 2741 else: 2742 id_purpose = TRIPPUROPSES['unknown'] 2743 2744 id_trip = self.add_row(ids_sumo=kwargs.get('id_sumo', None), 2745 ids_vtype=kwargs.get('id_vtype', None), 2746 timestamps=kwargs.get('timestamp', None), 2747 distances_gps=kwargs.get('distance_gps', None), 2748 durations_gps=kwargs.get('duration_gps', None), 2749 speeds_average=kwargs.get('speed_average', None), 2750 speeds_max=kwargs.get('speed_max', None), 2751 ids_purpose=id_purpose, 2752 ids_device=id_device, 2753 ids_points=kwargs.get('ids_point', None), 2754 ) 2755 return id_trip 2756 2757 def set_points(self, id_trip, ids_point): 2758 self.ids_points[id_trip] = ids_point 2759 2760 def get_ids_selected(self): 2761 return self.select_ids(self.are_selected.get_value()) 2762 2763 def route_fastest_with_waits(self, time_modespecific=3.0, c_modespecific=0.9, 2764 is_ignor_connections=False, times_wait_nodes=None, 2765 speeds_in_motion=None, dist_min_modespecific=15.0, 2766 color_route=COLOR_FASTEST_ROUTE.copy()): 2767 """ 2768 Shortest fastest routing. 2769 """ 2770 print 'route_fastest_with_waits', time_modespecific, c_modespecific 2771 # TODO: if too mant vtypes, better go through id_modes 2772 exectime_start = time.clock() 2773 scenario = self.parent.get_scenario() 2774 net = scenario.net 2775 edges = net.edges 2776 vtypes = scenario.demand.vtypes 2777 routes = self.get_routes() 2778 #ids_edges = [] 2779 #ids_trip = [] 2780 #costs = [] 2781 2782 distancesmap = self.parent.get_distancesmap() 2783 accesslevelsmap = self.parent.get_accesslevelsmap() 2784 2785 # delete current 2786 #ids_with_shortes = self.select_ids(np.logical_and(self.are_selected.get_value(), self.ids_route_shortest.get_value()>=0)) 2787 # routes.del_rows(self.ids_route_shortest[ids_with_shortes]) 2788 #self.ids_route_shortest[ids_with_shortes] = -1 2789 2790 fstar = edges.get_fstar(is_ignor_connections=is_ignor_connections) 2791 for id_vtype in self.get_vtypes(): 2792 id_mode = vtypes.ids_mode[id_vtype] 2793 2794 # no routing for pedestrians 2795 if id_mode != net.modes.get_id_mode('pedestrian'): 2796 dists_orig = distancesmap[id_mode].copy() 2797 times = np.zeros(len(dists_orig), dtype=np.float32) 2798 weights = np.zeros(len(dists_orig), dtype=np.float32) 2799 2800 # this will subtract some meters dependent on 2801 # access-level of the edge 2802 accesslevels = accesslevelsmap[id_mode] 2803 ids_edge = edges.get_ids() 2804 are_valid = dists_orig > dist_min_modespecific 2805 2806 ids_trip_vtype = self.select_ids(np.logical_and(self.ids_vtype.get_value( 2807 ) == id_vtype, self.are_selected.get_value(), self.ids_route_matched.get_value() >= 0)) 2808 #ids_trip_vtype = self.get_trips_for_vtype(id_vtype) 2809 # print ' id_vtype,id_mode',id_vtype,id_mode#,ids_trip_vtype 2810 # print ' weights',weights 2811 2812 edgewaittimes = times_wait_nodes[edges.ids_tonode[ids_edge]] 2813 specifictimes = time_modespecific * are_valid[ids_edge] * accesslevels[ids_edge] 2814 specificfactors = 1 - (1-c_modespecific) * are_valid[ids_edge] * (accesslevels[ids_edge] == 2) 2815 2816 #ids_edge_depart = self.ids_edge_depart[ids_trip_vtype] 2817 #ids_edge_arrival = self.ids_edge_arrival[ids_trip_vtype] 2818 2819 for id_trip, id_route, speed_inmotion in zip(ids_trip_vtype, self.ids_route_matched[ids_trip_vtype], speeds_in_motion[ids_trip_vtype]): 2820 route_matched = routes.ids_edges[id_route] 2821 # print ' id_trip,speed_inmotion',id_trip,speed_inmotion 2822 times[ids_edge] = dists_orig[ids_edge]/speed_inmotion + edgewaittimes 2823 weights[ids_edge] = (times[ids_edge] - specifictimes)*specificfactors 2824 # weights[ids_edge] -= 2825 # weights[ids_edge] *= 2826 2827 # compute time wit speed in motion and add waiting time of tonode 2828 cost, route = routing.get_mincostroute_edge2edge(route_matched[0], 2829 route_matched[-1], 2830 weights=weights, 2831 fstar=fstar) 2832 if len(route) > 0: 2833 # ids_edges.append(route) 2834 # ids_trip.append(id_trip) 2835 # costs.append(cost) 2836 2837 id_route = self.ids_route_shortest[id_trip] 2838 if id_route >= 0: 2839 # there is already a previous shortest route 2840 routes.set_row(id_route, 2841 #ids_edges = list(route), 2842 costs=cost, 2843 colors=color_route, 2844 ) 2845 # TODO!!! this assigment does not work in set_row!!!! 2846 # tales only first edge !! why?? 2847 routes.ids_edges[id_route] = route 2848 # print ' old route',id_route,type(route) 2849 else: 2850 # create new route 2851 id_route = routes.add_row(ids_trip=id_trip, 2852 ids_edges=route, 2853 costs=cost, 2854 colors=color_route, 2855 ) 2856 self.ids_route_fastest[id_trip] = id_route 2857 # print ' new route',type(route) 2858 2859 self.lengths_route_fastest[id_trip] = np.sum(dists_orig[route]) 2860 self.durations_route_fastest[id_trip] = np.sum(times[route]) 2861 self.timelosses_route_fastest[id_trip] = np.sum( 2862 times[route_matched])-self.durations_route_fastest[id_trip] 2863 # print ' route', route 2864 # print ' times',times[route] 2865 # print ' routes.ids_edges' ,routes.ids_edges[id_route] 2866 2867 print ' exectime', time.clock()-exectime_start 2868 2869 def route_fastest(self, time_modespecific=3.0, c_modespecific=0.9, 2870 is_ignor_connections=False, color_route=COLOR_FASTEST_ROUTE.copy()): 2871 """ 2872 Shortest fastest routing. 2873 """ 2874 print 'route_fastest', time_modespecific, c_modespecific 2875 # TODO: if too mant vtypes, better go through id_modes 2876 exectime_start = time.clock() 2877 scenario = self.parent.get_scenario() 2878 net = scenario.net 2879 edges = net.edges 2880 vtypes = scenario.demand.vtypes 2881 routes = self.get_routes() 2882 2883 timesmap = self.parent.get_timesmap() 2884 #distancesmap = self.parent.get_distancesmap() 2885 accesslevelsmap = self.parent.get_accesslevelsmap() 2886 2887 fstar = edges.get_fstar(is_ignor_connections=is_ignor_connections) 2888 for id_vtype in self.get_vtypes(): 2889 id_mode = vtypes.ids_mode[id_vtype] 2890 2891 # no routing for pedestrians 2892 if id_mode != net.modes.get_id_mode('pedestrian'): 2893 #dists = distancesmap[id_mode] 2894 times_orig = timesmap[id_mode].copy() 2895 2896 # TODO: needs to be improved with default junction waits 2897 weights = times_orig.copy() 2898 2899 # this will subtract some meters dependent on 2900 2901 accesslevels = accesslevelsmap[id_mode] 2902 ids_edge = edges.get_ids() 2903 are_valid = weights > 3*time_modespecific 2904 2905 weights[ids_edge] -= time_modespecific * are_valid[ids_edge] * accesslevels[ids_edge] 2906 weights[ids_edge] *= 1 - (1-c_modespecific) * are_valid[ids_edge] * (accesslevels[ids_edge] == 2) 2907 2908 ids_trip_vtype = self.select_ids(np.logical_and(self.ids_vtype.get_value( 2909 ) == id_vtype, self.are_selected.get_value(), self.ids_route_matched.get_value() >= 0)) 2910 #ids_trip_vtype = self.get_trips_for_vtype(id_vtype) 2911 # print ' id_vtype,id_mode',id_vtype,id_mode#,ids_trip_vtype 2912 # print ' weights',weights 2913 2914 #ids_edge_depart = self.ids_edge_depart[ids_trip_vtype] 2915 #ids_edge_arrival = self.ids_edge_arrival[ids_trip_vtype] 2916 2917 for id_trip, id_route in zip(ids_trip_vtype, self.ids_route_matched[ids_trip_vtype]): 2918 route_matched = routes.ids_edges[id_route] 2919 2920 cost, route = routing.get_mincostroute_edge2edge(route_matched[0], 2921 route_matched[-1], 2922 weights=weights, 2923 fstar=fstar, 2924 ) 2925 2926 if len(route) > 0: 2927 # ids_edges.append(route) 2928 # ids_trip.append(id_trip) 2929 # costs.append(cost) 2930 2931 id_route = self.ids_route_fastest[id_trip] 2932 if id_route >= 0: 2933 # there is already a previous shortest route 2934 routes.set_row(id_route, 2935 #ids_edges = list(route), 2936 costs=cost, 2937 colors=color_route, 2938 ) 2939 # TODO!!! this assigment does not work in set_row!!!! 2940 # tales only first edge !! why?? 2941 routes.ids_edges[id_route] = route 2942 # print ' old route',id_route,type(route) 2943 else: 2944 # create new route 2945 id_route = routes.add_row(ids_trip=id_trip, 2946 ids_edges=route, 2947 costs=cost, 2948 colors=color_route, 2949 ) 2950 self.ids_route_fastest[id_trip] = id_route 2951 # print ' new route',type(route) 2952 2953 self.durations_route_fastest[id_trip] = np.sum(times_orig[route]) 2954 self.timelosses_route_fastest[id_trip] = np.sum( 2955 times_orig[route_matched])-self.durations_route_fastest[id_trip] 2956 print ' route', route 2957 print ' routes.ids_edges', routes.ids_edges[id_route] 2958 2959 print ' exectime', time.clock()-exectime_start 2960 2961 def route_shortest(self, dist_modespecific=5.0, c_modespecific=0.9, 2962 is_ignor_connections=False, dist_min_modespecific=15.0, 2963 color_route=None): 2964 """ 2965 Shortest path routing. 2966 """ 2967 print 'route_shortest', dist_modespecific, c_modespecific 2968 # TODO: if too mant vtypes, better go through id_modes 2969 exectime_start = time.clock() 2970 scenario = self.parent.get_scenario() 2971 net = scenario.net 2972 edges = net.edges 2973 vtypes = scenario.demand.vtypes 2974 routes = self.get_routes() 2975 #ids_edges = [] 2976 #ids_trip = [] 2977 #costs = [] 2978 2979 distancesmap = self.parent.get_distancesmap() 2980 accesslevelsmap = self.parent.get_accesslevelsmap() 2981 2982 # delete current 2983 #ids_with_shortes = self.select_ids(np.logical_and(self.are_selected.get_value(), self.ids_route_shortest.get_value()>=0)) 2984 # routes.del_rows(self.ids_route_shortest[ids_with_shortes]) 2985 #self.ids_route_shortest[ids_with_shortes] = -1 2986 2987 fstar = edges.get_fstar(is_ignor_connections=is_ignor_connections) 2988 for id_vtype in self.get_vtypes(): 2989 id_mode = vtypes.ids_mode[id_vtype] 2990 2991 # no routing for pedestrians 2992 if id_mode != net.modes.get_id_mode('pedestrian'): 2993 dists_orig = distancesmap[id_mode].copy() 2994 weights = dists_orig.copy() 2995 2996 # this will subtract some meters dependent on 2997 # access-level of the edge 2998 accesslevels = accesslevelsmap[id_mode] 2999 ids_edge = edges.get_ids() 3000 are_valid = weights > dist_min_modespecific 3001 weights[ids_edge] -= dist_modespecific * are_valid[ids_edge] * accesslevels[ids_edge] 3002 weights[ids_edge] *= 1 - (1-c_modespecific) * are_valid[ids_edge] * (accesslevels[ids_edge] == 2) 3003 3004 ids_trip_vtype = self.select_ids(np.logical_and(self.ids_vtype.get_value( 3005 ) == id_vtype, self.are_selected.get_value(), self.ids_route_matched.get_value() >= 0)) 3006 #ids_trip_vtype = self.get_trips_for_vtype(id_vtype) 3007 # print ' id_vtype,id_mode',id_vtype,id_mode#,ids_trip_vtype 3008 # print ' weights',weights 3009 3010 #ids_edge_depart = self.ids_edge_depart[ids_trip_vtype] 3011 #ids_edge_arrival = self.ids_edge_arrival[ids_trip_vtype] 3012 3013 for id_trip, id_route in zip(ids_trip_vtype, self.ids_route_matched[ids_trip_vtype]): 3014 route_matched = routes.ids_edges[id_route] 3015 3016 cost, route = routing.get_mincostroute_edge2edge(route_matched[0], 3017 route_matched[-1], 3018 weights=weights, 3019 fstar=fstar) 3020 if len(route) > 0: 3021 # ids_edges.append(route) 3022 # ids_trip.append(id_trip) 3023 # costs.append(cost) 3024 3025 id_route = self.ids_route_shortest[id_trip] 3026 if id_route >= 0: 3027 # there is already a previous shortest route 3028 routes.set_row(id_route, 3029 #ids_edges = list(route), 3030 costs=cost, 3031 colors=color_route, 3032 ) 3033 # TODO!!! this assigment does not work in set_row!!!! 3034 # tales only first edge !! why?? 3035 routes.ids_edges[id_route] = route 3036 # print ' old route',id_route,type(route) 3037 else: 3038 # create new route 3039 id_route = routes.add_row(ids_trip=id_trip, 3040 ids_edges=route, 3041 costs=cost, 3042 colors=color_route, 3043 ) 3044 self.ids_route_shortest[id_trip] = id_route 3045 # print ' new route',type(route) 3046 3047 self.lengths_route_shortest[id_trip] = np.sum(dists_orig[route]) 3048 # print ' route', route 3049 # print ' routes.ids_edges' ,routes.ids_edges[id_route] 3050 3051 print ' exectime', time.clock()-exectime_start 3052 3053 def get_ids_edge_matched(self, id_trip): 3054 return self.get_routes().ids_edges[self.ids_route_matched[id_trip]] 3055 3056 def get_speedprofile(self, id_trip): 3057 """ 3058 NOT USED!!?? 3059 """ 3060 3061 points = self.parent.points 3062 ids_point = self.ids_points[id_trip] 3063 ids_point_edgeend = self.ids_points_edgeend[id_trip] 3064 ids_edge = self.get_routes().ids_edges[self.ids_route_matched[id_trip]] 3065 id_edge_current = -1 3066 n_edges = len(ids_edge) 3067 3068 positions_gps = [] 3069 times_gps = [] 3070 ids_edges_profile = [] 3071 ids_nodes_profile = [] 3072 3073 for id_point, coord, timestamp in zip(ids_point, points.coords[ids_point], points.timestamps[ids_point]): 3074 #get_pos_from_coord(id_edge_current, coord) 3075 3076 if id_point in ids_point_edgeend: 3077 ind = ids_point_edgeend.index(id_point) 3078 if ind == n_edges-1: 3079 id_edge_current = -1 3080 else: 3081 id_edge_current = ids_edge[ind+1] 3082 3083 def get_flows(self, is_shortest_path=False): 3084 """ 3085 Determine the total number of vehicles for each edge. 3086 returns ids_edge and flows 3087 """ 3088 ids_edges = self.get_routes.ids_edges 3089 counts = np.zeros(np.max(self.get_net().edges.get_ids())+1, int) 3090 3091 ids_trip = self.get_ids_selected() 3092 if not is_shortest_path: 3093 ids_route = self.ids_route_matched[ids_trip] 3094 else: 3095 ids_route = self.ids_route_shortest[ids_trip] 3096 inds_valid = np.flatnonzero(ids_route > 0) 3097 for id_trip, id_route in zip(ids_trip[inds_valid], ids_route[inds_valid]): 3098 counts[ids_edges[id_route][:]] += 1 3099 3100 ids_edge = np.flatnonzero(counts) 3101 3102 return ids_edge, counts[ids_edge].copy() 3103 3104 def get_ids_route_selected(self): 3105 # TODO: here we could append direct routes 3106 print 'get_ids_route_selected' 3107 ids_route_matched = self.ids_route_matched[self.get_ids_selected()] 3108 ids_route_shortest = self.ids_route_shortest[self.get_ids_selected()] 3109 ids_route_fastest = self.ids_route_fastest[self.get_ids_selected()] 3110 # print ' ids_route_matched.dtype',ids_route_matched.dtype 3111 # print ' ids_route_shortest.dtype',ids_route_shortest.dtype 3112 # print ' ids_route_matched[ids_route_matched >= 0] ',ids_route_matched[ids_route_matched >= 0] 3113 return np.concatenate([ids_route_matched[ids_route_matched >= 0], 3114 ids_route_shortest[ids_route_shortest >= 0], 3115 ids_route_fastest[ids_route_fastest >= 0]]) 3116 # return ids_route_matched[ids_route_matched >= 0] 3117 3118 3119class GpsPoints(am.ArrayObjman): 3120 """ 3121 Contains data of points of a single trace. 3122 """ 3123 3124 def __init__(self, ident, mapmatching, **kwargs): 3125 # print 'PrtVehicles vtype id_default',vtypes.ids_sumo.get_id_from_index('passenger1') 3126 self._init_objman(ident=ident, 3127 parent=mapmatching, 3128 name='GPS Points', 3129 info='GPS points database.', 3130 version=0.0, 3131 **kwargs) 3132 3133 self._init_attributes() 3134 self._init_constants() 3135 3136 def _init_attributes(self): 3137 scenario = self.get_scenario() 3138 3139 # ident is the path id of the trace 3140 3141 # the actual numpy arrays are stored in .cols 3142 self.add_col(am.ArrayConf('longitudes', default=0.0, 3143 dtype=np.float32, 3144 groupnames=['parameters', ], 3145 perm='rw', 3146 name='Longitude', 3147 symbol='Lon', 3148 unit='deg', 3149 info='Longitude of point', 3150 )) 3151 3152 self.add_col(am.ArrayConf('latitudes', default=0.0, 3153 groupnames=['parameters', ], 3154 dtype=np.float32, 3155 perm='rw', 3156 name='Latitude', 3157 symbol='Lat', 3158 unit='deg', 3159 info='Latitude of point', 3160 )) 3161 3162 self.add_col(am.ArrayConf('altitudes', default=-100000.0, 3163 groupnames=['parameters', ], 3164 dtype=np.float32, 3165 perm='rw', 3166 name='Altitude', 3167 symbol='Alt', 3168 unit='m', 3169 info='Altitude of point', 3170 )) 3171 3172 self.add_col(am.ArrayConf('radii', 10.0, 3173 dtype=np.float32, 3174 groupnames=['parameters', ], 3175 perm='rw', 3176 name='Radius', 3177 unit='m', 3178 info='Point radius, representing the imprecision of the point, which depends on the recording device ane the environment.', 3179 )) 3180 3181 self.add_col(am.ArrayConf('coords', default=[0.0, 0.0, 0.0], 3182 groupnames=['parameters', ], 3183 dtype=np.float32, 3184 perm='rw', 3185 name='Coordinate', 3186 symbol='x,y,z', 3187 unit='m', 3188 info='Local 3D coordinate of point', 3189 )) 3190 3191 self.add_col(am.ArrayConf('timestamps', default=0.0, 3192 dtype=np.float, 3193 groupnames=['parameters', ], 3194 perm='r', 3195 name='timestamp', 3196 symbol='t', 3197 metatype='datetime', 3198 unit='s', 3199 digits_fraction=2, 3200 info='Time stamp of point in seconds after 01 January 1970.', 3201 )) 3202 # test: 3203 self.timestamps.metatype = 'datetime' 3204 self.timestamps.set_perm('r') 3205 3206 def set_trips(self, trips): 3207 self.add_col(am.IdsArrayConf('ids_trip', trips, 3208 groupnames=['state'], 3209 name='Trip ID', 3210 info='ID of trips to which this point belongs to.', 3211 )) 3212 # put in geometry filter 3213 # self.add_col(am.ArrayConf( 'are_inside_boundary', default =False, 3214 # groupnames = ['parameters',], 3215 # perm='r', 3216 # name = 'in boundary', 3217 # info = 'True if this the data point is within the boundaries of the road network.', 3218 # )) 3219 3220 def get_ids_selected(self): 3221 """ 3222 Returns point ids of selected traces 3223 """ 3224 # print 'GpsPoints.get_ids_selected' 3225 # print ' ??ids_points = ',self.select_ids(self.parent.trips.are_selected[self.ids_trip.get_value()] ) 3226 # TODO: why is this working??? do we need trips.ids_points???? 3227 return self.select_ids(self.parent.trips.are_selected[self.ids_trip.get_value()]) 3228 # return self.get_ids()#self.select_ids(self.get_ids() 3229 # return self.select_ids( 3230 3231 def get_scenario(self): 3232 return self.parent.get_scenario() 3233 3234 def get_coords(self): 3235 """ 3236 Returns an array of x,y coordinates of all points. 3237 """ 3238 return self.coords.get_value() 3239 3240 def get_times(self): 3241 """ 3242 Returns an array of time stamps of all points. 3243 """ 3244 return self.timestamp.get_value() 3245 3246 def get_interval(self): 3247 if len(self) == 0: 3248 return [0.0, 0.0] 3249 else: 3250 timestamps = self.timestamps.get_value() 3251 return [timestamps.min(), timestamps.max()] 3252 3253 def get_duration(self): 3254 ts, te = self.get_interval() 3255 return te-ts 3256 3257 def get_distance(self): 3258 v = self.get_coords() 3259 # return np.linalg.norm( self.cols.coords[0:-1] - self.cols.coords[1:] ) 3260 return np.sum(np.sqrt((v[1:, 0]-v[0:-1, 0])**2 + (v[1:, 1]-v[0:-1, 1])**2)) 3261 3262 def get_boundary(self): 3263 if len(self) == 0: 3264 return [0, 0, 0, 0] 3265 else: 3266 x_min, y_min = self.get_coords().min(0) 3267 x_max, y_max = self.get_coords().max(0) 3268 3269 return [x_min, y_min, x_max, y_max] 3270 3271 def project(self, proj=None, offset=None): 3272 if proj is None: 3273 proj, offset = self.parent.get_proj_and_offset() 3274 x, y = proj(self.longitudes.get_value(), self.latitudes.get_value()) 3275 self.get_coords()[:] = np.transpose(np.concatenate( 3276 ([x+offset[0]], [y+offset[1]], [self.altitudes.get_value()]), axis=0)) 3277 3278 3279class GpsPersons(am.ArrayObjman): 3280 3281 def __init__(self, ident, mapmatching, **kwargs): 3282 # print 'PrtVehicles vtype id_default',vtypes.ids_sumo.get_id_from_index('passenger1') 3283 self._init_objman(ident=ident, 3284 parent=mapmatching, 3285 name='GPS Persons', 3286 info='GPS person database.', 3287 version=0.2, 3288 **kwargs) 3289 3290 self._init_attributes() 3291 3292 def _init_attributes(self): 3293 trips = self.parent.trips 3294 3295 # TODO: add/update vtypes here 3296 self.add_col(SumoIdsConf('User', xmltag='id')) 3297 3298 self.add_col(am.ArrayConf('ids_gender', default=-1, 3299 dtype=np.int32, 3300 groupnames=['parameters'], 3301 choices=GENDERS, 3302 name='Gender', 3303 info='Gender of person.', 3304 )) 3305 3306 self.add_col(am.ArrayConf('years_birth', default=-1, 3307 dtype=np.int32, 3308 groupnames=['parameters'], 3309 name='Birth year', 3310 info='Year when person has been born.', 3311 )) 3312 3313 self.add_col(am.ArrayConf('ids_occupation', default=OCCUPATIONS['unknown'], 3314 dtype=np.int32, 3315 choices=OCCUPATIONS, 3316 groupnames=['parameters'], 3317 name='occupation', 3318 info='Tupe of occupation', 3319 )) 3320 3321 self.add_col(am.ArrayConf('are_frequent_user', False, 3322 dtype=np.bool, 3323 groupnames=['parameters'], 3324 name='frequent user', 3325 info='If true, this person is a frequent user of the recorded transport mode.', 3326 )) 3327 3328 # change from int ti string 3329 print 'GpsPersons.versio,', self.get_version(), self.get_version() < 0.2 3330 3331 if hasattr(self, 'zips'): 3332 # print ' zips',self.zips.get_value().dtype,self.zips.get_value() 3333 if self.zips.get_value().dtype in [np.dtype(np.int32), np.dtype(np.int64)]: 3334 print 'WARNING: delete old person.zips' 3335 self.delete('zips') 3336 3337 # if self.get_version()<0.2: 3338 # #if hasattr(self,'zips'): 3339 # self.delete('zips') 3340 3341 self.add_col(am.ArrayConf('zips', '', 3342 dtype=np.object, 3343 groupnames=['parameters'], 3344 name='ZIP', 3345 info="ZIP code of person's home.", 3346 )) 3347 3348 self.add_col(am.IdlistsArrayConf('ids_trips', trips, 3349 #groupnames = ['_private'], 3350 name='Trip IDs', 3351 info="IDs of trips made by this vehicle. This is a collection of recorded trips associated with this person.", 3352 )) 3353 3354 self.add_col(am.ArrayConf('numbers_tot_trip_gps', 0, 3355 dtype=np.int32, 3356 groupnames=['results'], 3357 name='tot. trips', 3358 symbol='N tot GPS', 3359 info='Total number of recorded GPS traces.', 3360 )) 3361 3362 self.add_col(am.ArrayConf('lengths_tot_route_gps', 0.0, 3363 dtype=np.float32, 3364 groupnames=['results'], 3365 name='tot. GPS length', 3366 symbol='L tot GPS', 3367 unit='m', 3368 info='Total distances of recorded GPS traces.', 3369 )) 3370 self.add_col(am.ArrayConf('times_tot_route_gps', 0.0, 3371 dtype=np.float32, 3372 groupnames=['results'], 3373 name='Tot. GPS time', 3374 symbol='T tot GPS', 3375 unit='s', 3376 info='Total trip times of recorded GPS traces.', 3377 )) 3378 3379 self.add_col(am.ArrayConf('speeds_av_gps', 0.0, 3380 dtype=np.float32, 3381 groupnames=['results'], 3382 name='Tot. GPS time', 3383 symbol='V avg GPS', 3384 unit='m/s', 3385 info='Average speed of recorded GPS traces.', 3386 )) 3387 3388 self.add_col(am.ArrayConf('numbers_tot_trip_mached', 0, 3389 dtype=np.int32, 3390 groupnames=['results'], 3391 name='tot. trips', 3392 symbol='N tot match', 3393 info='Total number of recorded GPS traces.', 3394 )) 3395 3396 self.add_col(am.ArrayConf('lengths_tot_route_matched', default=-1.0, 3397 dtype=np.float32, 3398 groupnames=['results'], 3399 name='Tot. matched length', 3400 symbol='L tot match', 3401 unit='m', 3402 info='Total length of the matched parts of the GPS traces, measured by summing the length of edges of the matched route. Note the only a fraction of the GPS trace ma be within the given network.', 3403 )) 3404 3405 # self.add_col(am.ArrayConf('times_tot_route_matched', default = -1.0, 3406 # dtype = np.float32, 3407 # groupnames = ['results'], 3408 # name = 'Tot. matched duration', 3409 # symbol = 'T tot match', 3410 # unit = 's', 3411 # info = 'Total duration of all matched part of the GPS trace. This is the difference in timestamps between last and first GPS point of the matched route. Note the only a fraction of the GPS trace ma be within the given network.', 3412 # )) 3413 3414 self.add_col(am.ArrayConf('lengths_tot_route_shortest', default=-1.0, 3415 dtype=np.float32, 3416 groupnames=['results'], 3417 name='Tot. shortest length', 3418 symbol='L tot short', 3419 unit='m', 3420 info='Total length of the shortest routes. Shortest route is connecting the first matched edge and the final matched edge.', 3421 )) 3422 3423 self.add_col(am.ArrayConf('lengths_tot_route_matched_mixed', default=-1.0, 3424 dtype=np.float32, 3425 groupnames=['results'], 3426 name='Tot. matched length mixed access', 3427 symbol='L tot match mix', 3428 unit='m', 3429 info='Total length of the matched part of the GPS traces. Note the only a fraction of the GPS trace ma be within the given network.', 3430 )) 3431 3432 self.add_col(am.ArrayConf('lengths_tot_route_matched_exclusive', default=-1.0, 3433 dtype=np.float32, 3434 groupnames=['results'], 3435 name='Matched length exclusive access', 3436 symbol='L tot match excl', 3437 unit='m', 3438 info='Length of the matched part of the GPS trace. Note the only a fraction of the GPS trace ma be within the given network.', 3439 )) 3440 3441 # upgrade 3442 if hasattr(self, 'ids_genders'): 3443 self.delete('ids_genders') 3444 3445 def analyze(self): 3446 print 'Persons.analyze' 3447 # ids_person = self.select_ids(self.) 3448 trips = self.parent.trips 3449 points = self.parent.points 3450 npsum = np.sum 3451 3452 ids_person = self.get_ids() 3453 n_pers = len(ids_person) 3454 3455 numbers_tot_trip_gps = np.zeros(n_pers, dtype=np.int32) 3456 lengths_tot_route_gps = np.zeros(n_pers, dtype=np.float32) 3457 times_tot_route_gps = np.zeros(n_pers, dtype=np.float32) 3458 speeds_av_gps = np.zeros(n_pers, dtype=np.float32) 3459 numbers_tot_trip_mached = np.zeros(n_pers, dtype=np.int32) 3460 lengths_tot_route_matched = np.zeros(n_pers, dtype=np.float32) 3461 times_tot_route_matched = np.zeros(n_pers, dtype=np.float32) 3462 lengths_tot_route_shortest = np.zeros(n_pers, dtype=np.float32) 3463 lengths_tot_route_matched_mixed = np.zeros(n_pers, dtype=np.float32) 3464 lengths_tot_route_matched_exclusive = np.zeros(n_pers, dtype=np.float32) 3465 3466 timebudgets = -1*np.ones(n_pers, dtype=np.float32) 3467 3468 i = 0 3469 for id_person, ids_trip_all in zip(ids_person, self.ids_trips[ids_person]): 3470 # get selected trips only 3471 ids_trip = np.array(ids_trip_all)[trips.are_selected[ids_trip_all]] 3472 3473 numbers_tot_trip_gps[i] = len(ids_trip) 3474 # print ' id_person, ids_trip',id_person, ids_trip 3475 if len(ids_trip) > 0: 3476 3477 length_tot = npsum(trips.distances_gps[ids_trip]) 3478 time_tot = npsum(trips.durations_gps[ids_trip]) 3479 3480 lengths_tot_route_gps[i] = length_tot 3481 times_tot_route_gps[i] = time_tot 3482 if time_tot > 0: 3483 speeds_av_gps[i] = length_tot/time_tot 3484 3485 # do statistics on matched trips 3486 # print ' ids_route_shortest',trips.ids_route_shortest[ids_trip] 3487 # print ' inds',trips.ids_route_shortest[ids_trip]>=0 3488 ids_trip_matched = ids_trip[trips.ids_route_shortest[ids_trip] >= 0] 3489 if len(ids_trip_matched) > 0: 3490 numbers_tot_trip_mached[i] = len(ids_trip_matched) 3491 lengths_tot_route_matched[i] = npsum(trips.lengths_route_matched[ids_trip_matched]) 3492 #times_tot_route_matched[i] = npsum(trips.lengths_route_matched[ids_trip]) 3493 lengths_tot_route_shortest[i] = npsum(trips.lengths_route_shortest[ids_trip_matched]) 3494 lengths_tot_route_matched_mixed[i] = npsum(trips.lengths_route_matched_mixed[ids_trip_matched]) 3495 lengths_tot_route_matched_exclusive[i] = npsum( 3496 trips.lengths_route_matched_exclusive[ids_trip_matched]) 3497 3498 # do statistics time budget 3499 # coord0 = None#points.coords[ids_points[ids_trip[0]]] 3500 # date = None# points.timestamps[ids_points[ids_trip[0]]] 3501 # for ids_point in trips.ids_points[ids_trip]: 3502 # coord0 = None#points.coords[ids_points[ids_trip[0]]] 3503 # date = None# points.timestamps[ids_points[ids_trip[0]]] 3504 3505 i += 1 3506 3507 self.set_rows(ids_person, 3508 numbers_tot_trip_gps=numbers_tot_trip_gps, 3509 lengths_tot_route_gps=lengths_tot_route_gps, 3510 times_tot_route_gps=times_tot_route_gps, 3511 speeds_av_gps=speeds_av_gps, 3512 numbers_tot_trip_mached=numbers_tot_trip_mached, 3513 lengths_tot_route_matched=lengths_tot_route_matched, 3514 times_tot_route_matched=times_tot_route_matched, 3515 lengths_tot_route_shortest=lengths_tot_route_shortest, 3516 lengths_tot_route_matched_mixed=lengths_tot_route_matched_mixed, 3517 lengths_tot_route_matched_exclusive=lengths_tot_route_matched_exclusive, 3518 ) 3519 3520 def make(self, id_sumo, **kwargs): 3521 print 'make id_pers_sumo', id_sumo 3522 3523 id_trip = kwargs.get('id_trip', -1) 3524 if self.ids_sumo.has_index(id_sumo): 3525 # person exisis 3526 id_pers = self.ids_sumo.get_id_from_index(id_sumo) 3527 3528 if id_trip >= 0: 3529 self.ids_trips[id_pers].append(id_trip) 3530 3531 # debug 3532 # print ' exists id_pers',id_pers,self.ids_sumo[id_pers] 3533 #trips = self.parent.trips 3534 # for id_trip in self.ids_trips[id_pers]: 3535 # print ' id_trip',id_trip,trips.ids_sumo[id_trip] 3536 3537 #self.set_row(id_pers, **kwargs) 3538 return id_pers 3539 3540 else: 3541 # print 'make new person',kwargs 3542 # add new person 3543 # if id_trip >= 0: 3544 # ids_trip = [id_trip] 3545 # else: 3546 # ids_trip = [] 3547 3548 gender = kwargs.get('gender', '').lower() 3549 if gender == 'm': 3550 # print ' m gender=*%s*'%gender 3551 id_gender = GENDERS['male'] 3552 elif gender == 'f': 3553 # print ' f gender=*%s*'%gender 3554 id_gender = GENDERS['female'] 3555 else: 3556 # print ' u gender=*%s*'%gender 3557 id_gender = GENDERS['unknown'] 3558 3559 occupation = kwargs.get('occupation', '') 3560 occupation = occupation.lower() 3561 if occupation in ['None', '', 'unknown']: 3562 id_occupation = OCCUPATIONS['unknown'] 3563 elif occupation in OCCUPATIONS: 3564 id_occupation = OCCUPATIONS[occupation] 3565 else: 3566 id_occupation = OCCUPATIONS['other'] 3567 3568 id_pers = self.add_row(ids_sumo=id_sumo, 3569 ids_gender=id_gender, 3570 years_birth=kwargs.get('year_birth', None), 3571 ids_occupation=id_occupation, 3572 are_frequent_user=kwargs.get('is_frequent_user', None), 3573 zips=kwargs.get('zip', None), 3574 ) 3575 if id_trip >= 0: 3576 self.ids_trips[id_pers] = [id_trip] 3577 else: 3578 self.ids_trips[id_pers] = [] 3579 3580 # debug 3581 # print ' made id_pers',id_pers, self.ids_sumo[id_pers] 3582 #trips = self.parent.trips 3583 # for id_trip in self.ids_trips[id_pers]: 3584 # print ' id_trip',id_trip,trips.ids_sumo[id_trip] 3585 3586 return id_pers 3587 3588 3589class Mapmatching(DemandobjMixin, cm.BaseObjman): 3590 def __init__(self, ident, demand=None, 3591 name='Mapmatching', info='Mapmatching functionality.', 3592 **kwargs): 3593 3594 self._init_objman(ident=ident, parent=demand, 3595 name=name, info=info, **kwargs) 3596 3597 attrsman = self.set_attrsman(cm.Attrsman(self)) 3598 3599 self._init_attributes() 3600 self._init_constants() 3601 3602 def get_scenario(self): 3603 return self.parent.parent 3604 3605 def clear_all(self): 3606 self.trips.clear() 3607 self.points.clear() 3608 self.persons.clear() 3609 self._init_constants() 3610 3611 def _init_attributes(self): 3612 print 'Mapmatching._init_attributes' 3613 attrsman = self.get_attrsman() 3614 3615 self.points = attrsman.add(cm.ObjConf(GpsPoints('points', self))) 3616 self.trips = attrsman.add(cm.ObjConf(GpsTrips('trips', self))) 3617 self.points.set_trips(self.trips) 3618 self.persons = attrsman.add(cm.ObjConf(GpsPersons('persons', self))) 3619 3620 def _init_constants(self): 3621 self._proj = None 3622 self._segvertices_xy = None 3623 self._distancesmap = None 3624 self._timesmap = None 3625 self._accesslevelsmap = None 3626 3627 attrsman = self.get_attrsman() 3628 attrsman.do_not_save_attrs(['_segvertices_xy', '_proj', '_distancesmap', '_timesmap', '_accesslevelsmap']) 3629 3630 def clear_routes(self): 3631 self.trips.clear_routes() 3632 3633 def delete_unselected_trips(self): 3634 trips = self.trips 3635 points = self.points 3636 persons = self.persons 3637 3638 if len(persons) == 0: 3639 # no persons, just trips 3640 ids_del = trips.select_ids(np.logical_not(trips.are_selected.get_value())) 3641 3642 for ids_point in trips.ids_points[ids_del]: 3643 if ids_point is not None: 3644 points.del_rows(ids_point) 3645 trips.del_rows(ids_del) 3646 else: 3647 for ids_trip in persons.ids_trips[persons.get_ids()]: 3648 if ids_trip is not None: 3649 ids_del = np.array(ids_trip, dtype=np.int32)[np.logical_not(trips.are_selected[ids_trip])] 3650 for id_del, ids_point in zip(ids_del, trips.ids_points[ids_del]): 3651 ids_trip.remove(id_del) 3652 if ids_point is not None: 3653 points.del_rows(ids_point) 3654 3655 trips.del_rows(ids_del) 3656 3657 def get_proj_and_offset(self): 3658 if self._proj is None: 3659 net = self.get_scenario().net 3660 proj_params = str(net.get_projparams()) 3661 # try: 3662 self._proj = pyproj.Proj(proj_params) 3663 # except: 3664 # proj_params ="+proj=utm +zone=32 +ellps=WGS84 +datum=WGS84 +units=m +no_defs" 3665 # self._proj = pyproj.Proj(self.proj_params) 3666 3667 self._offset = net.get_offset() 3668 3669 return self._proj, self._offset 3670 3671 def get_segvertices_xy(self): 3672 if self._segvertices_xy is None: 3673 self._segvertices_xy = self.get_scenario().net.edges.get_segvertices_xy() 3674 3675 return self._segvertices_xy 3676 3677 def get_timesmap(self, is_check_lanes=False): 3678 """ 3679 Returns a dictionary where key is id_mode and 3680 value is a distance-lookup table, mapping id_edge to edge distance 3681 """ 3682 # print 'get_timesmap',self._distancesmap is None 3683 3684 if self._timesmap is None: 3685 3686 vtypes = self.get_scenario().demand.vtypes 3687 edges = self.get_scenario().net.edges 3688 ids_vtype = self.trips.ids_vtype[self.trips.get_ids_selected()] 3689 ids_mode = vtypes.ids_mode[ids_vtype] 3690 # print ' ids_mode',ids_mode 3691 3692 self._timesmap = {} 3693 for id_mode in set(ids_mode): 3694 #ids_vtype_mode = vtypes.select_by_mode(id_mode) 3695 3696 self._timesmap[id_mode] = edges.get_times(id_mode=id_mode, 3697 is_check_lanes=is_check_lanes, 3698 ) 3699 3700 # print ' len(self._distancesmap)',len(self._distancesmap) 3701 return self._timesmap 3702 3703 def get_distancesmap(self, is_check_lanes=False): 3704 """ 3705 Returns a dictionary where key is id_mode and 3706 value is a distance-lookup table, mapping id_edge to edge distance 3707 """ 3708 # print 'get_distancesmap',self._distancesmap is None 3709 3710 if self._distancesmap is None: 3711 3712 vtypes = self.get_scenario().demand.vtypes 3713 edges = self.get_scenario().net.edges 3714 ids_vtype = self.trips.ids_vtype[self.trips.get_ids_selected()] 3715 ids_mode = vtypes.ids_mode[ids_vtype] 3716 # print ' ids_mode',ids_mode 3717 3718 self._distancesmap = {} 3719 for id_mode in set(ids_mode): 3720 #ids_vtype_mode = vtypes.select_by_mode(id_mode) 3721 3722 self._distancesmap[id_mode] = edges.get_distances(id_mode=id_mode, 3723 is_check_lanes=is_check_lanes, 3724 ) 3725 3726 # print ' len(self._distancesmap)',len(self._distancesmap) 3727 return self._distancesmap 3728 3729 def get_accesslevelsmap(self): 3730 """ 3731 Returns a dictionary where key is id_mode and 3732 value is a distance-lookup table, mapping id_edge to edge distance 3733 """ 3734 3735 if self._accesslevelsmap is None: 3736 vtypes = self.get_scenario().demand.vtypes 3737 edges = self.get_scenario().net.edges 3738 ids_vtype = self.trips.ids_vtype[self.trips.get_ids_selected()] 3739 ids_mode = vtypes.ids_mode[ids_vtype] 3740 3741 self._accesslevelsmap = {} 3742 for id_mode in set(ids_mode): 3743 #ids_vtype_mode = vtypes.select_by_mode(id_mode) 3744 self._accesslevelsmap[id_mode] = edges.get_accesslevels(id_mode) 3745 return self._accesslevelsmap 3746 3747 3748class Matchresults(cm.BaseObjman): 3749 def __init__(self, ident, mapmatching, 3750 name='Mapmatching results', 3751 info='Results of mapmatching analysis.', 3752 **kwargs): 3753 3754 # make results a child of process or of wxgui 3755 # use these objects to access matched trips 3756 3757 self._init_objman(ident, parent=mapmatching, name=name, 3758 info=info, **kwargs) 3759 attrsman = self.set_attrsman(cm.Attrsman(self)) 3760 3761 self._init_attributes() 3762 3763 def _init_attributes(self): 3764 attrsman = self.get_attrsman() 3765 mapmatching = self.parent 3766 # self.routesresults = attrsman.add(cm.ObjConf( Routesresults('routesresults', 3767 # self, mapmatching.trips.routes), 3768 # groupnames = ['Route results'], 3769 # )) 3770 3771 # add trip results from all demand objects 3772 # print 'Matchresults._init_attributes' 3773 3774 def config(self, resultobj, **kwargs): 3775 # attention: need to check whether already set 3776 # because setattr is set explicitely after add 3777 if not hasattr(self, resultobj.get_ident()): 3778 if kwargs.has_key('groupnames'): 3779 kwargs['groupnames'].append('Results') 3780 else: 3781 kwargs['groupnames'] = ['Results'] 3782 attrsman = self.get_attrsman() 3783 attrsman.add(cm.ObjConf(resultobj, **kwargs)) 3784 setattr(self, resultobj.get_ident(), resultobj) 3785 3786 def get_scenario(self): 3787 return self.parent.get_scenario() 3788 3789 def clear_all(self): 3790 self.clear() 3791 3792 def save(self, filepath=None, is_not_save_parent=True): 3793 if filepath is None: 3794 self.get_scenario().get_rootfilepath()+'.mmatch.obj' 3795 # parent will not be saved because in no_save set 3796 cm.save_obj(self, filepath, is_not_save_parent=is_not_save_parent) 3797 3798 3799class Nodesresults(am.ArrayObjman): 3800 def __init__(self, ident, parent, 3801 name='Node results', 3802 info='Table with data from matched traces on different node types.', 3803 **kwargs): 3804 3805 self._init_objman(ident=ident, 3806 parent=parent, # main results object 3807 info=info, 3808 name=name, 3809 **kwargs) 3810 3811 self.add_col(am.IdsArrayConf('ids_node', parent.get_scenario().net.nodes, 3812 groupnames=['state'], 3813 is_index=True, 3814 name='Node ID', 3815 info='ID of network node.', 3816 )) 3817 3818 # rdundant 3819 # self.add_col(am.ArrayConf('types', default = 0.0, 3820 # dtype = np.int32, 3821 # choices = parent.get_scenario().net.nodes.types.choices.copy() , 3822 # groupnames = ['results'], 3823 # name = 'Node type', 3824 # is_index = True, 3825 # info = 'Node type.', 3826 # )) 3827 3828 self._init_attributes() 3829 3830 def _init_attributes(self): 3831 3832 self.add_col(am.ArrayConf('times_wait', default=0.0, 3833 dtype=np.float32, 3834 groupnames=['results'], 3835 name='wait time', 3836 unit='s', 3837 info='Average wait times at this node.', 3838 )) 3839 self.add_col(am.ArrayConf('numbers_tot_matched', default=0, 3840 dtype=np.int32, 3841 groupnames=['results'], 3842 name='number matched', 3843 info='Total number of matched routes crossing this node.', 3844 )) 3845 3846 def get_nodes_significant(self, ids_node_raw=None, 3847 n_lane_in_min=2, n_lane_out_min=2): 3848 """ 3849 Returns an array with significant nodes where wait times 3850 can be expected. 3851 """ 3852 nodes = self.ids_node.get_linktab() 3853 net = nodes.parent 3854 lanes = net.lanes 3855 edges = net.edges 3856 if ids_node_raw is None: 3857 ids_node_raw = nodes.get_ids() 3858 3859 ids_node = [] 3860 id_mode_ped = net.modes.get_id_mode('pedestrian') 3861 id_ped_allow = [id_mode_ped] 3862 for id_node, type, ids_incoming, ids_outgoing, id_tls in zip( 3863 ids_node_raw, 3864 nodes.types[ids_node_raw], 3865 nodes.ids_incoming[ids_node_raw], 3866 nodes.ids_outgoing[ids_node_raw], 3867 nodes.ids_tls[ids_node_raw]): 3868 3869 if (ids_incoming is not None) & (ids_outgoing is not None): 3870 n_in = len(ids_incoming) 3871 n_out = len(ids_outgoing) 3872 for ids_lane in edges.ids_lanes[ids_incoming]: 3873 if len(ids_lane) == 1: 3874 if lanes.ids_modes_allow[ids_lane[0]] == id_ped_allow: 3875 n_in -= 1 3876 for ids_lane in edges.ids_lanes[ids_outgoing]: 3877 if len(ids_lane) == 1: 3878 if lanes.ids_modes_allow[ids_lane[0]] == id_ped_allow: 3879 n_out -= 1 3880 if (n_in >= n_lane_in_min) & (n_out >= n_lane_out_min): 3881 ids_node.append(id_node) 3882 return ids_node 3883 3884 def get_times_wait_est(self): 3885 """ 3886 Estimate wait times at all nodes. 3887 Returns an array times_wait_est such that 3888 the average wait tie at node id_node is 3889 times_wait_est[id_node] 3890 """ 3891 print 'get_times_wait_est' 3892 nodes = self.ids_node.get_linktab() 3893 ids_node = nodes.get_ids() 3894 ids_node_signif = self.get_nodes_significant() 3895 #nodetypes = nodes.types[ids_node_signif] 3896 map_nodetype_to_times_wait = self.get_map_nodetype_to_times_wait() 3897 3898 print ' map_nodetype_to_times_wait', map_nodetype_to_times_wait 3899 3900 times_wait = np.zeros(max(ids_node)+1, dtype=np.int32) 3901 print ' ', np.min(nodes.types[ids_node_signif]), np.max(nodes.types[ids_node_signif]) 3902 3903 times_wait[ids_node_signif] = map_nodetype_to_times_wait[nodes.types[ids_node_signif]] 3904 3905 # for nodetype, time_wait in map_nodetype_to_times_wait.iteritems(): 3906 # times_wait[ids_node_signif[nodetypes == nodetype]] = time_wait 3907 return times_wait 3908 3909 def get_map_nodetype_to_times_wait(self): 3910 print 'get_map_nodetype_to_times_wait' 3911 nodes = self.ids_node.get_linktab() 3912 ids_res = self.get_ids() 3913 nodetypes = nodes.types[self.ids_node[ids_res]] 3914 nodetypeset = nodes.types.choices.values() 3915 #map_type_to_typename = get_inversemap(nodes.types.choices) 3916 #map_type_to_times_wait = {} 3917 map_type_to_times_wait = np.zeros(max(nodetypeset)+1, dtype=np.float32) 3918 for thistype in nodetypeset: 3919 inds_res = np.flatnonzero(nodetypes == thistype) 3920 if len(inds_res) > 0: 3921 map_type_to_times_wait[thistype] = np.mean(self.times_wait[ids_res[inds_res]]) 3922 3923 return map_type_to_times_wait 3924 3925 3926class Edgesresults(am.ArrayObjman): 3927 def __init__(self, ident, parent, 3928 name='Edges results', 3929 info='Table with results from edges that are part of matched routes or alternative routes.', 3930 **kwargs): 3931 3932 self._init_objman(ident=ident, 3933 parent=parent, # main results object 3934 info=info, 3935 name=name, 3936 **kwargs) 3937 3938 # self.add(cm.AttrConf( 'datapathkey',datapathkey, 3939 # groupnames = ['_private'], 3940 # name = 'data pathkey', 3941 # info = "key of data path", 3942 # )) 3943 3944 self.add_col(am.IdsArrayConf('ids_edge', parent.get_scenario().net.edges, 3945 groupnames=['state'], 3946 is_index=True, 3947 name='Edge ID', 3948 info='ID of network edge.', 3949 )) 3950 self._init_attributes() 3951 3952 def _init_attributes(self): 3953 3954 self.add_col(am.ArrayConf('speeds_average', default=0.0, 3955 dtype=np.float32, 3956 groupnames=['results'], 3957 name='Avg. speed', 3958 unit='m/s', 3959 info='Average speed on this edge.', 3960 )) 3961 3962 self.add_col(am.ArrayConf('speeds_inmotion', default=0.0, 3963 dtype=np.float32, 3964 groupnames=['results'], 3965 name='Avg. speed in mot.', 3966 unit='m/s', 3967 info='Average speed in motion this edge.', 3968 )) 3969 3970 self.add_col(am.ArrayConf('durations_tot_matched', default=0.0, 3971 dtype=np.float32, 3972 groupnames=['results'], 3973 name='Tot. duration', 3974 unit='s', 3975 info='Total time of matched routes spent on this edge.', 3976 )) 3977 3978 self.add_col(am.ArrayConf('numbers_tot_matched', default=0, 3979 dtype=np.int32, 3980 groupnames=['results'], 3981 name='number matched', 3982 info='Total number of matched routes crossing this edge.', 3983 )) 3984 3985 self.add_col(am.ArrayConf('numbers_tot_shortest', default=0, 3986 dtype=np.int32, 3987 groupnames=['results'], 3988 name='number shortest', 3989 info='Total number of shortest routes crossing this edge.', 3990 )) 3991 3992 self.add_col(am.ArrayConf('numbers_tot_fastest', default=0, 3993 dtype=np.int32, 3994 groupnames=['results'], 3995 name='number fastest', 3996 info='Total number of fastest routes crossing this edge.', 3997 )) 3998 3999 self.add_col(am.ArrayConf('differences_dist_tot_shortest', default=0.0, 4000 dtype=np.float32, 4001 groupnames=['results'], 4002 name='Tot. short. length difference', 4003 unit='m', 4004 info='Sum of length differences between matched route length and the corrisponding shortest route using this edge.', 4005 )) 4006 4007 self.add_col(am.ArrayConf('differences_dist_tot_fastest', default=0.0, 4008 dtype=np.float32, 4009 groupnames=['results'], 4010 name='Tot. fast. length difference', 4011 unit='m', 4012 info='Sum of length differences between matched route length and the corrisponding fastest route using this edge.', 4013 )) 4014 4015 self.add_col(am.ArrayConf('probabilities_tot_matched', default=0.0, 4016 dtype=np.float32, 4017 groupnames=['results'], 4018 name='trip probab.', 4019 info='The probability that the edge has been used by the totality of all trips.', 4020 )) 4021 4022 self.add_col(am.ArrayConf('flows_est', default=0.0, 4023 dtype=np.float32, 4024 groupnames=['results'], 4025 name='Estim. Flows', 4026 unit='1/h', 4027 info='Estimated vehicle flows as a resukt of all trips.', 4028 )) 4029 4030 self.add_col(am.ArrayConf('times_wait', default=0.0, 4031 dtype=np.float32, 4032 groupnames=['results'], 4033 name='wait time', 4034 unit='s', 4035 info='Average wait times per vehicle passed on this edge, including stops at junctions or TLS.', 4036 )) 4037 4038 self.add_col(am.ArrayConf('times_wait_junc', default=0.0, 4039 dtype=np.float32, 4040 groupnames=['results'], 4041 name='wait time at junction', 4042 unit='s', 4043 info='Average wait times per vehicle at junction at the end of this edge.', 4044 )) 4045 4046 self.add_col(am.ArrayConf('times_wait_tls', default=0.0, 4047 dtype=np.float32, 4048 groupnames=['results'], 4049 name='wait time at TLS', 4050 unit='s', 4051 info='Average wait times per vehicle at a traffic light systems at the end of this edge.', 4052 )) 4053 4054 def init_for_routes(self, routes): 4055 """ 4056 Initializes a row for each edge ID in routes 4057 """ 4058 ids_edge_init = set() 4059 for ids_edge in routes.ids_edges.get_value(): 4060 if ids_edge is not None: 4061 ids_edge_init.update(ids_edge) 4062 ids_edge_init = list(ids_edge_init) 4063 # return result ids and respective edge ids 4064 ids_edgeresmap = np.zeros(np.max(ids_edge_init)+1, dtype=np.int32) 4065 ids_edgeresmap[ids_edge_init] = self.add_rows(n=len(ids_edge_init), ids_edge=ids_edge_init) 4066 4067 return ids_edgeresmap 4068 4069 4070class Routesresults(am.ArrayObjman): 4071 def __init__(self, ident, parent, 4072 name='Route results', 4073 info='Table with results from analysis of each matched route.', 4074 **kwargs): 4075 4076 self._init_objman(ident=ident, 4077 parent=parent, # main results object 4078 info=info, 4079 name=name, 4080 **kwargs) 4081 4082 # self.add(cm.AttrConf( 'datapathkey',datapathkey, 4083 # groupnames = ['_private'], 4084 # name = 'data pathkey', 4085 # info = "key of data path", 4086 # )) 4087 4088 self.add_col(am.IdsArrayConf('ids_route', parent.parent.trips.get_routes(), 4089 groupnames=['state'], 4090 is_index=True, 4091 name='ID route', 4092 info='ID of route.', 4093 )) 4094 self._init_attributes() 4095 4096 def _init_attributes(self): 4097 4098 self.add_col(am.ArrayConf('distances', default=-1.0, 4099 dtype=np.float32, 4100 groupnames=['results'], 4101 name='distance', 4102 unit='m', 4103 info='Length of the route.', 4104 )) 4105 4106 self.add_col(am.ArrayConf('durations', default=0.0, 4107 dtype=np.float32, 4108 groupnames=['results'], 4109 name='duration', 4110 unit='s', 4111 info='Time duration of the route.', 4112 )) 4113 4114 self.add_col(am.ArrayConf('lengths_mixed', default=-1.0, 4115 dtype=np.float32, 4116 groupnames=['results'], 4117 name='Length mixed access', 4118 symbol='L mix', 4119 unit='m', 4120 info='Length of roads with mixed access.', 4121 )) 4122 4123 self.add_col(am.ArrayConf('lengths_exclusive', default=-1.0, 4124 dtype=np.float32, 4125 groupnames=['results'], 4126 name='Length exclusive access', 4127 symbol='L excl', 4128 unit='m', 4129 info='Length of roads with exclusive access.', 4130 )) 4131 4132 self.add_col(am.ArrayConf('lengths_low_priority', default=-1.0, 4133 dtype=np.float32, 4134 groupnames=['results'], 4135 name='Length low priority', 4136 symbol='L lowprio', 4137 unit='m', 4138 info='Length of low priority roads. These are roads with either speed limit to 30 or below, or classified as residential, or exclusive bike or pedestrian ways. This correspond to SUMO priorities 1-6.', 4139 )) 4140 4141 self.add_col(am.ArrayConf('lengths_overlap_matched', default=-1.0, 4142 dtype=np.float32, 4143 groupnames=['results'], 4144 name='Length overlap', 4145 symbol='L overl', 4146 unit='m', 4147 info='Length of overlap with matched route.', 4148 )) 4149 4150 self.add_col(am.ArrayConf('numbers_nodes', default=-1, 4151 dtype=np.int32, 4152 groupnames=['results'], 4153 name='number of nodes', 4154 symbol='N nodes', 4155 info='Total number of nodes.', 4156 )) 4157 4158 self.add_col(am.ArrayConf('numbers_nodes_tls', default=-1, 4159 dtype=np.int32, 4160 groupnames=['results'], 4161 name='number of TL nodes', 4162 symbol='N TL', 4163 info='Total number of traffic light controlled nodes.', 4164 )) 4165 4166 self.add_col(am.ArrayConf('numbers_prioritychange', default=-1, 4167 dtype=np.int32, 4168 groupnames=['results'], 4169 name='number of prio. change', 4170 symbol='N prio', 4171 info='Total number of change in road priority.', 4172 )) 4173 4174 self.add_col(am.ArrayConf('times_inmotion', default=0.0, 4175 dtype=np.float32, 4176 groupnames=['results'], 4177 name='Time in motion', 4178 unit='s', 4179 info='Times while moving during the matched trip.', 4180 )) 4181 4182 self.add_col(am.ArrayConf('times_wait', default=0.0, 4183 dtype=np.float32, 4184 groupnames=['results'], 4185 name='wait time', 4186 unit='s', 4187 info='Wait times or times of low speed during the matched trip.', 4188 )) 4189 4190 self.add_col(am.ArrayConf('times_wait_tls', default=0.0, 4191 dtype=np.float32, 4192 groupnames=['results'], 4193 name='wait time at TLS', 4194 unit='s', 4195 info='Wait times or times of low speed at traffic lights during the matched trip.', 4196 )) 4197 4198 self.add_col(am.ListArrayConf('pointsspeeds', 4199 groupnames=['_private'], 4200 perm='rw', 4201 name='Point speeds', 4202 unit='m/s', 4203 info='List of velocities associated with each matched GPS of this route.', 4204 )) 4205 4206 self.add_col(am.ListArrayConf('pointspositions', 4207 groupnames=['_private'], 4208 perm='rw', 4209 name='Point positions', 4210 unit='m', 4211 info='List of point positions on edge associated with each matched GPS point of this route.', 4212 )) 4213 4214 self.add_col(am.ListArrayConf('pointstimes', 4215 groupnames=['_private'], 4216 perm='rw', 4217 name='Point times', 4218 unit='s', 4219 info='List of time points associated with each matched GPS point of this route. First point in routs has zero seconds.', 4220 )) 4221 4222 self.add_col(am.IdlistsArrayConf('ids_pointedges', self.parent.get_scenario().net.edges, 4223 groupnames=['results', '_private'], 4224 name='Point edge IDs', 4225 info="This is a list edge IDs corrisponding to each matched GPS point of this route.", 4226 )) 4227 4228 def get_speeds_inmotion(self, ids_routeres): 4229 return self.distances[ids_routeres]/self.times_inmotion[ids_routeres] 4230 4231 def get_speeds_inmotion_est(self): 4232 """ 4233 Estimate speeds in motion. 4234 Returns an array speeds_inmotion_est such that 4235 the average speed in motion of trip id_trip is 4236 speeds_inmotion_est[id_trip] 4237 """ 4238 routes = self.ids_route.get_linktab() 4239 4240 ids_routeres = self.get_ids() 4241 ids_trip = routes.ids_trip[self.ids_route[ids_routeres]] 4242 4243 speeds_inmotion_est = np.zeros(max(ids_trip)+1, dtype=np.float32) 4244 4245 #ids_trip_matched = self.ids_trip[ids_tripres] 4246 speeds_inmotion_est[ids_trip] = self.get_speeds_inmotion(ids_routeres) 4247 return speeds_inmotion_est 4248 4249 4250class Shortestrouter(Process): 4251 def __init__(self, ident, mapmatching, logger=None, **kwargs): 4252 print 'Shortestrouter.__init__' 4253 4254 # TODO: let this be independent, link to it or child?? 4255 4256 self._init_common(ident, 4257 parent=mapmatching, 4258 name='Shortest Router', 4259 logger=logger, 4260 info='Shortest path router.', 4261 ) 4262 4263 attrsman = self.set_attrsman(cm.Attrsman(self)) 4264 4265 self.c_modespecific = attrsman.add(cm.AttrConf('c_modespecific', kwargs.get('c_modespecific', 0.9), 4266 groupnames=['options'], 4267 perm='rw', 4268 name='Mode constant', 4269 info='The Mode constant is multiplied with the the distance of each edge if vehicle has exclusive access.', 4270 )) 4271 4272 self.dist_modespecific = attrsman.add(cm.AttrConf('dist_modespecific', kwargs.get('dist_modespecific', 0.0), 4273 groupnames=['options'], 4274 perm='rw', 4275 name='Mode dist', 4276 unit='m', 4277 info='This mode specific distance is multiplied with the access-level and subtracted from the edge distance in case the edge is exclusive for the mode of the matched trip.', 4278 )) 4279 4280 self.dist_min_modespecific = attrsman.add(cm.AttrConf('dist_min_modespecific', kwargs.get('dist_min_modespecific', 15.0), 4281 groupnames=['options'], 4282 perm='rw', 4283 name='Mode dist min', 4284 unit='m', 4285 info='Minimum edge distance for which mode specific modifications take place. This is to revent that a sum of very short edges with exclusive access causes the route to receive too much cost reduction.', 4286 )) 4287 4288 self.is_ignor_connections = attrsman.add(cm.AttrConf('is_ignor_connections', kwargs.get('is_ignor_connections', True), 4289 groupnames=['options'], 4290 perm='rw', 4291 name='Ignore connections', 4292 info='Ignore connections means that the vehicle can always make turns into all possible edges, whether they are allowed or not.', 4293 )) 4294 self.color_route = attrsman.add(cm.AttrConf('color_route', kwargs.get('color_route', COLOR_SHORTEST_ROUTE.copy()), 4295 groupnames=['options'], 4296 perm='wr', 4297 metatype='color', 4298 name='Route color', 4299 info='Color of matched routes used in various visualization tools.', 4300 )) 4301 4302 def do(self): 4303 print 'Shortestrouter.do' 4304 # links 4305 mapmatching = self.parent 4306 trips = mapmatching.trips 4307 trips.route_shortest(dist_modespecific=self.dist_modespecific, 4308 dist_min_modespecific=self.dist_min_modespecific, 4309 c_modespecific=self.c_modespecific, 4310 is_ignor_connections=self.is_ignor_connections, 4311 color_route=self.color_route, 4312 ) 4313 return True 4314 4315 4316class Fastestrouter(Process): 4317 def __init__(self, ident, mapmatching, logger=None, matchresults=None, **kwargs): 4318 print 'Fastestrouter.__init__' 4319 4320 # TODO: let this be independent, link to it or child?? 4321 4322 self._init_common(ident, 4323 parent=mapmatching, 4324 name='Fastest Router', 4325 logger=logger, 4326 info='Fastest path router.', 4327 ) 4328 4329 attrsman = self.set_attrsman(cm.Attrsman(self)) 4330 4331 self.matchresults = matchresults 4332 4333 self.c_modespecific = attrsman.add(cm.AttrConf('c_modespecific', kwargs.get('c_modespecific', 0.9), 4334 groupnames=['options'], 4335 perm='rw', 4336 name='Mode constant', 4337 info='The Mode constant is multiplied with the the distance of each edge if vehicle has exclusive access.', 4338 )) 4339 4340 self.time_modespecific = attrsman.add(cm.AttrConf('time_modespecific', kwargs.get('time_modespecific', 0.0), 4341 groupnames=['options'], 4342 perm='rw', 4343 name='Mode time', 4344 unit='s', 4345 info='This mode specific time is multiplied with the access-level and subtracted from the edge distance in case the edge is exclusive for the mode of the matched trip.', 4346 )) 4347 4348 self.dist_min_modespecific = attrsman.add(cm.AttrConf('dist_min_modespecific', kwargs.get('dist_min_modespecific', 15.0), 4349 groupnames=['options'], 4350 perm='rw', 4351 name='Mode dist min', 4352 unit='m', 4353 info='Minimum edge distance for which mode specific modifications take place. This is to revent that a sum of very short edges with exclusive access causes the route to receive too much cost reduction.', 4354 )) 4355 4356 self.is_ignor_connections = attrsman.add(cm.AttrConf('is_ignor_connections', kwargs.get('is_ignor_connections', True), 4357 groupnames=['options'], 4358 perm='rw', 4359 name='Ignore connections', 4360 info='Ignore connections means that the vehicle can always make turns into all possible edges, whether they are allowed or not.', 4361 )) 4362 self.color_route = attrsman.add(cm.AttrConf('color_route', kwargs.get('color_route', COLOR_FASTEST_ROUTE.copy()), 4363 groupnames=['options'], 4364 perm='wr', 4365 metatype='color', 4366 name='Route color', 4367 info='Color of fastest routes used in various visualization tools.', 4368 )) 4369 4370 if (self.matchresults is not None): 4371 if hasattr(self.matchresults, 'nodesresults'): 4372 self.is_use_nodeswaittimes_est = attrsman.add(cm.AttrConf('is_use_nodeswaittimes_est', kwargs.get('is_use_nodeswaittimes_est', True), 4373 groupnames=['options'], 4374 perm='rw', 4375 name='Use estimated waittime at nodes', 4376 info='If True, the average waittime at different node types are used.', 4377 #is_enabled = lambda self: self.nodesresults is not None, 4378 )) 4379 else: 4380 self.is_use_nodeswaittimes_est = False 4381 else: 4382 self.is_use_nodeswaittimes_est = False 4383 4384 def do(self): 4385 print 'Shortestrouter.do' 4386 # links 4387 mapmatching = self.parent 4388 trips = mapmatching.trips 4389 # map_nodetype_to_times_wait = get_map_nodetype_to_times_wait 4390 if self.is_use_nodeswaittimes_est & (self.matchresults is not None): 4391 trips.route_fastest_with_waits(time_modespecific=self.time_modespecific, 4392 c_modespecific=self.c_modespecific, 4393 is_ignor_connections=self.is_ignor_connections, 4394 times_wait_nodes=self.matchresults.nodesresults.get_times_wait_est(), 4395 speeds_in_motion=self.matchresults.routesresults_matched.get_speeds_inmotion_est(), 4396 dist_min_modespecific=self.dist_min_modespecific, 4397 color_route=self.color_route, 4398 ) 4399 else: 4400 trips.route_fastest(time_modespecific=self.time_modespecific, 4401 c_modespecific=self.c_modespecific, 4402 is_ignor_connections=self.is_ignor_connections, 4403 color_route=self.color_route, 4404 ) 4405 return True 4406 4407 4408class Routesanalyzer(Process): 4409 def __init__(self, ident, mapmatching, results=None, logger=None, **kwargs): 4410 print 'Routesanalyzer.__init__' 4411 4412 # TODO: let this be independent, link to it or child?? 4413 4414 if results is None: 4415 self._results = Matchresults('matchresults', mapmatching) 4416 else: 4417 self._results = results 4418 4419 self._init_common(ident, 4420 parent=mapmatching, 4421 name='Routes Analyzer', 4422 logger=logger, 4423 info='Determines attributes of matched route and alternative routes.', 4424 ) 4425 4426 attrsman = self.set_attrsman(cm.Attrsman(self)) 4427 4428 self.priority_max_low = attrsman.add(cm.AttrConf('priority_max_low', kwargs.get('priority_max_low', 6), 4429 groupnames=['options'], 4430 perm='rw', 4431 name='Max. low priority', 4432 info='Maximum priority of an edge, such that it is still considered low priority.', 4433 )) 4434 4435 self.timeloss_intersection = attrsman.add(cm.AttrConf('timeloss_intersection', kwargs.get('timeloss_intersection', 5.0), 4436 groupnames=['options'], 4437 perm='rw', 4438 name='Timeloss intersection', 4439 info='Estimated timeloss at intersections due to waiting or reduction of speed. This value is used to estimate travel time of route alternatives.', 4440 )) 4441 4442 self.timeloss_tl = attrsman.add(cm.AttrConf('timeloss_tl', kwargs.get('timeloss_tl', 15.0), 4443 groupnames=['options'], 4444 perm='rw', 4445 name='Timeloss TL', 4446 info='Additional estimated timeloss at traffic light intersections due to waiting at the red light. This value is used to estimate travel time of route alternatives.', 4447 )) 4448 4449 self.edgedurations_tot_min = attrsman.add(cm.AttrConf('edgedurations_tot_min', kwargs.get('edgedurations_tot_min', 10.0), 4450 groupnames=['options'], 4451 perm='rw', 4452 name='min tot. edge duration', 4453 unit='s', 4454 info='Minimum total duration of all users in an edge in order to calculate average speed. A too small value distors the results.', 4455 )) 4456 4457 self.is_speedana = attrsman.add(cm.AttrConf('is_speedana', kwargs.get('is_speedana', False), 4458 groupnames=['options'], 4459 perm='rw', 4460 name='Speed analysis?', 4461 info='If True, speed analysis will be performed (can take some time and use a lot of memory).', 4462 )) 4463 4464 self.edgespeed_max = attrsman.add(cm.AttrConf('edgespeed_max', kwargs.get('edgespeed_max', 14.0), 4465 groupnames=['options'], 4466 perm='rw', 4467 name='Max edge speed', 4468 unit='m/s', 4469 info='Edge speed estimates will be clipped at this speed.', 4470 )) 4471 4472 self.waitspeed = attrsman.add(cm.AttrConf('waitspeed', kwargs.get('waitspeed', 0.7), 4473 groupnames=['options'], 4474 perm='rw', 4475 name='Wait speed', 4476 unit='m/s', 4477 info='Below this speed, the vehicle is considered waiting.', 4478 )) 4479 4480 self.junctionrange = attrsman.add(cm.AttrConf('junctionrange', kwargs.get('junctionrange', 10.0), 4481 groupnames=['options'], 4482 perm='rw', 4483 name='Junction range', 4484 unit='m', 4485 info='This is the range after an edge for in which waiting times are considered as part of the edge.', 4486 )) 4487 4488 self.is_nodeana = attrsman.add(cm.AttrConf('is_nodeana', kwargs.get('is_nodeana', False), 4489 groupnames=['options'], 4490 perm='rw', 4491 name='Node analysis?', 4492 info='If True, Node analysis will be performed. This is mainly the calculation of the average waiting time at different types of junctions.', 4493 )) 4494 4495 self.flowfactor = attrsman.add(cm.AttrConf('flowfactor', kwargs.get('flowfactor', 10.0), 4496 groupnames=['options'], 4497 perm='rw', 4498 name='Flow factor', 4499 info='This is the factor which will be multiplied with the edge probability to estimate the absolute vehicle flows.', 4500 )) 4501 4502 self.is_oldversion = attrsman.add(cm.AttrConf('is_oldversion', kwargs.get('is_oldversion', False), 4503 groupnames=['options'], 4504 perm='rw', 4505 name='Old mapmatch?', 4506 info='If True, analyze for old mapmatch version.', 4507 )) 4508 4509 results = self.get_results() 4510 results.config(Routesresults('routesresults_matched', results, 4511 name='Results of matched routes'), name='Results of matched routes') 4512 results.config(Routesresults('routesresults_shortest', results, 4513 name='Results of shortest routes'), name='Results of shortest routes') 4514 results.config(Routesresults('routesresults_fastest', results, 4515 name='Results of fastest routes'), name='Results of fastest routes') 4516 4517 results.config(Routesresults('routesresults_matched_nonoverlap', results, name='Results of matched, non-overlapping routes'), 4518 name='Results of matched routes using only edges which do not overlap with the shortest route.') 4519 results.config(Routesresults('routesresults_shortest_nonoverlap', results, name='Results of shortest, non-overlapping routes'), 4520 name='Results of shortest routes using only edges which do not overlap with the matched route.') 4521 4522 results.config(Edgesresults('edgesresults', results)) 4523 results.config(Nodesresults('nodesresults', results)) 4524 4525 def get_results(self): 4526 return self._results 4527 4528 def do(self): 4529 print 'Routesanalyzer.do' 4530 # results 4531 results = self.get_results() 4532 routesresults_shortest = results.routesresults_shortest 4533 routesresults_fastest = results.routesresults_fastest 4534 routesresults_matched = results.routesresults_matched 4535 4536 routesresults_shortest_nonoverlap = results.routesresults_shortest_nonoverlap 4537 routesresults_matched_nonoverlap = results.routesresults_matched_nonoverlap 4538 4539 edgesresults = results.edgesresults 4540 nodesresults = results.nodesresults 4541 4542 # links 4543 mapmatching = self.parent 4544 trips = mapmatching.trips 4545 4546 routes = trips.get_routes() 4547 scenario = mapmatching.get_scenario() 4548 edges = scenario.net.edges 4549 lanes = scenario.net.lanes 4550 nodes = scenario.net.nodes 4551 id_mode_ped = scenario.net.modes.get_id_mode('pedestrian') 4552 get_pos_from_coord = edges.get_pos_from_coord 4553 4554 vtypes = scenario.demand.vtypes 4555 points = mapmatching.points 4556 timestamps = points.timestamps 4557 4558 priority_max_low = self.priority_max_low 4559 timeloss_intersection = self.timeloss_intersection 4560 timeloss_tl = self.timeloss_tl 4561 4562 distancesmap = mapmatching.get_distancesmap() 4563 accesslevelsmap = mapmatching.get_accesslevelsmap() 4564 priorities = edges.priorities 4565 ids_tonode = edges.ids_tonode 4566 nodetypes = scenario.net.nodes.types 4567 tlstype = nodetypes.choices['traffic_light'] 4568 ids_tls = scenario.net.nodes.ids_tls 4569 4570 ids_trip_sel = trips.get_ids_selected() 4571 4572 ids_route_sel = trips.ids_route_matched[ids_trip_sel] 4573 inds_valid = np.flatnonzero(ids_route_sel > 0) 4574 4575 ids_route = ids_route_sel[inds_valid] 4576 ids_trip = ids_trip_sel[inds_valid] 4577 ids_route_shortest = trips.ids_route_shortest[ids_trip] 4578 ids_route_fastest = trips.ids_route_fastest[ids_trip] 4579 4580 ids_vtype = trips.ids_vtype[ids_trip] 4581 ids_mode = vtypes.ids_mode[ids_vtype] 4582 4583 #ind = 0 4584 4585 print ' analyzing %d trips' % len(ids_trip) 4586 4587 routesresults_shortest.clear() 4588 routesresults_matched.clear() 4589 routesresults_fastest.clear() 4590 routesresults_shortest_nonoverlap.clear() 4591 routesresults_matched_nonoverlap.clear() 4592 4593 edgesresults.clear() 4594 ids_res = routesresults_matched.add_rows(n=len(ids_trip)) 4595 routesresults_shortest.add_rows(ids=ids_res) 4596 routesresults_fastest.add_rows(ids=ids_res) 4597 routesresults_matched_nonoverlap.add_rows(ids=ids_res) 4598 routesresults_shortest_nonoverlap.add_rows(ids=ids_res) 4599 4600 ids_edgeresmap = edgesresults.init_for_routes(routes) 4601 4602 for id_trip, id_route_matched, id_route_shortest, id_route_fastest, id_mode, id_res, dist_gps, duration_gps\ 4603 in zip(ids_trip, 4604 ids_route, 4605 ids_route_shortest, 4606 ids_route_fastest, 4607 ids_mode, 4608 ids_res, 4609 trips.lengths_gpsroute_matched[ids_trip], 4610 trips.durations_route_matched[ids_trip]): 4611 4612 #ids_point = trips.ids_points[id_trip] 4613 distances = distancesmap[id_mode] 4614 4615 # here we cut of first edge for analysis 4616 ids_edge_matched = np.array(routes.ids_edges[id_route_matched][1:], dtype=np.int32) 4617 4618 if self.is_oldversion: 4619 ids_points_edgeend = np.array(trips.ids_points_edgeend[id_trip], dtype=np.int32) # [1:] 4620 else: 4621 ids_points_edgeend = np.array(trips.ids_points_edgeend[id_trip][1:], dtype=np.int32) 4622 4623 ids_points = np.array(trips.ids_points[id_trip], dtype=np.int32) 4624 # 4625 times = points.timestamps[ids_points] 4626 coords = points.coords[ids_points] 4627 accesslevels_matched = accesslevelsmap[id_mode][ids_edge_matched] 4628 priorities_matched = priorities[ids_edge_matched] 4629 nodetypes_matched = nodetypes[ids_tonode[ids_edge_matched]] 4630 4631 print ' analyzing id_trip', id_trip 4632 # print ' len(ids_edge_matched)',len(ids_edge_matched) 4633 # print ' len(ids_points_edgeend)',len(ids_points_edgeend) 4634 # print ' ids_edge_matched',ids_edge_matched 4635 # print ' accesslevels_matched',accesslevels_matched 4636 # print ' tlstype',tlstype 4637 # print ' accesslevels_mixed',accesslevels_matched==1 4638 # print ' accesslevels_mixed',np.flatnonzero(accesslevels_matched==1) 4639 # print ' distances', 4640 # print ' nodetypes_matched',nodetypes_matched 4641 if len(ids_points_edgeend) > 1: 4642 dist_matched = np.sum(distances[ids_edge_matched]) 4643 duration_matched = timestamps[ids_points_edgeend[-1]] - timestamps[ids_points_edgeend[0]] 4644 n_nodes_matched = len(nodetypes_matched) 4645 n_tls_matched = np.sum(nodetypes_matched == tlstype) 4646 lineduration_matched = duration_matched-n_nodes_matched*timeloss_intersection-n_tls_matched*timeloss_tl 4647 linespeed_matched = dist_matched/lineduration_matched 4648 4649 else: 4650 dist_matched = 0.0 4651 duration_matched = 0.0 4652 n_nodes_matched = 0 4653 n_tls_matched = 0 4654 lineduration_matched = 0.0 4655 linespeed_matched = 0.0 4656 4657 # do edge by edge analyses if at least more than 1 edge 4658 n_matched = len(ids_edge_matched) 4659 if n_matched > 1: 4660 4661 # cut off last edge 4662 4663 print ' ids_edge_matched', ids_edge_matched.shape, ids_edge_matched 4664 print ' ids_points_edgeend', ids_points_edgeend.shape, ids_points_edgeend 4665 n_matched -= 1 4666 ids_edge = ids_edge_matched[:-1] 4667 edgelengths = edges.lengths[ids_edge] 4668 ids_points_ee = ids_points_edgeend 4669 4670 print ' ids_edge', ids_edge.shape, n_matched, ids_edge 4671 print ' ids_points_ee', ids_points_ee.shape, ids_points_ee 4672 4673 ids_tls = nodes.ids_tls[edges.ids_tonode[ids_edge]] 4674 4675 durations_edge = timestamps[ids_points_ee[1:]] - timestamps[ids_points_ee[:-1]] 4676 4677 # print ' durations_edge',durations_edge.shape,durations_edge 4678 edgesresults.numbers_tot_matched[ids_edgeresmap[ids_edge]] += 1 4679 edgesresults.durations_tot_matched[ids_edgeresmap[ids_edge]] += durations_edge 4680 #dists_edge = distances[ids_edge] 4681 4682 # identify gps points with id_point_from, id_point_to 4683 # and compute line speed, waiting time.... 4684 pointsposition = [] 4685 pointsspeed = [] 4686 pointstime = [] 4687 ids_pointedge = [] 4688 4689 if self.is_speedana | self.is_nodeana: # nodes ana needs speeds ana 4690 4691 time_inmotion_route = 0.0 4692 time_wait_route = 0.0 4693 time_wait_tls_route = 0.0 4694 time_wait_junction_route = 0.0 4695 4696 ind_matched = 0 4697 id_edge_current = -1 4698 id_tls_current = -1 4699 time_enter = 0.0 4700 location_enter = 0.0 4701 time_speedaverage = 0.0 4702 location_speedaverage = 0.0 4703 time_speedinmotion = 0.0 4704 location_speedinmotion = 0.0 4705 time_wait = 0.0 4706 time_wait_tls = 0.0 4707 n_points = len(ids_points) 4708 dists = np.zeros(n_points, dtype=np.float32) 4709 dists[1:] = np.sqrt(np.sum((coords[1:]-coords[:-1])**2, 1)) 4710 loctions = np.cumsum(dists) 4711 deltatimes = np.zeros(n_points, dtype=np.float32) 4712 deltatimes[1:] = times[1:]-times[:-1] 4713 speeds = np.clip(dists/deltatimes, 0, self.edgespeed_max) 4714 4715 #speeds_edge_av = np.zeros(n_matched, dtype = np.float32) 4716 print ' dists', dists 4717 print ' deltatimes', deltatimes 4718 print ' speeds', speeds 4719 is_begin = False 4720 is_waiting = False 4721 id_longedge = -1 4722 id_tlsedge = -1 4723 time_start = times[0] 4724 i_point = 0 4725 4726 # there are basically two loops: 4727 # the outer for loop rind through all GPS points 4728 # and the inner while loop increases the 4729 # edge counter until the point??? 4730 for id_point, time, coord, location, dist, deltatime, speed in zip(ids_points, times, coords, loctions, dists, deltatimes, speeds): 4731 4732 # if id_point == ids_points_ee[ind_matched]: 4733 # is_begin = True 4734 # # try to find last edge with this point as end point 4735 4736 if is_begin: 4737 pos = get_pos_from_coord(id_edge_current, coord) 4738 print ' id_point=%d,id_end %d id_edge_current=%d, id_edgeres=%d, pos= %.2f, v=%.2f' % ( 4739 id_point, ids_points_ee[ind_matched], id_edge_current, id_edgeres_current, pos, speed) 4740 4741 pointsposition.append(pos) 4742 pointsspeed.append(speed) 4743 pointstime.append(time-time_start) 4744 ids_pointedge.append(id_edge_current) 4745 4746 if speed < self.waitspeed: 4747 print ' waiting detected add', deltatime 4748 4749 is_waiting = True 4750 edgesresults.times_wait[id_edgeres_current] += deltatime 4751 time_wait += deltatime 4752 time_wait_tls += deltatime 4753 # is waiting at initial part of edge 4754 if pos < self.junctionrange: 4755 # halt is at junction at initial part of an edge 4756 # add wait to last longedge 4757 edgesresults.times_wait_junc[id_longedgeres] += deltatime 4758 time_wait_junction_route += deltatime 4759 4760 elif pos > edgelength_current-self.junctionrange: 4761 # halt is at junction at the end of current edge 4762 edgesresults.times_wait_junc[id_edgeres_current] += deltatime 4763 time_wait_junction_route += deltatime 4764 4765 else: 4766 is_waiting = False 4767 4768 # while loop through points of an edge until ede ends 4769 is_cont = True 4770 while is_cont: 4771 4772 # is current point a last point of edge ind_matched 4773 is_cont = id_point == ids_points_ee[ind_matched] 4774 print ' endpoint id_point =%d, id_startpoint%d ind_matched=%d,n_matched=%d' % ( 4775 id_point, ids_points_ee[ind_matched], ind_matched, n_matched), is_cont 4776 if is_cont: 4777 # this is the first point in a new edge 4778 # TODO: it should actually the last point in an edge 4779 4780 # save previous results 4781 # edgesresults.speeds_average[ids_edgeresmap[ids_edge]] 4782 4783 #edgesresults.times_wait[ids_edgeres] = time_wait 4784 4785 # update edge-values 4786 4787 if ind_matched < n_matched: 4788 # edge is not the last matched edge 4789 if is_begin: 4790 # 4791 # this part is avoided for the first time 4792 # only from secon time and after is_begin is True 4793 # 4794 # do speed and average speed on right edge 4795 v_av = (location - location_speedaverage)/(time - time_speedaverage) 4796 edgesresults.speeds_average[id_edgeres_current] += v_av 4797 v_inmotion = np.clip((location - location_speedaverage) / 4798 (time - time_speedaverage-time_wait), 0, self.edgespeed_max) 4799 4800 edgesresults.speeds_inmotion[id_edgeres_current] += v_inmotion 4801 4802 print ' id_edge = %d, v_av =%.2fkm/h, v_im = %.2fkm/h' % ( 4803 id_edge_current, v_av*3.6, v_inmotion*3.6) 4804 4805 #lengths_inmotion_route += location- location_speedaverage 4806 time_inmotion_route += time - time_speedaverage-time_wait 4807 time_wait_route += time_wait 4808 4809 time_wait = 0.0 4810 4811 if time - time_speedaverage > 10.0: 4812 # time passed since enering last edge is 4813 # sufficient to do averaging 4814 time_speedaverage = time 4815 location_speedaverage = location 4816 4817 id_edge_current = ids_edge[ind_matched] 4818 id_edgeres_current = ids_edgeresmap[id_edge_current] 4819 edgelength_current = edgelengths[ind_matched] 4820 4821 if (ids_tls[ind_matched] != id_tls_current): 4822 # tls changed 4823 4824 if id_tlsedge != -1: 4825 # there has been an old tls recording 4826 edgesresults.times_wait_tls[id_tlsedge] += time_wait_tls 4827 time_wait_tls_route += time_wait_tls 4828 4829 if (ids_tls[ind_matched] != -1): 4830 # memorize new edge, which is used to 4831 # accumulate wait time of entire tls crossing 4832 id_tlsedge = id_edgeres_current 4833 else: 4834 # memorize no tls wait time accumulation 4835 id_tlsedge = -1 4836 4837 # memorize current tls ID (or -1 for no tls) 4838 id_tls_current = ids_tls[ind_matched] 4839 4840 # reset tls wait counter 4841 time_wait_tls = 0.0 4842 4843 time_enter = time 4844 location_enter = location 4845 4846 if (edgelength_current > self.junctionrange) | (id_longedge == -1): 4847 # new longedge of at least a junction range has been detected 4848 id_longedge = id_edge_current 4849 id_longedgeres = ids_edgeresmap[id_longedge] 4850 location_longedge = location 4851 length_longedge = edgelength_current 4852 4853 # get next matched edge 4854 ind_matched += 1 4855 4856 else: 4857 print ' reached end of matched edges', 4858 is_cont = False 4859 4860 # update speed average for last visited edge 4861 v_av = (location - location_speedaverage)/(time - time_speedaverage) 4862 edgesresults.speeds_average[id_edgeres_current] += v_av 4863 v_inmotion = np.clip((location - location_speedaverage) / 4864 (time - time_speedaverage-time_wait), 0, self.edgespeed_max) 4865 4866 edgesresults.speeds_inmotion[id_edgeres_current] += v_inmotion 4867 4868 print ' last id_edge = %d, v_av =%.2fkm/h, v_im = %.2fkm/h' % ( 4869 id_edge_current, v_av*3.6, v_inmotion*3.6), time - time_speedaverage, time_wait, time - time_speedaverage-time_wait 4870 4871 #lengths_inmotion_route += location- location_speedaverage 4872 time_inmotion_route += time - time_speedaverage-time_wait 4873 time_wait_route += time_wait 4874 time_wait = 0.0 4875 4876 # save wait times in tls is necessary 4877 if id_tlsedge != -1: 4878 # there has been an old tls recording 4879 edgesresults.times_wait_tls[id_tlsedge] += time_wait_tls 4880 time_wait_tls_route += time_wait_tls 4881 4882 # this will trigger the final break for loop 4883 ind_matched += 1 4884 4885 if not is_begin: 4886 is_begin = True 4887 time_start = time 4888 4889 if ind_matched == n_matched+1: 4890 print ' speed ana reached end. Break for loop' 4891 break 4892 4893 # print ' save results id_res',id_res 4894 # print ' pointsposition',pointsposition 4895 # print ' pointsspeed',pointsspeed 4896 # print ' pointstime',pointstime 4897 # print ' ids_pointedge',ids_pointedge 4898 4899 routesresults_matched.times_wait[id_res] = time_wait_route 4900 routesresults_matched.times_wait_tls[id_res] = time_wait_tls_route 4901 routesresults_matched.times_inmotion[id_res] = time_inmotion_route 4902 4903 routesresults_matched.pointspositions[id_res] = pointsposition 4904 routesresults_matched.pointsspeeds[id_res] = pointsspeed 4905 routesresults_matched.pointstimes[id_res] = pointstime 4906 routesresults_matched.ids_pointedges[id_res] = ids_pointedge 4907 4908 # else: 4909 # # no speedanalysis 4910 # pointsposition = None 4911 # pointsspeed = None 4912 # pointstime = None 4913 # ids_pointedge = None 4914 4915 # print ' BEFORE:' 4916 # print ' routesresults_matched.ids_route',routesresults_matched.ids_route.get_value() 4917 # print ' routesresults_matched.ids_pointedges',routesresults_matched.ids_pointedges.get_value() 4918 # print ' routesresults_matched.pointspositions',routesresults_matched.pointspositions.get_value() 4919 routesresults_matched.set_row(id_res, 4920 ids_route=id_route_matched, 4921 distances=dist_matched, 4922 durations=duration_matched, 4923 lengths_mixed=np.sum(distances[ids_edge_matched[accesslevels_matched == 1]]), 4924 lengths_exclusive=np.sum( 4925 distances[ids_edge_matched[accesslevels_matched == 2]]), 4926 lengths_low_priority=np.sum( 4927 distances[ids_edge_matched[priorities_matched <= priority_max_low]]), 4928 lengths_overlap_matched=np.sum(distances[ids_edge_matched]), 4929 numbers_nodes=n_nodes_matched, 4930 numbers_nodes_tls=n_tls_matched, 4931 numbers_prioritychange=np.sum(np.logical_not( 4932 priorities_matched[:-1], priorities_matched[1:])), 4933 #pointspositions = pointsposition, 4934 #pointsspeeds = pointsspeed, 4935 #pointstimes = pointstime, 4936 #ids_pointedges = ids_pointedge, 4937 ) 4938 4939 # print ' AFTER:' 4940 # print ' routesresults_matched.ids_route',routesresults_matched.ids_route.get_value() 4941 # print ' routesresults_matched.ids_pointedges',routesresults_matched.ids_pointedges.get_value() 4942 # print ' routesresults_matched.pointsposition',routesresults_matched.pointspositions.get_value() 4943 4944 if id_route_shortest >= 0: 4945 ids_edge_shortest = np.array(routes.ids_edges[id_route_shortest], dtype=np.int32)[1:] 4946 accesslevels_shortest = accesslevelsmap[id_mode][ids_edge_shortest] 4947 priorities_shortest = priorities[ids_edge_shortest] 4948 nodetypes_shortest = nodetypes[ids_tonode[ids_edge_shortest]] 4949 4950 ids_edge_overlap = list(set(ids_edge_matched).intersection(ids_edge_shortest)) 4951 ids_edge_shortest_nonoverlap = np.array( 4952 list(set(ids_edge_shortest).difference(ids_edge_matched)), dtype=np.int32) 4953 ids_edge_match_nonoverlap = np.array( 4954 list(set(ids_edge_matched).difference(ids_edge_shortest)), dtype=np.int32) 4955 dist_shortest = np.sum(distances[ids_edge_shortest]) 4956 n_nodes_shortest = len(nodetypes_shortest) 4957 n_tls_shortest = np.sum(nodetypes_shortest == tlstype) 4958 4959 edgesresults.numbers_tot_shortest[ids_edgeresmap[ids_edge_shortest]] += 1 4960 edgesresults.differences_dist_tot_shortest[ids_edgeresmap[ids_edge_shortest_nonoverlap] 4961 ] += dist_matched-dist_shortest 4962 4963 routesresults_shortest.set_row(id_res, 4964 ids_route=id_route_shortest, 4965 distances=dist_shortest, 4966 durations=dist_shortest/linespeed_matched+timeloss_intersection * n_nodes_shortest + timeloss_tl * n_tls_shortest, 4967 lengths_mixed=np.sum( 4968 distances[ids_edge_shortest[accesslevels_shortest == 1]]), 4969 lengths_exclusive=np.sum( 4970 distances[ids_edge_shortest[accesslevels_shortest == 2]]), 4971 lengths_low_priority=np.sum( 4972 distances[ids_edge_shortest[priorities_shortest <= priority_max_low]]), 4973 numbers_nodes=n_nodes_shortest, 4974 numbers_nodes_tls=n_tls_shortest, 4975 numbers_prioritychange=np.sum(np.logical_not( 4976 priorities_shortest[:-1], priorities_shortest[1:])), 4977 lengths_overlap_matched=np.sum(distances[ids_edge_overlap]), 4978 ) 4979 4980 accesslevels_nonoverlap = accesslevelsmap[id_mode][ids_edge_match_nonoverlap] 4981 # print ' ids_edge_match_nonoverlap',ids_edge_match_nonoverlap 4982 # print ' accesslevels_nonoverlap==1',np.flatnonzero(accesslevels_nonoverlap==1),np.flatnonzero(accesslevels_nonoverlap==1).dtype 4983 # print ' ids_edge_match_nonoverlap[accesslevels_nonoverlap==1]',ids_edge_match_nonoverlap[np.flatnonzero(accesslevels_nonoverlap==1)] 4984 priorities_nonoverlap = priorities[ids_edge_match_nonoverlap] 4985 nodetypes_nonoverlap = nodetypes[ids_tonode[ids_edge_match_nonoverlap]] 4986 4987 dist_nonoverlap = np.sum(distances[ids_edge_match_nonoverlap]) 4988 n_nodes_nonoverlap = len(nodetypes_nonoverlap) 4989 n_tls_nonoverlap = np.sum(nodetypes_nonoverlap == tlstype) 4990 4991 routesresults_matched_nonoverlap.set_row(id_res, 4992 ids_route=id_route_matched, 4993 distances=dist_nonoverlap, 4994 durations=dist_nonoverlap/linespeed_matched+timeloss_intersection * n_nodes_nonoverlap + timeloss_tl * n_tls_nonoverlap, 4995 lengths_mixed=np.sum( 4996 distances[ids_edge_match_nonoverlap[accesslevels_nonoverlap == 1]]), 4997 lengths_exclusive=np.sum( 4998 distances[ids_edge_match_nonoverlap[accesslevels_nonoverlap == 2]]), 4999 lengths_low_priority=np.sum( 5000 distances[ids_edge_match_nonoverlap[priorities_nonoverlap <= priority_max_low]]), 5001 lengths_overlap_matched=np.sum( 5002 distances[ids_edge_match_nonoverlap]), 5003 numbers_nodes=n_nodes_nonoverlap, 5004 numbers_prioritychange=np.sum(np.logical_not( 5005 priorities_nonoverlap[:-1], priorities_nonoverlap[1:])), 5006 numbers_nodes_tls=n_tls_nonoverlap, 5007 ) 5008 5009 accesslevels_nonoverlap = accesslevelsmap[id_mode][ids_edge_shortest_nonoverlap] 5010 priorities_nonoverlap = priorities[ids_edge_shortest_nonoverlap] 5011 nodetypes_nonoverlap = nodetypes[ids_tonode[ids_edge_shortest_nonoverlap]] 5012 5013 dist_nonoverlap = np.sum(distances[ids_edge_shortest_nonoverlap]) 5014 n_nodes_nonoverlap = len(nodetypes_nonoverlap) 5015 n_tls_nonoverlap = np.sum(nodetypes_nonoverlap == tlstype) 5016 5017 routesresults_shortest_nonoverlap.set_row(id_res, 5018 ids_route=id_route_matched, 5019 distances=dist_nonoverlap, 5020 durations=dist_nonoverlap/linespeed_matched+timeloss_intersection * n_nodes_nonoverlap + timeloss_tl * n_tls_nonoverlap, 5021 lengths_mixed=np.sum( 5022 distances[ids_edge_shortest_nonoverlap[accesslevels_nonoverlap == 1]]), 5023 lengths_exclusive=np.sum( 5024 distances[ids_edge_shortest_nonoverlap[accesslevels_nonoverlap == 2]]), 5025 lengths_low_priority=np.sum( 5026 distances[ids_edge_shortest_nonoverlap[priorities_nonoverlap <= priority_max_low]]), 5027 lengths_overlap_matched=np.sum( 5028 distances[ids_edge_shortest_nonoverlap]), 5029 numbers_nodes=n_nodes_nonoverlap, 5030 numbers_nodes_tls=n_tls_nonoverlap, 5031 numbers_prioritychange=np.sum(np.logical_not( 5032 priorities_nonoverlap[:-1], priorities_nonoverlap[1:])), 5033 ) 5034 # print ' analyzing id_trip',id_trip,'Done.' 5035 5036 if id_route_fastest >= 0: 5037 ids_edge_fastest = np.array(routes.ids_edges[id_route_fastest], dtype=np.int32)[1:] 5038 accesslevels_fastest = accesslevelsmap[id_mode][ids_edge_fastest] 5039 priorities_fastest = priorities[ids_edge_fastest] 5040 nodetypes_fastest = nodetypes[ids_tonode[ids_edge_fastest]] 5041 5042 # overlap analyses 5043 ids_edge_overlap = list(set(ids_edge_matched).intersection(ids_edge_fastest)) 5044 ids_edge_fastest_nonoverlap = np.array( 5045 list(set(ids_edge_fastest).difference(ids_edge_matched)), dtype=np.int32) 5046 ids_edge_match_nonoverlap = np.array( 5047 list(set(ids_edge_matched).difference(ids_edge_fastest)), dtype=np.int32) 5048 5049 dist_fastest = trips.lengths_route_fastest[id_trip] # np.sum(distances[ids_edge_fastest]) 5050 n_nodes_fastest = len(nodetypes_fastest) 5051 n_tls_fastest = np.sum(nodetypes_fastest == tlstype) 5052 5053 edgesresults.numbers_tot_fastest[ids_edgeresmap[ids_edge_fastest]] += 1 5054 edgesresults.differences_dist_tot_fastest[ids_edgeresmap[ids_edge_fastest_nonoverlap] 5055 ] += dist_matched-dist_fastest 5056 5057 routesresults_fastest.set_row(id_res, 5058 ids_route=id_route_fastest, 5059 distances=dist_fastest, 5060 durations=trips.durations_route_fastest[id_trip], 5061 lengths_mixed=np.sum(distances[ids_edge_fastest[accesslevels_fastest == 1]]), 5062 lengths_exclusive=np.sum( 5063 distances[ids_edge_fastest[accesslevels_fastest == 2]]), 5064 lengths_low_priority=np.sum( 5065 distances[ids_edge_fastest[priorities_fastest <= priority_max_low]]), 5066 numbers_nodes=n_nodes_fastest, 5067 numbers_nodes_tls=n_tls_fastest, 5068 numbers_prioritychange=np.sum(np.logical_not( 5069 priorities_fastest[:-1], priorities_fastest[1:])), 5070 lengths_overlap_matched=np.sum(distances[ids_edge_overlap]), 5071 ) 5072 5073 # do mass edge result operations 5074 #edgesresults.speeds_average[ids_valid] = np.clip(edges.lengths[edgesresults.ids_edge[ids_valid]]/(edgesresults.durations_tot_matched[ids_valid]/edgesresults.numbers_tot_matched[ids_valid]),0.0,self.edgespeed_max) 5075 5076 ids_valid = edgesresults.select_ids(edgesresults.durations_tot_matched.get_value() > self.edgedurations_tot_min) 5077 5078 edgesresults.probabilities_tot_matched[ids_valid] = edgesresults.numbers_tot_matched[ids_valid] / \ 5079 float(len(ids_valid)) 5080 edgesresults.flows_est[ids_valid] = self.flowfactor * edgesresults.numbers_tot_matched[ids_valid] 5081 ids_valid = edgesresults.select_ids(edgesresults.numbers_tot_matched.get_value() > 0) 5082 5083 edgesresults.speeds_average[ids_valid] = edgesresults.speeds_average[ids_valid] / \ 5084 edgesresults.numbers_tot_matched[ids_valid] 5085 edgesresults.speeds_inmotion[ids_valid] = edgesresults.speeds_inmotion[ids_valid] / \ 5086 edgesresults.numbers_tot_matched[ids_valid] 5087 5088 edgesresults.times_wait[ids_valid] = edgesresults.times_wait[ids_valid] / \ 5089 edgesresults.numbers_tot_matched[ids_valid] 5090 edgesresults.times_wait_tls[ids_valid] = edgesresults.times_wait_tls[ids_valid] / \ 5091 edgesresults.numbers_tot_matched[ids_valid] 5092 edgesresults.times_wait_junc[ids_valid] = edgesresults.times_wait_junc[ids_valid] / \ 5093 edgesresults.numbers_tot_matched[ids_valid] 5094 5095 # print ' ids_valid',ids_valid 5096 5097 if self.is_nodeana: 5098 # do node type analyses 5099 5100 # extract the set of nodes that are involved in the mapmatching 5101 ids_edge = edgesresults.ids_edge[ids_valid] 5102 #ids_node_raw = np.array(list(set(edges.ids_tonode[ids_edge])), dtype = np.int32) 5103 ids_node_raw = list(set(edges.ids_tonode[ids_edge])) 5104 5105 print ' identified nodes:', ids_node_raw 5106 # for id_node_raw in ids_node_raw: 5107 # print ' id_node_raw',id_node_raw 5108 # 5109 #map_id_node_to_type = {} 5110 ids_node = nodesresults.get_nodes_significant(ids_node_raw) 5111 5112 ids_noderes = nodesresults.add_rows(n=len(ids_node), ids_node=ids_node) 5113 print ' nodesresults.ids_node', nodesresults.ids_node.get_value() 5114 get_id_nodesres = nodesresults.ids_node.get_id_from_index 5115 has_id_node = nodesresults.ids_node.has_index 5116 for id_nodes_to, nodetype, time_wait, time_wait_tls in zip( 5117 edges.ids_tonode[ids_edge], 5118 nodes.types[edges.ids_tonode[ids_edge]], 5119 edgesresults.times_wait_junc[ids_valid], 5120 edgesresults.times_wait_tls[ids_valid], 5121 ): 5122 print ' id_nodes_to', id_nodes_to, nodetype 5123 if has_id_node(id_nodes_to): 5124 id_nodseres = get_id_nodesres(id_nodes_to) 5125 5126 if nodetype == 1: # traffic_light 5127 nodesresults.times_wait[id_nodseres] += time_wait_tls 5128 else: 5129 nodesresults.times_wait[id_nodseres] += time_wait 5130 nodesresults.numbers_tot_matched[id_nodseres] += 1 5131 5132 nodesresults.times_wait[ids_noderes] = nodesresults.times_wait[ids_noderes] / \ 5133 nodesresults.numbers_tot_matched[ids_noderes] 5134 print ' Route analyses done.' 5135 return True 5136 5137 5138def routes_to_shapefile(mapmatching, results, filepath, 5139 dataname='routeresshapedata', name='Route result shape data', 5140 log=None): 5141 """ 5142 Writes routes to file. 5143 """ 5144 print '\n routes_to_shapefile for mapmatching' 5145 net = mapmatching.get_scenario().net 5146 edges = net.edges 5147 trips = mapmatching.trips 5148 routes = trips.get_routes() 5149 shapedata = shapeformat.Shapedata(trips, dataname, 5150 filepath=filepath, 5151 name=name, 5152 projparams_shape=net.get_projparams(), 5153 offset=net.get_offset(), 5154 shapetype=3, # Polygons 5155 log=log, 5156 ) 5157 5158 fieldlength_default = 32 5159 attrlist = [ 5160 ('id', 'id', 'ID_TRIP', 'N', fieldlength_default, 0), 5161 ('timestamps', '', 'TIMESTAMP', 'C', fieldlength_default, 0), 5162 ('durations_gps', '', 'DUR_GPS', 'N', fieldlength_default, 0), 5163 ('lengths_route_matched', '', 'LEN_MATCH', 'N', fieldlength_default, 3), 5164 ('lengths_route_shortest', '', 'LEN_SHORT', 'N', fieldlength_default, 3), 5165 ('lengths_route_matched_mixed', '', 'LEN_MIX', 'N', fieldlength_default, 3), 5166 ('lengths_route_matched_exclusive', '', 'LEN_EXCL', 'N', fieldlength_default, 3), 5167 ('lengthindexes', '', 'LENGTHIND', 'N', fieldlength_default, 0), 5168 ('errors_dist', '', 'ERR_DIST', 'N', fieldlength_default, 0), 5169 ('times_computation', '', 'TIME_COMP', 'N', fieldlength_default, 0), 5170 # ('','','','N',fieldlength_default,3), 5171 ] 5172 5173 for attr in attrlist: 5174 shapedata.add_field(attr[2:]) 5175 5176 ids_trip = trips.select_ids(trips.ids_route_matched.get_value() > -1) 5177 5178 ids_shape = shapedata.add_rows(len(ids_trip)) 5179 # print ' shapedata.ID_ARC',shapedata.ID_ARC,'dir',dir(shapedata.ID_ARC) 5180 shapedata.ID_TRIP[ids_shape] = ids_trip 5181 5182 for id_shape, id_trip, ids_edge in zip(ids_shape, ids_trip, routes.ids_edges[trips.ids_route_matched[ids_trip]]): 5183 # print ' export id_route',id_route 5184 #route = traces.routes.get(id_route) 5185 if len(ids_edge) > 0: 5186 polyline = [] 5187 for shape in edges.shapes[ids_edge]: 5188 # print ' shape',type(shape),shape 5189 # print ' polyline',type(polyline),polyline 5190 polyline += shape.tolist() 5191 5192 shapedata.shapes[id_shape] = polyline 5193 5194 for netattrname, gettype, shapeattrname, x1, x2, x3 in attrlist: 5195 if netattrname not in ('id', 'timestamps'): 5196 getattr(shapedata, shapeattrname)[ids_shape] = getattr(trips, netattrname)[ids_trip] 5197 5198 for id_shape, timestamp in zip(ids_shape, trips.timestamps[ids_trip]): 5199 shapedata.TIMESTAMP[id_shape] = time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime(timestamp)) 5200 5201 shapedata.adjust_fieldlength() 5202 shapedata.export_shapefile() 5203 return True 5204 5205 5206def edgesresults_to_shapefile(mapmatching, results, filepath, 5207 dataname='edgeresshapedata', name='Edge result shape data', 5208 log=None): 5209 """ 5210 Writes edge results of mapmatching to shape-file. 5211 """ 5212 print '\n edgesresults_to_shapefile for mapmatching' 5213 net = mapmatching.get_scenario().net 5214 edges = net.edges 5215 edgesresults = results.edgesresults 5216 #trips = mapmatching.trips 5217 #routes = trips.get_routes() 5218 shapedata = shapeformat.Shapedata(edgesresults, dataname, 5219 filepath=filepath, 5220 name=name, 5221 projparams_shape=net.get_projparams(), 5222 offset=net.get_offset(), 5223 shapetype=3, # Polygons 5224 log=log, 5225 ) 5226 5227 fieldlength_default = 32 5228 attrlist = [ 5229 ('id', 'id', 'ID_ARC', 'N', fieldlength_default, 0), 5230 ('speeds_average', '', 'SPEED_AV', 'N', fieldlength_default, 5), 5231 ('speeds_inmotion', '', 'SPEED_MOV', 'N', fieldlength_default, 5), 5232 ('durations_tot_matched', '', 'TIME_TOT', 'N', fieldlength_default, 0), 5233 ('numbers_tot_matched', '', 'COUNTER', 'N', fieldlength_default, 0), 5234 ('times_wait', '', 'TIME_WAIT', 'N', fieldlength_default, 5), 5235 # ('','','','N',fieldlength_default,3), 5236 ] 5237 5238 for attr in attrlist: 5239 shapedata.add_field(attr[2:]) 5240 5241 ids_edgeres = edgesresults.select_ids(edgesresults.numbers_tot_matched.get_value() > 0) 5242 ids_edge = edgesresults.ids_edge[ids_edgeres] 5243 5244 ids_shape = shapedata.add_rows(len(ids_edge)) 5245 # print ' shapedata.ID_ARC',shapedata.ID_ARC,'dir',dir(shapedata.ID_ARC) 5246 shapedata.ID_ARC[ids_shape] = ids_edge 5247 shapedata.shapes[ids_shape] = edges.shapes[ids_edge] 5248 5249 for netattrname, gettype, shapeattrname, x1, x2, x3 in attrlist: 5250 if netattrname not in ('id',): 5251 getattr(shapedata, shapeattrname)[ids_shape] = getattr(edgesresults, netattrname)[ids_edgeres] 5252 5253 shapedata.adjust_fieldlength() 5254 shapedata.export_shapefile() 5255 return True 5256 5257 5258def points_to_shapefile(mapmatching, filepath, dataname='pointshapedata', 5259 parent=None, log=None): 5260 """ 5261 Export GPS points to shapefile. 5262 """ 5263 net = mapmatching.get_scenario().net 5264 points = mapmatching.points 5265 trips = mapmatching.trips 5266 shapedata = shapeformat.Shapedata(parent, dataname, name='GPS points shape data', 5267 filepath=filepath, 5268 shapetype=shapeformat.SHAPETYPES['Point'], 5269 projparams_shape=net.get_projparams(), 5270 offset=net.get_offset(), log=log) 5271 5272 #attrname, ftype, flen, fdigit = field 5273 attrlist = [ 5274 ('id', 'id', 'ID_POINT', 'N', 12, 0), 5275 ('timestamps', 'val', 'TIME', 'N', 32, 0), 5276 ('ids_trip', 'id', 'ID_TRIP', 'N', 32, 0), 5277 # ('radii','val','RADIUS','N',5,3), 5278 ] 5279 # 5280 5281 print 'nodes_to_shapefile', filepath 5282 5283 for attr in attrlist: 5284 shapedata.add_field(attr[2:]) 5285 5286 ids_point = points.select_ids(trips.ids_route_matched[points.ids_trip.get_value()] > -1) 5287 5288 ids_shape = shapedata.add_rows(len(ids_point)) 5289 # print ' shapedata.ID_ARC',shapedata.ID_ARC,'dir',dir(shapedata.ID_ARC) 5290 shapedata.ID_POINT[ids_shape] = ids_point 5291 shapedata.coords[ids_shape] = points.coords[ids_point] 5292 5293 # copy rest of attributes 5294 for netattrname, gettype, shapeattrname, x1, x2, x3 in attrlist: 5295 if netattrname not in ('id',): 5296 getattr(shapedata, shapeattrname)[ids_shape] = getattr(points, netattrname)[ids_point] 5297 5298 shapedata.adjust_fieldlength() 5299 shapedata.export_shapefile() 5300 return True 5301