Skip to main content

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 objects;
38pub mod rules;
39
40/// Enumerates the available maliput road network backends.
41///
42/// Each variant corresponds to a plugin that implements the `RoadNetworkLoader` interface.
43/// The string representation matches the plugin ID expected by the C++ `MaliputPluginManager`.
44///
45/// Which variants are available depends on the enabled features:
46/// - `maliput_malidrive` (default): Enables the `MaliputMalidrive` variant.
47/// - `maliput_geopackage` (opt-in): Enables the `MaliputGeopackage` variant.
48///
49/// # Example
50///
51/// ```rust
52/// use maliput::api::RoadNetworkBackend;
53///
54/// let backend = RoadNetworkBackend::MaliputMalidrive;
55/// assert_eq!(backend.to_string(), "maliput_malidrive");
56/// ```
57#[derive(Debug, Clone, Copy, PartialEq, Eq, strum_macros::Display, strum_macros::EnumString)]
58pub enum RoadNetworkBackend {
59    /// The `maliput_malidrive` backend. Loads road networks from OpenDRIVE (`.xodr`) files.
60    #[cfg(feature = "maliput_malidrive")]
61    #[strum(serialize = "maliput_malidrive")]
62    MaliputMalidrive,
63    /// The `maliput_geopackage` backend. Loads road networks from GeoPackage (`.gpkg`) files.
64    #[cfg(feature = "maliput_geopackage")]
65    #[strum(serialize = "maliput_geopackage")]
66    MaliputGeopackage,
67}
68
69/// Represents a complete Maliput road network.
70///
71/// A `RoadNetwork` is the main entry point for interacting with a road map in Maliput.
72/// It serves as a container for all the elements that describe a road network,
73/// including its physical layout and the rules of the road.
74///
75/// It provides access to the following key components:
76///
77/// * [`RoadGeometry`]: The geometric description of the road surfaces.
78/// * [`rules::RoadRulebook`]: The set of traffic rules, like speed limits and right-of-way.
79/// * [`rules::TrafficLightBook`]: A catalog of all traffic lights in the network.
80/// * [`IntersectionBook`]: A collection of logical intersections and their states.
81///   TODO: Complete with other books when available (e.g., `RuleRegistry / PhaseRingBook / etc)
82///
83/// More info can be found at https://maliput.readthedocs.io/en/latest/html/deps/maliput/html/maliput_design.html.
84///
85/// # Example
86///
87/// ```rust, no_run
88/// use maliput::api::{RoadNetwork, RoadNetworkBackend};
89/// use std::collections::HashMap;
90///
91/// // Properties to load an OpenDRIVE file using the maliput_malidrive backend.
92/// let package_location = std::env::var("CARGO_MANIFEST_DIR").unwrap();
93/// let xodr_path = format!("{}/data/xodr/TShapeRoad.xodr", package_location);
94/// let road_network_properties = HashMap::from([("road_geometry_id", "my_rg_from_rust"), ("opendrive_file", xodr_path.as_str())]);
95///
96/// // Create the RoadNetwork by specifying the backend and properties.
97/// let road_network = RoadNetwork::new(RoadNetworkBackend::MaliputMalidrive, &road_network_properties).unwrap();
98/// ```
99pub struct RoadNetwork {
100    pub(crate) rn: cxx::UniquePtr<maliput_sys::api::ffi::RoadNetwork>,
101}
102
103impl RoadNetwork {
104    /// Create a new `RoadNetwork` with the given `backend` and `properties`.
105    ///
106    /// # Arguments
107    ///
108    /// * `backend` - The backend to use for loading the road network. See [`RoadNetworkBackend`].
109    /// * `properties` - The properties of the road network.
110    ///
111    /// # Details
112    /// It relies on `maliput_sys::plugin::ffi::CreateRoadNetwork` to create a new `RoadNetwork`.
113    ///
114    /// # Returns
115    /// A result containing the `RoadNetwork` or a `MaliputError` if the creation fails.
116    #[allow(clippy::vec_init_then_push)]
117    pub fn new(
118        backend: RoadNetworkBackend,
119        properties: &std::collections::HashMap<&str, &str>,
120    ) -> Result<RoadNetwork, MaliputError> {
121        // Translate the properties to ffi types
122        let mut properties_vec = Vec::new();
123        for (key, value) in properties.iter() {
124            properties_vec.push(format!("{}:{}", key, value));
125        }
126        // If MALIPUT_PLUGIN_PATH is not set, it will be created.
127        let new_path = match std::env::var_os("MALIPUT_PLUGIN_PATH") {
128            Some(current_path) => {
129                // Add the plugin paths obtained from maliput_sdk to MALIPUT_PLUGIN_PATH.
130                // These are added first in the list as the plugins are loaded sequentially and we
131                // want these to be used only when no others are present. (typically in dev mode).
132                let mut new_paths = vec![];
133                #[cfg(feature = "maliput_malidrive")]
134                new_paths.push(maliput_sdk::get_maliput_malidrive_plugin_path());
135                #[cfg(feature = "maliput_geopackage")]
136                new_paths.push(maliput_sdk::get_maliput_geopackage_plugin_path());
137                new_paths.extend(std::env::split_paths(&current_path).collect::<Vec<_>>());
138                std::env::join_paths(new_paths).unwrap()
139            }
140            None => {
141                let mut paths = vec![];
142                #[cfg(feature = "maliput_malidrive")]
143                paths.push(maliput_sdk::get_maliput_malidrive_plugin_path());
144                #[cfg(feature = "maliput_geopackage")]
145                paths.push(maliput_sdk::get_maliput_geopackage_plugin_path());
146                std::env::join_paths(paths).unwrap()
147            }
148        };
149        std::env::set_var("MALIPUT_PLUGIN_PATH", new_path);
150        let rn = maliput_sys::plugin::ffi::CreateRoadNetwork(&backend.to_string(), &properties_vec)?;
151        Ok(RoadNetwork { rn })
152    }
153
154    /// Get the `RoadGeometry` of the `RoadNetwork`.
155    pub fn road_geometry(&self) -> RoadGeometry<'_> {
156        unsafe {
157            RoadGeometry {
158                rg: self.rn.road_geometry().as_ref().expect(""),
159            }
160        }
161    }
162    /// Get the `IntersectionBook` of the `RoadNetwork`.
163    pub fn intersection_book(&self) -> IntersectionBook<'_> {
164        let intersection_book_ffi = maliput_sys::api::ffi::RoadNetwork_intersection_book(&self.rn);
165        IntersectionBook {
166            intersection_book: unsafe {
167                intersection_book_ffi
168                    .as_ref()
169                    .expect("Underlying IntersectionBook is null")
170            },
171        }
172    }
173    /// Get the `TrafficLightBook` of the `RoadNetwork`.
174    pub fn traffic_light_book(&self) -> rules::TrafficLightBook<'_> {
175        let traffic_light_book_ffi = self.rn.traffic_light_book();
176        rules::TrafficLightBook {
177            traffic_light_book: unsafe {
178                traffic_light_book_ffi
179                    .as_ref()
180                    .expect("Underlying TrafficLightBook is null")
181            },
182        }
183    }
184
185    /// Get the `RoadObjectBook` of the `RoadNetwork`.
186    pub fn road_object_book(&self) -> objects::RoadObjectBook<'_> {
187        let road_object_book_ffi = self.rn.road_object_book();
188        objects::RoadObjectBook {
189            road_object_book: unsafe {
190                road_object_book_ffi
191                    .as_ref()
192                    .expect("Underlying RoadObjectBook is null")
193            },
194        }
195    }
196
197    /// Get the `RoadMarkingBook` of the `RoadNetwork`.
198    pub fn road_marking_book(&self) -> objects::RoadMarkingBook<'_> {
199        let road_marking_book_ffi = self.rn.road_marking_book();
200        objects::RoadMarkingBook {
201            road_marking_book: unsafe {
202                road_marking_book_ffi
203                    .as_ref()
204                    .expect("Underlying RoadMarkingBook is null")
205            },
206        }
207    }
208
209    /// Get the `TrafficSignBook` of the `RoadNetwork`.
210    pub fn traffic_sign_book(&self) -> rules::TrafficSignBook<'_> {
211        let traffic_sign_book_ffi = self.rn.traffic_sign_book();
212        rules::TrafficSignBook {
213            traffic_sign_book: unsafe {
214                traffic_sign_book_ffi
215                    .as_ref()
216                    .expect("Underlying TrafficSignBook is null")
217            },
218        }
219    }
220
221    /// Get the `RoadRulebook` of the `RoadNetwork`.
222    pub fn rulebook(&self) -> rules::RoadRulebook<'_> {
223        let rulebook_ffi = self.rn.rulebook();
224        rules::RoadRulebook {
225            road_rulebook: unsafe { rulebook_ffi.as_ref().expect("Underlying RoadRulebook is null") },
226        }
227    }
228
229    /// Get the `PhaseRingBook` of the `RoadNetwork`.
230    pub fn phase_ring_book(&self) -> rules::PhaseRingBook<'_> {
231        let phase_ring_book_ffi = self.rn.phase_ring_book();
232        rules::PhaseRingBook {
233            phase_ring_book: unsafe { phase_ring_book_ffi.as_ref().expect("Underlying PhaseRingBook is null") },
234        }
235    }
236
237    /// Get the `RuleRegistry` of the `RoadNetwork`.
238    pub fn rule_registry(&self) -> rules::RuleRegistry<'_> {
239        let rule_registry_ffi = self.rn.rule_registry();
240        rules::RuleRegistry {
241            rule_registry: unsafe { rule_registry_ffi.as_ref().expect("Underlying RuleRegistry is null") },
242        }
243    }
244
245    /// Get the `PhaseProvider` of the `RoadNetwork`.
246    pub fn phase_provider(&self) -> rules::PhaseProvider<'_> {
247        let phase_provider_ffi = maliput_sys::api::ffi::RoadNetwork_phase_provider(&self.rn);
248        rules::PhaseProvider {
249            phase_provider: unsafe { phase_provider_ffi.as_ref().expect("Underlying PhaseProvider is null") },
250        }
251    }
252
253    /// Get the `DiscreteValueRuleStateProvider` of the `RoadNetwork`.
254    pub fn discrete_value_rule_state_provider(&self) -> rules::DiscreteValueRuleStateProvider<'_> {
255        let state_provider = maliput_sys::api::ffi::RoadNetwork_discrete_value_rule_state_provider(&self.rn);
256        rules::DiscreteValueRuleStateProvider {
257            state_provider: unsafe {
258                state_provider
259                    .as_ref()
260                    .expect("Underlying DiscreteValueRuleStateProvider is null")
261            },
262        }
263    }
264
265    /// Get the `RangeValueRuleStateProvider` of the `RoadNetwork`.
266    pub fn range_value_rule_state_provider(&self) -> rules::RangeValueRuleStateProvider<'_> {
267        let state_provider = maliput_sys::api::ffi::RoadNetwork_range_value_rule_state_provider(&self.rn);
268        rules::RangeValueRuleStateProvider {
269            state_provider: unsafe {
270                state_provider
271                    .as_ref()
272                    .expect("Underlying RangeValueRuleStateProvider is null")
273            },
274        }
275    }
276}
277
278/// Represents the geometry of a road network.
279///
280/// `RoadGeometry` is the top-level container for the road network's geometric
281/// description. It is composed of a set of `Junction`s, which in turn contain
282/// `Segment`s and `Lane`s.
283///
284/// It provides access to the entire road network's geometric structure,
285/// allowing for queries about its components (e.g., finding a `Lane` by its ID)
286/// and for coordinate conversions between the inertial frame and the road network's
287/// intrinsic coordinate systems (lane coordinates).
288///
289/// An instance of `RoadGeometry` is typically obtained from a `RoadNetwork`.
290///
291/// More info can be found at https://maliput.readthedocs.io/en/latest/html/deps/maliput/html/maliput_design.html.
292///
293/// # Example of obtaining a `RoadGeometry`
294///
295/// ```rust, no_run
296/// use maliput::api::{RoadNetwork, RoadNetworkBackend};
297/// use std::collections::HashMap;
298///
299/// let package_location = std::env::var("CARGO_MANIFEST_DIR").unwrap();
300/// let xodr_path = format!("{}/data/xodr/TShapeRoad.xodr", package_location);
301/// let road_network_properties = HashMap::from([("road_geometry_id", "my_rg_from_rust"), ("opendrive_file", xodr_path.as_str())]);
302/// let road_network = RoadNetwork::new(RoadNetworkBackend::MaliputMalidrive, &road_network_properties).unwrap();
303/// let road_geometry = road_network.road_geometry();
304/// println!("RoadGeometry ID: {}", road_geometry.id());
305/// ```
306pub struct RoadGeometry<'a> {
307    rg: &'a maliput_sys::api::ffi::RoadGeometry,
308}
309
310impl<'a> RoadGeometry<'a> {
311    /// Returns the id of the RoadGeometry.
312    pub fn id(&self) -> String {
313        maliput_sys::api::ffi::RoadGeometry_id(self.rg)
314    }
315    /// Returns the number of Junctions in the RoadGeometry.
316    ///
317    /// Return value is non-negative.
318    pub fn num_junctions(&self) -> i32 {
319        self.rg.num_junctions()
320    }
321    /// Returns the tolerance guaranteed for linear measurements (positions).
322    pub fn linear_tolerance(&self) -> f64 {
323        self.rg.linear_tolerance()
324    }
325    /// Returns the tolerance guaranteed for angular measurements (orientations).
326    pub fn angular_tolerance(&self) -> f64 {
327        self.rg.angular_tolerance()
328    }
329    /// Returns the number of BranchPoints in the RoadGeometry.
330    ///
331    /// Return value is non-negative.
332    pub fn num_branch_points(&self) -> i32 {
333        self.rg.num_branch_points()
334    }
335    /// Determines the [RoadPosition] on the 3D road manifold that corresponds to
336    /// [InertialPosition] `inertial_position`.
337    ///
338    /// The [RoadGeometry]'s manifold is a 3D volume, with each point defined by (s, r, h)
339    /// coordinates. This method returns a [RoadPositionQuery]. Its [RoadPosition] is the
340    /// point in the [RoadGeometry]'s manifold which is, in the `Inertial`-frame, closest to
341    /// `inertial_position`. Its InertialPosition is the `Inertial`-frame equivalent of the
342    /// [RoadPosition] and its distance is the Cartesian distance from
343    /// `inertial_position` to the nearest point.
344    ///
345    /// This method guarantees that its result satisfies the condition that
346    /// `result.lane.to_lane_position(result.pos)` is within `linear_tolerance()`
347    /// of the returned [InertialPosition].
348    ///
349    /// The map from [RoadGeometry] to the `Inertial`-frame is not onto (as a bounded
350    /// [RoadGeometry] cannot completely cover the unbounded Cartesian universe).
351    /// If `inertial_position` does represent a point contained within the volume
352    /// of the RoadGeometry, then result distance is guaranteed to be less
353    /// than or equal to `linear_tolerance()`.
354    ///
355    /// The map from [RoadGeometry] to `Inertial`-frame is not necessarily one-to-one.
356    /// Different `(s,r,h)` coordinates from different Lanes, potentially from
357    /// different Segments, may map to the same `(x,y,z)` `Inertial`-frame location.
358    ///
359    /// If `inertial_position` is contained within the volumes of multiple Segments,
360    /// then to_road_position() will choose a [Segment] which yields the minimum
361    /// height `h` value in the result.  If the chosen [Segment] has multiple
362    /// Lanes, then to_road_position() will choose a [Lane] which contains
363    /// `inertial_position` within its `lane_bounds()` if possible, and if that is
364    /// still ambiguous, it will further select a [Lane] which minimizes the
365    /// absolute value of the lateral `r` coordinate in the result.
366    ///
367    /// # Arguments
368    /// * `inertial_position` - The [InertialPosition] to convert into a [RoadPosition].
369    ///
370    /// # Return
371    /// A [RoadPositionQuery] with the nearest [RoadPosition], the corresponding [InertialPosition]
372    /// to that [RoadPosition] and the distance between the input and output [InertialPosition]s.
373    pub fn to_road_position(&self, inertial_position: &InertialPosition) -> Result<RoadPositionQuery, MaliputError> {
374        let rpr = maliput_sys::api::ffi::RoadGeometry_ToRoadPosition(self.rg, &inertial_position.ip)?;
375        Ok(RoadPositionQuery {
376            road_position: RoadPosition {
377                rp: maliput_sys::api::ffi::RoadPositionResult_road_position(&rpr),
378            },
379            nearest_position: InertialPosition {
380                ip: maliput_sys::api::ffi::RoadPositionResult_nearest_position(&rpr),
381            },
382            distance: maliput_sys::api::ffi::RoadPositionResult_distance(&rpr),
383        })
384    }
385
386    /// Determines the [RoadPosition] on the road surface that corresponds to
387    /// [InertialPosition] `inertial_position`.
388    ///
389    /// This method is similar to [RoadGeometry::to_road_position], in a way that it determines if
390    /// `inertial_position` is within the [RoadGeometry]'s 3D volume. If it is, a [RoadPosition] is
391    /// returned where the height `h` is set to 0, effectively placing the point on the road
392    /// surface.
393    ///
394    /// # Arguments
395    /// * `inertial_position` - The [InertialPosition] to convert into a [RoadPosition].
396    ///
397    /// # Return
398    /// 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`).
399    ///
400    /// # Example
401    ///
402    /// ```rust, no_run
403    /// use maliput::api::{RoadNetwork, RoadNetworkBackend, InertialPosition};
404    /// use std::collections::HashMap;
405    ///
406    /// let package_location = std::env::var("CARGO_MANIFEST_DIR").unwrap();
407    /// let xodr_path = format!("{}/data/xodr/TShapeRoad.xodr", package_location);
408    /// let road_network_properties = HashMap::from([("road_geometry_id", "my_rg_from_rust"), ("opendrive_file", xodr_path.as_str())]);
409    /// let road_network = RoadNetwork::new(RoadNetworkBackend::MaliputMalidrive, &road_network_properties).unwrap();
410    /// let road_geometry = road_network.road_geometry();
411    ///
412    /// // Although this isn't directly on the surface, it is within the RoadGeometry volume.
413    /// let inertial_pos = InertialPosition::new(1.0, 0.0, 1.0);
414    /// let road_pos = road_geometry.to_road_position_surface(&inertial_pos);
415    /// assert!(road_pos.is_ok());
416    /// let road_pos = road_pos.unwrap();
417    /// println!("Road position on surface: s={}, r={}, h={}", road_pos.pos().s(), road_pos.pos().r(), road_pos.pos().h());
418    /// assert_eq!(road_pos.pos().s(), 1.0);
419    /// assert_eq!(road_pos.pos().r(), 0.0);
420    /// assert_eq!(road_pos.pos().h(), 0.0);  // h is set to 0.
421    ///
422    /// // An inertial position that is off the road volume.
423    /// let inertial_pos= InertialPosition::new(1.0, 0.0, 10.0);
424    /// let road_pos= road_geometry.to_road_position_surface(&inertial_pos);
425    /// assert!(road_pos.is_err());
426    /// ```
427    pub fn to_road_position_surface(&self, inertial_position: &InertialPosition) -> Result<RoadPosition, MaliputError> {
428        let rpr = maliput_sys::api::ffi::RoadGeometry_ToRoadPosition(self.rg, &inertial_position.ip)?;
429        let road_position = RoadPosition {
430            rp: maliput_sys::api::ffi::RoadPositionResult_road_position(&rpr),
431        };
432
433        let distance = maliput_sys::api::ffi::RoadPositionResult_distance(&rpr);
434        if distance > self.linear_tolerance() {
435            return Err(MaliputError::Other(format!(
436                "InertialPosition {} does not correspond to a RoadPosition. It is off by {}m to the closest lane {} at {}.",
437                maliput_sys::api::ffi::InertialPosition_to_str(&inertial_position.ip),
438                distance, road_position.lane().id(), road_position.pos())));
439        }
440
441        let lane_position =
442            maliput_sys::api::ffi::LanePosition_new(road_position.pos().s(), road_position.pos().r(), 0.);
443        unsafe {
444            Ok(RoadPosition {
445                rp: maliput_sys::api::ffi::RoadPosition_new(road_position.lane().lane, &lane_position),
446            })
447        }
448    }
449
450    /// Obtains all [RoadPosition]s within a radius of the inertial_position.
451    ///
452    /// Only Lanes whose segment regions include points that are within radius of
453    /// inertial position are included in the search. For each of these Lanes,
454    /// include the [RoadPosition] or [RoadPosition]s with the minimum distance to
455    /// inertial position in the returned result.
456    ///
457    /// # Arguments
458    ///
459    /// * `inertial_position` - The [InertialPosition] to search around.
460    /// * `radius` - The radius around the [InertialPosition] to search for [RoadPosition]s.
461    ///
462    /// # Return
463    ///
464    /// A vector of [RoadPositionQuery]s.
465    pub fn find_road_positions(
466        &self,
467        inertial_position: &InertialPosition,
468        radius: f64,
469    ) -> Result<Vec<RoadPositionQuery>, MaliputError> {
470        let positions = maliput_sys::api::ffi::RoadGeometry_FindRoadPositions(self.rg, &inertial_position.ip, radius)?;
471        Ok(positions
472            .iter()
473            .map(|rpr| RoadPositionQuery {
474                road_position: RoadPosition {
475                    rp: maliput_sys::api::ffi::RoadPositionResult_road_position(rpr),
476                },
477                nearest_position: InertialPosition {
478                    ip: maliput_sys::api::ffi::RoadPositionResult_nearest_position(rpr),
479                },
480                distance: maliput_sys::api::ffi::RoadPositionResult_distance(rpr),
481            })
482            .collect())
483    }
484
485    /// Finds all [RoadPosition]s within a 2D radius of the given (x, y) inertial coordinates.
486    ///
487    /// Unlike [`find_road_positions`](Self::find_road_positions), this method uses only the X and Y
488    /// components for distance filtering (2D planar distance). The Z coordinate of the returned
489    /// nearest positions is computed from the road surface (i.e., the point on the road at h=0).
490    ///
491    /// This is useful for mapping 2D trajectories onto the road network, where the caller
492    /// has (x, y) coordinates but not the elevation.
493    ///
494    /// # Arguments
495    ///
496    /// * `x` - The x-coordinate in the Inertial frame.
497    /// * `y` - The y-coordinate in the Inertial frame.
498    /// * `radius` - The 2D search radius (in meters). Only results within this planar distance are returned.
499    ///
500    /// # Return
501    ///
502    /// A vector of [RoadPositionQuery]s sorted by ascending distance (nearest first) where:
503    ///  * `road_position.pos.h()` is 0 (on the road surface).
504    ///  * `nearest_position` contains the full 3D inertial position on the road surface.
505    ///  * `distance` is the 2D planar distance between (x, y) and the nearest point.
506    pub fn find_surface_road_positions_at_xy(
507        &self,
508        x: f64,
509        y: f64,
510        radius: f64,
511    ) -> Result<Vec<RoadPositionQuery>, MaliputError> {
512        let positions = maliput_sys::api::ffi::RoadGeometry_FindSurfaceRoadPositionsAtXY(self.rg, x, y, radius)?;
513        Ok(positions
514            .iter()
515            .map(|rpr| RoadPositionQuery {
516                road_position: RoadPosition {
517                    rp: maliput_sys::api::ffi::RoadPositionResult_road_position(rpr),
518                },
519                nearest_position: InertialPosition {
520                    ip: maliput_sys::api::ffi::RoadPositionResult_nearest_position(rpr),
521                },
522                distance: maliput_sys::api::ffi::RoadPositionResult_distance(rpr),
523            })
524            .collect())
525    }
526
527    /// Get the lane matching given `lane_id`.
528    ///
529    /// # Arguments
530    /// * `lane_id` - The id of the lane.
531    ///
532    /// # Return
533    /// The lane with the given id.
534    /// If no lane is found with the given id, return None.
535    pub fn get_lane(&self, lane_id: &String) -> Option<Lane<'_>> {
536        let lane = maliput_sys::api::ffi::RoadGeometry_GetLane(self.rg, lane_id);
537        if lane.lane.is_null() {
538            return None;
539        }
540        Some(Lane {
541            lane: unsafe { lane.lane.as_ref().expect("") },
542        })
543    }
544    /// Get all lanes of the `RoadGeometry`.
545    /// Returns a vector of `Lane`.
546    /// # Example
547    /// ```rust, no_run
548    /// use maliput::api::{RoadNetwork, RoadNetworkBackend};
549    /// use std::collections::HashMap;
550    ///
551    /// let package_location = std::env::var("CARGO_MANIFEST_DIR").unwrap();
552    /// let xodr_path = format!("{}/data/xodr/TShapeRoad.xodr", package_location);
553    /// let road_network_properties = HashMap::from([("road_geometry_id", "my_rg_from_rust"), ("opendrive_file", xodr_path.as_str())]);
554    /// let road_network = RoadNetwork::new(RoadNetworkBackend::MaliputMalidrive, &road_network_properties).unwrap();
555    /// let road_geometry = road_network.road_geometry();
556    /// let lanes = road_geometry.get_lanes();
557    /// for lane in lanes {
558    ///    println!("lane_id: {}", lane.id());
559    /// }
560    /// ```
561    pub fn get_lanes(&self) -> Vec<Lane<'_>> {
562        let lanes = maliput_sys::api::ffi::RoadGeometry_GetLanes(self.rg);
563        lanes
564            .into_iter()
565            .map(|l| Lane {
566                lane: unsafe { l.lane.as_ref().expect("") },
567            })
568            .collect::<Vec<Lane>>()
569    }
570    /// Get the segment matching given `segment_id`.
571    ///
572    /// # Arguments
573    /// * `segment_id` - The id of the segment.
574    ///
575    /// # Return
576    /// The segment with the given id.
577    /// If no segment is found with the given id, return None.
578    pub fn get_segment(&self, segment_id: &String) -> Option<Segment<'_>> {
579        let segment = maliput_sys::api::ffi::RoadGeometry_GetSegment(self.rg, segment_id);
580        if segment.is_null() {
581            return None;
582        }
583        unsafe {
584            Some(Segment {
585                segment: segment.as_ref().expect(""),
586            })
587        }
588    }
589
590    /// Returns a Vec with all [Junction]s in the RoadGeometry, which can be iterated.
591    ///
592    /// # Returns
593    /// A Vec with all junction in the road geometry.
594    pub fn get_juntions(&self) -> Result<Vec<Junction<'_>>, MaliputError> {
595        let mut junctions = vec![];
596        for i in 0..self.num_junctions() {
597            if let Some(junction) = self.junction(i) {
598                junctions.push(junction);
599            } else {
600                return Err(MaliputError::Other(format!("No junction found at index {}", i)));
601            };
602        }
603        Ok(junctions)
604    }
605
606    /// Get the junction at the given index.
607    /// The index is in the range [0, num_junctions).
608    ///
609    /// # Arguments
610    /// * `index` - The index of the junction.
611    ///
612    /// # Return
613    /// The junction at the given index.
614    /// If no junction is found at the given index, return None.
615    pub fn junction(&self, index: i32) -> Option<Junction<'_>> {
616        let junction = self.rg.junction(index).ok()?;
617        if junction.is_null() {
618            return None;
619        }
620        unsafe {
621            Some(Junction {
622                junction: junction.as_ref().expect(""),
623            })
624        }
625    }
626
627    /// Get the junction matching given `junction_id`.
628    ///
629    /// # Arguments
630    /// * `junction_id` - The id of the junction.
631    ///
632    /// # Return
633    /// The junction with the given id.
634    /// If no junction is found with the given id, return None.
635    pub fn get_junction(&self, junction_id: &String) -> Option<Junction<'_>> {
636        let junction = maliput_sys::api::ffi::RoadGeometry_GetJunction(self.rg, junction_id);
637        if junction.is_null() {
638            return None;
639        }
640        unsafe {
641            Some(Junction {
642                junction: junction.as_ref().expect(""),
643            })
644        }
645    }
646    /// Get the branch point matching given `branch_point_id`.
647    ///
648    /// # Arguments
649    /// * `branch_point_id` - The id of the branch point.
650    ///
651    /// # Return
652    /// The branch point with the given id.
653    /// If no branch point is found with the given id, return None.
654    pub fn get_branch_point(&self, branch_point_id: &String) -> Option<BranchPoint<'_>> {
655        let branch_point = maliput_sys::api::ffi::RoadGeometry_GetBranchPoint(self.rg, branch_point_id);
656        if branch_point.is_null() {
657            return None;
658        }
659        unsafe {
660            Some(BranchPoint {
661                branch_point: branch_point.as_ref().expect(""),
662            })
663        }
664    }
665    /// Execute a custom command on the backend.
666    ///
667    /// # Details
668    /// 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
669    ///
670    /// # Arguments
671    /// * `command` - The command to execute.
672    ///
673    /// # Return
674    /// The result of the command.
675    // pub fn backend_custom_command(&self, command: &String) -> String {
676    pub fn backend_custom_command(&self, command: &String) -> Result<String, MaliputError> {
677        Ok(maliput_sys::api::ffi::RoadGeometry_BackendCustomCommand(
678            self.rg, command,
679        )?)
680    }
681    /// Obtains the Geo Reference info of this RoadGeometry.
682    ///
683    /// # Return
684    /// A string containing the Geo Reference projection, if any.
685    pub fn geo_reference_info(&self) -> String {
686        maliput_sys::api::ffi::RoadGeometry_GeoReferenceInfo(self.rg)
687    }
688
689    /// Get the boundary matching given `boundary_id`.
690    ///
691    /// # Arguments
692    /// * `boundary_id` - The ID of the boundary.
693    ///
694    /// # Return
695    /// The lane boundary with the given ID.
696    /// If no lane boundary is found with the given ID, return None.
697    pub fn get_boundary(&self, boundary_id: &String) -> Option<LaneBoundary<'_>> {
698        let boundary = maliput_sys::api::ffi::RoadGeometry_GetLaneBoundary(self.rg, boundary_id);
699        if boundary.is_null() {
700            return None;
701        }
702        Some(LaneBoundary {
703            lane_boundary: unsafe { boundary.as_ref().expect("") },
704        })
705    }
706}
707
708/// A 3-dimensional position in a `Lane`-frame, consisting of three components:
709///
710/// * s is longitudinal position, as arc-length along a Lane's reference line.
711/// * r is lateral position, perpendicular to the reference line at s. +r is to
712///   to the left when traveling in the direction of +s.
713/// * h is height above the road surface.
714///
715/// # Example
716///
717/// ```rust, no_run
718/// use maliput::api::LanePosition;
719///
720/// let lane_pos = LanePosition::new(1.0, 2.0, 3.0);
721/// println!("lane_pos = {}", lane_pos);
722/// assert_eq!(lane_pos.s(), 1.0);
723/// assert_eq!(lane_pos.r(), 2.0);
724/// assert_eq!(lane_pos.h(), 3.0);
725/// ```
726pub struct LanePosition {
727    lp: cxx::UniquePtr<maliput_sys::api::ffi::LanePosition>,
728}
729
730impl LanePosition {
731    /// Create a new `LanePosition` with the given `s`, `r`, and `h` components.
732    pub fn new(s: f64, r: f64, h: f64) -> LanePosition {
733        LanePosition {
734            lp: maliput_sys::api::ffi::LanePosition_new(s, r, h),
735        }
736    }
737    /// Get the `s` component of the `LanePosition`.
738    pub fn s(&self) -> f64 {
739        self.lp.s()
740    }
741    /// Get the `r` component of the `LanePosition`.
742    pub fn r(&self) -> f64 {
743        self.lp.r()
744    }
745    /// Get the `h` component of the `LanePosition`.
746    pub fn h(&self) -> f64 {
747        self.lp.h()
748    }
749
750    /// Returns all components as 3-vector `[s, r, h]`.
751    pub fn srh(&self) -> Vector3 {
752        let srh = self.lp.srh();
753        Vector3::new(srh.x(), srh.y(), srh.z())
754    }
755
756    /// Set the `s` component of the `LanePosition`.
757    pub fn set_s(&mut self, s: f64) {
758        self.lp.as_mut().expect("Underlying LanePosition is null").set_s(s);
759    }
760
761    /// Set the `r` component of the `LanePosition`.
762    pub fn set_r(&mut self, r: f64) {
763        self.lp.as_mut().expect("Underlying LanePosition is null").set_r(r);
764    }
765
766    /// Set the `h` component of the `LanePosition`.
767    pub fn set_h(&mut self, h: f64) {
768        self.lp.as_mut().expect("Underlying LanePosition is null").set_h(h);
769    }
770
771    /// Set all components from 3-vector `[s, r, h]`.
772    pub fn set_srh(&mut self, srh: &Vector3) {
773        let ffi_vec = maliput_sys::math::ffi::Vector3_new(srh.x(), srh.y(), srh.z());
774        self.lp
775            .as_mut()
776            .expect("Underlying LanePosition is null")
777            .set_srh(&ffi_vec);
778    }
779}
780
781impl PartialEq for LanePosition {
782    fn eq(&self, other: &Self) -> bool {
783        self.srh() == other.srh()
784    }
785}
786
787impl Eq for LanePosition {}
788
789impl std::fmt::Display for LanePosition {
790    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
791        write!(f, "{}", maliput_sys::api::ffi::LanePosition_to_str(&self.lp))
792    }
793}
794
795impl std::fmt::Debug for LanePosition {
796    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
797        f.debug_struct("LanePosition")
798            .field("s", &self.s())
799            .field("r", &self.r())
800            .field("h", &self.h())
801            .finish()
802    }
803}
804
805/// A position in 3-dimensional geographical Cartesian space, i.e., in the
806/// `Inertial`-frame, consisting of three components x, y, and z.
807///
808/// # Example
809///
810/// ```rust, no_run
811/// use maliput::api::InertialPosition;
812///
813/// let inertial_pos = InertialPosition::new(1.0, 2.0, 3.0);
814/// println!("inertial_pos = {}", inertial_pos);
815/// assert_eq!(inertial_pos.x(), 1.0);
816/// assert_eq!(inertial_pos.y(), 2.0);
817/// assert_eq!(inertial_pos.z(), 3.0);
818/// ```
819pub struct InertialPosition {
820    ip: cxx::UniquePtr<maliput_sys::api::ffi::InertialPosition>,
821}
822
823impl InertialPosition {
824    /// Create a new `InertialPosition` with the given `x`, `y`, and `z` components.
825    pub fn new(x: f64, y: f64, z: f64) -> InertialPosition {
826        InertialPosition {
827            ip: maliput_sys::api::ffi::InertialPosition_new(x, y, z),
828        }
829    }
830    /// Get the `x` component of the `InertialPosition`.
831    pub fn x(&self) -> f64 {
832        self.ip.x()
833    }
834    /// Get the `y` component of the `InertialPosition`.
835    pub fn y(&self) -> f64 {
836        self.ip.y()
837    }
838    /// Get the `z` component of the `InertialPosition`.
839    pub fn z(&self) -> f64 {
840        self.ip.z()
841    }
842
843    /// Returns all components as 3-vector `[x, y, z]`.
844    pub fn xyz(&self) -> Vector3 {
845        let xyz = self.ip.xyz();
846        Vector3::new(xyz.x(), xyz.y(), xyz.z())
847    }
848
849    /// Set the `x` component of the `InertialPosition`.
850    pub fn set_x(&mut self, x: f64) {
851        self.ip.as_mut().expect("Underlying InertialPosition is null").set_x(x);
852    }
853
854    /// Set the `y` component of the `InertialPosition`.
855    pub fn set_y(&mut self, y: f64) {
856        self.ip.as_mut().expect("Underlying InertialPosition is null").set_y(y);
857    }
858
859    /// Set the `z` component of the `InertialPosition`.
860    pub fn set_z(&mut self, z: f64) {
861        self.ip.as_mut().expect("Underlying InertialPosition is null").set_z(z);
862    }
863
864    /// Set all components from 3-vector `[x, y, z]`.
865    pub fn set_xyz(&mut self, xyz: &Vector3) {
866        let ffi_vec = maliput_sys::math::ffi::Vector3_new(xyz.x(), xyz.y(), xyz.z());
867        self.ip
868            .as_mut()
869            .expect("Underlying InertialPosition is null")
870            .set_xyz(&ffi_vec);
871    }
872
873    /// Get the length of `InertialPosition`.
874    pub fn length(&self) -> f64 {
875        self.ip.length()
876    }
877
878    /// Get the distance between two `InertialPosition`.
879    pub fn distance(&self, other: &InertialPosition) -> f64 {
880        self.ip.Distance(&other.ip)
881    }
882}
883
884impl PartialEq for InertialPosition {
885    fn eq(&self, other: &Self) -> bool {
886        maliput_sys::api::ffi::InertialPosition_operator_eq(&self.ip, &other.ip)
887    }
888}
889
890impl Eq for InertialPosition {}
891
892impl std::fmt::Display for InertialPosition {
893    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
894        write!(f, "{}", maliput_sys::api::ffi::InertialPosition_to_str(&self.ip))
895    }
896}
897
898impl std::fmt::Debug for InertialPosition {
899    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
900        f.debug_struct("InertialPosition")
901            .field("x", &self.x())
902            .field("y", &self.y())
903            .field("z", &self.z())
904            .finish()
905    }
906}
907
908impl std::ops::Add for InertialPosition {
909    type Output = InertialPosition;
910
911    fn add(self, other: InertialPosition) -> InertialPosition {
912        InertialPosition {
913            ip: maliput_sys::api::ffi::InertialPosition_operator_sum(&self.ip, &other.ip),
914        }
915    }
916}
917
918impl std::ops::Sub for InertialPosition {
919    type Output = InertialPosition;
920
921    fn sub(self, other: InertialPosition) -> InertialPosition {
922        InertialPosition {
923            ip: maliput_sys::api::ffi::InertialPosition_operator_sub(&self.ip, &other.ip),
924        }
925    }
926}
927
928impl std::ops::Mul<f64> for InertialPosition {
929    type Output = InertialPosition;
930
931    fn mul(self, scalar: f64) -> InertialPosition {
932        InertialPosition {
933            ip: maliput_sys::api::ffi::InertialPosition_operator_mul_scalar(&self.ip, scalar),
934        }
935    }
936}
937
938impl Clone for InertialPosition {
939    fn clone(&self) -> Self {
940        InertialPosition {
941            ip: maliput_sys::api::ffi::InertialPosition_new(self.x(), self.y(), self.z()),
942        }
943    }
944}
945
946/// Bounds in the lateral dimension (r component) of a `Lane`-frame, consisting
947/// of a pair of minimum and maximum r value.  The bounds must straddle r = 0,
948/// i.e., the minimum must be <= 0 and the maximum must be >= 0.
949pub struct RBounds {
950    min: f64,
951    max: f64,
952}
953
954impl RBounds {
955    /// Create a new `RBounds` with the given `min` and `max` values.
956    pub fn new(min: f64, max: f64) -> RBounds {
957        RBounds { min, max }
958    }
959    /// Get the `min` value of the `RBounds`.
960    pub fn min(&self) -> f64 {
961        self.min
962    }
963    /// Get the `max` value of the `RBounds`.
964    pub fn max(&self) -> f64 {
965        self.max
966    }
967    /// Set the `min` value of the `RBounds`.
968    pub fn set_min(&mut self, min: f64) {
969        self.min = min;
970    }
971    /// Set the `max` value of the `RBounds`.
972    pub fn set_max(&mut self, max: f64) {
973        self.max = max;
974    }
975}
976
977/// Bounds in the elevation dimension (`h` component) of a `Lane`-frame,
978/// consisting of a pair of minimum and maximum `h` value.  The bounds
979/// must straddle `h = 0`, i.e., the minimum must be `<= 0` and the
980/// maximum must be `>= 0`.
981pub struct HBounds {
982    min: f64,
983    max: f64,
984}
985
986impl HBounds {
987    /// Create a new `HBounds` with the given `min` and `max` values.
988    pub fn new(min: f64, max: f64) -> HBounds {
989        HBounds { min, max }
990    }
991    /// Get the `min` value of the `HBounds`.
992    pub fn min(&self) -> f64 {
993        self.min
994    }
995    /// Get the `max` value of the `HBounds`.
996    pub fn max(&self) -> f64 {
997        self.max
998    }
999    /// Set the `min` value of the `HBounds`.
1000    pub fn set_min(&mut self, min: f64) {
1001        self.min = min;
1002    }
1003    /// Set the `max` value of the `HBounds`.
1004    pub fn set_max(&mut self, max: f64) {
1005        self.max = max;
1006    }
1007}
1008
1009/// Isometric velocity vector in a `Lane`-frame.
1010///
1011/// sigma_v, rho_v, and eta_v are the components of velocity in a
1012/// (sigma, rho, eta) coordinate system.  (sigma, rho, eta) have the same
1013/// orientation as the (s, r, h) at any given point in space, however they
1014/// form an isometric system with a Cartesian distance metric.  Hence,
1015/// IsoLaneVelocity represents a "real" physical velocity vector (albeit
1016/// with an orientation relative to the road surface).
1017#[derive(Default, Copy, Clone, Debug, PartialEq)]
1018pub struct IsoLaneVelocity {
1019    pub sigma_v: f64,
1020    pub rho_v: f64,
1021    pub eta_v: f64,
1022}
1023
1024impl IsoLaneVelocity {
1025    /// Create a new `IsoLaneVelocity` with the given `sigma_v`, `rho_v`, and `eta_v` components.
1026    pub fn new(sigma_v: f64, rho_v: f64, eta_v: f64) -> IsoLaneVelocity {
1027        IsoLaneVelocity { sigma_v, rho_v, eta_v }
1028    }
1029}
1030
1031/// Lane classification options.
1032///
1033/// LaneType defines the intended use of a lane.
1034#[derive(strum_macros::Display, Debug, Copy, Clone, PartialEq, Eq)]
1035pub enum LaneType {
1036    /// Default state.
1037    Unknown,
1038    /// Standard driving lane.
1039    Driving,
1040    /// Turn available.
1041    Turn,
1042    /// High Occupancy Vehicle lane (+2 passengers).
1043    Hov,
1044    /// Bus only.
1045    Bus,
1046    /// Taxi only.
1047    Taxi,
1048    /// Emergency vehicles only (fire, ambulance, police).
1049    Emergency,
1050    /// Soft border at the edge of the road.
1051    Shoulder,
1052    /// Reserved for cyclists.
1053    Biking,
1054    /// Sidewalks / Crosswalks.
1055    Walking,
1056    /// Lane with parking spaces.
1057    Parking,
1058    /// Hard shoulder / Emergency stop.
1059    Stop,
1060    /// Hard border at the edge of the road.
1061    Border,
1062    /// Curb stones.
1063    Curb,
1064    /// Sits between driving lanes that lead in opposite directions.
1065    Median,
1066    /// Generic restricted (use if HOV/Bus/Emergency don't fit).
1067    Restricted,
1068    /// Road works.
1069    Construction,
1070    /// Trains/Trams.
1071    Rail,
1072    /// Merge into main road.
1073    Entry,
1074    /// Exit from the main road.
1075    Exit,
1076    /// Ramp leading to a motorway.
1077    OnRamp,
1078    /// Ramp leading away from a motorway.
1079    OffRamp,
1080    // Ramp that connects two motorways.
1081    ConnectingRamp,
1082    /// Change roads without driving into the main intersection.
1083    SlipLane,
1084    /// Intersection crossings with no physical markings.
1085    Virtual,
1086}
1087
1088/// A Lane represents a lane of travel in a road network.  A Lane defines
1089/// a curvilinear coordinate system covering the road surface, with a
1090/// longitudinal 's' coordinate that expresses the arc-length along a
1091/// central reference curve.  The reference curve nominally represents
1092/// an ideal travel trajectory along the Lane.
1093///
1094/// Lanes are grouped by Segment.  All Lanes belonging to a Segment
1095/// represent the same road surface, but with different coordinate
1096/// parameterizations (e.g., each Lane has its own reference curve).
1097pub struct Lane<'a> {
1098    lane: &'a maliput_sys::api::ffi::Lane,
1099}
1100
1101impl<'a> Lane<'a> {
1102    /// Returns the id of the Lane.
1103    ///
1104    /// The id is a unique identifier for the Lane within the RoadGeometry.
1105    ///
1106    /// # Returns
1107    /// A `String` containing the id of the Lane.
1108    pub fn id(&self) -> String {
1109        maliput_sys::api::ffi::Lane_id(self.lane)
1110    }
1111    /// Returns the index of this Lane within the Segment which owns it.
1112    pub fn index(&self) -> i32 {
1113        self.lane.index()
1114    }
1115    /// Returns the Segment to which this Lane belongs.
1116    ///
1117    /// # Returns
1118    /// A [`Segment`] containing the Segment to which this Lane belongs.
1119    pub fn segment(&self) -> Segment<'a> {
1120        unsafe {
1121            Segment {
1122                segment: self.lane.segment().as_ref().expect(""),
1123            }
1124        }
1125    }
1126    /// Returns the adjacent lane to the left, if one exists.
1127    ///
1128    /// "Left" is defined as the direction of `+r` in the `(s, r, h)` lane-coordinate frame.
1129    ///
1130    /// # Returns
1131    ///
1132    /// An [`Option<Lane>`] containing the left lane, or `None` if this is the
1133    /// leftmost lane.
1134    pub fn to_left(&self) -> Option<Lane<'_>> {
1135        let lane = self.lane.to_left();
1136        if lane.is_null() {
1137            None
1138        } else {
1139            unsafe {
1140                Some(Lane {
1141                    lane: lane.as_ref().expect(""),
1142                })
1143            }
1144        }
1145    }
1146    /// Returns the adjacent lane to the right, if one exists.
1147    ///
1148    /// "Right" is defined as the direction of `-r` in the `(s, r, h)` lane-coordinate
1149    /// frame.
1150    ///
1151    /// # Returns
1152    ///
1153    /// An [`Option<Lane>`] containing the right lane, or `None` if this is the
1154    /// rightmost lane.
1155    pub fn to_right(&self) -> Option<Lane<'_>> {
1156        let lane = self.lane.to_right();
1157        if lane.is_null() {
1158            None
1159        } else {
1160            unsafe {
1161                Some(Lane {
1162                    lane: lane.as_ref().expect(""),
1163                })
1164            }
1165        }
1166    }
1167    /// Returns the arc-length of the Lane along its reference curve.
1168    ///
1169    /// The value of length() is also the maximum s-coordinate for this Lane;
1170    /// i.e., the domain of s is [0, length()].
1171    ///
1172    /// # Returns
1173    ///
1174    /// The length of the Lane in meters.
1175    pub fn length(&self) -> f64 {
1176        self.lane.length()
1177    }
1178
1179    /// Get the orientation of the `Lane` at the given `LanePosition`.
1180    pub fn get_orientation(&self, lane_position: &LanePosition) -> Result<Rotation, MaliputError> {
1181        Ok(Rotation {
1182            r: maliput_sys::api::ffi::Lane_GetOrientation(self.lane, lane_position.lp.as_ref().expect(""))?,
1183        })
1184    }
1185
1186    /// Returns the signed Euclidean curvature at the given [LanePosition].
1187    ///
1188    /// The Euclidean curvature magnitude is defined as the reciprocal of the radius
1189    /// of the osculating circle at a given point on the curve: $|\kappa| = 1/R$.
1190    ///
1191    /// The sign convention follows the right-hand rule with respect to the lane's
1192    /// `h`-axis (vertical/normal direction):
1193    /// - **Positive curvature**: The path curves to the left (toward +r direction),
1194    ///   i.e., counter-clockwise when viewed from above.
1195    /// - **Negative curvature**: The path curves to the right (toward -r direction),
1196    ///   i.e., clockwise when viewed from above.
1197    ///
1198    /// # Arguments
1199    /// * `lane_position` - A [LanePosition]. The `s` component must be in domain
1200    ///   `[0, Lane::length()]`. The `r` and `h` components are used to determine
1201    ///   the curvature at the corresponding offset from the centerline.
1202    ///
1203    /// # Returns
1204    /// The signed Euclidean curvature (1/m) at the given position.
1205    pub fn get_curvature(&self, lane_position: &LanePosition) -> Result<f64, MaliputError> {
1206        Ok(self.lane.GetCurvature(lane_position.lp.as_ref().expect(""))?)
1207    }
1208
1209    /// # Brief
1210    /// Get the [InertialPosition] of the [Lane] at the given [LanePosition].
1211    ///
1212    /// # Notes
1213    /// Note there is no constraint for the `r` coordinate, as it can be outside the lane boundaries.
1214    /// In that scenario, the resultant inertial position represents a point in the `s-r` plane at the given `s` and `h`
1215    /// coordinates. It's on the user side to verify, if needed, that the lane position is within lane boundaries.
1216    /// Bare in mind that the inertial position will be a point in the `s-r` plane, but *not* necessarily on the road surface.
1217    ///
1218    /// # Arguments
1219    /// * `lane_position` - A maliput [LanePosition].
1220    ///
1221    /// # Precondition
1222    /// The s component of `lane_position` must be in domain [0, Lane::length()].
1223    ///
1224    /// # Return
1225    /// The [InertialPosition] corresponding to the input [LanePosition].
1226    pub fn to_inertial_position(&self, lane_position: &LanePosition) -> Result<InertialPosition, MaliputError> {
1227        Ok(InertialPosition {
1228            ip: maliput_sys::api::ffi::Lane_ToInertialPosition(self.lane, lane_position.lp.as_ref().expect(""))?,
1229        })
1230    }
1231    /// Determines the LanePosition corresponding to InertialPosition `inertial_position`.
1232    /// The LanePosition is expected to be contained within the lane's 3D boundaries (s, r, h).
1233    /// See [Lane::to_segment_position] method.
1234    ///
1235    /// This method guarantees that its result satisfies the condition that
1236    /// `to_inertial_position(result.lane_position)` is within `linear_tolerance()`
1237    ///  of `result.nearest_position`.
1238    ///
1239    /// # Arguments
1240    /// * `inertial_position` - A [InertialPosition] to get a [LanePosition] from.
1241    ///
1242    /// # Return
1243    /// A [LanePositionQuery] with the closest [LanePosition], the corresponding [InertialPosition] to that [LanePosition]
1244    /// and the distance between the input and output [InertialPosition]s.
1245    pub fn to_lane_position(&self, inertial_position: &InertialPosition) -> Result<LanePositionQuery, MaliputError> {
1246        let lpr = maliput_sys::api::ffi::Lane_ToLanePosition(self.lane, inertial_position.ip.as_ref().expect(""))?;
1247        Ok(LanePositionQuery {
1248            lane_position: LanePosition {
1249                lp: maliput_sys::api::ffi::LanePositionResult_road_position(&lpr),
1250            },
1251            nearest_position: InertialPosition {
1252                ip: maliput_sys::api::ffi::LanePositionResult_nearest_position(&lpr),
1253            },
1254            distance: maliput_sys::api::ffi::LanePositionResult_distance(&lpr),
1255        })
1256    }
1257    /// Determines the [LanePosition] corresponding to [InertialPosition] `inertial_position`.
1258    /// The [LanePosition] is expected to be contained within the segment's 3D boundaries (s, r, h).
1259    /// See [Lane::to_lane_position] method.
1260    ///
1261    /// This method guarantees that its result satisfies the condition that
1262    /// `to_inertial_position(result.lane_position)` is within `linear_tolerance()`
1263    ///  of `result.nearest_position`.
1264    ///
1265    /// # Arguments
1266    /// * `inertial_position` - A [InertialPosition] to get a SegmentPosition from.
1267    ///
1268    /// # Return
1269    /// A [LanePositionQuery] with the closest [LanePosition] within the segment, the corresponding
1270    /// [InertialPosition] to that [LanePosition] and the distance between the input and output
1271    /// [InertialPosition]s.
1272    pub fn to_segment_position(&self, inertial_position: &InertialPosition) -> Result<LanePositionQuery, MaliputError> {
1273        let spr = maliput_sys::api::ffi::Lane_ToSegmentPosition(self.lane, inertial_position.ip.as_ref().expect(""))?;
1274        Ok(LanePositionQuery {
1275            lane_position: LanePosition {
1276                lp: maliput_sys::api::ffi::LanePositionResult_road_position(&spr),
1277            },
1278            nearest_position: InertialPosition {
1279                ip: maliput_sys::api::ffi::LanePositionResult_nearest_position(&spr),
1280            },
1281            distance: maliput_sys::api::ffi::LanePositionResult_distance(&spr),
1282        })
1283    }
1284    /// Returns the nominal lateral (r) bounds for the lane as a function of s.
1285    ///
1286    /// These are the lateral bounds for a position that is considered to be
1287    /// "staying in the lane".
1288    ///
1289    /// See also [Lane::segment_bounds] that defines the whole surface.
1290    ///
1291    /// # Arguments
1292    /// * `s` - The longitudinal position along the lane's reference line.
1293    ///
1294    /// # Returns
1295    /// A [RBounds] containing the lateral bounds of the lane at the given `s.
1296    ///
1297    /// # Errors
1298    /// If lane bounds cannot be computed, an error is returned. This can happen if the
1299    /// `s` value is out of bounds (i.e., not in the range [0, Lane::length()]).
1300    pub fn lane_bounds(&self, s: f64) -> Result<RBounds, MaliputError> {
1301        let bounds = maliput_sys::api::ffi::Lane_lane_bounds(self.lane, s)?;
1302        Ok(RBounds::new(bounds.min(), bounds.max()))
1303    }
1304    /// Returns the lateral segment (r) bounds of the lane as a function of s.
1305    ///
1306    /// These are the lateral bounds for a position that is considered to be
1307    /// "on segment", reflecting the physical extent of the surface of the
1308    /// lane's segment.
1309    ///
1310    /// See also [Lane::lane_bounds] that defines what's considered to be "staying
1311    /// in the lane".
1312    ///
1313    /// # Arguments
1314    /// * `s` - The longitudinal position along the lane's reference line.
1315    ///
1316    /// # Returns
1317    /// A [RBounds] containing the lateral segment bounds of the lane at the given `
1318    /// s`.
1319    ///
1320    /// # Errors
1321    /// If segment bounds cannot be computed, an error is returned. This can happen if the
1322    /// `s` value is out of bounds (i.e., not in the range [0, Lane::length()]).
1323    pub fn segment_bounds(&self, s: f64) -> Result<RBounds, MaliputError> {
1324        let bounds = maliput_sys::api::ffi::Lane_segment_bounds(self.lane, s)?;
1325        Ok(RBounds::new(bounds.min(), bounds.max()))
1326    }
1327    /// Returns the elevation (`h`) bounds of the lane as a function of `(s, r)`.
1328    ///
1329    /// These are the elevation bounds for a position that is considered to be
1330    /// within the Lane's volume modeled by the RoadGeometry.
1331    ///
1332    /// `s` is within [0, `length()`] of this Lane and `r` is within
1333    /// `lane_bounds(s)`.
1334    ///
1335    /// # Arguments
1336    /// * `s` - The longitudinal position along the lane's reference line.
1337    /// * `r` - The lateral position perpendicular to the reference line at `s`.
1338    ///
1339    /// # Returns
1340    /// A [HBounds] containing the elevation bounds of the lane at the given `(s, r)`.
1341    ///
1342    /// # Errors
1343    /// If elevation bounds cannot be computed, an error is returned. This can happen if the
1344    /// `s` value is out of bounds (i.e., not in the range [0, Lane::length()]) or if `r` is not within the
1345    /// lane bounds at `s`.
1346    pub fn elevation_bounds(&self, s: f64, r: f64) -> Result<HBounds, MaliputError> {
1347        let bounds = maliput_sys::api::ffi::Lane_elevation_bounds(self.lane, s, r)?;
1348        Ok(HBounds::new(bounds.min(), bounds.max()))
1349    }
1350    /// Computes derivatives of [LanePosition] given a velocity vector `velocity`.
1351    /// `velocity` is a isometric velocity vector oriented in the `Lane`-frame
1352    /// at `position`.
1353    ///
1354    /// # Arguments
1355    /// * `lane_position` - A [LanePosition] at which to evaluate the derivatives.
1356    /// * `velocity` - An [IsoLaneVelocity] representing the velocity vector in the `Lane`-frame
1357    ///   at `lane_position`.
1358    ///
1359    /// # Returns
1360    /// Returns `Lane`-frame derivatives packed into a [LanePosition] struct.
1361    pub fn eval_motion_derivatives(&self, lane_position: &LanePosition, velocity: &IsoLaneVelocity) -> LanePosition {
1362        LanePosition {
1363            lp: maliput_sys::api::ffi::Lane_EvalMotionDerivatives(
1364                self.lane,
1365                lane_position.lp.as_ref().expect(""),
1366                velocity.sigma_v,
1367                velocity.rho_v,
1368                velocity.eta_v,
1369            ),
1370        }
1371    }
1372    /// Returns the lane's [BranchPoint] for the specified end.
1373    ///
1374    /// # Argument
1375    /// * `end` - This lane's start or end [LaneEnd].
1376    ///
1377    /// # Return
1378    /// The lane's [BranchPoint] for the specified end.
1379    pub fn get_branch_point(&self, end: &LaneEnd) -> Result<BranchPoint<'_>, MaliputError> {
1380        if end != &LaneEnd::Start(self.clone()) && end != &LaneEnd::Finish(self.clone()) {
1381            return Err(MaliputError::AssertionError(format!(
1382                "LaneEnd must be an end of this lane {:?}",
1383                end
1384            )));
1385        }
1386        Ok(BranchPoint {
1387            branch_point: unsafe {
1388                maliput_sys::api::ffi::Lane_GetBranchPoint(self.lane, end == &LaneEnd::Start(self.clone()))
1389                    .as_ref()
1390                    .expect("Underlying BranchPoint is null")
1391            },
1392        })
1393    }
1394    /// Returns the set of [LaneEnd]'s which connect with this lane on the
1395    /// same side of the [BranchPoint] at `end`. At a minimum,
1396    /// this set will include this [Lane].
1397    ///
1398    /// # Arguments
1399    /// * `end` - This lane's start or end [LaneEnd].
1400    ///
1401    /// # Return
1402    /// A [LaneEndSet] with all the [LaneEnd]s at the same side of the [BranchPoint] at `end`.
1403    pub fn get_confluent_branches(&self, end: &LaneEnd) -> Result<LaneEndSet<'_>, MaliputError> {
1404        if end != &LaneEnd::Start(self.clone()) && end != &LaneEnd::Finish(self.clone()) {
1405            return Err(MaliputError::AssertionError(format!(
1406                "LaneEnd must be an end of this lane {:?}",
1407                end
1408            )));
1409        }
1410        Ok(LaneEndSet {
1411            lane_end_set: unsafe {
1412                maliput_sys::api::ffi::Lane_GetConfluentBranches(self.lane, end == &LaneEnd::Start(self.clone()))?
1413                    .as_ref()
1414                    .expect("Underlying LaneEndSet is null")
1415            },
1416        })
1417    }
1418    /// Returns the set of [LaneEnd]s which continue onward from this lane at the
1419    /// [BranchPoint] at `end`.
1420    ///
1421    /// # Arguments
1422    /// * `end` - This lane's start or end [LaneEnd].
1423    ///
1424    /// # Return
1425    /// A [LaneEndSet] with all the [LaneEnd]s at the opposite side of the [BranchPoint] at `end`.
1426    pub fn get_ongoing_branches(&self, end: &LaneEnd) -> Result<LaneEndSet<'_>, MaliputError> {
1427        if end != &LaneEnd::Start(self.clone()) && end != &LaneEnd::Finish(self.clone()) {
1428            return Err(MaliputError::AssertionError(format!(
1429                "LaneEnd must be an end of this lane {:?}",
1430                end
1431            )));
1432        }
1433        Ok(LaneEndSet {
1434            lane_end_set: unsafe {
1435                maliput_sys::api::ffi::Lane_GetOngoingBranches(self.lane, end == &LaneEnd::Start(self.clone()))?
1436                    .as_ref()
1437                    .expect("Underlying LaneEndSet is null")
1438            },
1439        })
1440    }
1441    /// Returns the default ongoing LaneEnd connected at `end`,
1442    /// or None if no default branch has been established.
1443    ///
1444    /// # Arguments
1445    /// * `end` - This lane's start or end [LaneEnd].
1446    ///
1447    /// # Return
1448    /// An `Option<LaneEnd>` containing the default branch if it exists, or None
1449    /// if no default branch has been established.
1450    pub fn get_default_branch(&self, end: &LaneEnd) -> Option<LaneEnd<'_>> {
1451        assert! {
1452            end == &LaneEnd::Start(self.clone()) || end == &LaneEnd::Finish(self.clone()),
1453            "LaneEnd must be an end of this lane {:?}",
1454           end
1455        }
1456        let lane_end = maliput_sys::api::ffi::Lane_GetDefaultBranch(self.lane, end == &LaneEnd::Start(self.clone()));
1457        match lane_end.is_null() {
1458            true => None,
1459            false => {
1460                let lane_end_ref: &maliput_sys::api::ffi::LaneEnd =
1461                    lane_end.as_ref().expect("Underlying LaneEnd is null");
1462                let is_start = maliput_sys::api::ffi::LaneEnd_is_start(lane_end_ref);
1463                let lane_ref = unsafe {
1464                    maliput_sys::api::ffi::LaneEnd_lane(lane_end_ref)
1465                        .as_ref()
1466                        .expect("Underlying LaneEnd is null")
1467                };
1468                match is_start {
1469                    true => Some(LaneEnd::Start(Lane { lane: lane_ref })),
1470                    false => Some(LaneEnd::Finish(Lane { lane: lane_ref })),
1471                }
1472            }
1473        }
1474    }
1475    /// Evaluates if the `Lane` contains the given `LanePosition`.
1476    ///
1477    /// # Arguments
1478    /// * `lane_position` - A [LanePosition] to check if it is contained within the `Lane`.
1479    ///
1480    /// # Returns
1481    /// A boolean indicating whether the `Lane` contains the `LanePosition`.
1482    pub fn contains(&self, lane_position: &LanePosition) -> bool {
1483        self.lane.Contains(lane_position.lp.as_ref().expect(""))
1484    }
1485
1486    /// Returns whether this lane is part of an intersection.
1487    ///
1488    /// Returns `None` when the backend does not provide this classification.
1489    pub fn is_intersection(&self) -> Option<bool> {
1490        let result = maliput_sys::api::ffi::Lane_is_intersection(self.lane);
1491        if result.has_value {
1492            Some(result.value)
1493        } else {
1494            None
1495        }
1496    }
1497
1498    /// Returns the [LaneType] of the [Lane].
1499    ///
1500    /// # Returns
1501    /// The [LaneType] of the [Lane].
1502    pub fn lane_type(&self) -> LaneType {
1503        let lane_type = maliput_sys::api::ffi::Lane_type(self.lane);
1504        match lane_type {
1505            maliput_sys::api::ffi::LaneType::kDriving => LaneType::Driving,
1506            maliput_sys::api::ffi::LaneType::kTurn => LaneType::Turn,
1507            maliput_sys::api::ffi::LaneType::kHov => LaneType::Hov,
1508            maliput_sys::api::ffi::LaneType::kBus => LaneType::Bus,
1509            maliput_sys::api::ffi::LaneType::kTaxi => LaneType::Taxi,
1510            maliput_sys::api::ffi::LaneType::kEmergency => LaneType::Emergency,
1511            maliput_sys::api::ffi::LaneType::kShoulder => LaneType::Shoulder,
1512            maliput_sys::api::ffi::LaneType::kBiking => LaneType::Biking,
1513            maliput_sys::api::ffi::LaneType::kWalking => LaneType::Walking,
1514            maliput_sys::api::ffi::LaneType::kParking => LaneType::Parking,
1515            maliput_sys::api::ffi::LaneType::kStop => LaneType::Stop,
1516            maliput_sys::api::ffi::LaneType::kBorder => LaneType::Border,
1517            maliput_sys::api::ffi::LaneType::kCurb => LaneType::Curb,
1518            maliput_sys::api::ffi::LaneType::kMedian => LaneType::Median,
1519            maliput_sys::api::ffi::LaneType::kRestricted => LaneType::Restricted,
1520            maliput_sys::api::ffi::LaneType::kConstruction => LaneType::Construction,
1521            maliput_sys::api::ffi::LaneType::kRail => LaneType::Rail,
1522            maliput_sys::api::ffi::LaneType::kEntry => LaneType::Entry,
1523            maliput_sys::api::ffi::LaneType::kExit => LaneType::Exit,
1524            maliput_sys::api::ffi::LaneType::kOnRamp => LaneType::OnRamp,
1525            maliput_sys::api::ffi::LaneType::kOffRamp => LaneType::OffRamp,
1526            maliput_sys::api::ffi::LaneType::kConnectingRamp => LaneType::ConnectingRamp,
1527            maliput_sys::api::ffi::LaneType::kSlipLane => LaneType::SlipLane,
1528            maliput_sys::api::ffi::LaneType::kVirtual => LaneType::Virtual,
1529            _ => LaneType::Unknown,
1530        }
1531    }
1532
1533    /// Returns the boundary at the left of the lane.
1534    pub fn left_boundary(&self) -> Result<LaneBoundary<'_>, MaliputError> {
1535        let lane_boundary = self.lane.left_boundary()?;
1536        if lane_boundary.is_null() {
1537            return Err(MaliputError::AssertionError(
1538                "Lane does not have a left boundary".to_string(),
1539            ));
1540        }
1541
1542        Ok(LaneBoundary {
1543            lane_boundary: unsafe { lane_boundary.as_ref().expect("") },
1544        })
1545    }
1546
1547    /// Returns the boundary at the right of the lane.
1548    pub fn right_boundary(&self) -> Result<LaneBoundary<'_>, MaliputError> {
1549        let lane_boundary = self.lane.right_boundary()?;
1550        if lane_boundary.is_null() {
1551            return Err(MaliputError::AssertionError(
1552                "Lane does not have a right boundary".to_string(),
1553            ));
1554        }
1555
1556        Ok(LaneBoundary {
1557            lane_boundary: unsafe { lane_boundary.as_ref().expect("") },
1558        })
1559    }
1560}
1561
1562/// Copy trait for Lane.
1563/// A reference to the Lane is copied.
1564impl Clone for Lane<'_> {
1565    fn clone(&self) -> Self {
1566        Lane { lane: self.lane }
1567    }
1568}
1569
1570/// A Segment represents a bundle of adjacent Lanes which share a
1571/// continuously traversable road surface. Every [LanePosition] on a
1572/// given [Lane] of a Segment has a corresponding [LanePosition] on each
1573/// other [Lane], all with the same height-above-surface h, that all
1574/// map to the same GeoPoint in 3-space.
1575///
1576/// Segments are grouped by [Junction].
1577pub struct Segment<'a> {
1578    segment: &'a maliput_sys::api::ffi::Segment,
1579}
1580
1581impl<'a> Segment<'a> {
1582    /// Returns the id of the Segment.
1583    /// The id is a unique identifier for the Segment within the RoadGeometry.
1584    ///
1585    /// # Returns
1586    /// A `String` containing the id of the Segment.
1587    pub fn id(&self) -> String {
1588        maliput_sys::api::ffi::Segment_id(self.segment)
1589    }
1590    /// Returns the [Junction] to which this Segment belongs.
1591    ///
1592    /// # Returns
1593    /// An [`Result<Junction, MaliputError>`] containing the Junction to which this Segment belongs.
1594    /// If the Segment does not belong to a Junction, an error is returned.
1595    pub fn junction(&self) -> Result<Junction<'_>, MaliputError> {
1596        let junction = self.segment.junction()?;
1597        if junction.is_null() {
1598            return Err(MaliputError::AssertionError(
1599                "Segment does not belong to a Junction".to_string(),
1600            ));
1601        }
1602        unsafe {
1603            Ok(Junction {
1604                junction: junction.as_ref().expect(""),
1605            })
1606        }
1607    }
1608    /// Returns the number of lanes in the Segment.
1609    ///
1610    /// # Returns
1611    /// The number of lanes in the Segment.
1612    pub fn num_lanes(&self) -> i32 {
1613        self.segment.num_lanes()
1614    }
1615
1616    /// Returns whether this segment is part of an intersection.
1617    ///
1618    /// Returns `None` when the backend does not provide this classification.
1619    pub fn is_intersection(&self) -> Option<bool> {
1620        let result = maliput_sys::api::ffi::Segment_is_intersection(self.segment);
1621        if result.has_value {
1622            Some(result.value)
1623        } else {
1624            None
1625        }
1626    }
1627
1628    /// Returns the lane at the given `index`.
1629    ///
1630    /// # Arguments
1631    /// * `index` - The index of the lane to retrieve.
1632    ///
1633    /// # Returns
1634    /// A [`Lane`] containing the lane at the given index.
1635    pub fn lane(&self, index: i32) -> Result<Lane<'_>, MaliputError> {
1636        if index < 0 || index >= self.num_lanes() {
1637            return Err(MaliputError::AssertionError(format!(
1638                "Index {} is out of bounds for Segment with {} lanes",
1639                index,
1640                self.num_lanes()
1641            )));
1642        }
1643        let lane = self.segment.lane(index)?;
1644        unsafe {
1645            Ok(Lane {
1646                lane: lane.as_ref().expect(""),
1647            })
1648        }
1649    }
1650
1651    /// Returns the amount of boundaries in the segment.
1652    pub fn num_boundaries(&self) -> i32 {
1653        self.segment.num_boundaries()
1654    }
1655
1656    /// Returns a Vec with all [LaneBoundary]s in the segment, which can be iterated.
1657    ///
1658    /// # Returns
1659    /// A Vec with all lane boundaries in the segment.
1660    pub fn boundaries(&self) -> Result<Vec<LaneBoundary<'_>>, MaliputError> {
1661        let mut boundaries = vec![];
1662        for i in 0..self.num_boundaries() {
1663            let boundary = self.boundary(i)?;
1664            boundaries.push(boundary);
1665        }
1666        Ok(boundaries)
1667    }
1668
1669    /// Returns the [LaneBoundary] that matches the index.
1670    ///
1671    /// # Arguments
1672    /// * `index` - The index of the boundary. See [LaneBoundary] for more info about indexes.
1673    ///
1674    /// # Returns
1675    /// The [LaneBoundary] at the given index.
1676    pub fn boundary(&self, index: i32) -> Result<LaneBoundary<'_>, MaliputError> {
1677        let lane_boundary = self.segment.boundary(index)?;
1678        if lane_boundary.is_null() {
1679            return Err(MaliputError::AssertionError(
1680                "Segment does not have a boundary".to_string(),
1681            ));
1682        }
1683        Ok(LaneBoundary {
1684            lane_boundary: unsafe { lane_boundary.as_ref().expect("") },
1685        })
1686    }
1687}
1688
1689/// A Junction is a closed set of [Segment]s which have physically
1690/// coplanar road surfaces, in the sense that [RoadPosition]s with the
1691/// same h value (height above surface) in the domains of two [Segment]s
1692/// map to the same [InertialPosition].  The [Segment]s need not be directly
1693/// connected to one another in the network topology.
1694///
1695/// Junctions are grouped by [RoadGeometry].
1696pub struct Junction<'a> {
1697    junction: &'a maliput_sys::api::ffi::Junction,
1698}
1699
1700impl<'a> Junction<'a> {
1701    /// Returns the id of the Junction.
1702    /// The id is a unique identifier for the Junction within the RoadGeometry.
1703    ///
1704    /// # Returns
1705    /// A `String` containing the id of the Junction.
1706    pub fn id(&self) -> String {
1707        maliput_sys::api::ffi::Junction_id(self.junction)
1708    }
1709    /// Returns the [RoadGeometry] to which this Junction belongs.
1710    ///
1711    /// # Returns
1712    /// A [`RoadGeometry`] containing the RoadGeometry to which this Junction belongs.
1713    pub fn road_geometry(&self) -> RoadGeometry<'_> {
1714        unsafe {
1715            RoadGeometry {
1716                rg: self.junction.road_geometry().as_ref().expect(""),
1717            }
1718        }
1719    }
1720    /// Returns the number of segments in the Junction.
1721    ///
1722    /// # Returns
1723    /// The number of segments in the Junction.
1724    pub fn num_segments(&self) -> i32 {
1725        self.junction.num_segments()
1726    }
1727
1728    /// Returns whether this junction is classified as an intersection.
1729    ///
1730    /// Returns `None` when the backend does not provide this classification.
1731    pub fn is_intersection(&self) -> Option<bool> {
1732        let result = maliput_sys::api::ffi::Junction_is_intersection(self.junction);
1733        if result.has_value {
1734            Some(result.value)
1735        } else {
1736            None
1737        }
1738    }
1739
1740    /// Returns the segment at the given `index`.
1741    ///
1742    /// # Arguments
1743    /// * `index` - The index of the segment to retrieve.
1744    ///
1745    /// # Returns
1746    /// A [Result<Segment, MaliputError>] containing the segment at the given index.
1747    /// If the index is out of bounds, an error is returned.
1748    pub fn segment(&self, index: i32) -> Result<Segment<'_>, MaliputError> {
1749        unsafe {
1750            Ok(Segment {
1751                segment: self.junction.segment(index)?.as_ref().expect(""),
1752            })
1753        }
1754    }
1755
1756    /// Returns a Vec with all [Segment]s in the Junction, which can be iterated.
1757    ///
1758    /// # Returns
1759    /// A Vec with all segments in the junction.
1760    pub fn get_segments(&self) -> Result<Vec<Segment<'_>>, MaliputError> {
1761        let mut segments = vec![];
1762        for i in 0..self.num_segments() {
1763            let segment = self.segment(i)?;
1764            segments.push(segment);
1765        }
1766        Ok(segments)
1767    }
1768}
1769
1770/// A position in the road network compound by a specific lane and a lane-frame position in that lane.
1771/// This position is defined by a [Lane] and a [LanePosition].
1772pub struct RoadPosition {
1773    rp: cxx::UniquePtr<maliput_sys::api::ffi::RoadPosition>,
1774}
1775
1776impl RoadPosition {
1777    /// Create a new `RoadPosition` with the given `lane` and `lane_pos`.
1778    ///
1779    /// # Arguments
1780    /// * `lane` - A reference to a [Lane] that this `RoadPosition` is associated with.
1781    /// * `lane_pos` - A reference to a [LanePosition] that defines the position within the lane.
1782    ///
1783    /// # Returns
1784    /// A new `RoadPosition` instance.
1785    pub fn new(lane: &Lane, lane_pos: &LanePosition) -> RoadPosition {
1786        unsafe {
1787            RoadPosition {
1788                rp: maliput_sys::api::ffi::RoadPosition_new(lane.lane, &lane_pos.lp),
1789            }
1790        }
1791    }
1792    /// Computes the [InertialPosition] corresponding to this `RoadPosition`.
1793    ///
1794    /// # Notes
1795    /// This is an indirection to [Lane::to_inertial_position] method.
1796    ///
1797    /// # Returns
1798    /// An [InertialPosition] corresponding to this `RoadPosition`.
1799    pub fn to_inertial_position(&self) -> Result<InertialPosition, MaliputError> {
1800        Ok(InertialPosition {
1801            ip: maliput_sys::api::ffi::RoadPosition_ToInertialPosition(&self.rp)?,
1802        })
1803    }
1804    /// Gets the [Lane] associated with this `RoadPosition`.
1805    ///
1806    /// # Returns
1807    /// A [Lane] that this `RoadPosition` is associated with.
1808    pub fn lane(&self) -> Lane<'_> {
1809        unsafe {
1810            Lane {
1811                lane: maliput_sys::api::ffi::RoadPosition_lane(&self.rp).as_ref().expect(""),
1812            }
1813        }
1814    }
1815    /// Gets the [LanePosition] associated with this `RoadPosition`.
1816    ///
1817    /// # Returns
1818    /// A [LanePosition] that defines the position within the lane for this `RoadPosition`.
1819    pub fn pos(&self) -> LanePosition {
1820        LanePosition {
1821            lp: maliput_sys::api::ffi::RoadPosition_pos(&self.rp),
1822        }
1823    }
1824}
1825
1826/// Represents the result of a RoadPosition query.
1827/// This struct contains the `RoadPosition`, the nearest `InertialPosition` to that `RoadPosition`,
1828/// and the distance between the input `InertialPosition` and the nearest `InertialPosition`.
1829///
1830/// This struct is typically used as return type for the methods: [RoadGeometry::to_road_position] and [RoadGeometry::find_road_positions].
1831pub struct RoadPositionQuery {
1832    /// The candidate RoadPosition returned by the query.
1833    pub road_position: RoadPosition,
1834    /// The nearest InertialPosition to the candidate RoadPosition.
1835    /// This is the position in the inertial frame that is closest to the candidate RoadPosition
1836    pub nearest_position: InertialPosition,
1837    /// The distance between the input InertialPosition and the nearest InertialPosition.
1838    pub distance: f64,
1839}
1840
1841impl RoadPositionQuery {
1842    /// Create a new `RoadPositionQuery` with the given `road_position`, `nearest_position`, and `distance`.
1843    pub fn new(road_position: RoadPosition, nearest_position: InertialPosition, distance: f64) -> RoadPositionQuery {
1844        RoadPositionQuery {
1845            road_position,
1846            nearest_position,
1847            distance,
1848        }
1849    }
1850}
1851
1852/// Represents the result of a LanePosition query.
1853/// This struct contains the `LanePosition`, the nearest `InertialPosition` to that `LanePosition`,
1854/// and the distance between the input `InertialPosition` and the nearest `InertialPosition`.
1855///
1856/// This struct is typically used as return type for the methods: [Lane::to_lane_position] and [Lane::to_segment_position].
1857pub struct LanePositionQuery {
1858    /// The candidate LanePosition within the Lane' lane-bounds or segment-bounds
1859    /// depending if [Lane::to_lane_position] or [Lane::to_segment_position] respectively, was called.
1860    /// The LanePosition is closest to a `inertial_position` supplied to [Lane::to_lane_position]
1861    /// (measured by the Cartesian metric in the `Inertial`-frame).
1862    pub lane_position: LanePosition,
1863    /// The position that exactly corresponds to `lane_position`.
1864    pub nearest_position: InertialPosition,
1865    /// The Cartesian distance between `nearest_position` and the
1866    /// `inertial_position` supplied to [Lane::to_lane_position] / [Lane::to_segment_position].
1867    pub distance: f64,
1868}
1869
1870impl LanePositionQuery {
1871    /// Create a new `LanePositionQuery` with the given `lane_position`, `nearest_position`, and `distance`.
1872    pub fn new(lane_position: LanePosition, nearest_position: InertialPosition, distance: f64) -> LanePositionQuery {
1873        LanePositionQuery {
1874            lane_position,
1875            nearest_position,
1876            distance,
1877        }
1878    }
1879}
1880
1881/// A 3-dimensional rotation in the road network.
1882/// This struct represents a rotation in the road network, which can be defined
1883/// using a quaternion or roll-pitch-yaw angles.
1884/// It provides methods to create a rotation, convert between representations,
1885/// and apply the rotation to an inertial position.
1886pub struct Rotation {
1887    r: cxx::UniquePtr<maliput_sys::api::ffi::Rotation>,
1888}
1889
1890impl Default for Rotation {
1891    fn default() -> Self {
1892        Self::new()
1893    }
1894}
1895
1896impl Rotation {
1897    /// Create a new `Rotation`.
1898    pub fn new() -> Rotation {
1899        Rotation {
1900            r: maliput_sys::api::ffi::Rotation_new(),
1901        }
1902    }
1903    /// Create a new `Rotation` from a `Quaternion`.
1904    pub fn from_quat(q: &Quaternion) -> Rotation {
1905        let q_ffi = maliput_sys::math::ffi::Quaternion_new(q.w(), q.x(), q.y(), q.z());
1906        Rotation {
1907            r: maliput_sys::api::ffi::Rotation_from_quat(&q_ffi),
1908        }
1909    }
1910    /// Create a new `Rotation` from a `RollPitchYaw`.
1911    pub fn from_rpy(rpy: &RollPitchYaw) -> Rotation {
1912        let rpy_ffi = maliput_sys::math::ffi::RollPitchYaw_new(rpy.roll_angle(), rpy.pitch_angle(), rpy.yaw_angle());
1913        Rotation {
1914            r: maliput_sys::api::ffi::Rotation_from_rpy(&rpy_ffi),
1915        }
1916    }
1917    /// Get the roll of the `Rotation`.
1918    pub fn roll(&self) -> f64 {
1919        self.r.roll()
1920    }
1921    /// Get the pitch of the `Rotation`.
1922    pub fn pitch(&self) -> f64 {
1923        self.r.pitch()
1924    }
1925    /// Get the yaw of the `Rotation`.
1926    pub fn yaw(&self) -> f64 {
1927        self.r.yaw()
1928    }
1929    /// Get a quaternion representation of the `Rotation`.
1930    pub fn quat(&self) -> Quaternion {
1931        let q_ffi = self.r.quat();
1932        Quaternion::new(q_ffi.w(), q_ffi.x(), q_ffi.y(), q_ffi.z())
1933    }
1934    /// Get a roll-pitch-yaw representation of the `Rotation`.
1935    pub fn rpy(&self) -> RollPitchYaw {
1936        let rpy_ffi = maliput_sys::api::ffi::Rotation_rpy(&self.r);
1937        RollPitchYaw::new(rpy_ffi.roll_angle(), rpy_ffi.pitch_angle(), rpy_ffi.yaw_angle())
1938    }
1939    /// Set the `Rotation` from a `Quaternion`.
1940    pub fn set_quat(&mut self, q: &Quaternion) {
1941        let q_ffi = maliput_sys::math::ffi::Quaternion_new(q.w(), q.x(), q.y(), q.z());
1942        maliput_sys::api::ffi::Rotation_set_quat(self.r.pin_mut(), &q_ffi);
1943    }
1944    /// Get the matrix representation of the `Rotation`.
1945    pub fn matrix(&self) -> Matrix3 {
1946        let matrix_ffi: cxx::UniquePtr<maliput_sys::math::ffi::Matrix3> =
1947            maliput_sys::api::ffi::Rotation_matrix(&self.r);
1948        let row_0 = maliput_sys::math::ffi::Matrix3_row(matrix_ffi.as_ref().expect(""), 0);
1949        let row_1 = maliput_sys::math::ffi::Matrix3_row(matrix_ffi.as_ref().expect(""), 1);
1950        let row_2 = maliput_sys::math::ffi::Matrix3_row(matrix_ffi.as_ref().expect(""), 2);
1951        Matrix3::new(
1952            Vector3::new(row_0.x(), row_0.y(), row_0.z()),
1953            Vector3::new(row_1.x(), row_1.y(), row_1.z()),
1954            Vector3::new(row_2.x(), row_2.y(), row_2.z()),
1955        )
1956    }
1957    /// Get the distance between two `Rotation`.
1958    pub fn distance(&self, other: &Rotation) -> f64 {
1959        self.r.Distance(&other.r)
1960    }
1961    /// Apply the `Rotation` to an `InertialPosition`.
1962    pub fn apply(&self, v: &InertialPosition) -> InertialPosition {
1963        InertialPosition {
1964            ip: maliput_sys::api::ffi::Rotation_Apply(&self.r, &v.ip),
1965        }
1966    }
1967    /// Get the reverse of the `Rotation`.
1968    pub fn reverse(&self) -> Rotation {
1969        Rotation {
1970            r: maliput_sys::api::ffi::Rotation_Reverse(&self.r),
1971        }
1972    }
1973}
1974
1975/// Directed, inclusive longitudinal (s value) range from s0 to s1.
1976pub struct SRange {
1977    s_range: cxx::UniquePtr<maliput_sys::api::ffi::SRange>,
1978}
1979
1980impl SRange {
1981    /// Creates a new `SRange` with the given `s0` and `s1`.
1982    ///
1983    /// # Arguments
1984    /// * `s0` - The starting value of the range.
1985    /// * `s1` - The ending value of the range.
1986    ///
1987    /// # Returns
1988    /// A new `SRange` instance.
1989    pub fn new(s0: f64, s1: f64) -> SRange {
1990        SRange {
1991            s_range: maliput_sys::api::ffi::SRange_new(s0, s1),
1992        }
1993    }
1994    /// Returns the s0 of the `SRange`.
1995    ///
1996    /// # Returns
1997    /// The starting value of the range.
1998    pub fn s0(&self) -> f64 {
1999        self.s_range.s0()
2000    }
2001    /// Returns the s1 of the `SRange`.
2002    ///
2003    /// # Returns
2004    /// The ending value of the range.
2005    pub fn s1(&self) -> f64 {
2006        self.s_range.s1()
2007    }
2008    /// Sets the s0 of the `SRange`.
2009    ///
2010    /// # Arguments
2011    /// * `s0` - The new starting value of the range.
2012    pub fn set_s0(&mut self, s0: f64) {
2013        self.s_range.as_mut().expect("Underlying SRange is null").set_s0(s0);
2014    }
2015    /// Sets the s1 of the `SRange`.
2016    ///
2017    /// # Arguments
2018    /// * `s1` - The new ending value of the range.
2019    pub fn set_s1(&mut self, s1: f64) {
2020        self.s_range.as_mut().expect("Underlying SRange is null").set_s1(s1);
2021    }
2022    /// Get the size of the `SRange`.
2023    ///
2024    /// # Returns
2025    /// The size of the range, which is the difference between s1 and s0.
2026    pub fn size(&self) -> f64 {
2027        self.s_range.size()
2028    }
2029    /// Defines whether this SRange is in the direction of +s (i.e., s1() > s0()).
2030    ///
2031    /// # Returns
2032    /// A boolean indicating whether the SRange is in the direction of +s.
2033    pub fn with_s(&self) -> bool {
2034        self.s_range.WithS()
2035    }
2036    /// Determines whether this SRange intersects with `s_range`.
2037    ///
2038    /// # Arguments
2039    /// * `s_range` - Another `SRange` to check for intersection.
2040    /// * `tolerance` - A tolerance value to consider when checking for intersection.
2041    ///
2042    /// # Returns
2043    /// A boolean indicating whether this SRange intersects with `s_range`.
2044    pub fn intersects(&self, s_range: &SRange, tolerance: f64) -> bool {
2045        self.s_range.Intersects(&s_range.s_range, tolerance)
2046    }
2047    /// Determines whether this SRange contains `s_range`.
2048    ///
2049    /// # Arguments
2050    /// * `s_range` - Another `SRange` to check if it is contained within this SRange.
2051    /// * `tolerance` - A tolerance value to consider when checking for containment.
2052    pub fn contains(&self, s_range: &SRange, tolerance: f64) -> bool {
2053        self.s_range.Contains(&s_range.s_range, tolerance)
2054    }
2055    /// Get the intersection of this SRange with `s_range`.
2056    ///
2057    /// # Arguments
2058    /// * `s_range` - Another `SRange` to get the intersection with.
2059    /// * `tolerance` - A tolerance value to consider when checking for intersection.
2060    ///
2061    /// # Returns
2062    /// An `Option<SRange>` containing the intersection of this SRange with `s_range`.
2063    /// If the intersection is empty, it returns None.
2064    pub fn get_intersection(&self, s_range: &SRange, tolerance: f64) -> Option<SRange> {
2065        let intersection = maliput_sys::api::ffi::SRange_GetIntersection(&self.s_range, &s_range.s_range, tolerance);
2066        match intersection.is_null() {
2067            true => None,
2068            false => Some(SRange { s_range: intersection }),
2069        }
2070    }
2071}
2072
2073impl std::fmt::Debug for SRange {
2074    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2075        write!(f, "SRange {{ s0: {}, s1: {} }}", self.s0(), self.s1())
2076    }
2077}
2078
2079/// Directed longitudinal range of a specific Lane, identified by a LaneId.
2080/// Similar to [SRange], but associated with a specific Lane.
2081pub struct LaneSRange {
2082    pub(crate) lane_s_range: cxx::UniquePtr<maliput_sys::api::ffi::LaneSRange>,
2083}
2084
2085impl LaneSRange {
2086    /// Creates a new `LaneSRange` with the given `lane_id` and `s_range`.
2087    /// # Arguments
2088    /// * `lane_id` - A `String` representing the id of the lane.
2089    /// * `s_range` - A reference to an [SRange] that defines the longitudinal range of the lane.
2090    ///
2091    /// # Returns
2092    /// A new `LaneSRange` instance.
2093    pub fn new(lane_id: &String, s_range: &SRange) -> LaneSRange {
2094        LaneSRange {
2095            lane_s_range: maliput_sys::api::ffi::LaneSRange_new(lane_id, &s_range.s_range),
2096        }
2097    }
2098    /// Returns the lane id of the `LaneSRange`.
2099    ///
2100    /// # Returns
2101    /// A `String` containing the id of the lane associated with this `LaneSRange`.
2102    pub fn lane_id(&self) -> String {
2103        maliput_sys::api::ffi::LaneSRange_lane_id(&self.lane_s_range)
2104    }
2105    /// Returns the [SRange] of the `LaneSRange`.
2106    ///
2107    /// # Returns
2108    /// An [SRange] containing the longitudinal range of the lane associated with this `LaneSRange`.
2109    pub fn s_range(&self) -> SRange {
2110        SRange {
2111            s_range: maliput_sys::api::ffi::LaneSRange_s_range(&self.lane_s_range),
2112        }
2113    }
2114    /// Returns the length of the `LaneSRange`.
2115    ///
2116    /// This is equivalent to `s_range.size()`.
2117    ///
2118    /// # Returns
2119    /// A `f64` representing the length of the `LaneSRange`.
2120    pub fn length(&self) -> f64 {
2121        self.lane_s_range.length()
2122    }
2123    /// Determines whether this LaneSRange intersects with `lane_s_range`.
2124    ///
2125    /// # Arguments
2126    /// * `lane_s_range` - Another `LaneSRange` to check for intersection.
2127    /// * `tolerance` - A tolerance value to consider when checking for intersection.
2128    ///
2129    /// # Returns
2130    /// A boolean indicating whether this LaneSRange intersects with `lane_s_range`.
2131    pub fn intersects(&self, lane_s_range: &LaneSRange, tolerance: f64) -> bool {
2132        self.lane_s_range.Intersects(&lane_s_range.lane_s_range, tolerance)
2133    }
2134    /// Determines whether this LaneSRange contains `lane_s_range`.
2135    ///
2136    /// # Arguments
2137    /// * `lane_s_range` - Another `LaneSRange` to check if it is contained within this LaneSRange.
2138    /// * `tolerance` - A tolerance value to consider when checking for containment.
2139    ///
2140    /// # Returns
2141    /// A boolean indicating whether this LaneSRange contains `lane_s_range`.
2142    /// This checks if the `s_range` of `lane_s_range` is fully contained
2143    /// within the `s_range` of this `LaneSRange`, considering the lane id.
2144    /// If the lane id does not match, it returns false.
2145    pub fn contains(&self, lane_s_range: &LaneSRange, tolerance: f64) -> bool {
2146        self.lane_s_range.Contains(&lane_s_range.lane_s_range, tolerance)
2147    }
2148    /// Computes the intersection of this `LaneSRange` with `lane_s_range`.
2149    ///
2150    /// # Arguments
2151    /// * `lane_s_range` - Another `LaneSRange` to get the intersection with.
2152    /// * `tolerance` - A tolerance value to consider when checking for intersection.
2153    ///
2154    /// # Returns
2155    /// An `Option<LaneSRange>` containing the intersection of this `LaneSRange` with `lane_s_range`.
2156    /// If the lane ids do not match, it returns None.
2157    /// If the intersection is empty, it returns None.
2158    pub fn get_intersection(&self, lane_s_range: &LaneSRange, tolerance: f64) -> Option<LaneSRange> {
2159        let intersection = maliput_sys::api::ffi::LaneSRange_GetIntersection(
2160            &self.lane_s_range,
2161            &lane_s_range.lane_s_range,
2162            tolerance,
2163        );
2164        match intersection.is_null() {
2165            true => None,
2166            false => Some(LaneSRange {
2167                lane_s_range: intersection,
2168            }),
2169        }
2170    }
2171}
2172
2173impl std::fmt::Debug for LaneSRange {
2174    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2175        write!(
2176            f,
2177            "LaneSRange {{ lane_id: {}, s_range: {:?} }}",
2178            self.lane_id(),
2179            self.s_range()
2180        )
2181    }
2182}
2183
2184/// A route, possibly spanning multiple (end-to-end) lanes.
2185///
2186/// The sequence of [LaneSRange]s should be contiguous by either presenting
2187/// laterally adjacent [LaneSRange]s, or consecutive [LaneSRange]s. (In other words,
2188/// taken as a Lane-space path with r=0 and h=0, it should present a
2189/// G1-continuous curve.)
2190pub struct LaneSRoute {
2191    lane_s_route: cxx::UniquePtr<maliput_sys::api::ffi::LaneSRoute>,
2192}
2193
2194impl LaneSRoute {
2195    /// Creates a new `LaneSRoute` with the given `ranges`.
2196    ///
2197    /// # Arguments
2198    /// * `ranges` - A vector of [LaneSRange] to create the [LaneSRoute].
2199    ///
2200    /// # Returns
2201    /// A new `LaneSRoute` instance containing the provided ranges.
2202    pub fn new(ranges: Vec<LaneSRange>) -> LaneSRoute {
2203        let mut lane_s_ranges_cpp = cxx::CxxVector::new();
2204        for range in &ranges {
2205            lane_s_ranges_cpp
2206                .as_mut()
2207                .unwrap()
2208                .push(maliput_sys::api::ffi::ConstLaneSRangeRef {
2209                    lane_s_range: &range.lane_s_range,
2210                });
2211        }
2212        LaneSRoute {
2213            lane_s_route: maliput_sys::api::ffi::LaneSRoute_new(&lane_s_ranges_cpp),
2214        }
2215    }
2216
2217    /// Returns the sequence of [LaneSRange]s.
2218    ///
2219    /// # Returns
2220    /// A vector of [LaneSRange]s that make up this [LaneSRoute].
2221    pub fn ranges(&self) -> Vec<LaneSRange> {
2222        let mut ranges = Vec::new();
2223        let lane_s_ranges = self.lane_s_route.ranges();
2224        for range in lane_s_ranges {
2225            ranges.push(LaneSRange {
2226                lane_s_range: maliput_sys::api::ffi::LaneSRange_new(
2227                    &maliput_sys::api::ffi::LaneSRange_lane_id(range),
2228                    maliput_sys::api::ffi::LaneSRange_s_range(range).as_ref().expect(""),
2229                ),
2230            })
2231        }
2232        ranges
2233    }
2234
2235    /// Computes the accumulated length of all [LaneSRange]s.
2236    ///
2237    /// # Returns
2238    /// A `f64` representing the total length of the [LaneSRoute].
2239    pub fn length(&self) -> f64 {
2240        self.lane_s_route.length()
2241    }
2242
2243    /// Determines whether this LaneSRoute intersects with `other`.
2244    ///
2245    /// # Arguments
2246    /// * `other` - The other LaneSRoute to check for intersection.
2247    /// * `tolerance` - The tolerance to use for intersection checks.
2248    ///
2249    /// # Returns
2250    /// * `true` if the two LaneSRoute intersect, `false` otherwise.
2251    pub fn intersects(&self, other: &LaneSRoute, tolerance: f64) -> bool {
2252        self.lane_s_route.Intersects(&other.lane_s_route, tolerance)
2253    }
2254}
2255
2256impl std::fmt::Debug for LaneSRoute {
2257    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2258        write!(f, "LaneSRoute {{ ranges: {:?} }}", self.ranges())
2259    }
2260}
2261
2262/// A specific endpoint of a specific Lane.
2263pub enum LaneEnd<'a> {
2264    /// The start of the Lane. ("s == 0")
2265    Start(Lane<'a>),
2266    /// The end of the Lane. ("s == length")
2267    Finish(Lane<'a>),
2268}
2269
2270impl LaneEnd<'_> {
2271    /// Gets the Lane of the `LaneEnd`.
2272    ///
2273    /// # Returns
2274    /// A reference to the [Lane] associated with this `LaneEnd`.
2275    /// This will return the Lane for both Start and Finish variants.
2276    pub fn lane(&self) -> &Lane<'_> {
2277        match self {
2278            LaneEnd::Start(lane) => lane,
2279            LaneEnd::Finish(lane) => lane,
2280        }
2281    }
2282}
2283
2284impl PartialEq for LaneEnd<'_> {
2285    fn eq(&self, other: &Self) -> bool {
2286        match self {
2287            LaneEnd::Start(lane) => match other {
2288                LaneEnd::Start(other_lane) => lane.id() == other_lane.id(),
2289                _ => false,
2290            },
2291            LaneEnd::Finish(lane) => match other {
2292                LaneEnd::Finish(other_lane) => lane.id() == other_lane.id(),
2293                _ => false,
2294            },
2295        }
2296    }
2297}
2298
2299impl Eq for LaneEnd<'_> {}
2300
2301impl std::fmt::Display for LaneEnd<'_> {
2302    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2303        match self {
2304            LaneEnd::Start(lane) => write!(f, "LaneEnd::Start({})", lane.id()),
2305            LaneEnd::Finish(lane) => write!(f, "LaneEnd::Finish({})", lane.id()),
2306        }
2307    }
2308}
2309
2310impl std::fmt::Debug for LaneEnd<'_> {
2311    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2312        match self {
2313            LaneEnd::Start(lane) => write!(f, "LaneEnd::Start({})", lane.id()),
2314            LaneEnd::Finish(lane) => write!(f, "LaneEnd::Finish({})", lane.id()),
2315        }
2316    }
2317}
2318
2319/// A set of LaneEnds.
2320pub struct LaneEndSet<'a> {
2321    lane_end_set: &'a maliput_sys::api::ffi::LaneEndSet,
2322}
2323
2324impl<'a> LaneEndSet<'a> {
2325    /// Obtains the size of the LaneEndSet.
2326    ///
2327    /// # Returns
2328    /// The number of LaneEnds in the set.
2329    pub fn size(&self) -> i32 {
2330        self.lane_end_set.size()
2331    }
2332    /// Gets the [LaneEnd] at the given index.
2333    ///
2334    /// # Arguments
2335    /// * `index` - The index of the LaneEnd to retrieve.
2336    ///
2337    /// # Returns
2338    /// A [Result<LaneEnd, MaliputError>] containing the LaneEnd at the given index.
2339    /// If the index is out of bounds, an error is returned.
2340    pub fn get(&self, index: i32) -> Result<LaneEnd<'_>, MaliputError> {
2341        let lane_end = self.lane_end_set.get(index)?;
2342        // Obtain end type and lane reference.
2343        let is_start = maliput_sys::api::ffi::LaneEnd_is_start(lane_end);
2344        let lane_ref = unsafe {
2345            maliput_sys::api::ffi::LaneEnd_lane(lane_end)
2346                .as_ref()
2347                .expect("Underlying LaneEnd is null")
2348        };
2349        // Create a LaneEnd enum variant.
2350        Ok(match is_start {
2351            true => LaneEnd::Start(Lane { lane: lane_ref }),
2352            false => LaneEnd::Finish(Lane { lane: lane_ref }),
2353        })
2354    }
2355
2356    /// Converts the LaneEndSet to a map of lane-id to LaneEnd.
2357    ///
2358    /// # Returns
2359    /// A `HashMap<String, LaneEnd>` where the key is the lane id and
2360    /// the value is the corresponding LaneEnd.
2361    pub fn to_lane_map(&self) -> std::collections::HashMap<String, LaneEnd<'_>> {
2362        (0..self.size())
2363            .map(|i| {
2364                let end = self.get(i).unwrap();
2365                (end.lane().id(), end)
2366            })
2367            .collect()
2368    }
2369}
2370
2371/// A BranchPoint is a node in the network of a RoadGeometry at which
2372/// Lanes connect to one another.  A BranchPoint is a collection of LaneEnds
2373/// specifying the Lanes (and, in particular, which ends of the Lanes) are
2374/// connected at the BranchPoint.
2375///
2376/// LaneEnds participating in a BranchPoint are grouped into two sets,
2377/// arbitrarily named "A-side" and "B-side". LaneEnds on the same "side"
2378/// have coincident into-the-lane tangent vectors, which are anti-parallel
2379/// to those of LaneEnds on the other side.
2380pub struct BranchPoint<'a> {
2381    branch_point: &'a maliput_sys::api::ffi::BranchPoint,
2382}
2383
2384impl<'a> BranchPoint<'a> {
2385    /// Returns the id of the BranchPoint.
2386    ///
2387    /// # Returns
2388    /// A `String` containing the id of the BranchPoint.
2389    pub fn id(&self) -> String {
2390        maliput_sys::api::ffi::BranchPoint_id(self.branch_point)
2391    }
2392    /// Returns the [RoadGeometry] to which this BranchPoint belongs.
2393    ///
2394    /// # Returns
2395    /// A [RoadGeometry] containing the RoadGeometry to which this BranchPoint belongs.
2396    pub fn road_geometry(&self) -> RoadGeometry<'_> {
2397        unsafe {
2398            RoadGeometry {
2399                rg: self.branch_point.road_geometry().as_ref().expect(""),
2400            }
2401        }
2402    }
2403    /// Returns the set of [LaneEnd]s on the same side as the given [LaneEnd].
2404    /// E.g: For a T-junction, this would return the set of LaneEnds on the merging side.
2405    ///
2406    /// # Arguments
2407    /// * `end` - This branch's start or end [LaneEnd].
2408    ///
2409    /// # Return
2410    /// A [LaneEndSet] of [LaneEnd]s on the same side as the given [LaneEnd].
2411    pub fn get_confluent_branches(&self, end: &LaneEnd) -> Result<LaneEndSet<'_>, MaliputError> {
2412        let lane_end_set_ptr = self.branch_point.GetConfluentBranches(
2413            BranchPoint::from_lane_end_to_ffi(end)
2414                .as_ref()
2415                .expect("Underlying LaneEnd is null"),
2416        )?;
2417        Ok(LaneEndSet {
2418            lane_end_set: unsafe { lane_end_set_ptr.as_ref().expect("Underlying LaneEndSet is null") },
2419        })
2420    }
2421    /// Returns the set of [LaneEnd]s on the opposite side as the given [LaneEnd].
2422    /// E.g: For a T-junction, this would return the [LaneEnd]s which end flows into the junction.
2423    ///
2424    /// # Arguments
2425    /// * `end` - This branch's start or end [LaneEnd].
2426    ///
2427    /// # Return
2428    /// A [LaneEndSet] of [LaneEnd]s on the opposite side as the given [LaneEnd].
2429    pub fn get_ongoing_branches(&self, end: &LaneEnd) -> Result<LaneEndSet<'_>, MaliputError> {
2430        let lane_end_set_ptr = self.branch_point.GetOngoingBranches(
2431            BranchPoint::from_lane_end_to_ffi(end)
2432                .as_ref()
2433                .expect("Underlying LaneEnd is null"),
2434        )?;
2435        Ok(LaneEndSet {
2436            lane_end_set: unsafe { lane_end_set_ptr.as_ref().expect("Underlying LaneEndSet is null") },
2437        })
2438    }
2439    /// Returns the default ongoing branch (if any) for the given `end`.
2440    /// This typically represents what would be considered "continuing
2441    /// through-traffic" from `end` (e.g., as opposed to a branch executing
2442    /// a turn).
2443    ///
2444    /// If `end` has no default-branch at this BranchPoint, the return
2445    /// value will be None.
2446    ///
2447    /// # Arguments
2448    /// * `end` - The [LaneEnd] for which to get the default branch.
2449    ///
2450    /// # Returns
2451    /// An `Option<LaneEnd>` containing the default branch if it exists.
2452    /// If no default branch exists, it returns None.
2453    pub fn get_default_branch(&self, end: &LaneEnd) -> Option<LaneEnd<'_>> {
2454        let lane_end = maliput_sys::api::ffi::BranchPoint_GetDefaultBranch(
2455            self.branch_point,
2456            BranchPoint::from_lane_end_to_ffi(end)
2457                .as_ref()
2458                .expect("Underlying LaneEnd is null"),
2459        );
2460        match lane_end.is_null() {
2461            true => None,
2462            false => {
2463                let lane_end_ref: &maliput_sys::api::ffi::LaneEnd =
2464                    lane_end.as_ref().expect("Underlying LaneEnd is null");
2465                let is_start = maliput_sys::api::ffi::LaneEnd_is_start(lane_end_ref);
2466                let lane_ref = unsafe {
2467                    maliput_sys::api::ffi::LaneEnd_lane(lane_end_ref)
2468                        .as_ref()
2469                        .expect("Underlying LaneEnd is null")
2470                };
2471                match is_start {
2472                    true => Some(LaneEnd::Start(Lane { lane: lane_ref })),
2473                    false => Some(LaneEnd::Finish(Lane { lane: lane_ref })),
2474                }
2475            }
2476        }
2477    }
2478    /// Returns the set of LaneEnds grouped together on the "A-side".
2479    ///
2480    /// # Returns
2481    /// A [LaneEndSet] containing the LaneEnds on the "A-side" of the BranchPoint.
2482    pub fn get_a_side(&self) -> LaneEndSet<'_> {
2483        let lane_end_set_ptr = self.branch_point.GetASide();
2484        LaneEndSet {
2485            lane_end_set: unsafe { lane_end_set_ptr.as_ref().expect("Underlying LaneEndSet is null") },
2486        }
2487    }
2488    /// Returns the set of LaneEnds grouped together on the "B-side".
2489    ///
2490    /// # Returns
2491    /// A [LaneEndSet] containing the LaneEnds on the "B-side" of the BranchPoint.
2492    /// This is the opposite side of the "A-side".
2493    pub fn get_b_side(&self) -> LaneEndSet<'_> {
2494        let lane_end_set_ptr = self.branch_point.GetBSide();
2495        LaneEndSet {
2496            lane_end_set: unsafe { lane_end_set_ptr.as_ref().expect("Underlying LaneEndSet is null") },
2497        }
2498    }
2499    /// Converts LaneEnd enum to LaneEnd ffi.
2500    fn from_lane_end_to_ffi(end: &LaneEnd) -> cxx::UniquePtr<maliput_sys::api::ffi::LaneEnd> {
2501        match end {
2502            LaneEnd::Start(lane) => unsafe { maliput_sys::api::ffi::LaneEnd_new(lane.lane, true) },
2503            LaneEnd::Finish(lane) => unsafe { maliput_sys::api::ffi::LaneEnd_new(lane.lane, false) },
2504        }
2505    }
2506}
2507
2508/// An abstract convenience class that aggregates information pertaining to an
2509/// intersection. Its primary purpose is to serve as a single source of this
2510/// information and to remove the need for users to query numerous disparate
2511/// data structures and state providers.
2512pub struct Intersection<'a> {
2513    intersection: &'a maliput_sys::api::ffi::Intersection,
2514}
2515
2516impl<'a> Intersection<'a> {
2517    /// Returns the id of the `Intersection` as a string.
2518    pub fn id(&self) -> String {
2519        maliput_sys::api::ffi::Intersection_id(self.intersection)
2520    }
2521    /// Returns the current `phase` of the [Intersection].
2522    ///
2523    /// Based on the current `phase`, it returns a [rules::StateProviderQuery] with the phase's ID
2524    /// and the next state.
2525    ///
2526    /// # Returns
2527    /// A [rules::StateProviderQuery] for the current [rules::Phase].
2528    pub fn phase(&self) -> rules::StateProviderQuery<String> {
2529        let query = maliput_sys::api::ffi::Intersection_Phase(self.intersection);
2530        let next_state = maliput_sys::api::rules::ffi::PhaseStateProvider_next(&query);
2531        let next_state = if next_state.is_null() {
2532            None
2533        } else {
2534            Some(rules::NextState {
2535                next_state: next_state.phase_id.clone(),
2536                duration_until: if next_state.duration_until.is_null() {
2537                    None
2538                } else {
2539                    Some(next_state.duration_until.value)
2540                },
2541            })
2542        };
2543        rules::StateProviderQuery {
2544            state: maliput_sys::api::rules::ffi::PhaseStateProvider_state(&query),
2545            next: next_state,
2546        }
2547    }
2548    /// Returns the region of the `RoadNetwork` that is considered part of the `Intersection`.
2549    ///
2550    /// # Returns
2551    /// A vector of [LaneSRange]s where the intersection lives.
2552    pub fn region(&self) -> Vec<LaneSRange> {
2553        self.intersection
2554            .region()
2555            .iter()
2556            .map(|region| LaneSRange {
2557                lane_s_range: maliput_sys::api::ffi::LaneSRange_new(
2558                    &maliput_sys::api::ffi::LaneSRange_lane_id(region),
2559                    &maliput_sys::api::ffi::LaneSRange_s_range(region),
2560                ),
2561            })
2562            .collect::<Vec<LaneSRange>>()
2563    }
2564    /// Returns the ID of the [rules::PhaseRing] that applies to this intersection.
2565    ///
2566    /// # Returns
2567    /// A `String` with the ID of a [rules::PhaseRing].
2568    pub fn phase_ring_id(&self) -> String {
2569        maliput_sys::api::ffi::Intersection_ring_id(self.intersection)
2570    }
2571    pub fn bulb_ids(&self) -> Vec<rules::UniqueBulbId> {
2572        maliput_sys::api::ffi::Intersection_unique_bulb_ids(self.intersection)
2573            .iter()
2574            .map(|unique_bulb_id| rules::UniqueBulbId {
2575                unique_bulb_id: maliput_sys::api::rules::ffi::UniqueBulbId_create_unique_ptr(unique_bulb_id),
2576            })
2577            .collect()
2578    }
2579    /// Returns the current [rules::BulbState]s within the `Intersection`.
2580    ///
2581    /// # Returns
2582    /// A vector of [rules::BulbState]s.
2583    pub fn get_bulb_state(&self, unique_bulb_id: &rules::UniqueBulbId) -> Option<rules::BulbState> {
2584        let bulb_state =
2585            maliput_sys::api::ffi::Intersection_bulb_state(self.intersection, &unique_bulb_id.unique_bulb_id);
2586        if bulb_state.is_null() {
2587            return None;
2588        }
2589        match *bulb_state {
2590            maliput_sys::api::ffi::BulbState::kOn => Some(rules::BulbState::On),
2591            maliput_sys::api::ffi::BulbState::kOff => Some(rules::BulbState::Off),
2592            maliput_sys::api::ffi::BulbState::kBlinking => Some(rules::BulbState::Blinking),
2593            _ => None,
2594        }
2595    }
2596    /// Returns the current discrete value rule states within the intersection.
2597    pub fn discrete_value_rule_states(&self) -> Vec<rules::DiscreteValueRuleState> {
2598        maliput_sys::api::ffi::Intersection_DiscreteValueRuleStates(self.intersection)
2599            .iter()
2600            .map(|dvrs| rules::DiscreteValueRuleState {
2601                rule_id: dvrs.rule_id.clone(),
2602                state: rules::discrete_value_from_discrete_value_cxx(&dvrs.state),
2603            })
2604            .collect::<Vec<rules::DiscreteValueRuleState>>()
2605    }
2606    /// Determines whether the [rules::TrafficLight] is within this [Intersection].
2607    ///
2608    /// # Arguments
2609    /// * `traffic_light_id` - A [rules::TrafficLight] ID.
2610    ///
2611    /// # Returns
2612    /// True when `traffic_light_id` is within this [Intersection].
2613    pub fn includes_traffic_light(&self, traffic_light_id: &str) -> bool {
2614        maliput_sys::api::ffi::Intersection_IncludesTrafficLight(self.intersection, &traffic_light_id.to_string())
2615    }
2616    /// Determines whether the [rules::DiscreteValueRule] is within this [Intersection].
2617    ///
2618    /// # Arguments
2619    /// * `rule_id` - A [rules::DiscreteValueRule] ID.
2620    ///
2621    /// # Returns
2622    /// True when `rule_id` is within this [Intersection].
2623    pub fn includes_discrete_value_rule(&self, rule_id: &str) -> bool {
2624        maliput_sys::api::ffi::Intersection_IncludesDiscreteValueRule(self.intersection, &rule_id.to_string())
2625    }
2626    /// Determines whether `inertial_position` is within this [Intersection::region].
2627    ///
2628    /// `inertial_position` is contained if the distance to the closest LanePosition in
2629    /// [Intersection::region] is less or equal than the linear tolerance of the `road_geometry`.
2630    ///
2631    /// # Arguments
2632    /// * `inertial_position` -  An [InertialPosition] in the `Inertial`-frame.
2633    /// * `road_geometry` - The [RoadGeometry].
2634    ///
2635    /// # Returns
2636    /// True when `inertial_position` is within [Intersection::region]. False otherwise.
2637    pub fn includes_inertial_position(
2638        &self,
2639        inertial_position: &InertialPosition,
2640        road_geometry: &RoadGeometry,
2641    ) -> bool {
2642        maliput_sys::api::ffi::Intersection_IncludesInertialPosition(
2643            self.intersection,
2644            &maliput_sys::api::ffi::InertialPosition_new(
2645                inertial_position.x(),
2646                inertial_position.y(),
2647                inertial_position.z(),
2648            ),
2649            road_geometry.rg,
2650        )
2651    }
2652}
2653
2654/// A book of Intersections.
2655pub struct IntersectionBook<'a> {
2656    intersection_book: &'a maliput_sys::api::ffi::IntersectionBook,
2657}
2658
2659impl<'a> IntersectionBook<'a> {
2660    /// Returns all Intersections in the book.
2661    ///
2662    /// # Returns
2663    /// A vector of [Intersection]s containing all Intersections in the book.
2664    pub fn get_intersections(&self) -> Vec<Intersection<'_>> {
2665        let intersections_cpp = maliput_sys::api::ffi::IntersectionBook_GetIntersections(self.intersection_book);
2666        unsafe {
2667            intersections_cpp
2668                .into_iter()
2669                .map(|intersection| Intersection {
2670                    intersection: intersection
2671                        .intersection
2672                        .as_ref()
2673                        .expect("Underlying Intersection is null"),
2674                })
2675                .collect::<Vec<Intersection>>()
2676        }
2677    }
2678
2679    /// Gets the specified Intersection.
2680    ///
2681    /// # Arguments
2682    ///   * `id` - The id of the Intersection to get.
2683    ///
2684    /// # Returns
2685    ///   * An `Option<Intersection>`
2686    ///     * Some(Intersection) - The Intersection with the specified id.
2687    ///     * None - If the Intersection with the specified id does not exist.
2688    pub fn get_intersection(&self, id: &str) -> Option<Intersection<'_>> {
2689        let intersection_option = unsafe {
2690            maliput_sys::api::ffi::IntersectionBook_GetIntersection(self.intersection_book, &String::from(id))
2691                .intersection
2692                .as_ref()
2693        };
2694        intersection_option.map(|intersection| Intersection { intersection })
2695    }
2696
2697    /// Finds the [Intersection] which contains the `traffic_light_id`.
2698    ///
2699    /// # Arguments
2700    /// * `traffic_light_id` - A String with the ID of a [rules::TrafficLight].
2701    ///
2702    /// # Returns
2703    /// The [Intersection] which contains the `traffic_light_id`.
2704    pub fn find_intersection_with_traffic_light(&self, traffic_light_id: &str) -> Option<Intersection<'_>> {
2705        let intersection = maliput_sys::api::ffi::IntersectionBook_FindIntersectionTrafficLight(
2706            self.intersection_book,
2707            &String::from(traffic_light_id),
2708        );
2709        if intersection.intersection.is_null() {
2710            return None;
2711        }
2712        unsafe {
2713            Some(Intersection {
2714                intersection: intersection
2715                    .intersection
2716                    .as_ref()
2717                    .expect("Underlying Intersection is null"),
2718            })
2719        }
2720    }
2721
2722    /// Finds the [Intersection] which contains the `rule_id`.
2723    ///
2724    /// # Arguments
2725    /// * `rule_id` - A String with the ID of a [rules::DiscreteValueRule].
2726    ///
2727    /// # Returns
2728    /// The [Intersection] which contains the `rule_id`.
2729    pub fn find_intersection_with_discrete_value_rule(&self, rule_id: &str) -> Option<Intersection<'_>> {
2730        let intersection = maliput_sys::api::ffi::IntersectionBook_FindIntersectionDiscreteValueRule(
2731            self.intersection_book,
2732            &String::from(rule_id),
2733        );
2734        if intersection.intersection.is_null() {
2735            return None;
2736        }
2737        unsafe {
2738            Some(Intersection {
2739                intersection: intersection
2740                    .intersection
2741                    .as_ref()
2742                    .expect("Underlying Intersection is null"),
2743            })
2744        }
2745    }
2746
2747    /// Finds the [Intersection] which contains the `inertial_position`.
2748    ///
2749    /// # Arguments
2750    /// * `inertial_position` - An [InertialPosition] to find the [Intersection] for.
2751    ///
2752    /// # Returns
2753    /// The [Intersection] which contains the `inertial_position`.
2754    pub fn find_intersection_with_inertial_position(
2755        &self,
2756        inertial_position: &InertialPosition,
2757    ) -> Option<Intersection<'_>> {
2758        let intersection = maliput_sys::api::ffi::IntersectionBook_FindIntersectionInertialPosition(
2759            self.intersection_book,
2760            &inertial_position.ip,
2761        );
2762        if intersection.intersection.is_null() {
2763            return None;
2764        }
2765        unsafe {
2766            Some(Intersection {
2767                intersection: intersection
2768                    .intersection
2769                    .as_ref()
2770                    .expect("Underlying Intersection is null"),
2771            })
2772        }
2773    }
2774}
2775
2776#[derive(Debug, Copy, Clone, PartialEq)]
2777pub struct LaneMarkingLine {
2778    /// Length of the visible (painted) part of each dash.
2779    /// For solid lines, this should be 0 (value is ignored).
2780    pub length: f64,
2781
2782    /// Length of the gap between visible parts.
2783    /// For solid lines, this should be 0.
2784    pub space: f64,
2785
2786    /// Width of this line, in meters.
2787    pub width: f64,
2788
2789    /// Lateral offset from the lane boundary.
2790    /// Positive values offset in the positive r-direction (towards the lane's
2791    /// left edge when facing the positive s-direction).
2792    /// This allows positioning multiple lines relative to each other.
2793    pub r_offset: f64,
2794
2795    /// Color of this specific line.
2796    /// If set to kUnknown, the parent LaneMarking's color should be used.
2797    pub color: LaneMarkingColor,
2798}
2799
2800impl LaneMarkingLine {
2801    /// Creates a new LaneMarkingLine.
2802    pub fn new(length: f64, space: f64, width: f64, r_offset: f64, color: LaneMarkingColor) -> LaneMarkingLine {
2803        LaneMarkingLine {
2804            length,
2805            space,
2806            width,
2807            r_offset,
2808            color,
2809        }
2810    }
2811}
2812
2813/// LaneMarking classification options.
2814///
2815/// LaneMarkingType defines types of lane markings on the road.
2816#[derive(strum_macros::Display, Debug, Copy, Clone, PartialEq, Eq)]
2817pub enum LaneMarkingType {
2818    Unknown,
2819    None,
2820    Solid,
2821    Broken,
2822    SolidSolid,
2823    SolidBroken,
2824    BrokenSolid,
2825    BrokenBroken,
2826    BottsDots,
2827    Grass,
2828    Curb,
2829    Edge,
2830}
2831
2832#[derive(strum_macros::Display, Debug, Copy, Clone, PartialEq, Eq)]
2833pub enum LaneMarkingWeight {
2834    Unknown,
2835    Standard,
2836    Bold,
2837}
2838
2839#[derive(strum_macros::Display, Debug, Copy, Clone, PartialEq, Eq)]
2840pub enum LaneMarkingColor {
2841    Unknown,
2842    White,
2843    Yellow,
2844    Orange,
2845    Red,
2846    Blue,
2847    Green,
2848    Violet,
2849}
2850
2851#[derive(strum_macros::Display, Debug, Copy, Clone, PartialEq, Eq)]
2852pub enum LaneChangePermission {
2853    Unknown,
2854    Allowed,
2855    ToLeft,
2856    ToRight,
2857    Prohibited,
2858}
2859
2860/// Describes the complete lane marking at a lane boundary.
2861///
2862/// A LaneMarking describes all properties of the road marking at a lane's
2863/// boundary. The marking can vary along the lane's s-coordinate, so this
2864/// structure represents the marking for a specific s-range.
2865///
2866/// **Simple markings:** For single-line markings (e.g., a solid white edge line),
2867/// the `type`, `color`, `width`, and `weight` fields are sufficient. The `lines`
2868/// vector can be left empty.
2869///
2870/// **Complex markings:** For compound markings (e.g., double lines with different
2871/// patterns like `kSolidBroken`), the `lines` vector provides detailed information
2872/// about each component line. When `lines` is non-empty, the individual line
2873/// definitions take precedence for geometry and per-line colors. The top-level
2874/// `type`, `color`, and `width` fields remain useful as summary/fallback values.
2875pub struct LaneMarking {
2876    lane_marking: cxx::UniquePtr<maliput_sys::api::ffi::LaneMarking>,
2877}
2878
2879impl LaneMarking {
2880    /// Returns the total width of the marking.
2881    pub fn width(&self) -> f64 {
2882        maliput_sys::api::ffi::LaneMarking_width(&self.lane_marking)
2883    }
2884
2885    /// Returns the total height of the marking.
2886    pub fn height(&self) -> f64 {
2887        maliput_sys::api::ffi::LaneMarking_height(&self.lane_marking)
2888    }
2889
2890    /// Returns the marking material.
2891    ///
2892    /// # Returns
2893    /// A [String] describing the marking material.
2894    pub fn material(&self) -> String {
2895        maliput_sys::api::ffi::LaneMarking_material(&self.lane_marking)
2896    }
2897
2898    /// Returns the type of marking.
2899    ///
2900    /// # Returns
2901    /// A [LaneMarkingType] representing the pattern or type of marking.
2902    pub fn get_type(&self) -> LaneMarkingType {
2903        let marking_type = maliput_sys::api::ffi::LaneMarking_type(&self.lane_marking);
2904        match marking_type {
2905            maliput_sys::api::ffi::LaneMarkingType::kUnknown => LaneMarkingType::Unknown,
2906            maliput_sys::api::ffi::LaneMarkingType::kNone => LaneMarkingType::None,
2907            maliput_sys::api::ffi::LaneMarkingType::kSolid => LaneMarkingType::Solid,
2908            maliput_sys::api::ffi::LaneMarkingType::kBroken => LaneMarkingType::Broken,
2909            maliput_sys::api::ffi::LaneMarkingType::kSolidSolid => LaneMarkingType::SolidSolid,
2910            maliput_sys::api::ffi::LaneMarkingType::kSolidBroken => LaneMarkingType::SolidBroken,
2911            maliput_sys::api::ffi::LaneMarkingType::kBrokenSolid => LaneMarkingType::BrokenSolid,
2912            maliput_sys::api::ffi::LaneMarkingType::kBrokenBroken => LaneMarkingType::BrokenBroken,
2913            maliput_sys::api::ffi::LaneMarkingType::kBottsDots => LaneMarkingType::BottsDots,
2914            maliput_sys::api::ffi::LaneMarkingType::kGrass => LaneMarkingType::Grass,
2915            maliput_sys::api::ffi::LaneMarkingType::kCurb => LaneMarkingType::Curb,
2916            maliput_sys::api::ffi::LaneMarkingType::kEdge => LaneMarkingType::Edge,
2917            _ => LaneMarkingType::Unknown,
2918        }
2919    }
2920
2921    /// Returns the visual weight or thickness type of the marking.
2922    ///
2923    /// # Returns
2924    /// A [LaneMarkingWeight] that indicates the type of visual weight of the marking.
2925    pub fn weight(&self) -> LaneMarkingWeight {
2926        let marking_weight = maliput_sys::api::ffi::LaneMarking_weight(&self.lane_marking);
2927        match marking_weight {
2928            maliput_sys::api::ffi::LaneMarkingWeight::kUnknown => LaneMarkingWeight::Unknown,
2929            maliput_sys::api::ffi::LaneMarkingWeight::kStandard => LaneMarkingWeight::Standard,
2930            maliput_sys::api::ffi::LaneMarkingWeight::kBold => LaneMarkingWeight::Bold,
2931            _ => LaneMarkingWeight::Unknown,
2932        }
2933    }
2934    pub fn color(&self) -> LaneMarkingColor {
2935        self.get_marking_color(maliput_sys::api::ffi::LaneMarking_color(&self.lane_marking))
2936    }
2937
2938    /// Returns the type of lane change the marking allows.
2939    ///
2940    /// # Returns
2941    /// A [LaneChangePermission] that indicates the type of lane change that is allowed.
2942    pub fn lane_change(&self) -> LaneChangePermission {
2943        let lane_change = maliput_sys::api::ffi::LaneMarking_lane_change(&self.lane_marking);
2944        match lane_change {
2945            maliput_sys::api::ffi::LaneChangePermission::kUnknown => LaneChangePermission::Unknown,
2946            maliput_sys::api::ffi::LaneChangePermission::kAllowed => LaneChangePermission::Allowed,
2947            maliput_sys::api::ffi::LaneChangePermission::kToLeft => LaneChangePermission::ToLeft,
2948            maliput_sys::api::ffi::LaneChangePermission::kToRight => LaneChangePermission::ToRight,
2949            maliput_sys::api::ffi::LaneChangePermission::kProhibited => LaneChangePermission::Prohibited,
2950            _ => LaneChangePermission::Unknown,
2951        }
2952    }
2953
2954    /// Returns all lines in the LaneMarking.
2955    ///
2956    /// # Returns
2957    /// A vector of [LaneMarkingLine]s.
2958    pub fn lines(&self) -> Vec<LaneMarkingLine> {
2959        let lines = maliput_sys::api::ffi::LaneMarking_lines(&self.lane_marking);
2960        lines
2961            .into_iter()
2962            .map(|line| LaneMarkingLine {
2963                length: maliput_sys::api::ffi::LaneMarkingLine_length(line),
2964                space: maliput_sys::api::ffi::LaneMarkingLine_space(line),
2965                width: maliput_sys::api::ffi::LaneMarkingLine_width(line),
2966                r_offset: maliput_sys::api::ffi::LaneMarkingLine_r_offset(line),
2967                color: self.get_marking_color(maliput_sys::api::ffi::LaneMarkingLine_color(line)),
2968            })
2969            .collect::<Vec<LaneMarkingLine>>()
2970    }
2971
2972    // Private helper to get marking color and avoid code duplication.
2973    fn get_marking_color(&self, color: maliput_sys::api::ffi::LaneMarkingColor) -> LaneMarkingColor {
2974        match color {
2975            maliput_sys::api::ffi::LaneMarkingColor::kUnknown => LaneMarkingColor::Unknown,
2976            maliput_sys::api::ffi::LaneMarkingColor::kWhite => LaneMarkingColor::White,
2977            maliput_sys::api::ffi::LaneMarkingColor::kYellow => LaneMarkingColor::Yellow,
2978            maliput_sys::api::ffi::LaneMarkingColor::kOrange => LaneMarkingColor::Orange,
2979            maliput_sys::api::ffi::LaneMarkingColor::kRed => LaneMarkingColor::Red,
2980            maliput_sys::api::ffi::LaneMarkingColor::kBlue => LaneMarkingColor::Blue,
2981            maliput_sys::api::ffi::LaneMarkingColor::kGreen => LaneMarkingColor::Green,
2982            maliput_sys::api::ffi::LaneMarkingColor::kViolet => LaneMarkingColor::Violet,
2983            _ => LaneMarkingColor::Unknown,
2984        }
2985    }
2986}
2987
2988/// The result of querying a [LaneMarking] at a specific position or range.
2989/// This structure pairs a [LaneMarking] with the s-range over which it is valid.
2990/// Lane markings can change along the lane (e.g., solid to broken at an
2991/// intersection approach), so the validity range is essential.
2992///
2993/// The range uses half-open interval semantics: `[s_start, s_end)`.
2994pub struct LaneMarkingQuery {
2995    /// LaneMarking description.
2996    pub lane_marking: LaneMarking,
2997    /// Start s-coordinate where the marking begins
2998    /// This is relative to the lane's s-coordinate system..
2999    pub s_start: f64,
3000    /// End s-coordinate where the marking ends.
3001    /// This is relative to the lane's s-coordinate system.
3002    pub s_end: f64,
3003}
3004
3005/// Represents a boundary between adjacent lanes or at the edge of a Segment.
3006///
3007/// A [LaneBoundary] is owned by a [Segment] and serves as the interface between
3008/// two adjacent lanes, or between a lane and the segment edge. For a [Segment]
3009/// with N lanes, there are N+1 boundaries:
3010///
3011/// ```text
3012///                                                        +r direction
3013///                                                      <─────────────
3014///   Boundary N    ...    Boundary 2    Boundary 1    Boundary 0
3015///      |                     |             |             |
3016///      | Lane N-1  |   ...   |   Lane 1    |   Lane 0    |
3017///      |                     |             |             |
3018///  (left edge)                                     (right edge)
3019/// ```
3020///
3021/// Where:
3022/// - Boundary 0 is the right edge (minimum r coordinate).
3023/// - Boundary N is the left edge (maximum r coordinate).
3024/// - Boundaries are indexed with increasing r direction.
3025///
3026/// Each [LaneBoundary] provides:
3027/// - Reference to the lane on its left (if any).
3028/// - Reference to the lane on its right (if any).
3029/// - Query methods for lane markings at specific s-coordinates.
3030///
3031/// The design ensures that adjacent lanes share the same boundary object,
3032/// avoiding redundancy and ensuring consistency. For example, [Lane] 1's right
3033/// boundary is the same object as [Lane] 0's left boundary (Boundary 1).
3034pub struct LaneBoundary<'a> {
3035    lane_boundary: &'a maliput_sys::api::ffi::LaneBoundary,
3036}
3037
3038impl<'a> LaneBoundary<'a> {
3039    /// Returns the ID of the [LaneBoundary].
3040    /// The ID is a unique identifier for the [LaneBoundary] within the Segment.
3041    ///
3042    /// # Returns
3043    /// A `String` containing the ID of the [LaneBoundary].
3044    pub fn id(&self) -> String {
3045        maliput_sys::api::ffi::LaneBoundary_id(self.lane_boundary)
3046    }
3047
3048    /// Returns the segment that contains this [LaneBoundary].
3049    ///
3050    /// # Returns
3051    /// An `Option<Segment>` containing a reference to the [Segment] if it exists,
3052    /// or `None` if the [LaneBoundary] is not associated with a segment.
3053    pub fn segment(&self) -> Option<Segment<'a>> {
3054        let segment = self.lane_boundary.segment();
3055        if segment.is_null() {
3056            return None;
3057        }
3058        Some(unsafe {
3059            Segment {
3060                segment: segment.as_ref().expect(""),
3061            }
3062        })
3063    }
3064
3065    /// Returns the index of this boundary within the parent [Segment].
3066    ///
3067    /// Boundaries are indexed from 0 (rightmost, minimum r) to num_lanes()
3068    /// (leftmost, maximum r).
3069    pub fn index(&self) -> i32 {
3070        self.lane_boundary.index()
3071    }
3072
3073    /// Returns the [Lane] immediately to the left of this boundary (increasing r direction).
3074    ///
3075    /// # Returns
3076    /// An `Option<Lane>` containing the lane to the left, or `None` if this is
3077    /// the leftmost boundary of the [Segment].
3078    pub fn lane_to_left(&self) -> Option<Lane<'a>> {
3079        let lane = self.lane_boundary.lane_to_left();
3080        if lane.is_null() {
3081            return None;
3082        }
3083        Some(unsafe {
3084            Lane {
3085                lane: lane.as_ref().expect("Lane pointer from lane_to_left is null"),
3086            }
3087        })
3088    }
3089
3090    /// Returns the [Lane] immediately to the right of this boundary (decreasing r direction).
3091    ///
3092    /// # Returns
3093    /// An `Option<Lane>` containing the lane to the right, or `None` if this is
3094    /// the rightmost boundary of the Segment.
3095    pub fn lane_to_right(&self) -> Option<Lane<'a>> {
3096        let lane = self.lane_boundary.lane_to_right();
3097        if lane.is_null() {
3098            return None;
3099        }
3100        Some(unsafe {
3101            Lane {
3102                lane: lane.as_ref().expect("Lane pointer from lane_to_right is null"),
3103            }
3104        })
3105    }
3106
3107    /// Gets the lane marking at a specific s-coordinate along this boundary.
3108    ///
3109    /// # Arguments
3110    /// * `s` - The s-coordinate along the boundary (in the lane coordinate system).
3111    ///   Typically in the range [0, segment_length].
3112    ///
3113    /// # Returns
3114    /// A [LaneMarkingQuery] at the specified position, including the marking details and the
3115    /// s-range over which it is valid, or `None` if no marking information is available at that location.
3116    pub fn get_marking(&self, s: f64) -> Option<LaneMarkingQuery> {
3117        let lane_marking_query = maliput_sys::api::ffi::LaneBoundary_GetMarking(self.lane_boundary, s);
3118        if lane_marking_query.is_null() {
3119            return None;
3120        }
3121        Some(self.create_lane_marking_query(&lane_marking_query))
3122    }
3123
3124    /// Gets all lane markings along this boundary.
3125    ///
3126    /// # Returns
3127    /// A vector of [LaneMarkingQuery], each describing a marking and the s-range over which it is valid.
3128    /// The queried results are ordered by increasing s_start. If no markings are available, returns an empty vector.
3129    pub fn get_markings(&self) -> Vec<LaneMarkingQuery> {
3130        let lane_marking_queries = maliput_sys::api::ffi::LaneBoundary_GetMarkings(self.lane_boundary);
3131        lane_marking_queries
3132            .into_iter()
3133            .map(|lane_marking_query| self.create_lane_marking_query(lane_marking_query))
3134            .collect::<Vec<LaneMarkingQuery>>()
3135    }
3136
3137    /// Gets lane markings within a specified s-range.
3138    ///
3139    /// # Arguments
3140    /// * `s_start` - Start of the s-range to query.
3141    /// * `s_end` - End of the s-range to query.
3142    ///
3143    /// # Returns
3144    /// A vector of [LaneMarkingQuery] for markings that overlap with the specified range. Queried results are ordered by increasing `s_start`.
3145    /// If no markings are available in the range, returns an empty vector.
3146    pub fn get_markings_by_range(&self, s_start: f64, s_end: f64) -> Vec<LaneMarkingQuery> {
3147        let lane_marking_queries =
3148            maliput_sys::api::ffi::LaneBoundary_GetMarkingsByRange(self.lane_boundary, s_start, s_end);
3149        lane_marking_queries
3150            .into_iter()
3151            .map(|lane_marking_query| self.create_lane_marking_query(lane_marking_query))
3152            .collect::<Vec<LaneMarkingQuery>>()
3153    }
3154
3155    // Private helper to create a LaneMarkingQuery.
3156    fn create_lane_marking_query(
3157        &self,
3158        lane_marking_query: &maliput_sys::api::ffi::LaneMarkingResult,
3159    ) -> LaneMarkingQuery {
3160        LaneMarkingQuery {
3161            lane_marking: LaneMarking {
3162                lane_marking: maliput_sys::api::ffi::LaneMarkingResult_marking(lane_marking_query),
3163            },
3164            s_start: maliput_sys::api::ffi::LaneMarkingResult_s_start(lane_marking_query),
3165            s_end: maliput_sys::api::ffi::LaneMarkingResult_s_end(lane_marking_query),
3166        }
3167    }
3168}
3169
3170mod tests {
3171    mod road_geometry {
3172        #[test]
3173        fn to_road_position_surface_test() {
3174            let package_location = std::env::var("CARGO_MANIFEST_DIR").unwrap();
3175            let xodr_path = format!("{}/data/xodr/TShapeRoad.xodr", package_location);
3176            let road_network_properties = std::collections::HashMap::from([
3177                ("road_geometry_id", "my_rg_from_rust"),
3178                ("opendrive_file", xodr_path.as_str()),
3179            ]);
3180            let road_network = crate::api::RoadNetwork::new(
3181                crate::api::RoadNetworkBackend::MaliputMalidrive,
3182                &road_network_properties,
3183            )
3184            .unwrap();
3185            let road_geometry = road_network.road_geometry();
3186
3187            // Although this isn't directly on the surface, it is within the RoadGeometry volume.
3188            let inertial_pos = crate::api::InertialPosition::new(1.0, 0.0, 2.0);
3189            let road_pos = road_geometry.to_road_position_surface(&inertial_pos);
3190            assert!(road_pos.is_ok());
3191            let road_pos = road_pos.unwrap();
3192            let tolerance = 1e-3;
3193            assert!((road_pos.pos().s() - 1.0).abs() < tolerance);
3194            assert!((road_pos.pos().r() - -1.75).abs() < tolerance);
3195            assert!((road_pos.pos().h() - 0.0).abs() < tolerance);
3196
3197            // An inertial position that is off the road volume.
3198            let inertial_pos = crate::api::InertialPosition::new(1.0, 0.0, 10.0);
3199            let road_pos = road_geometry.to_road_position_surface(&inertial_pos);
3200            assert!(road_pos.is_err());
3201        }
3202    }
3203    mod lane_position {
3204        #[test]
3205        fn lane_position_new() {
3206            let lane_pos = crate::api::LanePosition::new(1.0, 2.0, 3.0);
3207            assert_eq!(lane_pos.s(), 1.0);
3208            assert_eq!(lane_pos.r(), 2.0);
3209            assert_eq!(lane_pos.h(), 3.0);
3210        }
3211
3212        #[test]
3213        fn equality() {
3214            let v = crate::api::LanePosition::new(1.0, 2.0, 3.0);
3215            let w = crate::api::LanePosition::new(1.0, 2.0, 3.0);
3216            assert_eq!(v, w);
3217            let z = crate::api::LanePosition::new(4.0, 5.0, 6.0);
3218            assert_ne!(v, z);
3219        }
3220
3221        #[test]
3222        fn set_s() {
3223            let mut lane_pos = crate::api::LanePosition::new(1.0, 2.0, 3.0);
3224            lane_pos.set_s(4.0);
3225            assert_eq!(lane_pos.s(), 4.0);
3226        }
3227
3228        #[test]
3229        fn set_r() {
3230            let mut lane_pos = crate::api::LanePosition::new(1.0, 2.0, 3.0);
3231            lane_pos.set_r(4.0);
3232            assert_eq!(lane_pos.r(), 4.0);
3233        }
3234
3235        #[test]
3236        fn set_h() {
3237            let mut lane_pos = crate::api::LanePosition::new(1.0, 2.0, 3.0);
3238            lane_pos.set_h(4.0);
3239            assert_eq!(lane_pos.h(), 4.0);
3240        }
3241
3242        #[test]
3243        fn set_srh() {
3244            use crate::math::Vector3;
3245            let mut lane_pos = crate::api::LanePosition::new(1.0, 2.0, 3.0);
3246            let vector = Vector3::new(4.0, 5.0, 6.0);
3247            lane_pos.set_srh(&vector);
3248            assert_eq!(lane_pos.s(), 4.0);
3249            assert_eq!(lane_pos.r(), 5.0);
3250            assert_eq!(lane_pos.h(), 6.0);
3251        }
3252    }
3253
3254    mod inertial_position {
3255
3256        #[test]
3257        fn inertial_position_new() {
3258            let inertial_pos = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
3259            assert_eq!(inertial_pos.x(), 1.0);
3260            assert_eq!(inertial_pos.y(), 2.0);
3261            assert_eq!(inertial_pos.z(), 3.0);
3262        }
3263
3264        #[test]
3265        fn equality() {
3266            let v = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
3267            let w = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
3268            assert_eq!(v, w);
3269            let z = crate::api::InertialPosition::new(4.0, 5.0, 6.0);
3270            assert_ne!(v, z);
3271        }
3272
3273        #[test]
3274        fn set_x() {
3275            let mut inertial_pos = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
3276            inertial_pos.set_x(4.0);
3277            assert_eq!(inertial_pos.x(), 4.0);
3278        }
3279
3280        #[test]
3281        fn set_y() {
3282            let mut inertial_pos = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
3283            inertial_pos.set_y(4.0);
3284            assert_eq!(inertial_pos.y(), 4.0);
3285        }
3286
3287        #[test]
3288        fn set_z() {
3289            let mut inertial_pos = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
3290            inertial_pos.set_z(4.0);
3291            assert_eq!(inertial_pos.z(), 4.0);
3292        }
3293
3294        #[test]
3295        fn set_xyz() {
3296            use crate::math::Vector3;
3297            let mut inertial_pos = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
3298            let vector = Vector3::new(4.0, 5.0, 6.0);
3299            inertial_pos.set_xyz(&vector);
3300            assert_eq!(inertial_pos.x(), 4.0);
3301            assert_eq!(inertial_pos.y(), 5.0);
3302            assert_eq!(inertial_pos.z(), 6.0);
3303        }
3304
3305        #[test]
3306        fn xyz() {
3307            let inertial_pos = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
3308            assert_eq!(inertial_pos.xyz(), crate::math::Vector3::new(1.0, 2.0, 3.0));
3309        }
3310
3311        #[test]
3312        fn length() {
3313            let inertial_pos = crate::api::InertialPosition::new(3.0, 0.0, 4.0);
3314            assert_eq!(inertial_pos.length(), 5.0);
3315        }
3316
3317        #[test]
3318        fn distance() {
3319            let inertial_pos1 = crate::api::InertialPosition::new(1.0, 1.0, 1.0);
3320            let inertial_pos2 = crate::api::InertialPosition::new(5.0, 1.0, 1.0);
3321            assert_eq!(inertial_pos1.distance(&inertial_pos2), 4.0);
3322        }
3323
3324        #[test]
3325        fn str() {
3326            let inertial_pos = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
3327            assert_eq!(inertial_pos.to_string(), "(x = 1, y = 2, z = 3)");
3328        }
3329
3330        #[test]
3331        fn add_operation() {
3332            let inertial_pos1 = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
3333            let inertial_pos2 = crate::api::InertialPosition::new(4.0, 5.0, 6.0);
3334            let inertial_pos3 = inertial_pos1 + inertial_pos2;
3335            assert_eq!(inertial_pos3.x(), 5.0);
3336            assert_eq!(inertial_pos3.y(), 7.0);
3337            assert_eq!(inertial_pos3.z(), 9.0);
3338        }
3339
3340        #[test]
3341        fn sub_operation() {
3342            let inertial_pos1 = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
3343            let inertial_pos2 = crate::api::InertialPosition::new(4.0, 5.0, 6.0);
3344            let inertial_pos3 = inertial_pos1 - inertial_pos2;
3345            assert_eq!(inertial_pos3.x(), -3.0);
3346            assert_eq!(inertial_pos3.y(), -3.0);
3347            assert_eq!(inertial_pos3.z(), -3.0);
3348        }
3349
3350        #[test]
3351        fn mul_scalar_operation() {
3352            let inertial_pos1 = crate::api::InertialPosition::new(1.0, 2.0, 3.0);
3353            let inertial_pos2 = inertial_pos1 * 2.0;
3354            assert_eq!(inertial_pos2.x(), 2.0);
3355            assert_eq!(inertial_pos2.y(), 4.0);
3356            assert_eq!(inertial_pos2.z(), 6.0);
3357        }
3358    }
3359    mod rotation {
3360        #[test]
3361        fn rotation_new() {
3362            let rotation = crate::api::Rotation::new();
3363            assert_eq!(rotation.roll(), 0.0);
3364            assert_eq!(rotation.pitch(), 0.0);
3365            assert_eq!(rotation.yaw(), 0.0);
3366        }
3367
3368        #[test]
3369        fn from_quat() {
3370            let quat = crate::math::Quaternion::new(1.0, 0.0, 0.0, 0.0);
3371            let rotation = crate::api::Rotation::from_quat(&quat);
3372            assert_eq!(rotation.roll(), 0.0);
3373            assert_eq!(rotation.pitch(), 0.0);
3374            assert_eq!(rotation.yaw(), 0.0);
3375        }
3376
3377        #[test]
3378        fn from_rpy() {
3379            let rpy = crate::math::RollPitchYaw::new(0.0, 0.0, 0.0);
3380            let rotation = crate::api::Rotation::from_rpy(&rpy);
3381            assert_eq!(rotation.roll(), 0.0);
3382            assert_eq!(rotation.pitch(), 0.0);
3383            assert_eq!(rotation.yaw(), 0.0);
3384        }
3385
3386        #[test]
3387        fn set_quat() {
3388            let mut rotation = crate::api::Rotation::new();
3389            let quat = crate::math::Quaternion::new(1.0, 0.0, 0.0, 0.0);
3390            rotation.set_quat(&quat);
3391            assert_eq!(rotation.roll(), 0.0);
3392            assert_eq!(rotation.pitch(), 0.0);
3393            assert_eq!(rotation.yaw(), 0.0);
3394        }
3395
3396        #[test]
3397        fn matrix() {
3398            let rotation = crate::api::Rotation::new();
3399            let matrix = rotation.matrix();
3400            assert_eq!(matrix.row(0), crate::math::Vector3::new(1.0, 0.0, 0.0));
3401            assert_eq!(matrix.row(1), crate::math::Vector3::new(0.0, 1.0, 0.0));
3402            assert_eq!(matrix.row(2), crate::math::Vector3::new(0.0, 0.0, 1.0));
3403        }
3404    }
3405
3406    mod s_range {
3407        #[test]
3408        fn s_range_new() {
3409            let s_range = crate::api::SRange::new(1.0, 2.0);
3410            assert_eq!(s_range.s0(), 1.0);
3411            assert_eq!(s_range.s1(), 2.0);
3412        }
3413        #[test]
3414        fn s_range_api() {
3415            let s_range_1 = crate::api::SRange::new(1.0, 3.0);
3416            let s_range_2 = crate::api::SRange::new(2.0, 4.0);
3417            assert_eq!(s_range_1.size(), 2.0);
3418            assert!(s_range_1.with_s());
3419            assert!(s_range_1.intersects(&s_range_2, 0.0));
3420            assert!(!s_range_1.contains(&s_range_2, 0.0));
3421        }
3422        #[test]
3423        fn s_range_setters() {
3424            let mut s_range = crate::api::SRange::new(0.0, 4.0);
3425            s_range.set_s0(1.0);
3426            s_range.set_s1(3.0);
3427            assert_eq!(s_range.s0(), 1.0);
3428            assert_eq!(s_range.s1(), 3.0);
3429        }
3430        #[test]
3431        fn s_range_get_intersection_with_intersection() {
3432            let s_range_1 = crate::api::SRange::new(1.0, 3.0);
3433            let s_range_2 = crate::api::SRange::new(2.0, 4.0);
3434            let intersection = s_range_1.get_intersection(&s_range_2, 0.0);
3435            assert!(intersection.is_some());
3436            let intersection = intersection.unwrap();
3437            assert_eq!(intersection.s0(), 2.0);
3438            assert_eq!(intersection.s1(), 3.0);
3439        }
3440        #[test]
3441        fn s_range_get_intersection_with_no_intersection() {
3442            let s_range_1 = crate::api::SRange::new(1.0, 2.0);
3443            let s_range_2 = crate::api::SRange::new(3.0, 4.0);
3444            let intersection = s_range_1.get_intersection(&s_range_2, 0.0);
3445            assert!(intersection.is_none());
3446        }
3447    }
3448
3449    mod lane_s_range {
3450        #[test]
3451        fn lane_s_range_new() {
3452            let lane_s_range =
3453                crate::api::LaneSRange::new(&String::from("lane_test"), &crate::api::SRange::new(1.0, 2.0));
3454            assert_eq!(lane_s_range.lane_id(), "lane_test");
3455            assert_eq!(lane_s_range.s_range().s0(), 1.0);
3456            assert_eq!(lane_s_range.s_range().s1(), 2.0);
3457            assert_eq!(lane_s_range.length(), 1.0);
3458        }
3459        #[test]
3460        fn lane_s_range_api() {
3461            let lane_s_range_1 =
3462                crate::api::LaneSRange::new(&String::from("lane_test"), &crate::api::SRange::new(1.0, 2.0));
3463            let lane_s_range_2 =
3464                crate::api::LaneSRange::new(&String::from("lane_test"), &crate::api::SRange::new(2.0, 3.0));
3465            assert!(lane_s_range_1.intersects(&lane_s_range_2, 0.0));
3466            assert!(!lane_s_range_1.contains(&lane_s_range_2, 0.0));
3467        }
3468        #[test]
3469        fn lane_s_range_get_intersection_with_intersection() {
3470            let lane_s_range_1 =
3471                crate::api::LaneSRange::new(&String::from("lane_test"), &crate::api::SRange::new(1.0, 3.0));
3472            let lane_s_range_2 =
3473                crate::api::LaneSRange::new(&String::from("lane_test"), &crate::api::SRange::new(2.0, 4.0));
3474            let intersection = lane_s_range_1.get_intersection(&lane_s_range_2, 0.0);
3475            assert!(intersection.is_some());
3476            let intersection = intersection.unwrap();
3477            assert_eq!(intersection.lane_id(), "lane_test");
3478            assert_eq!(intersection.s_range().s0(), 2.0);
3479            assert_eq!(intersection.s_range().s1(), 3.0);
3480        }
3481        #[test]
3482        fn lane_s_range_get_intersection_with_no_intersection() {
3483            let lane_s_range_1 =
3484                crate::api::LaneSRange::new(&String::from("lane test_1"), &crate::api::SRange::new(1.0, 3.0));
3485            let lane_s_range_2 =
3486                crate::api::LaneSRange::new(&String::from("lane_test_2"), &crate::api::SRange::new(2.0, 4.0));
3487            let intersection = lane_s_range_1.get_intersection(&lane_s_range_2, 0.0);
3488            assert!(intersection.is_none());
3489        }
3490    }
3491
3492    mod lane_s_route {
3493        // Helper function to create a LaneSRoute
3494        // with two LaneSRange.
3495        // # Arguments
3496        // * `s0_0` - The s0 of the first LaneSRange.
3497        // * `s1_0` - The s1 of the first LaneSRange.
3498        // * `s0_1` - The s0 of the second LaneSRange.
3499        // * `s1_1` - The s1 of the second LaneSRange.
3500        fn _get_lane_s_route(s0_0: f64, s1_0: f64, s0_1: f64, s1_1: f64) -> crate::api::LaneSRoute {
3501            let ranges = vec![
3502                crate::api::LaneSRange::new(&String::from("lane_test_1"), &crate::api::SRange::new(s0_0, s1_0)),
3503                crate::api::LaneSRange::new(&String::from("lane_test_2"), &crate::api::SRange::new(s0_1, s1_1)),
3504            ];
3505            crate::api::LaneSRoute::new(ranges)
3506        }
3507        #[test]
3508        fn lane_s_route_new() {
3509            let lane_s_route = _get_lane_s_route(0., 10., 0., 15.);
3510            assert!(!lane_s_route.lane_s_route.is_null());
3511            let ranges = lane_s_route.ranges();
3512            assert_eq!(ranges.len(), 2);
3513            assert_eq!(ranges[0].lane_id(), "lane_test_1");
3514            assert_eq!(ranges[1].lane_id(), "lane_test_2");
3515        }
3516        #[test]
3517        fn lane_s_route_length() {
3518            let lane_s_route = _get_lane_s_route(0., 10., 0., 15.);
3519            assert_eq!(lane_s_route.length(), 25.0);
3520        }
3521        #[test]
3522        fn lane_s_route_intersects() {
3523            let lane_s_route = _get_lane_s_route(0., 10., 0., 10.);
3524            let lane_s_route_that_intersects = _get_lane_s_route(5., 9., 5., 9.);
3525            let lane_s_route_that_not_intersects = _get_lane_s_route(11., 20., 11., 20.);
3526            assert!(lane_s_route.intersects(&lane_s_route_that_intersects, 0.0));
3527            assert!(!lane_s_route.intersects(&lane_s_route_that_not_intersects, 0.0));
3528        }
3529    }
3530}