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