forked from autowarefoundation/autoware_utils
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsat_2d.cpp
82 lines (73 loc) · 2.82 KB
/
sat_2d.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
// Copyright 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/sat_2d.hpp"
#include <utility>
namespace autoware_utils_geometry::sat
{
namespace
{
/// @brief calculate the edge normal of two points
Point2d edge_normal(const Point2d & p1, const Point2d & p2)
{
return {p2.y() - p1.y(), p1.x() - p2.x()};
}
/// @brief project a polygon onto an axis and return the minimum and maximum values
std::pair<double, double> project_polygon(const Polygon2d & poly, const Point2d & axis)
{
double min = poly.outer()[0].dot(axis);
double max = min;
for (const auto & point : poly.outer()) {
double projection = point.dot(axis);
if (projection < min) {
min = projection;
}
if (projection > max) {
max = projection;
}
}
return {min, max};
}
/// @brief check if two projections overlap
bool projections_overlap(
const std::pair<double, double> & proj1, const std::pair<double, double> & proj2)
{
return proj1.second >= proj2.first && proj2.second >= proj1.first;
}
/// @brief check is all edges of a polygon can be separated from the other polygon with a separating
/// axis
bool has_no_separating_axis(const Polygon2d & polygon, const Polygon2d & other)
{
for (size_t i = 0; i < polygon.outer().size(); ++i) {
const size_t next_i = (i + 1) % polygon.outer().size();
const Point2d edge = edge_normal(polygon.outer()[i], polygon.outer()[next_i]);
const auto projection1 = project_polygon(polygon, edge);
const auto projection2 = project_polygon(other, edge);
if (!projections_overlap(projection1, projection2)) {
return false;
}
}
return true;
}
} // namespace
/// @brief check if two convex polygons intersect using the SAT algorithm
/// @details this function uses the Separating Axis Theorem (SAT) to determine if two convex
/// polygons intersect. If projections overlap on all tested axes, the function returns `true`;
/// otherwise, it returns `false`. Note that touching polygons (e.g., at a point or along an edge)
/// will be considered as not intersecting.
bool intersects(const Polygon2d & convex_polygon1, const Polygon2d & convex_polygon2)
{
return has_no_separating_axis(convex_polygon1, convex_polygon2) &&
has_no_separating_axis(convex_polygon2, convex_polygon1);
}
} // namespace autoware_utils_geometry::sat