mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-28 12:12:00 +03:00
instantiate bus routes from GTFS too
This commit is contained in:
parent
143084a8a9
commit
58b01fce9e
@ -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>,
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user