diff --git a/build_depends.repos b/build_depends.repos
index 60bc6944..0aa73a95 100644
--- a/build_depends.repos
+++ b/build_depends.repos
@@ -24,6 +24,10 @@ repositories:
type: git
url: https://github.com/autowarefoundation/autoware_internal_msgs.git
version: main
+ core/autoware_lanelet2_extension:
+ type: git
+ url: https://github.com/autowarefoundation/autoware_lanelet2_extension.git
+ version: 0.6.0
# universe
universe/autoware.universe:
type: git
diff --git a/map/autoware_lanelet2_map_utils/CMakeLists.txt b/map/autoware_lanelet2_map_utils/CMakeLists.txt
new file mode 100644
index 00000000..0785647d
--- /dev/null
+++ b/map/autoware_lanelet2_map_utils/CMakeLists.txt
@@ -0,0 +1,34 @@
+cmake_minimum_required(VERSION 3.14)
+project(autoware_lanelet2_map_utils)
+
+find_package(autoware_cmake REQUIRED)
+autoware_package()
+
+find_package(PCL REQUIRED COMPONENTS common io kdtree)
+
+include_directories(
+ include
+ SYSTEM
+ ${PCL_INCLUDE_DIRS}
+)
+
+link_libraries(
+ ${PCL_LIBRARIES}
+)
+
+ament_auto_add_executable(fix_z_value_by_pcd src/fix_z_value_by_pcd.cpp)
+ament_auto_add_executable(transform_maps src/transform_maps.cpp)
+ament_auto_add_executable(merge_close_lines src/merge_close_lines.cpp)
+ament_auto_add_executable(merge_close_points src/merge_close_points.cpp)
+ament_auto_add_executable(remove_unreferenced_geometry src/remove_unreferenced_geometry.cpp)
+ament_auto_add_executable(fix_lane_change_tags src/fix_lane_change_tags.cpp)
+
+if(BUILD_TESTING)
+ find_package(ament_lint_auto REQUIRED)
+ ament_lint_auto_find_test_dependencies()
+endif()
+
+ament_auto_package(INSTALL_TO_SHARE
+ config
+ launch
+)
diff --git a/map/autoware_lanelet2_map_utils/README.md b/map/autoware_lanelet2_map_utils/README.md
new file mode 100644
index 00000000..6f4fc063
--- /dev/null
+++ b/map/autoware_lanelet2_map_utils/README.md
@@ -0,0 +1,3 @@
+# autoware_lanelet2_map_utils
+
+This package is for preprocessing the lanelet map.
diff --git a/map/autoware_lanelet2_map_utils/config/fix_z_value_by_pcd.param.yaml b/map/autoware_lanelet2_map_utils/config/fix_z_value_by_pcd.param.yaml
new file mode 100644
index 00000000..de86ef79
--- /dev/null
+++ b/map/autoware_lanelet2_map_utils/config/fix_z_value_by_pcd.param.yaml
@@ -0,0 +1,5 @@
+/**:
+ ros__parameters:
+ llt_map_path: $(var llt_map_path)
+ pcd_map_path: $(var pcd_map_path)
+ llt_output_path: $(var llt_output_path)
diff --git a/map/autoware_lanelet2_map_utils/config/transform_maps.param.yaml b/map/autoware_lanelet2_map_utils/config/transform_maps.param.yaml
new file mode 100644
index 00000000..548c2805
--- /dev/null
+++ b/map/autoware_lanelet2_map_utils/config/transform_maps.param.yaml
@@ -0,0 +1,12 @@
+/**:
+ ros__parameters:
+ llt_map_path: $(var llt_map_path)
+ pcd_map_path: $(var pcd_map_path)
+ llt_output_path: $(var llt_output_path)
+ pcd_output_path: $(var pcd_output_path)
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ roll: 0.0
+ pitch: 0.0
+ yaw: 0.0
diff --git a/map/autoware_lanelet2_map_utils/launch/fix_z_value_by_pcd.launch.xml b/map/autoware_lanelet2_map_utils/launch/fix_z_value_by_pcd.launch.xml
new file mode 100644
index 00000000..cab1ee9e
--- /dev/null
+++ b/map/autoware_lanelet2_map_utils/launch/fix_z_value_by_pcd.launch.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/map/autoware_lanelet2_map_utils/launch/transform_maps.launch.xml b/map/autoware_lanelet2_map_utils/launch/transform_maps.launch.xml
new file mode 100644
index 00000000..8976eeec
--- /dev/null
+++ b/map/autoware_lanelet2_map_utils/launch/transform_maps.launch.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/map/autoware_lanelet2_map_utils/package.xml b/map/autoware_lanelet2_map_utils/package.xml
new file mode 100644
index 00000000..6330fd75
--- /dev/null
+++ b/map/autoware_lanelet2_map_utils/package.xml
@@ -0,0 +1,30 @@
+
+
+
+ autoware_lanelet2_map_utils
+ 0.1.0
+ The autoware_lanelet2_map_utils package
+ Yamato Ando
+ Kento Yabuuchi
+ Masahiro Sakamoto
+ NGUYEN Viet Anh
+ Taiki Yamada
+ Shintaro Sakoda
+ Ryu Yamamoto
+ Apache License 2.0
+ Ryohsuke Mitsudome
+
+ ament_cmake_auto
+ autoware_cmake
+
+ autoware_lanelet2_extension
+ libpcl-all-dev
+ rclcpp
+
+ ament_lint_auto
+ autoware_lint_common
+
+
+ ament_cmake
+
+
diff --git a/map/autoware_lanelet2_map_utils/schema/transform_maps.schema.json b/map/autoware_lanelet2_map_utils/schema/transform_maps.schema.json
new file mode 100644
index 00000000..78fb3952
--- /dev/null
+++ b/map/autoware_lanelet2_map_utils/schema/transform_maps.schema.json
@@ -0,0 +1,75 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Parameters for Transforming Maps",
+ "type": "object",
+ "definitions": {
+ "transform_maps": {
+ "type": "object",
+ "properties": {
+ "llt_map_path": {
+ "type": "string",
+ "description": "Path pointing to the input lanelet2 file",
+ "default": ""
+ },
+ "pcd_map_path": {
+ "type": "string",
+ "description": "Path pointing to the input point cloud file",
+ "default": ""
+ },
+ "llt_output_path": {
+ "type": "string",
+ "description": "Path pointing to the output lanelet2 file",
+ "default": ""
+ },
+ "pcd_output_path": {
+ "type": "string",
+ "description": "Path pointing to the output point cloud file",
+ "default": ""
+ },
+ "x": {
+ "type": "number",
+ "default": 0.0,
+ "description": "x factor of Translation vector for transforming maps [m]"
+ },
+ "y": {
+ "type": "number",
+ "default": 0.0,
+ "description": "y factor of Translation vector for transforming maps [m]"
+ },
+ "z": {
+ "type": "number",
+ "default": 0.0,
+ "description": "z factor of Translation vector for transforming maps [m]"
+ },
+ "roll": {
+ "type": "number",
+ "default": 0.0,
+ "description": "roll factor of Rotation vector for transforming maps [rad]"
+ },
+ "pitch": {
+ "type": "number",
+ "default": 0.0,
+ "description": "pitch factor of Rotation vector for transforming maps [rad]"
+ },
+ "yaw": {
+ "type": "number",
+ "default": 0.0,
+ "description": "yaw factor of Rotation vector for transforming maps [rad]"
+ }
+ },
+ "required": ["x", "y", "z", "roll", "pitch", "yaw"]
+ }
+ },
+ "properties": {
+ "/**": {
+ "type": "object",
+ "properties": {
+ "ros__parameters": {
+ "$ref": "#/definitions/transform_maps"
+ }
+ },
+ "required": ["ros__parameters"]
+ }
+ },
+ "required": ["/**"]
+}
diff --git a/map/autoware_lanelet2_map_utils/src/fix_lane_change_tags.cpp b/map/autoware_lanelet2_map_utils/src/fix_lane_change_tags.cpp
new file mode 100644
index 00000000..01fba650
--- /dev/null
+++ b/map/autoware_lanelet2_map_utils/src/fix_lane_change_tags.cpp
@@ -0,0 +1,104 @@
+// Copyright 2020 Tier IV, Inc.
+//
+// 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
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+namespace autoware::lanelet2_map_utils
+{
+bool load_lanelet_map(
+ const std::string & llt_map_path, lanelet::LaneletMapPtr & lanelet_map_ptr,
+ lanelet::Projector & projector)
+{
+ lanelet::LaneletMapPtr lanelet_map;
+ lanelet::ErrorMessages errors;
+ lanelet_map_ptr = lanelet::load(llt_map_path, "autoware_osm_handler", projector, &errors);
+
+ for (const auto & error : errors) {
+ RCLCPP_ERROR_STREAM(rclcpp::get_logger("loadLaneletMap"), error);
+ }
+ if (!errors.empty()) {
+ return false;
+ }
+ std::cout << "Loaded Lanelet2 map" << std::endl;
+ return true;
+}
+
+lanelet::Lanelets convert_to_vector(const lanelet::LaneletMapPtr & lanelet_map_ptr)
+{
+ lanelet::Lanelets lanelets;
+ std::copy(
+ lanelet_map_ptr->laneletLayer.begin(), lanelet_map_ptr->laneletLayer.end(),
+ std::back_inserter(lanelets));
+ return lanelets;
+}
+void fix_tags(lanelet::LaneletMapPtr & lanelet_map_ptr)
+{
+ auto lanelets = convert_to_vector(lanelet_map_ptr);
+ lanelet::traffic_rules::TrafficRulesPtr traffic_rules =
+ lanelet::traffic_rules::TrafficRulesFactory::create(
+ lanelet::Locations::Germany, lanelet::Participants::Vehicle);
+ lanelet::routing::RoutingGraphUPtr routing_graph =
+ lanelet::routing::RoutingGraph::build(*lanelet_map_ptr, *traffic_rules);
+
+ for (auto & llt : lanelets) {
+ if (!routing_graph->conflicting(llt).empty()) {
+ continue;
+ }
+ llt.attributes().erase("turn_direction");
+ if (!!routing_graph->adjacentRight(llt)) {
+ llt.rightBound().attributes()["lane_change"] = "yes";
+ }
+ if (!!routing_graph->adjacentLeft(llt)) {
+ llt.leftBound().attributes()["lane_change"] = "yes";
+ }
+ }
+}
+} // namespace autoware::lanelet2_map_utils
+
+int main(int argc, char * argv[])
+{
+ rclcpp::init(argc, argv);
+
+ auto node = rclcpp::Node::make_shared("fix_lane_change_tags");
+
+ const auto llt_map_path = node->declare_parameter("llt_map_path");
+ const auto output_path = node->declare_parameter("output_path");
+
+ lanelet::LaneletMapPtr llt_map_ptr(new lanelet::LaneletMap);
+ lanelet::projection::MGRSProjector projector;
+
+ if (!autoware::lanelet2_map_utils::load_lanelet_map(llt_map_path, llt_map_ptr, projector)) {
+ return EXIT_FAILURE;
+ }
+
+ autoware::lanelet2_map_utils::fix_tags(llt_map_ptr);
+ lanelet::write(output_path, *llt_map_ptr, projector);
+
+ rclcpp::shutdown();
+
+ return 0;
+}
diff --git a/map/autoware_lanelet2_map_utils/src/fix_z_value_by_pcd.cpp b/map/autoware_lanelet2_map_utils/src/fix_z_value_by_pcd.cpp
new file mode 100644
index 00000000..cc46b385
--- /dev/null
+++ b/map/autoware_lanelet2_map_utils/src/fix_z_value_by_pcd.cpp
@@ -0,0 +1,168 @@
+// Copyright 2020 Tier IV, Inc.
+//
+// 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
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+namespace autoware::lanelet2_map_utils
+{
+bool load_lanelet_map(
+ const std::string & llt_map_path, lanelet::LaneletMapPtr & lanelet_map_ptr,
+ lanelet::Projector & projector)
+{
+ lanelet::LaneletMapPtr lanelet_map;
+ lanelet::ErrorMessages errors;
+ lanelet_map_ptr = lanelet::load(llt_map_path, "autoware_osm_handler", projector, &errors);
+
+ for (const auto & error : errors) {
+ RCLCPP_ERROR_STREAM(rclcpp::get_logger("loadLaneletMap"), error);
+ }
+ if (!errors.empty()) {
+ return false;
+ }
+ std::cout << "Loaded Lanelet2 map" << std::endl;
+ return true;
+}
+
+bool load_pcd_map(
+ const std::string & pcd_map_path, pcl::PointCloud::Ptr & pcd_map_ptr)
+{
+ if (pcl::io::loadPCDFile(pcd_map_path, *pcd_map_ptr) == -1) { //* load the file
+ RCLCPP_ERROR_STREAM(rclcpp::get_logger("loadPCDMap"), "Couldn't read file: " << pcd_map_path);
+ return false;
+ }
+ std::cout << "Loaded " << pcd_map_ptr->width * pcd_map_ptr->height << " data points."
+ << std::endl;
+ return true;
+}
+
+double get_min_height_around_point(
+ const pcl::PointCloud::Ptr & pcd_map_ptr,
+ const pcl::KdTreeFLANN & kdtree, const pcl::PointXYZ & search_pt,
+ const double search_radius3d, const double search_radius2d)
+{
+ std::vector point_idx_radius_search;
+ std::vector point_radius_squared_distance;
+ if (
+ kdtree.radiusSearch(
+ search_pt, search_radius3d, point_idx_radius_search, point_radius_squared_distance) <= 0) {
+ std::cout << "no points found within 3d radius " << search_radius3d << std::endl;
+ return search_pt.z;
+ }
+
+ double min_height = std::numeric_limits::max();
+ bool found = false;
+
+ for (auto pt_idx : point_idx_radius_search) {
+ const auto pt = pcd_map_ptr->points.at(pt_idx);
+ if (pt.z > min_height) {
+ continue;
+ }
+ double distance2d = std::hypot(pt.x - search_pt.x, pt.y - search_pt.y);
+ if (distance2d < search_radius2d) {
+ found = true;
+ min_height = pt.z;
+ }
+ }
+ if (!found) {
+ min_height = search_pt.z;
+ }
+ return min_height;
+}
+
+void adjust_height(
+ const pcl::PointCloud::Ptr & pcd_map_ptr,
+ const lanelet::LaneletMapPtr & lanelet_map_ptr)
+{
+ std::unordered_set done;
+ double search_radius2d = 0.5;
+ double search_radius3d = 10;
+
+ pcl::KdTreeFLANN kdtree;
+ kdtree.setInputCloud(pcd_map_ptr);
+
+ for (lanelet::Lanelet & llt : lanelet_map_ptr->laneletLayer) {
+ for (lanelet::Point3d & pt : llt.leftBound()) {
+ if (done.find(pt.id()) != done.end()) {
+ continue;
+ }
+ pcl::PointXYZ pcl_pt;
+ pcl_pt.x = static_cast(pt.x());
+ pcl_pt.y = static_cast(pt.y());
+ pcl_pt.z = static_cast(pt.z());
+ double min_height =
+ get_min_height_around_point(pcd_map_ptr, kdtree, pcl_pt, search_radius3d, search_radius2d);
+ std::cout << "moving from " << pt.z() << " to " << min_height << std::endl;
+ pt.z() = min_height;
+ done.insert(pt.id());
+ }
+ for (lanelet::Point3d & pt : llt.rightBound()) {
+ if (done.find(pt.id()) != done.end()) {
+ continue;
+ }
+ pcl::PointXYZ pcl_pt;
+ pcl_pt.x = static_cast(pt.x());
+ pcl_pt.y = static_cast(pt.y());
+ pcl_pt.z = static_cast(pt.z());
+ double min_height =
+ get_min_height_around_point(pcd_map_ptr, kdtree, pcl_pt, search_radius3d, search_radius2d);
+ std::cout << "moving from " << pt.z() << " to " << min_height << std::endl;
+ pt.z() = min_height;
+ done.insert(pt.id());
+ }
+ }
+}
+} // namespace autoware::lanelet2_map_utils
+
+int main(int argc, char * argv[])
+{
+ rclcpp::init(argc, argv);
+
+ auto node = rclcpp::Node::make_shared("lanelet_map_height_adjuster");
+
+ const auto llt_map_path = node->declare_parameter("llt_map_path");
+ const auto pcd_map_path = node->declare_parameter("pcd_map_path");
+ const auto llt_output_path = node->declare_parameter("llt_output_path");
+
+ lanelet::LaneletMapPtr llt_map_ptr(new lanelet::LaneletMap);
+ lanelet::projection::MGRSProjector projector;
+
+ pcl::PointCloud::Ptr pcd_map_ptr(new pcl::PointCloud);
+
+ if (!autoware::lanelet2_map_utils::load_lanelet_map(llt_map_path, llt_map_ptr, projector)) {
+ return EXIT_FAILURE;
+ }
+ if (!autoware::lanelet2_map_utils::load_pcd_map(pcd_map_path, pcd_map_ptr)) {
+ return EXIT_FAILURE;
+ }
+
+ autoware::lanelet2_map_utils::adjust_height(pcd_map_ptr, llt_map_ptr);
+ lanelet::write(llt_output_path, *llt_map_ptr, projector);
+
+ rclcpp::shutdown();
+
+ return 0;
+}
diff --git a/map/autoware_lanelet2_map_utils/src/merge_close_lines.cpp b/map/autoware_lanelet2_map_utils/src/merge_close_lines.cpp
new file mode 100644
index 00000000..4a358b6e
--- /dev/null
+++ b/map/autoware_lanelet2_map_utils/src/merge_close_lines.cpp
@@ -0,0 +1,191 @@
+// Copyright 2020 Tier IV, Inc.
+//
+// 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
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+namespace autoware::lanelet2_map_utils
+{
+bool load_lanelet_map(
+ const std::string & llt_map_path, lanelet::LaneletMapPtr & lanelet_map_ptr,
+ lanelet::Projector & projector)
+{
+ lanelet::LaneletMapPtr lanelet_map;
+ lanelet::ErrorMessages errors;
+ lanelet_map_ptr = lanelet::load(llt_map_path, "autoware_osm_handler", projector, &errors);
+
+ for (const auto & error : errors) {
+ RCLCPP_ERROR_STREAM(rclcpp::get_logger("loadLaneletMap"), error);
+ }
+ if (!errors.empty()) {
+ return false;
+ }
+ std::cout << "Loaded Lanelet2 map" << std::endl;
+ return true;
+}
+
+lanelet::LineStrings3d convert_line_layer_to_line_strings(
+ const lanelet::LaneletMapPtr & lanelet_map_ptr)
+{
+ lanelet::LineStrings3d lines;
+ std::copy(
+ lanelet_map_ptr->lineStringLayer.begin(), lanelet_map_ptr->lineStringLayer.end(),
+ std::back_inserter(lines));
+ return lines;
+}
+
+lanelet::ConstPoint3d get3d_point_from2d_arc_length(
+ const lanelet::ConstLineString3d & line, const double s)
+{
+ double accumulated_distance2d = 0;
+ if (line.size() < 2) {
+ return lanelet::Point3d();
+ }
+ auto prev_pt = line.front();
+ for (size_t i = 1; i < line.size(); i++) {
+ const auto & pt = line[i];
+ double distance2d =
+ lanelet::geometry::distance2d(lanelet::utils::to2D(prev_pt), lanelet::utils::to2D(pt));
+ if (accumulated_distance2d + distance2d >= s) {
+ double ratio = (s - accumulated_distance2d) / distance2d;
+ auto interpolated_pt = prev_pt.basicPoint() * (1 - ratio) + pt.basicPoint() * ratio;
+ std::cout << interpolated_pt << std::endl;
+ return lanelet::ConstPoint3d{
+ lanelet::utils::getId(), interpolated_pt.x(), interpolated_pt.y(), interpolated_pt.z()};
+ }
+ accumulated_distance2d += distance2d;
+ prev_pt = pt;
+ }
+ RCLCPP_ERROR(rclcpp::get_logger("merge_close_lines"), "interpolation failed");
+ return {};
+}
+
+bool are_lines_same(
+ const lanelet::ConstLineString3d & line1, const lanelet::ConstLineString3d & line2)
+{
+ bool same_ends = false;
+ if (line1.front() == line2.front() && line1.back() == line2.back()) {
+ same_ends = true;
+ }
+ if (line1.front() == line2.back() && line1.back() == line2.front()) {
+ same_ends = true;
+ }
+ if (!same_ends) {
+ return false;
+ }
+
+ double sum_distance =
+ std::accumulate(line1.begin(), line1.end(), 0.0, [&line2](double sum, const auto & pt) {
+ return sum + boost::geometry::distance(pt.basicPoint(), line2);
+ });
+ sum_distance +=
+ std::accumulate(line2.begin(), line2.end(), 0.0, [&line1](double sum, const auto & pt) {
+ return sum + boost::geometry::distance(pt.basicPoint(), line1);
+ });
+
+ double avg_distance = sum_distance / static_cast(line1.size() + line2.size());
+ std::cout << line1 << " " << line2 << " " << avg_distance << std::endl;
+ return avg_distance < 1.0;
+}
+
+lanelet::BasicPoint3d get_closest_point_on_line(
+ const lanelet::BasicPoint3d & search_point, const lanelet::ConstLineString3d & line)
+{
+ auto arc_coordinate = lanelet::geometry::toArcCoordinates(
+ lanelet::utils::to2D(line), lanelet::utils::to2D(search_point));
+ std::cout << arc_coordinate.length << " " << arc_coordinate.distance << std::endl;
+ return get3d_point_from2d_arc_length(line, arc_coordinate.length).basicPoint();
+}
+
+lanelet::LineString3d merge_two_lines(
+ const lanelet::LineString3d & line1, const lanelet::ConstLineString3d & line2)
+{
+ lanelet::Points3d new_points;
+ for (const auto & p1 : line1) {
+ const lanelet::BasicPoint3d & p1_basic_point = p1.basicPoint();
+ lanelet::BasicPoint3d p2_basic_point = get_closest_point_on_line(p1, line2);
+ lanelet::BasicPoint3d new_basic_point = (p1_basic_point + p2_basic_point) / 2;
+ lanelet::Point3d new_point(lanelet::utils::getId(), new_basic_point);
+ new_points.push_back(new_point);
+ }
+ return lanelet::LineString3d{lanelet::utils::getId(), new_points};
+}
+
+void copy_data(lanelet::LineString3d & dst, const lanelet::LineString3d & src)
+{
+ dst.clear();
+ for (const lanelet::ConstPoint3d & pt : src) {
+ dst.push_back(static_cast(pt));
+ }
+}
+
+void merge_lines(lanelet::LaneletMapPtr & lanelet_map_ptr)
+{
+ auto lines = convert_line_layer_to_line_strings(lanelet_map_ptr);
+
+ for (size_t i = 0; i < lines.size(); i++) {
+ auto line_i = lines.at(i);
+ for (size_t j = 0; j < i; j++) {
+ auto line_j = lines.at(j);
+ if (are_lines_same(line_i, line_j)) {
+ auto merged_line = merge_two_lines(line_i, line_j);
+ copy_data(line_i, merged_line);
+ copy_data(line_j, merged_line);
+ line_i.setId(line_j.id());
+ std::cout << line_j << " " << line_i << std::endl;
+ // lanelet_map_ptr->add(merged_line);
+ for (lanelet::Point3d & pt : merged_line) {
+ lanelet_map_ptr->add(pt);
+ }
+ break;
+ }
+ }
+ }
+}
+} // namespace autoware::lanelet2_map_utils
+
+int main(int argc, char * argv[])
+{
+ rclcpp::init(argc, argv);
+
+ auto node = rclcpp::Node::make_shared("merge_close_lines");
+
+ const auto llt_map_path = node->declare_parameter("llt_map_path");
+ const auto output_path = node->declare_parameter("output_path");
+
+ lanelet::LaneletMapPtr llt_map_ptr(new lanelet::LaneletMap);
+ lanelet::projection::MGRSProjector projector;
+
+ if (!autoware::lanelet2_map_utils::load_lanelet_map(llt_map_path, llt_map_ptr, projector)) {
+ return EXIT_FAILURE;
+ }
+
+ autoware::lanelet2_map_utils::merge_lines(llt_map_ptr);
+ lanelet::write(output_path, *llt_map_ptr, projector);
+
+ rclcpp::shutdown();
+
+ return 0;
+}
diff --git a/map/autoware_lanelet2_map_utils/src/merge_close_points.cpp b/map/autoware_lanelet2_map_utils/src/merge_close_points.cpp
new file mode 100644
index 00000000..904b97f1
--- /dev/null
+++ b/map/autoware_lanelet2_map_utils/src/merge_close_points.cpp
@@ -0,0 +1,120 @@
+// Copyright 2020 Tier IV, Inc.
+//
+// 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
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+namespace autoware::lanelet2_map_utils
+{
+bool load_lanelet_map(
+ const std::string & llt_map_path, lanelet::LaneletMapPtr & lanelet_map_ptr,
+ lanelet::Projector & projector)
+{
+ lanelet::LaneletMapPtr lanelet_map;
+ lanelet::ErrorMessages errors;
+ lanelet_map_ptr = lanelet::load(llt_map_path, "autoware_osm_handler", projector, &errors);
+
+ for (const auto & error : errors) {
+ RCLCPP_ERROR_STREAM(rclcpp::get_logger("loadLaneletMap"), error);
+ }
+ if (!errors.empty()) {
+ return false;
+ }
+ std::cout << "Loaded Lanelet2 map" << std::endl;
+ return true;
+}
+
+lanelet::Points3d convert_points_layer_to_points(const lanelet::LaneletMapPtr & lanelet_map_ptr)
+{
+ lanelet::Points3d points;
+ std::copy(
+ lanelet_map_ptr->pointLayer.begin(), lanelet_map_ptr->pointLayer.end(),
+ std::back_inserter(points));
+ return points;
+}
+
+// lanelet::LineString3d mergeClosePoints(const lanelet::ConstLineString3d& line1, const
+// lanelet::ConstLineString3d& line2)
+// {
+// lanelet::Points3d new_points;
+// for (const auto& p1 : line1)
+// {
+// p1_basic_point = p1.basicPoint();
+// lanelet::BasicPoint3d p2 = getClosestPointOnLine(line2, p1);
+// lanelet::BasicPoint3d new_basic_point = (p1_basic_point + p2_basic_point)/2;
+// lanelet::Point3d new_point(lanelet::utils::getId(), new_basic_point);
+// new_points.push_back(new_point);
+// }
+// return lanelet::LineString3d(lanelet::utils::getId(), new_points);
+// }
+
+void merge_points(const lanelet::LaneletMapPtr & lanelet_map_ptr)
+{
+ const auto & points = convert_points_layer_to_points(lanelet_map_ptr);
+
+ for (size_t i = 0; i < points.size(); i++) {
+ auto point_i = points.at(i);
+ for (size_t j = 0; j < i; j++) {
+ auto point_j = points.at(j);
+
+ double distance = boost::geometry::distance(point_i, point_j);
+ if (distance < 0.1) {
+ const auto new_point = (point_i.basicPoint() + point_j.basicPoint()) / 2;
+ // const auto new_pt3d = lanelet::Point3d(lanelet::utils::getId(), new_point);
+ point_i.x() = new_point.x();
+ point_i.y() = new_point.y();
+ point_i.z() = new_point.z();
+ point_j.x() = new_point.x();
+ point_j.y() = new_point.y();
+ point_j.z() = new_point.z();
+ point_i.setId(point_j.id());
+ }
+ }
+ }
+}
+} // namespace autoware::lanelet2_map_utils
+
+int main(int argc, char * argv[])
+{
+ rclcpp::init(argc, argv);
+
+ auto node = rclcpp::Node::make_shared("merge_close_points");
+
+ const auto llt_map_path = node->declare_parameter("llt_map_path");
+ const auto output_path = node->declare_parameter("output_path");
+
+ lanelet::LaneletMapPtr llt_map_ptr(new lanelet::LaneletMap);
+ lanelet::projection::MGRSProjector projector;
+
+ if (!autoware::lanelet2_map_utils::load_lanelet_map(llt_map_path, llt_map_ptr, projector)) {
+ return EXIT_FAILURE;
+ }
+
+ autoware::lanelet2_map_utils::merge_points(llt_map_ptr);
+ lanelet::write(output_path, *llt_map_ptr, projector);
+
+ rclcpp::shutdown();
+
+ return 0;
+}
diff --git a/map/autoware_lanelet2_map_utils/src/remove_unreferenced_geometry.cpp b/map/autoware_lanelet2_map_utils/src/remove_unreferenced_geometry.cpp
new file mode 100644
index 00000000..7d4e16f9
--- /dev/null
+++ b/map/autoware_lanelet2_map_utils/src/remove_unreferenced_geometry.cpp
@@ -0,0 +1,98 @@
+// Copyright 2020 Tier IV, Inc.
+//
+// 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
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+namespace autoware::lanelet2_map_utils
+{
+bool load_lanelet_map(
+ const std::string & llt_map_path, lanelet::LaneletMapPtr & lanelet_map_ptr,
+ lanelet::Projector & projector)
+{
+ lanelet::LaneletMapPtr lanelet_map;
+ lanelet::ErrorMessages errors;
+ lanelet_map_ptr = lanelet::load(llt_map_path, "autoware_osm_handler", projector, &errors);
+
+ for (const auto & error : errors) {
+ RCLCPP_ERROR_STREAM(rclcpp::get_logger("loadLaneletMap"), error);
+ }
+ if (!errors.empty()) {
+ return false;
+ }
+ std::cout << "Loaded Lanelet2 map" << std::endl;
+ return true;
+}
+
+lanelet::Points3d convert_points_layer_to_points(const lanelet::LaneletMapPtr & lanelet_map_ptr)
+{
+ lanelet::Points3d points;
+ std::copy(
+ lanelet_map_ptr->pointLayer.begin(), lanelet_map_ptr->pointLayer.end(),
+ std::back_inserter(points));
+ return points;
+}
+
+lanelet::LineStrings3d convert_line_layer_to_line_strings(
+ const lanelet::LaneletMapPtr & lanelet_map_ptr)
+{
+ lanelet::LineStrings3d lines;
+ std::copy(
+ lanelet_map_ptr->lineStringLayer.begin(), lanelet_map_ptr->lineStringLayer.end(),
+ std::back_inserter(lines));
+ return lines;
+}
+
+void remove_unreferenced_geometry(lanelet::LaneletMapPtr & lanelet_map_ptr)
+{
+ lanelet::LaneletMapPtr new_map(new lanelet::LaneletMap);
+ for (const auto & llt : lanelet_map_ptr->laneletLayer) {
+ new_map->add(llt);
+ }
+ lanelet_map_ptr = new_map;
+}
+} // namespace autoware::lanelet2_map_utils
+
+int main(int argc, char * argv[])
+{
+ rclcpp::init(argc, argv);
+
+ auto node = rclcpp::Node::make_shared("remove_unreferenced_geometry");
+
+ const auto llt_map_path = node->declare_parameter("llt_map_path");
+ const auto output_path = node->declare_parameter("output_path");
+
+ lanelet::LaneletMapPtr llt_map_ptr(new lanelet::LaneletMap);
+ lanelet::projection::MGRSProjector projector;
+
+ if (!autoware::lanelet2_map_utils::load_lanelet_map(llt_map_path, llt_map_ptr, projector)) {
+ return EXIT_FAILURE;
+ }
+ autoware::lanelet2_map_utils::remove_unreferenced_geometry(llt_map_ptr);
+ lanelet::write(output_path, *llt_map_ptr, projector);
+
+ rclcpp::shutdown();
+
+ return 0;
+}
diff --git a/map/autoware_lanelet2_map_utils/src/transform_maps.cpp b/map/autoware_lanelet2_map_utils/src/transform_maps.cpp
new file mode 100644
index 00000000..dde8f935
--- /dev/null
+++ b/map/autoware_lanelet2_map_utils/src/transform_maps.cpp
@@ -0,0 +1,154 @@
+// Copyright 2020 Tier IV, Inc.
+//
+// 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
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+namespace autoware::lanelet2_map_utils
+{
+bool load_lanelet_map(
+ const std::string & llt_map_path, lanelet::LaneletMapPtr & lanelet_map_ptr,
+ lanelet::Projector & projector)
+{
+ lanelet::LaneletMapPtr lanelet_map;
+ lanelet::ErrorMessages errors;
+ lanelet_map_ptr = lanelet::load(llt_map_path, "autoware_osm_handler", projector, &errors);
+
+ for (const auto & error : errors) {
+ RCLCPP_ERROR_STREAM(rclcpp::get_logger("loadLaneletMap"), error);
+ }
+ if (!errors.empty()) {
+ return false;
+ }
+ std::cout << "Loaded Lanelet2 map" << std::endl;
+ return true;
+}
+
+bool load_pcd_map(
+ const std::string & pcd_map_path, pcl::PointCloud::Ptr & pcd_map_ptr)
+{
+ if (pcl::io::loadPCDFile(pcd_map_path, *pcd_map_ptr) == -1) { //* load the file
+ RCLCPP_ERROR_STREAM(rclcpp::get_logger("loadPCDMap"), "Couldn't read file: " << pcd_map_path);
+ return false;
+ }
+ std::cout << "Loaded " << pcd_map_ptr->width * pcd_map_ptr->height << " data points."
+ << std::endl;
+ return true;
+}
+
+void transform_maps(
+ const pcl::PointCloud::Ptr & pcd_map_ptr,
+ const lanelet::LaneletMapPtr & lanelet_map_ptr, const Eigen::Affine3d & affine)
+{
+ {
+ for (lanelet::Point3d & pt : lanelet_map_ptr->pointLayer) {
+ Eigen::Vector3d eigen_pt(pt.x(), pt.y(), pt.z());
+ auto transformed_pt = affine * eigen_pt;
+ pt.x() = transformed_pt.x();
+ pt.y() = transformed_pt.y();
+ pt.z() = transformed_pt.z();
+ }
+ }
+
+ {
+ for (auto & pt : pcd_map_ptr->points) {
+ Eigen::Vector3d eigen_pt(pt.x, pt.y, pt.z);
+ auto transformed_pt = affine * eigen_pt;
+ pt.x = static_cast(transformed_pt.x());
+ pt.y = static_cast(transformed_pt.y());
+ pt.z = static_cast(transformed_pt.z());
+ }
+ }
+}
+
+Eigen::Affine3d create_affine_matrix_from_xyzrpy(
+ const double x, const double y, const double z, const double roll, const double pitch,
+ const double yaw)
+{
+ double roll_rad = roll * M_PI / 180.0;
+ double pitch_rad = pitch * M_PI / 180.0;
+ double yaw_rad = yaw * M_PI / 180.0;
+
+ Eigen::Translation trans(x, y, z);
+ Eigen::Matrix3d rot;
+ rot = Eigen::AngleAxisd(yaw_rad, Eigen::Vector3d::UnitZ()) *
+ Eigen::AngleAxisd(pitch_rad, Eigen::Vector3d::UnitY()) *
+ Eigen::AngleAxisd(roll_rad, Eigen::Vector3d::UnitX());
+ return trans * rot;
+}
+} // namespace autoware::lanelet2_map_utils
+
+int main(int argc, char * argv[])
+{
+ rclcpp::init(argc, argv);
+
+ auto node = rclcpp::Node::make_shared("transform_maps");
+
+ const auto llt_map_path = node->declare_parameter("llt_map_path");
+ const auto pcd_map_path = node->declare_parameter("pcd_map_path");
+ const auto llt_output_path = node->declare_parameter("llt_output_path");
+ const auto pcd_output_path = node->declare_parameter("pcd_output_path");
+ const auto x = node->declare_parameter("x");
+ const auto y = node->declare_parameter("y");
+ const auto z = node->declare_parameter("z");
+ const auto roll = node->declare_parameter("roll");
+ const auto pitch = node->declare_parameter("pitch");
+ const auto yaw = node->declare_parameter("yaw");
+
+ std::cout << "transforming maps with following parameters" << std::endl
+ << "x " << x << std::endl
+ << "y " << y << std::endl
+ << "z " << z << std::endl
+ << "roll " << roll << std::endl
+ << "pitch " << pitch << std::endl
+ << "yaw " << yaw << std::endl;
+
+ lanelet::LaneletMapPtr llt_map_ptr(new lanelet::LaneletMap);
+ lanelet::projection::MGRSProjector projector;
+
+ pcl::PointCloud::Ptr pcd_map_ptr(new pcl::PointCloud);
+
+ if (!autoware::lanelet2_map_utils::load_lanelet_map(llt_map_path, llt_map_ptr, projector)) {
+ return EXIT_FAILURE;
+ }
+ if (!autoware::lanelet2_map_utils::load_pcd_map(pcd_map_path, pcd_map_ptr)) {
+ return EXIT_FAILURE;
+ }
+ Eigen::Affine3d affine =
+ autoware::lanelet2_map_utils::create_affine_matrix_from_xyzrpy(x, y, z, roll, pitch, yaw);
+
+ const auto mgrs_grid =
+ node->declare_parameter("mgrs_grid", projector.getProjectedMGRSGrid());
+ std::cout << "using mgrs grid: " << mgrs_grid << std::endl;
+
+ autoware::lanelet2_map_utils::transform_maps(pcd_map_ptr, llt_map_ptr, affine);
+ lanelet::write(llt_output_path, *llt_map_ptr, projector);
+ pcl::io::savePCDFileBinary(pcd_output_path, *pcd_map_ptr);
+
+ rclcpp::shutdown();
+
+ return 0;
+}