maliput/utility/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::api::RoadNetwork;
32use std::error::Error;
33use std::fs::{create_dir_all, read_to_string, remove_file};
34use std::path::{Path, PathBuf};
35
36pub type ObjFeatures = maliput_sys::utility::ffi::Features;
37
38/// Generates a Wavefront and a Material file from the `road_network`.
39///
40/// # Arguments
41///
42/// * `road_network` - The road network to generate the Wavefront file from.
43/// * `dirpath` - The directory where the files will be created.
44/// * `fileroot` - The base name of the files. This means without the extension.
45/// * `obj_features` - Customization features for the Wavefront file.
46///
47/// # Returns
48/// A `PathBuf` object containing the path to the generated Wavefront file.
49///
50/// # Details
51/// These are written under the `dirpath` directory as `fileroot.obj` and `fileroot.mtl`.
52/// In case `dirpath` doesn't exist, or if the files can't be created, an error is returned.
53pub fn generate_obj_file(
54 road_network: &RoadNetwork,
55 dirpath: impl AsRef<Path>,
56 fileroot: impl AsRef<str>,
57 obj_features: &ObjFeatures,
58) -> Result<PathBuf, Box<dyn Error>> {
59 // Saves the complete path to the generated Wavefront file.
60 let future_obj_file_path = dirpath.as_ref().join(fileroot.as_ref().to_string() + ".obj");
61 let dirpath = to_string(dirpath)?;
62 // Creates dirpath if does not exist.
63 create_dir_all(&dirpath)?;
64 let raw_rn = road_network.rn.as_ref();
65 if let Some(raw_rn) = raw_rn {
66 unsafe {
67 maliput_sys::utility::ffi::Utility_GenerateObjFile(
68 raw_rn,
69 &dirpath,
70 &fileroot.as_ref().to_string(),
71 obj_features,
72 );
73 }
74 // Verify if the file was created.
75 if future_obj_file_path.is_file() && future_obj_file_path.with_extension("mtl").is_file() {
76 Ok(future_obj_file_path)
77 } else {
78 Result::Err(Box::from("Failed to generate the Wavefront files."))
79 }
80 } else {
81 Result::Err(Box::from("RoadNetwork is empty."))
82 }
83}
84
85/// Obtain a Wavefront formatted String that describes `road_network`'s geometry.
86///
87/// # Arguments
88///
89/// * `road_network` - The road network to get the Wavefront description from.
90/// * `obj_features` - Customization features for the Wavefront meshes.
91///
92/// # Returns
93///
94/// * A String containing the Wavefront description.
95/// * A dynamic error if there was an issue processing the road network.
96pub fn get_obj_description_from_road_network(
97 road_network: &RoadNetwork,
98 obj_features: &ObjFeatures,
99) -> Result<String, Box<dyn Error>> {
100 let output_directory = std::env::temp_dir().join("maliput");
101 create_dir_all(&output_directory)?;
102 let file_name = String::from("road_network");
103 let path_to_obj_file = generate_obj_file(road_network, &output_directory, &file_name, obj_features)?;
104 let obj_description = read_to_string(&path_to_obj_file)?;
105 remove_file(path_to_obj_file.clone())?;
106 let mtl_full_path = path_to_obj_file.with_extension("mtl");
107 remove_file(mtl_full_path)?;
108 Ok(obj_description)
109}
110
111/// Converts a `impl AsRef<Path>` to a `String` object.
112fn to_string(path: impl AsRef<Path>) -> Result<String, &'static str> {
113 Ok(path
114 .as_ref()
115 .as_os_str()
116 .to_str()
117 .ok_or("Failed to get output directory.")?
118 .to_string())
119}