diff --git a/map/autoware_lanelet2_map_validator/CHANGELOG.rst b/map/autoware_lanelet2_map_validator/CHANGELOG.rst new file mode 100644 index 000000000..44ebc334f --- /dev/null +++ b/map/autoware_lanelet2_map_validator/CHANGELOG.rst @@ -0,0 +1,32 @@ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Changelog for package autoware_lanelet2_map_validator +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +1.0.0 (2025-01-28) +------------------ +* Initial release +* Containing the following changes + * feat(autoware_lanelet2_map_validator): introduce autoware_lanelet2_map_validator (`#118 `_) + * chore(autoware_lanelet2_map_validator): add maintainers (`#141 `_) + * chore(autoware_lanelet2_map_validator): add requirement vm-02-02 to autoware_requirement_set (`#143 `_) + * refactor(lanelet2_map_validator): move headers to include/ (`#144 `_) + * feat(autoware_lanelet2_map_validator): allow prerequisites attribute for input (`#147 `_) + * Removed redundant appendIssues (`#148 `_) + * fix(lanelet2_map_validator): change validation order in regulatory_elements_details (`#151 `_) + * refactor(lanelet2_map_validator): move custom implementation to lanelet::autoware::validation (`#152 `_) + * refactor(lalenet2_map_validator): divide map loading process (`#153 `_) + * feat(lanelet2_map_validator): add test codes for existing validators (`#150 `_) + * feat(lanelet2_map_validator): added issue codes (`#163 `_) + * feat(lanelet2_map_validator): add validator to check traffic light facing (`#165 `_) + * Fixed issue that invalid prerequisites are not reflected to the results (`#169 `_) + * docs(lanelet2_map_validator): add a new document how_to_contribute.md (`#170 `_) + * feat(lanelet2_map_validator): check whether intersection_area satisfies vm-03-08 (`#171 `_) + * chore: sync files (`#11 `_) + * feat(autoware_lanelet_map_validator): add dangling reference checker to non existing intersection_area (`#177 `_) + * chore(lanelet2_map_validator): automate test code compilation and categorize test codes (`#183 `_) + * feat(lanelet2_map_validator): generation script for new validators (`#180 `_) + * docs(autoware_lanelet2_map_validator): update usage (`#191 `_) + * fix(lanelet2_map_validator): restore missing intersection lane and removed unnecessary linestrings from intersection test maps (`#188 `_) + * docs(lanelet2_map_validator): update README (`#193 `_) + * feat(lanelet2_map_validator): add validator to check whether intersection lanelets have valid turn_direction tags (`#186 `_) + * feat(lanelet2_map_validator): check local coordinates declaration (#194) (`#194 `_) diff --git a/map/autoware_lanelet2_map_validator/CMakeLists.txt b/map/autoware_lanelet2_map_validator/CMakeLists.txt index 3d5e1789f..3af88871e 100644 --- a/map/autoware_lanelet2_map_validator/CMakeLists.txt +++ b/map/autoware_lanelet2_map_validator/CMakeLists.txt @@ -67,6 +67,11 @@ if(BUILD_TESTING) endforeach() endif() +install( + FILES package.xml autoware_requirement_set.json + DESTINATION share/${PROJECT_NAME} +) + ament_auto_package( INSTALL_TO_SHARE test/data diff --git a/map/autoware_lanelet2_map_validator/autoware_requirement_set.json b/map/autoware_lanelet2_map_validator/autoware_requirement_set.json index fbc09182f..7906d474c 100644 --- a/map/autoware_lanelet2_map_validator/autoware_requirement_set.json +++ b/map/autoware_lanelet2_map_validator/autoware_requirement_set.json @@ -1,4 +1,5 @@ { + "version": "0.0.0", "requirements": [ { "id": "vm-02-02", diff --git a/map/autoware_lanelet2_map_validator/docs/how_to_contribute.md b/map/autoware_lanelet2_map_validator/docs/how_to_contribute.md index 1ddd75518..853a45c15 100644 --- a/map/autoware_lanelet2_map_validator/docs/how_to_contribute.md +++ b/map/autoware_lanelet2_map_validator/docs/how_to_contribute.md @@ -25,6 +25,43 @@ Please note that the validators are categorized according to [the vector map req - Area - Others +## Version Control + +`autoware_lanelet2_map_validator` began version control on January, 2025 in order to clarify the linkage to versioned map requirements and specifications. +The version of `autoware_lanelet2_map_validator` starts from `1.0.0` having the major, minor, and patch version. +See the following sections for further explanations of each version. +Note that the version of `autoware_lanelet2_map_validator` is stated in the `package.xml` and it is a separated to that of `autoware_requiremenet_set.json`. +Therefore, the version written in `autoware_requirement_set.json` is **NOT** linked to the version of `autoware_lanelet2_map_validator`. +The version of `autoware_requirement_set.json` refers to the version of [map requirements and specifications for Autoware](https://autowarefoundation.github.io/autoware-documentation/main/design/autoware-architecture/map/map-requirements/vector-map-requirements-overview/) (... which is not having its version controlled so yes leave it alone for now). + +### Major version + +The major version increases with the following changes. + +- Destructive changes that backward compatibility cannot be maintained. +- The format of inputs and outputs drastically changes. +- The entire code structure drastically changes. + +The major version is NOT intended to be updated frequenetly. + +### Minor version + +The minor version increases with the following changes. + +- Addition of new validators. +- Modification of existing validators due to updates of map requirements or other reasons. + - Even if the validation result changes, it will not be taken as the lost of backward compability if it only affects a few validators. +- Modification to the entire validation process that doesn't affect backward compatibility. + +This minor version is intended to be updated frequently as pull requests increase. + +### Patch version + +The patch version increases with the following changes. + +- Bug fixes +- Refactors that don't change the features. + ## Contribution Guide This section is aimed at contributors who want to add their own validators. If you want to change the core process of `autoware_lanelet2_map_validator`, please open a PR and discuss it with the maintainers. @@ -127,8 +164,6 @@ Contributors must also provide test codes to ensure your validator is working pr - A test function for each unique issue the validator can detect. It is recommended to create a small lanelet2 map for each unique issue. - In this test, please also check that the issue code is emitted as expected. - A test function ensuring that no issues occur when validating `test/data/map/sample_map.osm`. If `sample_map.osm` violates the validation or doesn't contain the primitive to validate, please fix or add the primitives to it. -- Add the test code to `CMakeLists.txt` using the `add_validation_test` function. - - Currently, this part must be added to CMakeLists.txt manually. Automation is expected in the future. ### 3. Test the entire validator @@ -159,6 +194,12 @@ The document must explain the following. In addition, add a link of the document to the table [Relationship between requirements and validators](https://github.com/autowarefoundation/autoware_tools/tree/main/map/autoware_lanelet2_map_validator#relationship-between-requirements-and-validators) in the main `README.md` to let the users know which map requirement your validator relates with. -### 5. Submit a pull request +### 5. Increase version + +Contributors must increase the version of `autoware_lanelet2_map_validator`. +See [Version Control](#version-control) for further information about how versioning is managed. +Note that contributors should increase the version in `package.xml` and do **NOT** edit the one in `autoware_requirement_set.json` unless the map requirements in Autoware documentation got its version changed. + +### 6. Submit a pull request Submit a pull request to the [autowarefoundation/autoware_tools](https://github.com/autowarefoundation/autoware_tools) repository. diff --git a/map/autoware_lanelet2_map_validator/package.xml b/map/autoware_lanelet2_map_validator/package.xml index d5d160656..59811f345 100644 --- a/map/autoware_lanelet2_map_validator/package.xml +++ b/map/autoware_lanelet2_map_validator/package.xml @@ -2,7 +2,7 @@ autoware_lanelet2_map_validator - 0.1.0 + 1.0.0 Validation tool for lanelet2 maps especially for Autoware usage Taiki Yamada Mamoru Sobue @@ -24,6 +24,7 @@ lanelet2_traffic_rules lanelet2_validation nlohmann-json-dev + pugixml-dev ament_cmake_ros diff --git a/map/autoware_lanelet2_map_validator/src/common/io.cpp b/map/autoware_lanelet2_map_validator/src/common/io.cpp new file mode 100644 index 000000000..d959edb22 --- /dev/null +++ b/map/autoware_lanelet2_map_validator/src/common/io.cpp @@ -0,0 +1,93 @@ +// Copyright 2024 Autoware Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "lanelet2_map_validator/io.hpp" + +#include +#include + +#include +#include +#include + +namespace lanelet::autoware::validation +{ +std::string get_validator_version() +{ + std::string package_share_directory = + ament_index_cpp::get_package_share_directory("autoware_lanelet2_map_validator"); + std::filesystem::path package_xml = + std::filesystem::path(package_share_directory) / "package.xml"; + + if (!std::filesystem::exists(package_xml)) { + throw std::runtime_error("package.xml not found in " + package_share_directory); + } + + pugi::xml_document doc; + if (!doc.load_file(package_xml.c_str())) { + throw std::runtime_error("Failed to parse package.xml!"); + } + + pugi::xml_node version_node = doc.child("package").child("version"); + if (!version_node) { + throw std::runtime_error("No tag found in package.xml!"); + } + + return version_node.text().as_string(); +} + +void insert_validator_info_to_map( + std::string osm_file, std::string requirements, std::string requirements_version) +{ + pugi::xml_document doc; + pugi::xml_parse_result result = doc.load_file(osm_file.c_str()); + + if (!result) { + throw std::invalid_argument("Failed to load osm file!"); + } + + pugi::xml_node osm_node = doc.child("osm"); + if (!osm_node) { + throw std::invalid_argument("No tag found in the osm file!"); + } + + pugi::xml_node validation_node = osm_node.child("validation"); + + if (!validation_node) { + validation_node = osm_node.prepend_child("validation"); + } + + // Helper function to set or append an attribute + auto set_or_append_attribute = [](pugi::xml_node & node, const char * name, const char * value) { + pugi::xml_attribute attr = node.attribute(name); + if (attr) { + attr.set_value(value); + } else { + node.append_attribute(name) = value; + } + }; + + // Set or append the required attributes + set_or_append_attribute(validation_node, "name", "autoware_lanelet2_map_validator"); + set_or_append_attribute(validation_node, "validator_version", get_validator_version().c_str()); + set_or_append_attribute(validation_node, "requirements", requirements.c_str()); + set_or_append_attribute(validation_node, "requirements_version", requirements_version.c_str()); + + if (!doc.save_file(osm_file.c_str())) { + throw std::runtime_error("Failed to save the validator info to osm file"); + } + + std::cout << "Modified validator information in the osm file." << std::endl; +} +} // namespace lanelet::autoware::validation diff --git a/map/autoware_lanelet2_map_validator/src/include/lanelet2_map_validator/io.hpp b/map/autoware_lanelet2_map_validator/src/include/lanelet2_map_validator/io.hpp new file mode 100644 index 000000000..9b1d42c51 --- /dev/null +++ b/map/autoware_lanelet2_map_validator/src/include/lanelet2_map_validator/io.hpp @@ -0,0 +1,27 @@ +// Copyright 2024 Autoware Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef LANELET2_MAP_VALIDATOR__IO_HPP_ +#define LANELET2_MAP_VALIDATOR__IO_HPP_ + +#include + +namespace lanelet::autoware::validation +{ +std::string get_validator_version(); +void insert_validator_info_to_map( + std::string osm_file, std::string requirements, std::string requirements_version); +} // namespace lanelet::autoware::validation + +#endif // LANELET2_MAP_VALIDATOR__IO_HPP_ diff --git a/map/autoware_lanelet2_map_validator/src/main.cpp b/map/autoware_lanelet2_map_validator/src/main.cpp index a62c8fe71..c58fd5fe5 100644 --- a/map/autoware_lanelet2_map_validator/src/main.cpp +++ b/map/autoware_lanelet2_map_validator/src/main.cpp @@ -13,6 +13,7 @@ // limitations under the License. #include "lanelet2_map_validator/cli.hpp" +#include "lanelet2_map_validator/io.hpp" #include "lanelet2_map_validator/map_loader.hpp" #include "lanelet2_map_validator/utils.hpp" #include "lanelet2_map_validator/validation.hpp" @@ -23,6 +24,7 @@ #include #include #include +#include int main(int argc, char * argv[]) { @@ -67,12 +69,16 @@ int main(int argc, char * argv[]) lanelet::validation::printAllIssues(map_issue); } else if (!meta_config.requirements_file.empty()) { if (!std::filesystem::is_regular_file(meta_config.requirements_file)) { - throw std::invalid_argument("Input file doesn't exist or is not a file!"); + throw std::invalid_argument("Input JSON file doesn't exist or is not a file!"); } std::ifstream input_file(meta_config.requirements_file); json json_data; input_file >> json_data; lanelet::autoware::validation::process_requirements(json_data, meta_config, *lanelet_map_ptr); + lanelet::autoware::validation::insert_validator_info_to_map( + meta_config.command_line_config.mapFile, + std::filesystem::path(meta_config.requirements_file).filename().string(), + json_data.value("version", "")); } else { const auto issues = lanelet::autoware::validation::apply_validation( *lanelet_map_ptr, meta_config.command_line_config.validationConfig); diff --git a/map/autoware_lanelet2_map_validator/test/src/test_version_control.cpp b/map/autoware_lanelet2_map_validator/test/src/test_version_control.cpp new file mode 100644 index 000000000..7a09da5ee --- /dev/null +++ b/map/autoware_lanelet2_map_validator/test/src/test_version_control.cpp @@ -0,0 +1,133 @@ +// Copyright 2025 Autoware Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "lanelet2_map_validator/io.hpp" + +#include +#include + +#include + +#include +#include +#include +#include +#include + +namespace lanelet::autoware::validation +{ + +class VersionControlTest : public ::testing::Test +{ +protected: + void SetUp() override { version_format_regex_ = std::regex(R"(\d+\.\d+\.\d+)"); } + bool has_duplicate_attributes(const pugi::xml_node & node) + { + std::set attribute_names; + for (pugi::xml_attribute attr = node.first_attribute(); attr; attr = attr.next_attribute()) { + if (!attribute_names.insert(attr.name()).second) { + return true; + } + } + return false; + } + + std::regex version_format_regex_; +}; + +TEST_F(VersionControlTest, GetValidVersion) // NOLINT for gtest +{ + std::string version; + + ASSERT_NO_THROW(version = get_validator_version();); + + ASSERT_TRUE(std::regex_match(version, version_format_regex_)) + << "The version \"" << version << "\" does not match the format X.Y.Z"; +} + +TEST_F(VersionControlTest, AddValidationInfo) // NOLINT for gtest +{ + const std::string package_share_directory = + ament_index_cpp::get_package_share_directory("autoware_lanelet2_map_validator"); + + const std::string empty_osm_file_name = package_share_directory + "/data/temp_empty.osm"; + + std::ofstream empty_osm_file(empty_osm_file_name); + empty_osm_file << R"( + + + )"; + empty_osm_file.close(); + + ASSERT_NO_THROW({ + insert_validator_info_to_map(empty_osm_file_name, "autoware_requirement_set.json", "1.2.3"); + }); + + pugi::xml_document doc; + ASSERT_TRUE(doc.load_file(empty_osm_file_name.c_str())); + + pugi::xml_node validation_node = doc.child("osm").child("validation"); + ASSERT_TRUE(validation_node); + + ASSERT_FALSE(has_duplicate_attributes(validation_node)); + + EXPECT_STREQ(validation_node.attribute("name").value(), "autoware_lanelet2_map_validator"); + EXPECT_TRUE(std::regex_match( + validation_node.attribute("validator_version").value(), version_format_regex_)); + EXPECT_STREQ(validation_node.attribute("requirements").value(), "autoware_requirement_set.json"); + EXPECT_STREQ(validation_node.attribute("requirements_version").value(), "1.2.3"); + + EXPECT_TRUE(std::filesystem::remove(empty_osm_file_name)) + << "Failed to remove temporary file " << empty_osm_file_name; +} + +TEST_F(VersionControlTest, ModifyValidationInfo) // NOLINT for gtest +{ + const std::string package_share_directory = + ament_index_cpp::get_package_share_directory("autoware_lanelet2_map_validator"); + + const std::string info_osm_file_name = package_share_directory + "/data/temp_info.osm"; + + std::ofstream info_osm_file(info_osm_file_name); + info_osm_file << R"( + + + + )"; + info_osm_file.close(); + + ASSERT_NO_THROW({ + insert_validator_info_to_map(info_osm_file_name, "original_requirement_set.json", "1.2.3"); + }); + + pugi::xml_document doc; + ASSERT_TRUE(doc.load_file(info_osm_file_name.c_str())); + + pugi::xml_node validation_node = doc.child("osm").child("validation"); + ASSERT_TRUE(validation_node); + + ASSERT_FALSE(has_duplicate_attributes(validation_node)); + + EXPECT_STREQ(validation_node.attribute("name").value(), "autoware_lanelet2_map_validator"); + EXPECT_TRUE(std::regex_match( + validation_node.attribute("validator_version").value(), version_format_regex_)); + EXPECT_STRNE(validation_node.attribute("validator_version").value(), "0.0.0"); + EXPECT_STREQ(validation_node.attribute("requirements").value(), "original_requirement_set.json"); + EXPECT_STREQ(validation_node.attribute("requirements_version").value(), "1.2.3"); + + EXPECT_TRUE(std::filesystem::remove(info_osm_file_name)) + << "Failed to remove temporary file " << info_osm_file_name; +} + +} // namespace lanelet::autoware::validation