1use crate::conflict::LinkConflict;
2use crate::group::Obstacle;
3use crate::math::{ParametricCurve2d, Point2d};
4use crate::util::rotated_range;
5use crate::vehicle::{ObstaclePassResult, RouteState, Vehicle};
6use crate::{LinkGroup, LinkId, LinkSet, VehicleId, VehicleSet};
7pub use curve::{LinkCurve, LinkSample};
8use serde::{Deserialize, Serialize};
9use smallvec::{smallvec, SmallVec};
10use std::cell::Cell;
11use std::cmp::Ordering;
12use std::ops::ControlFlow;
13use std::rc::Rc;
14
15mod curve;
16
17const MAX_LOOKAHEAD: f64 = 5.0;
19
20const GAP_BUFFER: f64 = 0.5;
22
23#[derive(Clone, Serialize, Deserialize)]
25pub struct Link {
26 id: LinkId,
28 #[serde(skip)]
30 group: Option<Rc<LinkGroup>>,
31 curve: LinkCurve,
33 links_in: SmallVec<[LinkId; 4]>,
35 links_out: SmallVec<[LinkId; 4]>,
37 links_adjacent: SmallVec<[LinkId; 2]>,
39 conflicts: Vec<LinkConflict>,
41 last_conflict: Cell<usize>,
43 speed_limit: f64,
45 vehicles: Vec<VehicleId>,
47 control: TrafficControl,
49 active: bool,
51}
52
53pub struct LinkAttributes<'a> {
55 pub curve: &'a dyn ParametricCurve2d,
57 pub speed_limit: f64,
59}
60
61#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
63pub enum TrafficControl {
64 Open,
66 Yield {
68 distance: f64,
70 must_stop: bool,
72 priority: i8,
74 },
75 Closed,
77}
78
79impl Link {
80 pub(crate) fn new(id: LinkId, attribs: &LinkAttributes) -> Self {
82 let curve = LinkCurve::new(&attribs.curve);
83 Self {
84 id,
85 curve,
86 group: None,
87 links_in: smallvec![],
88 links_out: smallvec![],
89 links_adjacent: smallvec![],
90 conflicts: vec![],
91 last_conflict: Cell::new(0),
92 speed_limit: attribs.speed_limit,
93 vehicles: vec![],
94 control: TrafficControl::Open,
95 active: false,
96 }
97 }
98
99 pub fn id(&self) -> LinkId {
101 self.id
102 }
103
104 pub fn length(&self) -> f64 {
106 self.curve.length()
107 }
108
109 pub fn curve(&self) -> &LinkCurve {
111 &self.curve
112 }
113
114 pub fn links_in(&self) -> &[LinkId] {
116 &self.links_in
117 }
118
119 pub fn links_out(&self) -> &[LinkId] {
121 &self.links_out
122 }
123
124 pub fn links_adjacent(&self) -> &[LinkId] {
126 &self.links_adjacent
127 }
128
129 pub(crate) fn add_link_out(&mut self, link_id: LinkId) {
131 self.links_out.push(link_id);
132 }
133
134 pub(crate) fn add_link_in(&mut self, link_id: LinkId) {
136 self.links_in.push(link_id);
137 }
138
139 pub(crate) fn add_lane_change(&mut self, link_id: LinkId) {
141 self.links_adjacent.push(link_id);
142 }
143
144 pub(crate) fn set_group(&mut self, group: Rc<LinkGroup>) {
146 self.group = Some(group);
147 }
148
149 pub(crate) fn add_conflict(&mut self, link_conflict: LinkConflict) {
151 self.conflicts.push(link_conflict);
152 }
153
154 #[allow(unused)]
156 pub(crate) fn can_insert_vehicle(&self, vehicles: &VehicleSet, pos: f64, len: f64) -> bool {
157 for id in &self.vehicles {
158 let other = &vehicles[*id];
159 let gap = other.pos_mid() - pos;
160 let needed = 0.5 * (len + other.length());
161 if gap.abs() < needed {
162 return false;
163 }
164 if gap > 0.0 {
165 break;
166 }
167 }
168 true
169 }
170
171 pub(crate) fn insert_vehicle(&mut self, vehicles: &VehicleSet, id: VehicleId) {
173 let veh_pos = vehicles[id].pos_mid();
174 let idx = self
175 .vehicles
176 .iter()
177 .map(|id| vehicles[*id].pos_mid())
178 .position(|pos| pos > veh_pos)
179 .unwrap_or(self.vehicles.len());
180 self.vehicles.insert(idx, id);
181 }
182
183 pub(crate) fn remove_vehicle(&mut self, id: VehicleId) {
185 if let Some(idx) = self.vehicles.iter().rposition(|v| *v == id) {
186 self.vehicles.remove(idx);
187 }
188 }
189
190 pub(crate) fn set_control(&mut self, control: TrafficControl) {
192 self.control = control;
193 }
194
195 pub(crate) fn apply_stoplines(&self, links: &LinkSet, vehicles: &VehicleSet) {
197 self.process_vehicles(
198 links,
199 vehicles,
200 &mut |vehicle| match vehicle.get_route(1) {
201 Some((_, RouteState::Entered)) => ControlFlow::Continue(()),
202 Some((link_id, state)) => match links[link_id].control {
203 TrafficControl::Open => {
204 if !vehicle.can_stop(-5.0) {
206 vehicle.enter_link();
207 ControlFlow::Continue(())
208 } else {
209 ControlFlow::Break(())
210 }
211 }
212 TrafficControl::Yield {
213 distance,
214 must_stop,
215 priority,
216 } => match state {
217 RouteState::NotEntered => {
218 let close_enough = vehicle.pos_front() > -distance;
220 let stopped = !must_stop || vehicle.has_stopped();
221 if close_enough && stopped {
222 vehicle.queue_link();
223 }
224 vehicle.stop_at_line(0.0);
225 ControlFlow::Break(())
226 }
227 RouteState::QueuedAt(frame) => {
228 if links[link_id].can_enter(
230 links,
231 vehicles,
232 &vehicle.offset(self.length()),
233 frame,
234 priority,
235 ) {
236 vehicle.enter_link();
237 ControlFlow::Continue(())
238 } else {
239 vehicle.stop_at_line(0.0);
240 ControlFlow::Break(())
241 }
242 }
243 RouteState::Entered => unreachable!(),
244 },
245 TrafficControl::Closed => {
246 vehicle.stop_at_line(0.0);
248 ControlFlow::Break(())
249 }
250 },
251 None => ControlFlow::Continue(()),
252 },
253 (0, self.id),
254 self.length(),
255 0,
256 );
257 }
258
259 fn can_enter(
261 &self,
262 links: &LinkSet,
263 vehicles: &VehicleSet,
264 vehicle: &RelativeVehicle,
265 queued_at: usize,
266 priority: i8,
267 ) -> bool {
268 for idx in rotated_range(self.conflicts.len(), self.last_conflict.get()) {
269 let conflict = &self.conflicts[idx];
270 let link = &links[conflict.link_id];
271 let queued_at = match link.control {
272 TrafficControl::Open => None,
273 TrafficControl::Yield { priority: p2, .. } => match priority.cmp(&p2) {
274 Ordering::Less => None,
275 Ordering::Equal => Some(queued_at),
276 Ordering::Greater => Some(0),
277 },
278 TrafficControl::Closed => Some(0),
279 };
280 let max_pos = conflict.own_max_pos;
281 let has_gap = link.check_gap(
282 links,
283 vehicles,
284 [conflict.min_pos, conflict.max_pos],
285 vehicle.min_reach_time(max_pos, self.speed_limit) + GAP_BUFFER,
286 queued_at,
287 (0, conflict.link_id),
288 0.0,
289 );
290 if !has_gap {
291 self.last_conflict.set(idx);
292 return false;
293 }
294 }
295 true
296 }
297
298 #[allow(clippy::too_many_arguments)]
300 fn check_gap(
301 &self,
302 links: &LinkSet,
303 vehicles: &VehicleSet,
304 pos: [f64; 2],
305 time: f64,
306 queued_at: Option<usize>,
307 route: (usize, LinkId),
308 max_vel: f64,
309 ) -> bool {
310 let max_vel = f64::max(max_vel, self.speed_limit);
311
312 let vehs_on_link = self
313 .vehicles
314 .iter()
315 .map(|id| &vehicles[*id])
316 .rev()
317 .skip_while(|veh| veh.pos_rear() > pos[1]);
318
319 for vehicle in vehs_on_link {
320 match (vehicle.get_route(route.0), queued_at) {
322 (None, _) => continue,
324 (Some((link_id, _)), _) if link_id != route.1 => continue,
325 (Some((_, RouteState::NotEntered)), Some(_)) => return true,
327 (Some((_, RouteState::QueuedAt(a))), Some(b)) if a > b => return true,
328 _ => return vehicle.min_reach_time(pos[0], max_vel) > time,
330 }
331 }
332
333 if pos[0] / max_vel > time {
334 true
335 } else {
336 let route = (route.0 + 1, route.1);
337 self.links_in.iter().all(|link_id| {
338 let link = &links[*link_id];
339 let pos = pos.map(|p| p + link.length());
340 link.check_gap(links, vehicles, pos, time, queued_at, route, max_vel)
341 })
342 }
343 }
344
345 pub(crate) fn apply_accelerations(&self, links: &LinkSet, vehicles: &VehicleSet) {
347 for ids in self.vehicles.windows(2) {
349 let [follower, leader] = [ids[0], ids[1]].map(|id| &vehicles[id]);
350 follower.follow_vehicle(leader.pos_rear(), leader.vel());
351 follower.apply_current_speed_limit(self.speed_limit);
352 }
353 if let Some(id) = self.vehicles.last() {
354 vehicles[*id].apply_current_speed_limit(self.speed_limit);
355 }
356
357 self.process_vehicles(
359 links,
360 vehicles,
361 &mut |veh| {
362 veh.apply_speed_limit(self.speed_limit, 0.0);
363 if let Some(leader) = self.vehicles.first().map(|id| &vehicles[*id]) {
364 veh.follow_vehicle(leader.pos_rear(), leader.vel());
365 }
366 ControlFlow::Break(())
367 },
368 (0, self.id),
369 0.0,
370 self.vehicles.len(),
371 );
372
373 if let Some(group) = self.group.as_deref() {
375 for proj in group.projections(self.id) {
376 let obstacles = self
377 .vehicles
378 .iter()
379 .rev()
380 .map(|id| vehicles[*id].project(proj));
381 links[proj.link_id()].follow_obstacles(links, vehicles, obstacles);
382 }
383 }
384 }
385
386 fn follow_obstacles(
390 &self,
391 links: &LinkSet,
392 vehicles: &VehicleSet,
393 obstacles: impl Iterator<Item = Obstacle>,
394 ) {
395 use ObstaclePassResult::*;
396
397 let mut skip = 0;
398
399 for obstacle in obstacles {
400 skip = self
402 .vehicles
403 .iter()
404 .rev()
405 .skip(skip)
406 .position(|id| vehicles[*id].pos_mid() < obstacle.pos)
407 .map(|cnt| skip + cnt)
408 .unwrap_or(self.vehicles.len());
409
410 self.process_vehicles(
412 links,
413 vehicles,
414 &mut |veh| match veh.can_pass(obstacle, self) {
415 Pass => ControlFlow::Continue(()),
416 Follow { pos, vel } => {
417 veh.follow_vehicle(pos - obstacle.pos, vel);
418 ControlFlow::Break(())
419 }
420 },
421 (0, self.id),
422 obstacle.pos,
423 skip,
424 );
425 }
426 }
427
428 pub(crate) fn deactivate(&mut self) {
430 self.active = false;
431 }
432
433 pub(crate) fn activate(&mut self) {
435 self.active = true;
436 }
437
438 pub(crate) fn process_vehicles<'a, F: FnMut(RelativeVehicle<'a>) -> ControlFlow<()>>(
450 &self,
451 links: &LinkSet,
452 vehicles: &'a VehicleSet,
453 func: &mut F,
454 route: (usize, LinkId),
455 pos: f64,
456 skip: usize,
457 ) {
458 if !self.active {
459 return;
460 }
461
462 let min_pos = pos - MAX_LOOKAHEAD * self.speed_limit;
463
464 for veh_id in self.vehicles.iter().rev().skip(skip) {
465 let vehicle = &vehicles[*veh_id];
466 if vehicle.pos_front() < min_pos {
467 return;
468 }
469 match vehicle.get_route(route.0) {
470 None => continue,
471 Some((link_id, _)) if link_id != route.1 => continue,
472 Some((_, RouteState::Entered)) => {}
473 Some((_, _)) => {
474 if pos > self.length() {
475 return;
476 }
477 }
478 }
479 let result = (*func)(RelativeVehicle {
480 vehicle,
481 route_idx: route.0,
482 pos,
483 });
484 if result.is_break() {
485 return;
486 }
487 }
488
489 if min_pos >= 0.0 {
490 return;
491 }
492
493 let route = (route.0 + 1, route.1);
494 for link_id in &self.links_in {
495 let link = &links[*link_id];
496 let pos = pos + link.length();
497 let skip = 0;
498 link.process_vehicles(links, vehicles, func, route, pos, skip);
499 }
500 }
501}
502
503pub(crate) struct RelativeVehicle<'a> {
505 vehicle: &'a Vehicle,
506 route_idx: usize,
507 pos: f64,
508}
509
510impl<'a> RelativeVehicle<'a> {
511 pub fn offset(&self, offset: f64) -> RelativeVehicle {
512 Self {
513 vehicle: self.vehicle,
514 pos: self.pos + offset,
515 route_idx: self.route_idx + 1,
516 }
517 }
518
519 pub fn pos_front(&self) -> f64 {
520 self.vehicle.pos_front() - self.pos
521 }
522
523 pub fn pos_rear(&self) -> f64 {
524 self.vehicle.pos_rear() - self.pos
525 }
526
527 pub fn can_stop(&self, pos: f64) -> bool {
528 self.vehicle.can_stop(self.pos + pos)
529 }
530
531 pub fn vel(&self) -> f64 {
532 self.vehicle.vel()
533 }
534
535 pub fn has_stopped(&self) -> bool {
536 self.vehicle.has_stopped()
537 }
538
539 pub fn rear_coords(&self) -> [Point2d; 2] {
540 self.vehicle.rear_coords()
541 }
542
543 pub fn min_reach_time(&self, pos: f64, max_vel: f64) -> f64 {
544 self.vehicle.min_reach_time(self.pos + pos, max_vel)
545 }
546
547 pub fn apply_speed_limit(&self, speed_limit: f64, pos: f64) {
548 self.vehicle.apply_speed_limit(speed_limit, self.pos + pos);
549 }
550
551 pub fn follow_vehicle(&self, pos: f64, vel: f64) {
552 self.vehicle.follow_vehicle(self.pos + pos, vel);
553 }
554
555 pub fn stop_at_line(&self, pos: f64) {
556 self.vehicle.stop_at_line(self.pos + pos);
557 }
558
559 pub fn follow_obstacle(&self, coords: [Point2d; 2], vel: f64) {
560 self.vehicle.follow_obstacle(coords, vel);
561 }
562
563 pub fn enter_link(&self) {
564 self.vehicle.enter_link();
565 }
566
567 pub fn queue_link(&self) {
568 self.vehicle.queue_link();
569 }
570
571 pub fn get_route(&self, idx: usize) -> Option<(LinkId, RouteState)> {
572 self.vehicle.get_route(self.route_idx + idx)
573 }
574
575 pub fn link_id(&self, idx: usize) -> Option<LinkId> {
576 self.get_route(idx).map(|(link_id, _)| link_id)
577 }
578
579 pub fn can_pass(&self, obstacle: Obstacle, link: &Link) -> ObstaclePassResult {
581 self.vehicle.can_pass(obstacle, link)
582 }
583}