mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-24 09:24:26 +03:00
At last, collapse the OD -> SpawnTrip -> TripSpec function into one thing. #258
This commit is contained in:
parent
7741ea79b5
commit
82c7cd1e8f
@ -469,7 +469,7 @@
|
||||
"size_bytes": 58767209
|
||||
},
|
||||
"data/system/seattle/prebaked_results/lakeslice/weekday.bin": {
|
||||
"checksum": "1da2f64c88888a6183849bd1e6a4b7f2",
|
||||
"checksum": "bfb09ece72ba926b9d7d2583736689fd",
|
||||
"size_bytes": 67024414
|
||||
},
|
||||
"data/system/seattle/prebaked_results/montlake/car vs bike contention.bin": {
|
||||
@ -477,7 +477,7 @@
|
||||
"size_bytes": 5277
|
||||
},
|
||||
"data/system/seattle/prebaked_results/montlake/weekday.bin": {
|
||||
"checksum": "72b8f5dbd00a8027eb6583346fd8ae4f",
|
||||
"checksum": "5817e0c4af88a8070577930effa409c5",
|
||||
"size_bytes": 9004723
|
||||
},
|
||||
"data/system/seattle/scenarios/ballard/weekday.bin": {
|
||||
|
@ -8,16 +8,12 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use abstutil::{prettyprint_usize, Counter, MapName, Parallelism, Timer};
|
||||
use geom::{Distance, Speed, Time};
|
||||
use map_model::{
|
||||
BuildingID, BusRouteID, BusStopID, DirectedRoadID, Map, OffstreetParking, PathConstraints,
|
||||
Position, RoadID,
|
||||
};
|
||||
use map_model::{BuildingID, Map, OffstreetParking, RoadID};
|
||||
|
||||
use crate::make::fork_rng;
|
||||
use crate::{
|
||||
CarID, DrivingGoal, OrigPersonID, ParkingSpot, PersonID, SidewalkSpot, Sim, TripEndpoint,
|
||||
TripInfo, TripMode, TripSpawner, TripSpec, Vehicle, VehicleSpec, VehicleType, BIKE_LENGTH,
|
||||
MAX_CAR_LENGTH, MIN_CAR_LENGTH, SPAWN_DIST,
|
||||
OrigPersonID, ParkingSpot, PersonID, Sim, TripEndpoint, TripInfo, TripMode, TripSpawner,
|
||||
TripSpec, Vehicle, VehicleSpec, VehicleType, BIKE_LENGTH, MAX_CAR_LENGTH, MIN_CAR_LENGTH,
|
||||
};
|
||||
|
||||
/// A Scenario describes all the input to a simulation. Usually a scenario covers one day.
|
||||
@ -71,32 +67,6 @@ impl IndividTrip {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
enum SpawnTrip {
|
||||
/// Only for interactive / debug trips
|
||||
VehicleAppearing {
|
||||
start: Position,
|
||||
goal: DrivingGoal,
|
||||
is_bike: bool,
|
||||
},
|
||||
FromBorder {
|
||||
dr: DirectedRoadID,
|
||||
goal: DrivingGoal,
|
||||
/// For bikes starting at a border, use FromBorder. UsingBike implies a walk->bike trip.
|
||||
is_bike: bool,
|
||||
},
|
||||
UsingParkedCar(BuildingID, DrivingGoal),
|
||||
UsingBike(BuildingID, DrivingGoal),
|
||||
JustWalking(SidewalkSpot, SidewalkSpot),
|
||||
UsingTransit(
|
||||
SidewalkSpot,
|
||||
SidewalkSpot,
|
||||
BusRouteID,
|
||||
BusStopID,
|
||||
Option<BusStopID>,
|
||||
),
|
||||
}
|
||||
|
||||
/// Lifted from Seattle's Soundcast model, but seems general enough to use anyhere.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||
pub enum TripPurpose {
|
||||
@ -195,17 +165,19 @@ impl Scenario {
|
||||
// The RNG call might change over edits for picking the spawning lane from a border
|
||||
// with multiple choices for a vehicle type.
|
||||
let mut tmp_rng = fork_rng(rng);
|
||||
let spec = match SpawnTrip::new(t.from.clone(), t.to.clone(), t.mode, map) {
|
||||
Some(trip) => trip.to_trip_spec(
|
||||
maybe_idx.map(|idx| person.vehicles[idx].id),
|
||||
retry_if_no_room,
|
||||
&mut tmp_rng,
|
||||
map,
|
||||
),
|
||||
None => TripSpec::SpawningFailure {
|
||||
let spec = match TripSpec::maybe_new(
|
||||
t.from.clone(),
|
||||
t.to.clone(),
|
||||
t.mode,
|
||||
maybe_idx.map(|idx| person.vehicles[idx].id),
|
||||
retry_if_no_room,
|
||||
&mut tmp_rng,
|
||||
map,
|
||||
) {
|
||||
Ok(spec) => spec,
|
||||
Err(error) => TripSpec::SpawningFailure {
|
||||
use_vehicle: maybe_idx.map(|idx| person.vehicles[idx].id),
|
||||
// TODO Collapse SpawnTrip::new and to_trip_spec and plumb better errors
|
||||
error: format!("unknown spawning error"),
|
||||
error,
|
||||
},
|
||||
};
|
||||
schedule_trips.push((
|
||||
@ -461,116 +433,6 @@ fn find_spot_near_building(
|
||||
}
|
||||
}
|
||||
|
||||
impl SpawnTrip {
|
||||
fn to_trip_spec(
|
||||
self,
|
||||
use_vehicle: Option<CarID>,
|
||||
retry_if_no_room: bool,
|
||||
rng: &mut XorShiftRng,
|
||||
map: &Map,
|
||||
) -> TripSpec {
|
||||
match self {
|
||||
SpawnTrip::VehicleAppearing { start, goal, .. } => TripSpec::VehicleAppearing {
|
||||
start_pos: start,
|
||||
goal,
|
||||
use_vehicle: use_vehicle.unwrap(),
|
||||
retry_if_no_room,
|
||||
},
|
||||
SpawnTrip::FromBorder { dr, goal, is_bike } => {
|
||||
let constraints = if is_bike {
|
||||
PathConstraints::Bike
|
||||
} else {
|
||||
PathConstraints::Car
|
||||
};
|
||||
if let Some(l) = dr.lanes(constraints, map).choose(rng) {
|
||||
TripSpec::VehicleAppearing {
|
||||
start_pos: Position::new(*l, SPAWN_DIST),
|
||||
goal,
|
||||
use_vehicle: use_vehicle.unwrap(),
|
||||
retry_if_no_room,
|
||||
}
|
||||
} else {
|
||||
TripSpec::SpawningFailure {
|
||||
use_vehicle,
|
||||
error: format!("{} has no lanes to spawn a {:?}", dr.id, constraints),
|
||||
}
|
||||
}
|
||||
}
|
||||
SpawnTrip::UsingParkedCar(start_bldg, goal) => TripSpec::UsingParkedCar {
|
||||
start_bldg,
|
||||
goal,
|
||||
car: use_vehicle.unwrap(),
|
||||
},
|
||||
SpawnTrip::UsingBike(start, goal) => TripSpec::UsingBike {
|
||||
bike: use_vehicle.unwrap(),
|
||||
start,
|
||||
goal,
|
||||
},
|
||||
SpawnTrip::JustWalking(start, goal) => TripSpec::JustWalking { start, goal },
|
||||
SpawnTrip::UsingTransit(start, goal, route, stop1, maybe_stop2) => {
|
||||
TripSpec::UsingTransit {
|
||||
start,
|
||||
goal,
|
||||
route,
|
||||
stop1,
|
||||
maybe_stop2,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn new(from: TripEndpoint, to: TripEndpoint, mode: TripMode, map: &Map) -> Option<SpawnTrip> {
|
||||
Some(match mode {
|
||||
TripMode::Drive => match from {
|
||||
TripEndpoint::Bldg(b) => {
|
||||
SpawnTrip::UsingParkedCar(b, to.driving_goal(PathConstraints::Car, map)?)
|
||||
}
|
||||
TripEndpoint::Border(i) => SpawnTrip::FromBorder {
|
||||
dr: map.get_i(i).some_outgoing_road(map)?,
|
||||
goal: to.driving_goal(PathConstraints::Car, map)?,
|
||||
is_bike: false,
|
||||
},
|
||||
TripEndpoint::SuddenlyAppear(start) => SpawnTrip::VehicleAppearing {
|
||||
start,
|
||||
goal: to.driving_goal(PathConstraints::Bike, map)?,
|
||||
is_bike: false,
|
||||
},
|
||||
},
|
||||
TripMode::Bike => match from {
|
||||
TripEndpoint::Bldg(b) => {
|
||||
SpawnTrip::UsingBike(b, to.driving_goal(PathConstraints::Bike, map)?)
|
||||
}
|
||||
TripEndpoint::Border(i) => SpawnTrip::FromBorder {
|
||||
dr: map.get_i(i).some_outgoing_road(map)?,
|
||||
goal: to.driving_goal(PathConstraints::Bike, map)?,
|
||||
is_bike: true,
|
||||
},
|
||||
TripEndpoint::SuddenlyAppear(start) => SpawnTrip::VehicleAppearing {
|
||||
start,
|
||||
goal: to.driving_goal(PathConstraints::Bike, map)?,
|
||||
is_bike: true,
|
||||
},
|
||||
},
|
||||
TripMode::Walk => {
|
||||
SpawnTrip::JustWalking(from.start_sidewalk_spot(map)?, to.end_sidewalk_spot(map)?)
|
||||
}
|
||||
TripMode::Transit => {
|
||||
let start = from.start_sidewalk_spot(map)?;
|
||||
let goal = to.end_sidewalk_spot(map)?;
|
||||
if let Some((stop1, maybe_stop2, route)) =
|
||||
map.should_use_transit(start.sidewalk_pos, goal.sidewalk_pos)
|
||||
{
|
||||
SpawnTrip::UsingTransit(start, goal, route, stop1, maybe_stop2)
|
||||
} else {
|
||||
//timer.warn(format!("{:?} not actually using transit, because pathfinding
|
||||
// didn't find any useful route", trip));
|
||||
SpawnTrip::JustWalking(start, goal)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PersonSpec {
|
||||
// Verify that the trip start/endpoints of the person match up
|
||||
fn check_schedule(&self) -> Result<(), String> {
|
||||
|
@ -1,14 +1,16 @@
|
||||
//! Intermediate structures used to instantiate a Scenario. Badly needs simplification:
|
||||
//! https://github.com/dabreegster/abstreet/issues/258
|
||||
|
||||
use rand::seq::SliceRandom;
|
||||
use rand_xorshift::XorShiftRng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use abstutil::Timer;
|
||||
use map_model::{BuildingID, BusRouteID, BusStopID, Map, PathConstraints, PathRequest, Position};
|
||||
|
||||
use crate::{
|
||||
CarID, Command, DrivingGoal, PersonID, Scheduler, SidewalkSpot, TripInfo, TripLeg, TripManager,
|
||||
VehicleType,
|
||||
CarID, Command, DrivingGoal, PersonID, Scheduler, SidewalkSpot, TripEndpoint, TripInfo,
|
||||
TripLeg, TripManager, TripMode, VehicleType, SPAWN_DIST,
|
||||
};
|
||||
|
||||
// TODO Some of these fields are unused now that we separately pass TripEndpoint
|
||||
@ -203,7 +205,6 @@ impl TripSpawner {
|
||||
}
|
||||
TripSpec::SpawningFailure { .. } => {
|
||||
// TODO Is it OK to have empty trip legs?
|
||||
// TODO Do we have to cancel the trip or move the vehicle here?
|
||||
let legs = Vec::new();
|
||||
trips.new_trip(person.id, info, legs)
|
||||
}
|
||||
@ -271,7 +272,7 @@ impl TripSpawner {
|
||||
}
|
||||
|
||||
impl TripSpec {
|
||||
pub(crate) fn get_pathfinding_request(&self, map: &Map) -> Option<PathRequest> {
|
||||
pub fn get_pathfinding_request(&self, map: &Map) -> Option<PathRequest> {
|
||||
match self {
|
||||
TripSpec::VehicleAppearing {
|
||||
start_pos,
|
||||
@ -310,4 +311,88 @@ impl TripSpec {
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Turn an origin/destination pair and mode into a specific plan for instantiating a trip.
|
||||
/// Decisions like how to use public transit happen here.
|
||||
pub fn maybe_new(
|
||||
from: TripEndpoint,
|
||||
to: TripEndpoint,
|
||||
mode: TripMode,
|
||||
use_vehicle: Option<CarID>,
|
||||
retry_if_no_room: bool,
|
||||
rng: &mut XorShiftRng,
|
||||
map: &Map,
|
||||
) -> Result<TripSpec, String> {
|
||||
Ok(match mode {
|
||||
TripMode::Drive | TripMode::Bike => {
|
||||
let constraints = if mode == TripMode::Drive {
|
||||
PathConstraints::Car
|
||||
} else {
|
||||
PathConstraints::Bike
|
||||
};
|
||||
let goal = to.driving_goal(constraints, map)?;
|
||||
match from {
|
||||
TripEndpoint::Bldg(start_bldg) => {
|
||||
if mode == TripMode::Drive {
|
||||
TripSpec::UsingParkedCar {
|
||||
start_bldg,
|
||||
goal,
|
||||
car: use_vehicle.unwrap(),
|
||||
}
|
||||
} else {
|
||||
TripSpec::UsingBike {
|
||||
start: start_bldg,
|
||||
goal,
|
||||
bike: use_vehicle.unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
TripEndpoint::Border(i) => {
|
||||
let start_lane = map
|
||||
.get_i(i)
|
||||
.some_outgoing_road(map)
|
||||
.and_then(|dr| dr.lanes(constraints, map).choose(rng).cloned())
|
||||
.ok_or_else(|| {
|
||||
format!("can't start a {} trip from {}", mode.ongoing_verb(), i)
|
||||
})?;
|
||||
TripSpec::VehicleAppearing {
|
||||
start_pos: Position::new(start_lane, SPAWN_DIST),
|
||||
goal,
|
||||
use_vehicle: use_vehicle.unwrap(),
|
||||
retry_if_no_room,
|
||||
}
|
||||
}
|
||||
TripEndpoint::SuddenlyAppear(start_pos) => TripSpec::VehicleAppearing {
|
||||
start_pos,
|
||||
goal,
|
||||
use_vehicle: use_vehicle.unwrap(),
|
||||
retry_if_no_room,
|
||||
},
|
||||
}
|
||||
}
|
||||
TripMode::Walk => TripSpec::JustWalking {
|
||||
start: from.start_sidewalk_spot(map)?,
|
||||
goal: to.end_sidewalk_spot(map)?,
|
||||
},
|
||||
TripMode::Transit => {
|
||||
let start = from.start_sidewalk_spot(map)?;
|
||||
let goal = to.end_sidewalk_spot(map)?;
|
||||
if let Some((stop1, maybe_stop2, route)) =
|
||||
map.should_use_transit(start.sidewalk_pos, goal.sidewalk_pos)
|
||||
{
|
||||
TripSpec::UsingTransit {
|
||||
start,
|
||||
goal,
|
||||
route,
|
||||
stop1,
|
||||
maybe_stop2,
|
||||
}
|
||||
} else {
|
||||
//timer.warn(format!("{:?} not actually using transit, because pathfinding
|
||||
// didn't find any useful route", trip));
|
||||
TripSpec::JustWalking { start, goal }
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1598,19 +1598,22 @@ pub enum PersonState {
|
||||
OffMap,
|
||||
}
|
||||
|
||||
// TODO Move these to make/spawner?
|
||||
impl TripEndpoint {
|
||||
pub(crate) fn start_sidewalk_spot(&self, map: &Map) -> Option<SidewalkSpot> {
|
||||
pub(crate) fn start_sidewalk_spot(&self, map: &Map) -> Result<SidewalkSpot, String> {
|
||||
match self {
|
||||
TripEndpoint::Bldg(b) => Some(SidewalkSpot::building(*b, map)),
|
||||
TripEndpoint::Border(i) => SidewalkSpot::start_at_border(*i, map),
|
||||
TripEndpoint::SuddenlyAppear(pos) => Some(SidewalkSpot::suddenly_appear(*pos, map)),
|
||||
TripEndpoint::Bldg(b) => Ok(SidewalkSpot::building(*b, map)),
|
||||
TripEndpoint::Border(i) => SidewalkSpot::start_at_border(*i, map)
|
||||
.ok_or_else(|| format!("can't start walking from {}", i)),
|
||||
TripEndpoint::SuddenlyAppear(pos) => Ok(SidewalkSpot::suddenly_appear(*pos, map)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn end_sidewalk_spot(&self, map: &Map) -> Option<SidewalkSpot> {
|
||||
pub(crate) fn end_sidewalk_spot(&self, map: &Map) -> Result<SidewalkSpot, String> {
|
||||
match self {
|
||||
TripEndpoint::Bldg(b) => Some(SidewalkSpot::building(*b, map)),
|
||||
TripEndpoint::Border(i) => SidewalkSpot::end_at_border(*i, map),
|
||||
TripEndpoint::Bldg(b) => Ok(SidewalkSpot::building(*b, map)),
|
||||
TripEndpoint::Border(i) => SidewalkSpot::end_at_border(*i, map)
|
||||
.ok_or_else(|| format!("can't end walking at {}", i)),
|
||||
TripEndpoint::SuddenlyAppear(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
@ -1619,12 +1622,14 @@ impl TripEndpoint {
|
||||
&self,
|
||||
constraints: PathConstraints,
|
||||
map: &Map,
|
||||
) -> Option<DrivingGoal> {
|
||||
) -> Result<DrivingGoal, String> {
|
||||
match self {
|
||||
TripEndpoint::Bldg(b) => Some(DrivingGoal::ParkNear(*b)),
|
||||
TripEndpoint::Border(i) => {
|
||||
DrivingGoal::end_at_border(map.get_i(*i).some_incoming_road(map)?, constraints, map)
|
||||
}
|
||||
TripEndpoint::Bldg(b) => Ok(DrivingGoal::ParkNear(*b)),
|
||||
TripEndpoint::Border(i) => map
|
||||
.get_i(*i)
|
||||
.some_incoming_road(map)
|
||||
.and_then(|dr| DrivingGoal::end_at_border(dr, constraints, map))
|
||||
.ok_or_else(|| format!("can't end at {} for {:?}", i, constraints)),
|
||||
TripEndpoint::SuddenlyAppear(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user