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