1use std::collections::{BTreeSet, VecDeque};
2
3use serde::{Deserialize, Serialize};
4
5use geom::{Distance, Duration, PolyLine, Time, EPSILON_DIST};
6use map_model::{Direction, LaneID, Map, Traversable};
7
8use crate::{
9 CarID, CarStatus, DistanceInterval, DrawCarInput, Intent, ParkingSpot, PersonID, Router,
10 TimeInterval, TransitSimState, TripID, Vehicle, VehicleType,
11};
12
13#[derive(Debug, Serialize, Deserialize, Clone)]
15pub(crate) struct Car {
16 pub vehicle: Vehicle,
17 pub state: CarState,
18 pub router: Router,
19 pub trip_and_person: Option<(TripID, PersonID)>,
22 pub started_at: Time,
23 pub total_blocked_time: Duration,
24
25 pub last_steps: VecDeque<Traversable>,
28
29 pub wants_to_overtake: BTreeSet<CarID>,
32}
33
34impl Car {
35 pub fn crossing_state(&self, start_dist: Distance, start_time: Time, map: &Map) -> CarState {
37 let end_dist = if self.router.last_step() {
38 self.router.get_end_dist()
39 } else {
40 self.router.head().get_polyline(map).length()
41 };
42 if end_dist < start_dist {
43 panic!(
44 "{} trying to make a crossing_state from {} to {} at {}. Something's very wrong",
45 self.vehicle.id, start_dist, end_dist, start_time
46 );
47 }
48
49 let dist_int = DistanceInterval::new_driving(start_dist, end_dist);
50 self.crossing_state_with_end_dist(dist_int, start_time, map)
51 }
52
53 pub fn crossing_state_with_end_dist(
54 &self,
55 dist_int: DistanceInterval,
56 start_time: Time,
57 map: &Map,
58 ) -> CarState {
59 let (speed, percent_incline) = self
60 .router
61 .get_path()
62 .current_step()
63 .max_speed_and_incline_along(
64 self.vehicle.max_speed,
65 self.vehicle.vehicle_type.to_constraints(),
66 map,
67 );
68 let dt = (dist_int.end - dist_int.start) / speed;
69 CarState::Crossing {
70 time_int: TimeInterval::new(start_time, start_time + dt),
71 dist_int,
72 steep_uphill: percent_incline >= 0.08,
73 }
74 }
75
76 pub fn get_draw_car(
77 &self,
78 front: Distance,
79 now: Time,
80 map: &Map,
81 transit: &TransitSimState,
82 ) -> DrawCarInput {
83 assert!(front >= Distance::ZERO);
84 let mut partly_on = Vec::new();
86 let raw_body = if front >= self.vehicle.length {
87 self.router
88 .head()
89 .get_polyline(map)
90 .exact_slice(front - self.vehicle.length, front)
91 } else {
92 let mut result = self
94 .router
95 .head()
96 .get_polyline(map)
97 .slice(Distance::ZERO, front)
98 .map(|(pl, _)| pl.into_points())
99 .ok()
100 .unwrap_or_else(Vec::new);
101 let mut leftover = self.vehicle.length - front;
102 let mut i = 0;
103 while leftover > Distance::ZERO {
104 if i == self.last_steps.len() {
105 break;
108 }
109 partly_on.push(self.last_steps[i]);
110 let len = self.last_steps[i].get_polyline(map).length();
111 let start = (len - leftover).max(Distance::ZERO);
112 let piece = self.last_steps[i]
113 .get_polyline(map)
114 .slice(start, len)
115 .map(|(pl, _)| pl.into_points())
116 .ok()
117 .unwrap_or_else(Vec::new);
118 result = match PolyLine::append(piece, result) {
119 Ok(pl) => pl,
120 Err(err) => panic!(
121 "{} at {} has weird geom along {:?}: {}",
122 self.vehicle.id, now, self.last_steps, err
123 ),
124 };
125 leftover -= len;
126 i += 1;
127 }
128
129 if result.len() < 2 {
130 if let Ok((pl, _)) = self
134 .router
135 .head()
136 .get_polyline(map)
137 .slice(Distance::ZERO, 2.0 * EPSILON_DIST)
138 {
139 result = pl.into_points();
140 }
141 }
142 match PolyLine::new(result) {
143 Ok(pl) => pl,
144 Err(err) => panic!("Weird body for {} at {}: {}", self.vehicle.id, now, err),
145 }
146 };
147
148 let body = match self.state {
149 CarState::ChangingLanes {
150 from,
151 to,
152 ref lc_time,
153 ..
154 } => {
155 let percent_time = 1.0 - lc_time.percent(now);
156 let mut diff = (to.offset as isize) - (from.offset as isize);
159 let from = map.get_l(from);
160 if from.dir == Direction::Fwd {
161 diff *= -1;
162 }
163 let width = from.width * (diff as f64) * percent_time;
165 match raw_body.shift_right(width) {
166 Ok(pl) => pl,
167 Err(err) => {
168 println!(
169 "Body for lane-changing {} at {} broken: {}",
170 self.vehicle.id, now, err
171 );
172 raw_body
173 }
174 }
175 }
176 CarState::Unparking {
177 ref spot,
178 ref time_int,
179 ..
180 }
181 | CarState::Parking(_, ref spot, ref time_int) => {
182 let (percent_time, is_parking) = match self.state {
183 CarState::Unparking { .. } => (1.0 - time_int.percent(now), false),
184 CarState::Parking(_, _, _) => (time_int.percent(now), true),
185 _ => unreachable!(),
186 };
187 match spot {
188 ParkingSpot::Onstreet(parking_l, _) => {
189 let driving_offset = self.router.head().as_lane().offset;
190 let parking_offset = parking_l.offset;
191 let mut diff = (parking_offset as isize) - (driving_offset as isize);
192 if map.get_l(self.router.head().as_lane()).dir == Direction::Back {
193 diff *= -1;
194 }
195 let width = map.get_l(*parking_l).width * (diff as f64) * percent_time;
198 match raw_body.shift_right(width) {
199 Ok(pl) => pl,
200 Err(err) => {
201 println!(
202 "Body for onstreet {} at {} broken: {}",
203 self.vehicle.id, now, err
204 );
205 raw_body
206 }
207 }
208 }
209 _ => {
210 let driveway = match spot {
211 ParkingSpot::Offstreet(b, _) => {
212 map.get_b(*b).driving_connection(map).unwrap().1
213 }
214 ParkingSpot::Lot(pl, _) => map.get_pl(*pl).driveway_line.clone(),
215 _ => unreachable!(),
216 };
217
218 let maybe_full_piece = if is_parking {
220 raw_body.clone().extend(driveway.reversed())
221 } else {
222 driveway
226 .clone()
227 .force_extend(raw_body.clone())
228 .map(|pl| pl.reversed())
229 };
230 let sliced = match maybe_full_piece {
231 Ok(full_piece) => {
232 let creep_along = driveway.length() * percent_time;
235 full_piece
239 .exact_slice(creep_along, creep_along + self.vehicle.length)
240 }
241 Err(err) => {
242 error!(
245 "Body and driveway for {} at {} broken: {}",
246 self.vehicle.id, now, err
247 );
248 raw_body
249 }
250 };
251 if is_parking {
252 sliced
253 } else {
254 sliced.reversed()
255 }
256 }
257 }
258 }
259 _ => raw_body,
260 };
261
262 DrawCarInput {
263 id: self.vehicle.id,
264 waiting_for_turn: match self.state {
265 CarState::WaitingToAdvance { .. } | CarState::Queued { .. } => {
267 match self.router.maybe_next() {
268 Some(Traversable::Turn(t)) => Some(t),
269 _ => None,
270 }
271 }
272 _ => None,
273 },
274 status: match self.state {
275 CarState::Queued { .. } => CarStatus::Moving,
276 CarState::WaitingToAdvance { .. } => CarStatus::Moving,
277 CarState::Crossing { .. } => CarStatus::Moving,
278 CarState::ChangingLanes { .. } => CarStatus::Moving,
279 CarState::Unparking { .. } => CarStatus::Moving,
280 CarState::Parking(_, _, _) => CarStatus::Moving,
281 CarState::IdlingAtStop(_, _) => CarStatus::Parked,
283 },
284 intent: if self.is_parking() || matches!(self.state, CarState::Unparking { .. }) {
285 Some(Intent::Parking)
286 } else {
287 match self.state {
288 CarState::Crossing { steep_uphill, .. } if steep_uphill => {
289 Some(Intent::SteepUphill)
290 }
291 _ => None,
292 }
293 },
294 on: self.router.head(),
295 partly_on,
296 label: if self.vehicle.vehicle_type == VehicleType::Bus
297 || self.vehicle.vehicle_type == VehicleType::Train
298 {
299 Some(
300 map.get_tr(transit.bus_route(self.vehicle.id))
301 .short_name
302 .clone(),
303 )
304 } else {
305 None
306 },
307 body,
308 person: self.trip_and_person.map(|(_, p)| p),
309 }
310 }
311
312 pub fn is_parking(&self) -> bool {
313 if let CarState::Parking(_, _, _) = self.state {
314 return true;
315 }
316 self.router.is_parking()
317 }
318}
319
320#[derive(Debug, Serialize, Deserialize, Clone)]
323pub(crate) enum CarState {
324 Crossing {
325 time_int: TimeInterval,
326 dist_int: DistanceInterval,
327 steep_uphill: bool,
328 },
329 ChangingLanes {
330 from: LaneID,
331 to: LaneID,
332 new_time: TimeInterval,
334 new_dist: DistanceInterval,
335 lc_time: TimeInterval,
337 },
338 Queued {
339 blocked_since: Time,
340 want_to_change_lanes: Option<LaneID>,
341 },
342 WaitingToAdvance {
343 blocked_since: Time,
344 },
345 Unparking {
347 front: Distance,
348 spot: ParkingSpot,
349 time_int: TimeInterval,
350 blocked_starts: Vec<LaneID>,
351 },
352 Parking(Distance, ParkingSpot, TimeInterval),
353 IdlingAtStop(Distance, TimeInterval),
354}
355
356impl CarState {
357 pub fn get_end_time(&self) -> Time {
358 match self {
359 CarState::Crossing { ref time_int, .. } => time_int.end,
360 CarState::Queued { .. } => unreachable!(),
361 CarState::WaitingToAdvance { .. } => unreachable!(),
362 CarState::ChangingLanes { ref lc_time, .. } => lc_time.end,
364 CarState::Unparking { ref time_int, .. } => time_int.end,
365 CarState::Parking(_, _, ref time_int) => time_int.end,
366 CarState::IdlingAtStop(_, ref time_int) => time_int.end,
367 }
368 }
369
370 pub fn time_spent_waiting(&self, now: Time) -> Duration {
371 match self {
372 CarState::Queued { blocked_since, .. }
373 | CarState::WaitingToAdvance { blocked_since } => now - *blocked_since,
374 _ => Duration::ZERO,
375 }
376 }
377}