mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 07:25:47 +03:00
Use explicit start/endpoints for trips in scenarios. This is necessary
for people that leave one border, then re-enter a different one. #664 Alternative considered: insert a dummy remote trip between the two borders. We used to do something like this at non-trivial code complexity expense and having to explain the trip in the UI. Regenerated all scenarios and prebaked data. - Modest file size increase, as expected. Montlake scenario goes from 1.3MB to 1.5, downtown from 37MB to 43MB, all Seattle scenarios from 280MB to 327MB - Eyeballed a few of the previously broken trips; they work now! - Montlake goes from 3127 cancelled trips to just 302! - No new gridlock, except in Rainier Valley -- disabling that for now - I discovered missing validation in Poundbury for no-op trips between the same building. I'll filter those out and restore prebaked results there in a followup.
This commit is contained in:
parent
3b375078b1
commit
9fc79b1089
1273
data/MANIFEST.json
1273
data/MANIFEST.json
File diff suppressed because it is too large
Load Diff
@ -30,7 +30,7 @@ pub fn prebake_all() {
|
||||
MapName::seattle("lakeslice"),
|
||||
MapName::seattle("phinney"),
|
||||
MapName::seattle("qa"),
|
||||
MapName::seattle("rainier_valley"),
|
||||
//MapName::seattle("rainier_valley"),
|
||||
MapName::seattle("wallingford"),
|
||||
] {
|
||||
let map = map_model::Map::load_synchronously(name.path(), &mut timer);
|
||||
@ -39,19 +39,21 @@ pub fn prebake_all() {
|
||||
prebake(&map, scenario, None, &mut timer);
|
||||
}
|
||||
|
||||
for &scenario_name in &["base", "go_active", "base_with_bg", "go_active_with_bg"] {
|
||||
let map = map_model::Map::load_synchronously(
|
||||
MapName::new("gb", "poundbury", "center").path(),
|
||||
&mut timer,
|
||||
);
|
||||
let scenario: Scenario = abstio::read_binary(
|
||||
abstio::path_scenario(map.get_name(), scenario_name),
|
||||
&mut timer,
|
||||
);
|
||||
let mut opts = SimOptions::new("prebaked");
|
||||
opts.alerts = AlertHandler::Silence;
|
||||
opts.infinite_parking = true;
|
||||
prebake(&map, scenario, Some(opts), &mut timer);
|
||||
if false {
|
||||
for &scenario_name in &["base", "go_active", "base_with_bg", "go_active_with_bg"] {
|
||||
let map = map_model::Map::load_synchronously(
|
||||
MapName::new("gb", "poundbury", "center").path(),
|
||||
&mut timer,
|
||||
);
|
||||
let scenario: Scenario = abstio::read_binary(
|
||||
abstio::path_scenario(map.get_name(), scenario_name),
|
||||
&mut timer,
|
||||
);
|
||||
let mut opts = SimOptions::new("prebaked");
|
||||
opts.alerts = AlertHandler::Silence;
|
||||
opts.infinite_parking = true;
|
||||
prebake(&map, scenario, Some(opts), &mut timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,8 @@ impl GameplayState for Actdev {
|
||||
.polygon;
|
||||
|
||||
for person in app.primary.sim.get_all_people() {
|
||||
if let TripEndpoint::Bldg(b) = person.home {
|
||||
if let TripEndpoint::Bldg(b) = app.primary.sim.trip_info(person.trips[0]).start
|
||||
{
|
||||
if study_area.contains_pt(app.primary.map.get_b(b).polygon.center()) {
|
||||
highlight.insert(person.id);
|
||||
}
|
||||
|
@ -372,13 +372,13 @@ pub fn spawn_agents_around(i: IntersectionID, app: &mut App) {
|
||||
};
|
||||
scenario.people.push(PersonSpec {
|
||||
orig_id: None,
|
||||
origin: TripEndpoint::SuddenlyAppear(Position::new(
|
||||
lane.id,
|
||||
Scenario::rand_dist(&mut rng, Distance::ZERO, lane.length()),
|
||||
)),
|
||||
trips: vec![IndividTrip::new(
|
||||
app.primary.sim.time(),
|
||||
TripPurpose::Shopping,
|
||||
TripEndpoint::SuddenlyAppear(Position::new(
|
||||
lane.id,
|
||||
Scenario::rand_dist(&mut rng, Distance::ZERO, lane.length()),
|
||||
)),
|
||||
TripEndpoint::Bldg(map.all_buildings().choose(&mut rng).unwrap().id),
|
||||
mode,
|
||||
)],
|
||||
@ -388,13 +388,13 @@ pub fn spawn_agents_around(i: IntersectionID, app: &mut App) {
|
||||
for _ in 0..5 {
|
||||
scenario.people.push(PersonSpec {
|
||||
orig_id: None,
|
||||
origin: TripEndpoint::SuddenlyAppear(Position::new(
|
||||
lane.id,
|
||||
Scenario::rand_dist(&mut rng, 0.1 * lane.length(), 0.9 * lane.length()),
|
||||
)),
|
||||
trips: vec![IndividTrip::new(
|
||||
app.primary.sim.time(),
|
||||
TripPurpose::Shopping,
|
||||
TripEndpoint::SuddenlyAppear(Position::new(
|
||||
lane.id,
|
||||
Scenario::rand_dist(&mut rng, 0.1 * lane.length(), 0.9 * lane.length()),
|
||||
)),
|
||||
TripEndpoint::Bldg(map.all_buildings().choose(&mut rng).unwrap().id),
|
||||
TripMode::Walk,
|
||||
)],
|
||||
|
@ -102,10 +102,10 @@ impl State<App> for AgentSpawner {
|
||||
for _ in 0..self.panel.spinner("number") {
|
||||
scenario.people.push(PersonSpec {
|
||||
orig_id: None,
|
||||
origin: from,
|
||||
trips: vec![IndividTrip::new(
|
||||
app.primary.sim.time(),
|
||||
TripPurpose::Shopping,
|
||||
from,
|
||||
to,
|
||||
self.panel.dropdown_value("mode"),
|
||||
)],
|
||||
|
@ -1077,13 +1077,13 @@ impl TutorialState {
|
||||
let mut scenario = Scenario::empty(map, "prank");
|
||||
scenario.people.push(PersonSpec {
|
||||
orig_id: None,
|
||||
origin: TripEndpoint::SuddenlyAppear(Position::new(
|
||||
start_lane,
|
||||
map.get_l(start_lane).length() * 0.8,
|
||||
)),
|
||||
trips: vec![IndividTrip::new(
|
||||
Time::START_OF_DAY,
|
||||
TripPurpose::Shopping,
|
||||
TripEndpoint::SuddenlyAppear(Position::new(
|
||||
start_lane,
|
||||
map.get_l(start_lane).length() * 0.8,
|
||||
)),
|
||||
TripEndpoint::Bldg(goal_bldg),
|
||||
TripMode::Drive,
|
||||
)],
|
||||
@ -1092,13 +1092,13 @@ impl TutorialState {
|
||||
for _ in 0..map.get_b(goal_bldg).num_parking_spots() {
|
||||
scenario.people.push(PersonSpec {
|
||||
orig_id: None,
|
||||
origin: TripEndpoint::SuddenlyAppear(Position::new(
|
||||
lane_near_bldg,
|
||||
map.get_l(lane_near_bldg).length() / 2.0,
|
||||
)),
|
||||
trips: vec![IndividTrip::new(
|
||||
Time::START_OF_DAY,
|
||||
TripPurpose::Shopping,
|
||||
TripEndpoint::SuddenlyAppear(Position::new(
|
||||
lane_near_bldg,
|
||||
map.get_l(lane_near_bldg).length() / 2.0,
|
||||
)),
|
||||
TripEndpoint::Bldg(goal_bldg),
|
||||
TripMode::Drive,
|
||||
)],
|
||||
|
@ -60,7 +60,8 @@ fn add_return_trips(scenario: &mut Scenario, rng: &mut XorShiftRng) {
|
||||
person.trips.push(IndividTrip::new(
|
||||
depart,
|
||||
TripPurpose::Home,
|
||||
person.origin,
|
||||
person.trips[0].destination,
|
||||
person.trips[0].origin,
|
||||
person.trips[0].mode,
|
||||
));
|
||||
cnt += 1;
|
||||
@ -92,7 +93,7 @@ fn add_lunch_trips(scenario: &mut Scenario, map: &Map, rng: &mut XorShiftRng, ti
|
||||
timer.next();
|
||||
let num_trips = person.trips.len();
|
||||
// Only handle people with their final trip going back home.
|
||||
if num_trips <= 1 || person.trips[num_trips - 1].destination != person.origin {
|
||||
if num_trips <= 1 || person.trips[num_trips - 1].destination != person.trips[0].origin {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -116,12 +117,14 @@ fn add_lunch_trips(scenario: &mut Scenario, map: &Map, rng: &mut XorShiftRng, ti
|
||||
person.trips.push(IndividTrip::new(
|
||||
depart,
|
||||
TripPurpose::Meal,
|
||||
TripEndpoint::Bldg(work),
|
||||
TripEndpoint::Bldg(restaurant),
|
||||
mode,
|
||||
));
|
||||
person.trips.push(IndividTrip::new(
|
||||
depart + Duration::minutes(30),
|
||||
TripPurpose::Work,
|
||||
TripEndpoint::Bldg(restaurant),
|
||||
TripEndpoint::Bldg(work),
|
||||
mode,
|
||||
));
|
||||
|
@ -54,9 +54,9 @@ fn parse_trips(csv_path: String) -> Result<Vec<ExternalPerson>> {
|
||||
// For each row in the CSV file, create a person who takes a single trip from the origin to
|
||||
// the destination. They do not take a later trip to return home.
|
||||
people.push(ExternalPerson {
|
||||
origin: ExternalTripEndpoint::Position(origin),
|
||||
trips: vec![ExternalTrip {
|
||||
departure,
|
||||
origin: ExternalTripEndpoint::Position(origin),
|
||||
destination: ExternalTripEndpoint::Position(destination),
|
||||
mode,
|
||||
purpose: TripPurpose::Work,
|
||||
|
@ -179,21 +179,18 @@ pub fn make_weekday_scenario(
|
||||
huge_map: &Map,
|
||||
timer: &mut Timer,
|
||||
) -> Scenario {
|
||||
// Include the origin with each trip
|
||||
let mut individ_trips: Vec<Option<(TripEndpoint, IndividTrip)>> = Vec::new();
|
||||
let mut individ_trips: Vec<Option<IndividTrip>> = Vec::new();
|
||||
// person -> (trip seq, index into individ_trips)
|
||||
let mut trips_per_person: MultiMap<OrigPersonID, ((usize, bool, usize), usize)> =
|
||||
MultiMap::new();
|
||||
for trip in clip_trips(map, popdat, huge_map, timer) {
|
||||
let idx = individ_trips.len();
|
||||
individ_trips.push(Some((
|
||||
individ_trips.push(Some(IndividTrip::new(
|
||||
trip.orig.depart_at,
|
||||
trip.orig.purpose,
|
||||
trip.from,
|
||||
IndividTrip::new(
|
||||
trip.orig.depart_at,
|
||||
trip.orig.purpose,
|
||||
trip.to,
|
||||
trip.orig.mode,
|
||||
),
|
||||
trip.to,
|
||||
trip.orig.mode,
|
||||
)));
|
||||
trips_per_person.insert(trip.orig.person, (trip.orig.seq, idx));
|
||||
}
|
||||
@ -205,17 +202,17 @@ pub fn make_weekday_scenario(
|
||||
|
||||
let mut people = Vec::new();
|
||||
for (orig_id, seq_trips) in trips_per_person.consume() {
|
||||
let mut pairs = Vec::new();
|
||||
let mut trips = Vec::new();
|
||||
for (_, idx) in seq_trips {
|
||||
pairs.push(individ_trips[idx].take().unwrap());
|
||||
trips.push(individ_trips[idx].take().unwrap());
|
||||
}
|
||||
// Actually, the sequence in the Soundcast dataset crosses midnight. Don't do that; sort by
|
||||
// departure time starting with midnight.
|
||||
pairs.sort_by_key(|(_, t)| t.depart);
|
||||
trips.sort_by_key(|t| t.depart);
|
||||
// Sanity check that endpoints match up
|
||||
for pair in pairs.windows(2) {
|
||||
let destination = &pair[0].1.destination;
|
||||
let origin = &pair[1].0;
|
||||
for pair in trips.windows(2) {
|
||||
let destination = &pair[0].destination;
|
||||
let origin = &pair[1].origin;
|
||||
if destination != origin {
|
||||
warn!(
|
||||
"Skipping {:?}, with adjacent trips that warp from {:?} to {:?}",
|
||||
@ -227,8 +224,7 @@ pub fn make_weekday_scenario(
|
||||
|
||||
people.push(PersonSpec {
|
||||
orig_id: Some(orig_id),
|
||||
origin: pairs[0].0,
|
||||
trips: pairs.into_iter().map(|(_, t)| t).collect(),
|
||||
trips,
|
||||
});
|
||||
}
|
||||
for maybe_t in individ_trips {
|
||||
|
@ -98,7 +98,7 @@ pub async fn generate_scenario(
|
||||
// Remove people from the scenario we just generated that live in the study area. The
|
||||
// data imported using importer/actdev_scenarios.sh already covers them.
|
||||
let before = scenario.people.len();
|
||||
scenario.people.retain(|p| match p.origin {
|
||||
scenario.people.retain(|p| match p.trips[0].origin {
|
||||
TripEndpoint::Bldg(b) => !study_area.contains_pt(map.get_b(b).polygon.center()),
|
||||
_ => true,
|
||||
});
|
||||
|
@ -184,7 +184,6 @@ impl PersonFactory {
|
||||
|
||||
let mut output = PersonSpec {
|
||||
orig_id: None,
|
||||
origin: TripEndpoint::Bldg(person.home),
|
||||
trips: Vec::new(),
|
||||
};
|
||||
|
||||
@ -204,9 +203,13 @@ impl PersonFactory {
|
||||
};
|
||||
|
||||
let mode = pick_mode(current_location, goto, map, rng, config);
|
||||
output
|
||||
.trips
|
||||
.push(IndividTrip::new(departure_time, purpose, goto, mode));
|
||||
output.trips.push(IndividTrip::new(
|
||||
departure_time,
|
||||
purpose,
|
||||
current_location,
|
||||
goto,
|
||||
mode,
|
||||
));
|
||||
|
||||
current_location = goto;
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ pub fn disaggregate(
|
||||
for _ in 0..desire.number_commuters {
|
||||
// Pick a specific home and workplace. It might be off-map, depending on how much the
|
||||
// zone overlaps the map.
|
||||
if let (Some((leave_home, goto_home)), Some((_, goto_work))) = (
|
||||
if let (Some((leave_home, goto_home)), Some((leave_work, goto_work))) = (
|
||||
home_zone.pick_home(desire.mode, map, rng),
|
||||
work_zone.pick_workplace(desire.mode, map, rng),
|
||||
) {
|
||||
@ -96,12 +96,18 @@ pub fn disaggregate(
|
||||
let return_home_time = goto_work_time + opts.work_duration.sample(rng);
|
||||
people.push(PersonSpec {
|
||||
orig_id: None,
|
||||
origin: leave_home,
|
||||
trips: vec![
|
||||
IndividTrip::new(goto_work_time, TripPurpose::Work, goto_work, desire.mode),
|
||||
IndividTrip::new(
|
||||
goto_work_time,
|
||||
TripPurpose::Work,
|
||||
leave_home,
|
||||
goto_work,
|
||||
desire.mode,
|
||||
),
|
||||
IndividTrip::new(
|
||||
return_home_time,
|
||||
TripPurpose::Home,
|
||||
leave_work,
|
||||
goto_home,
|
||||
desire.mode,
|
||||
),
|
||||
|
@ -272,10 +272,9 @@ fn create_prole(
|
||||
|
||||
Ok(PersonSpec {
|
||||
orig_id: None,
|
||||
origin: home,
|
||||
trips: vec![
|
||||
IndividTrip::new(depart_am, TripPurpose::Work, work, mode),
|
||||
IndividTrip::new(depart_pm, TripPurpose::Home, home, mode),
|
||||
IndividTrip::new(depart_am, TripPurpose::Work, home, work, mode),
|
||||
IndividTrip::new(depart_pm, TripPurpose::Home, work, home, mode),
|
||||
],
|
||||
})
|
||||
}
|
||||
|
@ -11,13 +11,13 @@ use crate::{IndividTrip, PersonSpec, TripEndpoint, TripMode, TripPurpose};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ExternalPerson {
|
||||
pub origin: ExternalTripEndpoint,
|
||||
pub trips: Vec<ExternalTrip>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ExternalTrip {
|
||||
pub departure: Time,
|
||||
pub origin: ExternalTripEndpoint,
|
||||
pub destination: ExternalTripEndpoint,
|
||||
pub mode: TripMode,
|
||||
pub purpose: TripPurpose,
|
||||
@ -74,25 +74,23 @@ impl ExternalPerson {
|
||||
for person in input {
|
||||
let mut spec = PersonSpec {
|
||||
orig_id: None,
|
||||
origin: match lookup_pt(person.origin, true, person.trips[0].mode) {
|
||||
Ok(endpt) => endpt,
|
||||
Err(err) => {
|
||||
if skip_problems {
|
||||
warn!("Skipping person: {}", err);
|
||||
continue;
|
||||
} else {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
},
|
||||
trips: Vec::new(),
|
||||
};
|
||||
for trip in person.trips {
|
||||
spec.trips.push(IndividTrip::new(
|
||||
trip.departure,
|
||||
trip.purpose,
|
||||
// TODO Do we handle somebody going off-map via one one-way bridge, and
|
||||
// re-entering using the other?
|
||||
match lookup_pt(trip.origin, true, trip.mode) {
|
||||
Ok(endpt) => endpt,
|
||||
Err(err) => {
|
||||
if skip_problems {
|
||||
warn!("Skipping person: {}", err);
|
||||
continue;
|
||||
} else {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
},
|
||||
match lookup_pt(trip.destination, false, trip.mode) {
|
||||
Ok(endpt) => endpt,
|
||||
Err(err) => {
|
||||
|
@ -163,10 +163,10 @@ impl SpawnOverTime {
|
||||
};
|
||||
scenario.people.push(PersonSpec {
|
||||
orig_id: None,
|
||||
origin: TripEndpoint::Bldg(from_bldg),
|
||||
trips: vec![IndividTrip::new(
|
||||
depart,
|
||||
TripPurpose::Shopping,
|
||||
TripEndpoint::Bldg(from_bldg),
|
||||
self.goal.unwrap_or_else(|| {
|
||||
TripEndpoint::Bldg(map.all_buildings().choose(rng).unwrap().id)
|
||||
}),
|
||||
@ -181,10 +181,10 @@ impl BorderSpawnOverTime {
|
||||
let depart = rand_time(rng, self.start_time, self.stop_time);
|
||||
scenario.people.push(PersonSpec {
|
||||
orig_id: None,
|
||||
origin: TripEndpoint::Border(self.start_from_border),
|
||||
trips: vec![IndividTrip::new(
|
||||
depart,
|
||||
TripPurpose::Shopping,
|
||||
TripEndpoint::Border(self.start_from_border),
|
||||
self.goal.unwrap_or_else(|| {
|
||||
TripEndpoint::Bldg(map.all_buildings().choose(rng).unwrap().id)
|
||||
}),
|
||||
|
@ -33,15 +33,16 @@ pub struct Scenario {
|
||||
pub struct PersonSpec {
|
||||
/// Just used for debugging
|
||||
pub orig_id: Option<OrigPersonID>,
|
||||
/// The first trip starts here
|
||||
pub origin: TripEndpoint,
|
||||
/// Each trip starts at the destination of the previous trip
|
||||
/// There must be continuity between trips: each trip starts at the destination of the previous
|
||||
/// trip. In the case of borders, the outbound and inbound border may be different. This means
|
||||
/// that there was some sort of "remote" trip happening outside the map that we don't simulate.
|
||||
pub trips: Vec<IndividTrip>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct IndividTrip {
|
||||
pub depart: Time,
|
||||
pub origin: TripEndpoint,
|
||||
pub destination: TripEndpoint,
|
||||
pub mode: TripMode,
|
||||
pub purpose: TripPurpose,
|
||||
@ -54,11 +55,13 @@ impl IndividTrip {
|
||||
pub fn new(
|
||||
depart: Time,
|
||||
purpose: TripPurpose,
|
||||
origin: TripEndpoint,
|
||||
destination: TripEndpoint,
|
||||
mode: TripMode,
|
||||
) -> IndividTrip {
|
||||
IndividTrip {
|
||||
depart,
|
||||
origin,
|
||||
destination,
|
||||
mode,
|
||||
purpose,
|
||||
@ -152,23 +155,17 @@ impl Scenario {
|
||||
|
||||
let (vehicle_specs, cars_initially_parked_at, vehicle_foreach_trip) =
|
||||
p.get_vehicles(rng);
|
||||
let person = sim.new_person(
|
||||
p.orig_id,
|
||||
p.origin,
|
||||
Scenario::rand_ped_speed(rng),
|
||||
vehicle_specs,
|
||||
);
|
||||
let person = sim.new_person(p.orig_id, Scenario::rand_ped_speed(rng), vehicle_specs);
|
||||
for (idx, b) in cars_initially_parked_at {
|
||||
parked_cars.push((person.vehicles[idx].clone(), b));
|
||||
}
|
||||
let mut from = p.origin;
|
||||
for (trip, maybe_idx) in p.trips.iter().zip(vehicle_foreach_trip) {
|
||||
schedule_trips.push((
|
||||
person.id,
|
||||
TripInfo {
|
||||
departure: trip.depart,
|
||||
mode: trip.mode,
|
||||
start: from,
|
||||
start: trip.origin,
|
||||
end: trip.destination,
|
||||
purpose: trip.purpose,
|
||||
modified: trip.modified,
|
||||
@ -184,7 +181,6 @@ impl Scenario {
|
||||
use_vehicle: maybe_idx.map(|idx| person.vehicles[idx].id),
|
||||
},
|
||||
));
|
||||
from = trip.destination;
|
||||
}
|
||||
}
|
||||
|
||||
@ -416,18 +412,19 @@ impl PersonSpec {
|
||||
pair[1].depart
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let mut endpts = vec![self.origin];
|
||||
for t in &self.trips {
|
||||
endpts.push(t.destination);
|
||||
}
|
||||
for pair in endpts.windows(2) {
|
||||
if pair[0] == pair[1] {
|
||||
if pair[0].destination != pair[1].origin {
|
||||
// Exiting one border and re-entering another is fine
|
||||
if matches!(pair[0].destination, TripEndpoint::Border(_))
|
||||
&& matches!(pair[1].origin, TripEndpoint::Border(_))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
bail!(
|
||||
"Person ({:?}) has two adjacent trips between the same place: {:?}",
|
||||
"Person ({:?}) warps from {:?} to {:?} during adjacent trips",
|
||||
self.orig_id,
|
||||
pair[0]
|
||||
pair[0].destination,
|
||||
pair[1].origin
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -452,7 +449,6 @@ impl PersonSpec {
|
||||
let mut car_locations: Vec<(usize, Option<BuildingID>)> = Vec::new();
|
||||
|
||||
// TODO If the trip is cancelled, this should be affected...
|
||||
let mut from = self.origin;
|
||||
for trip in &self.trips {
|
||||
let use_for_trip = match trip.mode {
|
||||
TripMode::Walk | TripMode::Transit => None,
|
||||
@ -464,7 +460,7 @@ impl PersonSpec {
|
||||
bike_idx
|
||||
}
|
||||
TripMode::Drive => {
|
||||
let need_parked_at = match from {
|
||||
let need_parked_at = match trip.origin {
|
||||
TripEndpoint::Bldg(b) => Some(b),
|
||||
_ => None,
|
||||
};
|
||||
@ -500,7 +496,6 @@ impl PersonSpec {
|
||||
Some(idx)
|
||||
}
|
||||
};
|
||||
from = trip.destination;
|
||||
vehicle_foreach_trip.push(use_for_trip);
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ pub(crate) struct TrafficRecorder {
|
||||
capture_points: BTreeSet<IntersectionID>,
|
||||
// TODO The RNG will determine vehicle length, so this won't be a perfect capture. Hopefully
|
||||
// good enough.
|
||||
trips: Vec<(TripEndpoint, IndividTrip)>,
|
||||
trips: Vec<IndividTrip>,
|
||||
seen_trips: BTreeSet<TripID>,
|
||||
}
|
||||
|
||||
@ -40,18 +40,16 @@ impl TrafficRecorder {
|
||||
for step in driving.get_path(*car).unwrap().get_steps() {
|
||||
if let PathStep::Turn(t) = step {
|
||||
if self.capture_points.contains(&t.parent) {
|
||||
self.trips.push((
|
||||
self.trips.push(IndividTrip::new(
|
||||
time,
|
||||
TripPurpose::Shopping,
|
||||
TripEndpoint::SuddenlyAppear(Position::start(*l)),
|
||||
IndividTrip::new(
|
||||
time,
|
||||
TripPurpose::Shopping,
|
||||
TripEndpoint::Border(t.parent),
|
||||
if car.vehicle_type == VehicleType::Bike {
|
||||
TripMode::Bike
|
||||
} else {
|
||||
TripMode::Drive
|
||||
},
|
||||
),
|
||||
TripEndpoint::Border(t.parent),
|
||||
if car.vehicle_type == VehicleType::Bike {
|
||||
TripMode::Bike
|
||||
} else {
|
||||
TripMode::Drive
|
||||
},
|
||||
));
|
||||
self.seen_trips.insert(*trip);
|
||||
return;
|
||||
@ -69,10 +67,9 @@ impl TrafficRecorder {
|
||||
|
||||
pub fn save(mut self, map: &Map) {
|
||||
let mut people = Vec::new();
|
||||
for (origin, trip) in self.trips.drain(..) {
|
||||
for trip in self.trips.drain(..) {
|
||||
people.push(PersonSpec {
|
||||
orig_id: None,
|
||||
origin,
|
||||
trips: vec![trip],
|
||||
});
|
||||
}
|
||||
|
@ -22,9 +22,9 @@ use crate::{
|
||||
AgentID, AlertLocation, Analytics, CapSimState, CarID, Command, CreateCar, DrivingSimState,
|
||||
Event, IntersectionSimState, OrigPersonID, PandemicModel, ParkedCar, ParkingSim,
|
||||
ParkingSimState, ParkingSpot, Person, PersonID, Router, Scheduler, SidewalkPOI, SidewalkSpot,
|
||||
StartTripArgs, TrafficRecorder, TransitSimState, TripEndpoint, TripID, TripInfo, TripManager,
|
||||
TripPhaseType, Vehicle, VehicleSpec, VehicleType, WalkingSimState, BUS_LENGTH,
|
||||
LIGHT_RAIL_LENGTH, MIN_CAR_LENGTH,
|
||||
StartTripArgs, TrafficRecorder, TransitSimState, TripID, TripInfo, TripManager, TripPhaseType,
|
||||
Vehicle, VehicleSpec, VehicleType, WalkingSimState, BUS_LENGTH, LIGHT_RAIL_LENGTH,
|
||||
MIN_CAR_LENGTH,
|
||||
};
|
||||
|
||||
mod queries;
|
||||
@ -317,12 +317,10 @@ impl Sim {
|
||||
pub(crate) fn new_person(
|
||||
&mut self,
|
||||
orig_id: Option<OrigPersonID>,
|
||||
home: TripEndpoint,
|
||||
ped_speed: Speed,
|
||||
vehicle_specs: Vec<VehicleSpec>,
|
||||
) -> &Person {
|
||||
self.trips
|
||||
.new_person(orig_id, home, ped_speed, vehicle_specs)
|
||||
self.trips.new_person(orig_id, ped_speed, vehicle_specs)
|
||||
}
|
||||
pub(crate) fn seed_parked_car(&mut self, vehicle: Vehicle, spot: ParkingSpot) {
|
||||
self.parking.reserve_spot(spot, vehicle.id);
|
||||
|
@ -60,7 +60,6 @@ impl TripManager {
|
||||
pub fn new_person(
|
||||
&mut self,
|
||||
orig_id: Option<OrigPersonID>,
|
||||
home: TripEndpoint,
|
||||
ped_speed: Speed,
|
||||
vehicle_specs: Vec<VehicleSpec>,
|
||||
) -> &Person {
|
||||
@ -78,7 +77,6 @@ impl TripManager {
|
||||
self.people.push(Person {
|
||||
id,
|
||||
orig_id,
|
||||
home,
|
||||
trips: Vec::new(),
|
||||
// The first new_trip will set this properly.
|
||||
state: PersonState::OffMap,
|
||||
@ -1341,7 +1339,6 @@ impl TripManager {
|
||||
for p in &self.people {
|
||||
scenario.people.push(PersonSpec {
|
||||
orig_id: p.orig_id,
|
||||
origin: self.trips[p.trips[0].0].info.start,
|
||||
trips: p
|
||||
.trips
|
||||
.iter()
|
||||
@ -1350,6 +1347,7 @@ impl TripManager {
|
||||
IndividTrip::new(
|
||||
trip.info.departure,
|
||||
trip.info.purpose,
|
||||
trip.info.start,
|
||||
trip.info.end,
|
||||
trip.info.mode,
|
||||
)
|
||||
@ -1511,7 +1509,6 @@ impl<T> TripResult<T> {
|
||||
pub struct Person {
|
||||
pub id: PersonID,
|
||||
pub orig_id: Option<OrigPersonID>,
|
||||
pub home: TripEndpoint,
|
||||
pub trips: Vec<TripID>,
|
||||
pub state: PersonState,
|
||||
|
||||
|
@ -192,12 +192,12 @@ fn test_lane_changing(map: &Map) -> Result<()> {
|
||||
for (idx, (from, to)) in od.into_iter().enumerate() {
|
||||
scenario.people.push(PersonSpec {
|
||||
orig_id: None,
|
||||
origin: TripEndpoint::Border(from),
|
||||
trips: vec![IndividTrip::new(
|
||||
// Space out the spawn times a bit. If a vehicle tries to spawn and something's in
|
||||
// the way, there's a fixed retry time in the simulation that we'll hit.
|
||||
Time::START_OF_DAY + Duration::seconds(idx as f64 - 0.5).max(Duration::ZERO),
|
||||
TripPurpose::Shopping,
|
||||
TripEndpoint::Border(from),
|
||||
TripEndpoint::Border(to),
|
||||
// About half cars, half bikes
|
||||
if idx % 2 == 0 {
|
||||
|
Loading…
Reference in New Issue
Block a user