Apollo  6.0
Open source self driving car software
polygon_scan_cvter.h
Go to the documentation of this file.
1 /******************************************************************************
2  * Copyright 2018 The Apollo Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *****************************************************************************/
16 #pragma once
17 
18 #include <algorithm>
19 #include <limits>
20 #include <utility>
21 #include <vector>
22 
23 #include "Eigen/Core"
24 #include "Eigen/StdVector"
25 
27 
28 namespace apollo {
29 namespace perception {
30 namespace lidar {
31 
32 template <typename T = double>
34  public:
35  typedef Eigen::Matrix<T, 2, 1> Point;
36  typedef std::vector<Point, Eigen::aligned_allocator<Point>> Polygon;
37  typedef std::pair<T, T> IntervalIn;
38  typedef std::pair<double, double> IntervalOut;
39  typedef std::pair<Point, Point> Segment;
40 
41  struct Edge {
42  bool operator<(const Edge& other) const { return y < other.y; }
43  bool MoveUp(double delta_x) {
44  if (delta_x < 0 || !std::isfinite(k)) {
45  return false;
46  }
47  x += delta_x;
48  if (x > max_x) {
49  return false;
50  }
51  y += (delta_x * k);
52  return true;
53  }
54  friend std::ostream& operator<<(std::ostream& out, const Edge& edge) {
55  out << boost::format(
56  "max_x: %13.10lf max_y: %13.10lf"
57  "min_x: %13.10lf min_y: %13.10lf"
58  "x: %13.10lf y: %13.10lf k %13.10lf") %
59  edge.max_x % edge.max_y % edge.min_x % edge.min_y % edge.x %
60  edge.y % edge.k;
61  return out;
62  }
63  // high x end point constant vars
64  double max_x = 0.0;
65  double max_y = 0.0;
66  // for test
67  double min_x = 0.0;
68  double min_y = 0.0;
69  // initial to low x y and move
70  double x = 0.0;
71  double y = 0.0;
72  double k = 0.0;
73  };
74 
75  enum DirectionMajor { XMAJOR = 0, YMAJOR = 1 };
76 
78  const DirectionMajor dir_major) {
79  return static_cast<DirectionMajor>(dir_major ^ 1);
80  }
81 
82  PolygonScanCvter() = default;
83  virtual ~PolygonScanCvter() = default;
84 
85  const Polygon& polygon() const { return polygon_; }
86  void Init(const Polygon& polygon);
87  void Reset();
88 
89  // get scan intervals
90  // HORIZONTAL = 0 for x, VERTICAL = 1 for y
91  void ScanCvt(const T& scan_loc, DirectionMajor dir_major,
92  std::vector<IntervalOut>* scan_intervals);
93  void ScansCvt(const IntervalIn& scans_interval,
94  const DirectionMajor dir_major, const T& step,
95  std::vector<std::vector<IntervalOut>>* scans_intervals);
96 
97  static const double s_epsilon_;
98  static const double s_inf_;
99 
100  private:
101  void DisturbPolygon(const DirectionMajor dir_major);
102  void ParsePolygon(const DirectionMajor dir_major, const bool disturb = false);
103  void BuildEt();
104  void UpdateAet(std::vector<IntervalOut>* scan_intervals);
105  // convert segment, x from continuous domain to discrete domain
106  bool ConvertSegment(const size_t seg_id, std::pair<int, Edge>* out_edge);
107 
108  Polygon polygon_;
109  Polygon polygon_disturbed_;
110  std::vector<std::vector<bool>> is_singular_; // 0 for x 1 for y
111  std::vector<std::vector<Segment>> segments_; // 0 for x 1 for y
112  // ensure the k = _s_inf edge to be filled
113  std::vector<std::vector<double>> ks_; // 0 for x 1 for y
114 
115  std::vector<std::pair<double, double>> top_segments_;
116 
117  // edge table
118  std::vector<std::vector<Edge>> et_;
119  // active edge table
120  std::pair<size_t, std::vector<Edge>> aet_;
121  double bottom_x_ = 0.0;
122  double step_ = 0.0;
123  size_t scans_size_ = 0;
124  DirectionMajor dir_major_ = DirectionMajor::XMAJOR;
125  DirectionMajor op_dir_major_ = DirectionMajor::YMAJOR;
126 };
127 
128 template <typename T>
129 const double PolygonScanCvter<T>::s_epsilon_ =
130  std::numeric_limits<float>::epsilon();
131 
132 template <typename T>
133 const double PolygonScanCvter<T>::s_inf_ = std::numeric_limits<T>::infinity();
134 
135 template <typename T>
137  Reset();
138  polygon_ = polygon;
139  is_singular_.resize(2);
140  segments_.resize(2);
141  ks_.resize(2);
142 }
143 
144 template <typename T>
146  polygon_ = Polygon();
147  is_singular_.clear();
148  segments_.clear();
149  ks_.clear();
150 }
151 
152 template <typename T>
153 void PolygonScanCvter<T>::ScanCvt(const T& scan_loc, DirectionMajor dir_major,
154  std::vector<IntervalOut>* scan_intervals) {
155  DirectionMajor op_dir_major = OppositeDirection(dir_major);
156  double x = scan_loc;
157  auto& is_singular = is_singular_[dir_major];
158  auto& segments = segments_[dir_major];
159  auto& ks = ks_[dir_major];
160  CHECK_EQ(segments.size(), polygon_.size());
161  CHECK_EQ(segments.size(), ks.size());
162  scan_intervals->clear();
163  scan_intervals->reserve(polygon_.size());
164  std::vector<double> nodes;
165  nodes.reserve(polygon_.size());
166  // for normal edge
167  for (size_t i = 0; i < segments.size(); ++i) {
168  const Segment& segment = segments[i];
169  const Point& low_vertex = segment.first;
170  const Point& high_vertex = segment.second;
171  double high_x = high_vertex[dir_major];
172  double high_y = high_vertex[op_dir_major];
173  double low_x = low_vertex[dir_major];
174  double low_y = low_vertex[op_dir_major];
175  double k = ks[i];
176  if (std::isfinite(k)) {
177  if ((x >= low_x && x < high_x) || (x <= low_x && x > high_x)) {
178  if (x == low_x) {
179  nodes.push_back(low_y);
180  if (is_singular[i]) {
181  nodes.push_back(low_y);
182  }
183  } else {
184  nodes.push_back(low_y + (x - low_x) * k);
185  }
186  }
187  } else {
188  if (std::abs(x - low_x) < s_epsilon_ ||
189  std::abs(x - high_x) < s_epsilon_) {
190  if (low_y < high_y) {
191  scan_intervals->push_back(IntervalOut(low_y, high_y));
192  } else {
193  scan_intervals->push_back(IntervalOut(high_y, low_y));
194  }
195  }
196  }
197  }
198  CHECK_EQ(nodes.size() % 2, static_cast<size_t>(0));
199  std::sort(nodes.begin(), nodes.end());
200  for (size_t i = 0; i < nodes.size(); i += 2) {
201  scan_intervals->push_back(IntervalOut(nodes[i], nodes[i + 1]));
202  }
203 }
204 
205 template <typename T>
207  const IntervalIn& scans_interval, const DirectionMajor dir_major,
208  const T& step, std::vector<std::vector<IntervalOut>>* scans_intervals) {
209  dir_major_ = dir_major;
210  op_dir_major_ = OppositeDirection(dir_major_);
211  CHECK_GT(step, 0.0);
212  step_ = step;
213  CHECK_GT(scans_interval.second, scans_interval.first + step);
214 
215  bottom_x_ = scans_interval.first;
216  double top_x = scans_interval.second;
217  scans_size_ = static_cast<size_t>((top_x - bottom_x_) / step_);
218 
219  top_segments_.clear();
220  top_segments_.reserve(2);
221 
222  ParsePolygon(dir_major, true);
223 
224  // allocate output data
225  scans_intervals->clear();
226  scans_intervals->resize(scans_size_);
227 
228  BuildEt();
229  // initialization aet
230  (*scans_intervals)[0].reserve(polygon_.size());
231  // add et to aet
232  for (const auto& edge : et_[0]) {
233  if (std::isfinite(edge.k)) {
234  aet_.second.push_back(edge);
235  } else {
236  (*scans_intervals)[0].push_back(IntervalOut(edge.y, edge.max_y));
237  }
238  }
239  // sort
240  std::sort(aet_.second.begin(), aet_.second.end());
241  CHECK_EQ(aet_.second.size() & 1, static_cast<size_t>(0));
242 
243  // add aet to result
244  for (size_t i = 0; i < aet_.second.size(); i += 2) {
245  double min_y = aet_.second[i].y;
246  double max_y = aet_.second[i + 1].y;
247  (*scans_intervals)[0].push_back(IntervalOut(min_y, max_y));
248  }
249  for (size_t i = 1; i < scans_size_; ++i) {
250  UpdateAet(&((*scans_intervals)[i]));
251  }
252 
253  if (top_segments_.size()) {
254  scans_intervals->resize(scans_size_ + 1);
255  for (auto& seg : top_segments_) {
256  double y1 = seg.first;
257  double y2 = seg.second;
258  double min_y = std::min(y1, y2);
259  double max_y = std::max(y1, y2);
260  (*scans_intervals)[scans_size_].push_back(IntervalOut(min_y, max_y));
261  }
262  }
263 }
264 
265 template <typename T>
267  for (auto& pt : polygon_disturbed_) {
268  T& x = pt[dir_major];
269  double d_x = (x - bottom_x_) / step_;
270  int int_d_x = static_cast<int>(std::round(d_x));
271  double delta_x = d_x - int_d_x;
272  if (std::abs(delta_x) < s_epsilon_) {
273  if (delta_x > 0) {
274  x = static_cast<T>((int_d_x + s_epsilon_) * step_ + bottom_x_);
275  } else {
276  x = static_cast<T>((int_d_x - s_epsilon_) * step_ + bottom_x_);
277  }
278  }
279  }
280 }
281 
282 template <typename T>
284  const bool disturb) {
285  polygon_disturbed_ = polygon_;
286  if (disturb) {
287  DisturbPolygon(dir_major);
288  }
289  DirectionMajor op_dir_major = OppositeDirection(dir_major);
290  size_t vertices_size = polygon_disturbed_.size();
291  is_singular_[dir_major].clear();
292  is_singular_[dir_major].reserve(vertices_size);
293  segments_[dir_major].clear();
294  segments_[dir_major].reserve(vertices_size);
295  ks_[dir_major].clear();
296  ks_[dir_major].reserve(vertices_size);
297 
298  auto& is_singular = is_singular_[dir_major];
299  auto& segments = segments_[dir_major];
300  auto& ks = ks_[dir_major];
301 
302  for (size_t i = 0; i < vertices_size; ++i) {
303  const Point& pre_vertex =
304  polygon_disturbed_[(i + vertices_size - 1) % vertices_size];
305  const Point& vertex = polygon_disturbed_[i];
306  const Point& nex_vertex = polygon_disturbed_[(i + 1) % vertices_size];
307  T pre_x = pre_vertex[dir_major];
308  T x = vertex[dir_major];
309  T y = vertex[op_dir_major];
310  T nex_x = nex_vertex[dir_major];
311  T nex_y = nex_vertex[op_dir_major];
312 
313  // get segment
314  Segment line_seg(vertex, nex_vertex);
315  double x_diff = nex_x - x;
316  double y_diff = nex_y - y;
317 
318  // get k
319  segments.push_back(line_seg);
320  std::abs(x_diff) < s_epsilon_ ? ks.push_back(s_inf_)
321  : ks.push_back(y_diff / x_diff);
322  double pre_x_diff = pre_x - x;
323 
324  // get singular property
325  // ensure fill edge
326  // case for zero
327  if (std::abs(x_diff) < s_epsilon_ || std::abs(pre_x_diff) < s_epsilon_) {
328  is_singular.push_back(true);
329  } else {
330  pre_x_diff* x_diff > 0 ? is_singular.push_back(true)
331  : is_singular.push_back(false);
332  }
333  }
334 }
335 
336 template <typename T>
338  const auto& segments = segments_[dir_major_];
339  // allocate memory
340  et_.clear();
341  et_.resize(scans_size_);
342  for (auto& edge_list : et_) {
343  edge_list.reserve(polygon_.size());
344  }
345 
346  // convert segments to edges
347  std::vector<std::pair<int, Edge>> edges;
348  edges.reserve(segments.size());
349  for (size_t i = 0; i < segments.size(); ++i) {
350  std::pair<int, Edge> out_edge;
351  if (ConvertSegment(i, &(out_edge))) {
352  edges.push_back(out_edge);
353  }
354  }
355 
356  // initial active edge table
357  aet_.first = 0;
358  aet_.second.clear();
359  aet_.second.reserve(segments.size());
360  for (size_t i = 0; i < edges.size(); ++i) {
361  int x_id = edges[i].first;
362  const Edge& edge = edges[i].second;
363  if (x_id >= static_cast<int>(scans_size_)) {
364  continue;
365  }
366  // add x_id == 0 to act
367  if (x_id >= 0) {
368  et_[x_id].push_back(edge);
369  } else {
370  // check if intersect at x_id = 0
371  Edge active_edge = edge;
372  if (active_edge.MoveUp(0.0 - active_edge.x)) {
373  aet_.second.push_back(active_edge);
374  }
375  }
376  }
377 }
378 
379 template <typename T>
380 void PolygonScanCvter<T>::UpdateAet(std::vector<IntervalOut>* scan_intervals) {
381  size_t x_id = aet_.first + 1;
382  CHECK_LT(x_id, et_.size());
383  aet_.first += 1;
384  scan_intervals->clear();
385  scan_intervals->reserve(polygon_.size());
386 
387  // check
388  size_t valid_edges_num = aet_.second.size();
389  size_t invalid_edges_num = 0;
390  for (auto& edge : aet_.second) {
391  if (!edge.MoveUp(step_)) {
392  --valid_edges_num;
393  ++invalid_edges_num;
394  edge.y = s_inf_;
395  }
396  }
397 
398  // add et to aet
399  size_t new_edges_num = 0;
400  for (const auto& edge : et_[x_id]) {
401  if (std::isfinite(edge.k)) {
402  ++valid_edges_num;
403  ++new_edges_num;
404  aet_.second.push_back(edge);
405  } else {
406  scan_intervals->push_back(IntervalOut(edge.y, edge.max_y));
407  }
408  }
409  CHECK_EQ(valid_edges_num & 1, static_cast<size_t>(0))
410  << boost::format(
411  "valid edges num: %d x: %lf bottom_x: %lf \n vertices num: %d "
412  "\n") %
413  valid_edges_num % (x_id * step_ + bottom_x_) % bottom_x_ %
414  polygon_.size()
415  << aet_.second[0] << "\n"
416  << aet_.second[1] << "\n"
417  << aet_.second[2] << "\n"
418  << aet_.second[3];
419 
420  // sort
421  if (invalid_edges_num != 0 || new_edges_num != 0) {
422  std::sort(aet_.second.begin(), aet_.second.end());
423  // remove invalid edges
424  aet_.second.resize(valid_edges_num);
425  }
426  for (size_t i = 0; i < aet_.second.size(); i += 2) {
427  // corner case, same point in the pre scan and complex polygon
428  double min_y = aet_.second[i].y;
429  double max_y = aet_.second[i + 1].y;
430  scan_intervals->push_back(IntervalOut(min_y, max_y));
431  }
432 }
433 
434 template <typename T>
435 bool PolygonScanCvter<T>::ConvertSegment(const size_t seg_id,
436  std::pair<int, Edge>* out_edge) {
437  const auto& segments = segments_[dir_major_];
438  const auto& ks = ks_[dir_major_];
439 
440  CHECK_LT(seg_id, segments.size());
441  Segment segment = segments[seg_id];
442  double k = ks[seg_id];
443  const Point& low_vertex = segment.first;
444  const Point& high_vertex = segment.second;
445  if (low_vertex[dir_major_] > high_vertex[dir_major_]) {
446  std::swap(segment.first, segment.second);
447  }
448  // return pair of int id and edge
449  Edge& edge = out_edge->second;
450  int& x_id = out_edge->first;
451  const Point& min_vertex = segment.first;
452  double min_x = min_vertex[dir_major_] - bottom_x_;
453  double min_y = min_vertex[op_dir_major_];
454  x_id = static_cast<int>(std::ceil(min_x / step_));
455  double min_x_ceil = x_id * step_;
456 
457  edge.x = min_x_ceil;
458  edge.min_x = edge.x;
459  edge.max_x = segment.second[dir_major_] - bottom_x_;
460  edge.max_y = segment.second[op_dir_major_];
461  edge.k = k;
462  // handle special edges
463  if (std::isfinite(edge.k)) {
464  edge.y = min_y + (edge.x - min_x) * edge.k;
465  } else {
466  edge.y = min_y;
467  // swap
468  if (edge.y > edge.max_y) {
469  std::swap(edge.y, edge.max_y);
470  }
471  }
472  edge.min_y = edge.y;
473 
474  // save top edge
475  if (static_cast<size_t>(x_id) >= scans_size_) {
476  std::pair<double, double> seg(low_vertex[op_dir_major_],
477  high_vertex[op_dir_major_]);
478  top_segments_.push_back(seg);
479  }
480  // check edge valid, for length < step
481  if (std::isfinite(edge.k) && edge.max_x < edge.x) {
482  return false;
483  }
484  return true;
485 }
486 
487 } // namespace lidar
488 } // namespace perception
489 } // namespace apollo
double y
Definition: polygon_scan_cvter.h:71
Definition: polygon_scan_cvter.h:75
PlanningContext is the runtime context in planning. It is persistent across multiple frames...
Definition: atomic_hash_map.h:25
double min_y
Definition: polygon_scan_cvter.h:68
const Polygon & polygon() const
Definition: polygon_scan_cvter.h:85
static const double s_epsilon_
Definition: polygon_scan_cvter.h:97
void Reset()
Definition: polygon_scan_cvter.h:145
Definition: segment_graph.h:47
T abs(const T &x)
Definition: misc.h:48
std::pair< Point, Point > Segment
Definition: polygon_scan_cvter.h:39
double max_y
Definition: polygon_scan_cvter.h:65
DirectionMajor
Definition: polygon_scan_cvter.h:75
double min_x
Definition: polygon_scan_cvter.h:67
static DirectionMajor OppositeDirection(const DirectionMajor dir_major)
Definition: polygon_scan_cvter.h:77
bool operator<(const Edge &other) const
Definition: polygon_scan_cvter.h:42
void ScansCvt(const IntervalIn &scans_interval, const DirectionMajor dir_major, const T &step, std::vector< std::vector< IntervalOut >> *scans_intervals)
Definition: polygon_scan_cvter.h:206
Definition: polygon_scan_cvter.h:33
static const double s_inf_
Definition: polygon_scan_cvter.h:98
double max_x
Definition: polygon_scan_cvter.h:64
double x
Definition: polygon_scan_cvter.h:70
std::vector< Point, Eigen::aligned_allocator< Point > > Polygon
Definition: polygon_scan_cvter.h:36
void ScanCvt(const T &scan_loc, DirectionMajor dir_major, std::vector< IntervalOut > *scan_intervals)
Definition: polygon_scan_cvter.h:153
std::pair< T, T > IntervalIn
Definition: polygon_scan_cvter.h:37
Definition: polygon_scan_cvter.h:75
std::pair< double, double > IntervalOut
Definition: polygon_scan_cvter.h:38
Eigen::Matrix< T, 2, 1 > Point
Definition: polygon_scan_cvter.h:35
void Init(const Polygon &polygon)
Definition: polygon_scan_cvter.h:136
double k
Definition: polygon_scan_cvter.h:72
Definition: polygon_scan_cvter.h:41
bool MoveUp(double delta_x)
Definition: polygon_scan_cvter.h:43
friend std::ostream & operator<<(std::ostream &out, const Edge &edge)
Definition: polygon_scan_cvter.h:54