Apollo 11.0
自动驾驶开放平台
convex_hull_2d.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#pragma once
17
18#include <algorithm>
19#include <limits>
20#include <numeric>
21#include <vector>
22
23#include "Eigen/Dense"
24
26
27namespace apollo {
28namespace perception {
29namespace algorithm {
30
31template <class CLOUD_IN_TYPE, class CLOUD_OUT_TYPE>
33 public:
34 template <class EigenType>
36
37 public:
38 ConvexHull2D() : in_cloud_(nullptr) {
39 points_.reserve(1000.0);
40 polygon_indices_.reserve(1000.0);
41 }
42 ~ConvexHull2D() { in_cloud_ = nullptr; }
43 // main interface to get polygon from input point cloud
44 bool GetConvexHull(const CLOUD_IN_TYPE& in_cloud,
45 CLOUD_OUT_TYPE* out_polygon) {
46 SetPoints(in_cloud);
47 if (!GetConvexHullMonotoneChain(out_polygon)) {
48 return MockConvexHull(out_polygon);
49 }
50 return true;
51 }
52 // main interface to get polygon from input point cloud(without ground points)
53 bool GetConvexHullWithoutGround(const CLOUD_IN_TYPE& in_cloud,
54 const float& distance_above_ground_thres,
55 CLOUD_OUT_TYPE* out_polygon) {
56 CLOUD_IN_TYPE in_cloud_without_ground;
57 in_cloud_without_ground.reserve(in_cloud.size());
58 for (std::size_t id = 0; id < in_cloud.size(); ++id) {
59 // compute point_heigh, note std::numeric_limits<float>::max() is the
60 // default value
61 if (in_cloud.points_height(id) >= distance_above_ground_thres) {
62 in_cloud_without_ground.push_back(in_cloud[id]);
63 }
64 }
65 if (in_cloud_without_ground.empty()) {
66 return GetConvexHull(in_cloud, out_polygon);
67 } else {
68 SetPoints(in_cloud_without_ground);
69 if (!GetConvexHullMonotoneChain(out_polygon)) {
70 return MockConvexHull(out_polygon);
71 }
72 }
73 return true;
74 }
75 // main interface to get polygon from input point cloud
76 // (without ground points and points above the head of self-driving car)
78 const CLOUD_IN_TYPE& in_cloud, const float& distance_above_ground_thres,
79 const float& distance_beneath_head_thres, CLOUD_OUT_TYPE* out_polygon) {
80 CLOUD_IN_TYPE in_cloud_without_ground_and_head;
81 in_cloud_without_ground_and_head.reserve(in_cloud.size());
82 for (std::size_t id = 0; id < in_cloud.size(); ++id) {
83 // compute point_heigh, note std::numeric_limits<float>::max() is the
84 // default value
85 if (in_cloud.points_height(id) == std::numeric_limits<float>::max() ||
86 (in_cloud.points_height(id) >= distance_above_ground_thres &&
87 in_cloud.points_height(id) <= distance_beneath_head_thres)) {
88 in_cloud_without_ground_and_head.push_back(in_cloud[id]);
89 }
90 }
91 if (in_cloud_without_ground_and_head.empty()) {
92 return GetConvexHull(in_cloud, out_polygon);
93 } else {
94 SetPoints(in_cloud_without_ground_and_head);
95 if (!GetConvexHullMonotoneChain(out_polygon)) {
96 return MockConvexHull(out_polygon);
97 }
98 }
99 return true;
100 }
101
102 private:
103 // save points in local memory, and transform to double
104 void SetPoints(const CLOUD_IN_TYPE& in_cloud);
105 // mock a polygon for some degenerate cases
106 bool MockConvexHull(CLOUD_OUT_TYPE* out_polygon);
107 // compute convex hull using Andrew's monotone chain algorithm
108 bool GetConvexHullMonotoneChain(CLOUD_OUT_TYPE* out_polygon);
109 // given 3 ordered points, return true if in counter clock wise.
110 bool IsCounterClockWise(const Eigen::Vector2d& p1, const Eigen::Vector2d& p2,
111 const Eigen::Vector2d& p3, const double& eps) {
112 Eigen::Vector2d p12 = p2 - p1;
113 Eigen::Vector2d p13 = p3 - p1;
114 return (p12(0) * p13(1) - p12(1) * p13(0) > eps);
115 }
116
117 private:
118 EigenVector<Eigen::Vector2d> points_;
119 std::vector<std::size_t> polygon_indices_;
120 const CLOUD_IN_TYPE* in_cloud_;
121};
122
123template <class CLOUD_IN_TYPE, class CLOUD_OUT_TYPE>
124void ConvexHull2D<CLOUD_IN_TYPE, CLOUD_OUT_TYPE>::SetPoints(
125 const CLOUD_IN_TYPE& in_cloud) {
126 points_.resize(in_cloud.size());
127 for (std::size_t i = 0; i < points_.size(); ++i) {
128 points_[i] << in_cloud[i].x, in_cloud[i].y;
129 }
130 in_cloud_ = &in_cloud;
131}
132
133template <class CLOUD_IN_TYPE, class CLOUD_OUT_TYPE>
134bool ConvexHull2D<CLOUD_IN_TYPE, CLOUD_OUT_TYPE>::MockConvexHull(
135 CLOUD_OUT_TYPE* out_polygon) {
136 if (in_cloud_->size() == 0) {
137 return false;
138 }
139 out_polygon->resize(4);
140 Eigen::Matrix<double, 3, 1> maxv;
141 Eigen::Matrix<double, 3, 1> minv;
142 maxv << in_cloud_->at(0).x, in_cloud_->at(0).y, in_cloud_->at(0).z;
143 minv = maxv;
144 for (std::size_t i = 1; i < in_cloud_->size(); ++i) {
145 maxv(0) = std::max<double>(maxv(0), in_cloud_->at(i).x);
146 maxv(1) = std::max<double>(maxv(1), in_cloud_->at(i).y);
147 maxv(2) = std::max<double>(maxv(2), in_cloud_->at(i).z);
148
149 minv(0) = std::min<double>(minv(0), in_cloud_->at(i).x);
150 minv(1) = std::min<double>(minv(1), in_cloud_->at(i).y);
151 minv(2) = std::min<double>(minv(2), in_cloud_->at(i).z);
152 }
153
154 static const double eps = 1e-3;
155 for (std::size_t i = 0; i < 3; ++i) {
156 if (maxv(i) - minv(i) < eps) {
157 maxv(i) += eps;
158 minv(i) -= eps;
159 }
160 }
161
162 // double NOT NECESSARY to static_cast float
163 out_polygon->at(0).x = minv(0);
164 out_polygon->at(0).y = minv(1);
165 out_polygon->at(0).z = minv(2);
166
167 out_polygon->at(1).x = maxv(0);
168 out_polygon->at(1).y = minv(1);
169 out_polygon->at(1).z = minv(2);
170
171 out_polygon->at(2).x = maxv(0);
172 out_polygon->at(2).y = maxv(1);
173 out_polygon->at(2).z = minv(2);
174
175 out_polygon->at(3).x = minv(0);
176 out_polygon->at(3).y = maxv(1);
177 out_polygon->at(3).z = minv(2);
178 return true;
179}
180
181template <class CLOUD_IN_TYPE, class CLOUD_OUT_TYPE>
182bool ConvexHull2D<CLOUD_IN_TYPE, CLOUD_OUT_TYPE>::GetConvexHullMonotoneChain(
183 CLOUD_OUT_TYPE* out_polygon) {
184 if (points_.size() < 3) {
185 return false;
186 }
187
188 std::vector<std::size_t> sorted_indices(points_.size());
189 std::iota(sorted_indices.begin(), sorted_indices.end(), 0);
190
191 static const double eps = 1e-9;
192 std::sort(sorted_indices.begin(), sorted_indices.end(),
193 [&](const std::size_t& lhs, const std::size_t& rhs) {
194 double dx = points_[lhs](0) - points_[rhs](0);
195 if (std::abs(dx) > eps) {
196 return dx < 0.0;
197 }
198 return points_[lhs](1) < points_[rhs](1);
199 });
200 int count = 0;
201 int last_count = 1;
202 polygon_indices_.clear();
203 polygon_indices_.reserve(points_.size());
204
205 std::size_t size2 = points_.size() * 2;
206 for (std::size_t i = 0; i < size2; ++i) {
207 if (i == points_.size()) {
208 last_count = count;
209 }
210 const std::size_t& idx =
211 sorted_indices[(i < points_.size()) ? i : (size2 - 1 - i)];
212 const auto& point = points_[idx];
213 while (count > last_count &&
214 !IsCounterClockWise(points_[polygon_indices_[count - 2]],
215 points_[polygon_indices_[count - 1]], point,
216 eps)) {
217 polygon_indices_.pop_back();
218 --count;
219 }
220 polygon_indices_.push_back(idx);
221 ++count;
222 }
223 --count;
224 polygon_indices_.pop_back();
225 if (count < 3) {
226 return false;
227 }
228 out_polygon->clear();
229 out_polygon->resize(polygon_indices_.size());
230 // double NOT NECESSARY to static_cast float
231 double min_z = in_cloud_->at(0).z;
232 for (std::size_t id = 0; id < in_cloud_->size(); ++id) {
233 min_z = std::min<double>(in_cloud_->at(id).z, min_z);
234 }
235 for (std::size_t i = 0; i < polygon_indices_.size(); ++i) {
236 out_polygon->at(i).x = points_[polygon_indices_[i]](0);
237 out_polygon->at(i).y = points_[polygon_indices_[i]](1);
238 out_polygon->at(i).z = min_z;
239 }
240 return true;
241}
242
243} // namespace algorithm
244} // namespace perception
245} // namespace apollo
bool GetConvexHullWithoutGroundAndHead(const CLOUD_IN_TYPE &in_cloud, const float &distance_above_ground_thres, const float &distance_beneath_head_thres, CLOUD_OUT_TYPE *out_polygon)
bool GetConvexHull(const CLOUD_IN_TYPE &in_cloud, CLOUD_OUT_TYPE *out_polygon)
bool GetConvexHullWithoutGround(const CLOUD_IN_TYPE &in_cloud, const float &distance_above_ground_thres, CLOUD_OUT_TYPE *out_polygon)
apollo::common::EigenVector< EigenType > EigenVector
std::vector< EigenType, Eigen::aligned_allocator< EigenType > > EigenVector
Definition eigen_defs.h:33
class register implement
Definition arena_queue.h:37