Apollo 10.0
自动驾驶开放平台
polygon_scan_cvter.h
浏览该文件的文档.
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
17#pragma once
18
19#include <algorithm>
20#include <limits>
21#include <utility>
22#include <vector>
23
24#include "Eigen/Core"
25#include "Eigen/StdVector"
26
28
29namespace apollo {
30namespace perception {
31namespace lidar {
32
33template <typename T = double>
35 public:
36 typedef Eigen::Matrix<T, 2, 1> Point;
37 typedef std::vector<Point, Eigen::aligned_allocator<Point>> Polygon;
38 typedef std::pair<T, T> IntervalIn;
39 typedef std::pair<double, double> IntervalOut;
40 typedef std::pair<Point, Point> Segment;
41
42 struct Edge {
43 bool operator<(const Edge& other) const { return y < other.y; }
44 bool MoveUp(double delta_x) {
45 if (delta_x < 0 || !std::isfinite(k)) {
46 return false;
47 }
48 x += delta_x;
49 if (x > max_x) {
50 return false;
51 }
52 y += (delta_x * k);
53 return true;
54 }
55 friend std::ostream& operator<<(std::ostream& out, const Edge& edge) {
56 out << boost::format(
57 "max_x: %13.10lf max_y: %13.10lf"
58 "min_x: %13.10lf min_y: %13.10lf"
59 "x: %13.10lf y: %13.10lf k %13.10lf") %
60 edge.max_x % edge.max_y % edge.min_x % edge.min_y % edge.x %
61 edge.y % edge.k;
62 return out;
63 }
64 // high x end point constant vars
65 double max_x = 0.0;
66 double max_y = 0.0;
67 // for test
68 double min_x = 0.0;
69 double min_y = 0.0;
70 // initial to low x y and move
71 double x = 0.0;
72 double y = 0.0;
73 double k = 0.0;
74 };
75
76 enum DirectionMajor { XMAJOR = 0, YMAJOR = 1 };
77
79 const DirectionMajor dir_major) {
80 return static_cast<DirectionMajor>(dir_major ^ 1);
81 }
82
87 PolygonScanCvter() = default;
88
93 virtual ~PolygonScanCvter() = default;
94
100 const Polygon& polygon() const { return polygon_; }
101
107 void Init(const Polygon& polygon);
108
113 void Reset();
114
115 // HORIZONTAL = 0 for x, VERTICAL = 1 for y
123 void ScanCvt(const T& scan_loc, DirectionMajor dir_major,
124 std::vector<IntervalOut>* scan_intervals);
125
134 void ScansCvt(const IntervalIn& scans_interval,
135 const DirectionMajor dir_major, const T& step,
136 std::vector<std::vector<IntervalOut>>* scans_intervals);
137
138 static const double s_epsilon_;
139 static const double s_inf_;
140
141 private:
142 void DisturbPolygon(const DirectionMajor dir_major);
143 void ParsePolygon(const DirectionMajor dir_major, const bool disturb = false);
144 void BuildEt();
145 void UpdateAet(std::vector<IntervalOut>* scan_intervals);
146 // convert segment, x from continuous domain to discrete domain
147 bool ConvertSegment(const size_t seg_id, std::pair<int, Edge>* out_edge);
148
149 Polygon polygon_;
150 Polygon polygon_disturbed_;
151 std::vector<std::vector<bool>> is_singular_; // 0 for x 1 for y
152 std::vector<std::vector<Segment>> segments_; // 0 for x 1 for y
153 // ensure the k = _s_inf edge to be filled
154 std::vector<std::vector<double>> ks_; // 0 for x 1 for y
155
156 std::vector<std::pair<double, double>> top_segments_;
157
158 // edge table
159 std::vector<std::vector<Edge>> et_;
160 // active edge table
161 std::pair<size_t, std::vector<Edge>> aet_;
162 double bottom_x_ = 0.0;
163 double step_ = 0.0;
164 size_t scans_size_ = 0;
165 DirectionMajor dir_major_ = DirectionMajor::XMAJOR;
166 DirectionMajor op_dir_major_ = DirectionMajor::YMAJOR;
167};
168
169template <typename T>
171 std::numeric_limits<float>::epsilon();
172
173template <typename T>
174const double PolygonScanCvter<T>::s_inf_ = std::numeric_limits<T>::infinity();
175
176template <typename T>
177void PolygonScanCvter<T>::Init(const Polygon& polygon) {
178 Reset();
179 polygon_ = polygon;
180 is_singular_.resize(2);
181 segments_.resize(2);
182 ks_.resize(2);
183}
184
185template <typename T>
187 polygon_ = Polygon();
188 is_singular_.clear();
189 segments_.clear();
190 ks_.clear();
191}
192
193template <typename T>
194void PolygonScanCvter<T>::ScanCvt(const T& scan_loc, DirectionMajor dir_major,
195 std::vector<IntervalOut>* scan_intervals) {
196 DirectionMajor op_dir_major = OppositeDirection(dir_major);
197 double x = scan_loc;
198 auto& is_singular = is_singular_[dir_major];
199 auto& segments = segments_[dir_major];
200 auto& ks = ks_[dir_major];
201 CHECK_EQ(segments.size(), polygon_.size());
202 CHECK_EQ(segments.size(), ks.size());
203 scan_intervals->clear();
204 scan_intervals->reserve(polygon_.size());
205 std::vector<double> nodes;
206 nodes.reserve(polygon_.size());
207 // for normal edge
208 for (size_t i = 0; i < segments.size(); ++i) {
209 const Segment& segment = segments[i];
210 const Point& low_vertex = segment.first;
211 const Point& high_vertex = segment.second;
212 double high_x = high_vertex[dir_major];
213 double high_y = high_vertex[op_dir_major];
214 double low_x = low_vertex[dir_major];
215 double low_y = low_vertex[op_dir_major];
216 double k = ks[i];
217 if (std::isfinite(k)) {
218 if ((x >= low_x && x < high_x) || (x <= low_x && x > high_x)) {
219 if (std::fabs(x - low_x) < 1.0e-6) {
220 nodes.push_back(low_y);
221 if (is_singular[i]) {
222 nodes.push_back(low_y);
223 }
224 } else {
225 nodes.push_back(low_y + (x - low_x) * k);
226 }
227 }
228 } else {
229 if (std::abs(x - low_x) < s_epsilon_ ||
230 std::abs(x - high_x) < s_epsilon_) {
231 if (low_y < high_y) {
232 scan_intervals->push_back(IntervalOut(low_y, high_y));
233 } else {
234 scan_intervals->push_back(IntervalOut(high_y, low_y));
235 }
236 }
237 }
238 }
239 CHECK_EQ(nodes.size() % 2, static_cast<size_t>(0));
240 std::sort(nodes.begin(), nodes.end());
241 for (size_t i = 0; i < nodes.size(); i += 2) {
242 scan_intervals->push_back(IntervalOut(nodes[i], nodes[i + 1]));
243 }
244}
245
246template <typename T>
248 const IntervalIn& scans_interval, const DirectionMajor dir_major,
249 const T& step, std::vector<std::vector<IntervalOut>>* scans_intervals) {
250 dir_major_ = dir_major;
251 op_dir_major_ = OppositeDirection(dir_major_);
252 CHECK_GT(step, 0.0);
253 step_ = step;
254 CHECK_GT(scans_interval.second, scans_interval.first + step);
255
256 bottom_x_ = scans_interval.first;
257 double top_x = scans_interval.second;
258 scans_size_ = static_cast<size_t>((top_x - bottom_x_) / step_);
259
260 top_segments_.clear();
261 top_segments_.reserve(2);
262
263 ParsePolygon(dir_major, true);
264
265 // allocate output data
266 scans_intervals->clear();
267 scans_intervals->resize(scans_size_);
268
269 BuildEt();
270 // initialization aet
271 (*scans_intervals)[0].reserve(polygon_.size());
272 // add et to aet
273 for (const auto& edge : et_[0]) {
274 if (std::isfinite(edge.k)) {
275 aet_.second.push_back(edge);
276 } else {
277 (*scans_intervals)[0].push_back(IntervalOut(edge.y, edge.max_y));
278 }
279 }
280 // sort
281 std::sort(aet_.second.begin(), aet_.second.end());
282 CHECK_EQ(aet_.second.size() & 1, static_cast<size_t>(0));
283
284 // add aet to result
285 for (size_t i = 0; i < aet_.second.size(); i += 2) {
286 double min_y = aet_.second[i].y;
287 double max_y = aet_.second[i + 1].y;
288 (*scans_intervals)[0].push_back(IntervalOut(min_y, max_y));
289 }
290 for (size_t i = 1; i < scans_size_; ++i) {
291 UpdateAet(&((*scans_intervals)[i]));
292 }
293
294 if (top_segments_.size()) {
295 scans_intervals->resize(scans_size_ + 1);
296 for (auto& seg : top_segments_) {
297 double y1 = seg.first;
298 double y2 = seg.second;
299 double min_y = std::min(y1, y2);
300 double max_y = std::max(y1, y2);
301 (*scans_intervals)[scans_size_].push_back(IntervalOut(min_y, max_y));
302 }
303 }
304}
305
306template <typename T>
308 for (auto& pt : polygon_disturbed_) {
309 T& x = pt[dir_major];
310 double d_x = (x - bottom_x_) / step_;
311 int int_d_x = static_cast<int>(std::round(d_x));
312 double delta_x = d_x - int_d_x;
313 if (std::abs(delta_x) < s_epsilon_) {
314 if (delta_x > 0) {
315 x = static_cast<T>((int_d_x + s_epsilon_) * step_ + bottom_x_);
316 } else {
317 x = static_cast<T>((int_d_x - s_epsilon_) * step_ + bottom_x_);
318 }
319 }
320 }
321}
322
323template <typename T>
324void PolygonScanCvter<T>::ParsePolygon(const DirectionMajor dir_major,
325 const bool disturb) {
326 polygon_disturbed_ = polygon_;
327 if (disturb) {
328 DisturbPolygon(dir_major);
329 }
330 DirectionMajor op_dir_major = OppositeDirection(dir_major);
331 size_t vertices_size = polygon_disturbed_.size();
332 is_singular_[dir_major].clear();
333 is_singular_[dir_major].reserve(vertices_size);
334 segments_[dir_major].clear();
335 segments_[dir_major].reserve(vertices_size);
336 ks_[dir_major].clear();
337 ks_[dir_major].reserve(vertices_size);
338
339 auto& is_singular = is_singular_[dir_major];
340 auto& segments = segments_[dir_major];
341 auto& ks = ks_[dir_major];
342
343 for (size_t i = 0; i < vertices_size; ++i) {
344 const Point& pre_vertex =
345 polygon_disturbed_[(i + vertices_size - 1) % vertices_size];
346 const Point& vertex = polygon_disturbed_[i];
347 const Point& nex_vertex = polygon_disturbed_[(i + 1) % vertices_size];
348 T pre_x = pre_vertex[dir_major];
349 T x = vertex[dir_major];
350 T y = vertex[op_dir_major];
351 T nex_x = nex_vertex[dir_major];
352 T nex_y = nex_vertex[op_dir_major];
353
354 // get segment
355 Segment line_seg(vertex, nex_vertex);
356 double x_diff = nex_x - x;
357 double y_diff = nex_y - y;
358
359 // get k
360 segments.push_back(line_seg);
361 std::abs(x_diff) < s_epsilon_ ? ks.push_back(s_inf_)
362 : ks.push_back(y_diff / x_diff);
363 double pre_x_diff = pre_x - x;
364
365 // get singular property
366 // ensure fill edge
367 // case for zero
368 if (std::abs(x_diff) < s_epsilon_ || std::abs(pre_x_diff) < s_epsilon_) {
369 is_singular.push_back(true);
370 } else {
371 pre_x_diff* x_diff > 0 ? is_singular.push_back(true)
372 : is_singular.push_back(false);
373 }
374 }
375}
376
377template <typename T>
378void PolygonScanCvter<T>::BuildEt() {
379 const auto& segments = segments_[dir_major_];
380 // allocate memory
381 et_.clear();
382 et_.resize(scans_size_);
383 for (auto& edge_list : et_) {
384 edge_list.reserve(polygon_.size());
385 }
386
387 // convert segments to edges
388 std::vector<std::pair<int, Edge>> edges;
389 edges.reserve(segments.size());
390 for (size_t i = 0; i < segments.size(); ++i) {
391 std::pair<int, Edge> out_edge;
392 if (ConvertSegment(i, &(out_edge))) {
393 edges.push_back(out_edge);
394 }
395 }
396
397 // initial active edge table
398 aet_.first = 0;
399 aet_.second.clear();
400 aet_.second.reserve(segments.size());
401 for (size_t i = 0; i < edges.size(); ++i) {
402 int x_id = edges[i].first;
403 const Edge& edge = edges[i].second;
404 if (x_id >= static_cast<int>(scans_size_)) {
405 continue;
406 }
407 // add x_id == 0 to act
408 if (x_id >= 0) {
409 et_[x_id].push_back(edge);
410 } else {
411 // check if intersect at x_id = 0
412 Edge active_edge = edge;
413 if (active_edge.MoveUp(0.0 - active_edge.x)) {
414 aet_.second.push_back(active_edge);
415 }
416 }
417 }
418}
419
420template <typename T>
421void PolygonScanCvter<T>::UpdateAet(std::vector<IntervalOut>* scan_intervals) {
422 size_t x_id = aet_.first + 1;
423 CHECK_LT(x_id, et_.size());
424 aet_.first += 1;
425 scan_intervals->clear();
426 scan_intervals->reserve(polygon_.size());
427
428 // check
429 size_t valid_edges_num = aet_.second.size();
430 size_t invalid_edges_num = 0;
431 for (auto& edge : aet_.second) {
432 if (!edge.MoveUp(step_)) {
433 --valid_edges_num;
434 ++invalid_edges_num;
435 edge.y = s_inf_;
436 }
437 }
438
439 // add et to aet
440 size_t new_edges_num = 0;
441 for (const auto& edge : et_[x_id]) {
442 if (std::isfinite(edge.k)) {
443 ++valid_edges_num;
444 ++new_edges_num;
445 aet_.second.push_back(edge);
446 } else {
447 scan_intervals->push_back(IntervalOut(edge.y, edge.max_y));
448 }
449 }
450 CHECK_EQ(valid_edges_num & 1, static_cast<size_t>(0))
451 << boost::format(
452 "valid edges num: %d x: %lf bottom_x: %lf \n vertices num: %d "
453 "\n") %
454 valid_edges_num % (x_id * step_ + bottom_x_) % bottom_x_ %
455 polygon_.size()
456 << aet_.second[0] << "\n"
457 << aet_.second[1] << "\n"
458 << aet_.second[2] << "\n"
459 << aet_.second[3];
460
461 // sort
462 if (invalid_edges_num != 0 || new_edges_num != 0) {
463 std::sort(aet_.second.begin(), aet_.second.end());
464 // remove invalid edges
465 aet_.second.resize(valid_edges_num);
466 }
467 for (size_t i = 0; i < aet_.second.size(); i += 2) {
468 // corner case, same point in the pre scan and complex polygon
469 double min_y = aet_.second[i].y;
470 double max_y = aet_.second[i + 1].y;
471 scan_intervals->push_back(IntervalOut(min_y, max_y));
472 }
473}
474
475template <typename T>
476bool PolygonScanCvter<T>::ConvertSegment(const size_t seg_id,
477 std::pair<int, Edge>* out_edge) {
478 const auto& segments = segments_[dir_major_];
479 const auto& ks = ks_[dir_major_];
480
481 CHECK_LT(seg_id, segments.size());
482 Segment segment = segments[seg_id];
483 double k = ks[seg_id];
484 const Point& low_vertex = segment.first;
485 const Point& high_vertex = segment.second;
486 if (low_vertex[dir_major_] > high_vertex[dir_major_]) {
487 std::swap(segment.first, segment.second);
488 }
489 // return pair of int id and edge
490 Edge& edge = out_edge->second;
491 int& x_id = out_edge->first;
492 const Point& min_vertex = segment.first;
493 double min_x = min_vertex[dir_major_] - bottom_x_;
494 double min_y = min_vertex[op_dir_major_];
495 x_id = static_cast<int>(std::ceil(min_x / step_));
496 double min_x_ceil = x_id * step_;
497
498 edge.x = min_x_ceil;
499 edge.min_x = edge.x;
500 edge.max_x = segment.second[dir_major_] - bottom_x_;
501 edge.max_y = segment.second[op_dir_major_];
502 edge.k = k;
503 // handle special edges
504 if (std::isfinite(edge.k)) {
505 edge.y = min_y + (edge.x - min_x) * edge.k;
506 } else {
507 edge.y = min_y;
508 // swap
509 if (edge.y > edge.max_y) {
510 std::swap(edge.y, edge.max_y);
511 }
512 }
513 edge.min_y = edge.y;
514
515 // save top edge
516 if (static_cast<size_t>(x_id) >= scans_size_) {
517 std::pair<double, double> seg(low_vertex[op_dir_major_],
518 high_vertex[op_dir_major_]);
519 top_segments_.push_back(seg);
520 }
521 // check edge valid, for length < step
522 if (std::isfinite(edge.k) && edge.max_x < edge.x) {
523 return false;
524 }
525 return true;
526}
527
528} // namespace lidar
529} // namespace perception
530} // namespace apollo
void Init(const Polygon &polygon)
Init of Polygon Scan Cvter object
void ScanCvt(const T &scan_loc, DirectionMajor dir_major, std::vector< IntervalOut > *scan_intervals)
Get scan intervals
PolygonScanCvter()=default
Construct a new Polygon Scan Cvter object
const Polygon & polygon() const
Return the polygon_
void ScansCvt(const IntervalIn &scans_interval, const DirectionMajor dir_major, const T &step, std::vector< std::vector< IntervalOut > > *scans_intervals)
Get scan intervals
void Reset()
Reset the Polygon Scan Cvter object
std::vector< Point, Eigen::aligned_allocator< Point > > Polygon
virtual ~PolygonScanCvter()=default
Destroy the Polygon Scan Cvter object
static DirectionMajor OppositeDirection(const DirectionMajor dir_major)
typename PolygonScanCvter< T >::Polygon Polygon
Bitmap2D::DirectionMajor DirectionMajor
apollo::common::Point3D Point
class register implement
Definition arena_queue.h:37
friend std::ostream & operator<<(std::ostream &out, const Edge &edge)