1use crate::{
5 client::TraciClient,
6 constants::*,
7 error::TraciError,
8 storage::Storage,
9 types::{
10 ContextSubscriptionResults, SubscriptionResults, TraciPosition, TraciRoadPosition,
11 TraciStage,
12 },
13};
14
15#[derive(Debug, Default)]
17pub struct SimulationScope {
18 pub subscription_results: SubscriptionResults,
19 pub context_subscription_results: ContextSubscriptionResults,
20}
21
22impl SimulationScope {
23 crate::impl_scope_accessors!();
24
25 pub fn get_current_time(&self, client: &mut TraciClient) -> Result<i32, TraciError> {
30 client.create_command(CMD_GET_SIM_VARIABLE, VAR_TIME_STEP, "", None);
31 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_INTEGER))?;
32 client.read_int_from_input()
33 }
34
35 pub fn get_time(&self, client: &mut TraciClient) -> Result<f64, TraciError> {
36 client.create_command(CMD_GET_SIM_VARIABLE, VAR_TIME, "", None);
37 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_DOUBLE))?;
38 client.read_double_from_input()
39 }
40
41 pub fn get_loaded_number(&self, client: &mut TraciClient) -> Result<i32, TraciError> {
42 client.create_command(CMD_GET_SIM_VARIABLE, VAR_LOADED_VEHICLES_NUMBER, "", None);
43 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_INTEGER))?;
44 client.read_int_from_input()
45 }
46
47 pub fn get_loaded_id_list(&self, client: &mut TraciClient) -> Result<Vec<String>, TraciError> {
48 client.create_command(CMD_GET_SIM_VARIABLE, VAR_LOADED_VEHICLES_IDS, "", None);
49 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_STRINGLIST))?;
50 client.read_string_list_from_input()
51 }
52
53 pub fn get_departed_number(&self, client: &mut TraciClient) -> Result<i32, TraciError> {
54 client.create_command(CMD_GET_SIM_VARIABLE, VAR_DEPARTED_VEHICLES_NUMBER, "", None);
55 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_INTEGER))?;
56 client.read_int_from_input()
57 }
58
59 pub fn get_departed_id_list(&self, client: &mut TraciClient) -> Result<Vec<String>, TraciError> {
60 client.create_command(CMD_GET_SIM_VARIABLE, VAR_DEPARTED_VEHICLES_IDS, "", None);
61 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_STRINGLIST))?;
62 client.read_string_list_from_input()
63 }
64
65 pub fn get_arrived_number(&self, client: &mut TraciClient) -> Result<i32, TraciError> {
66 client.create_command(CMD_GET_SIM_VARIABLE, VAR_ARRIVED_VEHICLES_NUMBER, "", None);
67 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_INTEGER))?;
68 client.read_int_from_input()
69 }
70
71 pub fn get_arrived_id_list(&self, client: &mut TraciClient) -> Result<Vec<String>, TraciError> {
72 client.create_command(CMD_GET_SIM_VARIABLE, VAR_ARRIVED_VEHICLES_IDS, "", None);
73 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_STRINGLIST))?;
74 client.read_string_list_from_input()
75 }
76
77 pub fn get_starting_teleport_number(&self, client: &mut TraciClient) -> Result<i32, TraciError> {
78 client.create_command(CMD_GET_SIM_VARIABLE, VAR_TELEPORT_STARTING_VEHICLES_NUMBER, "", None);
79 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_INTEGER))?;
80 client.read_int_from_input()
81 }
82
83 pub fn get_starting_teleport_id_list(&self, client: &mut TraciClient) -> Result<Vec<String>, TraciError> {
84 client.create_command(CMD_GET_SIM_VARIABLE, VAR_TELEPORT_STARTING_VEHICLES_IDS, "", None);
85 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_STRINGLIST))?;
86 client.read_string_list_from_input()
87 }
88
89 pub fn get_ending_teleport_number(&self, client: &mut TraciClient) -> Result<i32, TraciError> {
90 client.create_command(CMD_GET_SIM_VARIABLE, VAR_TELEPORT_ENDING_VEHICLES_NUMBER, "", None);
91 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_INTEGER))?;
92 client.read_int_from_input()
93 }
94
95 pub fn get_ending_teleport_id_list(&self, client: &mut TraciClient) -> Result<Vec<String>, TraciError> {
96 client.create_command(CMD_GET_SIM_VARIABLE, VAR_TELEPORT_ENDING_VEHICLES_IDS, "", None);
97 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_STRINGLIST))?;
98 client.read_string_list_from_input()
99 }
100
101 pub fn get_departed_person_number(&self, client: &mut TraciClient) -> Result<i32, TraciError> {
102 client.create_command(CMD_GET_SIM_VARIABLE, VAR_DEPARTED_PERSONS_NUMBER, "", None);
103 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_INTEGER))?;
104 client.read_int_from_input()
105 }
106
107 pub fn get_departed_person_id_list(&self, client: &mut TraciClient) -> Result<Vec<String>, TraciError> {
108 client.create_command(CMD_GET_SIM_VARIABLE, VAR_DEPARTED_PERSONS_IDS, "", None);
109 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_STRINGLIST))?;
110 client.read_string_list_from_input()
111 }
112
113 pub fn get_arrived_person_number(&self, client: &mut TraciClient) -> Result<i32, TraciError> {
114 client.create_command(CMD_GET_SIM_VARIABLE, VAR_ARRIVED_PERSONS_NUMBER, "", None);
115 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_INTEGER))?;
116 client.read_int_from_input()
117 }
118
119 pub fn get_arrived_person_id_list(&self, client: &mut TraciClient) -> Result<Vec<String>, TraciError> {
120 client.create_command(CMD_GET_SIM_VARIABLE, VAR_ARRIVED_PERSONS_IDS, "", None);
121 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_STRINGLIST))?;
122 client.read_string_list_from_input()
123 }
124
125 pub fn get_delta_t(&self, client: &mut TraciClient) -> Result<f64, TraciError> {
126 client.create_command(CMD_GET_SIM_VARIABLE, VAR_DELTA_T, "", None);
127 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_DOUBLE))?;
128 client.read_double_from_input()
129 }
130
131 pub fn get_net_boundary(&self, client: &mut TraciClient) -> Result<Vec<crate::types::TraciPosition>, TraciError> {
132 client.create_command(CMD_GET_SIM_VARIABLE, VAR_NET_BOUNDING_BOX, "", None);
133 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_POLYGON))?;
134 client.read_polygon_from_input()
135 }
136
137 pub fn get_min_expected_number(&self, client: &mut TraciClient) -> Result<i32, TraciError> {
138 client.create_command(CMD_GET_SIM_VARIABLE, VAR_MIN_EXPECTED_VEHICLES, "", None);
139 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_INTEGER))?;
140 client.read_int_from_input()
141 }
142
143 pub fn get_option(&self, client: &mut TraciClient, option: &str) -> Result<String, TraciError> {
144 client.create_command(CMD_GET_SIM_VARIABLE, VAR_OPTION, option, None);
145 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_STRING))?;
146 client.read_string_from_input()
147 }
148
149 pub fn get_bus_stop_waiting(&self, client: &mut TraciClient, stop_id: &str) -> Result<i32, TraciError> {
150 client.create_command(CMD_GET_SIM_VARIABLE, VAR_BUS_STOP_WAITING, stop_id, None);
151 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_INTEGER))?;
152 client.read_int_from_input()
153 }
154
155 pub fn get_bus_stop_waiting_id_list(&self, client: &mut TraciClient, stop_id: &str) -> Result<Vec<String>, TraciError> {
156 client.create_command(CMD_GET_SIM_VARIABLE, VAR_BUS_STOP_WAITING_IDS, stop_id, None);
157 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_STRINGLIST))?;
158 client.read_string_list_from_input()
159 }
160
161 pub fn convert2d(
167 &self,
168 client: &mut TraciClient,
169 edge_id: &str,
170 pos: f64,
171 lane_index: i32,
172 to_geo: bool,
173 ) -> Result<TraciPosition, TraciError> {
174 let pos_type = if to_geo { POSITION_LON_LAT } else { POSITION_2D };
175 let mut add = Storage::new();
176 add.write_u8(TYPE_COMPOUND);
177 add.write_i32(2);
178 add.write_u8(POSITION_ROADMAP);
179 add.write_string(edge_id);
180 add.write_f64(pos);
181 add.write_u8(lane_index as u8);
182 add.write_u8(TYPE_UBYTE);
183 add.write_u8(pos_type);
184 client.create_command(CMD_GET_SIM_VARIABLE, POSITION_CONVERSION, "", Some(&add));
185 client.process_get(CMD_GET_SIM_VARIABLE, Some(pos_type))?;
186 let x = client.read_double_from_input()?;
187 let y = client.read_double_from_input()?;
188 Ok(TraciPosition::new_2d(x, y))
189 }
190
191 pub fn convert3d(
193 &self,
194 client: &mut TraciClient,
195 edge_id: &str,
196 pos: f64,
197 lane_index: i32,
198 to_geo: bool,
199 ) -> Result<TraciPosition, TraciError> {
200 let pos_type = if to_geo { POSITION_LON_LAT_ALT } else { POSITION_3D };
201 let mut add = Storage::new();
202 add.write_u8(TYPE_COMPOUND);
203 add.write_i32(2);
204 add.write_u8(POSITION_ROADMAP);
205 add.write_string(edge_id);
206 add.write_f64(pos);
207 add.write_u8(lane_index as u8);
208 add.write_u8(TYPE_UBYTE);
209 add.write_u8(pos_type);
210 client.create_command(CMD_GET_SIM_VARIABLE, POSITION_CONVERSION, "", Some(&add));
211 client.process_get(CMD_GET_SIM_VARIABLE, Some(pos_type))?;
212 let x = client.read_double_from_input()?;
213 let y = client.read_double_from_input()?;
214 let z = client.read_double_from_input()?;
215 Ok(TraciPosition::new_3d(x, y, z))
216 }
217
218 pub fn convert_road(
220 &self,
221 client: &mut TraciClient,
222 x: f64,
223 y: f64,
224 is_geo: bool,
225 v_class: &str,
226 ) -> Result<TraciRoadPosition, TraciError> {
227 let src_pos_type = if is_geo { POSITION_LON_LAT } else { POSITION_2D };
228 let mut add = Storage::new();
229 add.write_u8(TYPE_COMPOUND);
230 add.write_i32(3);
231 add.write_u8(src_pos_type);
232 add.write_f64(x);
233 add.write_f64(y);
234 add.write_u8(TYPE_UBYTE);
235 add.write_u8(POSITION_ROADMAP);
236 add.write_u8(TYPE_STRING);
237 add.write_string(v_class);
238 client.create_command(CMD_GET_SIM_VARIABLE, POSITION_CONVERSION, "", Some(&add));
239 client.process_get(CMD_GET_SIM_VARIABLE, Some(POSITION_ROADMAP))?;
240 let edge_id = client.read_string_from_input()?;
241 let pos = client.read_double_from_input()?;
242 let lane_index = client.read_ubyte_from_input()? as i32;
243 Ok(TraciRoadPosition { edge_id, pos, lane_index })
244 }
245
246 pub fn convert_geo(
248 &self,
249 client: &mut TraciClient,
250 x: f64,
251 y: f64,
252 from_geo: bool,
253 ) -> Result<TraciPosition, TraciError> {
254 let pos_type = if from_geo { POSITION_2D } else { POSITION_LON_LAT };
255 let src_pos_type = if from_geo { POSITION_LON_LAT } else { POSITION_2D };
256 let mut add = Storage::new();
257 add.write_u8(TYPE_COMPOUND);
258 add.write_i32(2);
259 add.write_u8(src_pos_type);
260 add.write_f64(x);
261 add.write_f64(y);
262 add.write_u8(TYPE_UBYTE);
263 add.write_u8(pos_type);
264 client.create_command(CMD_GET_SIM_VARIABLE, POSITION_CONVERSION, "", Some(&add));
265 client.process_get(CMD_GET_SIM_VARIABLE, Some(pos_type))?;
266 let rx = client.read_double_from_input()?;
267 let ry = client.read_double_from_input()?;
268 Ok(TraciPosition::new_2d(rx, ry))
269 }
270
271 pub fn get_distance_2d(
277 &self,
278 client: &mut TraciClient,
279 x1: f64,
280 y1: f64,
281 x2: f64,
282 y2: f64,
283 is_geo: bool,
284 is_driving: bool,
285 ) -> Result<f64, TraciError> {
286 let pos_type = if is_geo { POSITION_LON_LAT } else { POSITION_2D };
287 let dist_type: u8 = if is_driving { REQUEST_DRIVINGDIST } else { REQUEST_AIRDIST };
288 let mut add = Storage::new();
289 add.write_u8(TYPE_COMPOUND);
290 add.write_i32(3);
291 add.write_u8(pos_type);
292 add.write_f64(x1);
293 add.write_f64(y1);
294 add.write_u8(pos_type);
295 add.write_f64(x2);
296 add.write_f64(y2);
297 add.write_u8(dist_type);
298 client.create_command(CMD_GET_SIM_VARIABLE, DISTANCE_REQUEST, "", Some(&add));
299 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_DOUBLE))?;
300 client.read_double_from_input()
301 }
302
303 pub fn get_distance_road(
305 &self,
306 client: &mut TraciClient,
307 edge_id1: &str,
308 pos1: f64,
309 edge_id2: &str,
310 pos2: f64,
311 is_driving: bool,
312 ) -> Result<f64, TraciError> {
313 let dist_type: u8 = if is_driving { REQUEST_DRIVINGDIST } else { REQUEST_AIRDIST };
314 let mut add = Storage::new();
315 add.write_u8(TYPE_COMPOUND);
316 add.write_i32(3);
317 add.write_u8(POSITION_ROADMAP);
318 add.write_string(edge_id1);
319 add.write_f64(pos1);
320 add.write_u8(0); add.write_u8(POSITION_ROADMAP);
322 add.write_string(edge_id2);
323 add.write_f64(pos2);
324 add.write_u8(0); add.write_u8(dist_type);
326 client.create_command(CMD_GET_SIM_VARIABLE, DISTANCE_REQUEST, "", Some(&add));
327 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_DOUBLE))?;
328 client.read_double_from_input()
329 }
330
331 pub fn find_route(
337 &self,
338 client: &mut TraciClient,
339 from_edge: &str,
340 to_edge: &str,
341 v_type: &str,
342 pos: f64,
343 routing_mode: i32,
344 ) -> Result<TraciStage, TraciError> {
345 let mut add = Storage::new();
346 add.write_u8(TYPE_COMPOUND);
347 add.write_i32(5);
348 add.write_u8(TYPE_STRING);
349 add.write_string(from_edge);
350 add.write_u8(TYPE_STRING);
351 add.write_string(to_edge);
352 add.write_u8(TYPE_STRING);
353 add.write_string(v_type);
354 add.write_u8(TYPE_DOUBLE);
355 add.write_f64(pos);
356 add.write_u8(TYPE_INTEGER);
357 add.write_i32(routing_mode);
358 client.create_command(CMD_GET_SIM_VARIABLE, FIND_ROUTE, "", Some(&add));
359 client.process_get(CMD_GET_SIM_VARIABLE, Some(TYPE_COMPOUND))?;
360 read_traci_stage(client)
361 }
362
363 pub fn load_state(&self, client: &mut TraciClient, path: &str) -> Result<(), TraciError> {
368 let mut add = Storage::new();
369 add.write_u8(TYPE_STRING);
370 add.write_string(path);
371 client.create_command(CMD_SET_SIM_VARIABLE, CMD_LOAD_SIMSTATE, "", Some(&add));
372 client.process_set(CMD_SET_SIM_VARIABLE)?;
373 Ok(())
374 }
375
376 pub fn save_state(&self, client: &mut TraciClient, destination: &str) -> Result<(), TraciError> {
377 let mut add = Storage::new();
378 add.write_u8(TYPE_STRING);
379 add.write_string(destination);
380 client.create_command(CMD_SET_SIM_VARIABLE, CMD_SAVE_SIMSTATE, "", Some(&add));
381 client.process_set(CMD_SET_SIM_VARIABLE)?;
382 Ok(())
383 }
384
385 pub fn write_message(&self, client: &mut TraciClient, msg: &str) -> Result<(), TraciError> {
386 let mut add = Storage::new();
387 add.write_u8(TYPE_STRING);
388 add.write_string(msg);
389 client.create_command(CMD_SET_SIM_VARIABLE, CMD_MESSAGE, "", Some(&add));
390 client.process_set(CMD_SET_SIM_VARIABLE)?;
391 Ok(())
392 }
393
394 pub fn subscribe(&self, client: &mut TraciClient, vars: &[u8], begin: f64, end: f64) -> Result<(), TraciError> {
395 client.subscribe_object_variable(CMD_SUBSCRIBE_SIM_VARIABLE, "", begin, end, vars)
396 }
397}
398
399pub(crate) fn read_traci_stage(client: &mut TraciClient) -> Result<TraciStage, TraciError> {
406 client.read_int_from_input()?; client.read_ubyte_from_input()?; let type_ = client.read_int_from_input()?;
409
410 client.read_ubyte_from_input()?; let v_type = client.read_string_from_input()?;
412
413 client.read_ubyte_from_input()?;
414 let line = client.read_string_from_input()?;
415
416 client.read_ubyte_from_input()?;
417 let dest_stop = client.read_string_from_input()?;
418
419 client.read_ubyte_from_input()?;
420 let edges = client.read_string_list_from_input()?;
421
422 client.read_ubyte_from_input()?;
423 let travel_time = client.read_double_from_input()?;
424
425 client.read_ubyte_from_input()?;
426 let cost = client.read_double_from_input()?;
427
428 client.read_ubyte_from_input()?;
429 let length = client.read_double_from_input()?;
430
431 client.read_ubyte_from_input()?;
432 let intended = client.read_string_from_input()?;
433
434 client.read_ubyte_from_input()?;
435 let depart = client.read_double_from_input()?;
436
437 client.read_ubyte_from_input()?;
438 let depart_pos = client.read_double_from_input()?;
439
440 client.read_ubyte_from_input()?;
441 let arrival_pos = client.read_double_from_input()?;
442
443 client.read_ubyte_from_input()?;
444 let description = client.read_string_from_input()?;
445
446 Ok(TraciStage {
447 type_,
448 v_type,
449 line,
450 dest_stop,
451 edges,
452 travel_time,
453 cost,
454 length,
455 intended,
456 depart,
457 depart_pos,
458 arrival_pos,
459 description,
460 })
461}