instantiate bus routes from GTFS too

This commit is contained in:
Dustin Carlino 2018-09-07 12:47:45 -07:00
parent 143084a8a9
commit 58b01fce9e
6 changed files with 69 additions and 44 deletions

View File

@ -34,3 +34,10 @@ pub use parcel::{Parcel, ParcelID};
pub use pathfind::pathfind; pub use pathfind::pathfind;
pub use road::{Road, RoadID}; pub use road::{Road, RoadID};
pub use turn::{Turn, TurnID}; pub use turn::{Turn, TurnID};
// TODO This sort of doesn't fit in the map layer, but it's quite convenient to store it.
#[derive(Serialize, Deserialize, Debug)]
pub struct BusRoute {
pub name: String,
pub stops: Vec<BusStop>,
}

View File

@ -4,20 +4,23 @@ use gtfs;
use make::sidewalk_finder::find_sidewalk_points; use make::sidewalk_finder::find_sidewalk_points;
use multimap::MultiMap; use multimap::MultiMap;
use ordered_float::NotNaN; use ordered_float::NotNaN;
use std::collections::HashSet; use std::collections::{HashMap, HashSet};
use {BusStop, BusStopDetails, Lane, LaneID, Road}; use {BusRoute, BusStop, BusStopDetails, Lane, LaneID, Road};
pub fn make_bus_stops( pub fn make_bus_stops(
lanes: &mut Vec<Lane>, lanes: &mut Vec<Lane>,
roads: &Vec<Road>, roads: &Vec<Road>,
bus_routes: &Vec<gtfs::Route>, bus_routes: &Vec<gtfs::Route>,
bounds: &Bounds, bounds: &Bounds,
) { ) -> Vec<BusRoute> {
let mut bus_stop_pts: HashSet<HashablePt2D> = HashSet::new(); let mut bus_stop_pts: HashSet<HashablePt2D> = HashSet::new();
let mut route_lookups: MultiMap<String, HashablePt2D> = MultiMap::new();
for route in bus_routes { for route in bus_routes {
for gps in &route.stops { for gps in &route.stops {
if bounds.contains(gps.longitude, gps.latitude) { if bounds.contains(gps.longitude, gps.latitude) {
bus_stop_pts.insert(Pt2D::from_gps(&gps, bounds).into()); let pt: HashablePt2D = Pt2D::from_gps(&gps, bounds).into();
bus_stop_pts.insert(pt);
route_lookups.insert(route.name.to_string(), pt);
} }
} }
} }
@ -27,23 +30,39 @@ pub fn make_bus_stops(
bus_routes.len() bus_routes.len()
); );
let mut stops_per_sidewalk: MultiMap<LaneID, si::Meter<f64>> = MultiMap::new(); let mut stops_per_sidewalk: MultiMap<LaneID, (si::Meter<f64>, HashablePt2D)> = MultiMap::new();
for (lane, dist_along) in find_sidewalk_points(bus_stop_pts, lanes).values() { for (pt, (lane, dist_along)) in find_sidewalk_points(bus_stop_pts, lanes).iter() {
stops_per_sidewalk.insert(*lane, *dist_along); stops_per_sidewalk.insert(*lane, (*dist_along, *pt));
} }
let mut point_to_stop_idx: HashMap<HashablePt2D, BusStop> = HashMap::new();
for (id, dists) in stops_per_sidewalk.iter_all_mut() { for (id, dists) in stops_per_sidewalk.iter_all_mut() {
// TODO duplicate a little logic from map, and also, this is fragile :) // TODO duplicate a little logic from map, and also, this is fragile :)
let road = &roads[lanes[id.0].parent.0]; let road = &roads[lanes[id.0].parent.0];
let parking = road.find_parking_lane(*id).unwrap(); let parking = road.find_parking_lane(*id).unwrap();
let driving_lane = road.find_driving_lane(parking).unwrap(); let driving_lane = road.find_driving_lane(parking).unwrap();
dists.sort_by_key(|dist| NotNaN::new(dist.value_unsafe).unwrap()); dists.sort_by_key(|(dist, _)| NotNaN::new(dist.value_unsafe).unwrap());
for (idx, dist_along) in dists.iter().enumerate() { for (idx, (dist_along, orig_pt)) in dists.iter().enumerate() {
let stop_id = BusStop { sidewalk: *id, idx };
point_to_stop_idx.insert(*orig_pt, stop_id);
lanes[id.0].bus_stops.push(BusStopDetails { lanes[id.0].bus_stops.push(BusStopDetails {
id: BusStop { sidewalk: *id, idx }, id: stop_id,
driving_lane, driving_lane,
dist_along: *dist_along, dist_along: *dist_along,
}); });
} }
} }
let mut results: Vec<BusRoute> = Vec::new();
for (route_name, stop_points) in route_lookups.iter_all() {
if stop_points.len() == 1 {
//println!("Skipping route {} since it only has 1 stop in the slice of the map", route_name);
continue;
}
results.push(BusRoute {
name: route_name.to_string(),
stops: stop_points.iter().map(|pt| point_to_stop_idx[pt]).collect(),
});
}
results
} }

View File

@ -1,20 +1,18 @@
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0 // Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
use abstutil; use abstutil;
use building::{Building, BuildingID};
use edits::Edits; use edits::Edits;
use geom::{Bounds, HashablePt2D, PolyLine, Pt2D}; use geom::{Bounds, HashablePt2D, PolyLine, Pt2D};
use geometry; use geometry;
use intersection::{Intersection, IntersectionID};
use lane::{BusStop, BusStopDetails, Lane, LaneID, LaneType};
use make; use make;
use parcel::{Parcel, ParcelID};
use raw_data; use raw_data;
use road::{Road, RoadID};
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use std::io::Error; use std::io::Error;
use std::path; use std::path;
use turn::{Turn, TurnID}; use {
Building, BuildingID, BusRoute, BusStop, BusStopDetails, Intersection, IntersectionID, Lane,
LaneID, LaneType, Parcel, ParcelID, Road, RoadID, Turn, TurnID,
};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct Map { pub struct Map {
@ -24,6 +22,7 @@ pub struct Map {
turns: BTreeMap<TurnID, Turn>, turns: BTreeMap<TurnID, Turn>,
buildings: Vec<Building>, buildings: Vec<Building>,
parcels: Vec<Parcel>, parcels: Vec<Parcel>,
bus_routes: Vec<BusRoute>,
// TODO maybe dont need to retain GPS stuff later // TODO maybe dont need to retain GPS stuff later
bounds: Bounds, bounds: Bounds,
@ -57,6 +56,7 @@ impl Map {
turns: BTreeMap::new(), turns: BTreeMap::new(),
buildings: Vec::new(), buildings: Vec::new(),
parcels: Vec::new(), parcels: Vec::new(),
bus_routes: Vec::new(),
}; };
let mut pt_to_intersection: HashMap<HashablePt2D, IntersectionID> = HashMap::new(); let mut pt_to_intersection: HashMap<HashablePt2D, IntersectionID> = HashMap::new();
@ -152,7 +152,7 @@ impl Map {
} }
} }
make::make_bus_stops(&mut m.lanes, &m.roads, &data.bus_routes, &bounds); m.bus_routes = make::make_bus_stops(&mut m.lanes, &m.roads, &data.bus_routes, &bounds);
for i in &m.intersections { for i in &m.intersections {
for t in make::make_all_turns(i, &m) { for t in make::make_all_turns(i, &m) {
@ -363,4 +363,8 @@ impl Map {
pub fn get_bus_stop(&self, stop: BusStop) -> &BusStopDetails { pub fn get_bus_stop(&self, stop: BusStop) -> &BusStopDetails {
&self.get_l(stop.sidewalk).bus_stops[stop.idx] &self.get_l(stop.sidewalk).bus_stops[stop.idx]
} }
pub fn get_all_bus_routes(&self) -> &Vec<BusRoute> {
&self.bus_routes
}
} }

View File

@ -1,6 +1,6 @@
use abstutil; use abstutil;
use control::ControlMap; use control::ControlMap;
use map_model::{BuildingID, BusStop, Edits, LaneID, Map}; use map_model::{BuildingID, BusRoute, BusStop, Edits, LaneID, Map};
use rand::Rng; use rand::Rng;
use std::collections::VecDeque; use std::collections::VecDeque;
use {CarID, Event, PedestrianID, RouteID, Sim, Tick}; use {CarID, Event, PedestrianID, RouteID, Sim, Tick};
@ -94,16 +94,8 @@ impl Sim {
self.seed_walking_trips(&map, 100); self.seed_walking_trips(&map, 100);
self.seed_driving_trips(&map, 100); self.seed_driving_trips(&map, 100);
if self.seed_bus_route( for route in map.get_all_bus_routes() {
vec![ self.seed_bus_route(route, map);
map.get_l(LaneID(309)).bus_stops[0].id,
map.get_l(LaneID(325)).bus_stops[0].id,
map.get_l(LaneID(840)).bus_stops[0].id,
],
map,
).len() != 3
{
panic!("Three buses didn't fit");
} }
// TODO this is introducing nondeterminism, because of slight floating point errors. // TODO this is introducing nondeterminism, because of slight floating point errors.
// fragile that this causes it, but true. :\ // fragile that this causes it, but true. :\
@ -131,13 +123,13 @@ impl Sim {
} }
} }
pub fn seed_bus_route(&mut self, stops: Vec<BusStop>, map: &Map) -> Vec<CarID> { pub fn seed_bus_route(&mut self, route: &BusRoute, map: &Map) -> Vec<CarID> {
// TODO throw away the events? :( // TODO throw away the events? :(
let mut events: Vec<Event> = Vec::new(); let mut events: Vec<Event> = Vec::new();
let mut result: Vec<CarID> = Vec::new(); let mut result: Vec<CarID> = Vec::new();
for v in self.spawner.seed_bus_route( for v in self.spawner.seed_bus_route(
&mut events, &mut events,
stops, route,
&mut self.rng, &mut self.rng,
map, map,
&mut self.driving_state, &mut self.driving_state,

View File

@ -1,7 +1,7 @@
use driving::DrivingSimState; use driving::DrivingSimState;
use kinematics::Vehicle; use kinematics::Vehicle;
use map_model; use map_model;
use map_model::{BuildingID, BusStop, LaneID, Map}; use map_model::{BuildingID, BusRoute, BusStop, LaneID, Map};
use parking::ParkingSimState; use parking::ParkingSimState;
use rand::Rng; use rand::Rng;
use router::Router; use router::Router;
@ -166,7 +166,7 @@ impl Spawner {
pub fn seed_bus_route<R: Rng + ?Sized>( pub fn seed_bus_route<R: Rng + ?Sized>(
&mut self, &mut self,
events: &mut Vec<Event>, events: &mut Vec<Event>,
stops: Vec<BusStop>, route: &BusRoute,
rng: &mut R, rng: &mut R,
map: &Map, map: &Map,
driving_sim: &mut DrivingSimState, driving_sim: &mut DrivingSimState,
@ -174,11 +174,11 @@ impl Spawner {
now: Tick, now: Tick,
properties: &BTreeMap<CarID, Vehicle>, properties: &BTreeMap<CarID, Vehicle>,
) -> Vec<Vehicle> { ) -> Vec<Vehicle> {
let route = transit_sim.create_empty_route(stops, map); let route_id = transit_sim.create_empty_route(route, map);
let mut vehicles: Vec<Vehicle> = Vec::new(); let mut vehicles: Vec<Vehicle> = Vec::new();
// Try to spawn a bus at each stop // Try to spawn a bus at each stop
for (next_stop_idx, start_dist_along, mut path) in for (next_stop_idx, start_dist_along, mut path) in
transit_sim.get_route_starts(route, map).into_iter() transit_sim.get_route_starts(route_id, map).into_iter()
{ {
let id = CarID(self.car_id_counter); let id = CarID(self.car_id_counter);
self.car_id_counter += 1; self.car_id_counter += 1;
@ -196,13 +196,13 @@ impl Spawner {
map, map,
properties, properties,
) { ) {
transit_sim.bus_created(id, route, next_stop_idx); transit_sim.bus_created(id, route_id, next_stop_idx);
println!("Spawned bus {} for route {}", id, route); println!("Spawned bus {} for route {} ({})", id, route.name, route_id);
vehicles.push(vehicle); vehicles.push(vehicle);
} else { } else {
println!( println!(
"No room for a bus headed towards stop {} of {}, giving up", "No room for a bus headed towards stop {} of {} ({}), giving up",
next_stop_idx, route next_stop_idx, route.name, route_id
); );
} }
} }

View File

@ -3,7 +3,7 @@ use dimensioned::si;
use events::Event; use events::Event;
use instrument::capture_backtrace; use instrument::capture_backtrace;
use map_model; use map_model;
use map_model::{BusStop, BusStopDetails, LaneID, Map}; use map_model::{BusRoute, BusStopDetails, LaneID, Map};
use spawn::Spawner; use spawn::Spawner;
use std::collections::{BTreeMap, VecDeque}; use std::collections::{BTreeMap, VecDeque};
use trips::TripManager; use trips::TripManager;
@ -17,6 +17,7 @@ type StopIdx = usize;
#[derive(Serialize, Deserialize, PartialEq, Eq)] #[derive(Serialize, Deserialize, PartialEq, Eq)]
struct Route { struct Route {
id: RouteID, id: RouteID,
name: String,
buses: Vec<CarID>, buses: Vec<CarID>,
stops: Vec<BusStopDetails>, stops: Vec<BusStopDetails>,
// TODO info on schedules // TODO info on schedules
@ -65,17 +66,19 @@ impl TransitSimState {
} }
} }
pub fn create_empty_route(&mut self, stops: Vec<BusStop>, map: &Map) -> RouteID { pub fn create_empty_route(&mut self, route: &BusRoute, map: &Map) -> RouteID {
assert!(stops.len() > 1); assert!(route.stops.len() > 1);
let id = RouteID(self.routes.len()); let id = RouteID(self.routes.len());
self.routes.insert( self.routes.insert(
id, id,
Route { Route {
id, id,
name: route.name.clone(),
buses: Vec::new(), buses: Vec::new(),
stops: stops stops: route
.into_iter() .stops
.map(|s| map.get_bus_stop(s).clone()) .iter()
.map(|s| map.get_bus_stop(*s).clone())
.collect(), .collect(),
}, },
); );