def process(self): """A trip has just ended. What do we do with it?""" # As this may be being REprocessed we need to clean up any traces of the # result of earlier processing so that we have a fresh start db.scrub_trip(self.trip_id) # see if we have enough stuff to bother with if len(self.vehicles) < 5: # km return db.ignore_trip(self.trip_id,'too few vehicles') # calculate vector of segment speeds self.segment_speeds = self.get_segment_speeds() # check for very short trips if self.length < 0.8: # km return db.ignore_trip(self.trip_id,'too short') # check for errors and attempt to correct them while self.has_errors(): # make sure it's still long enough to bother with if len(self.vehicles) < 5: return db.ignore_trip(self.trip_id,'processing made too short') # still long enough to try fixing self.fix_error() # update the segment speeds for the next iteration self.segment_speeds = self.get_segment_speeds() # trip is clean, so store the cleaned line db.set_trip_clean_geom( self.trip_id, dumpWKB( self.get_geom(), hex=True ) ) # get the stops (as a list of Stop objects) self.stops = db.get_stops(self.direction_id,self.last_seen) # and begin matching self.map_match_trip() if not self.match.is_useable: return db.ignore_trip(self.trip_id,'match problem') self.interpolate_stop_times()
def process(self): """A trip has just ended. What do we do with it?""" # As this may be being REprocessed we need to clean up any traces of the # result of earlier processing so that we have a fresh start db.scrub_trip(self.trip_id) # see if we have enough stuff to bother with if len(self.vehicles) < 5: # km return db.ignore_trip(self.trip_id, 'too few vehicles') # calculate vector of segment speeds self.segment_speeds = self.get_segment_speeds() # check for very short trips if self.length < 0.8: # km return db.ignore_trip(self.trip_id, 'too short') # check for errors and attempt to correct them while self.has_errors(): # make sure it's still long enough to bother with if len(self.vehicles) < 5: return db.ignore_trip(self.trip_id, 'processing made too short') # still long enough to try fixing self.fix_error() # update the segment speeds for the next iteration self.segment_speeds = self.get_segment_speeds() # trip is clean, so store the cleaned line db.set_trip_clean_geom(self.trip_id, dumpWKB(self.get_geom(), hex=True)) # and begin matching self.map_match_trip() if len(self.vehicles) == 0: return db.ignore_trip( self.trip_id, 'too many vehicles removed during measurement') self.interpolate_stop_times()
def get_geom(self): """return a clean WKB geometry string using all vehicles in the local projection""" line = [] for v in self.vehicles: line.append(v['geom']) return dumpWKB(LineString(line), hex=True)
def save(self): """Store a record of this trip in the DB. This allows us to reprocess as from the beginning with different parameters, data, etc. GPS points are stored as an array of times and a linestring. This function is to be called just before process() as data is being collected.""" times = [] for v in self.vehicles: times.append(v.time) db.insert_trip(self.trip_id, self.block_id, self.route_id, self.direction_id, self.vehicle_id, times, dumpWKB(self.get_geom(), hex=True))
def map_match_trip(self): """1) Match the trip GPS points to the road network, id est, improve the spatial accuracy of the trip. 2) Get the location/measure of stops and vehicles along the path. 4) Interpolate sequence of stop_times from vehicle times.""" # create a match object, passing it this trip to get it started self.match = map_api.match(self) if not self.match.is_useable: return db.ignore_trip(self.trip_id, 'match problem') # store the match info and geom in the DB db.add_trip_match(self.trip_id, self.match.confidence, dumpWKB(self.match.geometry, hex=True)) # find the measure of the vehicles for time interpolation self.match.locate_vehicles_on_route()
def map_match_trip(self): """Match the trip GPS points to the road network, ie, improve the spatial accuracy of the trip. Get the location/measure of stops and vehicles along the path.""" # create a match object, passing it this trip to get it started self.match = map_api.match(self) if not self.match.is_useable: return db.ignore_trip(self.trip_id,'match problem') # store the match info and geom in the DB db.add_trip_match( self.trip_id, self.match.confidence, dumpWKB(self.match.geometry,hex=True) )
def save(self): """Store a record of this trip in the DB. This allows us to reprocess as from the beginning with different parameters, data, etc. GPS points are stored as an array of times and a linestring. This function is to be called just before process() as data is being collected.""" db.insert_trip( self.trip_id, self.block_id, self.route_id, self.direction_id, self.vehicle_id, [ v.time for v in self.vehicles ], dumpWKB( self.get_geom(), hex=True ) )
dest = random_point(zones[trip_dest]) # create and send the request response = requests.get('http://localhost:5000/route/v1/bicycle/' + str(orig.x) + ',' + str(orig.y) + ';' + str(dest.x) + ',' + str(dest.y), params=options, timeout=1) # parse the output j = json.loads(response.text) if j['code'] != 'Ok': print(response.text, '\n') continue # good respone - now parse and store it results = {} results['uid'] = trip_uid results['network_distance'] = j['routes'][0]['distance'] results['orig_geom'] = dumpWKB(orig) results['dest_geom'] = dumpWKB(dest) results['path_geom'] = dumpWKB(asShape(j['routes'][0]['geometry'])) cursor2.execute( """ UPDATE syn_trips SET network_trip_distance = %(network_distance)s, orig_geog = %(orig_geom)s::geography, dest_geog = %(dest_geom)s::geography, network_trip_geog = %(path_geom)s::geography WHERE uid = %(uid)s; """, results)
edgeB.forward_count * edgeB.geometry.length ) / newGeom.length ) new_reverse_count = round( ( edgeA.reverse_count * edgeA.geometry.length + edgeB.reverse_count * edgeB.geometry.length ) / newGeom.length ) # delete the first edge and update the second one edge_cursor.execute(""" UPDATE street_edges SET node_1 = %(node_1)s, node_2 = %(node_2)s, r = %(r)s, f = %(f)s, edge = ST_SetSRID(%(geom)s::geometry,3857), renovated = TRUE WHERE uid = %(edge1id)s; DELETE FROM street_edges WHERE uid = %(edge2id)s; """,{ 'edge1id':edgeA.db_uid, 'edge2id':edgeB.db_uid, 'node_1': new_from_id, 'node_2': new_to_id, 'f':new_forward_count, 'r':new_reverse_count, 'geom': dumpWKB( newGeom, hex=True ) }) connection.commit()
def match(self): """Match the trip to the road network, and do all the things that follow therefrom.""" match = map_api.match(self.vehicles) if not match.is_useable: return db.ignore_trip(self.trip_id, 'match problem') self.match_confidence = match.confidence # store the trip geometry self.match_geom = match.geometry() # and reproject it self.match_geom = reproject(conf['projection'], self.match_geom) # simplify slightly for speed (2 meter simplification) self.match_geom = self.match_geom.simplify(2) # if the multi actually just had one line, this simplifies to a # linestring, which can cause problems down the road if self.match_geom.geom_type == 'LineString': self.match_geom = MultiLineString([self.match_geom]) # store the match info and geom in the DB db.add_trip_match(self.trip_id, self.match_confidence, dumpWKB(self.match_geom, hex=True)) # drop vehicles that did not contribute to the match vehicles_used = match.vehicles_used() for i in reversed(range(0, len(self.vehicles))): if not vehicles_used[i]: del self.vehicles[i] # get distances of each vehicle along the match geom for vehicle, cum_dist in zip(self.vehicles, match.cum_distances()): vehicle['cum_dist'] = cum_dist # However, because we've simplified the line, the distances will be slightly off # and need correcting adjust_factor = self.match_geom.length / self.vehicles[-1]['cum_dist'] for v in self.vehicles: v['cum_dist'] = v['cum_dist'] * adjust_factor # get the stops as a list of objects # with keys {'id':stop_id,'g':geom} self.stops = db.get_stops(self.direction_id, self.last_seen) # process the geoms for stop in self.stops: stop['geom'] = loadWKB(stop['geom'], hex=True) # now match stops to the trip geometry, 750m at a time path = self.match_geom traversed = 0 # while there is more than 750m of path remaining while path.length > 0: subpath, path = cut(path, 750) # check for nearby stops for stop in self.stops: # if the stop is close enough stop_dist = subpath.distance(stop['geom']) if stop_dist <= conf['stop_dist']: # measure how far it is along the trip measure = traversed + subpath.project(stop['geom']) # add it to a list of possible stop times self.add_arrival(stop['id'], measure, stop_dist) # note what we have already traversed traversed += 750 # sort stops by arrival time self.timepoints = sorted(self.timepoints, key=lambda k: k['time']) # there is more than one stop, right? if len(self.timepoints) > 1: # store the stop times db.store_timepoints(self.trip_id, self.timepoints) # Now set the service_id, which is the (local) DAY equivalent of # the unix epoch, which is centered on Greenwich. # (The service_id is distinct to a day in the local timezone) # First, shift the second_based epoch to local time tlocal = self.timepoints[0]['time'] + conf['timezone'] * 3600 # then find the "epoch day" service_id = math.floor(tlocal / (24 * 3600)) # and store it in the DB db.set_service_id(self.trip_id, service_id) else: db.ignore_trip(self.trip_id, 'one or fewer timepoints') return