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(¤t_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}