1use clap::Parser;
36
37use maliput::api::{LanePosition, RoadNetwork};
38use std::collections::HashMap;
39
40enum MaliputQuery {
42 PrintAllLanes,
43 GetNumberOfLanes,
44 GetTotalLengthOfTheRoadGeometry,
45 GetLaneLength(String),
46 GetLaneBounds(String, f64), GetSegmentBounds(String, f64), ToRoadPosition(f64, f64, f64), ToLanePosition(String, f64, f64, f64), ToSegmentPosition(String, f64, f64, f64), ToInertialPosition(String, f64, f64, f64), GetOrientaiton(String, f64, f64, f64), Invalid,
54}
55
56impl From<Vec<&str>> for MaliputQuery {
57 fn from(args: Vec<&str>) -> Self {
58 match args.as_slice() {
59 ["PrintAllLanes"] => MaliputQuery::PrintAllLanes,
60 ["GetNumberOfLanes"] => MaliputQuery::GetNumberOfLanes,
61 ["GetTotalLengthOfTheRoadGeometry"] => MaliputQuery::GetTotalLengthOfTheRoadGeometry,
62 ["GetLaneLength", lane_id] => MaliputQuery::GetLaneLength(lane_id.to_string()),
63 ["GetLaneBounds", lane_id, s] => MaliputQuery::GetLaneBounds(lane_id.to_string(), s.parse().unwrap()),
64 ["GetSegmentBounds", lane_id, s] => MaliputQuery::GetSegmentBounds(lane_id.to_string(), s.parse().unwrap()),
65 ["ToRoadPosition", x, y, z] => {
66 MaliputQuery::ToRoadPosition(x.parse().unwrap(), y.parse().unwrap(), z.parse().unwrap())
67 }
68 ["ToLanePosition", lane_id, x, y, z] => MaliputQuery::ToLanePosition(
69 lane_id.to_string(),
70 x.parse().unwrap(),
71 y.parse().unwrap(),
72 z.parse().unwrap(),
73 ),
74 ["ToSegmentPosition", lane_id, x, y, z] => MaliputQuery::ToSegmentPosition(
75 lane_id.to_string(),
76 x.parse().unwrap(),
77 y.parse().unwrap(),
78 z.parse().unwrap(),
79 ),
80 ["ToInertialPosition", lane_id, s, r, h] => MaliputQuery::ToInertialPosition(
81 lane_id.to_string(),
82 s.parse().unwrap(),
83 r.parse().unwrap(),
84 h.parse().unwrap(),
85 ),
86 ["GetOrientation", lane_id, s, r, h] => MaliputQuery::GetOrientaiton(
87 lane_id.to_string(),
88 s.parse().unwrap(),
89 r.parse().unwrap(),
90 h.parse().unwrap(),
91 ),
92 _ => MaliputQuery::Invalid,
93 }
94 }
95}
96
97impl MaliputQuery {
98 fn print_available_queries() {
99 println!("-> Available commands:");
100 println!("\t1. PrintAllLanes");
101 println!("\t2. GetNumberOfLanes");
102 println!("\t3. GetTotalLengthOfTheRoadGeometry");
103 println!("\t4. GetLaneLength <lane_id>");
104 println!("\t5. GetLaneBounds <lane_id> <s>");
105 println!("\t6. GetSegmentBounds <lane_id> <s>");
106 println!("\t7. ToRoadPosition <x> <y> <z>");
107 println!("\t8. ToLanePosition <lane_id> <x> <y> <z>");
108 println!("\t9. ToSegmentPosition <lane_id> <x> <y> <z>");
109 println!("\t10 ToInertialPosition <lane_id> <s> <r> <h>");
110 println!("\t11. GetOrientation <lane_id> <s> <r> <h>");
111 }
112}
113
114struct RoadNetworkQuery<'a> {
115 rn: &'a RoadNetwork,
116}
117
118impl<'a> RoadNetworkQuery<'a> {
119 fn new(rn: &'a RoadNetwork) -> Self {
120 RoadNetworkQuery { rn }
121 }
122
123 fn execute_query(&self, query: MaliputQuery) {
124 let rg = self.rn.road_geometry();
125 let start_time = std::time::Instant::now();
126 match query {
127 MaliputQuery::PrintAllLanes => {
128 let mut lanes = rg.get_lanes();
130 lanes.sort_by(|a, b| b.length().partial_cmp(&a.length()).unwrap());
131 print_elapsed_time(start_time);
132 println!("-> All lanes in the road geometry: {} lanes", lanes.len());
133 for lane in lanes {
134 println!(
135 "\t* Lane ID: {}\t Length: {} meters \t InertiaPos at (s=0,r=0,h=0): {}",
136 lane.id(),
137 lane.length(),
138 lane.to_inertial_position(&LanePosition::new(0., 0., 0.))
139 );
140 }
141 }
142 MaliputQuery::GetNumberOfLanes => {
143 let len = rg.get_lanes().len();
144 print_elapsed_time(start_time);
145 println!("-> Number of lanes: {}", len);
146 }
147 MaliputQuery::GetTotalLengthOfTheRoadGeometry => {
148 let lanes_num = rg.get_lanes().len();
149 let total_length = rg.get_lanes().iter().map(|lane| lane.length()).sum::<f64>();
150 print_elapsed_time(start_time);
151 println!("-> Total length of the road geometry: {} meters along {} lanes. The average lane length is {} meters.",
152 total_length,
153 lanes_num,
154 total_length / lanes_num as f64);
155 }
156 MaliputQuery::GetLaneLength(lane_id) => {
157 if let Some(lane) = rg.get_lane(&lane_id) {
158 let lane_length = lane.length();
159 print_elapsed_time(start_time);
160 println!("-> Length of lane {}: {} meters", lane_id, lane_length);
161 } else {
162 println!("-> Lane with ID {} not found.", lane_id);
163 }
164 }
165 MaliputQuery::GetLaneBounds(lane_id, s) => {
166 if let Some(lane) = rg.get_lane(&lane_id) {
167 let lane_bounds = lane.lane_bounds(s);
168 print_elapsed_time(start_time);
169 println!(
170 "-> Bounds of lane {} at s={}: max: {}, min: {}",
171 lane_id,
172 s,
173 lane_bounds.max(),
174 lane_bounds.min()
175 );
176 } else {
177 println!("-> Lane with ID {} not found.", lane_id);
178 }
179 }
180 MaliputQuery::GetSegmentBounds(lane_id, s) => {
181 if let Some(lane) = rg.get_lane(&lane_id) {
182 let segment_bounds = lane.segment_bounds(s);
183 print_elapsed_time(start_time);
184 println!(
185 "-> Segment bounds of lane {} at s={}: max: {}, min: {}",
186 lane_id,
187 s,
188 segment_bounds.max(),
189 segment_bounds.min()
190 );
191 } else {
192 println!("-> Lane with ID {} not found.", lane_id);
193 }
194 }
195 MaliputQuery::ToRoadPosition(x, y, z) => {
196 let road_position_result = rg.to_road_position(&maliput::api::InertialPosition::new(x, y, z));
197 print_elapsed_time(start_time);
198 println!("-> Road Position Result:");
199 println!("\t* Road Position:");
200 println!("\t\t* lane_id: {}", road_position_result.road_position.lane().id());
201 println!("\t\t* lane_position: {}", road_position_result.road_position.pos());
202 println!("\t* Nearest Position:");
203 println!("\t\t* inertial_position: {}", road_position_result.nearest_position);
204 println!("\t* Distance:");
205 println!("\t\t* distance: {}", road_position_result.distance);
206 }
207 MaliputQuery::ToLanePosition(lane_id, x, y, z) => {
208 if let Some(lane) = rg.get_lane(&lane_id) {
209 let lane_position_result = lane.to_lane_position(&maliput::api::InertialPosition::new(x, y, z));
210 print_elapsed_time(start_time);
211 println!("-> Lane Position Result for lane {}:", lane_id);
212 println!("\t* Lane Position:");
213 println!("\t\t* lane_position: {}", lane_position_result.lane_position);
214 println!("\t* Nearest Position:");
215 println!("\t\t* inertial_position: {}", lane_position_result.nearest_position);
216 println!("\t* Distance:");
217 println!("\t\t* distance: {}", lane_position_result.distance);
218 } else {
219 println!("Lane with ID {} not found.", lane_id);
220 }
221 }
222 MaliputQuery::ToSegmentPosition(lane_id, x, y, z) => {
223 if let Some(lane) = rg.get_lane(&lane_id) {
224 let lane_position_result = lane.to_segment_position(&maliput::api::InertialPosition::new(x, y, z));
225 print_elapsed_time(start_time);
226 println!("-> Segment Position Result for lane {}:", lane_id);
227 println!("\t* Lane Position:");
228 println!("\t\t* lane_position: {}", lane_position_result.lane_position);
229 println!("\t* Nearest Position:");
230 println!("\t\t* inertial_position: {}", lane_position_result.nearest_position);
231 println!("\t* Distance:");
232 println!("\t\t* distance: {}", lane_position_result.distance);
233 } else {
234 println!("Lane with ID {} not found.", lane_id);
235 }
236 }
237 MaliputQuery::ToInertialPosition(lane_id, s, r, h) => {
238 if let Some(lane) = rg.get_lane(&lane_id) {
239 let inertial_position = lane.to_inertial_position(&maliput::api::LanePosition::new(s, r, h));
240 print_elapsed_time(start_time);
241 println!("-> Inertial Position Result for lane {}:", lane_id);
242 println!("\t* inertial_position: {}", inertial_position);
243 } else {
244 println!("-> Lane with ID {} not found.", lane_id);
245 }
246 }
247 MaliputQuery::GetOrientaiton(lane_id, s, r, h) => {
248 if let Some(lane) = rg.get_lane(&lane_id) {
249 let orientation = lane.get_orientation(&maliput::api::LanePosition::new(s, r, h));
250 print_elapsed_time(start_time);
251 println!("-> Orientation Result for lane {}:", lane_id);
252 println!("\t* orientation:");
253 println!(
254 "\t\t* roll: {}, pitch: {}, yaw: {}",
255 orientation.roll(),
256 orientation.pitch(),
257 orientation.yaw()
258 );
259 } else {
260 println!("-> Lane with ID {} not found.", lane_id);
261 }
262 }
263 MaliputQuery::Invalid => {
264 println!("-> Invalid query command. Please try again.");
265 println!();
266 MaliputQuery::print_available_queries();
267 }
268 }
269 fn print_elapsed_time(start_time: std::time::Instant) {
271 let elapsed = start_time.elapsed();
272 println!("-> Query executed in {:.2?}.", elapsed);
273 }
274 }
275}
276
277#[derive(Parser, Debug)]
278#[command(author, version, about)]
279struct Args {
280 road_network_xodr_file_path: String,
281
282 #[arg(short, long, default_value_t = 0.05)]
286 linear_tolerance: f64,
287
288 #[arg(short, long)]
289 max_linear_tolerance: Option<f64>,
290
291 #[arg(short, long, default_value_t = 0.01)]
292 angular_tolerance: f64,
293
294 #[arg(long, default_value_t = false)]
295 allow_non_drivable_lanes: bool,
296
297 #[arg(long, default_value_t = false)]
298 disable_parallel_builder_policy: bool,
299
300 #[arg(long, default_value_t = maliput::common::LogLevel::Error)]
301 set_log_level: maliput::common::LogLevel,
302}
303
304use std::path::PathBuf;
308fn parse_xodr_file_path(path: &str) -> PathBuf {
309 let mut path_buf = PathBuf::from(path);
310 if !path_buf.is_absolute() {
311 if let Ok(current_dir) = std::env::current_dir() {
313 path_buf = current_dir.join(path_buf);
314 }
315 }
316 path_buf
317}
318
319fn main() -> Result<(), Box<dyn std::error::Error>> {
320 println!("Welcome to maliput_query app:");
321 println!("\t* This application allows you to query a road network built from an OpenDRIVE file.");
322 println!("\t* Usage: maliput_query <XODR_FILE_PATH> [OPTIONS]");
323 println!();
324 let args = Args::parse();
325
326 let xodr_path = parse_xodr_file_path(args.road_network_xodr_file_path.as_str());
328 let linear_tolerance: String = args.linear_tolerance.to_string();
329 let max_linear_tolerance = args.max_linear_tolerance;
330 let angular_tolerance = args.angular_tolerance.to_string();
331 let omit_non_drivable_lanes = if args.allow_non_drivable_lanes { "false" } else { "true" };
332 let parallel_builder_policy = !args.disable_parallel_builder_policy;
333
334 let mut road_network_properties = HashMap::from([
335 ("road_geometry_id", "maliput_query_rg"),
336 ("opendrive_file", xodr_path.to_str().unwrap()),
337 ("linear_tolerance", linear_tolerance.as_str()),
338 ("omit_nondrivable_lanes", omit_non_drivable_lanes),
339 ("angular_tolerance", angular_tolerance.as_str()),
340 (
341 "build_policy",
342 if parallel_builder_policy {
343 "parallel"
344 } else {
345 "sequential"
346 },
347 ),
348 ]);
349 let max_linear_tolerance_str;
350 if let Some(max_tolerance) = max_linear_tolerance {
351 max_linear_tolerance_str = max_tolerance.to_string();
352 road_network_properties.insert("max_linear_tolerance", max_linear_tolerance_str.as_str());
353 }
354
355 println!();
356 println!("-> Setting maliput log level to: {}", args.set_log_level);
357 maliput::common::set_log_level(args.set_log_level);
358 println!("-> Road network builder options: {:?}", road_network_properties);
359 println!("->");
360 println!(
361 "-> Building Maliput Road Network from OpenDRIVE file: {}",
362 xodr_path.display()
363 );
364 println!("-> This may take a while, depending on the size of the OpenDRIVE file and the complexity of the road network...");
365 println!("-> ...");
366 let now = std::time::Instant::now();
367 let road_network = RoadNetwork::new("maliput_malidrive", &road_network_properties);
368 let elapsed = now.elapsed();
369 println!("-> Road network loaded in {:.2?}.", elapsed);
370
371 println!();
373 MaliputQuery::print_available_queries();
374 println!("To exit the application, type 'exit'.");
375
376 loop {
377 println!();
378 let mut input = String::new();
379 println!("-> Enter a query command (or 'exit' to quit):");
380 std::io::stdin().read_line(&mut input)?;
381 let input = input.trim();
382
383 if input == "exit" {
384 break;
385 }
386
387 let query: MaliputQuery = input.split_whitespace().collect::<Vec<&str>>().into();
388 let query_handler = RoadNetworkQuery::new(&road_network);
389 query_handler.execute_query(query);
390 }
391
392 Ok(())
393}