1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
use crate::conflict::ConflictPoint;
use crate::debug::take_debug_frame;
use crate::light::TrafficLight;
use crate::link::{Link, LinkAttributes, TrafficControl};
use crate::math::CubicFn;
use crate::vehicle::{LaneChange, Vehicle, VehicleAttributes};
use crate::{LinkGroup, LinkId, LinkSet, TrafficLightId, VehicleId, VehicleSet};
use serde::{Deserialize, Serialize};
use slotmap::SlotMap;
use std::rc::Rc;
/// A traffic simulation.
#[derive(Default, Clone, Serialize, Deserialize)]
pub struct Simulation {
/// The links in the network.
links: LinkSet,
/// The traffic lights.
lights: SlotMap<TrafficLightId, TrafficLight>,
/// The vehicles being simulated.
vehicles: VehicleSet,
/// The conflict points.
conflicts: Vec<ConflictPoint>,
/// The set of "frozen" vehicles, which will not move.
frozen_vehs: Vec<VehicleId>,
/// The current frame of simulation.
frame: usize,
/// The next sequence number.
seq: usize,
/// Debugging information from the previously simulated frame.
debug: serde_json::Value,
}
impl Simulation {
/// Creates a new simulation.
pub fn new() -> Self {
Default::default()
}
/// Adds a link to the network.
pub fn add_link(&mut self, attributes: &LinkAttributes) -> LinkId {
self.links.insert_with_key(|id| Link::new(id, attributes))
}
/// Specifies that these vehicles on these links may
/// interact with vehicles on other links in the group.
pub fn add_link_group(&mut self, link_ids: &[LinkId]) {
let links = link_ids
.iter()
.map(|id| &self.links[*id])
.collect::<Vec<_>>();
let group = Rc::new(LinkGroup::new(&links));
for id in link_ids {
self.links[*id].set_group(group.clone());
}
}
/// Permits vehicles to lane change from the `from` link to the `to` link.
/// Both links must belong to the same [LinkGroup].
pub fn add_lane_change(&mut self, from: LinkId, to: LinkId) {
self.links[from].add_lane_change(to);
}
/// Specifies that two links may converge or cross.
pub fn add_link_convergance(&mut self, a: LinkId, b: LinkId) {
if let Some([a, b]) = self.links.get_disjoint_mut([a, b]) {
if let Some(conflict_point) = ConflictPoint::new(a, b) {
for (link_id, link_conflict) in conflict_point.link_conflicts() {
self.links[link_id].add_conflict(link_conflict);
}
self.conflicts.push(conflict_point);
}
}
}
/// Specifies that the end of the `from` link connects to the start of the `to` link.
pub fn add_link_connection(&mut self, from: LinkId, to: LinkId) {
self.links[from].add_link_out(to);
self.links[to].add_link_in(from);
}
/// Adds a traffic light to the simulation.
pub fn add_traffic_light(&mut self, light: TrafficLight) -> TrafficLightId {
self.lights.insert(light)
}
/// Adds a vehicle to the simulation.
pub fn add_vehicle(&mut self, attributes: &VehicleAttributes, link: LinkId) -> VehicleId {
let vehicle_id = self.vehicles.insert_with_key(|id| {
let mut vehicle = Vehicle::new(id, attributes);
vehicle.set_location(link, 0.0, None);
vehicle.update_coords(&self.links);
vehicle
});
self.links[link].insert_vehicle(&self.vehicles, vehicle_id);
vehicle_id
}
/// Sets the `frozen` attribute of a vehicle. When a vehicle is frozen,
/// it will maximally decelerate until its velocity is zero and remain stopped
/// until it is no longer frozen.
pub fn set_vehicle_frozen(&mut self, vehicle_id: VehicleId, frozen: bool) {
let idx = self.frozen_vehs.iter().position(|id| *id == vehicle_id);
match (frozen, idx) {
(true, None) => {
self.frozen_vehs.push(vehicle_id);
}
(false, Some(idx)) => {
self.frozen_vehs.remove(idx);
}
_ => {}
}
}
/// Gets the `frozen` attribute of a vehicle. [Read more](Self::set_vehicle_frozen).
pub fn get_vehicle_frozen(&mut self, vehicle_id: VehicleId) -> bool {
self.frozen_vehs.iter().any(|id| *id == vehicle_id)
}
/// Advances the simulation by `dt` seconds.
///
/// For a realistic simulation, do not use a time step greater than around 0.2.
pub fn step(&mut self, dt: f64) {
self.update_lights(dt);
self.apply_accelerations();
self.integrate(dt);
self.advance_vehicles();
self.update_vehicle_coords();
self.take_debug_frame();
self.frame += 1;
}
/// Advances the simulation by `dt` seconds, but only integrates vehicles positions,
/// and doesn't recalculate more expensive aspects of the simulation.
///
/// Use this to achieve better performance while retaining a smooth animation frame rate,
/// though beware that simulating too many consecutive frames with this method will result
/// in a noticeable degradation in simulation quality and realism.
pub fn step_fast(&mut self, dt: f64) {
self.update_lights(dt);
self.integrate(dt);
self.advance_vehicles();
self.update_vehicle_coords();
self.take_debug_frame();
self.frame += 1;
}
/// Gets the current simulation frame index.
pub fn frame(&self) -> usize {
self.frame
}
/// Returns an iterator over all the links in the simulation.
pub fn iter_links(&self) -> impl Iterator<Item = &Link> {
self.links.iter().map(|(_, link)| link)
}
/// Returns an iterator over all the vehicles in the simulation.
pub fn iter_vehicles(&self) -> impl Iterator<Item = &Vehicle> {
self.vehicles.iter().map(|(_, veh)| veh)
}
/// Gets a reference to the vehicle with the given ID.
pub fn get_vehicle(&self, vehicle_id: VehicleId) -> &Vehicle {
&self.vehicles[vehicle_id]
}
/// Gets a reference to the link with the given ID.
pub fn get_link(&self, link_id: LinkId) -> &Link {
&self.links[link_id]
}
/// Sets the [TrafficControl] at the start of the given link.
pub fn set_link_control(&mut self, link_id: LinkId, control: TrafficControl) {
self.links[link_id].set_control(control);
}
/// Gets the debugging information for the previously simulated frame as JSON array.
pub fn debug(&mut self) -> serde_json::Value {
self.debug.take()
}
/// Takes the debugging information from the global buffer.
fn take_debug_frame(&mut self) {
self.debug = take_debug_frame();
}
/// Updates the traffic lights.
fn update_lights(&mut self, dt: f64) {
for (_, light) in &mut self.lights {
light.step(dt);
for (link_id, control) in light.get_states() {
self.links[link_id].set_control(control);
}
}
}
/// Calculates the accelerations of the vehicles.
fn apply_accelerations(&mut self) {
for (_, link) in &mut self.links {
link.deactivate();
}
for (_, vehicle) in &mut self.vehicles {
vehicle.reset();
vehicle.activate_links(&mut self.links);
}
self.apply_stoplines();
self.apply_link_accelerations();
self.apply_frozen_vehicles();
}
/// Applies accelerations to stop vehicles before stop lines,
/// and allows vehicles to enter links.
fn apply_stoplines(&self) {
for (_, link) in &self.links {
link.apply_stoplines(&self.links, &self.vehicles);
}
}
/// Applies the car following model, speed limits, etc. to all vehicles.
fn apply_link_accelerations(&mut self) {
for (_, link) in &self.links {
link.apply_accelerations(&self.links, &self.vehicles);
}
for conflict in &self.conflicts {
conflict.apply_accelerations(&self.links, &self.vehicles);
}
}
/// Applies a large negative acceleration to all frozen vehicles.
fn apply_frozen_vehicles(&mut self) {
self.frozen_vehs.retain(|vehicle_id| {
if let Some(vehicle) = self.vehicles.get(*vehicle_id) {
vehicle.emergency_stop();
true
} else {
false
}
})
}
/// Integrates the velocities and positions of all vehicles,
/// then resets their accelerations.
fn integrate(&mut self, dt: f64) {
for (_, vehicle) in &mut self.vehicles {
vehicle.integrate(dt, &mut self.seq);
}
}
/// Find vehicles that have advanced their link and either move them
/// to their new link or remove them from the simulation.
fn advance_vehicles(&mut self) {
let mut advanced = vec![];
let mut exited = vec![];
for (vehicle_id, vehicle) in &mut self.vehicles {
let link_id = vehicle.link_id().unwrap();
let did_advance = vehicle.advance(&self.links);
if did_advance {
self.links[link_id].remove_vehicle(vehicle_id);
if let Some(link_id) = vehicle.link_id() {
// Vehicle is now on a new link
advanced.push((vehicle_id, link_id));
} else {
// Vehicle has exited the simulation
exited.push(vehicle_id);
}
}
}
for (vehicle_id, link_id) in advanced {
self.links[link_id].insert_vehicle(&self.vehicles, vehicle_id);
}
for vehicle_id in exited {
self.vehicles.remove(vehicle_id);
}
}
/// Updates the world coordinates of all the vehicles.
fn update_vehicle_coords(&mut self) {
for (_, vehicle) in &mut self.vehicles {
vehicle.update_coords(&self.links);
}
}
/// Causes the given vehicle to change lanes from its current link to the specified link.
/// It will smoothly transition from one to the other over the given `distance` specified in metres.
pub fn do_lane_change(&mut self, vehicle_id: VehicleId, link_id: LinkId, distance: f64) {
let vehicle = &mut self.vehicles[vehicle_id];
// Remove the vehicle from its current link
if let Some(link_id) = vehicle.link_id() {
self.links[link_id].remove_vehicle(vehicle_id);
}
// Project the vehicle's position onto the new link
let link = &mut self.links[link_id];
let (pos, offset, slope) = link
.curve()
.inverse_sample(vehicle.position(), vehicle.direction())
.unwrap();
// Set the vehicle's new position
let end_pos = pos + distance;
let lane_change = LaneChange {
end_pos,
offset: CubicFn::fit(pos, offset, slope, end_pos, 0.0, 0.0),
};
vehicle.set_location(link_id, pos, Some(lane_change));
// Add the vehicle to the new link
link.insert_vehicle(&self.vehicles, vehicle_id);
}
/// Sets the route for the given vehicle, which is the list of links it will traverse
/// after it has exited its current link.
pub fn set_vehicle_route(&mut self, vehicle_id: VehicleId, route: &[LinkId]) {
self.vehicles[vehicle_id].set_route(route, true);
}
}