forked from autowarefoundation/autoware_utils
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathboost_polygon_utils.cpp
267 lines (229 loc) · 9.7 KB
/
boost_polygon_utils.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
// Copyright 2022 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 "autoware_utils_geometry/geometry/boost_polygon_utils.hpp"
#include "autoware_utils_geometry/geometry/geometry.hpp"
#include <boost/geometry/geometry.hpp>
#include <tf2/utils.h>
namespace
{
namespace bg = boost::geometry;
using autoware_utils::Point2d;
using autoware_utils::Polygon2d;
void append_point_to_polygon(Polygon2d & polygon, const geometry_msgs::msg::Point & geom_point)
{
Point2d point;
point.x() = geom_point.x;
point.y() = geom_point.y;
bg::append(polygon.outer(), point);
}
void append_point_to_polygon(Polygon2d & polygon, const Point2d & point)
{
bg::append(polygon.outer(), point);
}
/*
* NOTE: Area is negative when footprint.points is clock wise.
* Area is positive when footprint.points is anti clock wise.
*/
double get_polygon_area(const geometry_msgs::msg::Polygon & footprint)
{
double area = 0.0;
for (size_t i = 0; i < footprint.points.size(); ++i) {
size_t j = (i + 1) % footprint.points.size();
area += 0.5 * (footprint.points.at(i).x * footprint.points.at(j).y -
footprint.points.at(j).x * footprint.points.at(i).y);
}
return area;
}
double get_rectangle_area(const geometry_msgs::msg::Vector3 & dimensions)
{
return static_cast<double>(dimensions.x * dimensions.y);
}
double get_circle_area(const geometry_msgs::msg::Vector3 & dimensions)
{
return static_cast<double>((dimensions.x / 2.0) * (dimensions.x / 2.0) * M_PI);
}
} // namespace
namespace autoware_utils_geometry
{
bool is_clockwise(const Polygon2d & polygon)
{
const int n = polygon.outer().size();
const double x_offset = polygon.outer().at(0).x();
const double y_offset = polygon.outer().at(0).y();
double sum = 0.0;
for (std::size_t i = 0; i < polygon.outer().size(); ++i) {
sum +=
(polygon.outer().at(i).x() - x_offset) * (polygon.outer().at((i + 1) % n).y() - y_offset) -
(polygon.outer().at(i).y() - y_offset) * (polygon.outer().at((i + 1) % n).x() - x_offset);
}
return sum < 0.0;
}
Polygon2d inverse_clockwise(const Polygon2d & polygon)
{
auto output_polygon = polygon;
boost::geometry::reverse(output_polygon);
return output_polygon;
}
geometry_msgs::msg::Polygon rotate_polygon(
const geometry_msgs::msg::Polygon & polygon, const double & angle)
{
const double cos = std::cos(angle);
const double sin = std::sin(angle);
geometry_msgs::msg::Polygon rotated_polygon;
for (const auto & point : polygon.points) {
auto rotated_point = point;
rotated_point.x = cos * point.x - sin * point.y;
rotated_point.y = sin * point.x + cos * point.y;
rotated_polygon.points.push_back(rotated_point);
}
return rotated_polygon;
}
Polygon2d rotate_polygon(const Polygon2d & polygon, const double angle)
{
Polygon2d rotated_polygon;
const boost::geometry::strategy::transform::rotate_transformer<
boost::geometry::radian, double, 2, 2>
rotation(-angle);
boost::geometry::transform(polygon, rotated_polygon, rotation);
return rotated_polygon;
}
Polygon2d to_polygon2d(
const geometry_msgs::msg::Pose & pose, const autoware_perception_msgs::msg::Shape & shape)
{
Polygon2d polygon;
if (shape.type == autoware_perception_msgs::msg::Shape::BOUNDING_BOX) {
const auto point0 = autoware_utils::calc_offset_pose(
pose, shape.dimensions.x / 2.0, shape.dimensions.y / 2.0, 0.0)
.position;
const auto point1 = autoware_utils::calc_offset_pose(
pose, -shape.dimensions.x / 2.0, shape.dimensions.y / 2.0, 0.0)
.position;
const auto point2 = autoware_utils::calc_offset_pose(
pose, -shape.dimensions.x / 2.0, -shape.dimensions.y / 2.0, 0.0)
.position;
const auto point3 = autoware_utils::calc_offset_pose(
pose, shape.dimensions.x / 2.0, -shape.dimensions.y / 2.0, 0.0)
.position;
append_point_to_polygon(polygon, point0);
append_point_to_polygon(polygon, point1);
append_point_to_polygon(polygon, point2);
append_point_to_polygon(polygon, point3);
} else if (shape.type == autoware_perception_msgs::msg::Shape::CYLINDER) {
const double radius = shape.dimensions.x / 2.0;
constexpr int circle_discrete_num = 6;
for (int i = 0; i < circle_discrete_num; ++i) {
geometry_msgs::msg::Point point;
point.x = std::cos(
(static_cast<double>(i) / static_cast<double>(circle_discrete_num)) * 2.0 * M_PI +
M_PI / static_cast<double>(circle_discrete_num)) *
radius +
pose.position.x;
point.y = std::sin(
(static_cast<double>(i) / static_cast<double>(circle_discrete_num)) * 2.0 * M_PI +
M_PI / static_cast<double>(circle_discrete_num)) *
radius +
pose.position.y;
append_point_to_polygon(polygon, point);
}
} else if (shape.type == autoware_perception_msgs::msg::Shape::POLYGON) {
const double poly_yaw = tf2::getYaw(pose.orientation);
const auto rotated_footprint = rotate_polygon(shape.footprint, poly_yaw);
for (const auto rel_point : rotated_footprint.points) {
geometry_msgs::msg::Point abs_point;
abs_point.x = pose.position.x + rel_point.x;
abs_point.y = pose.position.y + rel_point.y;
append_point_to_polygon(polygon, abs_point);
}
} else {
throw std::logic_error("The shape type is not supported in autoware_utils.");
}
// NOTE: push back the first point in order to close polygon
if (!polygon.outer().empty()) {
append_point_to_polygon(polygon, polygon.outer().front());
}
return is_clockwise(polygon) ? polygon : inverse_clockwise(polygon);
}
autoware_utils::Polygon2d to_polygon2d(const autoware_perception_msgs::msg::DetectedObject & object)
{
return autoware_utils::to_polygon2d(object.kinematics.pose_with_covariance.pose, object.shape);
}
autoware_utils::Polygon2d to_polygon2d(const autoware_perception_msgs::msg::TrackedObject & object)
{
return autoware_utils::to_polygon2d(object.kinematics.pose_with_covariance.pose, object.shape);
}
autoware_utils::Polygon2d to_polygon2d(
const autoware_perception_msgs::msg::PredictedObject & object)
{
return autoware_utils::to_polygon2d(
object.kinematics.initial_pose_with_covariance.pose, object.shape);
}
Polygon2d to_footprint(
const geometry_msgs::msg::Pose & base_link_pose, const double base_to_front,
const double base_to_rear, const double width)
{
Polygon2d polygon;
const auto point0 =
autoware_utils::calc_offset_pose(base_link_pose, base_to_front, width / 2.0, 0.0).position;
const auto point1 =
autoware_utils::calc_offset_pose(base_link_pose, base_to_front, -width / 2.0, 0.0).position;
const auto point2 =
autoware_utils::calc_offset_pose(base_link_pose, -base_to_rear, -width / 2.0, 0.0).position;
const auto point3 =
autoware_utils::calc_offset_pose(base_link_pose, -base_to_rear, width / 2.0, 0.0).position;
append_point_to_polygon(polygon, point0);
append_point_to_polygon(polygon, point1);
append_point_to_polygon(polygon, point2);
append_point_to_polygon(polygon, point3);
append_point_to_polygon(polygon, point0);
return is_clockwise(polygon) ? polygon : inverse_clockwise(polygon);
}
double get_area(const autoware_perception_msgs::msg::Shape & shape)
{
if (shape.type == autoware_perception_msgs::msg::Shape::BOUNDING_BOX) {
return get_rectangle_area(shape.dimensions);
} else if (shape.type == autoware_perception_msgs::msg::Shape::CYLINDER) {
return get_circle_area(shape.dimensions);
} else if (shape.type == autoware_perception_msgs::msg::Shape::POLYGON) {
return get_polygon_area(shape.footprint);
}
throw std::logic_error("The shape type is not supported in autoware_utils.");
}
// NOTE: The number of vertices on the expanded polygon by boost::geometry::buffer
// is larger than the original one.
// This function fixes the issue.
Polygon2d expand_polygon(const Polygon2d & input_polygon, const double offset)
{
// NOTE: input_polygon is supposed to have a duplicated point.
const size_t num_points = input_polygon.outer().size() - 1;
Polygon2d expanded_polygon;
for (size_t i = 0; i < num_points; ++i) {
const auto & curr_p = input_polygon.outer().at(i);
const auto & next_p = input_polygon.outer().at(i + 1);
const auto & prev_p =
i == 0 ? input_polygon.outer().at(num_points - 1) : input_polygon.outer().at(i - 1);
Eigen::Vector2d current_to_next(next_p.x() - curr_p.x(), next_p.y() - curr_p.y());
Eigen::Vector2d current_to_prev(prev_p.x() - curr_p.x(), prev_p.y() - curr_p.y());
current_to_next.normalize();
current_to_prev.normalize();
const Eigen::Vector2d offset_vector = (-current_to_next - current_to_prev).normalized();
const double theta = std::acos(offset_vector.dot(current_to_next));
const double scaled_offset = offset / std::sin(theta);
const Eigen::Vector2d offset_point =
Eigen::Vector2d(curr_p.x(), curr_p.y()) + offset_vector * scaled_offset;
expanded_polygon.outer().push_back(Point2d(offset_point.x(), offset_point.y()));
}
boost::geometry::correct(expanded_polygon);
return expanded_polygon;
}
} // namespace autoware_utils_geometry