maliput/api/
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 crate::common::MaliputError;
32use crate::math::Matrix3;
33use crate::math::Quaternion;
34use crate::math::RollPitchYaw;
35use crate::math::Vector3;
36
37pub mod rules;
38
39/// Represents a complete Maliput road network.
40///
41/// A `RoadNetwork` is the main entry point for interacting with a road map in Maliput.
42/// It serves as a container for all the elements that describe a road network,
43/// including its physical layout and the rules of the road.
44///
45/// It provides access to the following key components:
46///
47/// * [`RoadGeometry`]: The geometric description of the road surfaces.
48/// * [`rules::RoadRulebook`]: The set of traffic rules, like speed limits and right-of-way.
49/// * [`rules::TrafficLightBook`]: A catalog of all traffic lights in the network.
50/// * [`IntersectionBook`]: A collection of logical intersections and their states.
51///   TODO: Complete with other books when available (e.g., `RuleRegistry / PhaseRingBook / etc)
52///
53/// More info can be found at https://maliput.readthedocs.io/en/latest/html/deps/maliput/html/maliput_design.html.
54///
55/// # Example
56///
57/// ```rust, no_run
58/// use maliput::api::RoadNetwork;
59/// use std::collections::HashMap;
60///
61/// // Properties to load an OpenDRIVE file using the "maliput_malidrive" backend.
62/// let package_location = std::env::var("CARGO_MANIFEST_DIR").unwrap();
63/// let xodr_path = format!("{}/data/xodr/TShapeRoad.xodr", package_location);
64/// let road_network_properties = HashMap::from([("road_geometry_id", "my_rg_from_rust"), ("opendrive_file", xodr_path.as_str())]);
65///
66/// // Create the RoadNetwork by specifying the loader ID and properties.
67/// let road_network = RoadNetwork::new("maliput_malidrive", &road_network_properties).unwrap();
68/// ```
69pub struct RoadNetwork {
70    pub(crate) rn: cxx::UniquePtr<maliput_sys::api::ffi::RoadNetwork>,
71}
72
73impl RoadNetwork {
74    /// Create a new `RoadNetwork` with the given `road_network_loader_id` and `properties`.
75    ///
76    /// # Arguments
77    ///
78    /// * `road_network_loader_id` - The id of the road network loader. It identifies the backend to be used (e.g., "maliput_malidrive").
79    /// * `properties` - The properties of the road network.
80    ///
81    /// # Details
82    /// It relies on `maliput_sys::plugin::ffi::CreateRoadNetwork` to create a new `RoadNetwork`.
83    ///
84    /// # Returns
85    /// A result containing the `RoadNetwork` or a `MaliputError` if the creation fails.
86    pub fn new(
87        road_network_loader_id: &str,
88        properties: &std::collections::HashMap<&str, &str>,
89    ) -> Result<RoadNetwork, MaliputError> {
90        // Translate the properties to ffi types
91        let mut properties_vec = Vec::new();
92        for (key, value) in properties.iter() {
93            properties_vec.push(format!("{}:{}", key, value));
94        }
95        // If MALIPUT_PLUGIN_PATH is not set, it will be created.
96        let new_path = match std::env::var_os("MALIPUT_PLUGIN_PATH") {
97            Some(current_path) => {
98                // Add the maliput_malidrive plugin path obtained from maliput_sdk to MALIPUT_PLUGIN_PATH.
99                // This is added first in the list as the plugins are loaded sequentally and we
100                // want this to be used only when no others are present. (typically in dev mode).
101                let mut new_paths = vec![maliput_sdk::get_maliput_malidrive_plugin_path()];
102                new_paths.extend(std::env::split_paths(&current_path).collect::<Vec<_>>());
103                std::env::join_paths(new_paths).unwrap()
104            }
105            None => maliput_sdk::get_maliput_malidrive_plugin_path().into(),
106        };
107        std::env::set_var("MALIPUT_PLUGIN_PATH", new_path);
108        let rn = maliput_sys::plugin::ffi::CreateRoadNetwork(&road_network_loader_id.to_string(), &properties_vec)?;
109        Ok(RoadNetwork { rn })
110    }
111
112    /// Get the `RoadGeometry` of the `RoadNetwork`.
113    pub fn road_geometry(&self) -> RoadGeometry<'_> {
114        unsafe {
115            RoadGeometry {
116                rg: self.rn.road_geometry().as_ref().expect(""),
117            }
118        }
119    }
120    /// Get the `IntersectionBook` of the `RoadNetwork`.
121    pub fn intersection_book(&self) -> IntersectionBook<'_> {
122        let intersection_book_ffi = maliput_sys::api::ffi::RoadNetwork_intersection_book(&self.rn);
123        IntersectionBook {
124            intersection_book: unsafe {
125                intersection_book_ffi
126                    .as_ref()
127                    .expect("Underlying IntersectionBook is null")
128            },
129        }
130    }
131    /// Get the `TrafficLightBook` of the `RoadNetwork`.
132    pub fn traffic_light_book(&self) -> rules::TrafficLightBook<'_> {
133        let traffic_light_book_ffi = self.rn.traffic_light_book();
134        rules::TrafficLightBook {
135            traffic_light_book: unsafe {
136                traffic_light_book_ffi
137                    .as_ref()
138                    .expect("Underlying TrafficLightBook is null")
139            },
140        }
141    }
142    /// Get the `RoadRulebook` of the `RoadNetwork`.
143    pub fn rulebook(&self) -> rules::RoadRulebook<'_> {
144        let rulebook_ffi = self.rn.rulebook();
145        rules::RoadRulebook {
146            road_rulebook: unsafe { rulebook_ffi.as_ref().expect("Underlying RoadRulebook is null") },
147        }
148    }
149
150    /// Get the `PhaseRingBook` of the `RoadNetwork`.
151    pub fn phase_ring_book(&self) -> rules::PhaseRingBook<'_> {
152        let phase_ring_book_ffi = self.rn.phase_ring_book();
153        rules::PhaseRingBook {
154            phase_ring_book: unsafe { phase_ring_book_ffi.as_ref().expect("Underlying PhaseRingBook is null") },
155        }
156    }
157
158    /// Get the `RuleRegistry` of the `RoadNetwork`.
159    pub fn rule_registry(&self) -> rules::RuleRegistry<'_> {
160        let rule_registry_ffi = self.rn.rule_registry();
161        rules::RuleRegistry {
162            rule_registry: unsafe { rule_registry_ffi.as_ref().expect("Underlying RuleRegistry is null") },
163        }
164    }
165
166    /// Get the `PhaseProvider` of the `RoadNetwork`.
167    pub fn phase_provider(&self) -> rules::PhaseProvider<'_> {
168        let phase_provider_ffi = maliput_sys::api::ffi::RoadNetwork_phase_provider(&self.rn);
169        rules::PhaseProvider {
170            phase_provider: unsafe { phase_provider_ffi.as_ref().expect("Underlying PhaseProvider is null") },
171        }
172    }
173
174    /// Get the `DiscreteValueRuleStateProvider` of the `RoadNetwork`.
175    pub fn discrete_value_rule_state_provider(&self) -> rules::DiscreteValueRuleStateProvider<'_> {
176        let state_provider = maliput_sys::api::ffi::RoadNetwork_discrete_value_rule_state_provider(&self.rn);
177        rules::DiscreteValueRuleStateProvider {
178            state_provider: unsafe {
179                state_provider
180                    .as_ref()
181                    .expect("Underlying DiscreteValueRuleStateProvider is null")
182            },
183        }
184    }
185
186    /// Get the `RangeValueRuleStateProvider` of the `RoadNetwork`.
187    pub fn range_value_rule_state_provider(&self) -> rules::RangeValueRuleStateProvider<'_> {
188        let state_provider = maliput_sys::api::ffi::RoadNetwork_range_value_rule_state_provider(&self.rn);
189        rules::RangeValueRuleStateProvider {
190            state_provider: unsafe {
191                state_provider
192                    .as_ref()
193                    .expect("Underlying RangeValueRuleStateProvider is null")
194            },
195        }
196    }
197}
198
199/// Represents the geometry of a road network.
200///
201/// `RoadGeometry` is the top-level container for the road network's geometric
202/// description. It is composed of a set of `Junction`s, which in turn contain
203/// `Segment`s and `Lane`s.
204///
205/// It provides access to the entire road network's geometric structure,
206/// allowing for queries about its components (e.g., finding a `Lane` by its ID)
207/// and for coordinate conversions between the inertial frame and the road network's
208/// intrinsic coordinate systems (lane coordinates).
209///
210/// An instance of `RoadGeometry` is typically obtained from a `RoadNetwork`.
211///
212/// More info can be found at https://maliput.readthedocs.io/en/latest/html/deps/maliput/html/maliput_design.html.
213///
214/// # Example of obtaining a `RoadGeometry`
215///
216/// ```rust, no_run
217/// use maliput::api::RoadNetwork;
218/// use std::collections::HashMap;
219///
220/// let package_location = std::env::var("CARGO_MANIFEST_DIR").unwrap();
221/// let xodr_path = format!("{}/data/xodr/TShapeRoad.xodr", package_location);
222/// let road_network_properties = HashMap::from([("road_geometry_id", "my_rg_from_rust"), ("opendrive_file", xodr_path.as_str())]);
223/// let road_network = RoadNetwork::new("maliput_malidrive", &road_network_properties).unwrap();
224/// let road_geometry = road_network.road_geometry();
225/// println!("RoadGeometry ID: {}", road_geometry.id());
226/// ```
227pub struct RoadGeometry<'a> {
228    rg: &'a maliput_sys::api::ffi::RoadGeometry,
229}
230
231impl<'a> RoadGeometry<'a> {
232    /// Returns the id of the RoadGeometry.
233    pub fn id(&self) -> String {
234        maliput_sys::api::ffi::RoadGeometry_id(self.rg)
235    }
236    /// Returns the number of Junctions in the RoadGeometry.
237    ///
238    /// Return value is non-negative.
239    pub fn num_junctions(&self) -> i32 {
240        self.rg.num_junctions()
241    }
242    /// Returns the tolerance guaranteed for linear measurements (positions).
243    pub fn linear_tolerance(&self) -> f64 {
244        self.rg.linear_tolerance()
245    }
246    /// Returns the tolerance guaranteed for angular measurements (orientations).
247    pub fn angular_tolerance(&self) -> f64 {
248        self.rg.angular_tolerance()
249    }
250    /// Returns the number of BranchPoints in the RoadGeometry.
251    ///
252    /// Return value is non-negative.
253    pub fn num_branch_points(&self) -> i32 {
254        self.rg.num_branch_points()
255    }
256    /// Determines the [RoadPosition] on the 3D road manifold that corresponds to
257    /// [InertialPosition] `inertial_position`.
258    ///
259    /// The [RoadGeometry]'s manifold is a 3D volume, with each point defined by (s, r, h)
260    /// coordinates. This method returns a [RoadPositionQuery]. Its [RoadPosition] is the
261    /// point in the [RoadGeometry]'s manifold which is, in the `Inertial`-frame, closest to
262    /// `inertial_position`. Its InertialPosition is the `Inertial`-frame equivalent of the
263    /// [RoadPosition] and its distance is the Cartesian distance from
264    /// `inertial_position` to the nearest point.
265    ///
266    /// This method guarantees that its result satisfies the condition that
267    /// `result.lane.to_lane_position(result.pos)` is within `linear_tolerance()`
268    /// of the returned [InertialPosition].
269    ///
270    /// The map from [RoadGeometry] to the `Inertial`-frame is not onto (as a bounded
271    /// [RoadGeometry] cannot completely cover the unbounded Cartesian universe).
272    /// If `inertial_position` does represent a point contained within the volume
273    /// of the RoadGeometry, then result distance is guaranteed to be less
274    /// than or equal to `linear_tolerance()`.
275    ///
276    /// The map from [RoadGeometry] to `Inertial`-frame is not necessarily one-to-one.
277    /// Different `(s,r,h)` coordinates from different Lanes, potentially from
278    /// different Segments, may map to the same `(x,y,z)` `Inertial`-frame location.
279    ///
280    /// If `inertial_position` is contained within the volumes of multiple Segments,
281    /// then to_road_position() will choose a [Segment] which yields the minimum
282    /// height `h` value in the result.  If the chosen [Segment] has multiple
283    /// Lanes, then to_road_position() will choose a [Lane] which contains
284    /// `inertial_position` within its `lane_bounds()` if possible, and if that is
285    /// still ambiguous, it will further select a [Lane] which minimizes the
286    /// absolute value of the lateral `r` coordinate in the result.
287    ///
288    /// # Arguments
289    /// * `inertial_position` - The [InertialPosition] to convert into a [RoadPosition].
290    ///
291    /// # Return
292    /// A [RoadPositionQuery] with the nearest [RoadPosition], the corresponding [InertialPosition]
293    /// to that [RoadPosition] and the distance between the input and output [InertialPosition]s.
294    pub fn to_road_position(&self, inertial_position: &InertialPosition) -> Result<RoadPositionQuery, MaliputError> {
295        let rpr = maliput_sys::api::ffi::RoadGeometry_ToRoadPosition(self.rg, &inertial_position.ip)?;
296        Ok(RoadPositionQuery {
297            road_position: RoadPosition {
298                rp: maliput_sys::api::ffi::RoadPositionResult_road_position(&rpr),
299            },
300            nearest_position: InertialPosition {
301                ip: maliput_sys::api::ffi::RoadPositionResult_nearest_position(&rpr),
302            },
303            distance: maliput_sys::api::ffi::RoadPositionResult_distance(&rpr),
304        })
305    }
306
307    /// Determines the [RoadPosition] on the road surface that corresponds to
308    /// [InertialPosition] `inertial_position`.
309    ///
310    /// This method is similar to [RoadGeometry::to_road_position], in a way that it determines if
311    /// `inertial_position` is within the [RoadGeometry]'s 3D volume. If it is, a [RoadPosition] is
312    /// returned where the height `h` is set to 0, effectively placing the point on the road
313    /// surface.
314    ///
315    /// # Arguments
316    /// * `inertial_position` - The [InertialPosition] to convert into a [RoadPosition].
317    ///
318    /// # Return
319    /// The corresponding [RoadPosition] on the road surface or a [MaliputError] if the `inertial_position` is not on the road surface (i.e., the distance is greater than `linear_tolerance`).
320    ///
321    /// # Example
322    ///
323    /// ```rust, no_run
324    /// use maliput::api::{RoadNetwork, InertialPosition};
325    /// use std::collections::HashMap;
326    ///
327    /// let package_location = std::env::var("CARGO_MANIFEST_DIR").unwrap();
328    /// let xodr_path = format!("{}/data/xodr/TShapeRoad.xodr", package_location);
329    /// let road_network_properties = HashMap::from([("road_geometry_id", "my_rg_from_rust"), ("opendrive_file", xodr_path.as_str())]);
330    /// let road_network = RoadNetwork::new("maliput_malidrive", &road_network_properties).unwrap();
331    /// let road_geometry = road_network.road_geometry();
332    ///
333    /// // Although this isn't directly on the surface, it is within the RoadGeometry volume.
334    /// let inertial_pos = InertialPosition::new(1.0, 0.0, 1.0);
335    /// let road_pos = road_geometry.to_road_position_surface(&inertial_pos);
336    /// assert!(road_pos.is_ok());
337    /// let road_pos = road_pos.unwrap();
338    /// println!("Road position on surface: s={}, r={}, h={}", road_pos.pos().s(), road_pos.pos().r(), road_pos.pos().h());
339    /// assert_eq!(road_pos.pos().s(), 1.0);
340    /// assert_eq!(road_pos.pos().r(), 0.0);
341    /// assert_eq!(road_pos.pos().h(), 0.0);  // h is set to 0.
342    ///
343    /// // An inertial position that is off the road volume.
344    /// let inertial_pos= InertialPosition::new(1.0, 0.0, 10.0);
345    /// let road_pos= road_geometry.to_road_position_surface(&inertial_pos);
346    /// assert!(road_pos.is_err());
347    /// ```
348    pub fn to_road_position_surface(&self, inertial_position: &InertialPosition) -> Result<RoadPosition, MaliputError> {
349        let rpr = maliput_sys::api::ffi::RoadGeometry_ToRoadPosition(self.rg, &inertial_position.ip)?;
350        let road_position = RoadPosition {
351            rp: maliput_sys::api::ffi::RoadPositionResult_road_position(&rpr),
352        };
353
354        let distance = maliput_sys::api::ffi::RoadPositionResult_distance(&rpr);
355        if distance > self.linear_tolerance() {
356            return Err(MaliputError::Other(format!(
357                "InertialPosition {} does not correspond to a RoadPosition. It is off by {}m to the closest lane {} at {}.",
358                maliput_sys::api::ffi::InertialPosition_to_str(&inertial_position.ip),
359                distance, road_position.lane().id(), road_position.pos())));
360        }
361
362        let lane_position =
363            maliput_sys::api::ffi::LanePosition_new(road_position.pos().s(), road_position.pos().r(), 0.);
364        unsafe {
365            Ok(RoadPosition {
366                rp: maliput_sys::api::ffi::RoadPosition_new(road_position.lane().lane, &lane_position),
367            })
368        }
369    }
370
371    /// Obtains all [RoadPosition]s within a radius of the inertial_position.
372    ///
373    /// Only Lanes whose segment regions include points that are within radius of
374    /// inertial position are included in the search. For each of these Lanes,
375    /// include the [RoadPosition] or [RoadPosition]s with the minimum distance to
376    /// inertial position in the returned result.
377    ///
378    /// # Arguments
379    ///
380    /// * `inertial_position` - The [InertialPosition] to search around.
381    /// * `radius` - The radius around the [InertialPosition] to search for [RoadPosition]s.
382    ///
383    /// # Return
384    ///
385    /// A vector of [RoadPositionQuery]s.
386    pub fn find_road_positions(
387        &self,
388        inertial_position: &InertialPosition,
389        radius: f64,
390    ) -> Result<Vec<RoadPositionQuery>, MaliputError> {
391        let positions = maliput_sys::api::ffi::RoadGeometry_FindRoadPositions(self.rg, &inertial_position.ip, radius)?;
392        Ok(positions
393            .iter()
394            .map(|rpr| RoadPositionQuery {
395                road_position: RoadPosition {
396                    rp: maliput_sys::api::ffi::RoadPositionResult_road_position(rpr),
397                },
398                nearest_position: InertialPosition {
399                    ip: maliput_sys::api::ffi::RoadPositionResult_nearest_position(rpr),
400                },
401                distance: maliput_sys::api::ffi::RoadPositionResult_distance(rpr),
402            })
403            .collect())
404    }
405
406    /// Get the lane matching given `lane_id`.
407    ///
408    /// # Arguments
409    /// * `lane_id` - The id of the lane.
410    ///
411    /// # Return
412    /// The lane with the given id.
413    /// If no lane is found with the given id, return None.
414    pub fn get_lane(&self, lane_id: &String) -> Option<Lane<'_>> {
415        let lane = maliput_sys::api::ffi::RoadGeometry_GetLane(self.rg, lane_id);
416        if lane.lane.is_null() {
417            return None;
418        }
419        Some(Lane {
420            lane: unsafe { lane.lane.as_ref().expect("") },
421        })
422    }
423    /// Get all lanes of the `RoadGeometry`.
424    /// Returns a vector of `Lane`.
425    /// # Example
426    /// ```rust, no_run
427    /// use maliput::api::RoadNetwork;
428    /// use std::collections::HashMap;
429    ///
430    /// let package_location = std::env::var("CARGO_MANIFEST_DIR").unwrap();
431    /// let xodr_path = format!("{}/data/xodr/TShapeRoad.xodr", package_location);
432    /// let road_network_properties = HashMap::from([("road_geometry_id", "my_rg_from_rust"), ("opendrive_file", xodr_path.as_str())]);
433    /// let road_network = RoadNetwork::new("maliput_malidrive", &road_network_properties).unwrap();
434    /// let road_geometry = road_network.road_geometry();
435    /// let lanes = road_geometry.get_lanes();
436    /// for lane in lanes {
437    ///    println!("lane_id: {}", lane.id());
438    /// }
439    /// ```
440    pub fn get_lanes(&self) -> Vec<Lane<'_>> {
441        let lanes = maliput_sys::api::ffi::RoadGeometry_GetLanes(self.rg);
442        lanes
443            .into_iter()
444            .map(|l| Lane {
445                lane: unsafe { l.lane.as_ref().expect("") },
446            })
447            .collect::<Vec<Lane>>()
448    }
449    /// Get the segment matching given `segment_id`.
450    ///
451    /// # Arguments
452    /// * `segment_id` - The id of the segment.
453    ///
454    /// # Return
455    /// The segment with the given id.
456    /// If no segment is found with the given id, return None.
457    pub fn get_segment(&self, segment_id: &String) -> Option<Segment<'_>> {
458        let segment = maliput_sys::api::ffi::RoadGeometry_GetSegment(self.rg, segment_id);
459        if segment.is_null() {
460            return None;
461        }
462        unsafe {
463            Some(Segment {
464                segment: segment.as_ref().expect(""),
465            })
466        }
467    }
468    /// Get the junction at the given index.
469    /// The index is in the range [0, num_junctions).
470    ///
471    /// # Arguments
472    /// * `index` - The index of the junction.
473    ///
474    /// # Return
475    /// The junction at the given index.
476    /// If no junction is found at the given index, return None.
477    pub fn junction(&self, index: i32) -> Option<Junction<'_>> {
478        let junction = self.rg.junction(index).ok()?;
479        if junction.is_null() {
480            return None;
481        }
482        unsafe {
483            Some(Junction {
484                junction: junction.as_ref().expect(""),
485            })
486        }
487    }
488
489    /// Get the junction matching given `junction_id`.
490    ///
491    /// # Arguments
492    /// * `junction_id` - The id of the junction.
493    ///
494    /// # Return
495    /// The junction with the given id.
496    /// If no junction is found with the given id, return None.
497    pub fn get_junction(&self, junction_id: &String) -> Option<Junction<'_>> {
498        let junction = maliput_sys::api::ffi::RoadGeometry_GetJunction(self.rg, junction_id);
499        if junction.is_null() {
500            return None;
501        }
502        unsafe {
503            Some(Junction {
504                junction: junction.as_ref().expect(""),
505            })
506        }
507    }
508    /// Get the branch point matching given `branch_point_id`.
509    ///
510    /// # Arguments
511    /// * `branch_point_id` - The id of the branch point.
512    ///
513    /// # Return
514    /// The branch point with the given id.
515    /// If no branch point is found with the given id, return None.
516    pub fn get_branch_point(&self, branch_point_id: &String) -> Option<BranchPoint<'_>> {
517        let branch_point = maliput_sys::api::ffi::RoadGeometry_GetBranchPoint(self.rg, branch_point_id);
518        if branch_point.is_null() {
519            return None;
520        }
521        unsafe {
522            Some(BranchPoint {
523                branch_point: branch_point.as_ref().expect(""),
524            })
525        }
526    }
527    /// Execute a custom command on the backend.
528    ///
529    /// # Details
530    /// The documentation of the custom command should be provided by the backend: https://github.com/maliput/maliput_malidrive/blob/main/src/maliput_malidrive/base/road_geometry.h
531    ///
532    /// # Arguments
533    /// * `command` - The command to execute.
534    ///
535    /// # Return
536    /// The result of the command.
537    // pub fn backend_custom_command(&self, command: &String) -> String {
538    pub fn backend_custom_command(&self, command: &String) -> Result<String, MaliputError> {
539        Ok(maliput_sys::api::ffi::RoadGeometry_BackendCustomCommand(
540            self.rg, command,
541        )?)
542    }
543    /// Obtains the Geo Reference info of this RoadGeometry.
544    ///
545    /// # Return
546    /// A string containing the Geo Reference projection, if any.
547    pub fn geo_reference_info(&self) -> String {
548        maliput_sys::api::ffi::RoadGeometry_GeoReferenceInfo(self.rg)
549    }
550}
551
552/// A 3-dimensional position in a `Lane`-frame, consisting of three components:
553///
554/// * s is longitudinal position, as arc-length along a Lane's reference line.
555/// * r is lateral position, perpendicular to the reference line at s. +r is to
556///   to the left when traveling in the direction of +s.
557/// * h is height above the road surface.
558///
559/// # Example
560///
561/// ```rust, no_run
562/// use maliput::api::LanePosition;
563///
564/// let lane_pos = LanePosition::new(1.0, 2.0, 3.0);
565/// println!("lane_pos = {}", lane_pos);
566/// assert_eq!(lane_pos.s(), 1.0);
567/// assert_eq!(lane_pos.r(), 2.0);
568/// assert_eq!(lane_pos.h(), 3.0);
569/// ```
570pub struct LanePosition {
571    lp: cxx::UniquePtr<maliput_sys::api::ffi::LanePosition>,
572}
573
574impl LanePosition {
575    /// Create a new `LanePosition` with the given `s`, `r`, and `h` components.
576    pub fn new(s: f64, r: f64, h: f64) -> LanePosition {
577        LanePosition {
578            lp: maliput_sys::api::ffi::LanePosition_new(s, r, h),
579        }
580    }
581    /// Get the `s` component of the `LanePosition`.
582    pub fn s(&self) -> f64 {
583        self.lp.s()
584    }
585    /// Get the `r` component of the `LanePosition`.
586    pub fn r(&self) -> f64 {
587        self.lp.r()
588    }
589    /// Get the `h` component of the `LanePosition`.
590    pub fn h(&self) -> f64 {
591        self.lp.h()
592    }
593
594    /// Returns all components as 3-vector `[s, r, h]`.
595    pub fn srh(&self) -> Vector3 {
596        let srh = self.lp.srh();
597        Vector3::new(srh.x(), srh.y(), srh.z())
598    }
599
600    /// Set the `s` component of the `LanePosition`.
601    pub fn set_s(&mut self, s: f64) {
602        self.lp.as_mut().expect("Underlying LanePosition is null").set_s(s);
603    }
604
605    /// Set the `r` component of the `LanePosition`.
606    pub fn set_r(&mut self, r: f64) {
607        self.lp.as_mut().expect("Underlying LanePosition is null").set_r(r);
608    }
609
610    /// Set the `h` component of the `LanePosition`.
611    pub fn set_h(&mut self, h: f64) {
612        self.lp.as_mut().expect("Underlying LanePosition is null").set_h(h);
613    }
614
615    /// Set all components from 3-vector `[s, r, h]`.
616    pub fn set_srh(&mut self, srh: &Vector3) {
617        let ffi_vec = maliput_sys::math::ffi::Vector3_new(srh.x(), srh.y(), srh.z());
618        self.lp
619            .as_mut()
620            .expect("Underlying LanePosition is null")
621            .set_srh(&ffi_vec);
622    }
623}
624
625impl PartialEq for LanePosition {
626    fn eq(&self, other: &Self) -> bool {
627        self.srh() == other.srh()
628    }
629}
630
631impl Eq for LanePosition {}
632
633impl std::fmt::Display for LanePosition {
634    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
635        write!(f, "{}", maliput_sys::api::ffi::LanePosition_to_str(&self.lp))
636    }
637}
638
639impl std::fmt::Debug for LanePosition {
640    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
641        f.debug_struct("LanePosition")
642            .field("s", &self.s())
643            .field("r", &self.r())
644            .field("h", &self.h())
645            .finish()
646    }
647}
648
649/// A position in 3-dimensional geographical Cartesian space, i.e., in the
650/// `Inertial`-frame, consisting of three components x, y, and z.
651///
652/// # Example
653///
654/// ```rust, no_run
655/// use maliput::api::InertialPosition;
656///
657/// let inertial_pos = InertialPosition::new(1.0, 2.0, 3.0);
658/// println!("inertial_pos = {}", inertial_pos);
659/// assert_eq!(inertial_pos.x(), 1.0);
660/// assert_eq!(inertial_pos.y(), 2.0);
661/// assert_eq!(inertial_pos.z(), 3.0);
662/// ```
663pub struct InertialPosition {
664    ip: cxx::UniquePtr<maliput_sys::api::ffi::InertialPosition>,
665}
666
667impl InertialPosition {
668    /// Create a new `InertialPosition` with the given `x`, `y`, and `z` components.
669    pub fn new(x: f64, y: f64, z: f64) -> InertialPosition {
670        InertialPosition {
671            ip: maliput_sys::api::ffi::InertialPosition_new(x, y, z),
672        }
673    }
674    /// Get the `x` component of the `InertialPosition`.
675    pub fn x(&self) -> f64 {
676        self.ip.x()
677    }
678    /// Get the `y` component of the `InertialPosition`.
679    pub fn y(&self) -> f64 {
680        self.ip.y()
681    }
682    /// Get the `z` component of the `InertialPosition`.
683    pub fn z(&self) -> f64 {
684        self.ip.z()
685    }
686
687    /// Returns all components as 3-vector `[x, y, z]`.
688    pub fn xyz(&self) -> Vector3 {
689        let xyz = self.ip.xyz();
690        Vector3::new(xyz.x(), xyz.y(), xyz.z())
691    }
692
693    /// Set the `x` component of the `InertialPosition`.
694    pub fn set_x(&mut self, x: f64) {
695        self.ip.as_mut().expect("Underlying InertialPosition is null").set_x(x);
696    }
697
698    /// Set the `y` component of the `InertialPosition`.
699    pub fn set_y(&mut self, y: f64) {
700        self.ip.as_mut().expect("Underlying InertialPosition is null").set_y(y);
701    }
702
703    /// Set the `z` component of the `InertialPosition`.
704    pub fn set_z(&mut self, z: f64) {
705        self.ip.as_mut().expect("Underlying InertialPosition is null").set_z(z);
706    }
707
708    /// Set all components from 3-vector `[x, y, z]`.
709    pub fn set_xyz(&mut self, xyz: &Vector3) {
710        let ffi_vec = maliput_sys::math::ffi::Vector3_new(xyz.x(), xyz.y(), xyz.z());
711        self.ip
712            .as_mut()
713            .expect("Underlying InertialPosition is null")
714            .set_xyz(&ffi_vec);
715    }
716
717    /// Get the length of `InertialPosition`.
718    pub fn length(&self) -> f64 {
719        self.ip.length()
720    }
721
722    /// Get the distance between two `InertialPosition`.
723    pub fn distance(&self, other: &InertialPosition) -> f64 {
724        self.ip.Distance(&other.ip)
725    }
726}
727
728impl PartialEq for InertialPosition {
729    fn eq(&self, other: &Self) -> bool {
730        maliput_sys::api::ffi::InertialPosition_operator_eq(&self.ip, &other.ip)
731    }
732}
733
734impl Eq for InertialPosition {}
735
736impl std::fmt::Display for InertialPosition {
737    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
738        write!(f, "{}", maliput_sys::api::ffi::InertialPosition_to_str(&self.ip))
739    }
740}
741
742impl std::fmt::Debug for InertialPosition {
743    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
744        f.debug_struct("InertialPosition")
745            .field("x", &self.x())
746            .field("y", &self.y())
747            .field("z", &self.z())
748            .finish()
749    }
750}
751
752impl std::ops::Add for InertialPosition {
753    type Output = InertialPosition;
754
755    fn add(self, other: InertialPosition) -> InertialPosition {
756        InertialPosition {
757            ip: maliput_sys::api::ffi::InertialPosition_operator_sum(&self.ip, &other.ip),
758        }
759    }
760}
761
762impl std::ops::Sub for InertialPosition {
763    type Output = InertialPosition;
764
765    fn sub(self, other: InertialPosition) -> InertialPosition {
766        InertialPosition {
767            ip: maliput_sys::api::ffi::InertialPosition_operator_sub(&self.ip, &other.ip),
768        }
769    }
770}
771
772impl std::ops::Mul<f64> for InertialPosition {
773    type Output = InertialPosition;
774
775    fn mul(self, scalar: f64) -> InertialPosition {
776        InertialPosition {
777            ip: maliput_sys::api::ffi::InertialPosition_operator_mul_scalar(&self.ip, scalar),
778        }
779    }
780}
781
782impl Clone for InertialPosition {
783    fn clone(&self) -> Self {
784        InertialPosition {
785            ip: maliput_sys::api::ffi::InertialPosition_new(self.x(), self.y(), self.z()),
786        }
787    }
788}
789
790/// Bounds in the lateral dimension (r component) of a `Lane`-frame, consisting
791/// of a pair of minimum and maximum r value.  The bounds must straddle r = 0,
792/// i.e., the minimum must be <= 0 and the maximum must be >= 0.
793pub struct RBounds {
794    min: f64,
795    max: f64,
796}
797
798impl RBounds {
799    /// Create a new `RBounds` with the given `min` and `max` values.
800    pub fn new(min: f64, max: f64) -> RBounds {
801        RBounds { min, max }
802    }
803    /// Get the `min` value of the `RBounds`.
804    pub fn min(&self) -> f64 {
805        self.min
806    }
807    /// Get the `max` value of the `RBounds`.
808    pub fn max(&self) -> f64 {
809        self.max
810    }
811    /// Set the `min` value of the `RBounds`.
812    pub fn set_min(&mut self, min: f64) {
813        self.min = min;
814    }
815    /// Set the `max` value of the `RBounds`.
816    pub fn set_max(&mut self, max: f64) {
817        self.max = max;
818    }
819}
820
821/// Bounds in the elevation dimension (`h` component) of a `Lane`-frame,
822/// consisting of a pair of minimum and maximum `h` value.  The bounds
823/// must straddle `h = 0`, i.e., the minimum must be `<= 0` and the
824/// maximum must be `>= 0`.
825pub struct HBounds {
826    min: f64,
827    max: f64,
828}
829
830impl HBounds {
831    /// Create a new `HBounds` with the given `min` and `max` values.
832    pub fn new(min: f64, max: f64) -> HBounds {
833        HBounds { min, max }
834    }
835    /// Get the `min` value of the `HBounds`.
836    pub fn min(&self) -> f64 {
837        self.min
838    }
839    /// Get the `max` value of the `HBounds`.
840    pub fn max(&self) -> f64 {
841        self.max
842    }
843    /// Set the `min` value of the `HBounds`.
844    pub fn set_min(&mut self, min: f64) {
845        self.min = min;
846    }
847    /// Set the `max` value of the `HBounds`.
848    pub fn set_max(&mut self, max: f64) {
849        self.max = max;
850    }
851}
852
853/// Isometric velocity vector in a `Lane`-frame.
854///
855/// sigma_v, rho_v, and eta_v are the components of velocity in a
856/// (sigma, rho, eta) coordinate system.  (sigma, rho, eta) have the same
857/// orientation as the (s, r, h) at any given point in space, however they
858/// form an isometric system with a Cartesian distance metric.  Hence,
859/// IsoLaneVelocity represents a "real" physical velocity vector (albeit
860/// with an orientation relative to the road surface).
861#[derive(Default, Copy, Clone, Debug, PartialEq)]
862pub struct IsoLaneVelocity {
863    pub sigma_v: f64,
864    pub rho_v: f64,
865    pub eta_v: f64,
866}
867
868impl IsoLaneVelocity {
869    /// Create a new `IsoLaneVelocity` with the given `sigma_v`, `rho_v`, and `eta_v` components.
870    pub fn new(sigma_v: f64, rho_v: f64, eta_v: f64) -> IsoLaneVelocity {
871        IsoLaneVelocity { sigma_v, rho_v, eta_v }
872    }
873}
874
875/// A Lane represents a lane of travel in a road network.  A Lane defines
876/// a curvilinear coordinate system covering the road surface, with a
877/// longitudinal 's' coordinate that expresses the arc-length along a
878/// central reference curve.  The reference curve nominally represents
879/// an ideal travel trajectory along the Lane.
880///
881/// Lanes are grouped by Segment.  All Lanes belonging to a Segment
882/// represent the same road surface, but with different coordinate
883/// parameterizations (e.g., each Lane has its own reference curve).
884pub struct Lane<'a> {
885    lane: &'a maliput_sys::api::ffi::Lane,
886}
887
888impl<'a> Lane<'a> {
889    /// Returns the id of the Lane.
890    ///
891    /// The id is a unique identifier for the Lane within the RoadGeometry.
892    ///
893    /// # Returns
894    /// A `String` containing the id of the Lane.
895    pub fn id(&self) -> String {
896        maliput_sys::api::ffi::Lane_id(self.lane)
897    }
898    /// Returns the index of this Lane within the Segment which owns it.
899    pub fn index(&self) -> i32 {
900        self.lane.index()
901    }
902    /// Returns the Segment to which this Lane belongs.
903    ///
904    /// # Returns
905    /// A [`Segment`] containing the Segment to which this Lane belongs.
906    pub fn segment(&self) -> Segment<'a> {
907        unsafe {
908            Segment {
909                segment: self.lane.segment().as_ref().expect(""),
910            }
911        }
912    }
913    /// Returns the adjacent lane to the left, if one exists.
914    ///
915    /// "Left" is defined as the direction of `+r` in the `(s, r, h)` lane-coordinate frame.
916    ///
917    /// # Returns
918    ///
919    /// An [`Option<Lane>`] containing the left lane, or `None` if this is the
920    /// leftmost lane.
921    pub fn to_left(&self) -> Option<Lane<'_>> {
922        let lane = self.lane.to_left();
923        if lane.is_null() {
924            None
925        } else {
926            unsafe {
927                Some(Lane {
928                    lane: lane.as_ref().expect(""),
929                })
930            }
931        }
932    }
933    /// Returns the adjacent lane to the right, if one exists.
934    ///
935    /// "Right" is defined as the direction of `-r` in the `(s, r, h)` lane-coordinate
936    /// frame.
937    ///
938    /// # Returns
939    ///
940    /// An [`Option<Lane>`] containing the right lane, or `None` if this is the
941    /// rightmost lane.
942    pub fn to_right(&self) -> Option<Lane<'_>> {
943        let lane = self.lane.to_right();
944        if lane.is_null() {
945            None
946        } else {
947            unsafe {
948                Some(Lane {
949                    lane: lane.as_ref().expect(""),
950                })
951            }
952        }
953    }
954    /// Returns the arc-length of the Lane along its reference curve.
955    ///
956    /// The value of length() is also the maximum s-coordinate for this Lane;
957    /// i.e., the domain of s is [0, length()].
958    ///
959    /// # Returns
960    ///
961    /// The length of the Lane in meters.
962    pub fn length(&self) -> f64 {
963        self.lane.length()
964    }
965
966    /// Get the orientation of the `Lane` at the given `LanePosition`.
967    pub fn get_orientation(&self, lane_position: &LanePosition) -> Result<Rotation, MaliputError> {
968        Ok(Rotation {
969            r: maliput_sys::api::ffi::Lane_GetOrientation(self.lane, lane_position.lp.as_ref().expect(""))?,
970        })
971    }
972    /// # Brief
973    /// Get the [InertialPosition] of the [Lane] at the given [LanePosition].
974    ///
975    /// # Notes
976    /// Note there is no constraint for the `r` coordinate, as it can be outside the lane boundaries.
977    /// In that scenario, the resultant inertial position represents a point in the `s-r` plane at the given `s` and `h`
978    /// coordinates. It's on the user side to verify, if needed, that the lane position is within lane boundaries.
979    /// Bare in mind that the inertial position will be a point in the `s-r` plane, but *not* necessarily on the road surface.
980    ///
981    /// # Arguments
982    /// * `lane_position` - A maliput [LanePosition].
983    ///
984    /// # Precondition
985    /// The s component of `lane_position` must be in domain [0, Lane::length()].
986    ///
987    /// # Return
988    /// The [InertialPosition] corresponding to the input [LanePosition].
989    pub fn to_inertial_position(&self, lane_position: &LanePosition) -> Result<InertialPosition, MaliputError> {
990        Ok(InertialPosition {
991            ip: maliput_sys::api::ffi::Lane_ToInertialPosition(self.lane, lane_position.lp.as_ref().expect(""))?,
992        })
993    }
994    /// Determines the LanePosition corresponding to InertialPosition `inertial_position`.
995    /// The LanePosition is expected to be contained within the lane's 3D boundaries (s, r, h).
996    /// See [Lane::to_segment_position] method.
997    ///
998    /// This method guarantees that its result satisfies the condition that
999    /// `to_inertial_position(result.lane_position)` is within `linear_tolerance()`
1000    ///  of `result.nearest_position`.
1001    ///
1002    /// # Arguments
1003    /// * `inertial_position` - A [InertialPosition] to get a [LanePosition] from.
1004    ///
1005    /// # Return
1006    /// A [LanePositionQuery] with the closest [LanePosition], the corresponding [InertialPosition] to that [LanePosition]
1007    /// and the distance between the input and output [InertialPosition]s.
1008    pub fn to_lane_position(&self, inertial_position: &InertialPosition) -> Result<LanePositionQuery, MaliputError> {
1009        let lpr = maliput_sys::api::ffi::Lane_ToLanePosition(self.lane, inertial_position.ip.as_ref().expect(""))?;
1010        Ok(LanePositionQuery {
1011            lane_position: LanePosition {
1012                lp: maliput_sys::api::ffi::LanePositionResult_road_position(&lpr),
1013            },
1014            nearest_position: InertialPosition {
1015                ip: maliput_sys::api::ffi::LanePositionResult_nearest_position(&lpr),
1016            },
1017            distance: maliput_sys::api::ffi::LanePositionResult_distance(&lpr),
1018        })
1019    }
1020    /// Determines the [LanePosition] corresponding to [InertialPosition] `inertial_position`.
1021    /// The [LanePosition] is expected to be contained within the segment's 3D boundaries (s, r, h).
1022    /// See [Lane::to_lane_position] method.
1023    ///
1024    /// This method guarantees that its result satisfies the condition that
1025    /// `to_inertial_position(result.lane_position)` is within `linear_tolerance()`
1026    ///  of `result.nearest_position`.
1027    ///
1028    /// # Arguments
1029    /// * `inertial_position` - A [InertialPosition] to get a SegmentPosition from.
1030    ///
1031    /// # Return
1032    /// A [LanePositionQuery] with the closest [LanePosition] within the segment, the corresponding
1033    /// [InertialPosition] to that [LanePosition] and the distance between the input and output
1034    /// [InertialPosition]s.
1035    pub fn to_segment_position(&self, inertial_position: &InertialPosition) -> Result<LanePositionQuery, MaliputError> {
1036        let spr = maliput_sys::api::ffi::Lane_ToSegmentPosition(self.lane, inertial_position.ip.as_ref().expect(""))?;
1037        Ok(LanePositionQuery {
1038            lane_position: LanePosition {
1039                lp: maliput_sys::api::ffi::LanePositionResult_road_position(&spr),
1040            },
1041            nearest_position: InertialPosition {
1042                ip: maliput_sys::api::ffi::LanePositionResult_nearest_position(&spr),
1043            },
1044            distance: maliput_sys::api::ffi::LanePositionResult_distance(&spr),
1045        })
1046    }
1047    /// Returns the nominal lateral (r) bounds for the lane as a function of s.
1048    ///
1049    /// These are the lateral bounds for a position that is considered to be
1050    /// "staying in the lane".
1051    ///
1052    /// See also [Lane::segment_bounds] that defines the whole surface.
1053    ///
1054    /// # Arguments
1055    /// * `s` - The longitudinal position along the lane's reference line.
1056    ///
1057    /// # Returns
1058    /// A [RBounds] containing the lateral bounds of the lane at the given `s.
1059    ///
1060    /// # Errors
1061    /// If lane bounds cannot be computed, an error is returned. This can happen if the
1062    /// `s` value is out of bounds (i.e., not in the range [0, Lane::length()]).
1063    pub fn lane_bounds(&self, s: f64) -> Result<RBounds, MaliputError> {
1064        let bounds = maliput_sys::api::ffi::Lane_lane_bounds(self.lane, s)?;
1065        Ok(RBounds::new(bounds.min(), bounds.max()))
1066    }
1067    /// Returns the lateral segment (r) bounds of the lane as a function of s.
1068    ///
1069    /// These are the lateral bounds for a position that is considered to be
1070    /// "on segment", reflecting the physical extent of the surface of the
1071    /// lane's segment.
1072    ///
1073    /// See also [Lane::lane_bounds] that defines what's considered to be "staying
1074    /// in the lane".
1075    ///
1076    /// # Arguments
1077    /// * `s` - The longitudinal position along the lane's reference line.
1078    ///
1079    /// # Returns
1080    /// A [RBounds] containing the lateral segment bounds of the lane at the given `
1081    /// s`.
1082    ///
1083    /// # Errors
1084    /// If segment bounds cannot be computed, an error is returned. This can happen if the
1085    /// `s` value is out of bounds (i.e., not in the range [0, Lane::length()]).
1086    pub fn segment_bounds(&self, s: f64) -> Result<RBounds, MaliputError> {
1087        let bounds = maliput_sys::api::ffi::Lane_segment_bounds(self.lane, s)?;
1088        Ok(RBounds::new(bounds.min(), bounds.max()))
1089    }
1090    /// Returns the elevation (`h`) bounds of the lane as a function of `(s, r)`.
1091    ///
1092    /// These are the elevation bounds for a position that is considered to be
1093    /// within the Lane's volume modeled by the RoadGeometry.
1094    ///
1095    /// `s` is within [0, `length()`] of this Lane and `r` is within
1096    /// `lane_bounds(s)`.
1097    ///
1098    /// # Arguments
1099    /// * `s` - The longitudinal position along the lane's reference line.
1100    /// * `r` - The lateral position perpendicular to the reference line at `s`.
1101    ///
1102    /// # Returns
1103    /// A [HBounds] containing the elevation bounds of the lane at the given `(s, r)`.
1104    ///
1105    /// # Errors
1106    /// If elevation bounds cannot be computed, an error is returned. This can happen if the
1107    /// `s` value is out of bounds (i.e., not in the range [0, Lane::length()]) or if `r` is not within the
1108    /// lane bounds at `s`.
1109    pub fn elevation_bounds(&self, s: f64, r: f64) -> Result<HBounds, MaliputError> {
1110        let bounds = maliput_sys::api::ffi::Lane_elevation_bounds(self.lane, s, r)?;
1111        Ok(HBounds::new(bounds.min(), bounds.max()))
1112    }
1113    /// Computes derivatives of [LanePosition] given a velocity vector `velocity`.
1114    /// `velocity` is a isometric velocity vector oriented in the `Lane`-frame
1115    /// at `position`.
1116    ///
1117    /// # Arguments
1118    /// * `lane_position` - A [LanePosition] at which to evaluate the derivatives.
1119    /// * `velocity` - An [IsoLaneVelocity] representing the velocity vector in the `Lane`-frame
1120    ///   at `lane_position`.
1121    ///
1122    /// # Returns
1123    /// Returns `Lane`-frame derivatives packed into a [LanePosition] struct.
1124    pub fn eval_motion_derivatives(&self, lane_position: &LanePosition, velocity: &IsoLaneVelocity) -> LanePosition {
1125        LanePosition {
1126            lp: maliput_sys::api::ffi::Lane_EvalMotionDerivatives(
1127                self.lane,
1128                lane_position.lp.as_ref().expect(""),
1129                velocity.sigma_v,
1130                velocity.rho_v,
1131                velocity.eta_v,
1132            ),
1133        }
1134    }
1135    /// Returns the lane's [BranchPoint] for the specified end.
1136    ///
1137    /// # Argument
1138    /// * `end` - This lane's start or end [LaneEnd].
1139    ///
1140    /// # Return
1141    /// The lane's [BranchPoint] for the specified end.
1142    pub fn get_branch_point(&self, end: &LaneEnd) -> Result<BranchPoint<'_>, MaliputError> {
1143        if end != &LaneEnd::Start(self.clone()) && end != &LaneEnd::Finish(self.clone()) {
1144            return Err(MaliputError::AssertionError(format!(
1145                "LaneEnd must be an end of this lane {:?}",
1146                end
1147            )));
1148        }
1149        Ok(BranchPoint {
1150            branch_point: unsafe {
1151                maliput_sys::api::ffi::Lane_GetBranchPoint(self.lane, end == &LaneEnd::Start(self.clone()))
1152                    .as_ref()
1153                    .expect("Underlying BranchPoint is null")
1154            },
1155        })
1156    }
1157    /// Returns the set of [LaneEnd]'s which connect with this lane on the
1158    /// same side of the [BranchPoint] at `end`. At a minimum,
1159    /// this set will include this [Lane].
1160    ///
1161    /// # Arguments
1162    /// * `end` - This lane's start or end [LaneEnd].
1163    ///
1164    /// # Return
1165    /// A [LaneEndSet] with all the [LaneEnd]s at the same side of the [BranchPoint] at `end`.
1166    pub fn get_confluent_branches(&self, end: &LaneEnd) -> Result<LaneEndSet<'_>, MaliputError> {
1167        if end != &LaneEnd::Start(self.clone()) && end != &LaneEnd::Finish(self.clone()) {
1168            return Err(MaliputError::AssertionError(format!(
1169                "LaneEnd must be an end of this lane {:?}",
1170                end
1171            )));
1172        }
1173        Ok(LaneEndSet {
1174            lane_end_set: unsafe {
1175                maliput_sys::api::ffi::Lane_GetConfluentBranches(self.lane, end == &LaneEnd::Start(self.clone()))?
1176                    .as_ref()
1177                    .expect("Underlying LaneEndSet is null")
1178            },
1179        })
1180    }
1181    /// Returns the set of [LaneEnd]s which continue onward from this lane at the
1182    /// [BranchPoint] at `end`.
1183    ///
1184    /// # Arguments
1185    /// * `end` - This lane's start or end [LaneEnd].
1186    ///
1187    /// # Return
1188    /// A [LaneEndSet] with all the [LaneEnd]s at the opposite side of the [BranchPoint] at `end`.
1189    pub fn get_ongoing_branches(&self, end: &LaneEnd) -> Result<LaneEndSet<'_>, MaliputError> {
1190        if end != &LaneEnd::Start(self.clone()) && end != &LaneEnd::Finish(self.clone()) {
1191            return Err(MaliputError::AssertionError(format!(
1192                "LaneEnd must be an end of this lane {:?}",
1193                end
1194            )));
1195        }
1196        Ok(LaneEndSet {
1197            lane_end_set: unsafe {
1198                maliput_sys::api::ffi::Lane_GetOngoingBranches(self.lane, end == &LaneEnd::Start(self.clone()))?
1199                    .as_ref()
1200                    .expect("Underlying LaneEndSet is null")
1201            },
1202        })
1203    }
1204    /// Returns the default ongoing LaneEnd connected at `end`,
1205    /// or None if no default branch has been established.
1206    ///
1207    /// # Arguments
1208    /// * `end` - This lane's start or end [LaneEnd].
1209    ///
1210    /// # Return
1211    /// An `Option<LaneEnd>` containing the default branch if it exists, or None
1212    /// if no default branch has been established.
1213    pub fn get_default_branch(&self, end: &LaneEnd) -> Option<LaneEnd<'_>> {
1214        assert! {
1215            end == &LaneEnd::Start(self.clone()) || end == &LaneEnd::Finish(self.clone()),
1216            "LaneEnd must be an end of this lane {:?}",
1217           end
1218        }
1219        let lane_end = maliput_sys::api::ffi::Lane_GetDefaultBranch(self.lane, end == &LaneEnd::Start(self.clone()));
1220        match lane_end.is_null() {
1221            true => None,
1222            false => {
1223                let lane_end_ref: &maliput_sys::api::ffi::LaneEnd =
1224                    lane_end.as_ref().expect("Underlying LaneEnd is null");
1225                let is_start = maliput_sys::api::ffi::LaneEnd_is_start(lane_end_ref);
1226                let lane_ref = unsafe {
1227                    maliput_sys::api::ffi::LaneEnd_lane(lane_end_ref)
1228                        .as_ref()
1229                        .expect("Underlying LaneEnd is null")
1230                };
1231                match is_start {
1232                    true => Some(LaneEnd::Start(Lane { lane: lane_ref })),
1233                    false => Some(LaneEnd::Finish(Lane { lane: lane_ref })),
1234                }
1235            }
1236        }
1237    }
1238    /// Evaluates if the `Lane` contains the given `LanePosition`.
1239    ///
1240    /// # Arguments
1241    /// * `lane_position` - A [LanePosition] to check if it is contained within the `Lane`.
1242    ///
1243    /// # Returns
1244    /// A boolean indicating whether the `Lane` contains the `LanePosition`.
1245    pub fn contains(&self, lane_position: &LanePosition) -> bool {
1246        self.lane.Contains(lane_position.lp.as_ref().expect(""))
1247    }
1248}
1249
1250/// Copy trait for Lane.
1251/// A reference to the Lane is copied.
1252impl Clone for Lane<'_> {
1253    fn clone(&self) -> Self {
1254        Lane { lane: self.lane }
1255    }
1256}
1257
1258/// A Segment represents a bundle of adjacent Lanes which share a
1259/// continuously traversable road surface. Every [LanePosition] on a
1260/// given [Lane] of a Segment has a corresponding [LanePosition] on each
1261/// other [Lane], all with the same height-above-surface h, that all
1262/// map to the same GeoPoint in 3-space.
1263///
1264/// Segments are grouped by [Junction].
1265pub struct Segment<'a> {
1266    segment: &'a maliput_sys::api::ffi::Segment,
1267}
1268
1269impl<'a> Segment<'a> {
1270    /// Returns the id of the Segment.
1271    /// The id is a unique identifier for the Segment within the RoadGeometry.
1272    ///
1273    /// # Returns
1274    /// A `String` containing the id of the Segment.
1275    pub fn id(&self) -> String {
1276        maliput_sys::api::ffi::Segment_id(self.segment)
1277    }
1278    /// Returns the [Junction] to which this Segment belongs.
1279    ///
1280    /// # Returns
1281    /// An [`Result<Junction, MaliputError>`] containing the Junction to which this Segment belongs.
1282    /// If the Segment does not belong to a Junction, an error is returned.
1283    pub fn junction(&self) -> Result<Junction<'_>, MaliputError> {
1284        let junction = self.segment.junction()?;
1285        if junction.is_null() {
1286            return Err(MaliputError::AssertionError(
1287                "Segment does not belong to a Junction".to_string(),
1288            ));
1289        }
1290        unsafe {
1291            Ok(Junction {
1292                junction: junction.as_ref().expect(""),
1293            })
1294        }
1295    }
1296    /// Returns the number of lanes in the Segment.
1297    ///
1298    /// # Returns
1299    /// The number of lanes in the Segment.
1300    pub fn num_lanes(&self) -> i32 {
1301        self.segment.num_lanes()
1302    }
1303    /// Returns the lane at the given `index`.
1304    ///
1305    /// # Arguments
1306    /// * `index` - The index of the lane to retrieve.
1307    ///
1308    /// # Returns
1309    /// A [`Lane`] containing the lane at the given index.
1310    pub fn lane(&self, index: i32) -> Result<Lane<'_>, MaliputError> {
1311        if index < 0 || index >= self.num_lanes() {
1312            return Err(MaliputError::AssertionError(format!(
1313                "Index {} is out of bounds for Segment with {} lanes",
1314                index,
1315                self.num_lanes()
1316            )));
1317        }
1318        let lane = self.segment.lane(index)?;
1319        unsafe {
1320            Ok(Lane {
1321                lane: lane.as_ref().expect(""),
1322            })
1323        }
1324    }
1325}
1326
1327/// A Junction is a closed set of [Segment]s which have physically
1328/// coplanar road surfaces, in the sense that [RoadPosition]s with the
1329/// same h value (height above surface) in the domains of two [Segment]s
1330/// map to the same [InertialPosition].  The [Segment]s need not be directly
1331/// connected to one another in the network topology.
1332///
1333/// Junctions are grouped by [RoadGeometry].
1334pub struct Junction<'a> {
1335    junction: &'a maliput_sys::api::ffi::Junction,
1336}
1337
1338impl<'a> Junction<'a> {
1339    /// Returns the id of the Junction.
1340    /// The id is a unique identifier for the Junction within the RoadGeometry.
1341    ///
1342    /// # Returns
1343    /// A `String` containing the id of the Junction.
1344    pub fn id(&self) -> String {
1345        maliput_sys::api::ffi::Junction_id(self.junction)
1346    }
1347    /// Returns the [RoadGeometry] to which this Junction belongs.
1348    ///
1349    /// # Returns
1350    /// A [`RoadGeometry`] containing the RoadGeometry to which this Junction belongs.
1351    pub fn road_geometry(&self) -> RoadGeometry<'_> {
1352        unsafe {
1353            RoadGeometry {
1354                rg: self.junction.road_geometry().as_ref().expect(""),
1355            }
1356        }
1357    }
1358    /// Returns the number of segments in the Junction.
1359    ///
1360    /// # Returns
1361    /// The number of segments in the Junction.
1362    pub fn num_segments(&self) -> i32 {
1363        self.junction.num_segments()
1364    }
1365    /// Returns the segment at the given `index`.
1366    ///
1367    /// # Arguments
1368    /// * `index` - The index of the segment to retrieve.
1369    ///
1370    /// # Returns
1371    /// A [Result<Segment, MaliputError>] containing the segment at the given index.
1372    /// If the index is out of bounds, an error is returned.
1373    pub fn segment(&self, index: i32) -> Result<Segment<'_>, MaliputError> {
1374        unsafe {
1375            Ok(Segment {
1376                segment: self.junction.segment(index)?.as_ref().expect(""),
1377            })
1378        }
1379    }
1380}
1381
1382/// A position in the road network compound by a specific lane and a lane-frame position in that lane.
1383/// This position is defined by a [Lane] and a [LanePosition].
1384pub struct RoadPosition {
1385    rp: cxx::UniquePtr<maliput_sys::api::ffi::RoadPosition>,
1386}
1387
1388impl RoadPosition {
1389    /// Create a new `RoadPosition` with the given `lane` and `lane_pos`.
1390    ///
1391    /// # Arguments
1392    /// * `lane` - A reference to a [Lane] that this `RoadPosition` is associated with.
1393    /// * `lane_pos` - A reference to a [LanePosition] that defines the position within the lane.
1394    ///
1395    /// # Returns
1396    /// A new `RoadPosition` instance.
1397    pub fn new(lane: &Lane, lane_pos: &LanePosition) -> RoadPosition {
1398        unsafe {
1399            RoadPosition {
1400                rp: maliput_sys::api::ffi::RoadPosition_new(lane.lane, &lane_pos.lp),
1401            }
1402        }
1403    }
1404    /// Computes the [InertialPosition] corresponding to this `RoadPosition`.
1405    ///
1406    /// # Notes
1407    /// This is an indirection to [Lane::to_inertial_position] method.
1408    ///
1409    /// # Returns
1410    /// An [InertialPosition] corresponding to this `RoadPosition`.
1411    pub fn to_inertial_position(&self) -> Result<InertialPosition, MaliputError> {
1412        Ok(InertialPosition {
1413            ip: maliput_sys::api::ffi::RoadPosition_ToInertialPosition(&self.rp)?,
1414        })
1415    }
1416    /// Gets the [Lane] associated with this `RoadPosition`.
1417    ///
1418    /// # Returns
1419    /// A [Lane] that this `RoadPosition` is associated with.
1420    pub fn lane(&self) -> Lane<'_> {
1421        unsafe {
1422            Lane {
1423                lane: maliput_sys::api::ffi::RoadPosition_lane(&self.rp).as_ref().expect(""),
1424            }
1425        }
1426    }
1427    /// Gets the [LanePosition] associated with this `RoadPosition`.
1428    ///
1429    /// # Returns
1430    /// A [LanePosition] that defines the position within the lane for this `RoadPosition`.
1431    pub fn pos(&self) -> LanePosition {
1432        LanePosition {
1433            lp: maliput_sys::api::ffi::RoadPosition_pos(&self.rp),
1434        }
1435    }
1436}
1437
1438/// Represents the result of a RoadPosition query.
1439/// This struct contains the `RoadPosition`, the nearest `InertialPosition` to that `RoadPosition`,
1440/// and the distance between the input `InertialPosition` and the nearest `InertialPosition`.
1441///
1442/// This struct is typically used as return type for the methods: [RoadGeometry::to_road_position] and [RoadGeometry::find_road_positions].
1443pub struct RoadPositionQuery {
1444    /// The candidate RoadPosition returned by the query.
1445    pub road_position: RoadPosition,
1446    /// The nearest InertialPosition to the candidate RoadPosition.
1447    /// This is the position in the inertial frame that is closest to the candidate RoadPosition
1448    pub nearest_position: InertialPosition,
1449    /// The distance between the input InertialPosition and the nearest InertialPosition.
1450    pub distance: f64,
1451}
1452
1453impl RoadPositionQuery {
1454    /// Create a new `RoadPositionQuery` with the given `road_position`, `nearest_position`, and `distance`.
1455    pub fn new(road_position: RoadPosition, nearest_position: InertialPosition, distance: f64) -> RoadPositionQuery {
1456        RoadPositionQuery {
1457            road_position,
1458            nearest_position,
1459            distance,
1460        }
1461    }
1462}
1463
1464/// Represents the result of a LanePosition query.
1465/// This struct contains the `LanePosition`, the nearest `InertialPosition` to that `LanePosition`,
1466/// and the distance between the input `InertialPosition` and the nearest `InertialPosition`.
1467///
1468/// This struct is typically used as return type for the methods: [Lane::to_lane_position] and [Lane::to_segment_position].
1469pub struct LanePositionQuery {
1470    /// The candidate LanePosition within the Lane' lane-bounds or segment-bounds
1471    /// depending if [Lane::to_lane_position] or [Lane::to_segment_position] respectively, was called.
1472    /// The LanePosition is closest to a `inertial_position` supplied to [Lane::to_lane_position]
1473    /// (measured by the Cartesian metric in the `Inertial`-frame).
1474    pub lane_position: LanePosition,
1475    /// The position that exactly corresponds to `lane_position`.
1476    pub nearest_position: InertialPosition,
1477    /// The Cartesian distance between `nearest_position` and the
1478    /// `inertial_position` supplied to [Lane::to_lane_position] / [Lane::to_segment_position].
1479    pub distance: f64,
1480}
1481
1482impl LanePositionQuery {
1483    /// Create a new `LanePositionQuery` with the given `lane_position`, `nearest_position`, and `distance`.
1484    pub fn new(lane_position: LanePosition, nearest_position: InertialPosition, distance: f64) -> LanePositionQuery {
1485        LanePositionQuery {
1486            lane_position,
1487            nearest_position,
1488            distance,
1489        }
1490    }
1491}
1492
1493/// A 3-dimensional rotation in the road network.
1494/// This struct represents a rotation in the road network, which can be defined
1495/// using a quaternion or roll-pitch-yaw angles.
1496/// It provides methods to create a rotation, convert between representations,
1497/// and apply the rotation to an inertial position.
1498pub struct Rotation {
1499    r: cxx::UniquePtr<maliput_sys::api::ffi::Rotation>,
1500}
1501
1502impl Default for Rotation {
1503    fn default() -> Self {
1504        Self::new()
1505    }
1506}
1507
1508impl Rotation {
1509    /// Create a new `Rotation`.
1510    pub fn new() -> Rotation {
1511        Rotation {
1512            r: maliput_sys::api::ffi::Rotation_new(),
1513        }
1514    }
1515    /// Create a new `Rotation` from a `Quaternion`.
1516    pub fn from_quat(q: &Quaternion) -> Rotation {
1517        let q_ffi = maliput_sys::math::ffi::Quaternion_new(q.w(), q.x(), q.y(), q.z());
1518        Rotation {
1519            r: maliput_sys::api::ffi::Rotation_from_quat(&q_ffi),
1520        }
1521    }
1522    /// Create a new `Rotation` from a `RollPitchYaw`.
1523    pub fn from_rpy(rpy: &RollPitchYaw) -> Rotation {
1524        let rpy_ffi = maliput_sys::math::ffi::RollPitchYaw_new(rpy.roll_angle(), rpy.pitch_angle(), rpy.yaw_angle());
1525        Rotation {
1526            r: maliput_sys::api::ffi::Rotation_from_rpy(&rpy_ffi),
1527        }
1528    }
1529    /// Get the roll of the `Rotation`.
1530    pub fn roll(&self) -> f64 {
1531        self.r.roll()
1532    }
1533    /// Get the pitch of the `Rotation`.
1534    pub fn pitch(&self) -> f64 {
1535        self.r.pitch()
1536    }
1537    /// Get the yaw of the `Rotation`.
1538    pub fn yaw(&self) -> f64 {
1539        self.r.yaw()
1540    }
1541    /// Get a quaternion representation of the `Rotation`.
1542    pub fn quat(&self) -> Quaternion {
1543        let q_ffi = self.r.quat();
1544        Quaternion::new(q_ffi.w(), q_ffi.x(), q_ffi.y(), q_ffi.z())
1545    }
1546    /// Get a roll-pitch-yaw representation of the `Rotation`.
1547    pub fn rpy(&self) -> RollPitchYaw {
1548        let rpy_ffi = maliput_sys::api::ffi::Rotation_rpy(&self.r);
1549        RollPitchYaw::new(rpy_ffi.roll_angle(), rpy_ffi.pitch_angle(), rpy_ffi.yaw_angle())
1550    }
1551    /// Set the `Rotation` from a `Quaternion`.
1552    pub fn set_quat(&mut self, q: &Quaternion) {
1553        let q_ffi = maliput_sys::math::ffi::Quaternion_new(q.w(), q.x(), q.y(), q.z());
1554        maliput_sys::api::ffi::Rotation_set_quat(self.r.pin_mut(), &q_ffi);
1555    }
1556    /// Get the matrix representation of the `Rotation`.
1557    pub fn matrix(&self) -> Matrix3 {
1558        let matrix_ffi: cxx::UniquePtr<maliput_sys::math::ffi::Matrix3> =
1559            maliput_sys::api::ffi::Rotation_matrix(&self.r);
1560        let row_0 = maliput_sys::math::ffi::Matrix3_row(matrix_ffi.as_ref().expect(""), 0);
1561        let row_1 = maliput_sys::math::ffi::Matrix3_row(matrix_ffi.as_ref().expect(""), 1);
1562        let row_2 = maliput_sys::math::ffi::Matrix3_row(matrix_ffi.as_ref().expect(""), 2);
1563        Matrix3::new(
1564            Vector3::new(row_0.x(), row_0.y(), row_0.z()),
1565            Vector3::new(row_1.x(), row_1.y(), row_1.z()),
1566            Vector3::new(row_2.x(), row_2.y(), row_2.z()),
1567        )
1568    }
1569    /// Get the distance between two `Rotation`.
1570    pub fn distance(&self, other: &Rotation) -> f64 {
1571        self.r.Distance(&other.r)
1572    }
1573    /// Apply the `Rotation` to an `InertialPosition`.
1574    pub fn apply(&self, v: &InertialPosition) -> InertialPosition {
1575        InertialPosition {
1576            ip: maliput_sys::api::ffi::Rotation_Apply(&self.r, &v.ip),
1577        }
1578    }
1579    /// Get the reverse of the `Rotation`.
1580    pub fn reverse(&self) -> Rotation {
1581        Rotation {
1582            r: maliput_sys::api::ffi::Rotation_Reverse(&self.r),
1583        }
1584    }
1585}
1586
1587/// Directed, inclusive longitudinal (s value) range from s0 to s1.
1588pub struct SRange {
1589    s_range: cxx::UniquePtr<maliput_sys::api::ffi::SRange>,
1590}
1591
1592impl SRange {
1593    /// Creates a new `SRange` with the given `s0` and `s1`.
1594    ///
1595    /// # Arguments
1596    /// * `s0` - The starting value of the range.
1597    /// * `s1` - The ending value of the range.
1598    ///
1599    /// # Returns
1600    /// A new `SRange` instance.
1601    pub fn new(s0: f64, s1: f64) -> SRange {
1602        SRange {
1603            s_range: maliput_sys::api::ffi::SRange_new(s0, s1),
1604        }
1605    }
1606    /// Returns the s0 of the `SRange`.
1607    ///
1608    /// # Returns
1609    /// The starting value of the range.
1610    pub fn s0(&self) -> f64 {
1611        self.s_range.s0()
1612    }
1613    /// Returns the s1 of the `SRange`.
1614    ///
1615    /// # Returns
1616    /// The ending value of the range.
1617    pub fn s1(&self) -> f64 {
1618        self.s_range.s1()
1619    }
1620    /// Sets the s0 of the `SRange`.
1621    ///
1622    /// # Arguments
1623    /// * `s0` - The new starting value of the range.
1624    pub fn set_s0(&mut self, s0: f64) {
1625        self.s_range.as_mut().expect("Underlying SRange is null").set_s0(s0);
1626    }
1627    /// Sets the s1 of the `SRange`.
1628    ///
1629    /// # Arguments
1630    /// * `s1` - The new ending value of the range.
1631    pub fn set_s1(&mut self, s1: f64) {
1632        self.s_range.as_mut().expect("Underlying SRange is null").set_s1(s1);
1633    }
1634    /// Get the size of the `SRange`.
1635    ///
1636    /// # Returns
1637    /// The size of the range, which is the difference between s1 and s0.
1638    pub fn size(&self) -> f64 {
1639        self.s_range.size()
1640    }
1641    /// Defines whether this SRange is in the direction of +s (i.e., s1() > s0()).
1642    ///
1643    /// # Returns
1644    /// A boolean indicating whether the SRange is in the direction of +s.
1645    pub fn with_s(&self) -> bool {
1646        self.s_range.WithS()
1647    }
1648    /// Determines whether this SRange intersects with `s_range`.
1649    ///
1650    /// # Arguments
1651    /// * `s_range` - Another `SRange` to check for intersection.
1652    /// * `tolerance` - A tolerance value to consider when checking for intersection.
1653    ///
1654    /// # Returns
1655    /// A boolean indicating whether this SRange intersects with `s_range`.
1656    pub fn intersects(&self, s_range: &SRange, tolerance: f64) -> bool {
1657        self.s_range.Intersects(&s_range.s_range, tolerance)
1658    }
1659    /// Determines whether this SRange contains `s_range`.
1660    ///
1661    /// # Arguments
1662    /// * `s_range` - Another `SRange` to check if it is contained within this SRange.
1663    /// * `tolerance` - A tolerance value to consider when checking for containment.
1664    pub fn contains(&self, s_range: &SRange, tolerance: f64) -> bool {
1665        self.s_range.Contains(&s_range.s_range, tolerance)
1666    }
1667    /// Get the intersection of this SRange with `s_range`.
1668    ///
1669    /// # Arguments
1670    /// * `s_range` - Another `SRange` to get the intersection with.
1671    /// * `tolerance` - A tolerance value to consider when checking for intersection.
1672    ///
1673    /// # Returns
1674    /// An `Option<SRange>` containing the intersection of this SRange with `s_range`.
1675    /// If the intersection is empty, it returns None.
1676    pub fn get_intersection(&self, s_range: &SRange, tolerance: f64) -> Option<SRange> {
1677        let intersection = maliput_sys::api::ffi::SRange_GetIntersection(&self.s_range, &s_range.s_range, tolerance);
1678        match intersection.is_null() {
1679            true => None,
1680            false => Some(SRange { s_range: intersection }),
1681        }
1682    }
1683}
1684
1685impl std::fmt::Debug for SRange {
1686    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1687        write!(f, "SRange {{ s0: {}, s1: {} }}", self.s0(), self.s1())
1688    }
1689}
1690
1691/// Directed longitudinal range of a specific Lane, identified by a LaneId.
1692/// Similar to [SRange], but associated with a specific Lane.
1693pub struct LaneSRange {
1694    pub(crate) lane_s_range: cxx::UniquePtr<maliput_sys::api::ffi::LaneSRange>,
1695}
1696
1697impl LaneSRange {
1698    /// Creates a new `LaneSRange` with the given `lane_id` and `s_range`.
1699    /// # Arguments
1700    /// * `lane_id` - A `String` representing the id of the lane.
1701    /// * `s_range` - A reference to an [SRange] that defines the longitudinal range of the lane.
1702    ///
1703    /// # Returns
1704    /// A new `LaneSRange` instance.
1705    pub fn new(lane_id: &String, s_range: &SRange) -> LaneSRange {
1706        LaneSRange {
1707            lane_s_range: maliput_sys::api::ffi::LaneSRange_new(lane_id, &s_range.s_range),
1708        }
1709    }
1710    /// Returns the lane id of the `LaneSRange`.
1711    ///
1712    /// # Returns
1713    /// A `String` containing the id of the lane associated with this `LaneSRange`.
1714    pub fn lane_id(&self) -> String {
1715        maliput_sys::api::ffi::LaneSRange_lane_id(&self.lane_s_range)
1716    }
1717    /// Returns the [SRange] of the `LaneSRange`.
1718    ///
1719    /// # Returns
1720    /// An [SRange] containing the longitudinal range of the lane associated with this `LaneSRange`.
1721    pub fn s_range(&self) -> SRange {
1722        SRange {
1723            s_range: maliput_sys::api::ffi::LaneSRange_s_range(&self.lane_s_range),
1724        }
1725    }
1726    /// Returns the length of the `LaneSRange`.
1727    ///
1728    /// This is equivalent to `s_range.size()`.
1729    ///
1730    /// # Returns
1731    /// A `f64` representing the length of the `LaneSRange`.
1732    pub fn length(&self) -> f64 {
1733        self.lane_s_range.length()
1734    }
1735    /// Determines whether this LaneSRange intersects with `lane_s_range`.
1736    ///
1737    /// # Arguments
1738    /// * `lane_s_range` - Another `LaneSRange` to check for intersection.
1739    /// * `tolerance` - A tolerance value to consider when checking for intersection.
1740    ///
1741    /// # Returns
1742    /// A boolean indicating whether this LaneSRange intersects with `lane_s_range`.
1743    pub fn intersects(&self, lane_s_range: &LaneSRange, tolerance: f64) -> bool {
1744        self.lane_s_range.Intersects(&lane_s_range.lane_s_range, tolerance)
1745    }
1746    /// Determines whether this LaneSRange contains `lane_s_range`.
1747    ///
1748    /// # Arguments
1749    /// * `lane_s_range` - Another `LaneSRange` to check if it is contained within this LaneSRange.
1750    /// * `tolerance` - A tolerance value to consider when checking for containment.
1751    ///
1752    /// # Returns
1753    /// A boolean indicating whether this LaneSRange contains `lane_s_range`.
1754    /// This checks if the `s_range` of `lane_s_range` is fully contained
1755    /// within the `s_range` of this `LaneSRange`, considering the lane id.
1756    /// If the lane id does not match, it returns false.
1757    pub fn contains(&self, lane_s_range: &LaneSRange, tolerance: f64) -> bool {
1758        self.lane_s_range.Contains(&lane_s_range.lane_s_range, tolerance)
1759    }
1760    /// Computes the intersection of this `LaneSRange` with `lane_s_range`.
1761    ///
1762    /// # Arguments
1763    /// * `lane_s_range` - Another `LaneSRange` to get the intersection with.
1764    /// * `tolerance` - A tolerance value to consider when checking for intersection.
1765    ///
1766    /// # Returns
1767    /// An `Option<LaneSRange>` containing the intersection of this `LaneSRange` with `lane_s_range`.
1768    /// If the lane ids do not match, it returns None.
1769    /// If the intersection is empty, it returns None.
1770    pub fn get_intersection(&self, lane_s_range: &LaneSRange, tolerance: f64) -> Option<LaneSRange> {
1771        let intersection = maliput_sys::api::ffi::LaneSRange_GetIntersection(
1772            &self.lane_s_range,
1773            &lane_s_range.lane_s_range,
1774            tolerance,
1775        );
1776        match intersection.is_null() {
1777            true => None,
1778            false => Some(LaneSRange {
1779                lane_s_range: intersection,
1780            }),
1781        }
1782    }
1783}
1784
1785impl std::fmt::Debug for LaneSRange {
1786    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1787        write!(
1788            f,
1789            "LaneSRange {{ lane_id: {}, s_range: {:?} }}",
1790            self.lane_id(),
1791            self.s_range()
1792        )
1793    }
1794}
1795
1796/// A route, possibly spanning multiple (end-to-end) lanes.
1797///
1798/// The sequence of [LaneSRange]s should be contiguous by either presenting
1799/// laterally adjacent [LaneSRange]s, or consecutive [LaneSRange]s. (In other words,
1800/// taken as a Lane-space path with r=0 and h=0, it should present a
1801/// G1-continuous curve.)
1802pub struct LaneSRoute {
1803    lane_s_route: cxx::UniquePtr<maliput_sys::api::ffi::LaneSRoute>,
1804}
1805
1806impl LaneSRoute {
1807    /// Creates a new `LaneSRoute` with the given `ranges`.
1808    ///
1809    /// # Arguments
1810    /// * `ranges` - A vector of [LaneSRange] to create the [LaneSRoute].
1811    ///
1812    /// # Returns
1813    /// A new `LaneSRoute` instance containing the provided ranges.
1814    pub fn new(ranges: Vec<LaneSRange>) -> LaneSRoute {
1815        let mut lane_s_ranges_cpp = cxx::CxxVector::new();
1816        for range in &ranges {
1817            lane_s_ranges_cpp
1818                .as_mut()
1819                .unwrap()
1820                .push(maliput_sys::api::ffi::ConstLaneSRangeRef {
1821                    lane_s_range: &range.lane_s_range,
1822                });
1823        }
1824        LaneSRoute {
1825            lane_s_route: maliput_sys::api::ffi::LaneSRoute_new(&lane_s_ranges_cpp),
1826        }
1827    }
1828
1829    /// Returns the sequence of [LaneSRange]s.
1830    ///
1831    /// # Returns
1832    /// A vector of [LaneSRange]s that make up this [LaneSRoute].
1833    pub fn ranges(&self) -> Vec<LaneSRange> {
1834        let mut ranges = Vec::new();
1835        let lane_s_ranges = self.lane_s_route.ranges();
1836        for range in lane_s_ranges {
1837            ranges.push(LaneSRange {
1838                lane_s_range: maliput_sys::api::ffi::LaneSRange_new(
1839                    &maliput_sys::api::ffi::LaneSRange_lane_id(range),
1840                    maliput_sys::api::ffi::LaneSRange_s_range(range).as_ref().expect(""),
1841                ),
1842            })
1843        }
1844        ranges
1845    }
1846
1847    /// Computes the accumulated length of all [LaneSRange]s.
1848    ///
1849    /// # Returns
1850    /// A `f64` representing the total length of the [LaneSRoute].
1851    pub fn length(&self) -> f64 {
1852        self.lane_s_route.length()
1853    }
1854
1855    /// Determines whether this LaneSRoute intersects with `other`.
1856    ///
1857    /// # Arguments
1858    /// * `other` - The other LaneSRoute to check for intersection.
1859    /// * `tolerance` - The tolerance to use for intersection checks.
1860    ///
1861    /// # Returns
1862    /// * `true` if the two LaneSRoute intersect, `false` otherwise.
1863    pub fn intersects(&self, other: &LaneSRoute, tolerance: f64) -> bool {
1864        self.lane_s_route.Intersects(&other.lane_s_route, tolerance)
1865    }
1866}
1867
1868impl std::fmt::Debug for LaneSRoute {
1869    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1870        write!(f, "LaneSRoute {{ ranges: {:?} }}", self.ranges())
1871    }
1872}
1873
1874/// A specific endpoint of a specific Lane.
1875pub enum LaneEnd<'a> {
1876    /// The start of the Lane. ("s == 0")
1877    Start(Lane<'a>),
1878    /// The end of the Lane. ("s == length")
1879    Finish(Lane<'a>),
1880}
1881
1882impl LaneEnd<'_> {
1883    /// Gets the Lane of the `LaneEnd`.
1884    ///
1885    /// # Returns
1886    /// A reference to the [Lane] associated with this `LaneEnd`.
1887    /// This will return the Lane for both Start and Finish variants.
1888    pub fn lane(&self) -> &Lane<'_> {
1889        match self {
1890            LaneEnd::Start(lane) => lane,
1891            LaneEnd::Finish(lane) => lane,
1892        }
1893    }
1894}
1895
1896impl PartialEq for LaneEnd<'_> {
1897    fn eq(&self, other: &Self) -> bool {
1898        match self {
1899            LaneEnd::Start(lane) => match other {
1900                LaneEnd::Start(other_lane) => lane.id() == other_lane.id(),
1901                _ => false,
1902            },
1903            LaneEnd::Finish(lane) => match other {
1904                LaneEnd::Finish(other_lane) => lane.id() == other_lane.id(),
1905                _ => false,
1906            },
1907        }
1908    }
1909}
1910
1911impl Eq for LaneEnd<'_> {}
1912
1913impl std::fmt::Display for LaneEnd<'_> {
1914    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1915        match self {
1916            LaneEnd::Start(lane) => write!(f, "LaneEnd::Start({})", lane.id()),
1917            LaneEnd::Finish(lane) => write!(f, "LaneEnd::Finish({})", lane.id()),
1918        }
1919    }
1920}
1921
1922impl std::fmt::Debug for LaneEnd<'_> {
1923    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1924        match self {
1925            LaneEnd::Start(lane) => write!(f, "LaneEnd::Start({})", lane.id()),
1926            LaneEnd::Finish(lane) => write!(f, "LaneEnd::Finish({})", lane.id()),
1927        }
1928    }
1929}
1930
1931/// A set of LaneEnds.
1932pub struct LaneEndSet<'a> {
1933    lane_end_set: &'a maliput_sys::api::ffi::LaneEndSet,
1934}
1935
1936impl<'a> LaneEndSet<'a> {
1937    /// Obtains the size of the LaneEndSet.
1938    ///
1939    /// # Returns
1940    /// The number of LaneEnds in the set.
1941    pub fn size(&self) -> i32 {
1942        self.lane_end_set.size()
1943    }
1944    /// Gets the [LaneEnd] at the given index.
1945    ///
1946    /// # Arguments
1947    /// * `index` - The index of the LaneEnd to retrieve.
1948    ///
1949    /// # Returns
1950    /// A [Result<LaneEnd, MaliputError>] containing the LaneEnd at the given index.
1951    /// If the index is out of bounds, an error is returned.
1952    pub fn get(&self, index: i32) -> Result<LaneEnd<'_>, MaliputError> {
1953        let lane_end = self.lane_end_set.get(index)?;
1954        // Obtain end type and lane reference.
1955        let is_start = maliput_sys::api::ffi::LaneEnd_is_start(lane_end);
1956        let lane_ref = unsafe {
1957            maliput_sys::api::ffi::LaneEnd_lane(lane_end)
1958                .as_ref()
1959                .expect("Underlying LaneEnd is null")
1960        };
1961        // Create a LaneEnd enum variant.
1962        Ok(match is_start {
1963            true => LaneEnd::Start(Lane { lane: lane_ref }),
1964            false => LaneEnd::Finish(Lane { lane: lane_ref }),
1965        })
1966    }
1967
1968    /// Converts the LaneEndSet to a map of lane-id to LaneEnd.
1969    ///
1970    /// # Returns
1971    /// A `HashMap<String, LaneEnd>` where the key is the lane id and
1972    /// the value is the corresponding LaneEnd.
1973    pub fn to_lane_map(&self) -> std::collections::HashMap<String, LaneEnd<'_>> {
1974        (0..self.size())
1975            .map(|i| {
1976                let end = self.get(i).unwrap();
1977                (end.lane().id(), end)
1978            })
1979            .collect()
1980    }
1981}
1982
1983/// A BranchPoint is a node in the network of a RoadGeometry at which
1984/// Lanes connect to one another.  A BranchPoint is a collection of LaneEnds
1985/// specifying the Lanes (and, in particular, which ends of the Lanes) are
1986/// connected at the BranchPoint.
1987///
1988/// LaneEnds participating in a BranchPoint are grouped into two sets,
1989/// arbitrarily named "A-side" and "B-side". LaneEnds on the same "side"
1990/// have coincident into-the-lane tangent vectors, which are anti-parallel
1991/// to those of LaneEnds on the other side.
1992pub struct BranchPoint<'a> {
1993    branch_point: &'a maliput_sys::api::ffi::BranchPoint,
1994}
1995
1996impl<'a> BranchPoint<'a> {
1997    /// Returns the id of the BranchPoint.
1998    ///
1999    /// # Returns
2000    /// A `String` containing the id of the BranchPoint.
2001    pub fn id(&self) -> String {
2002        maliput_sys::api::ffi::BranchPoint_id(self.branch_point)
2003    }
2004    /// Returns the [RoadGeometry] to which this BranchPoint belongs.
2005    ///
2006    /// # Returns
2007    /// A [RoadGeometry] containing the RoadGeometry to which this BranchPoint belongs.
2008    pub fn road_geometry(&self) -> RoadGeometry<'_> {
2009        unsafe {
2010            RoadGeometry {
2011                rg: self.branch_point.road_geometry().as_ref().expect(""),
2012            }
2013        }
2014    }
2015    /// Returns the set of [LaneEnd]s on the same side as the given [LaneEnd].
2016    /// E.g: For a T-junction, this would return the set of LaneEnds on the merging side.
2017    ///
2018    /// # Arguments
2019    /// * `end` - This branch's start or end [LaneEnd].
2020    ///
2021    /// # Return
2022    /// A [LaneEndSet] of [LaneEnd]s on the same side as the given [LaneEnd].
2023    pub fn get_confluent_branches(&self, end: &LaneEnd) -> Result<LaneEndSet<'_>, MaliputError> {
2024        let lane_end_set_ptr = self.branch_point.GetConfluentBranches(
2025            BranchPoint::from_lane_end_to_ffi(end)
2026                .as_ref()
2027                .expect("Underlying LaneEnd is null"),
2028        )?;
2029        Ok(LaneEndSet {
2030            lane_end_set: unsafe { lane_end_set_ptr.as_ref().expect("Underlying LaneEndSet is null") },
2031        })
2032    }
2033    /// Returns the set of [LaneEnd]s on the opposite side as the given [LaneEnd].
2034    /// E.g: For a T-junction, this would return the [LaneEnd]s which end flows into the junction.
2035    ///
2036    /// # Arguments
2037    /// * `end` - This branch's start or end [LaneEnd].
2038    ///
2039    /// # Return
2040    /// A [LaneEndSet] of [LaneEnd]s on the opposite side as the given [LaneEnd].
2041    pub fn get_ongoing_branches(&self, end: &LaneEnd) -> Result<LaneEndSet<'_>, MaliputError> {
2042        let lane_end_set_ptr = self.branch_point.GetOngoingBranches(
2043            BranchPoint::from_lane_end_to_ffi(end)
2044                .as_ref()
2045                .expect("Underlying LaneEnd is null"),
2046        )?;
2047        Ok(LaneEndSet {
2048            lane_end_set: unsafe { lane_end_set_ptr.as_ref().expect("Underlying LaneEndSet is null") },
2049        })
2050    }
2051    /// Returns the default ongoing branch (if any) for the given `end`.
2052    /// This typically represents what would be considered "continuing
2053    /// through-traffic" from `end` (e.g., as opposed to a branch executing
2054    /// a turn).
2055    ///
2056    /// If `end` has no default-branch at this BranchPoint, the return
2057    /// value will be None.
2058    ///
2059    /// # Arguments
2060    /// * `end` - The [LaneEnd] for which to get the default branch.
2061    ///
2062    /// # Returns
2063    /// An `Option<LaneEnd>` containing the default branch if it exists.
2064    /// If no default branch exists, it returns None.
2065    pub fn get_default_branch(&self, end: &LaneEnd) -> Option<LaneEnd<'_>> {
2066        let lane_end = maliput_sys::api::ffi::BranchPoint_GetDefaultBranch(
2067            self.branch_point,
2068            BranchPoint::from_lane_end_to_ffi(end)
2069                .as_ref()
2070                .expect("Underlying LaneEnd is null"),
2071        );
2072        match lane_end.is_null() {
2073            true => None,
2074            false => {
2075                let lane_end_ref: &maliput_sys::api::ffi::LaneEnd =
2076                    lane_end.as_ref().expect("Underlying LaneEnd is null");
2077                let is_start = maliput_sys::api::ffi::LaneEnd_is_start(lane_end_ref);
2078                let lane_ref = unsafe {
2079                    maliput_sys::api::ffi::LaneEnd_lane(lane_end_ref)
2080                        .as_ref()
2081                        .expect("Underlying LaneEnd is null")
2082                };
2083                match is_start {
2084                    true => Some(LaneEnd::Start(Lane { lane: lane_ref })),
2085                    false => Some(LaneEnd::Finish(Lane { lane: lane_ref })),
2086                }
2087            }
2088        }
2089    }
2090    /// Returns the set of LaneEnds grouped together on the "A-side".
2091    ///
2092    /// # Returns
2093    /// A [LaneEndSet] containing the LaneEnds on the "A-side" of the BranchPoint.
2094    pub fn get_a_side(&self) -> LaneEndSet<'_> {
2095        let lane_end_set_ptr = self.branch_point.GetASide();
2096        LaneEndSet {
2097            lane_end_set: unsafe { lane_end_set_ptr.as_ref().expect("Underlying LaneEndSet is null") },
2098        }
2099    }
2100    /// Returns the set of LaneEnds grouped together on the "B-side".
2101    ///
2102    /// # Returns
2103    /// A [LaneEndSet] containing the LaneEnds on the "B-side" of the BranchPoint.
2104    /// This is the opposite side of the "A-side".
2105    pub fn get_b_side(&self) -> LaneEndSet<'_> {
2106        let lane_end_set_ptr = self.branch_point.GetBSide();
2107        LaneEndSet {
2108            lane_end_set: unsafe { lane_end_set_ptr.as_ref().expect("Underlying LaneEndSet is null") },
2109        }
2110    }
2111    /// Converts LaneEnd enum to LaneEnd ffi.
2112    fn from_lane_end_to_ffi(end: &LaneEnd) -> cxx::UniquePtr<maliput_sys::api::ffi::LaneEnd> {
2113        match end {
2114            LaneEnd::Start(lane) => unsafe { maliput_sys::api::ffi::LaneEnd_new(lane.lane, true) },
2115            LaneEnd::Finish(lane) => unsafe { maliput_sys::api::ffi::LaneEnd_new(lane.lane, false) },
2116        }
2117    }
2118}
2119
2120/// An abstract convenience class that aggregates information pertaining to an
2121/// intersection. Its primary purpose is to serve as a single source of this
2122/// information and to remove the need for users to query numerous disparate
2123/// data structures and state providers.
2124pub struct Intersection<'a> {
2125    intersection: &'a maliput_sys::api::ffi::Intersection,
2126}
2127
2128impl<'a> Intersection<'a> {
2129    /// Returns the id of the `Intersection` as a string.
2130    pub fn id(&self) -> String {
2131        maliput_sys::api::ffi::Intersection_id(self.intersection)
2132    }
2133    /// Returns the current `phase` of the [Intersection].
2134    ///
2135    /// Based on the current `phase`, it returns a [rules::StateProviderQuery] with the phase's ID
2136    /// and the next state.
2137    ///
2138    /// # Returns
2139    /// A [rules::StateProviderQuery] for the current [rules::Phase].
2140    pub fn phase(&self) -> rules::StateProviderQuery<String> {
2141        let query = maliput_sys::api::ffi::Intersection_Phase(self.intersection);
2142        let next_state = maliput_sys::api::rules::ffi::PhaseStateProvider_next(&query);
2143        let next_state = if next_state.is_null() {
2144            None
2145        } else {
2146            Some(rules::NextState {
2147                next_state: next_state.phase_id.clone(),
2148                duration_until: if next_state.duration_until.is_null() {
2149                    None
2150                } else {
2151                    Some(next_state.duration_until.value)
2152                },
2153            })
2154        };
2155        rules::StateProviderQuery {
2156            state: maliput_sys::api::rules::ffi::PhaseStateProvider_state(&query),
2157            next: next_state,
2158        }
2159    }
2160    /// Returns the region of the `RoadNetwork` that is considered part of the `Intersection`.
2161    ///
2162    /// # Returns
2163    /// A vector of [LaneSRange]s where the intersection lives.
2164    pub fn region(&self) -> Vec<LaneSRange> {
2165        self.intersection
2166            .region()
2167            .iter()
2168            .map(|region| LaneSRange {
2169                lane_s_range: maliput_sys::api::ffi::LaneSRange_new(
2170                    &maliput_sys::api::ffi::LaneSRange_lane_id(region),
2171                    &maliput_sys::api::ffi::LaneSRange_s_range(region),
2172                ),
2173            })
2174            .collect::<Vec<LaneSRange>>()
2175    }
2176    /// Returns the ID of the [rules::PhaseRing] that applies to this intersection.
2177    ///
2178    /// # Returns
2179    /// A `String` with the ID of a [rules::PhaseRing].
2180    pub fn phase_ring_id(&self) -> String {
2181        maliput_sys::api::ffi::Intersection_ring_id(self.intersection)
2182    }
2183    pub fn bulb_ids(&self) -> Vec<rules::UniqueBulbId> {
2184        maliput_sys::api::ffi::Intersection_unique_bulb_ids(self.intersection)
2185            .iter()
2186            .map(|unique_bulb_id| rules::UniqueBulbId {
2187                unique_bulb_id: maliput_sys::api::rules::ffi::UniqueBulbId_create_unique_ptr(unique_bulb_id),
2188            })
2189            .collect()
2190    }
2191    /// Returns the current [rules::BulbState]s within the `Intersection`.
2192    ///
2193    /// # Returns
2194    /// A vector of [rules::BulbState]s.
2195    pub fn get_bulb_state(&self, unique_bulb_id: &rules::UniqueBulbId) -> Option<rules::BulbState> {
2196        let bulb_state =
2197            maliput_sys::api::ffi::Intersection_bulb_state(self.intersection, &unique_bulb_id.unique_bulb_id);
2198        if bulb_state.is_null() {
2199            return None;
2200        }
2201        match *bulb_state {
2202            maliput_sys::api::ffi::BulbState::kOn => Some(rules::BulbState::On),
2203            maliput_sys::api::ffi::BulbState::kOff => Some(rules::BulbState::Off),
2204            maliput_sys::api::ffi::BulbState::kBlinking => Some(rules::BulbState::Blinking),
2205            _ => None,
2206        }
2207    }
2208    /// Returns the current discrete value rule states within the intersection.
2209    pub fn discrete_value_rule_states(&self) -> Vec<rules::DiscreteValueRuleState> {
2210        maliput_sys::api::ffi::Intersection_DiscreteValueRuleStates(self.intersection)
2211            .iter()
2212            .map(|dvrs| rules::DiscreteValueRuleState {
2213                rule_id: dvrs.rule_id.clone(),
2214                state: rules::discrete_value_from_discrete_value_cxx(&dvrs.state),
2215            })
2216            .collect::<Vec<rules::DiscreteValueRuleState>>()
2217    }
2218    /// Determines whether the [rules::TrafficLight] is within this [Intersection].
2219    ///
2220    /// # Arguments
2221    /// * `traffic_light_id` - A [rules::TrafficLight] ID.
2222    ///
2223    /// # Returns
2224    /// True when `traffic_light_id` is within this [Intersection].
2225    pub fn includes_traffic_light(&self, traffic_light_id: &str) -> bool {
2226        maliput_sys::api::ffi::Intersection_IncludesTrafficLight(self.intersection, &traffic_light_id.to_string())
2227    }
2228    /// Determines whether the [rules::DiscreteValueRule] is within this [Intersection].
2229    ///
2230    /// # Arguments
2231    /// * `rule_id` - A [rules::DiscreteValueRule] ID.
2232    ///
2233    /// # Returns
2234    /// True when `rule_id` is within this [Intersection].
2235    pub fn includes_discrete_value_rule(&self, rule_id: &str) -> bool {
2236        maliput_sys::api::ffi::Intersection_IncludesDiscreteValueRule(self.intersection, &rule_id.to_string())
2237    }
2238    /// Determines whether `inertial_position` is within this [Intersection::region].
2239    ///
2240    /// `inertial_position` is contained if the distance to the closest LanePosition in
2241    /// [Intersection::region] is less or equal than the linear tolerance of the `road_geometry`.
2242    ///
2243    /// # Arguments
2244    /// * `inertial_position` -  An [InertialPosition] in the `Inertial`-frame.
2245    /// * `road_geometry` - The [RoadGeometry].
2246    ///
2247    /// # Returns
2248    /// True when `inertial_position` is within [Intersection::region]. False otherwise.
2249    pub fn includes_inertial_position(
2250        &self,
2251        inertial_position: &InertialPosition,
2252        road_geometry: &RoadGeometry,
2253    ) -> bool {
2254        maliput_sys::api::ffi::Intersection_IncludesInertialPosition(
2255            self.intersection,
2256            &maliput_sys::api::ffi::InertialPosition_new(
2257                inertial_position.x(),
2258                inertial_position.y(),
2259                inertial_position.z(),
2260            ),
2261            road_geometry.rg,
2262        )
2263    }
2264}
2265
2266/// A book of Intersections.
2267pub struct IntersectionBook<'a> {
2268    intersection_book: &'a maliput_sys::api::ffi::IntersectionBook,
2269}
2270
2271impl<'a> IntersectionBook<'a> {
2272    /// Returns all Intersections in the book.
2273    ///
2274    /// # Returns
2275    /// A vector of [Intersection]s containing all Intersections in the book.
2276    pub fn get_intersections(&self) -> Vec<Intersection<'_>> {
2277        let intersections_cpp = maliput_sys::api::ffi::IntersectionBook_GetIntersections(self.intersection_book);
2278        unsafe {
2279            intersections_cpp
2280                .into_iter()
2281                .map(|intersection| Intersection {
2282                    intersection: intersection
2283                        .intersection
2284                        .as_ref()
2285                        .expect("Underlying Intersection is null"),
2286                })
2287                .collect::<Vec<Intersection>>()
2288        }
2289    }
2290
2291    /// Gets the specified Intersection.
2292    ///
2293    /// # Arguments
2294    ///   * `id` - The id of the Intersection to get.
2295    ///
2296    /// # Returns
2297    ///   * An `Option<Intersection>`
2298    ///     * Some(Intersection) - The Intersection with the specified id.
2299    ///     * None - If the Intersection with the specified id does not exist.
2300    pub fn get_intersection(&self, id: &str) -> Option<Intersection<'_>> {
2301        let intersection_option = unsafe {
2302            maliput_sys::api::ffi::IntersectionBook_GetIntersection(self.intersection_book, &String::from(id))
2303                .intersection
2304                .as_ref()
2305        };
2306        intersection_option.map(|intersection| Intersection { intersection })
2307    }
2308
2309    /// Finds the [Intersection] which contains the `traffic_light_id`.
2310    ///
2311    /// # Arguments
2312    /// * `traffic_light_id` - A String with the ID of a [rules::TrafficLight].
2313    ///
2314    /// # Returns
2315    /// The [Intersection] which contains the `traffic_light_id`.
2316    pub fn find_intersection_with_traffic_light(&self, traffic_light_id: &str) -> Option<Intersection<'_>> {
2317        let intersection = maliput_sys::api::ffi::IntersectionBook_FindIntersectionTrafficLight(
2318            self.intersection_book,
2319            &String::from(traffic_light_id),
2320        );
2321        if intersection.intersection.is_null() {
2322            return None;
2323        }
2324        unsafe {
2325            Some(Intersection {
2326                intersection: intersection
2327                    .intersection
2328                    .as_ref()
2329                    .expect("Underlying Intersection is null"),
2330            })
2331        }
2332    }
2333
2334    /// Finds the [Intersection] which contains the `rule_id`.
2335    ///
2336    /// # Arguments
2337    /// * `rule_id` - A String with the ID of a [rules::DiscreteValueRule].
2338    ///
2339    /// # Returns
2340    /// The [Intersection] which contains the `rule_id`.
2341    pub fn find_intersection_with_discrete_value_rule(&self, rule_id: &str) -> Option<Intersection<'_>> {
2342        let intersection = maliput_sys::api::ffi::IntersectionBook_FindIntersectionDiscreteValueRule(
2343            self.intersection_book,
2344            &String::from(rule_id),
2345        );
2346        if intersection.intersection.is_null() {
2347            return None;
2348        }
2349        unsafe {
2350            Some(Intersection {
2351                intersection: intersection
2352                    .intersection
2353                    .as_ref()
2354                    .expect("Underlying Intersection is null"),
2355            })
2356        }
2357    }
2358
2359    /// Finds the [Intersection] which contains the `inertial_position`.
2360    ///
2361    /// # Arguments
2362    /// * `inertial_position` - An [InertialPosition] to find the [Intersection] for.
2363    ///
2364    /// # Returns
2365    /// The [Intersection] which contains the `inertial_position`.
2366    pub fn find_intersection_with_inertial_position(
2367        &self,
2368        inertial_position: &InertialPosition,
2369    ) -> Option<Intersection<'_>> {
2370        let intersection = maliput_sys::api::ffi::IntersectionBook_FindIntersectionInertialPosition(
2371            self.intersection_book,
2372            &inertial_position.ip,
2373        );
2374        if intersection.intersection.is_null() {
2375            return None;
2376        }
2377        unsafe {
2378            Some(Intersection {
2379                intersection: intersection
2380                    .intersection
2381                    .as_ref()
2382                    .expect("Underlying Intersection is null"),
2383            })
2384        }
2385    }
2386}
2387
2388mod tests {
2389    mod road_geometry {
2390        #[test]
2391        fn to_road_position_surface_test() {
2392            let package_location = std::env::var("CARGO_MANIFEST_DIR").unwrap();
2393            let xodr_path = format!("{}/data/xodr/TShapeRoad.xodr", package_location);
2394            let road_network_properties = std::collections::HashMap::from([
2395                ("road_geometry_id", "my_rg_from_rust"),
2396                ("opendrive_file", xodr_path.as_str()),
2397            ]);
2398            let road_network = crate::api::RoadNetwork::new("maliput_malidrive", &road_network_properties).unwrap();
2399            let road_geometry = road_network.road_geometry();
2400
2401            // Although this isn't directly on the surface, it is within the RoadGeometry volume.
2402            let inertial_pos = crate::api::InertialPosition::new(1.0, 0.0, 2.0);
2403            let road_pos = road_geometry.to_road_position_surface(&inertial_pos);
2404            assert!(road_pos.is_ok());
2405            let road_pos = road_pos.unwrap();
2406            let tolerance = 1e-3;
2407            assert!((road_pos.pos().s() - 1.0).abs() < tolerance);
2408            assert!((road_pos.pos().r() - -1.75).abs() < tolerance);
2409            assert!((road_pos.pos().h() - 0.0).abs() < tolerance);
2410
2411            // An inertial position that is off the road volume.
2412            let inertial_pos = crate::api::InertialPosition::new(1.0, 0.0, 10.0);
2413            let road_pos = road_geometry.to_road_position_surface(&inertial_pos);
2414            assert!(road_pos.is_err());
2415        }
2416    }
2417    mod lane_position {
2418        #[test]
2419        fn lane_position_new() {
2420            let lane_pos = crate::api::LanePosition::new(1.0, 2.0, 3.0);
2421            assert_eq!(lane_pos.s(), 1.0);
2422            assert_eq!(lane_pos.r(), 2.0);
2423            assert_eq!(lane_pos.h(), 3.0);
2424        }
2425
2426        #[test]
2427        fn equality() {
2428            let v = crate::api::LanePosition::new(1.0, 2.0, 3.0);
2429            let w = crate::api::LanePosition::new(1.0, 2.0, 3.0);
2430            assert_eq!(v, w);
2431            let z = crate::api::LanePosition::new(4.0, 5.0, 6.0);
2432            assert_ne!(v, z);
2433        }
2434
2435        #[test]
2436        fn set_s() {
2437            let mut lane_pos = crate::api::LanePosition::new(1.0, 2.0, 3.0);
2438            lane_pos.set_s(4.0);
2439            assert_eq!(lane_pos.s(), 4.0);
2440        }
2441
2442        #[test]
2443        fn set_r() {
2444            let mut lane_pos = crate::api::LanePosition::new(1.0, 2.0, 3.0);
2445            lane_pos.set_r(4.0);
2446            assert_eq!(lane_pos.r(), 4.0);
2447        }
2448
2449        #[test]
2450        fn set_h() {
2451            let mut lane_pos = crate::api::LanePosition::new(1.0, 2.0, 3.0);
2452            lane_pos.set_h(4.0);
2453            assert_eq!(lane_pos.h(), 4.0);
2454        }
2455
2456        #[test]
2457        fn set_srh() {
2458            use crate::math::Vector3;
2459            let mut lane_pos = crate::api::LanePosition::new(1.0, 2.0, 3.0);
2460            let vector = Vector3::new(4.0, 5.0, 6.0);
2461            lane_pos.set_srh(&vector);
2462            assert_eq!(lane_pos.s(), 4.0);
2463            assert_eq!(lane_pos.r(), 5.0);
2464            assert_eq!(lane_pos.h(), 6.0);
2465        }
2466    }
2467
2468    mod inertial_position {
2469
2470        #[test]
2471        fn inertial_position_new() {
2472            let inertial_pos = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
2473            assert_eq!(inertial_pos.x(), 1.0);
2474            assert_eq!(inertial_pos.y(), 2.0);
2475            assert_eq!(inertial_pos.z(), 3.0);
2476        }
2477
2478        #[test]
2479        fn equality() {
2480            let v = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
2481            let w = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
2482            assert_eq!(v, w);
2483            let z = crate::api::InertialPosition::new(4.0, 5.0, 6.0);
2484            assert_ne!(v, z);
2485        }
2486
2487        #[test]
2488        fn set_x() {
2489            let mut inertial_pos = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
2490            inertial_pos.set_x(4.0);
2491            assert_eq!(inertial_pos.x(), 4.0);
2492        }
2493
2494        #[test]
2495        fn set_y() {
2496            let mut inertial_pos = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
2497            inertial_pos.set_y(4.0);
2498            assert_eq!(inertial_pos.y(), 4.0);
2499        }
2500
2501        #[test]
2502        fn set_z() {
2503            let mut inertial_pos = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
2504            inertial_pos.set_z(4.0);
2505            assert_eq!(inertial_pos.z(), 4.0);
2506        }
2507
2508        #[test]
2509        fn set_xyz() {
2510            use crate::math::Vector3;
2511            let mut inertial_pos = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
2512            let vector = Vector3::new(4.0, 5.0, 6.0);
2513            inertial_pos.set_xyz(&vector);
2514            assert_eq!(inertial_pos.x(), 4.0);
2515            assert_eq!(inertial_pos.y(), 5.0);
2516            assert_eq!(inertial_pos.z(), 6.0);
2517        }
2518
2519        #[test]
2520        fn xyz() {
2521            let inertial_pos = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
2522            assert_eq!(inertial_pos.xyz(), crate::math::Vector3::new(1.0, 2.0, 3.0));
2523        }
2524
2525        #[test]
2526        fn length() {
2527            let inertial_pos = crate::api::InertialPosition::new(3.0, 0.0, 4.0);
2528            assert_eq!(inertial_pos.length(), 5.0);
2529        }
2530
2531        #[test]
2532        fn distance() {
2533            let inertial_pos1 = crate::api::InertialPosition::new(1.0, 1.0, 1.0);
2534            let inertial_pos2 = crate::api::InertialPosition::new(5.0, 1.0, 1.0);
2535            assert_eq!(inertial_pos1.distance(&inertial_pos2), 4.0);
2536        }
2537
2538        #[test]
2539        fn str() {
2540            let inertial_pos = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
2541            assert_eq!(inertial_pos.to_string(), "(x = 1, y = 2, z = 3)");
2542        }
2543
2544        #[test]
2545        fn add_operation() {
2546            let inertial_pos1 = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
2547            let inertial_pos2 = crate::api::InertialPosition::new(4.0, 5.0, 6.0);
2548            let inertial_pos3 = inertial_pos1 + inertial_pos2;
2549            assert_eq!(inertial_pos3.x(), 5.0);
2550            assert_eq!(inertial_pos3.y(), 7.0);
2551            assert_eq!(inertial_pos3.z(), 9.0);
2552        }
2553
2554        #[test]
2555        fn sub_operation() {
2556            let inertial_pos1 = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
2557            let inertial_pos2 = crate::api::InertialPosition::new(4.0, 5.0, 6.0);
2558            let inertial_pos3 = inertial_pos1 - inertial_pos2;
2559            assert_eq!(inertial_pos3.x(), -3.0);
2560            assert_eq!(inertial_pos3.y(), -3.0);
2561            assert_eq!(inertial_pos3.z(), -3.0);
2562        }
2563
2564        #[test]
2565        fn mul_scalar_operation() {
2566            let inertial_pos1 = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
2567            let inertial_pos2 = inertial_pos1 * 2.0;
2568            assert_eq!(inertial_pos2.x(), 2.0);
2569            assert_eq!(inertial_pos2.y(), 4.0);
2570            assert_eq!(inertial_pos2.z(), 6.0);
2571        }
2572    }
2573    mod rotation {
2574        #[test]
2575        fn rotation_new() {
2576            let rotation = crate::api::Rotation::new();
2577            assert_eq!(rotation.roll(), 0.0);
2578            assert_eq!(rotation.pitch(), 0.0);
2579            assert_eq!(rotation.yaw(), 0.0);
2580        }
2581
2582        #[test]
2583        fn from_quat() {
2584            let quat = crate::math::Quaternion::new(1.0, 0.0, 0.0, 0.0);
2585            let rotation = crate::api::Rotation::from_quat(&quat);
2586            assert_eq!(rotation.roll(), 0.0);
2587            assert_eq!(rotation.pitch(), 0.0);
2588            assert_eq!(rotation.yaw(), 0.0);
2589        }
2590
2591        #[test]
2592        fn from_rpy() {
2593            let rpy = crate::math::RollPitchYaw::new(0.0, 0.0, 0.0);
2594            let rotation = crate::api::Rotation::from_rpy(&rpy);
2595            assert_eq!(rotation.roll(), 0.0);
2596            assert_eq!(rotation.pitch(), 0.0);
2597            assert_eq!(rotation.yaw(), 0.0);
2598        }
2599
2600        #[test]
2601        fn set_quat() {
2602            let mut rotation = crate::api::Rotation::new();
2603            let quat = crate::math::Quaternion::new(1.0, 0.0, 0.0, 0.0);
2604            rotation.set_quat(&quat);
2605            assert_eq!(rotation.roll(), 0.0);
2606            assert_eq!(rotation.pitch(), 0.0);
2607            assert_eq!(rotation.yaw(), 0.0);
2608        }
2609
2610        #[test]
2611        fn matrix() {
2612            let rotation = crate::api::Rotation::new();
2613            let matrix = rotation.matrix();
2614            assert_eq!(matrix.row(0), crate::math::Vector3::new(1.0, 0.0, 0.0));
2615            assert_eq!(matrix.row(1), crate::math::Vector3::new(0.0, 1.0, 0.0));
2616            assert_eq!(matrix.row(2), crate::math::Vector3::new(0.0, 0.0, 1.0));
2617        }
2618    }
2619
2620    mod s_range {
2621        #[test]
2622        fn s_range_new() {
2623            let s_range = crate::api::SRange::new(1.0, 2.0);
2624            assert_eq!(s_range.s0(), 1.0);
2625            assert_eq!(s_range.s1(), 2.0);
2626        }
2627        #[test]
2628        fn s_range_api() {
2629            let s_range_1 = crate::api::SRange::new(1.0, 3.0);
2630            let s_range_2 = crate::api::SRange::new(2.0, 4.0);
2631            assert_eq!(s_range_1.size(), 2.0);
2632            assert!(s_range_1.with_s());
2633            assert!(s_range_1.intersects(&s_range_2, 0.0));
2634            assert!(!s_range_1.contains(&s_range_2, 0.0));
2635        }
2636        #[test]
2637        fn s_range_setters() {
2638            let mut s_range = crate::api::SRange::new(0.0, 4.0);
2639            s_range.set_s0(1.0);
2640            s_range.set_s1(3.0);
2641            assert_eq!(s_range.s0(), 1.0);
2642            assert_eq!(s_range.s1(), 3.0);
2643        }
2644        #[test]
2645        fn s_range_get_intersection_with_intersection() {
2646            let s_range_1 = crate::api::SRange::new(1.0, 3.0);
2647            let s_range_2 = crate::api::SRange::new(2.0, 4.0);
2648            let intersection = s_range_1.get_intersection(&s_range_2, 0.0);
2649            assert!(intersection.is_some());
2650            let intersection = intersection.unwrap();
2651            assert_eq!(intersection.s0(), 2.0);
2652            assert_eq!(intersection.s1(), 3.0);
2653        }
2654        #[test]
2655        fn s_range_get_intersection_with_no_intersection() {
2656            let s_range_1 = crate::api::SRange::new(1.0, 2.0);
2657            let s_range_2 = crate::api::SRange::new(3.0, 4.0);
2658            let intersection = s_range_1.get_intersection(&s_range_2, 0.0);
2659            assert!(intersection.is_none());
2660        }
2661    }
2662
2663    mod lane_s_range {
2664        #[test]
2665        fn lane_s_range_new() {
2666            let lane_s_range =
2667                crate::api::LaneSRange::new(&String::from("lane_test"), &crate::api::SRange::new(1.0, 2.0));
2668            assert_eq!(lane_s_range.lane_id(), "lane_test");
2669            assert_eq!(lane_s_range.s_range().s0(), 1.0);
2670            assert_eq!(lane_s_range.s_range().s1(), 2.0);
2671            assert_eq!(lane_s_range.length(), 1.0);
2672        }
2673        #[test]
2674        fn lane_s_range_api() {
2675            let lane_s_range_1 =
2676                crate::api::LaneSRange::new(&String::from("lane_test"), &crate::api::SRange::new(1.0, 2.0));
2677            let lane_s_range_2 =
2678                crate::api::LaneSRange::new(&String::from("lane_test"), &crate::api::SRange::new(2.0, 3.0));
2679            assert!(lane_s_range_1.intersects(&lane_s_range_2, 0.0));
2680            assert!(!lane_s_range_1.contains(&lane_s_range_2, 0.0));
2681        }
2682        #[test]
2683        fn lane_s_range_get_intersection_with_intersection() {
2684            let lane_s_range_1 =
2685                crate::api::LaneSRange::new(&String::from("lane_test"), &crate::api::SRange::new(1.0, 3.0));
2686            let lane_s_range_2 =
2687                crate::api::LaneSRange::new(&String::from("lane_test"), &crate::api::SRange::new(2.0, 4.0));
2688            let intersection = lane_s_range_1.get_intersection(&lane_s_range_2, 0.0);
2689            assert!(intersection.is_some());
2690            let intersection = intersection.unwrap();
2691            assert_eq!(intersection.lane_id(), "lane_test");
2692            assert_eq!(intersection.s_range().s0(), 2.0);
2693            assert_eq!(intersection.s_range().s1(), 3.0);
2694        }
2695        #[test]
2696        fn lane_s_range_get_intersection_with_no_intersection() {
2697            let lane_s_range_1 =
2698                crate::api::LaneSRange::new(&String::from("lane test_1"), &crate::api::SRange::new(1.0, 3.0));
2699            let lane_s_range_2 =
2700                crate::api::LaneSRange::new(&String::from("lane_test_2"), &crate::api::SRange::new(2.0, 4.0));
2701            let intersection = lane_s_range_1.get_intersection(&lane_s_range_2, 0.0);
2702            assert!(intersection.is_none());
2703        }
2704    }
2705
2706    mod lane_s_route {
2707        // Helper function to create a LaneSRoute
2708        // with two LaneSRange.
2709        // # Arguments
2710        // * `s0_0` - The s0 of the first LaneSRange.
2711        // * `s1_0` - The s1 of the first LaneSRange.
2712        // * `s0_1` - The s0 of the second LaneSRange.
2713        // * `s1_1` - The s1 of the second LaneSRange.
2714        fn _get_lane_s_route(s0_0: f64, s1_0: f64, s0_1: f64, s1_1: f64) -> crate::api::LaneSRoute {
2715            let ranges = vec![
2716                crate::api::LaneSRange::new(&String::from("lane_test_1"), &crate::api::SRange::new(s0_0, s1_0)),
2717                crate::api::LaneSRange::new(&String::from("lane_test_2"), &crate::api::SRange::new(s0_1, s1_1)),
2718            ];
2719            crate::api::LaneSRoute::new(ranges)
2720        }
2721        #[test]
2722        fn lane_s_route_new() {
2723            let lane_s_route = _get_lane_s_route(0., 10., 0., 15.);
2724            assert!(!lane_s_route.lane_s_route.is_null());
2725            let ranges = lane_s_route.ranges();
2726            assert_eq!(ranges.len(), 2);
2727            assert_eq!(ranges[0].lane_id(), "lane_test_1");
2728            assert_eq!(ranges[1].lane_id(), "lane_test_2");
2729        }
2730        #[test]
2731        fn lane_s_route_length() {
2732            let lane_s_route = _get_lane_s_route(0., 10., 0., 15.);
2733            assert_eq!(lane_s_route.length(), 25.0);
2734        }
2735        #[test]
2736        fn lane_s_route_intersects() {
2737            let lane_s_route = _get_lane_s_route(0., 10., 0., 10.);
2738            let lane_s_route_that_intersects = _get_lane_s_route(5., 9., 5., 9.);
2739            let lane_s_route_that_not_intersects = _get_lane_s_route(11., 20., 11., 20.);
2740            assert!(lane_s_route.intersects(&lane_s_route_that_intersects, 0.0));
2741            assert!(!lane_s_route.intersects(&lane_s_route_that_not_intersects, 0.0));
2742        }
2743    }
2744}