Skip to content

Commit 42f5eb6

Browse files
committed
feat(trajectory): add populate function
Signed-off-by: Mamoru Sobue <mamoru.sobue@tier4.jp>
1 parent 4639e9b commit 42f5eb6

File tree

5 files changed

+658
-0
lines changed

5 files changed

+658
-0
lines changed

common/autoware_trajectory/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ if(BUILD_TESTING)
2828
find_package(ament_lint_auto REQUIRED)
2929
find_package(autoware_pyplot REQUIRED)
3030
find_package(range-v3 REQUIRED)
31+
find_package(autoware_test_utils REQUIRED)
3132
ament_lint_auto_find_test_dependencies()
3233
find_package(pybind11 REQUIRED)
3334
include_directories(${autoware_pyplot_INCLUDE_DIRS})
35+
include_directories(${autoware_test_utils_INCLUDE_DIRS})
3436
foreach(example_file ${example_files})
3537
get_filename_component(example_name ${example_file} NAME_WE)
3638
ament_auto_add_executable(${example_name}
@@ -41,6 +43,7 @@ if(BUILD_TESTING)
4143
${autoware_pyplot_LIBRARIES}
4244
range-v3::range-v3
4345
pybind11::embed
46+
${autoware_test_utils_LIBRARIES}
4447
)
4548
endforeach()
4649
endif()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2025 TIER IV, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef AUTOWARE__TRAJECTORY__UTILS__POPULATE_HPP_
16+
#define AUTOWARE__TRAJECTORY__UTILS__POPULATE_HPP_
17+
18+
#include "autoware/trajectory/detail/types.hpp"
19+
#include "autoware/trajectory/forward.hpp"
20+
21+
#include <tl_expected/expected.hpp>
22+
23+
#include <autoware_internal_planning_msgs/msg/path_point_with_lane_id.hpp>
24+
25+
#include <string>
26+
#include <vector>
27+
28+
namespace autoware::trajectory
29+
{
30+
31+
/**
32+
* @brief if the input point size is less than 3, add 3rd point, otherwise return as is
33+
* @param[in] inputs vector of point whose size is at least 2
34+
* @return the vector of points whose size is at least 3, or error reason
35+
* @note {x, y, z}/orientation are interpolated by Linear/SphericalLinear. other properties as
36+
* interpolated by StairStep
37+
*/
38+
tl::expected<std::vector<autoware_internal_planning_msgs::msg::PathPointWithLaneId>, std::string>
39+
populate3(const std::vector<autoware_internal_planning_msgs::msg::PathPointWithLaneId> & inputs);
40+
41+
/**
42+
* @brief if the input point size is less than 4, add 4th point, otherwise return as is
43+
* @param[in] inputs inputs
44+
* @return optional the vector of points whose size is at least 4, so that it can be interpolated by
45+
* CubicSpline, or error reason
46+
* @note {x, y, z}/orientation are interpolated by Linear/SphericalLinear. other properties as
47+
* interpolated by StairStep
48+
*/
49+
tl::expected<std::vector<autoware_internal_planning_msgs::msg::PathPointWithLaneId>, std::string>
50+
populate4(const std::vector<autoware_internal_planning_msgs::msg::PathPointWithLaneId> & inputs);
51+
52+
/**
53+
* @brief if the input point size is less than 5, add 5th point, otherwise return as is
54+
* @param[in] inputs inputs
55+
* @return the vector of points whose size is at least 5, so that it can be interpolated by
56+
* AkimaSpline, or error reason
57+
* @note {x, y, z}/orientation are interpolated by Cubic/SphericalLinear. other properties as
58+
* interpolated by StairStep
59+
std::vector<autoware_internal_planning_msgs::msg::PathPointWithLaneId> populate5(
60+
const std::vector<autoware_internal_planning_msgs::msg::PathPointWithLaneId> & inputs,
61+
const size_t minimum_number_of_points);
62+
*/
63+
64+
} // namespace autoware::trajectory
65+
#endif // AUTOWARE__TRAJECTORY__UTILS__POPULATE_HPP_

common/autoware_trajectory/package.xml

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
<depend>autoware_internal_planning_msgs</depend>
1818
<depend>autoware_planning_msgs</depend>
19+
<depend>autoware_utils_geometry</depend>
1920
<depend>geometry_msgs</depend>
2021
<depend>lanelet2_core</depend>
2122
<depend>rclcpp</depend>
@@ -27,6 +28,7 @@
2728
<test_depend>ament_lint_auto</test_depend>
2829
<test_depend>autoware_lint_common</test_depend>
2930
<test_depend>autoware_pyplot</test_depend>
31+
<test_depend>autoware_test_utils</test_depend>
3032
<test_depend>pybind11_vendor</test_depend>
3133
<test_depend>range-v3</test_depend>
3234

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Copyright 2025 TIER IV, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "autoware/trajectory/utils/populate.hpp"
16+
17+
#include "autoware/trajectory/interpolator/linear.hpp"
18+
#include "autoware/trajectory/interpolator/spherical_linear.hpp"
19+
#include "autoware/trajectory/path_point_with_lane_id.hpp"
20+
#include "autoware_utils_geometry/geometry.hpp"
21+
22+
#include <string>
23+
#include <vector>
24+
25+
namespace autoware::trajectory
26+
{
27+
28+
tl::expected<std::vector<autoware_internal_planning_msgs::msg::PathPointWithLaneId>, std::string>
29+
populate3(const std::vector<autoware_internal_planning_msgs::msg::PathPointWithLaneId> & inputs)
30+
{
31+
if (inputs.size() >= 3) {
32+
return inputs;
33+
}
34+
if (inputs.size() < 2) {
35+
return tl::unexpected("cannot populate3() from #" + std::to_string(inputs.size()) + " points!");
36+
}
37+
38+
// assert(inputs.size() == 2);
39+
40+
const auto & p1 = inputs.at(0).point.pose;
41+
const auto & pos1 = p1.position;
42+
const auto & p2 = inputs.at(1).point.pose;
43+
const auto & pos2 = p2.position;
44+
const auto l = autoware_utils_geometry::calc_distance3d(pos1, pos2);
45+
46+
const auto quat_result =
47+
interpolator::SphericalLinear::Builder{}
48+
.set_bases(std::vector<double>{0.0, l})
49+
.set_values(std::vector<geometry_msgs::msg::Quaternion>({p1.orientation, p2.orientation}))
50+
.build();
51+
52+
// LCOV_EXCL_START
53+
if (!quat_result) {
54+
// this never happens because two values are given
55+
return tl::unexpected(std::string("failed to interpolate orientation"));
56+
}
57+
// LCOV_EXCL_END
58+
59+
const geometry_msgs::msg::Point mid_position = geometry_msgs::build<geometry_msgs::msg::Point>()
60+
.x((pos1.x + pos2.x) / 2.0)
61+
.y((pos1.y + pos2.y) / 2.0)
62+
.z((pos1.z + pos2.z) / 2.0);
63+
const auto mid_quat = quat_result->compute(l / 2.0);
64+
65+
autoware_internal_planning_msgs::msg::PathPointWithLaneId point;
66+
point.point.pose.position = mid_position;
67+
point.point.pose.orientation = mid_quat;
68+
point.point.longitudinal_velocity_mps = inputs.at(0).point.longitudinal_velocity_mps;
69+
point.point.lateral_velocity_mps = inputs.at(0).point.lateral_velocity_mps;
70+
point.point.heading_rate_rps = inputs.at(0).point.heading_rate_rps;
71+
point.lane_ids = inputs.at(0).lane_ids;
72+
73+
return std::vector{inputs[0], point, inputs[1]};
74+
}
75+
76+
tl::expected<std::vector<autoware_internal_planning_msgs::msg::PathPointWithLaneId>, std::string>
77+
populate4(const std::vector<autoware_internal_planning_msgs::msg::PathPointWithLaneId> & inputs)
78+
{
79+
if (inputs.size() >= 4) {
80+
return inputs;
81+
}
82+
if (inputs.size() < 2) {
83+
return tl::unexpected("cannot populate4() from #" + std::to_string(inputs.size()) + " points!");
84+
}
85+
86+
const auto try_inputs3 = populate3(inputs);
87+
if (!try_inputs3) {
88+
return tl::unexpected(try_inputs3.error());
89+
}
90+
const auto & inputs3 = inputs.size() == 2 ? try_inputs3.value() : inputs;
91+
92+
const auto input3_interpolation_result =
93+
Trajectory<autoware_internal_planning_msgs::msg::PathPointWithLaneId>::Builder{}
94+
.set_xy_interpolator<interpolator::Linear>()
95+
.set_z_interpolator<interpolator::Linear>()
96+
.set_orientation_interpolator<interpolator::SphericalLinear>()
97+
.build(inputs3);
98+
99+
// LCOV_EXCL_START
100+
if (!input3_interpolation_result) {
101+
// actually this block is impossible because 3 points are given, which is sufficient for Linear
102+
// interpolation
103+
return tl::unexpected(std::string("failed Linear interpolation in populate4()!"));
104+
}
105+
// LCOV_EXCL_END
106+
107+
const auto & interpolation = input3_interpolation_result.value();
108+
109+
const auto bases = interpolation.get_internal_bases();
110+
// assert(bases.size() == 3);
111+
const auto bases_diff =
112+
std::vector<double>{(bases.at(1) - bases.at(0)), (bases.at(2) - bases.at(1))};
113+
if (bases_diff.at(0) >= bases_diff.at(1)) {
114+
const auto new_base = (bases.at(0) + bases.at(1)) / 2.0;
115+
return std::vector{
116+
inputs3.at(0), interpolation.compute(new_base), inputs3.at(1), inputs3.at(2)};
117+
}
118+
const auto new_base = (bases.at(1) + bases.at(2)) / 2.0;
119+
return std::vector{inputs3.at(0), inputs3.at(1), interpolation.compute(new_base), inputs3.at(2)};
120+
}
121+
122+
} // namespace autoware::trajectory

0 commit comments

Comments
 (0)