mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-24 01:15:12 +03:00
Simplify the old ScenarioGenerator, mostly by removing OriginDestination
in favor of Option<TripEndpoint>. The bike/car contention tutorial stage has to be tweaked manually, since there's no longer a nice way to spawn vehicles at a non-border intersection and force them to use a certain DirectedRoad. #258
This commit is contained in:
parent
0599d4b47b
commit
8d28274736
@ -473,8 +473,8 @@
|
||||
"size_bytes": 67024414
|
||||
},
|
||||
"data/system/seattle/prebaked_results/montlake/car vs bike contention.bin": {
|
||||
"checksum": "b49475b95dbc7663c704fac8eac9e35a",
|
||||
"size_bytes": 5226
|
||||
"checksum": "35ddb56c2668365156c256b91cc3aee1",
|
||||
"size_bytes": 5277
|
||||
},
|
||||
"data/system/seattle/prebaked_results/montlake/weekday.bin": {
|
||||
"checksum": "72b8f5dbd00a8027eb6583346fd8ae4f",
|
||||
|
@ -3,11 +3,10 @@ use std::collections::BTreeSet;
|
||||
use abstutil::Timer;
|
||||
use geom::{ArrowCap, Distance, Duration, PolyLine, Pt2D, Time};
|
||||
use map_model::raw::OriginalRoad;
|
||||
use map_model::{osm, BuildingID, DirectedRoadID, Direction, Map, Position};
|
||||
use map_model::{osm, BuildingID, Map, Position};
|
||||
use sim::{
|
||||
AgentID, Analytics, BorderSpawnOverTime, CarID, IndividTrip, OriginDestination, PersonID,
|
||||
PersonSpec, Scenario, ScenarioGenerator, SpawnOverTime, SpawnTrip, TripEndpoint, TripMode,
|
||||
TripPurpose, VehicleType,
|
||||
AgentID, Analytics, BorderSpawnOverTime, CarID, IndividTrip, PersonID, PersonSpec, Scenario,
|
||||
ScenarioGenerator, SpawnOverTime, SpawnTrip, TripEndpoint, TripMode, TripPurpose, VehicleType,
|
||||
};
|
||||
use widgetry::{
|
||||
hotkeys, lctrl, Btn, Color, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel,
|
||||
@ -27,7 +26,7 @@ use crate::sandbox::{
|
||||
};
|
||||
|
||||
const ESCORT: CarID = CarID(0, VehicleType::Car);
|
||||
const CAR_BIKE_CONTENTION_GOAL: Duration = Duration::const_seconds(60.0);
|
||||
const CAR_BIKE_CONTENTION_GOAL: Duration = Duration::const_seconds(15.0);
|
||||
|
||||
pub struct Tutorial {
|
||||
top_center: Panel,
|
||||
@ -656,13 +655,10 @@ fn make_bike_lane_scenario(map: &Map) -> ScenarioGenerator {
|
||||
percent_use_transit: 0.0,
|
||||
start_time: Time::START_OF_DAY,
|
||||
stop_time: Time::START_OF_DAY + Duration::seconds(10.0),
|
||||
start_from_border: DirectedRoadID {
|
||||
id: map
|
||||
.find_r_by_osm_id(OriginalRoad::new(263665925, (2499826475, 53096959)))
|
||||
.unwrap(),
|
||||
dir: Direction::Back,
|
||||
},
|
||||
goal: OriginDestination::GotoBldg(map.find_b_by_osm_id(bldg(217699501)).unwrap()),
|
||||
start_from_border: map.find_i_by_osm_id(osm::NodeID(3005680098)).unwrap(),
|
||||
goal: Some(TripEndpoint::Bldg(
|
||||
map.find_b_by_osm_id(bldg(217699501)).unwrap(),
|
||||
)),
|
||||
});
|
||||
s
|
||||
}
|
||||
@ -1175,7 +1171,7 @@ impl TutorialState {
|
||||
num_agents: 1000,
|
||||
start_time: Time::START_OF_DAY,
|
||||
stop_time: Time::START_OF_DAY + Duration::hours(3),
|
||||
goal: OriginDestination::Anywhere,
|
||||
goal: None,
|
||||
percent_driving: 1.0,
|
||||
percent_biking: 0.0,
|
||||
percent_use_transit: 0.0,
|
||||
|
@ -34,8 +34,8 @@ pub(crate) use self::events::Event;
|
||||
pub use self::events::{AlertLocation, TripPhaseType};
|
||||
pub use self::make::{
|
||||
BorderSpawnOverTime, ExternalPerson, ExternalTrip, ExternalTripEndpoint, IndividTrip,
|
||||
OriginDestination, PersonSpec, Scenario, ScenarioGenerator, ScenarioModifier, SimFlags,
|
||||
SpawnOverTime, SpawnTrip, TripPurpose,
|
||||
PersonSpec, Scenario, ScenarioGenerator, ScenarioModifier, SimFlags, SpawnOverTime, SpawnTrip,
|
||||
TripPurpose,
|
||||
};
|
||||
pub(crate) use self::make::{TripSpawner, TripSpec};
|
||||
pub(crate) use self::mechanics::{
|
||||
|
@ -10,12 +10,14 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use abstutil::Timer;
|
||||
use geom::{Duration, Time};
|
||||
use map_model::{BuildingID, DirectedRoadID, Map, PathConstraints};
|
||||
use map_model::{IntersectionID, Map};
|
||||
|
||||
use crate::{
|
||||
DrivingGoal, IndividTrip, PersonID, PersonSpec, Scenario, SidewalkSpot, SpawnTrip, TripPurpose,
|
||||
IndividTrip, PersonID, PersonSpec, Scenario, SpawnTrip, TripEndpoint, TripMode, TripPurpose,
|
||||
};
|
||||
|
||||
// TODO This can be simplified dramatically.
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct ScenarioGenerator {
|
||||
pub scenario_name: String,
|
||||
@ -34,7 +36,7 @@ pub struct SpawnOverTime {
|
||||
// TODO use https://docs.rs/rand/0.5.5/rand/distributions/struct.Normal.html
|
||||
pub start_time: Time,
|
||||
pub stop_time: Time,
|
||||
pub goal: OriginDestination,
|
||||
pub goal: Option<TripEndpoint>,
|
||||
pub percent_driving: f64,
|
||||
pub percent_biking: f64,
|
||||
pub percent_use_transit: f64,
|
||||
@ -49,8 +51,8 @@ pub struct BorderSpawnOverTime {
|
||||
// TODO use https://docs.rs/rand/0.5.5/rand/distributions/struct.Normal.html
|
||||
pub start_time: Time,
|
||||
pub stop_time: Time,
|
||||
pub start_from_border: DirectedRoadID,
|
||||
pub goal: OriginDestination,
|
||||
pub start_from_border: IntersectionID,
|
||||
pub goal: Option<TripEndpoint>,
|
||||
}
|
||||
|
||||
impl ScenarioGenerator {
|
||||
@ -65,30 +67,27 @@ impl ScenarioGenerator {
|
||||
timer.start_iter("SpawnOverTime each agent", s.num_agents);
|
||||
for _ in 0..s.num_agents {
|
||||
timer.next();
|
||||
s.spawn_agent(rng, &mut scenario, map, timer);
|
||||
s.spawn_agent(rng, &mut scenario, map);
|
||||
}
|
||||
}
|
||||
|
||||
timer.start_iter("BorderSpawnOverTime", self.border_spawn_over_time.len());
|
||||
for s in &self.border_spawn_over_time {
|
||||
timer.next();
|
||||
s.spawn_peds(rng, &mut scenario, map, timer);
|
||||
s.spawn_vehicles(
|
||||
s.num_cars,
|
||||
PathConstraints::Car,
|
||||
rng,
|
||||
&mut scenario,
|
||||
map,
|
||||
timer,
|
||||
);
|
||||
s.spawn_vehicles(
|
||||
s.num_bikes,
|
||||
PathConstraints::Bike,
|
||||
rng,
|
||||
&mut scenario,
|
||||
map,
|
||||
timer,
|
||||
);
|
||||
for _ in 0..s.num_peds {
|
||||
let mode = if rng.gen_bool(s.percent_use_transit) {
|
||||
TripMode::Transit
|
||||
} else {
|
||||
TripMode::Walk
|
||||
};
|
||||
s.spawn(rng, &mut scenario, mode, map);
|
||||
}
|
||||
for _ in 0..s.num_cars {
|
||||
s.spawn(rng, &mut scenario, TripMode::Drive, map);
|
||||
}
|
||||
for _ in 0..s.num_bikes {
|
||||
s.spawn(rng, &mut scenario, TripMode::Bike, map);
|
||||
}
|
||||
}
|
||||
|
||||
timer.stop(format!("Generating scenario {}", self.scenario_name));
|
||||
@ -103,7 +102,7 @@ impl ScenarioGenerator {
|
||||
num_agents: 100,
|
||||
start_time: Time::START_OF_DAY,
|
||||
stop_time: Time::START_OF_DAY + Duration::seconds(5.0),
|
||||
goal: OriginDestination::Anywhere,
|
||||
goal: None,
|
||||
percent_driving: 0.5,
|
||||
percent_biking: 0.5,
|
||||
percent_use_transit: 0.5,
|
||||
@ -119,8 +118,8 @@ impl ScenarioGenerator {
|
||||
num_bikes: 10,
|
||||
start_time: Time::START_OF_DAY,
|
||||
stop_time: Time::START_OF_DAY + Duration::seconds(5.0),
|
||||
start_from_border: i.some_outgoing_road(map).unwrap(),
|
||||
goal: OriginDestination::Anywhere,
|
||||
start_from_border: i.id,
|
||||
goal: None,
|
||||
percent_use_transit: 0.5,
|
||||
})
|
||||
.collect(),
|
||||
@ -130,7 +129,7 @@ impl ScenarioGenerator {
|
||||
num_agents: 10,
|
||||
start_time: Time::START_OF_DAY,
|
||||
stop_time: Time::START_OF_DAY + Duration::seconds(5.0),
|
||||
goal: OriginDestination::EndOfRoad(i.some_incoming_road(map).unwrap()),
|
||||
goal: Some(TripEndpoint::Border(i.id)),
|
||||
percent_driving: 0.5,
|
||||
percent_biking: 0.5,
|
||||
percent_use_transit: 0.5,
|
||||
@ -157,7 +156,7 @@ impl ScenarioGenerator {
|
||||
num_agents: num_agents,
|
||||
start_time: Time::START_OF_DAY,
|
||||
stop_time: Time::START_OF_DAY + Duration::seconds(5.0),
|
||||
goal: OriginDestination::Anywhere,
|
||||
goal: None,
|
||||
percent_driving: 0.5,
|
||||
percent_biking: 0.5,
|
||||
percent_use_transit: 0.5,
|
||||
@ -168,246 +167,55 @@ impl ScenarioGenerator {
|
||||
}
|
||||
|
||||
impl SpawnOverTime {
|
||||
fn spawn_agent(
|
||||
&self,
|
||||
rng: &mut XorShiftRng,
|
||||
scenario: &mut Scenario,
|
||||
map: &Map,
|
||||
timer: &mut Timer,
|
||||
) {
|
||||
fn spawn_agent(&self, rng: &mut XorShiftRng, scenario: &mut Scenario, map: &Map) {
|
||||
let depart = rand_time(rng, self.start_time, self.stop_time);
|
||||
// Note that it's fine for agents to start/end at the same building. Later we might
|
||||
// want a better assignment of people per household, or workers per office building.
|
||||
let from_bldg = map.all_buildings().choose(rng).unwrap().id;
|
||||
let id = PersonID(scenario.people.len());
|
||||
|
||||
if rng.gen_bool(self.percent_driving) {
|
||||
if let Some(goal) = self
|
||||
.goal
|
||||
.pick_driving_goal(PathConstraints::Car, map, rng, timer)
|
||||
{
|
||||
scenario.people.push(PersonSpec {
|
||||
id,
|
||||
orig_id: None,
|
||||
trips: vec![IndividTrip::new(
|
||||
depart,
|
||||
TripPurpose::Shopping,
|
||||
SpawnTrip::UsingParkedCar(from_bldg, goal),
|
||||
)],
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if rng.gen_bool(self.percent_biking) {
|
||||
if let Some(goal) = self
|
||||
.goal
|
||||
.pick_driving_goal(PathConstraints::Bike, map, rng, timer)
|
||||
{
|
||||
scenario.people.push(PersonSpec {
|
||||
id,
|
||||
orig_id: None,
|
||||
trips: vec![IndividTrip::new(
|
||||
depart,
|
||||
TripPurpose::Shopping,
|
||||
SpawnTrip::UsingBike(from_bldg, goal),
|
||||
)],
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let start_spot = SidewalkSpot::building(from_bldg, map);
|
||||
if let Some(goal) = self.goal.pick_walking_goal(map, rng, timer) {
|
||||
if start_spot == goal {
|
||||
timer.warn("Skipping walking trip between same two buildings".to_string());
|
||||
return;
|
||||
}
|
||||
|
||||
if rng.gen_bool(self.percent_use_transit) {
|
||||
// TODO This throws away some work. It also sequentially does expensive
|
||||
// work right here.
|
||||
if let Some((stop1, maybe_stop2, route)) =
|
||||
map.should_use_transit(start_spot.sidewalk_pos, goal.sidewalk_pos)
|
||||
{
|
||||
scenario.people.push(PersonSpec {
|
||||
id,
|
||||
orig_id: None,
|
||||
trips: vec![IndividTrip::new(
|
||||
depart,
|
||||
TripPurpose::Shopping,
|
||||
SpawnTrip::UsingTransit(start_spot, goal, route, stop1, maybe_stop2),
|
||||
)],
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let mode = if rng.gen_bool(self.percent_driving) {
|
||||
TripMode::Drive
|
||||
} else if rng.gen_bool(self.percent_biking) {
|
||||
TripMode::Bike
|
||||
} else if rng.gen_bool(self.percent_use_transit) {
|
||||
TripMode::Transit
|
||||
} else {
|
||||
TripMode::Walk
|
||||
};
|
||||
if let Some(trip) = SpawnTrip::new(
|
||||
TripEndpoint::Bldg(from_bldg),
|
||||
self.goal
|
||||
.clone()
|
||||
.unwrap_or_else(|| TripEndpoint::Bldg(map.all_buildings().choose(rng).unwrap().id)),
|
||||
mode,
|
||||
map,
|
||||
) {
|
||||
scenario.people.push(PersonSpec {
|
||||
id,
|
||||
orig_id: None,
|
||||
trips: vec![IndividTrip::new(
|
||||
depart,
|
||||
TripPurpose::Shopping,
|
||||
SpawnTrip::JustWalking(start_spot, goal),
|
||||
)],
|
||||
trips: vec![IndividTrip::new(depart, TripPurpose::Shopping, trip)],
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
timer.warn(format!("Couldn't fulfill {:?} at all", self));
|
||||
}
|
||||
}
|
||||
|
||||
impl BorderSpawnOverTime {
|
||||
fn spawn_peds(
|
||||
&self,
|
||||
rng: &mut XorShiftRng,
|
||||
scenario: &mut Scenario,
|
||||
map: &Map,
|
||||
timer: &mut Timer,
|
||||
) {
|
||||
if self.num_peds == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let start = if let Some(s) =
|
||||
SidewalkSpot::start_at_border(self.start_from_border.src_i(map), map)
|
||||
{
|
||||
s
|
||||
} else {
|
||||
timer.warn(format!(
|
||||
"Can't start_at_border for {} without sidewalk",
|
||||
self.start_from_border
|
||||
));
|
||||
return;
|
||||
};
|
||||
|
||||
for _ in 0..self.num_peds {
|
||||
let depart = rand_time(rng, self.start_time, self.stop_time);
|
||||
let id = PersonID(scenario.people.len());
|
||||
if let Some(goal) = self.goal.pick_walking_goal(map, rng, timer) {
|
||||
if rng.gen_bool(self.percent_use_transit) {
|
||||
// TODO This throws away some work. It also sequentially does expensive
|
||||
// work right here.
|
||||
if let Some((stop1, maybe_stop2, route)) =
|
||||
map.should_use_transit(start.sidewalk_pos, goal.sidewalk_pos)
|
||||
{
|
||||
scenario.people.push(PersonSpec {
|
||||
id,
|
||||
orig_id: None,
|
||||
trips: vec![IndividTrip::new(
|
||||
depart,
|
||||
TripPurpose::Shopping,
|
||||
SpawnTrip::UsingTransit(
|
||||
start.clone(),
|
||||
goal,
|
||||
route,
|
||||
stop1,
|
||||
maybe_stop2,
|
||||
),
|
||||
)],
|
||||
});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
scenario.people.push(PersonSpec {
|
||||
id,
|
||||
orig_id: None,
|
||||
trips: vec![IndividTrip::new(
|
||||
depart,
|
||||
TripPurpose::Shopping,
|
||||
SpawnTrip::JustWalking(start.clone(), goal),
|
||||
)],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn_vehicles(
|
||||
&self,
|
||||
num: usize,
|
||||
constraints: PathConstraints,
|
||||
rng: &mut XorShiftRng,
|
||||
scenario: &mut Scenario,
|
||||
map: &Map,
|
||||
timer: &mut Timer,
|
||||
) {
|
||||
for _ in 0..num {
|
||||
let depart = rand_time(rng, self.start_time, self.stop_time);
|
||||
if let Some(goal) = self.goal.pick_driving_goal(constraints, map, rng, timer) {
|
||||
let id = PersonID(scenario.people.len());
|
||||
scenario.people.push(PersonSpec {
|
||||
id,
|
||||
orig_id: None,
|
||||
trips: vec![IndividTrip::new(
|
||||
depart,
|
||||
TripPurpose::Shopping,
|
||||
SpawnTrip::FromBorder {
|
||||
dr: self.start_from_border,
|
||||
goal,
|
||||
is_bike: constraints == PathConstraints::Bike,
|
||||
},
|
||||
)],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub enum OriginDestination {
|
||||
Anywhere,
|
||||
EndOfRoad(DirectedRoadID),
|
||||
GotoBldg(BuildingID),
|
||||
}
|
||||
|
||||
impl OriginDestination {
|
||||
fn pick_driving_goal(
|
||||
&self,
|
||||
constraints: PathConstraints,
|
||||
map: &Map,
|
||||
rng: &mut XorShiftRng,
|
||||
timer: &mut Timer,
|
||||
) -> Option<DrivingGoal> {
|
||||
match self {
|
||||
OriginDestination::Anywhere => Some(DrivingGoal::ParkNear(
|
||||
map.all_buildings().choose(rng).unwrap().id,
|
||||
)),
|
||||
OriginDestination::GotoBldg(b) => Some(DrivingGoal::ParkNear(*b)),
|
||||
OriginDestination::EndOfRoad(dr) => {
|
||||
let goal = DrivingGoal::end_at_border(*dr, constraints, map);
|
||||
if goal.is_none() {
|
||||
timer.warn(format!(
|
||||
"Can't spawn a {:?} ending at border {}; no appropriate lanes there",
|
||||
constraints, dr
|
||||
));
|
||||
}
|
||||
goal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn pick_walking_goal(
|
||||
&self,
|
||||
map: &Map,
|
||||
rng: &mut XorShiftRng,
|
||||
timer: &mut Timer,
|
||||
) -> Option<SidewalkSpot> {
|
||||
match self {
|
||||
OriginDestination::Anywhere => Some(SidewalkSpot::building(
|
||||
map.all_buildings().choose(rng).unwrap().id,
|
||||
map,
|
||||
)),
|
||||
OriginDestination::EndOfRoad(dr) => {
|
||||
let goal = SidewalkSpot::end_at_border(dr.dst_i(map), map);
|
||||
if goal.is_none() {
|
||||
timer.warn(format!("Can't end_at_border for {} without a sidewalk", dr));
|
||||
}
|
||||
goal
|
||||
}
|
||||
OriginDestination::GotoBldg(b) => Some(SidewalkSpot::building(*b, map)),
|
||||
fn spawn(&self, rng: &mut XorShiftRng, scenario: &mut Scenario, mode: TripMode, map: &Map) {
|
||||
let depart = rand_time(rng, self.start_time, self.stop_time);
|
||||
let id = PersonID(scenario.people.len());
|
||||
if let Some(trip) = SpawnTrip::new(
|
||||
TripEndpoint::Border(self.start_from_border),
|
||||
self.goal
|
||||
.clone()
|
||||
.unwrap_or_else(|| TripEndpoint::Bldg(map.all_buildings().choose(rng).unwrap().id)),
|
||||
mode,
|
||||
map,
|
||||
) {
|
||||
scenario.people.push(PersonSpec {
|
||||
id,
|
||||
orig_id: None,
|
||||
trips: vec![IndividTrip::new(depart, TripPurpose::Shopping, trip)],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,9 +5,7 @@ use rand::{RngCore, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
|
||||
pub use self::external::{ExternalPerson, ExternalTrip, ExternalTripEndpoint};
|
||||
pub use self::generator::{
|
||||
BorderSpawnOverTime, OriginDestination, ScenarioGenerator, SpawnOverTime,
|
||||
};
|
||||
pub use self::generator::{BorderSpawnOverTime, ScenarioGenerator, SpawnOverTime};
|
||||
pub use self::load::SimFlags;
|
||||
pub use self::modifier::ScenarioModifier;
|
||||
pub use self::scenario::{IndividTrip, PersonSpec, Scenario, SpawnTrip, TripPurpose};
|
||||
|
Loading…
Reference in New Issue
Block a user