Autoware.Auto
geometry.hpp
Go to the documentation of this file.
1 // Copyright 2020 Embotech AG, Zurich, Switzerland. All rights reserved.
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 // This file defines 2D points, halfplanes and polyhedra as templates. The templates
16 // work both for concrete numerical types such as float and double as well as for
17 // "symbol" types such as CasADi variables. The advantage of this is that they can
18 // be used both when formulating constraints for an optimization problem as well
19 // as for numerical evaluation outside of such formulations.
20 
21 #ifndef PARKING_PLANNER__GEOMETRY_HPP_
22 #define PARKING_PLANNER__GEOMETRY_HPP_
23 
24 #include <vector>
25 #include <array>
26 #include <cmath>
27 #include <limits>
28 #include <utility>
29 
30 namespace autoware
31 {
32 
33 namespace motion
34 {
35 
36 namespace planning
37 {
38 
39 namespace parking_planner
40 {
41 
42 // -- Point2D -----------------------------------------------------------------
44 template<typename T>
45 class Point2D
46 {
47 public:
49  Point2D() noexcept
50  {
51  this->m_coord = std::pair<T, T>(T{}, T{});
52  }
53 
55  Point2D(T x, T y) noexcept
56  {
57  this->m_coord = std::pair<T, T>(x, y);
58  }
59 
61  bool operator==(const Point2D<T> & other) const noexcept
62  {
63  return this->m_coord == other.m_coord;
64  }
65 
67  Point2D<T> operator+(const Point2D<T> & other) const noexcept
68  {
69  return Point2D<T>(
70  this->m_coord.first + other.m_coord.first,
71  this->m_coord.second + other.m_coord.second);
72  }
73 
75  Point2D<T> operator-(const Point2D<T> & other) const noexcept
76  {
77  return Point2D<T>(
78  this->m_coord.first - other.m_coord.first,
79  this->m_coord.second - other.m_coord.second);
80  }
81 
83  Point2D<T> operator/(const T dividend) const
84  {
85  if (dividend == T{}) {
86  throw std::domain_error{"Divide by zero encountered"};
87  }
88 
89  return Point2D<T>(
90  this->m_coord.first / dividend,
91  this->m_coord.second / dividend);
92  }
93 
95  Point2D<T> operator*(const T multiplier) const noexcept
96  {
97  return Point2D<T>(
98  this->m_coord.first * multiplier,
99  this->m_coord.second * multiplier);
100  }
101 
103  T norm2() const noexcept
104  {
105  return sqrt(this->dot(*this));
106  }
107 
109  T dot(const Point2D<T> & other) const noexcept
110  {
111  return this->m_coord.first * other.m_coord.first +
112  this->m_coord.second * other.m_coord.second;
113  }
114 
116  void rotate(const T angle) noexcept
117  {
118  T cos_angle = cos(angle);
119  T sin_angle = sin(angle);
120  T x = this->m_coord.first;
121  T y = this->m_coord.second;
122  this->m_coord.first = x * cos_angle - y * sin_angle;
123  this->m_coord.second = x * sin_angle + y * cos_angle;
124  }
125 
127  const std::pair<T, T> & get_coord() const noexcept
128  {
129  return this->m_coord;
130  }
131 
132 private:
134  bool operator<=(const Point2D<T> & other) const noexcept
135  {
136  return this->m_coord <= other.m_coord;
137  }
138 
140  bool operator<(const Point2D<T> & other) const noexcept
141  {
142  return this->m_coord <= other.m_coord;
143  }
144 
146  bool operator>=(const Point2D<T> & other) const noexcept
147  {
148  return this->m_coord <= other.m_coord;
149  }
150 
152  bool operator>(const Point2D<T> & other) const noexcept
153  {
154  return this->m_coord <= other.m_coord;
155  }
156 
157  std::pair<T, T> m_coord;
158 };
159 
160 // -- Halfplane2D -------------------------------------------------------------
162 template<typename T>
164 {
165 public:
166  Halfplane2D(const Point2D<T> & coefficients, T right_hand_side)
167  {
168  this->m_coefficients = coefficients;
169  this->m_right_hand_side = right_hand_side;
170  this->normalize();
171  }
172 
174  template<typename S = T, std::enable_if_t<std::is_arithmetic<S>::value, int> = 0>
175  bool contains_point(const Point2D<T> & point) const noexcept
176  {
177  return this->m_coefficients.dot(point) <= this->m_right_hand_side;
178  }
179 
181  const Point2D<T> & get_coefficients() const noexcept
182  {
183  return this->m_coefficients;
184  }
185 
187  const T & get_right_hand_side() const noexcept
188  {
189  return this->m_right_hand_side;
190  }
191 
193  std::vector<T> serialize() const
194  {
195  std::vector<T> serialized{};
196  serialized.reserve(internal_scalars_number);
197  const auto & coordinates = m_coefficients.get_coord();
198  serialized.push_back(coordinates.first);
199  serialized.push_back(coordinates.second);
200  serialized.push_back(m_right_hand_side);
201  return serialized;
202  }
203 
205  static constexpr std::size_t get_serialized_length() noexcept
206  {
207  return internal_scalars_number;
208  }
209 
210 private:
212  static constexpr std::size_t internal_scalars_number = 3;
213 
214  Point2D<T> m_coefficients;
215  T m_right_hand_side;
216 
217  // \brief This template may be used for concrete number types as well as for symbolic
218  // variable objects. In the case of symbolic variable objects, normalization
219  // is not desired, and the norm check makes no sense anyway. The enable_if_t
220  // feature gating here turns the normalization on only if there is a concrete
221  // numeric type. If not, then the variant below that does nothing is used.
222  template<typename S = T, std::enable_if_t<std::is_arithmetic<S>::value, int> = 0>
223  void normalize()
224  {
225  S two_norm = this->m_coefficients.norm2();
226  if (two_norm < std::numeric_limits<S>::epsilon()) {
227  throw std::domain_error{"Divide by zero encountered"};
228  }
229  this->m_coefficients = this->m_coefficients / two_norm;
230  this->m_right_hand_side = this->m_right_hand_side / two_norm;
231  }
232 
233  // This case is used for symbolic template parameters T
234  template<typename S = T, std::enable_if_t<!std::is_arithmetic<S>::value, int> = 0>
235  void normalize() noexcept
236  {
237  }
238 };
239 
240 
241 // -- Polytope2D --------------------------------------------------------------
243 template<typename T>
245 {
246 public:
250  explicit Polytope2D(const std::vector<Point2D<T>> & vertices) noexcept
251  {
252  this->m_vertices = vertices;
253  this->update_halfplanes_from_vertices();
254  }
255 
258  const T rotation_angle,
259  const Point2D<T> & rotation_center,
260  const Point2D<T> & shift_vector)
261  {
262  for (auto & v : this->m_vertices) {
263  v = v - rotation_center;
264  v.rotate(rotation_angle);
265  v = v + rotation_center;
266  v = v + shift_vector;
267  }
268  this->update_halfplanes_from_vertices();
269  }
270 
272  bool contains_point(const Point2D<T> & point) const noexcept
273  {
274  for (const auto & halfplane : this->m_halfplanes) {
275  if (!halfplane.contains_point(point)) {
276  return false;
277  }
278  }
279  return true;
280  }
281 
283  bool intersects_with(const Polytope2D<T> & other) const noexcept
284  {
285  for (const auto & halfplane : other.m_halfplanes) {
286  bool contains_any_point = false;
287  for (const auto & vertex : this->m_vertices) {
288  if (halfplane.contains_point(vertex)) {
289  contains_any_point = true;
290  }
291  }
292  if (!contains_any_point) {
293  return false;
294  }
295  }
296 
297  for (const auto & halfplane : this->m_halfplanes) {
298  bool contains_any_point = false;
299  for (const auto & vertex : other.m_vertices) {
300  if (halfplane.contains_point(vertex)) {
301  contains_any_point = true;
302  }
303  }
304  if (!contains_any_point) {
305  return false;
306  }
307  }
308 
309  return true;
310  }
311 
313  const std::vector<Halfplane2D<T>> & get_halfplanes() const noexcept
314  {
315  return this->m_halfplanes;
316  }
317 
319  const std::vector<Point2D<T>> & get_vertices() const noexcept
320  {
321  return this->m_vertices;
322  }
323 
324 private:
325  void update_vertices_from_halfplanes() noexcept
326  {
327  this->m_vertices.clear();
328  const auto it_begin = this->m_halfplanes.begin();
329  const auto it_end = this->m_halfplanes.end();
330  auto it_last = it_end;
331  for (auto it_current = it_begin; it_current != it_end; ++it_current) {
332  const Point2D<T> & coeff_last = it_last->get_coefficients();
333  const T & rhs_last = it_last->get_right_hand_side();
334  const Point2D<T> & coeff_current = it_current->get_coefficients();
335  const T & rhs_current = it_current->get_right_hand_side();
336  T x = coeff_current.get_coord().second * rhs_last -
337  coeff_last.get_coord().second * rhs_current;
338  T y = -coeff_last.get_coord().first * rhs_last +
339  coeff_current.get_coord().first * rhs_current;
340  this->m_vertices.push_back(Point2D<T>(x, y));
341  it_last = it_current;
342  }
343  }
344 
345  void update_halfplanes_from_vertices() noexcept
346  {
347  this->m_halfplanes.clear();
348  const auto it_begin = this->m_vertices.begin();
349  auto it_last = it_begin;
350  const auto it_end = this->m_vertices.end();
351  if (it_begin != it_end) {
352  for (auto it = it_begin + 1; it != it_end; ++it) {
353  const Point2D<T> & vertex_last = *it_last;
354  const Point2D<T> & vertex_current = *it;
355  Point2D<T> diff_vector = vertex_current - vertex_last;
356  Point2D<T> norm_vector = Point2D<T>(
357  diff_vector.get_coord().second,
358  -diff_vector.get_coord().first);
359  this->m_halfplanes.push_back(Halfplane2D<T>(norm_vector, norm_vector.dot(vertex_current)));
360  it_last = it;
361  }
362  const Point2D<T> & vertex_last = *it_last;
363  const Point2D<T> & vertex_current = *it_begin;
364  Point2D<T> diff_vector = vertex_current - vertex_last;
365  Point2D<T> norm_vector = Point2D<T>(
366  diff_vector.get_coord().second,
367  -diff_vector.get_coord().first);
368  this->m_halfplanes.push_back(Halfplane2D<T>(norm_vector, norm_vector.dot(vertex_current)));
369  }
370  }
371 
372  // These representations should be kept consistent, i.e. whenever one is
373  // set the other needs to be updated. This is done by all the methods at
374  // this point, but should further methods be added, they also need to take
375  // care of this. The two helper methods above can be used for this.
376 
378  std::vector<Point2D<T>> m_vertices;
379 
381  std::vector<Halfplane2D<T>> m_halfplanes;
382 };
383 
384 
385 } // namespace parking_planner
386 } // namespace planning
387 } // namespace motion
388 } // namespace autoware
389 
390 #endif // PARKING_PLANNER__GEOMETRY_HPP_
autoware::motion::planning::parking_planner::Point2D::operator/
Point2D< T > operator/(const T dividend) const
Divide by a constant.
Definition: geometry.hpp:83
autoware::motion::planning::parking_planner::Point2D::operator+
Point2D< T > operator+(const Point2D< T > &other) const noexcept
Add two points.
Definition: geometry.hpp:67
autoware::motion::planning::parking_planner::Point2D
Class describing a point in two-dimensional space.
Definition: geometry.hpp:45
autoware::motion::planning::parking_planner::Point2D::rotate
void rotate(const T angle) noexcept
Rotate around the origin.
Definition: geometry.hpp:116
autoware::motion::planning::parking_planner::Halfplane2D
Class describing a halfplane in two-dimensional space.
Definition: geometry.hpp:163
autoware::motion::planning::parking_planner::Polytope2D::Polytope2D
Polytope2D(const std::vector< Point2D< T >> &vertices) noexcept
Construct a polyhedron.
Definition: geometry.hpp:250
catr_diff.T
T
Definition: catr_diff.py:22
autoware::motion::planning::parking_planner::Halfplane2D::get_serialized_length
static constexpr std::size_t get_serialized_length() noexcept
Query how many scalars are involved in serializing this halfplane.
Definition: geometry.hpp:205
autoware::motion::planning::parking_planner::Point2D::get_coord
const std::pair< T, T > & get_coord() const noexcept
Get the coordinates.
Definition: geometry.hpp:127
autoware::motion::planning::parking_planner::Point2D::norm2
T norm2() const noexcept
Compute the 2-norm of a point (as in, the distance to the origin)
Definition: geometry.hpp:103
y
DifferentialState y
Definition: kinematic_bicycle.snippet.hpp:28
autoware::motion::planning::parking_planner::Point2D::Point2D
Point2D(T x, T y) noexcept
Scalar type Constructor.
Definition: geometry.hpp:55
autoware::motion::planning::parking_planner::Polytope2D::get_vertices
const std::vector< Point2D< T > > & get_vertices() const noexcept
Getter for vertices.
Definition: geometry.hpp:319
autoware::motion::planning::parking_planner::Point2D::Point2D
Point2D() noexcept
No-argument constructor.
Definition: geometry.hpp:49
autoware::motion::planning::parking_planner::Polytope2D
Class describing a polytope in two-dimensional space.
Definition: geometry.hpp:244
autoware::motion::planning::parking_planner::Point2D::operator==
bool operator==(const Point2D< T > &other) const noexcept
Check for equality of two points.
Definition: geometry.hpp:61
autoware
This file defines the lanelet2_map_provider_node class.
Definition: quick_sort.hpp:24
autoware::motion::planning::parking_planner::Point2D::operator*
Point2D< T > operator*(const T multiplier) const noexcept
Multiply by something.
Definition: geometry.hpp:95
autoware::motion::planning::parking_planner::Polytope2D::get_halfplanes
const std::vector< Halfplane2D< T > > & get_halfplanes() const noexcept
Getter for halfplanes.
Definition: geometry.hpp:313
autoware::motion::planning::parking_planner::Halfplane2D::get_right_hand_side
const T & get_right_hand_side() const noexcept
Get the right-hand side constant of the halfplane equation.
Definition: geometry.hpp:187
x
DifferentialState x
Definition: kinematic_bicycle.snippet.hpp:28
autoware::motion::planning::parking_planner::Halfplane2D::contains_point
bool contains_point(const Point2D< T > &point) const noexcept
Check if a given point is in the halfplane or not.
Definition: geometry.hpp:175
autoware::motion::planning::parking_planner::Point2D::dot
T dot(const Point2D< T > &other) const noexcept
Perform inner-product.
Definition: geometry.hpp:109
motion
Definition: controller_base.hpp:30
autoware::motion::planning::parking_planner::Polytope2D::contains_point
bool contains_point(const Point2D< T > &point) const noexcept
Check if polytope contains a point.
Definition: geometry.hpp:272
autoware::motion::planning::parking_planner::Halfplane2D::Halfplane2D
Halfplane2D(const Point2D< T > &coefficients, T right_hand_side)
Definition: geometry.hpp:166
autoware::motion::planning::parking_planner::Point2D::operator-
Point2D< T > operator-(const Point2D< T > &other) const noexcept
Subtract one point from the other.
Definition: geometry.hpp:75
autoware::motion::planning::parking_planner::Halfplane2D::get_coefficients
const Point2D< T > & get_coefficients() const noexcept
Get the coefficients of the left-hand side of the halfplane equation.
Definition: geometry.hpp:181
autoware::motion::planning::parking_planner::Polytope2D::rotate_and_shift
void rotate_and_shift(const T rotation_angle, const Point2D< T > &rotation_center, const Point2D< T > &shift_vector)
Rotate and shift the polytope.
Definition: geometry.hpp:257
v
DifferentialState v
Definition: linear_tire.snippet.hpp:28
autoware::motion::planning::parking_planner::Halfplane2D::serialize
std::vector< T > serialize() const
Turn this halfplane into a vector of scalars.
Definition: geometry.hpp:193
autoware::motion::planning::parking_planner::Polytope2D::intersects_with
bool intersects_with(const Polytope2D< T > &other) const noexcept
Check if polytope intersects with another.
Definition: geometry.hpp:283