39 #ifndef FCL_SHAPE_CONVEX_INL_H 40 #define FCL_SHAPE_CONVEX_INL_H 61 const std::shared_ptr<
const std::vector<
Vector3<S>>>& vertices,
62 int num_faces,
const std::shared_ptr<
const std::vector<int>>& faces,
63 bool throw_if_invalid)
66 num_faces_(num_faces),
68 throw_if_invalid_(throw_if_invalid),
69 find_extreme_via_neighbors_{vertices->size() >
70 kMinVertCountForEdgeWalking} {
71 assert(vertices !=
nullptr);
72 assert(faces !=
nullptr);
76 for (
const auto& vertex : *vertices_) {
79 interior_point_ = sum * (
S)(1.0 / vertices_->size());
80 FindVertexNeighbors();
81 ValidateMesh(throw_if_invalid);
90 for (
const auto& v : *vertices_) {
91 this->aabb_local += v;
94 this->aabb_center = this->aabb_local.center();
95 this->aabb_radius = (this->aabb_local.min_ - this->aabb_center).norm();
110 template <
typename S>
112 const std::vector<Vector3<S>>& vertices = *vertices_;
113 const std::vector<int>& faces = *faces_;
117 C_canonical << 1/ 60.0, 1/120.0, 1/120.0,
118 1/120.0, 1/ 60.0, 1/120.0,
119 1/120.0, 1/120.0, 1/ 60.0;
123 for (
int i = 0; i < num_faces_; ++i) {
124 const int vertex_count = faces[face_index];
128 for (
int j = 1; j <= vertex_count; ++j) {
129 face_center += vertices[faces[face_index + j]];
131 face_center = face_center * (1.0 / vertex_count);
136 const int vertex_base = face_index + 1;
137 for (
int j = 0; j < vertex_count; ++j) {
138 int e_first = faces[vertex_base + j];
139 int e_second = faces[vertex_base + (j + 1) % vertex_count];
142 S d_six_vol = (v1.cross(v2)).dot(v3);
147 C += A.transpose() * C_canonical * A * d_six_vol;
148 vol_times_six += d_six_vol;
151 face_index += vertex_count + 1;
154 S trace_C = C(0, 0) + C(1, 1) + C(2, 2);
157 m << trace_C - C(0, 0), -C(0, 1), -C(0, 2),
158 -C(1, 0), trace_C - C(1, 1), -C(1, 2),
159 -C(2, 0), -C(2, 1), trace_C - C(2, 2);
161 return m * (6 / vol_times_six);
165 template <
typename S>
167 const std::vector<Vector3<S>>& vertices = *vertices_;
168 const std::vector<int>& faces = *faces_;
172 for (
int i = 0; i < num_faces_; ++i) {
173 const int vertex_count = faces[face_index];
180 for (
int j = 1; j <= vertex_count; ++j) {
181 face_center += vertices[faces[face_index + j]];
183 face_center = face_center * (1.0 / vertex_count);
188 for (
int j = 1; j <= vertex_count; ++j) {
189 int e_first = faces[face_index + j];
190 int e_second = faces[face_index + (j % vertex_count) + 1];
193 S d_six_vol = (v1.cross(v2)).dot(v3);
195 com += (v1 + v2 + face_center) * d_six_vol;
198 face_index += vertex_count + 1;
201 return com / (vol * 4);
206 const std::vector<Vector3<S>>& vertices = *vertices_;
207 const std::vector<int>& faces = *faces_;
210 for (
int i = 0; i < num_faces_; ++i) {
211 const int vertex_count = faces[face_index];
222 for (
int j = 1; j <= vertex_count; ++j) {
223 face_center += vertices[faces[face_index + j]];
225 face_center = face_center * (1.0 / vertex_count);
235 for (
int j = 1; j <= vertex_count; ++j) {
236 int e_first = faces[face_index + j];
237 int e_second = faces[face_index + (j % vertex_count) + 1];
240 S d_six_vol = (v1.cross(v2)).dot(v3);
244 face_index += vertex_count + 1;
251 template <
typename S>
254 std::vector<Vector3<S>> result;
255 result.reserve(vertices_->size());
257 for (
const auto& v : *vertices_) {
258 result.push_back(tf * v);
265 template <
typename S>
270 const std::vector<Vector3<S>>& vertices = *vertices_;
274 std::vector<int8_t> visited(vertices.size(), 0);
275 int extreme_index = 0;
276 S extreme_value = v_C.dot(vertices[extreme_index]);
278 if (find_extreme_via_neighbors_) {
279 bool keep_searching =
true;
280 while (keep_searching) {
281 keep_searching =
false;
282 const int neighbor_start = neighbors_[extreme_index];
283 const int neighbor_count = neighbors_[neighbor_start];
284 for (
int n_index = neighbor_start + 1;
285 n_index <= neighbor_start + neighbor_count; ++n_index) {
286 const int neighbor_index = neighbors_[n_index];
287 if (visited[neighbor_index])
continue;
288 visited[neighbor_index] = 1;
289 const S neighbor_value = v_C.dot(vertices[neighbor_index]);
296 if (neighbor_value >= extreme_value) {
297 keep_searching =
true;
298 extreme_index = neighbor_index;
299 extreme_value = neighbor_value;
305 for (
int i = 1; i < static_cast<int>(vertices.size()); ++i) {
306 S value = v_C.dot(vertices[i]);
307 if (value > extreme_value) {
309 extreme_value = value;
313 return vertices[extreme_index];
317 template <
typename S>
320 std::stringstream ss;
321 ss << std::setprecision(precision);
322 ss <<
"Convex<" << S_str <<
">(" 323 <<
"\n std::make_shared<std::vector<Vector3<" << S_str <<
">>>(" 324 <<
"\n std::initializer_list<Vector3<" << S_str <<
">>{";
326 ss <<
"\n Vector3<" << S_str <<
">(" << p_GV[0] <<
", " << p_GV[1]
327 <<
", " << p_GV[2] <<
"),";
330 ss <<
"\n " << num_faces_ <<
",";
331 ss <<
"\n std::make_shared<std::vector<int>>(" 332 <<
"\n std::initializer_list<int>{" 334 const std::vector<int>& faces = *faces_;
336 for (
int i = 0; i < num_faces_; ++i) {
337 const int vertex_count = faces[face_index];
338 ss <<
" " << vertex_count <<
",";
339 for (
int j = 1; j <= vertex_count; ++j) {
340 ss <<
" " << faces[face_index + j] <<
",";
342 face_index += vertex_count + 1;
345 <<
"\n " << std::boolalpha << throw_if_invalid_ <<
");";
351 template <
typename S>
353 ValidateTopology(throw_on_error);
359 template <
typename S>
362 assert(neighbors_.size() > vertices_->size());
364 std::stringstream ss;
365 ss <<
"Found errors in the Convex mesh:";
369 auto make_edge = [](
int v0,
int v1) {
371 return std::make_pair(v0, v1);
374 bool all_connected =
true;
377 std::map<std::pair<int, int>,
int> per_edge_face_count;
379 for (
int v = 0; v < static_cast<int>(vertices_->size()); ++v) {
380 const int neighbor_start = neighbors_[v];
381 const int neighbor_count = neighbors_[neighbor_start];
382 if (neighbor_count == 0) {
384 ss <<
"\n Not all vertices are connected.";
385 all_connected =
false;
387 ss <<
"\n Vertex " << v <<
" is not included in any faces.";
389 for (
int n_index = neighbor_start + 1;
390 n_index <= neighbor_start + neighbor_count; ++n_index) {
391 const int n = neighbors_[n_index];
392 per_edge_face_count[make_edge(v, n)] = 0;
400 const std::vector<int>& faces = *faces_;
402 for (
int f = 0; f < num_faces_; ++f) {
403 const int vertex_count = faces[face_index];
404 int prev_v = faces[face_index + vertex_count];
405 for (
int i = face_index + 1; i <= face_index + vertex_count; ++i) {
406 const int v = faces[i];
407 ++per_edge_face_count[make_edge(v, prev_v)];
410 face_index += vertex_count + 1;
414 bool is_watertight =
true;
415 for (
const auto& key_value_pair : per_edge_face_count) {
416 const auto& edge = key_value_pair.first;
417 const int count = key_value_pair.second;
420 is_watertight =
false;
421 ss <<
"\n The mesh is not watertight.";
423 ss <<
"\n Edge between vertices " << edge.first <<
" and " << edge.second
424 <<
" is shared by " << count <<
" faces (should be 2).";
428 const bool has_error = !(is_watertight && all_connected);
432 find_extreme_via_neighbors_ = find_extreme_via_neighbors_ && !has_error;
433 if (has_error && throw_on_error) {
434 throw std::runtime_error(ss.str());
439 template <
typename S>
445 const int v_count =
static_cast<int>(vertices_->size());
446 std::vector<std::set<int>> neighbors(v_count);
447 const std::vector<int>& faces = *faces_;
449 for (
int f = 0; f < num_faces_; ++f) {
450 const int vertex_count = faces[face_index];
451 int prev_v = faces[face_index + vertex_count];
452 for (
int i = face_index + 1; i <= face_index + vertex_count; ++i) {
453 const int v = faces[i];
454 neighbors[v].insert(prev_v);
455 neighbors[prev_v].insert(v);
458 face_index += vertex_count + 1;
462 neighbors_.resize(v_count);
463 for (
int v = 0; v < v_count; ++v) {
464 const std::set<int>& v_neighbors = neighbors[v];
465 neighbors_[v] =
static_cast<int>(neighbors_.size());
466 neighbors_.push_back(static_cast<int>(v_neighbors.size()));
467 neighbors_.insert(neighbors_.end(), v_neighbors.begin(), v_neighbors.end());
Convex(const std::shared_ptr< const std::vector< Vector3< S >>> &vertices, int num_faces, const std::shared_ptr< const std::vector< int >> &faces, bool throw_if_invalid=false)
Constructor.
NODE_TYPE
traversal node type: bounding volume (AABB, OBB, RSS, kIOS, OBBRSS, KDOP16, KDOP18, kDOP24), basic shape (box, sphere, ellipsoid, capsule, cone, cylinder, convex, plane, halfspace, triangle), and octree
Base class for all basic geometric shapes.
Eigen::Transform< S, 3, Eigen::Isometry > Transform3
Eigen::Matrix< S, 3, 3 > Matrix3
template class FCL_EXPORT Convex< double >
Eigen::Matrix< S, 3, 1 > Vector3
static void swap(T &x, T &y)