diff --git a/CHANGELOG.md b/CHANGELOG.md index 967c635..f9edd87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- Added `includes` parameter to `creo2urdf` to include additional yamls. + ## [0.4.7] - 2024-04-09 - Made `creo2urdf` runnable from terminal diff --git a/README.md b/README.md index 3965aab..15c1abd 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,18 @@ If the export process was successful, you should see three files": "bar.stl", "b ### YAML Parameter File The YAML format is used to pass parameters to the plugin to customized the conversion process. -The parameter accepted by the plugin are documented in the following. +The parameters accepted by the plugin are documented in the following. + +##### Include Parameters +The YAML can eventually include other YAML files using the `includes` parameter, if so, the included files are merged with the main file. +All internal groups are merged if they are maps, they are overwritten only if an element is not a map, taking precedence over the main file in case of conflicts. + +> [!NOTE] +> The `includes` parameter is not mandatory, but if it is present, it must be a list of strings, containing relative path respect the directory of the main YAML file. + +| Attribute name | Type | Default Value | Description | +|:----------------:|:---------:|:------------:|:-------------:| +| `includes` | List of strings | "" | List of paths relative to the main YAML directory | ##### Severity Parameters | Attribute name | Type | Default Value | Description | diff --git a/src/creo2urdf/include/creo2urdf/Utils.h b/src/creo2urdf/include/creo2urdf/Utils.h index 2250bc1..ff6372a 100644 --- a/src/creo2urdf/include/creo2urdf/Utils.h +++ b/src/creo2urdf/include/creo2urdf/Utils.h @@ -32,6 +32,7 @@ #include #include #include +#include /** * @brief Small positive value used for numerical precision comparisons. @@ -439,4 +440,22 @@ std::pair getTransformFromPart(pfcModel_ptr modelhdl, */ std::pair getAxisFromPart(pfcModel_ptr modelhdl, const std::string& axis_name, const std::string& link_frame_name, const array& scale); +/** + * @brief Extracts the folder path from a file path. + * + * @param filePath The file path from which to extract the folder path. + * @return std::string The folder path extracted from the input file path. + */ +std::string extractFolderPath(const std::string& filePath); + +/** + * @brief Merge two YAML nodes, recursively. + * + * @param dest The destination YAML node. + * @param src The source YAML node. + * @return void + * + */ +void mergeYAMLNodes(YAML::Node& dest, const YAML::Node& src); + #endif // !UTILS_H diff --git a/src/creo2urdf/src/Creo2Urdf.cpp b/src/creo2urdf/src/Creo2Urdf.cpp index b6ad8e4..9beefc5 100644 --- a/src/creo2urdf/src/Creo2Urdf.cpp +++ b/src/creo2urdf/src/Creo2Urdf.cpp @@ -377,6 +377,7 @@ void Creo2Urdf::OnCommand() { m_yaml_path.clear(); m_csv_path.clear(); m_output_path.clear(); + config = YAML::Node(); m_asm_model_ptr = nullptr; return; @@ -723,7 +724,19 @@ bool Creo2Urdf::loadYamlConfig(const std::string& filename) { try { - config = YAML::LoadFile(filename); + auto config_temp = YAML::LoadFile(filename); + auto folder_path = extractFolderPath(filename); + if (config_temp["includes"].IsDefined() && config_temp["includes"].IsSequence()) { + for (const auto& include : config_temp["includes"]) { + auto include_filename = folder_path + include.as(); + auto include_config = YAML::LoadFile(include_filename); + mergeYAMLNodes(config, include_config); + } + } + else + { + config = config_temp; + } } catch (YAML::BadFile file_does_not_exist) { diff --git a/src/creo2urdf/src/Utils.cpp b/src/creo2urdf/src/Utils.cpp index 72e9c36..05983f2 100644 --- a/src/creo2urdf/src/Utils.cpp +++ b/src/creo2urdf/src/Utils.cpp @@ -215,3 +215,38 @@ std::pair getAxisFromPart(pfcModel_ptr modelhdl, cons return { true, axis_unit_vector }; } + +std::string extractFolderPath(const std::string& filePath) { + auto found = std::find_if(filePath.rbegin(), filePath.rend(), + [](char c) { return c == '/' || c == '\\'; }); + + if (found != filePath.rend()) { + return std::string(filePath.begin(), found.base()); + } + else { + return ""; + } +} + + +void mergeYAMLNodes(YAML::Node& dest, const YAML::Node& src) { + + for (const auto& item : src) { + std::string key = item.first.as(); + if (!dest[key]) { + // If the key doesn't exist in the destination node, simply add it + dest[key] = item.second; + } + else { + // If the key exists in the destination node, merge the values + // If both values are maps, recursively merge them + if (dest[key].IsMap() && item.second.IsMap()) { + mergeYAMLNodes(dest[key], item.second); + } + else { + // Otherwise, overwrite the value in the destination node + dest[key] = item.second; + } + } + } +}