maliput/api/rules/mod.rs
1// BSD 3-Clause License
2//
3// Copyright (c) 2024, Woven by Toyota.
4// All rights reserved.
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are met:
8//
9// * Redistributions of source code must retain the above copyright notice, this
10// list of conditions and the following disclaimer.
11//
12// * Redistributions in binary form must reproduce the above copyright notice,
13// this list of conditions and the following disclaimer in the documentation
14// and/or other materials provided with the distribution.
15//
16// * Neither the name of the copyright holder nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31use std::collections::HashMap;
32
33use crate::{api::RoadPosition, common::MaliputError};
34use strum_macros::{Display, IntoStaticStr};
35
36/// Interface for accessing the [TrafficLight] in the [super::RoadNetwork]
37pub struct TrafficLightBook<'a> {
38 pub(super) traffic_light_book: &'a maliput_sys::api::rules::ffi::TrafficLightBook,
39}
40
41impl<'a> TrafficLightBook<'a> {
42 /// Gets all the [TrafficLight]s in the [TrafficLightBook]
43 ///
44 /// # Returns
45 /// A vector of [TrafficLight]s
46 pub fn traffic_lights(&self) -> Vec<TrafficLight<'_>> {
47 let traffic_lights_cpp = maliput_sys::api::rules::ffi::TrafficLightBook_TrafficLights(self.traffic_light_book);
48 traffic_lights_cpp
49 .into_iter()
50 .map(|tl| TrafficLight {
51 traffic_light: unsafe { tl.traffic_light.as_ref().expect("") },
52 })
53 .collect::<Vec<TrafficLight>>()
54 }
55
56 /// Gets a [TrafficLight] by its id.
57 ///
58 /// # Arguments
59 /// * `id` - The id of the [TrafficLight].
60 ///
61 /// # Returns
62 /// The [TrafficLight] with the given id.
63 /// If no [TrafficLight] is found with the given id, return None.
64 pub fn get_traffic_light(&self, id: &String) -> Option<TrafficLight<'_>> {
65 let traffic_light = maliput_sys::api::rules::ffi::TrafficLightBook_GetTrafficLight(self.traffic_light_book, id);
66 if traffic_light.is_null() {
67 return None;
68 }
69 Some(TrafficLight {
70 traffic_light: unsafe {
71 traffic_light
72 .as_ref()
73 .expect("Unable to get underlying traffic light pointer")
74 },
75 })
76 }
77
78 /// Gets all [TrafficLight]s whose `related_lanes()` includes the given lane ID.
79 ///
80 /// # Arguments
81 /// * `lane_id` - The lane ID to look up.
82 ///
83 /// # Returns
84 /// A vector of [TrafficLight]s associated with the given lane.
85 /// Returns an empty vector if no traffic lights are associated with the lane.
86 pub fn find_by_lane(&self, lane_id: &String) -> Vec<TrafficLight<'_>> {
87 let traffic_lights_cpp =
88 maliput_sys::api::rules::ffi::TrafficLightBook_FindByLane(self.traffic_light_book, lane_id);
89 traffic_lights_cpp
90 .into_iter()
91 .map(|tl| TrafficLight {
92 traffic_light: unsafe { tl.traffic_light.as_ref().expect("TrafficLight pointer is null") },
93 })
94 .collect::<Vec<TrafficLight>>()
95 }
96}
97
98/// Models a traffic light. A traffic light is a physical signaling device
99/// typically located at road intersections. It contains one or more groups of
100/// light bulbs with varying colors and shapes. The lighting patterns of the
101/// bulbs signify right-of-way rule information to the agents navigating the
102/// intersection (e.g., vehicles, bicyclists, pedestrians, etc.). Typically, an
103/// intersection will be managed by multiple traffic lights.
104///
105/// Note that traffic lights are physical manifestations of underlying
106/// right-of-way rules and thus naturally have lower signal-to-noise ratio
107/// relative to the underlying rules. Thus, oracular agents should directly use
108/// the underlying right-of-way rules instead of traffic lights when navigating
109/// intersections. TrafficLight exists for testing autonomous vehicles that do
110/// not have access to right-of-way rules.
111pub struct TrafficLight<'a> {
112 pub traffic_light: &'a maliput_sys::api::rules::ffi::TrafficLight,
113}
114
115impl<'a> TrafficLight<'a> {
116 /// Get the id of the [TrafficLight].
117 ///
118 /// # Returns
119 /// The id of the [TrafficLight].
120 pub fn id(&self) -> String {
121 maliput_sys::api::rules::ffi::TrafficLight_id(self.traffic_light)
122 }
123
124 /// Get the position of the [TrafficLight] in the road network.
125 ///
126 /// # Returns
127 /// An [super::InertialPosition] representing the position of the [TrafficLight] in the road network.
128 pub fn position_road_network(&self) -> super::InertialPosition {
129 let inertial_position = maliput_sys::api::rules::ffi::TrafficLight_position_road_network(self.traffic_light);
130 super::InertialPosition { ip: inertial_position }
131 }
132
133 /// Get the orientation of the [TrafficLight] in the road network.
134 ///
135 /// # Returns
136 /// An [super::Rotation] representing the orientation of the [TrafficLight] in the road network.
137 pub fn orientation_road_network(&self) -> super::Rotation {
138 let rotation = maliput_sys::api::rules::ffi::TrafficLight_orientation_road_network(self.traffic_light);
139 super::Rotation { r: rotation }
140 }
141
142 /// Get the bulb groups of the [TrafficLight].
143 ///
144 /// # Returns
145 /// A vector of [BulbGroup]s in the [TrafficLight].
146 /// If the [TrafficLight] has no bulb groups, return an empty vector.
147 pub fn bulb_groups(&self) -> Vec<BulbGroup<'_>> {
148 let bulb_groups_cpp = maliput_sys::api::rules::ffi::TrafficLight_bulb_groups(self.traffic_light);
149 bulb_groups_cpp
150 .into_iter()
151 .map(|bg| BulbGroup {
152 bulb_group: unsafe { bg.bulb_group.as_ref().expect("") },
153 })
154 .collect::<Vec<BulbGroup>>()
155 }
156
157 /// Get a [BulbGroup] by its id.
158 ///
159 /// # Arguments
160 /// * `id` - The id of the [BulbGroup].
161 ///
162 /// # Returns
163 /// The [BulbGroup] with the given id.
164 /// If no [BulbGroup] is found with the given id, return None.
165 pub fn get_bulb_group(&self, id: &String) -> Option<BulbGroup<'_>> {
166 let bulb_group = maliput_sys::api::rules::ffi::TrafficLight_GetBulbGroup(self.traffic_light, id);
167 if bulb_group.is_null() {
168 return None;
169 }
170 Some(BulbGroup {
171 bulb_group: unsafe {
172 bulb_group
173 .as_ref()
174 .expect("Unable to get underlying bulb group pointer")
175 },
176 })
177 }
178
179 /// Get the lane IDs that this traffic light is physically relevant to.
180 ///
181 /// # Returns
182 /// A vector of lane ID strings.
183 pub fn related_lanes(&self) -> Vec<String> {
184 maliput_sys::api::rules::ffi::TrafficLight_related_lanes(self.traffic_light)
185 }
186}
187
188#[derive(Debug, Copy, Clone, PartialEq, Eq)]
189/// Defines the possible bulb colors.
190pub enum BulbColor {
191 Red,
192 Yellow,
193 Green,
194}
195
196#[derive(Debug, Copy, Clone, PartialEq, Eq)]
197/// Defines the possible bulb types.
198pub enum BulbType {
199 Round,
200 /// Arrow with a custom orientation specified by [Bulb::arrow_orientation_rad].
201 Arrow,
202 /// Predefined arrow pointing left.
203 ArrowLeft,
204 /// Predefined arrow pointing right.
205 ArrowRight,
206 /// Predefined arrow pointing up (forward).
207 ArrowUp,
208 /// Predefined arrow pointing upper-left.
209 ArrowUpperLeft,
210 /// Predefined arrow pointing upper-right.
211 ArrowUpperRight,
212 /// U-turn to the left.
213 UTurnLeft,
214 /// U-turn to the right.
215 UTurnRight,
216 /// Pedestrian walk signal.
217 Walk,
218 /// Pedestrian don't walk signal.
219 DontWalk,
220}
221
222#[derive(Debug, Copy, Clone, PartialEq, Eq)]
223/// Defines the possible bulb states.
224pub enum BulbState {
225 Off,
226 On,
227 Blinking,
228}
229
230/// Models a bulb within a bulb group.
231pub struct Bulb<'a> {
232 pub bulb: &'a maliput_sys::api::rules::ffi::Bulb,
233}
234
235impl Bulb<'_> {
236 /// Returns this Bulb instance's unique identifier.
237 ///
238 /// # Returns
239 /// A [UniqueBulbId] representing the unique identifier of the [Bulb].
240 pub fn unique_id(&self) -> UniqueBulbId {
241 UniqueBulbId {
242 unique_bulb_id: maliput_sys::api::rules::ffi::Bulb_unique_id(self.bulb),
243 }
244 }
245
246 /// Get the id of the [Bulb].
247 ///
248 /// # Returns
249 /// The id of the [Bulb].
250 pub fn id(&self) -> String {
251 maliput_sys::api::rules::ffi::Bulb_id(self.bulb)
252 }
253
254 /// Get the color of the [Bulb].
255 ///
256 /// # Returns
257 /// The [BulbColor].
258 pub fn color(&self) -> BulbColor {
259 let color = self.bulb.color();
260 match *color {
261 maliput_sys::api::rules::ffi::BulbColor::kRed => BulbColor::Red,
262 maliput_sys::api::rules::ffi::BulbColor::kYellow => BulbColor::Yellow,
263 maliput_sys::api::rules::ffi::BulbColor::kGreen => BulbColor::Green,
264 _ => panic!("Invalid bulb color"),
265 }
266 }
267
268 /// Get the type of the [Bulb].
269 ///
270 /// # Returns
271 /// The [BulbType].
272 pub fn bulb_type(&self) -> BulbType {
273 let bulb_type = maliput_sys::api::rules::ffi::Bulb_type(self.bulb);
274 match *bulb_type {
275 maliput_sys::api::rules::ffi::BulbType::kRound => BulbType::Round,
276 maliput_sys::api::rules::ffi::BulbType::kArrow => BulbType::Arrow,
277 maliput_sys::api::rules::ffi::BulbType::kArrowLeft => BulbType::ArrowLeft,
278 maliput_sys::api::rules::ffi::BulbType::kArrowRight => BulbType::ArrowRight,
279 maliput_sys::api::rules::ffi::BulbType::kArrowUp => BulbType::ArrowUp,
280 maliput_sys::api::rules::ffi::BulbType::kArrowUpperLeft => BulbType::ArrowUpperLeft,
281 maliput_sys::api::rules::ffi::BulbType::kArrowUpperRight => BulbType::ArrowUpperRight,
282 maliput_sys::api::rules::ffi::BulbType::kUTurnLeft => BulbType::UTurnLeft,
283 maliput_sys::api::rules::ffi::BulbType::kUTurnRight => BulbType::UTurnRight,
284 maliput_sys::api::rules::ffi::BulbType::kWalk => BulbType::Walk,
285 maliput_sys::api::rules::ffi::BulbType::kDontWalk => BulbType::DontWalk,
286 _ => panic!("Invalid bulb type"),
287 }
288 }
289
290 /// Get the position of the [Bulb] in the bulb group.
291 ///
292 /// # Returns
293 /// An [super::InertialPosition] representing the position of the [Bulb] in the bulb group.
294 pub fn position_bulb_group(&self) -> super::InertialPosition {
295 let inertial_position = maliput_sys::api::rules::ffi::Bulb_position_bulb_group(self.bulb);
296 super::InertialPosition { ip: inertial_position }
297 }
298
299 /// Get the orientation of the [Bulb] in the bulb group.
300 ///
301 /// # Returns
302 /// An [super::Rotation] representing the orientation of the [Bulb] in the bulb group.
303 pub fn orientation_bulb_group(&self) -> super::Rotation {
304 let rotation = maliput_sys::api::rules::ffi::Bulb_orientation_bulb_group(self.bulb);
305 super::Rotation { r: rotation }
306 }
307
308 /// Returns the arrow's orientation. Only applicable if [Bulb::bulb_type] returns [BulbType::Arrow].
309 ///
310 /// # Returns
311 /// An `Option<f64>` representing the orientation of the arrow in radians.
312 pub fn arrow_orientation_rad(&self) -> Option<f64> {
313 let arrow_orientation = maliput_sys::api::rules::ffi::Bulb_arrow_orientation_rad(self.bulb);
314 if arrow_orientation.is_null() {
315 return None;
316 }
317 Some(arrow_orientation.value)
318 }
319
320 /// Gets the possible states of the [Bulb].
321 ///
322 /// # Returns
323 /// A vector of [BulbState]s representing the possible states of the [Bulb].
324 pub fn states(&self) -> Vec<BulbState> {
325 let states_cpp = maliput_sys::api::rules::ffi::Bulb_states(self.bulb);
326 states_cpp
327 .into_iter()
328 .map(Bulb::_from_cpp_state_to_rust_state)
329 .collect::<Vec<BulbState>>()
330 }
331
332 /// Gets the default state of the [Bulb].
333 ///
334 /// # Returns
335 /// A [BulbState] representing the default state of the [Bulb].
336 pub fn get_default_state(&self) -> BulbState {
337 let default_state = self.bulb.GetDefaultState();
338 Bulb::_from_cpp_state_to_rust_state(&default_state)
339 }
340
341 /// Check if the given state is possible valid for the [Bulb].
342 ///
343 /// # Arguments
344 /// * `state` - The [BulbState] to check.
345 ///
346 /// # Returns
347 /// A boolean indicating whether the given state is valid for the [Bulb].
348 pub fn is_valid_state(&self, state: &BulbState) -> bool {
349 self.bulb.IsValidState(&Bulb::_from_rust_state_to_cpp_state(state))
350 }
351
352 /// Returns the bounding box of the bulb.
353 ///
354 /// # Returns
355 /// A tuple containing the minimum and maximum points of the bounding box.
356 pub fn bounding_box(&self) -> (crate::math::Vector3, crate::math::Vector3) {
357 let min = maliput_sys::api::rules::ffi::Bulb_bounding_box_min(self.bulb);
358 let max = maliput_sys::api::rules::ffi::Bulb_bounding_box_max(self.bulb);
359 (crate::math::Vector3 { v: min }, crate::math::Vector3 { v: max })
360 }
361
362 /// Returns the parent [BulbGroup] of the bulb.
363 ///
364 /// # Returns
365 /// The parent [BulbGroup] of the bulb.
366 /// If the bulb is not part of any group, return None.
367 pub fn bulb_group(&self) -> BulbGroup<'_> {
368 BulbGroup {
369 bulb_group: unsafe {
370 maliput_sys::api::rules::ffi::Bulb_bulb_group(self.bulb)
371 .as_ref()
372 .expect("Unable to get underlying bulb group pointer. The Bulb might not be part of any BulbGroup.")
373 },
374 }
375 }
376
377 /// Convert from the C++ BulbState to the Rust BulbState
378 /// It is expected to be used only internally.
379 ///
380 /// # Arguments
381 /// * `cpp_bulb_state` - The C++ BulbState
382 ///
383 /// # Returns
384 /// The Rust BulbState
385 ///
386 /// # Panics
387 /// If the C++ BulbState is invalid.
388 fn _from_cpp_state_to_rust_state(cpp_bulb_state: &maliput_sys::api::rules::ffi::BulbState) -> BulbState {
389 match *cpp_bulb_state {
390 maliput_sys::api::rules::ffi::BulbState::kOff => BulbState::Off,
391 maliput_sys::api::rules::ffi::BulbState::kOn => BulbState::On,
392 maliput_sys::api::rules::ffi::BulbState::kBlinking => BulbState::Blinking,
393 _ => panic!("Invalid bulb state"),
394 }
395 }
396
397 /// Convert from the Rust BulbState to the C++ BulbState
398 /// It is expected to be used only internally.
399 ///
400 /// # Arguments
401 /// * `rust_bulb_state` - The Rust BulbState
402 ///
403 /// # Returns
404 /// The C++ BulbState
405 fn _from_rust_state_to_cpp_state(rust_bulb_state: &BulbState) -> maliput_sys::api::rules::ffi::BulbState {
406 match rust_bulb_state {
407 BulbState::Off => maliput_sys::api::rules::ffi::BulbState::kOff,
408 BulbState::On => maliput_sys::api::rules::ffi::BulbState::kOn,
409 BulbState::Blinking => maliput_sys::api::rules::ffi::BulbState::kBlinking,
410 }
411 }
412}
413
414/// Models a group of bulbs within a traffic light. All of the bulbs within a
415/// group should share the same approximate orientation. However, this is not
416/// programmatically enforced.
417/// About the bulb group pose:
418/// - The position of the bulb group is defined as the linear offset of this bulb group's frame
419/// relative to the frame of the traffic light that contains it. The origin of
420/// this bulb group's frame should approximate the bulb group's CoM.
421/// - The orientation of the bulb group is defined as the rotational offset of this bulb
422/// group's frame relative to the frame of the traffic light that contains it.
423/// The +Z axis should align with the bulb group's "up" direction, and the +X
424/// axis should point in the direction that the bulb group is facing.
425/// Following a right-handed coordinate frame, the +Y axis should point left
426/// when facing the +X direction.
427pub struct BulbGroup<'a> {
428 pub bulb_group: &'a maliput_sys::api::rules::ffi::BulbGroup,
429}
430
431impl BulbGroup<'_> {
432 /// Returns this BulbGroup instance's unique identifier.
433 ///
434 /// # Returns
435 /// A [UniqueBulbGroupId] representing the unique identifier of the [BulbGroup].
436 pub fn unique_id(&self) -> UniqueBulbGroupId {
437 UniqueBulbGroupId {
438 unique_bulb_group_id: maliput_sys::api::rules::ffi::BulbGroup_unique_id(self.bulb_group),
439 }
440 }
441
442 /// Gets the id of the [BulbGroup].
443 ///
444 /// # Returns
445 /// The id of the [BulbGroup].
446 pub fn id(&self) -> String {
447 maliput_sys::api::rules::ffi::BulbGroup_id(self.bulb_group)
448 }
449
450 /// Gets the position of the [BulbGroup] in the traffic light.
451 ///
452 /// # Returns
453 /// An [super::InertialPosition] representing the position of the [BulbGroup] in the traffic light.
454 pub fn position_traffic_light(&self) -> super::InertialPosition {
455 let inertial_position = maliput_sys::api::rules::ffi::BulbGroup_position_traffic_light(self.bulb_group);
456 super::InertialPosition { ip: inertial_position }
457 }
458
459 /// Gets the orientation of the [BulbGroup] in the traffic light.
460 ///
461 /// # Returns
462 /// An [super::Rotation] representing the orientation of the [BulbGroup] in the traffic light.
463 pub fn orientation_traffic_light(&self) -> super::Rotation {
464 let rotation = maliput_sys::api::rules::ffi::BulbGroup_orientation_traffic_light(self.bulb_group);
465 super::Rotation { r: rotation }
466 }
467
468 /// Returns the bulbs in the bulb group.
469 ///
470 /// # Returns
471 /// A vector of [Bulb]s in the bulb group.
472 pub fn bulbs(&self) -> Vec<Bulb<'_>> {
473 let bulbs_cpp = maliput_sys::api::rules::ffi::BulbGroup_bulbs(self.bulb_group);
474 bulbs_cpp
475 .into_iter()
476 .map(|b| Bulb {
477 bulb: unsafe { b.bulb.as_ref().expect("") },
478 })
479 .collect::<Vec<Bulb>>()
480 }
481
482 /// Gets a [Bulb] by its id
483 ///
484 /// # Arguments
485 /// * `id` - The id of the [Bulb].
486 ///
487 /// # Returns
488 /// The [Bulb] with the given id.
489 /// If no [Bulb] is found with the given id, return None.
490 pub fn get_bulb(&self, id: &String) -> Option<Bulb<'_>> {
491 let bulb = maliput_sys::api::rules::ffi::BulbGroup_GetBulb(self.bulb_group, id);
492 if bulb.is_null() {
493 return None;
494 }
495 Some(Bulb {
496 bulb: unsafe { bulb.as_ref().expect("Unable to get underlying bulb pointer") },
497 })
498 }
499
500 /// Returns the parent [TrafficLight] of the bulb group.
501 ///
502 /// # Returns
503 /// The parent [TrafficLight] of the bulb group.
504 pub fn traffic_light(&self) -> TrafficLight<'_> {
505 TrafficLight {
506 traffic_light: unsafe {
507 maliput_sys::api::rules::ffi::BulbGroup_traffic_light(self.bulb_group)
508 .as_ref()
509 .expect("Unable to get underlying traffic light pointer. The BulbGroup might not be registered to a TrafficLight.")
510 },
511 }
512 }
513}
514
515/// Uniquely identifies a bulb in the `Inertial` space. This consists of the
516/// concatenation of the bulb's ID, the ID of the bulb group that contains the
517/// bulb, and the the ID of the traffic light that contains the bulb group.
518///
519/// String representation of this ID is:
520/// "`traffic_light_id().string()`-`bulb_group_id.string()`-`bulb_id.string()`"
521pub struct UniqueBulbId {
522 pub(crate) unique_bulb_id: cxx::UniquePtr<maliput_sys::api::rules::ffi::UniqueBulbId>,
523}
524
525impl UniqueBulbId {
526 /// Get the traffic light id of the [UniqueBulbId].
527 ///
528 /// # Returns
529 /// The traffic light id of the [UniqueBulbId].
530 pub fn traffic_light_id(&self) -> String {
531 maliput_sys::api::rules::ffi::UniqueBulbId_traffic_light_id(&self.unique_bulb_id)
532 }
533
534 /// Get the bulb group id of the [UniqueBulbId].
535 ///
536 /// # Returns
537 /// The bulb group id of the [UniqueBulbId].
538 pub fn bulb_group_id(&self) -> String {
539 maliput_sys::api::rules::ffi::UniqueBulbId_bulb_group_id(&self.unique_bulb_id)
540 }
541
542 /// Get the bulb id of the [UniqueBulbId].
543 ///
544 /// # Returns
545 /// The bulb id of the [UniqueBulbId].
546 pub fn bulb_id(&self) -> String {
547 maliput_sys::api::rules::ffi::UniqueBulbId_bulb_id(&self.unique_bulb_id)
548 }
549
550 /// Get the string representation of the [UniqueBulbId].
551 ///
552 /// # Returns
553 /// The string representation of the [UniqueBulbId].
554 pub fn string(&self) -> String {
555 self.unique_bulb_id.string().to_string()
556 }
557}
558
559/// Uniquely identifies a bulb group in the `Inertial` space. This consists of
560/// the concatenation of the ID of the bulb group, and the ID of the traffic
561/// light that contains the bulb group.
562///
563/// String representation of this ID is:
564/// "`traffic_light_id().string()`-`bulb_group_id.string()`"
565pub struct UniqueBulbGroupId {
566 unique_bulb_group_id: cxx::UniquePtr<maliput_sys::api::rules::ffi::UniqueBulbGroupId>,
567}
568
569impl UniqueBulbGroupId {
570 /// Get the traffic light id of the [UniqueBulbGroupId].
571 ///
572 /// # Returns
573 /// The traffic light id of the [UniqueBulbGroupId].
574 pub fn traffic_light_id(&self) -> String {
575 maliput_sys::api::rules::ffi::UniqueBulbGroupId_traffic_light_id(&self.unique_bulb_group_id)
576 }
577
578 /// Get the bulb group id of the [UniqueBulbGroupId].
579 ///
580 /// # Returns
581 /// The bulb group id of the [UniqueBulbGroupId].
582 pub fn bulb_group_id(&self) -> String {
583 maliput_sys::api::rules::ffi::UniqueBulbGroupId_bulb_group_id(&self.unique_bulb_group_id)
584 }
585
586 /// Get the string representation of the [UniqueBulbGroupId].
587 ///
588 /// # Returns
589 /// The string representation of the [UniqueBulbGroupId].
590 pub fn string(&self) -> String {
591 self.unique_bulb_group_id.string().to_string()
592 }
593}
594
595/// Interface for querying types of rules. It includes both Discrete and Range value rules. It
596/// provides a registry of the various rule types.
597pub struct RuleRegistry<'a> {
598 pub(super) rule_registry: &'a maliput_sys::api::rules::ffi::RuleRegistry,
599}
600
601/// Represents the rule values the [RuleRegistry] can contain by their Discrete or Range type.
602pub enum RuleValuesByType {
603 DiscreteValues(Vec<DiscreteValue>),
604 Ranges(Vec<Range>),
605}
606
607impl<'a> RuleRegistry<'a> {
608 /// Returns all [DiscreteValue] rule type IDs.
609 ///
610 /// # Returns
611 /// A vector of [String]s representing rule type IDs that correspond to different
612 /// [DiscreteValue]s in the [RuleRegistry].
613 pub fn get_discrete_value_rule_types(&self) -> Vec<String> {
614 let discrete_value_types =
615 maliput_sys::api::rules::ffi::RuleRegistry_DiscreteValueRuleTypes(self.rule_registry);
616 let discrete_value_types = discrete_value_types
617 .as_ref()
618 .expect("Unable to get underlying discrete value rule types pointer.");
619 discrete_value_types.iter().map(|dvt| dvt.type_id.clone()).collect()
620 }
621
622 /// Returns all [DiscreteValue]s corresponding to the specified `rule_type_id`.
623 ///
624 /// This methods works in tandem with [RuleRegistry::get_discrete_value_rule_types].
625 ///
626 /// # Arguments
627 /// * `rule_type_id` - The id of the rule type.
628 ///
629 /// # Returns
630 /// A vector of [DiscreteValue]s or [None] if the `rule_type_id` doesn't match any type id in
631 /// the [RuleRegistry].
632 pub fn discrete_values_by_type(&self, rule_type_id: String) -> Option<Vec<DiscreteValue>> {
633 let discrete_value_types =
634 maliput_sys::api::rules::ffi::RuleRegistry_DiscreteValueRuleTypes(self.rule_registry);
635 let discrete_value_types = discrete_value_types
636 .as_ref()
637 .expect("Unable to get underlying discrete value rule types pointer.");
638 discrete_value_types
639 .iter()
640 .find(|dvt| dvt.type_id == rule_type_id)
641 .map(|dvt| discrete_values_from_cxx(&dvt.values))
642 }
643
644 /// Returns all [Range] rule type IDs.
645 ///
646 /// # Returns
647 /// A vector of [String]s representing rule type IDs that correspond to different [Range]s in
648 /// the [RuleRegistry].
649 pub fn get_range_rule_types(&self) -> Vec<String> {
650 let range_value_types = maliput_sys::api::rules::ffi::RuleRegistry_RangeValueRuleTypes(self.rule_registry);
651 let range_value_types = range_value_types
652 .as_ref()
653 .expect("Unable to get underlying range rule types pointer.");
654 range_value_types.iter().map(|rvt| rvt.type_id.clone()).collect()
655 }
656
657 /// Returns all [Range]s corresponding to the specified `rule_type_id`.
658 ///
659 /// This methods works in tandem with [RuleRegistry::get_range_rule_types].
660 ///
661 /// # Arguments
662 /// * `rule_type_id` - The id of the rule type.
663 ///
664 /// # Returns
665 /// A vector of [Range]s or [None] if the `rule_type_id` doesn't match any type id in the
666 /// [RuleRegistry].
667 pub fn range_values_by_type(&self, rule_type_id: String) -> Option<Vec<Range>> {
668 let range_value_types = maliput_sys::api::rules::ffi::RuleRegistry_RangeValueRuleTypes(self.rule_registry);
669 let range_value_types = range_value_types
670 .as_ref()
671 .expect("Unable to get underlying range rule types pointer.");
672 range_value_types
673 .iter()
674 .find(|rvt| rvt.type_id == rule_type_id)
675 .map(|rvt| range_values_from_cxx(&rvt.values))
676 }
677
678 /// Returns all possible states for a given `rule_type_id`.
679 ///
680 /// # Arguments
681 /// * `rule_type_id` - The id of the rule type.
682 ///
683 /// # Returns
684 /// An `Option` containing a [RuleValuesByType] enum with either a vector of [Range]s or a
685 /// vector of [DiscreteValue]s. Returns `None` if the `rule_type_id` is not found.
686 pub fn get_possible_states_of_rule_type(&self, rule_type_id: String) -> Option<RuleValuesByType> {
687 if let Some(ranges) = self.range_values_by_type(rule_type_id.clone()) {
688 Some(RuleValuesByType::Ranges(ranges))
689 } else {
690 self.discrete_values_by_type(rule_type_id)
691 .map(RuleValuesByType::DiscreteValues)
692 }
693 }
694}
695
696/// Abstraction for holding the output of [RoadRulebook::rules()] and [RoadRulebook::find_rules()]
697/// methods.
698/// This struct contains a map of [DiscreteValueRule]s and [RangeValueRule]s.
699/// The keys of the map are the ids of the rules.
700/// The values of the map are the rules.
701pub struct QueryResults {
702 pub discrete_value_rules: std::collections::HashMap<String, DiscreteValueRule>,
703 pub range_value_rules: std::collections::HashMap<String, RangeValueRule>,
704}
705
706/// Interface for querying "rules of the road". This interface
707/// provides access to static information about a road network (i.e.,
708/// information determined prior to the beginning of a simulation). Some
709/// rule types may refer to additional dynamic information which will be
710/// provided by other interfaces.
711pub struct RoadRulebook<'a> {
712 pub(super) road_rulebook: &'a maliput_sys::api::rules::ffi::RoadRulebook,
713}
714
715impl<'a> RoadRulebook<'a> {
716 /// Returns the DiscreteValueRule with the specified `id`.
717 ///
718 /// # Arguments
719 /// * `rule_id` - The id of the rule.
720 ///
721 /// # Returns
722 /// The DiscreteValueRule with the given id or None if the id is not in the Rulebook.
723 pub fn get_discrete_value_rule(&self, rule_id: &String) -> Option<DiscreteValueRule> {
724 let discrete_value_rule =
725 maliput_sys::api::rules::ffi::RoadRulebook_GetDiscreteValueRule(self.road_rulebook, rule_id);
726 if discrete_value_rule.is_null() {
727 return None;
728 }
729 Some(DiscreteValueRule { discrete_value_rule })
730 }
731 /// Returns the RangeValueRule with the specified `id`.
732 ///
733 /// # Arguments
734 /// * `rule_id` - The id of the rule.
735 ///
736 /// # Returns
737 /// The RangeValueRule with the given id or None if the id is not in the Rulebook.
738 pub fn get_range_value_rule(&self, rule_id: &String) -> Option<RangeValueRule> {
739 let range_value_rule =
740 maliput_sys::api::rules::ffi::RoadRulebook_GetRangeValueRule(self.road_rulebook, rule_id);
741 if range_value_rule.is_null() {
742 return None;
743 }
744 Some(RangeValueRule { range_value_rule })
745 }
746
747 /// Returns all the rules in the road rulebook.
748 ///
749 /// # Returns
750 /// A [QueryResults] containing all the rules in the road rulebook.
751 pub fn rules(&self) -> QueryResults {
752 let query_results_cpp = maliput_sys::api::rules::ffi::RoadRulebook_Rules(self.road_rulebook);
753 let discrete_value_rules_id =
754 maliput_sys::api::rules::ffi::QueryResults_discrete_value_rules(&query_results_cpp);
755 let range_value_rules_id = maliput_sys::api::rules::ffi::QueryResults_range_value_rules(&query_results_cpp);
756 let mut dvr_map = std::collections::HashMap::new();
757 for rule_id in discrete_value_rules_id {
758 // It is okay to unwrap here since we are iterating valid IDs obtained above.
759 let rule = self.get_discrete_value_rule(&rule_id).unwrap();
760 dvr_map.insert(rule.id(), rule);
761 }
762 let mut rvr_map = std::collections::HashMap::new();
763 for rule_id in range_value_rules_id {
764 // It is okay to unwrap here since we are iterating valid IDs obtained above.
765 let rule = self.get_range_value_rule(&rule_id).unwrap();
766 rvr_map.insert(rule.id(), rule);
767 }
768 QueryResults {
769 discrete_value_rules: dvr_map,
770 range_value_rules: rvr_map,
771 }
772 }
773
774 /// Finds rules that apply to the given lane s ranges.
775 ///
776 /// # Arguments
777 /// * `ranges` - A vector of [super::LaneSRange]s to find rules for.
778 /// * `tolerance` - A tolerance value to use when finding rules.
779 ///
780 /// # Returns
781 /// A [QueryResults] containing the rules that apply to the given lane s ranges.
782 /// If no rules are found, an empty [QueryResults] is returned.
783 ///
784 /// # Errors
785 /// Returns a [MaliputError] if the underlying C++ function fails.
786 pub fn find_rules(&self, ranges: &Vec<super::LaneSRange>, tolerance: f64) -> Result<QueryResults, MaliputError> {
787 let mut ranges_cpp = Vec::new();
788 for range in ranges {
789 ranges_cpp.push(maliput_sys::api::rules::ffi::ConstLaneSRangeRef {
790 lane_s_range: &range.lane_s_range,
791 });
792 }
793 let query_results_cpp =
794 maliput_sys::api::rules::ffi::RoadRulebook_FindRules(self.road_rulebook, &ranges_cpp, tolerance)?;
795
796 let discrete_value_rules_id =
797 maliput_sys::api::rules::ffi::QueryResults_discrete_value_rules(&query_results_cpp);
798 let range_value_rules_id = maliput_sys::api::rules::ffi::QueryResults_range_value_rules(&query_results_cpp);
799 let mut dvr_map = std::collections::HashMap::new();
800 for rule_id in discrete_value_rules_id {
801 if let Some(rule) = self.get_discrete_value_rule(&rule_id) {
802 dvr_map.insert(rule.id(), rule);
803 }
804 }
805 let mut rvr_map = std::collections::HashMap::new();
806 for rule_id in range_value_rules_id {
807 if let Some(rule) = self.get_range_value_rule(&rule_id) {
808 rvr_map.insert(rule.id(), rule);
809 }
810 }
811 Ok(QueryResults {
812 discrete_value_rules: dvr_map,
813 range_value_rules: rvr_map,
814 })
815 }
816}
817
818/// # Rule
819///
820/// A Rule may have multiple states that affect agent behavior while it is
821/// driving through the rule's zone. The possible states of a Rule must be
822/// semantically coherent. The current state of a Rule is given by a
823/// [RuleStateProvider]. States can be:
824///
825/// - range based ([RangeValueRule]).
826/// - discrete ([DiscreteValueRule]).
827///
828/// # DiscreteValueRule
829///
830/// [DiscreteValue]s are defined by a string value.
831/// Semantics of this rule are based on _all_ possible values that this
832/// [DiscreteValueRule::type_id] could have (as specified by RuleRegistry::FindRuleByType()),
833/// not only the subset of values that a specific instance of this rule can
834/// be in.
835pub struct DiscreteValueRule {
836 discrete_value_rule: cxx::UniquePtr<maliput_sys::api::rules::ffi::DiscreteValueRule>,
837}
838
839impl DiscreteValueRule {
840 /// Returns the Id of the rule as a string.
841 ///
842 /// # Returns
843 /// The id of the rule.
844 pub fn id(&self) -> String {
845 maliput_sys::api::rules::ffi::DiscreteValueRule_id(&self.discrete_value_rule)
846 }
847 /// Returns the type of the rule as a string.
848 /// Example: "right-of-way-rule-type-id", "direction-usage-rule-type-id"
849 ///
850 /// # Returns
851 /// The type id of the rule.
852 pub fn type_id(&self) -> String {
853 maliput_sys::api::rules::ffi::DiscreteValueRule_type_id(&self.discrete_value_rule)
854 }
855 /// Returns a [super::LaneSRoute] that represents the zone that the rule applies to.
856 ///
857 /// # Returns
858 /// A [super::LaneSRoute] representing the zone of the rule.
859 pub fn zone(&self) -> super::LaneSRoute {
860 let lane_s_route = maliput_sys::api::rules::ffi::DiscreteValueRule_zone(&self.discrete_value_rule);
861 super::LaneSRoute { lane_s_route }
862 }
863 /// Returns the states of the rule.
864 ///
865 /// # Returns
866 /// A vector of [DiscreteValue]s representing the states of the rule.
867 /// If the rule has no states, an empty vector is returned.
868 pub fn states(&self) -> Vec<DiscreteValue> {
869 discrete_values_from_cxx(self.discrete_value_rule.states())
870 }
871}
872
873impl std::fmt::Debug for DiscreteValueRule {
874 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
875 write!(
876 f,
877 "DiscreteValueRule {{ id: {}, type_id: {}, zone: {:?}, states: {:?} }}",
878 self.id(),
879 self.type_id(),
880 self.zone(),
881 self.states()
882 )
883 }
884}
885
886/// Holds a `Rule` ID and the current state of that `Rule`.
887/// It is usually used as a return type for [super::Intersection::discrete_value_rule_states].
888pub struct DiscreteValueRuleState {
889 /// Rule ID.
890 pub rule_id: String,
891 /// Current state of the rule.
892 pub state: DiscreteValue,
893}
894
895/// # Rule
896///
897/// A Rule may have multiple states that affect agent behavior while it is
898/// driving through the rule's zone. The possible states of a Rule must be
899/// semantically coherent. The current state of a Rule is given by a
900/// [RuleStateProvider]. States can be:
901///
902/// - range based ([RangeValueRule]).
903/// - discrete ([DiscreteValueRule]).
904///
905/// # RangeValueRule
906///
907/// [Range]s describe a numeric range based rule.
908/// Ranges are closed and continuous, defined by a minimum and maximum quantity.
909/// When only one extreme is formally defined, the other should take a
910/// semantically correct value. For example, if a speed limit only specifies a
911/// maximum value, the minimum value is typically zero.
912pub struct RangeValueRule {
913 range_value_rule: cxx::UniquePtr<maliput_sys::api::rules::ffi::RangeValueRule>,
914}
915
916impl RangeValueRule {
917 /// Returns the Id of the rule as a string.
918 ///
919 /// # Returns
920 /// The id of the rule.
921 pub fn id(&self) -> String {
922 maliput_sys::api::rules::ffi::RangeValueRule_id(&self.range_value_rule)
923 }
924 /// Returns the type of the rule as a string.
925 /// Example: "right-of-way-rule-type-id", "direction-usage-rule-type-id"
926 ///
927 /// # Returns
928 /// The type id of the rule.
929 pub fn type_id(&self) -> String {
930 maliput_sys::api::rules::ffi::RangeValueRule_type_id(&self.range_value_rule)
931 }
932 /// Returns a [super::LaneSRoute] that represents the zone that the rule applies to.
933 ///
934 /// # Returns
935 /// A [super::LaneSRoute] representing the zone of the rule.
936 pub fn zone(&self) -> super::LaneSRoute {
937 let lane_s_route = maliput_sys::api::rules::ffi::RangeValueRule_zone(&self.range_value_rule);
938 super::LaneSRoute { lane_s_route }
939 }
940 /// Returns the states of the rule.
941 ///
942 /// # Returns
943 /// A vector of [Range]s representing the states of the rule.
944 /// If the rule has no states, an empty vector is returned.
945 pub fn states(&self) -> Vec<Range> {
946 range_values_from_cxx(self.range_value_rule.states())
947 }
948}
949
950/// Defines a Rule Type.
951///
952/// # RuleType
953///
954/// [RuleType]s provide a way of obtaining a rule type's string defined in
955/// maliput's backend. Since new rule types can be created in a custom manner,
956/// [RuleType] only holds the most common types which are already defined in
957/// the backend.
958#[derive(Display, IntoStaticStr)]
959pub enum RuleType {
960 #[strum(serialize = "Direction-Usage Rule Type")]
961 DirectionUsage,
962 #[strum(serialize = "Right-Of-Way Rule Type")]
963 RightOfWay,
964 #[strum(serialize = "Vehicle-Stop-In-Zone-Behavior Rule Type")]
965 VehicleStopInZoneBehavior,
966 #[strum(serialize = "Speed-Limit Rule Type")]
967 SpeedLimit,
968}
969
970impl RuleType {
971 /// Gets the Rule ID for the [RuleType] and `lane_id`.
972 ///
973 /// # Arguments
974 /// - `lane_id` - The lane ID to get the rule ID from.
975 ///
976 /// # Returns
977 /// A rule ID formatted the way the backend defines it.
978 pub fn get_rule_id(&self, lane_id: &str) -> String {
979 // We rely on maliput_malidrive which define the rule id as:
980 // "<rule_type>/<lane_id>"
981 self.to_string() + "/" + lane_id
982 }
983}
984
985/// Defines a base state for a rule.
986///
987/// # RuleStateBase
988///
989/// - `severity` - The severity of the rule state.
990/// - `related_rules` - A map of related rules. The key is the group name and the value is a vector of rule ids.
991/// - `related_unique_ids` - A map of related unique ids. The key is the group name and the value is a vector of unique ids.
992///
993/// See [DiscreteValueRule] and [RangeValueRule] for more information.
994pub struct RuleStateBase {
995 /// Severity of the rule's state. A non-negative quantity that specifies the
996 /// level of enforcement. The smaller it is, the more strictly the rule is
997 /// enforced. Each rule type can define its own set of severity level
998 /// semantics.
999 severity: i32,
1000 related_rules: cxx::UniquePtr<cxx::CxxVector<maliput_sys::api::rules::ffi::RelatedRule>>,
1001 related_unique_ids: cxx::UniquePtr<cxx::CxxVector<maliput_sys::api::rules::ffi::RelatedUniqueId>>,
1002}
1003
1004/// A trait representing a possible state of a `Rule`.
1005///
1006/// A `Rule` can have multiple states that affect agent behavior. This trait
1007/// provides a common interface for accessing the properties shared by all
1008/// rule states, such as severity and related rules.
1009///
1010/// This trait is implemented by specific state types like [`DiscreteValue`]
1011/// and [`Range`].
1012///
1013/// # Implementors
1014///
1015/// When implementing this trait, you must provide an implementation for the
1016/// [`get_rule_state()`] method, which gives access to the underlying
1017/// [`RuleStateBase`] data. The other methods have default implementations.
1018pub trait RuleState {
1019 /// Gets the underlying [`RuleStateBase`] that contains common state properties.
1020 ///
1021 /// # Returns
1022 /// A reference to the [`RuleStateBase`] that contains the severity, related rules,
1023 /// and related unique ids for the rule state.
1024 fn get_rule_state(&self) -> &RuleStateBase;
1025
1026 /// Returns the severity of the rule state.
1027 ///
1028 /// # Returns
1029 /// An `i32` representing the severity of the rule state.
1030 /// The severity is a numeric value that indicates the importance or urgency of the rule. The lower the value, the more strictly the rule is enforced.
1031 fn severity(&self) -> i32 {
1032 self.get_rule_state().severity
1033 }
1034
1035 /// Returns a map of related rules ids. The key is the group name and the value is a vector of rule ids.
1036 ///
1037 /// # Returns
1038 /// A map of related rules where the key is the group name and the value is a vector of rule ids.
1039 fn related_rules(&self) -> std::collections::HashMap<&String, &Vec<String>> {
1040 self.get_rule_state()
1041 .related_rules
1042 .iter()
1043 .map(|rr| (&rr.group_name, &rr.rule_ids))
1044 .collect::<std::collections::HashMap<&String, &Vec<String>>>()
1045 }
1046 /// Returns a map of related unique ids. The key is the group name and the value is a vector of unique ids.
1047 ///
1048 /// # Returns
1049 /// A map of related unique ids where the key is the group name and the value is a vector of unique ids.
1050 fn related_unique_ids(&self) -> std::collections::HashMap<&String, &Vec<String>> {
1051 self.get_rule_state()
1052 .related_unique_ids
1053 .iter()
1054 .map(|rui| (&rui.group_name, &rui.unique_ids))
1055 .collect::<std::collections::HashMap<&String, &Vec<String>>>()
1056 }
1057}
1058
1059/// Defines a discrete value for a [DiscreteValueRule].
1060/// It extends the [RuleStateBase] with the value of the discrete value.
1061pub struct DiscreteValue {
1062 rule_state: RuleStateBase,
1063 value: String,
1064}
1065
1066impl RuleState for DiscreteValue {
1067 fn get_rule_state(&self) -> &RuleStateBase {
1068 &self.rule_state
1069 }
1070}
1071
1072impl DiscreteValue {
1073 /// Returns the value of the discrete value.
1074 pub fn value(&self) -> &String {
1075 &self.value
1076 }
1077}
1078
1079impl std::fmt::Debug for DiscreteValue {
1080 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1081 write!(
1082 f,
1083 "DiscreteValue {{ value: {}, severity: {}, related_rules: {:?}, related_unique_ids: {:?} }}",
1084 self.value(),
1085 self.severity(),
1086 self.related_rules(),
1087 self.related_unique_ids()
1088 )
1089 }
1090}
1091
1092/// Defines a range value for a [RangeValueRule].
1093/// It extends the [RuleStateBase] with the description, and min and max values of the range.
1094pub struct Range {
1095 rule_state: RuleStateBase,
1096 description: String,
1097 min: f64,
1098 max: f64,
1099}
1100
1101impl RuleState for Range {
1102 fn get_rule_state(&self) -> &RuleStateBase {
1103 &self.rule_state
1104 }
1105}
1106
1107impl Range {
1108 /// Returns the description of the range value.
1109 pub fn description(&self) -> &String {
1110 &self.description
1111 }
1112 /// Returns the minimum value of the range.
1113 pub fn min(&self) -> f64 {
1114 self.min
1115 }
1116 /// Returns the maximum value of the range.
1117 pub fn max(&self) -> f64 {
1118 self.max
1119 }
1120}
1121
1122/// Defines a phase in a traffic rule system.
1123///
1124/// A phase represents a specific state or configuration of traffic signals
1125/// and semantic rules within a traffic control system. Each phase has a unique
1126/// identifier and may include various traffic signal states and rule configurations
1127/// that dictate how traffic should behave during that phase.
1128pub struct Phase {
1129 phase: cxx::UniquePtr<maliput_sys::api::rules::ffi::Phase>,
1130}
1131
1132impl Phase {
1133 /// Gets the id of the [Phase].
1134 ///
1135 /// # Returns
1136 /// The id of the [Phase].
1137 pub fn id(&self) -> String {
1138 maliput_sys::api::rules::ffi::Phase_id(&self.phase)
1139 }
1140
1141 /// Gets the states of all discrete value rules for this phase.
1142 ///
1143 /// # Returns
1144 /// A `HashMap` where the key is the rule ID as a [String] and the value is the
1145 /// [DiscreteValue] state of that rule.
1146 pub fn discrete_value_rule_states(&self) -> HashMap<String, DiscreteValue> {
1147 let rule_states = maliput_sys::api::rules::ffi::Phase_discrete_value_rule_states(&self.phase);
1148 rule_states
1149 .iter()
1150 .map(|state| {
1151 (
1152 state.rule_id.clone(),
1153 discrete_value_from_discrete_value_cxx(&state.state),
1154 )
1155 })
1156 .collect()
1157 }
1158
1159 /// Obtains all [UniqueBulbId]s in the [Phase].
1160 ///
1161 /// # Returns
1162 /// A vector of [UniqueBulbId].
1163 pub fn unique_bulb_ids(&self) -> Vec<UniqueBulbId> {
1164 let unique_bulb_ids = maliput_sys::api::rules::ffi::Phase_unique_bulb_ids(&self.phase);
1165 unique_bulb_ids
1166 .iter()
1167 .map(|bulb_id| UniqueBulbId {
1168 unique_bulb_id: maliput_sys::api::rules::ffi::ptr_from_unique_bulb_id(bulb_id),
1169 })
1170 .collect()
1171 }
1172
1173 /// Returns the [BulbState] corresponding to a `bulb_id`.
1174 ///
1175 /// # Arguments
1176 /// * `unique_bulb_id` - The [UniqueBulbId] to get the [BulbState] from.
1177 ///
1178 /// # Returns
1179 /// The [BulbState] the `unique_bulb_id` is in, or [None] if the [UniqueBulbId] is not in this [Phase].
1180 pub fn bulb_state(&self, unique_bulb_id: &UniqueBulbId) -> Option<BulbState> {
1181 let bulb_state = maliput_sys::api::rules::ffi::Phase_bulb_state(&self.phase, &unique_bulb_id.unique_bulb_id);
1182 if bulb_state.is_null() {
1183 return None;
1184 }
1185 Some(match *bulb_state {
1186 maliput_sys::api::rules::ffi::BulbState::kOff => BulbState::Off,
1187 maliput_sys::api::rules::ffi::BulbState::kOn => BulbState::On,
1188 maliput_sys::api::rules::ffi::BulbState::kBlinking => BulbState::Blinking,
1189 _ => return None,
1190 })
1191 }
1192}
1193
1194/// Defines a phase that comes after another [Phase].
1195/// Used as a return type by:
1196/// - [PhaseRing::get_next_phases].
1197pub struct NextPhase {
1198 /// The next phase.
1199 pub next_phase: Phase,
1200 /// The default time before transitioning to the next phase. This is
1201 /// relative to when the current phase began. It is just a recommendation,
1202 /// the actual duration is determined by the PhaseProvider and may depend on
1203 /// events like a vehicle arriving at a left-turn lane or a pedestrian
1204 /// hitting a crosswalk button.
1205 pub duration_until: Option<f64>,
1206}
1207
1208/// Defines a ring of phases in a traffic rule system.
1209///
1210/// A phase ring represents a sequence of phases that a traffic control system
1211/// cycles through.
1212pub struct PhaseRing {
1213 phase_ring: cxx::UniquePtr<maliput_sys::api::rules::ffi::PhaseRing>,
1214}
1215
1216impl PhaseRing {
1217 /// Gets the id of the [PhaseRing].
1218 ///
1219 /// # Returns
1220 /// The id of the [PhaseRing].
1221 pub fn id(&self) -> String {
1222 maliput_sys::api::rules::ffi::PhaseRing_id(&self.phase_ring)
1223 }
1224
1225 /// Gets a [Phase] by its id
1226 ///
1227 /// # Arguments
1228 /// * `id` - The id of the [Phase].
1229 /// # Returns
1230 /// The [Phase] with the given id.
1231 /// If no [Phase] is found with the given id, return None.
1232 pub fn get_phase(&self, id: &String) -> Option<Phase> {
1233 let phase = maliput_sys::api::rules::ffi::PhaseRing_GetPhase(&self.phase_ring, id);
1234 if phase.is_null() {
1235 return None;
1236 }
1237 Some(Phase { phase })
1238 }
1239
1240 /// Returns the ids of all Phases in the PhaseRing.
1241 ///
1242 /// # Returns
1243 /// A vector of strings representing the ids of all Phases in the PhaseRing.
1244 pub fn phases(&self) -> Vec<String> {
1245 maliput_sys::api::rules::ffi::PhaseRing_phases_ids(&self.phase_ring)
1246 }
1247
1248 /// Returns the next phases for a given phase `id`.
1249 ///
1250 /// # Arguments
1251 /// * `id` - The id of the phase to get the next phases from.
1252 ///
1253 /// # Returns
1254 /// A `Result` containing a vector of [NextPhase]s.
1255 ///
1256 /// # Errors
1257 /// Returns a [MaliputError] if the provided `id` is not found in the [PhaseRing].
1258 pub fn get_next_phases(&self, id: &String) -> Result<Vec<NextPhase>, MaliputError> {
1259 let next_phases = maliput_sys::api::rules::ffi::PhaseRing_GetNextPhases(&self.phase_ring, id)?;
1260 Ok(next_phases
1261 .iter()
1262 .map(|np| NextPhase {
1263 next_phase: Phase {
1264 phase: maliput_sys::api::rules::ffi::PhaseRing_GetPhase(&self.phase_ring, &np.phase_id),
1265 },
1266 duration_until: if np.duration_until.is_null() {
1267 None
1268 } else {
1269 Some(np.duration_until.value)
1270 },
1271 })
1272 .collect())
1273 }
1274}
1275
1276/// Defines a book of phase rings in a traffic rule system.
1277pub struct PhaseRingBook<'a> {
1278 pub(super) phase_ring_book: &'a maliput_sys::api::rules::ffi::PhaseRingBook,
1279}
1280
1281impl<'a> PhaseRingBook<'a> {
1282 /// Returns the ids of all PhaseRings in the PhaseRingBook.
1283 ///
1284 /// # Returns
1285 /// A vector of strings representing the ids of all PhaseRings in the PhaseRingBook.
1286 pub fn get_phase_rings_ids(&self) -> Vec<String> {
1287 maliput_sys::api::rules::ffi::PhaseRingBook_GetPhaseRingsId(self.phase_ring_book)
1288 }
1289
1290 /// Returns the PhaseRing with the specified `id`.
1291 ///
1292 /// # Arguments
1293 /// * `phase_ring_id` - The id of the phase ring.
1294 ///
1295 /// # Returns
1296 /// The PhaseRing with the given id or None if the id is not in the PhaseRingBook.
1297 pub fn get_phase_ring(&self, phase_ring_id: &String) -> Option<PhaseRing> {
1298 let phase_ring = maliput_sys::api::rules::ffi::PhaseRingBook_GetPhaseRing(self.phase_ring_book, phase_ring_id);
1299 if phase_ring.is_null() {
1300 return None;
1301 }
1302 Some(PhaseRing { phase_ring })
1303 }
1304
1305 /// Finds the [PhaseRing] that contains the rule with the specified `rule_id`.
1306 ///
1307 /// # Arguments
1308 /// * `rule_id` - The id of the rule.
1309 ///
1310 /// # Returns
1311 /// The [PhaseRing] that contains the rule with the given id or `None` if no [PhaseRing] is found.
1312 pub fn find_phase_ring(&self, rule_id: &String) -> Option<PhaseRing> {
1313 let phase_ring = maliput_sys::api::rules::ffi::PhaseRingBook_FindPhaseRing(self.phase_ring_book, rule_id);
1314 if phase_ring.is_null() {
1315 return None;
1316 }
1317 Some(PhaseRing { phase_ring })
1318 }
1319}
1320
1321/// Defines a next state of a generic type.
1322pub struct NextState<T> {
1323 /// The next state.
1324 pub next_state: T,
1325 /// The default time before transitioning to the next state. This is
1326 /// relative to when the current state began. It is just a recommendation,
1327 /// the actual duration is determined by the StateProvider and may depend on
1328 /// events like a vehicle arriving at a left-turn lane or a pedestrian
1329 /// hitting a crosswalk button.
1330 pub duration_until: Option<f64>,
1331}
1332
1333/// Holds the current and possible next state of a system.
1334/// It is usually returned by the different types of state providers.
1335pub struct StateProviderQuery<T> {
1336 /// The current state.
1337 pub state: T,
1338 /// The next state.
1339 pub next: Option<NextState<T>>,
1340}
1341
1342/// Alias for the [StateProviderQuery] returned by [PhaseProvider::get_phase].
1343pub type PhaseStateProviderQuery = StateProviderQuery<String>;
1344
1345/// Defines a phase provider.
1346///
1347/// A phase provider is able to get the current phase from a phase-based system.
1348pub struct PhaseProvider<'a> {
1349 pub(super) phase_provider: &'a maliput_sys::api::rules::ffi::PhaseProvider,
1350}
1351
1352impl<'a> PhaseProvider<'a> {
1353 /// Returns the [PhaseStateProviderQuery] for the specified `phase_ring_id`.
1354 ///
1355 /// The states are represented with Strings containing the IDs of each [Phase].
1356 ///
1357 /// # Arguments
1358 /// * `phase_ring_id` - The id of the phase ring.
1359 ///
1360 /// # Returns
1361 /// An `Option` containing the [PhaseStateProviderQuery] for the given `phase_ring_id`.
1362 /// Returns `None` if no phase provider is found for the given id.
1363 pub fn get_phase(&self, phase_ring_id: &String) -> Option<PhaseStateProviderQuery> {
1364 let phase_state = maliput_sys::api::rules::ffi::PhaseProvider_GetPhase(self.phase_provider, phase_ring_id);
1365 if phase_state.is_null() {
1366 return None;
1367 }
1368
1369 let next_state = maliput_sys::api::rules::ffi::PhaseStateProvider_next(&phase_state);
1370 let next_phase = if next_state.is_null() {
1371 None
1372 } else {
1373 Some(NextState {
1374 next_state: next_state.phase_id.clone(),
1375 duration_until: if next_state.duration_until.is_null() {
1376 None
1377 } else {
1378 Some(next_state.duration_until.value)
1379 },
1380 })
1381 };
1382
1383 Some(StateProviderQuery {
1384 state: maliput_sys::api::rules::ffi::PhaseStateProvider_state(&phase_state),
1385 next: next_phase,
1386 })
1387 }
1388}
1389
1390/// Provides the dynamic state of [DiscreteValueRule]s.
1391///
1392/// While a [RoadRulebook] provides the static definitions of rules, a
1393/// `DiscreteValueRuleStateProvider` provides the current state of those rules
1394/// at runtime. This allows for querying what state a rule is currently in,
1395/// which is essential for dynamic systems where rule states can change over
1396/// time (e.g., traffic light phases changing).
1397pub struct DiscreteValueRuleStateProvider<'a> {
1398 pub(super) state_provider: &'a maliput_sys::api::rules::ffi::DiscreteValueRuleStateProvider,
1399}
1400
1401impl<'a> DiscreteValueRuleStateProvider<'a> {
1402 /// Gets a state from the provider based on it's `rule_id`.
1403 ///
1404 /// # Arguments
1405 /// * `rule_id` - A Rule ID.
1406 ///
1407 /// # Returns
1408 /// An Option containing the [StateProviderQuery] with a [DiscreteValue] if the `rule_id` matches with any rule.
1409 /// Otherwise, None is returned.
1410 pub fn get_state_by_rule_id(&self, rule_id: &String) -> Option<StateProviderQuery<DiscreteValue>> {
1411 let query_state =
1412 maliput_sys::api::rules::ffi::DiscreteValueRuleStateProvider_GetStateById(self.state_provider, rule_id);
1413 Self::next_state_from_cxx_query(query_state)
1414 }
1415
1416 /// Gets a state from the provider if there is a `rule_type` in the received `road_position`.
1417 ///
1418 /// # Arguments
1419 /// * `road_position` - A position in the road geometry.
1420 /// * `rule_type` - A Rule Type.
1421 /// * `tolerance` - The tolerance in which to look for the Rule of type `rule_type` around the `road_position`.
1422 ///
1423 /// # Returns
1424 /// An Option containing the [StateProviderQuery] with a [DiscreteValue] if `rule_type` matches with any rule's type near `road_position`.
1425 /// Otherwise, None is returned.
1426 pub fn get_state_by_rule_type(
1427 &self,
1428 road_position: &RoadPosition,
1429 rule_type: RuleType,
1430 tolerance: f64,
1431 ) -> Option<StateProviderQuery<DiscreteValue>> {
1432 let query_state = maliput_sys::api::rules::ffi::DiscreteValueRuleStateProvider_GetStateByType(
1433 self.state_provider,
1434 &road_position.rp,
1435 &rule_type.to_string(),
1436 tolerance,
1437 );
1438 Self::next_state_from_cxx_query(query_state)
1439 }
1440
1441 // Internal helper to avoid code duplication.
1442 fn next_state_from_cxx_query(
1443 query_state: cxx::UniquePtr<maliput_sys::api::rules::ffi::DiscreteValueRuleStateProviderQuery>,
1444 ) -> Option<StateProviderQuery<DiscreteValue>> {
1445 if query_state.is_null() {
1446 return None;
1447 }
1448 let next_state = maliput_sys::api::rules::ffi::DiscreteValueRuleStateProviderQuery_next(&query_state);
1449 Some(StateProviderQuery {
1450 state: discrete_value_from_discrete_value_cxx(
1451 &maliput_sys::api::rules::ffi::DiscreteValueRuleStateProviderQuery_state(&query_state),
1452 ),
1453 next: if next_state.is_null() {
1454 None
1455 } else {
1456 Some(NextState {
1457 next_state: discrete_value_from_discrete_value_cxx(&next_state.state),
1458 duration_until: if next_state.duration_until.is_null() {
1459 None
1460 } else {
1461 Some(next_state.duration_until.value)
1462 },
1463 })
1464 },
1465 })
1466 }
1467}
1468
1469/// Provides the dynamic state of [RangeValueRule]s.
1470///
1471/// While a [RoadRulebook] provides the static definitions of rules, a
1472/// `RangeValueRuleStateProvider` provides the current state of those rules
1473/// at runtime. This allows for querying what state a rule is currently in,
1474/// which is essential for dynamic systems where rule states can change over
1475/// time (e.g., variable speed limits based on types of roads).
1476pub struct RangeValueRuleStateProvider<'a> {
1477 pub(super) state_provider: &'a maliput_sys::api::rules::ffi::RangeValueRuleStateProvider,
1478}
1479
1480impl<'a> RangeValueRuleStateProvider<'a> {
1481 /// Gets a state from the provider based on it's `rule_id`.
1482 ///
1483 /// # Arguments
1484 /// * `rule_id` - A Rule ID.
1485 ///
1486 /// # Returns
1487 /// An Option containing the [StateProviderQuery] with a [Range] if the `rule_id` matches with any rule.
1488 /// Otherwise, None is returned.
1489 pub fn get_state_by_rule_id(&self, rule_id: &String) -> Option<StateProviderQuery<Range>> {
1490 let query_state =
1491 maliput_sys::api::rules::ffi::RangeValueRuleStateProvider_GetStateById(self.state_provider, rule_id);
1492 Self::next_state_from_cxx_query(query_state)
1493 }
1494
1495 /// Gets a state from the provider if there is a `rule_type` in the received `road_position`.
1496 ///
1497 /// # Arguments
1498 /// * `road_position` - A position in the road geometry.
1499 /// * `rule_type` - A Rule Type.
1500 /// * `tolerance` - The tolerance in which to look for the Rule of type `rule_type` around the `road_position`.
1501 ///
1502 /// # Returns
1503 /// An Option containing the [StateProviderQuery] with a [Range] if `rule_type` matches with any rule's type near `road_position`.
1504 /// Otherwise, None is returned.
1505 pub fn get_state_by_rule_type(
1506 &self,
1507 road_position: &RoadPosition,
1508 rule_type: RuleType,
1509 tolerance: f64,
1510 ) -> Option<StateProviderQuery<Range>> {
1511 let query_state = maliput_sys::api::rules::ffi::RangeValueRuleStateProvider_GetStateByType(
1512 self.state_provider,
1513 &road_position.rp,
1514 &rule_type.to_string(),
1515 tolerance,
1516 );
1517 Self::next_state_from_cxx_query(query_state)
1518 }
1519
1520 // Internal helper to avoid code duplication.
1521 fn next_state_from_cxx_query(
1522 query_state: cxx::UniquePtr<maliput_sys::api::rules::ffi::RangeValueRuleStateProviderQuery>,
1523 ) -> Option<StateProviderQuery<Range>> {
1524 if query_state.is_null() {
1525 return None;
1526 }
1527 let next_state = maliput_sys::api::rules::ffi::RangeValueRuleStateProviderQuery_next(&query_state);
1528 Some(StateProviderQuery {
1529 state: range_value_from_range_value_cxx(
1530 &maliput_sys::api::rules::ffi::RangeValueRuleStateProviderQuery_state(&query_state),
1531 ),
1532 next: if next_state.is_null() {
1533 None
1534 } else {
1535 Some(NextState {
1536 next_state: range_value_from_range_value_cxx(&next_state.state),
1537 duration_until: if next_state.duration_until.is_null() {
1538 None
1539 } else {
1540 Some(next_state.duration_until.value)
1541 },
1542 })
1543 },
1544 })
1545 }
1546}
1547
1548// Auxiliary method to create a [Vec<Range>] from a [cxx::Vector<RangeValueRuleRange>].
1549fn range_values_from_cxx(
1550 range_values_cxx: &cxx::Vector<maliput_sys::api::rules::ffi::RangeValueRuleRange>,
1551) -> Vec<Range> {
1552 range_values_cxx
1553 .iter()
1554 .map(|range| Range {
1555 rule_state: RuleStateBase {
1556 severity: maliput_sys::api::rules::ffi::RangeValueRuleRange_severity(range),
1557 related_rules: maliput_sys::api::rules::ffi::RangeValueRuleRange_related_rules(range),
1558 related_unique_ids: maliput_sys::api::rules::ffi::RangeValueRuleRange_related_unique_ids(range),
1559 },
1560 description: maliput_sys::api::rules::ffi::RangeValueRuleRange_description(range),
1561 min: maliput_sys::api::rules::ffi::RangeValueRuleRange_min(range),
1562 max: maliput_sys::api::rules::ffi::RangeValueRuleRange_max(range),
1563 })
1564 .collect()
1565}
1566
1567// Auxiliary method to create a [Vec<DiscreteValue>] from a [cxx::Vector<DiscreteValueRuleDiscreteValue>].
1568fn discrete_values_from_cxx(
1569 discrete_values_cxx: &cxx::Vector<maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue>,
1570) -> Vec<DiscreteValue> {
1571 discrete_values_cxx
1572 .iter()
1573 .map(discrete_value_from_discrete_value_cxx)
1574 .collect()
1575}
1576
1577// Auxiliary method to create a [DiscreteValue] from a [maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue].
1578pub(crate) fn discrete_value_from_discrete_value_cxx(
1579 discrete_value: &maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue,
1580) -> DiscreteValue {
1581 DiscreteValue {
1582 rule_state: RuleStateBase {
1583 severity: maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue_severity(discrete_value),
1584 related_rules: maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue_related_rules(discrete_value),
1585 related_unique_ids: maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue_related_unique_ids(
1586 discrete_value,
1587 ),
1588 },
1589 value: maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue_value(discrete_value),
1590 }
1591}
1592
1593// Auxiliary method to create a [Range] from a [maliput_sys::api::rules::ffi::RangeValueRuleRange].
1594fn range_value_from_range_value_cxx(range: &maliput_sys::api::rules::ffi::RangeValueRuleRange) -> Range {
1595 Range {
1596 rule_state: RuleStateBase {
1597 severity: maliput_sys::api::rules::ffi::RangeValueRuleRange_severity(range),
1598 related_rules: maliput_sys::api::rules::ffi::RangeValueRuleRange_related_rules(range),
1599 related_unique_ids: maliput_sys::api::rules::ffi::RangeValueRuleRange_related_unique_ids(range),
1600 },
1601 description: maliput_sys::api::rules::ffi::RangeValueRuleRange_description(range),
1602 min: maliput_sys::api::rules::ffi::RangeValueRuleRange_min(range),
1603 max: maliput_sys::api::rules::ffi::RangeValueRuleRange_max(range),
1604 }
1605}
1606
1607#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1608/// Defines the possible traffic sign types.
1609pub enum TrafficSignType {
1610 Stop,
1611 Yield,
1612 SpeedLimit,
1613 NoEntry,
1614 OneWay,
1615 PedestrianCrossing,
1616 NoLeftTurn,
1617 NoRightTurn,
1618 NoUTurn,
1619 SchoolZone,
1620 Construction,
1621 RailroadCrossing,
1622 NoOvertaking,
1623 Unknown,
1624}
1625
1626fn traffic_sign_type_from_cpp(sign_type: &maliput_sys::api::rules::ffi::TrafficSignType) -> TrafficSignType {
1627 match *sign_type {
1628 maliput_sys::api::rules::ffi::TrafficSignType::kStop => TrafficSignType::Stop,
1629 maliput_sys::api::rules::ffi::TrafficSignType::kYield => TrafficSignType::Yield,
1630 maliput_sys::api::rules::ffi::TrafficSignType::kSpeedLimit => TrafficSignType::SpeedLimit,
1631 maliput_sys::api::rules::ffi::TrafficSignType::kNoEntry => TrafficSignType::NoEntry,
1632 maliput_sys::api::rules::ffi::TrafficSignType::kOneWay => TrafficSignType::OneWay,
1633 maliput_sys::api::rules::ffi::TrafficSignType::kPedestrianCrossing => TrafficSignType::PedestrianCrossing,
1634 maliput_sys::api::rules::ffi::TrafficSignType::kNoLeftTurn => TrafficSignType::NoLeftTurn,
1635 maliput_sys::api::rules::ffi::TrafficSignType::kNoRightTurn => TrafficSignType::NoRightTurn,
1636 maliput_sys::api::rules::ffi::TrafficSignType::kNoUTurn => TrafficSignType::NoUTurn,
1637 maliput_sys::api::rules::ffi::TrafficSignType::kSchoolZone => TrafficSignType::SchoolZone,
1638 maliput_sys::api::rules::ffi::TrafficSignType::kConstruction => TrafficSignType::Construction,
1639 maliput_sys::api::rules::ffi::TrafficSignType::kRailroadCrossing => TrafficSignType::RailroadCrossing,
1640 maliput_sys::api::rules::ffi::TrafficSignType::kNoOvertaking => TrafficSignType::NoOvertaking,
1641 _ => TrafficSignType::Unknown,
1642 }
1643}
1644
1645fn traffic_sign_type_to_cpp(sign_type: &TrafficSignType) -> maliput_sys::api::rules::ffi::TrafficSignType {
1646 match sign_type {
1647 TrafficSignType::Stop => maliput_sys::api::rules::ffi::TrafficSignType::kStop,
1648 TrafficSignType::Yield => maliput_sys::api::rules::ffi::TrafficSignType::kYield,
1649 TrafficSignType::SpeedLimit => maliput_sys::api::rules::ffi::TrafficSignType::kSpeedLimit,
1650 TrafficSignType::NoEntry => maliput_sys::api::rules::ffi::TrafficSignType::kNoEntry,
1651 TrafficSignType::OneWay => maliput_sys::api::rules::ffi::TrafficSignType::kOneWay,
1652 TrafficSignType::PedestrianCrossing => maliput_sys::api::rules::ffi::TrafficSignType::kPedestrianCrossing,
1653 TrafficSignType::NoLeftTurn => maliput_sys::api::rules::ffi::TrafficSignType::kNoLeftTurn,
1654 TrafficSignType::NoRightTurn => maliput_sys::api::rules::ffi::TrafficSignType::kNoRightTurn,
1655 TrafficSignType::NoUTurn => maliput_sys::api::rules::ffi::TrafficSignType::kNoUTurn,
1656 TrafficSignType::SchoolZone => maliput_sys::api::rules::ffi::TrafficSignType::kSchoolZone,
1657 TrafficSignType::Construction => maliput_sys::api::rules::ffi::TrafficSignType::kConstruction,
1658 TrafficSignType::RailroadCrossing => maliput_sys::api::rules::ffi::TrafficSignType::kRailroadCrossing,
1659 TrafficSignType::NoOvertaking => maliput_sys::api::rules::ffi::TrafficSignType::kNoOvertaking,
1660 TrafficSignType::Unknown => maliput_sys::api::rules::ffi::TrafficSignType::kUnknown,
1661 }
1662}
1663
1664/// Interface for accessing the [TrafficSign]s in the [super::RoadNetwork].
1665pub struct TrafficSignBook<'a> {
1666 pub(super) traffic_sign_book: &'a maliput_sys::api::rules::ffi::TrafficSignBook,
1667}
1668
1669impl<'a> TrafficSignBook<'a> {
1670 /// Gets all the [TrafficSign]s in the [TrafficSignBook].
1671 ///
1672 /// # Returns
1673 /// A vector of [TrafficSign]s.
1674 pub fn traffic_signs(&self) -> Vec<TrafficSign<'_>> {
1675 let traffic_signs_cpp = maliput_sys::api::rules::ffi::TrafficSignBook_TrafficSigns(self.traffic_sign_book);
1676 traffic_signs_cpp
1677 .into_iter()
1678 .map(|ts| TrafficSign {
1679 traffic_sign: unsafe { ts.traffic_sign.as_ref().expect("TrafficSign pointer is null") },
1680 })
1681 .collect::<Vec<TrafficSign>>()
1682 }
1683
1684 /// Gets a [TrafficSign] by its id.
1685 ///
1686 /// # Arguments
1687 /// * `id` - The id of the [TrafficSign].
1688 ///
1689 /// # Returns
1690 /// The [TrafficSign] with the given id, or `None` if not found.
1691 pub fn get_traffic_sign(&self, id: &String) -> Option<TrafficSign<'_>> {
1692 let ptr = maliput_sys::api::rules::ffi::TrafficSignBook_GetTrafficSign(self.traffic_sign_book, id);
1693 if ptr.is_null() {
1694 return None;
1695 }
1696 Some(TrafficSign {
1697 traffic_sign: unsafe { ptr.as_ref().expect("Unable to get underlying traffic sign pointer") },
1698 })
1699 }
1700
1701 /// Gets all [TrafficSign]s whose `related_lanes()` includes the given lane ID.
1702 ///
1703 /// # Arguments
1704 /// * `lane_id` - The lane ID to filter by.
1705 ///
1706 /// # Returns
1707 /// A vector of [TrafficSign]s associated with the given lane.
1708 pub fn find_by_lane(&self, lane_id: &String) -> Vec<TrafficSign<'_>> {
1709 let traffic_signs_cpp =
1710 maliput_sys::api::rules::ffi::TrafficSignBook_FindByLane(self.traffic_sign_book, lane_id);
1711 traffic_signs_cpp
1712 .into_iter()
1713 .map(|ts| TrafficSign {
1714 traffic_sign: unsafe { ts.traffic_sign.as_ref().expect("TrafficSign pointer is null") },
1715 })
1716 .collect::<Vec<TrafficSign>>()
1717 }
1718
1719 /// Gets all [TrafficSign]s of the given [TrafficSignType].
1720 ///
1721 /// # Arguments
1722 /// * `sign_type` - The [TrafficSignType] to filter by.
1723 ///
1724 /// # Returns
1725 /// A vector of [TrafficSign]s of the given type.
1726 pub fn find_by_type(&self, sign_type: &TrafficSignType) -> Vec<TrafficSign<'_>> {
1727 let sign_type_ffi = traffic_sign_type_to_cpp(sign_type);
1728 let traffic_signs_cpp =
1729 maliput_sys::api::rules::ffi::TrafficSignBook_FindByType(self.traffic_sign_book, sign_type_ffi);
1730 traffic_signs_cpp
1731 .into_iter()
1732 .map(|ts| TrafficSign {
1733 traffic_sign: unsafe { ts.traffic_sign.as_ref().expect("TrafficSign pointer is null") },
1734 })
1735 .collect::<Vec<TrafficSign>>()
1736 }
1737}
1738
1739/// Models a physical traffic sign — a static, passive signaling device placed
1740/// along or above the road to convey regulatory, warning, or informational
1741/// messages to road users.
1742///
1743/// Unlike [TrafficLight], a traffic sign has no dynamic state. It simply
1744/// exists at a position with an orientation and a type.
1745pub struct TrafficSign<'a> {
1746 pub traffic_sign: &'a maliput_sys::api::rules::ffi::TrafficSign,
1747}
1748
1749impl<'a> TrafficSign<'a> {
1750 /// Gets the unique identifier of the [TrafficSign].
1751 ///
1752 /// # Returns
1753 /// The id of the [TrafficSign].
1754 pub fn id(&self) -> String {
1755 maliput_sys::api::rules::ffi::TrafficSign_id(self.traffic_sign)
1756 }
1757
1758 /// Gets the [TrafficSignType] of the [TrafficSign].
1759 ///
1760 /// # Returns
1761 /// The [TrafficSignType].
1762 pub fn sign_type(&self) -> TrafficSignType {
1763 let sign_type = maliput_sys::api::rules::ffi::TrafficSign_type(self.traffic_sign);
1764 traffic_sign_type_from_cpp(sign_type)
1765 }
1766
1767 /// Gets the position of the [TrafficSign] in the road network's Inertial frame.
1768 ///
1769 /// # Returns
1770 /// An [super::InertialPosition] representing the position of the [TrafficSign].
1771 pub fn position_road_network(&self) -> super::InertialPosition {
1772 let inertial_position = maliput_sys::api::rules::ffi::TrafficSign_position_road_network(self.traffic_sign);
1773 super::InertialPosition { ip: inertial_position }
1774 }
1775
1776 /// Gets the orientation of the [TrafficSign] in the road network's Inertial frame.
1777 ///
1778 /// # Returns
1779 /// An [super::Rotation] representing the orientation of the [TrafficSign].
1780 pub fn orientation_road_network(&self) -> super::Rotation {
1781 let rotation = maliput_sys::api::rules::ffi::TrafficSign_orientation_road_network(self.traffic_sign);
1782 super::Rotation { r: rotation }
1783 }
1784
1785 /// Gets the optional text message displayed on the [TrafficSign].
1786 ///
1787 /// # Returns
1788 /// `Some(String)` if a message is set, `None` otherwise.
1789 pub fn message(&self) -> Option<String> {
1790 let wrapper = maliput_sys::api::rules::ffi::TrafficSign_message(self.traffic_sign);
1791 if wrapper.is_null() {
1792 return None;
1793 }
1794 Some(wrapper.value.clone())
1795 }
1796
1797 /// Gets the lane IDs that this sign is physically relevant to.
1798 ///
1799 /// # Returns
1800 /// A vector of lane ID strings.
1801 pub fn related_lanes(&self) -> Vec<String> {
1802 maliput_sys::api::rules::ffi::TrafficSign_related_lanes(self.traffic_sign)
1803 }
1804
1805 /// Gets the bounding box of the [TrafficSign].
1806 ///
1807 /// # Returns
1808 /// A [crate::math::BoundingBox] describing the sign's oriented bounding volume.
1809 /// The box position is the centroid, `box_size` gives full extents, and `orientation`
1810 /// is expressed as roll-pitch-yaw angles.
1811 pub fn bounding_box(&self) -> crate::math::BoundingBox {
1812 let b = maliput_sys::api::rules::ffi::TrafficSign_bounding_box(self.traffic_sign);
1813 crate::math::BoundingBox { b }
1814 }
1815}