1use std::collections::BTreeSet;
2
3use geom::Time;
4use map_model::{IntersectionID, LaneID, Map, PathStep, Position, Traversable};
5use synthpop::{IndividTrip, PersonSpec, Scenario, TripEndpoint, TripMode, TripPurpose};
6
7use crate::{AgentID, CarID, DrivingSimState, Event, TripID, VehicleType};
8
9#[derive(Clone)]
13pub(crate) struct TrafficRecorder {
14 capture_points: BTreeSet<IntersectionID>,
15 trips: Vec<IndividTrip>,
18 seen_trips: BTreeSet<TripID>,
19}
20
21impl TrafficRecorder {
22 pub fn new(capture_points: BTreeSet<IntersectionID>) -> TrafficRecorder {
23 TrafficRecorder {
24 capture_points,
25 trips: Vec::new(),
26 seen_trips: BTreeSet::new(),
27 }
28 }
29
30 pub fn handle_event(&mut self, time: Time, ev: &Event, map: &Map, driving: &DrivingSimState) {
31 if let Event::AgentEntersTraversable(AgentID::Car(car), Some(trip), on, _) = ev {
32 self.on_car_enters_traversable(time, *car, *trip, *on, map, driving);
33 }
34 }
35
36 fn on_car_enters_traversable(
37 &mut self,
38 time: Time,
39 car: CarID,
40 trip: TripID,
41 on: Traversable,
42 map: &Map,
43 driving: &DrivingSimState,
44 ) {
45 if self.seen_trips.contains(&trip) {
46 return;
47 }
48 if let Traversable::Lane(lane) = on {
49 self.on_car_enters_lane(time, car, trip, lane, map, driving);
50 }
51 }
52
53 fn on_car_enters_lane(
54 &mut self,
55 time: Time,
56 car: CarID,
57 trip: TripID,
58 lane: LaneID,
59 map: &Map,
60 driving: &DrivingSimState,
61 ) {
62 if !self.capture_points.contains(&map.get_l(lane).src_i) {
63 return;
64 }
65 let exit_intersection =
67 driving
68 .get_path(car)
69 .unwrap()
70 .get_steps()
71 .iter()
72 .find_map(|step| {
73 if let PathStep::Turn(t) = step {
74 if self.capture_points.contains(&t.parent) {
75 return Some(t.parent);
76 }
77 }
78 None
79 });
80 if let Some(exit_intersection) = exit_intersection {
81 self.trips.push(IndividTrip::new(
82 time,
83 TripPurpose::Shopping,
84 TripEndpoint::SuddenlyAppear(Position::start(lane)),
85 TripEndpoint::Border(exit_intersection),
86 if car.vehicle_type == VehicleType::Bike {
87 TripMode::Bike
88 } else {
89 TripMode::Drive
90 },
91 ));
92 self.seen_trips.insert(trip);
93 };
94 }
95
96 pub fn num_recorded_trips(&self) -> usize {
97 self.trips.len()
98 }
99
100 pub fn save(mut self, map: &Map) {
101 Scenario {
102 scenario_name: "recorded".to_string(),
103 map_name: map.get_name().clone(),
104 people: self
105 .trips
106 .drain(..)
107 .map(|trip| PersonSpec {
108 orig_id: None,
109 trips: vec![trip],
110 })
111 .collect::<Vec<_>>(),
112 only_seed_buses: None,
113 }
114 .save();
115 }
116}