forked from autowarefoundation/autoware_utils
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgeometry.cpp
397 lines (341 loc) · 12.5 KB
/
geometry.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
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
// Copyright 2023-2024 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/geometry.hpp"
#include "autoware_utils_geometry/geometry/gjk_2d.hpp"
#include <Eigen/Geometry>
#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
#include <tf2/convert.h>
#include <string>
namespace tf2
{
void fromMsg(const geometry_msgs::msg::PoseStamped & msg, tf2::Stamped<tf2::Transform> & out)
{
out.stamp_ = tf2_ros::fromMsg(msg.header.stamp);
out.frame_id_ = msg.header.frame_id;
tf2::Transform tmp;
fromMsg(msg.pose, tmp);
out.setData(tmp);
}
} // namespace tf2
namespace autoware_utils_geometry
{
geometry_msgs::msg::Vector3 get_rpy(const geometry_msgs::msg::Quaternion & quat)
{
geometry_msgs::msg::Vector3 rpy;
tf2::Quaternion q(quat.x, quat.y, quat.z, quat.w);
tf2::Matrix3x3(q).getRPY(rpy.x, rpy.y, rpy.z);
return rpy;
}
geometry_msgs::msg::Vector3 get_rpy(const geometry_msgs::msg::Pose & pose)
{
return get_rpy(pose.orientation);
}
geometry_msgs::msg::Vector3 get_rpy(const geometry_msgs::msg::PoseStamped & pose)
{
return get_rpy(pose.pose);
}
geometry_msgs::msg::Vector3 get_rpy(const geometry_msgs::msg::PoseWithCovarianceStamped & pose)
{
return get_rpy(pose.pose.pose);
}
geometry_msgs::msg::Quaternion create_quaternion(
const double x, const double y, const double z, const double w)
{
geometry_msgs::msg::Quaternion q;
q.x = x;
q.y = y;
q.z = z;
q.w = w;
return q;
}
geometry_msgs::msg::Vector3 create_translation(const double x, const double y, const double z)
{
geometry_msgs::msg::Vector3 v;
v.x = x;
v.y = y;
v.z = z;
return v;
}
// Revival of tf::create_quaternion_from_rpy
// https://answers.ros.org/question/304397/recommended-way-to-construct-quaternion-from-rollpitchyaw-with-tf2/
geometry_msgs::msg::Quaternion create_quaternion_from_rpy(
const double roll, const double pitch, const double yaw)
{
tf2::Quaternion q;
q.setRPY(roll, pitch, yaw);
return tf2::toMsg(q);
}
geometry_msgs::msg::Quaternion create_quaternion_from_yaw(const double yaw)
{
tf2::Quaternion q;
q.setRPY(0, 0, yaw);
return tf2::toMsg(q);
}
double calc_elevation_angle(
const geometry_msgs::msg::Point & p_from, const geometry_msgs::msg::Point & p_to)
{
const double dz = p_to.z - p_from.z;
const double dist_2d = calc_distance2d(p_from, p_to);
return std::atan2(dz, dist_2d);
}
/**
* @brief calculate azimuth angle of two points.
* @details This function returns the azimuth angle of the position of the two input points
* with respect to the origin of their coordinate system.
* If x and y of the two points are the same, the calculation result will be unstable.
* @param p_from source point
* @param p_to target point
* @return -pi < azimuth angle < pi.
*/
double calc_azimuth_angle(
const geometry_msgs::msg::Point & p_from, const geometry_msgs::msg::Point & p_to)
{
const double dx = p_to.x - p_from.x;
const double dy = p_to.y - p_from.y;
return std::atan2(dy, dx);
}
geometry_msgs::msg::Pose transform2pose(const geometry_msgs::msg::Transform & transform)
{
geometry_msgs::msg::Pose pose;
pose.position.x = transform.translation.x;
pose.position.y = transform.translation.y;
pose.position.z = transform.translation.z;
pose.orientation = transform.rotation;
return pose;
}
geometry_msgs::msg::PoseStamped transform2pose(
const geometry_msgs::msg::TransformStamped & transform)
{
geometry_msgs::msg::PoseStamped pose;
pose.header = transform.header;
pose.pose = transform2pose(transform.transform);
return pose;
}
geometry_msgs::msg::Transform pose2transform(const geometry_msgs::msg::Pose & pose)
{
geometry_msgs::msg::Transform transform;
transform.translation.x = pose.position.x;
transform.translation.y = pose.position.y;
transform.translation.z = pose.position.z;
transform.rotation = pose.orientation;
return transform;
}
geometry_msgs::msg::TransformStamped pose2transform(
const geometry_msgs::msg::PoseStamped & pose, const std::string & child_frame_id)
{
geometry_msgs::msg::TransformStamped transform;
transform.header = pose.header;
transform.transform = pose2transform(pose.pose);
transform.child_frame_id = child_frame_id;
return transform;
}
Point3d transform_point(const Point3d & point, const geometry_msgs::msg::Transform & transform)
{
const auto & translation = transform.translation;
const auto & rotation = transform.rotation;
const Eigen::Translation3d T(translation.x, translation.y, translation.z);
const Eigen::Quaterniond R(rotation.w, rotation.x, rotation.y, rotation.z);
const Eigen::Vector3d transformed(T * R * point);
return Point3d{transformed.x(), transformed.y(), transformed.z()};
}
Point2d transform_point(const Point2d & point, const geometry_msgs::msg::Transform & transform)
{
Point3d point_3d{point.x(), point.y(), 0};
const auto transformed = transform_point(point_3d, transform);
return Point2d{transformed.x(), transformed.y()};
}
Eigen::Vector3d transform_point(
const Eigen::Vector3d & point, const geometry_msgs::msg::Pose & pose)
{
geometry_msgs::msg::Transform transform;
transform.translation.x = pose.position.x;
transform.translation.y = pose.position.y;
transform.translation.z = pose.position.z;
transform.rotation = pose.orientation;
Point3d p = transform_point(Point3d(point.x(), point.y(), point.z()), transform);
return Eigen::Vector3d(p.x(), p.y(), p.z());
}
geometry_msgs::msg::Point transform_point(
const geometry_msgs::msg::Point & point, const geometry_msgs::msg::Pose & pose)
{
const Eigen::Vector3d vec = Eigen::Vector3d(point.x, point.y, point.z);
auto transformed_vec = transform_point(vec, pose);
geometry_msgs::msg::Point transformed_point;
transformed_point.x = transformed_vec.x();
transformed_point.y = transformed_vec.y();
transformed_point.z = transformed_vec.z();
return transformed_point;
}
geometry_msgs::msg::Point32 transform_point(
const geometry_msgs::msg::Point32 & point32, const geometry_msgs::msg::Pose & pose)
{
const auto point =
geometry_msgs::build<geometry_msgs::msg::Point>().x(point32.x).y(point32.y).z(point32.z);
const auto transformed_point = autoware_utils::transform_point(point, pose);
return geometry_msgs::build<geometry_msgs::msg::Point32>()
.x(transformed_point.x)
.y(transformed_point.y)
.z(transformed_point.z);
}
geometry_msgs::msg::Pose transform_pose(
const geometry_msgs::msg::Pose & pose, const geometry_msgs::msg::TransformStamped & transform)
{
geometry_msgs::msg::Pose transformed_pose;
tf2::doTransform(pose, transformed_pose, transform);
return transformed_pose;
}
geometry_msgs::msg::Pose transform_pose(
const geometry_msgs::msg::Pose & pose, const geometry_msgs::msg::Transform & transform)
{
geometry_msgs::msg::TransformStamped transform_stamped;
transform_stamped.transform = transform;
return transform_pose(pose, transform_stamped);
}
geometry_msgs::msg::Pose transform_pose(
const geometry_msgs::msg::Pose & pose, const geometry_msgs::msg::Pose & pose_transform)
{
tf2::Transform transform;
tf2::convert(pose_transform, transform);
geometry_msgs::msg::TransformStamped transform_msg;
transform_msg.transform = tf2::toMsg(transform);
return transform_pose(pose, transform_msg);
}
// Transform pose in world coordinates to local coordinates
/*
geometry_msgs::msg::Pose inverse_transform_pose(
const geometry_msgs::msg::Pose & pose, const geometry_msgs::msg::TransformStamped & transform)
{
tf2::Transform tf;
tf2::fromMsg(transform, tf);
geometry_msgs::msg::TransformStamped transform_stamped;
transform_stamped.transform = tf2::toMsg(tf.inverse());
return transform_pose(pose, transform_stamped);
}
*/
// Transform pose in world coordinates to local coordinates
geometry_msgs::msg::Pose inverse_transform_pose(
const geometry_msgs::msg::Pose & pose, const geometry_msgs::msg::Transform & transform)
{
tf2::Transform tf;
tf2::fromMsg(transform, tf);
geometry_msgs::msg::TransformStamped transform_stamped;
transform_stamped.transform = tf2::toMsg(tf.inverse());
return transform_pose(pose, transform_stamped);
}
// Transform pose in world coordinates to local coordinates
geometry_msgs::msg::Pose inverse_transform_pose(
const geometry_msgs::msg::Pose & pose, const geometry_msgs::msg::Pose & transform_pose)
{
tf2::Transform transform;
tf2::convert(transform_pose, transform);
return inverse_transform_pose(pose, tf2::toMsg(transform));
}
// Transform point in world coordinates to local coordinates
Eigen::Vector3d inverse_transform_point(
const Eigen::Vector3d & point, const geometry_msgs::msg::Pose & pose)
{
const Eigen::Quaterniond q(
pose.orientation.w, pose.orientation.x, pose.orientation.y, pose.orientation.z);
const Eigen::Matrix3d R = q.normalized().toRotationMatrix();
const Eigen::Vector3d local_origin(pose.position.x, pose.position.y, pose.position.z);
Eigen::Vector3d local_point = R.transpose() * point - R.transpose() * local_origin;
return local_point;
}
// Transform point in world coordinates to local coordinates
geometry_msgs::msg::Point inverse_transform_point(
const geometry_msgs::msg::Point & point, const geometry_msgs::msg::Pose & pose)
{
const Eigen::Vector3d local_vec =
inverse_transform_point(Eigen::Vector3d(point.x, point.y, point.z), pose);
geometry_msgs::msg::Point local_point;
local_point.x = local_vec.x();
local_point.y = local_vec.y();
local_point.z = local_vec.z();
return local_point;
}
double calc_curvature(
const geometry_msgs::msg::Point & p1, const geometry_msgs::msg::Point & p2,
const geometry_msgs::msg::Point & p3)
{
// Calculation details are described in the following page
// https://en.wikipedia.org/wiki/Menger_curvature
const double denominator =
calc_distance2d(p1, p2) * calc_distance2d(p2, p3) * calc_distance2d(p3, p1);
if (std::fabs(denominator) < 1e-10) {
throw std::runtime_error("points are too close for curvature calculation.");
}
return 2.0 * ((p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x)) / denominator;
}
/**
* @brief Calculate offset pose. The offset values are defined in the local coordinate of the input
* pose.
*/
geometry_msgs::msg::Pose calc_offset_pose(
const geometry_msgs::msg::Pose & p, const double x, const double y, const double z,
const double yaw)
{
geometry_msgs::msg::Pose pose;
geometry_msgs::msg::Transform transform;
transform.translation = create_translation(x, y, z);
transform.rotation = create_quaternion_from_yaw(yaw);
tf2::Transform tf_pose;
tf2::Transform tf_offset;
tf2::fromMsg(transform, tf_offset);
tf2::fromMsg(p, tf_pose);
tf2::toMsg(tf_pose * tf_offset, pose);
return pose;
}
/**
* @brief Judge whether twist covariance is valid.
*
* @param twist_with_covariance source twist with covariance
* @return If all element of covariance is 0, return false.
*/
//
bool is_twist_covariance_valid(
const geometry_msgs::msg::TwistWithCovariance & twist_with_covariance)
{
for (const auto & c : twist_with_covariance.covariance) {
if (c != 0.0) {
return true;
}
}
return false;
}
// NOTE: much faster than boost::geometry::intersects()
std::optional<geometry_msgs::msg::Point> intersect(
const geometry_msgs::msg::Point & p1, const geometry_msgs::msg::Point & p2,
const geometry_msgs::msg::Point & p3, const geometry_msgs::msg::Point & p4)
{
// calculate intersection point
const double det = (p1.x - p2.x) * (p4.y - p3.y) - (p4.x - p3.x) * (p1.y - p2.y);
if (det == 0.0) {
return std::nullopt;
}
const double t = ((p4.y - p3.y) * (p4.x - p2.x) + (p3.x - p4.x) * (p4.y - p2.y)) / det;
const double s = ((p2.y - p1.y) * (p4.x - p2.x) + (p1.x - p2.x) * (p4.y - p2.y)) / det;
if (t < 0 || 1 < t || s < 0 || 1 < s) {
return std::nullopt;
}
geometry_msgs::msg::Point intersect_point;
intersect_point.x = t * p1.x + (1.0 - t) * p2.x;
intersect_point.y = t * p1.y + (1.0 - t) * p2.y;
intersect_point.z = t * p1.z + (1.0 - t) * p2.z;
return intersect_point;
}
bool intersects_convex(const Polygon2d & convex_polygon1, const Polygon2d & convex_polygon2)
{
return gjk::intersects(convex_polygon1, convex_polygon2);
}
} // namespace autoware_utils_geometry