def classify_locations_by_intersection(conn): curs = conn.cursor() curs.execute("""select latitude, longitude, time, intersection from location where bus_id = 234105 order by time""") intersections = [] locations = [] for result in curs.fetchall(): latitude, longitude, time, intersection = result location = (latitude, longitude) point = dict(latitude=latitude, longitude=longitude, distance=st_line_locate_point(route, location), time=time) if intersection: intersections.append(point) else: locations.append(point) prev_intersection = intersections[0] next_intersection = intersections[1] i = 1 rejected = 0 accepted = 0 start_time = locations[0]['time'] for point in locations: if point['time'] < prev_intersection['time']: continue #silently reject because it is temporally before the bus starts while point['time'] > next_intersection['time']: #advance intersections to match time prev_intersection = next_intersection i += 1 if i < len(intersections): next_intersection = intersections[i] break #check distance against intersection distances if prev_intersection['distance'] <= point['distance'] <= next_intersection['distance']: accepted += 1 style = "accepted" else: rejected += 1 style = "rejected" print """ <Placemark> <name>%s - %s</name> <styleUrl>#%s</styleUrl> <Point> <coordinates> %s, %s </coordinates> </Point> </Placemark> """ % (point['time'] - start_time, style, style, point['longitude'], point['latitude']) print "</Document></kml>" print >>sys.stderr, "accepted, rejected, total", accepted, rejected, len(locations)
def find_shape_by_stops(feed, candidate_routes, stops, table_name): """This is brutal -- it matches a set of route paths against a known set of bus stops to choose the route path which falls nearest to the trip.""" key = freeze([candidate_routes, stops, table_name]) if key in _shape_by_stops_cache: return _shape_by_stops_cache[key] best_route = None best_dist = 100000000000000 #routes are sorted by length, because we want to use the shortest #route that matches the points. for route in sorted(candidate_routes, key=lambda route:route.the_geom.length): total_dist = 0 for stop in stops: total_dist += route.the_geom.distance(Point(stop.stop_lon, stop.stop_lat)) if total_dist < best_dist: best_dist = total_dist best_route = route if candidate_routes[0].route == 'S55': print "The MTA's route shape for S55 is from 2007. So we're skipping it." return None if candidate_routes[0].route == 'Q48': #this is a total hack; the Q48 is in general a total hack if len(stops) == 22: for route in candidate_routes: if route.gid == 10707: best_route = route #figure out if the set of stops is shorter than the best route #(the bus stops or ends in the middle of the route) and if so, #cut the route down. start_location = st_line_locate_point(best_route.the_geom, (stops[0].stop_lon, stops[0].stop_lat)) end_location = st_line_locate_point(best_route.the_geom, (stops[-1].stop_lon, stops[-1].stop_lat)) if start_location > end_location: print "Backwards route %s, Skipping." % route.gid return None if end_location - start_location < 0.98 and best_route.route not in loop_routes: if end_location - start_location < 0.05: print """"This is a very short route segment. Is it a miscategorized loop? Route: %s, first and last: %s, %s""" % ( best_route.route, stops[0].location, stops[-1].location) #create a new shape for the short route i = 0 while 1: new_gid = str(best_route.gid * 100 + 20000 + i) i += 1 try: feed.GetShape(new_gid) except KeyError: break shape = transitfeed.Shape(new_gid) #while a binary search for start and end would probably be #faster, it assumes that the shapes are correctly plotted in #ascending order, which they appear not to be. distance = 0 for point in best_route.the_geom.coords: last_distance = distance distance = st_line_locate_point(best_route.the_geom, point) if start_location <= distance - 0.001: if distance <= end_location + 0.001: shape.AddPoint(point[1], point[0]) else: line_distance_span = distance - last_distance; end_distance_span = end_location - last_distance; interp_ratio = end_distance_span / line_distance_span interp_x = last_point[1] * interp_ratio + point[1] * (1 - interp_ratio) interp_y = last_point[0] * interp_ratio + point[0] * (1 - interp_ratio) shape.AddPoint(interp_x, interp_y) last_point = point feed.AddShapeObject(shape) else: #not a too-short route try: shape = feed.GetShape(str(best_route.gid)) except KeyError: shape = transitfeed.Shape(str(best_route.gid)) for point in best_route.the_geom.coords: shape.AddPoint(point[1], point[0]) feed.AddShapeObject(shape) _shape_by_stops_cache[key] = shape return shape