|
| 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