hpp-fcl  3.0.0
HPP fork of FCL -- The Flexible Collision Library
traversal_node_bvhs.h
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2011-2014, Willow Garage, Inc.
5  * Copyright (c) 2014-2015, Open Source Robotics Foundation
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of Open Source Robotics Foundation nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35 
38 #ifndef HPP_FCL_TRAVERSAL_NODE_MESHES_H
39 #define HPP_FCL_TRAVERSAL_NODE_MESHES_H
40 
42 
43 #include <hpp/fcl/collision_data.h>
45 #include <hpp/fcl/BV/BV_node.h>
46 #include <hpp/fcl/BV/BV.h>
47 #include <hpp/fcl/BVH/BVH_model.h>
53 
54 #include <cassert>
55 
56 namespace hpp {
57 namespace fcl {
58 
61 
63 template <typename BV>
64 class BVHCollisionTraversalNode : public CollisionTraversalNodeBase {
65  public:
66  BVHCollisionTraversalNode(const CollisionRequest& request)
67  : CollisionTraversalNodeBase(request) {
68  model1 = NULL;
69  model2 = NULL;
70 
71  num_bv_tests = 0;
72  num_leaf_tests = 0;
73  query_time_seconds = 0.0;
74  }
75 
77  bool isFirstNodeLeaf(unsigned int b) const {
78  assert(model1 != NULL && "model1 is NULL");
79  return model1->getBV(b).isLeaf();
80  }
81 
83  bool isSecondNodeLeaf(unsigned int b) const {
84  assert(model2 != NULL && "model2 is NULL");
85  return model2->getBV(b).isLeaf();
86  }
87 
89  bool firstOverSecond(unsigned int b1, unsigned int b2) const {
90  FCL_REAL sz1 = model1->getBV(b1).bv.size();
91  FCL_REAL sz2 = model2->getBV(b2).bv.size();
92 
93  bool l1 = model1->getBV(b1).isLeaf();
94  bool l2 = model2->getBV(b2).isLeaf();
95 
96  if (l2 || (!l1 && (sz1 > sz2))) return true;
97  return false;
98  }
99 
101  int getFirstLeftChild(unsigned int b) const {
102  return model1->getBV(b).leftChild();
103  }
104 
106  int getFirstRightChild(unsigned int b) const {
107  return model1->getBV(b).rightChild();
108  }
109 
111  int getSecondLeftChild(unsigned int b) const {
112  return model2->getBV(b).leftChild();
113  }
114 
116  int getSecondRightChild(unsigned int b) const {
117  return model2->getBV(b).rightChild();
118  }
119 
121  const BVHModel<BV>* model1;
123  const BVHModel<BV>* model2;
124 
126  mutable int num_bv_tests;
127  mutable int num_leaf_tests;
128  mutable FCL_REAL query_time_seconds;
129 };
130 
132 template <typename BV, int _Options = RelativeTransformationIsIdentity>
133 class MeshCollisionTraversalNode : public BVHCollisionTraversalNode<BV> {
134  public:
135  enum {
136  Options = _Options,
137  RTIsIdentity = _Options & RelativeTransformationIsIdentity
138  };
139 
140  MeshCollisionTraversalNode(const CollisionRequest& request)
141  : BVHCollisionTraversalNode<BV>(request) {
142  vertices1 = NULL;
143  vertices2 = NULL;
144  tri_indices1 = NULL;
145  tri_indices2 = NULL;
146  }
147 
152  bool BVDisjoints(unsigned int b1, unsigned int b2,
153  FCL_REAL& sqrDistLowerBound) const {
154  if (this->enable_statistics) this->num_bv_tests++;
155  bool disjoint;
156  if (RTIsIdentity)
157  disjoint = !this->model1->getBV(b1).overlap(
158  this->model2->getBV(b2), this->request, sqrDistLowerBound);
159  else {
160  disjoint = !overlap(RT._R(), RT._T(), this->model2->getBV(b2).bv,
161  this->model1->getBV(b1).bv, this->request,
162  sqrDistLowerBound);
163  }
164  if (disjoint)
165  internal::updateDistanceLowerBoundFromBV(this->request, *this->result,
166  sqrDistLowerBound);
167  return disjoint;
168  }
169 
184  void leafCollides(unsigned int b1, unsigned int b2,
185  FCL_REAL& sqrDistLowerBound) const {
186  if (this->enable_statistics) this->num_leaf_tests++;
187 
188  const BVNode<BV>& node1 = this->model1->getBV(b1);
189  const BVNode<BV>& node2 = this->model2->getBV(b2);
190 
191  int primitive_id1 = node1.primitiveId();
192  int primitive_id2 = node2.primitiveId();
193 
194  const Triangle& tri_id1 = tri_indices1[primitive_id1];
195  const Triangle& tri_id2 = tri_indices2[primitive_id2];
196 
197  const Vec3f& P1 = vertices1[tri_id1[0]];
198  const Vec3f& P2 = vertices1[tri_id1[1]];
199  const Vec3f& P3 = vertices1[tri_id1[2]];
200  const Vec3f& Q1 = vertices2[tri_id2[0]];
201  const Vec3f& Q2 = vertices2[tri_id2[1]];
202  const Vec3f& Q3 = vertices2[tri_id2[2]];
203 
204  TriangleP tri1(P1, P2, P3);
205  TriangleP tri2(Q1, Q2, Q3);
206 
207  // TODO(louis): MeshCollisionTraversalNode should have its own GJKSolver.
208  GJKSolver solver(this->request);
209 
210  const bool compute_penetration =
211  this->request.enable_contact || (this->request.security_margin < 0);
212  Vec3f p1, p2, normal;
213  DistanceResult distanceResult;
214  FCL_REAL distance = internal::ShapeShapeDistance<TriangleP, TriangleP>(
215  &tri1, this->tf1, &tri2, this->tf2, &solver, compute_penetration, p1,
216  p2, normal);
217 
218  const FCL_REAL distToCollision = distance - this->request.security_margin;
219 
220  internal::updateDistanceLowerBoundFromLeaf(this->request, *(this->result),
221  distToCollision, p1, p2, normal);
222 
223  if (distToCollision <=
224  this->request.collision_distance_threshold) { // collision
225  sqrDistLowerBound = 0;
226  if (this->result->numContacts() < this->request.num_max_contacts) {
227  this->result->addContact(Contact(this->model1, this->model2,
228  primitive_id1, primitive_id2, p1, p2,
229  normal, distance));
230  }
231  } else
232  sqrDistLowerBound = distToCollision * distToCollision;
233  }
234 
235  Vec3f* vertices1;
236  Vec3f* vertices2;
237 
238  Triangle* tri_indices1;
239  Triangle* tri_indices2;
240 
241  details::RelativeTransformation<!bool(RTIsIdentity)> RT;
242 };
243 
246 typedef MeshCollisionTraversalNode<OBB, 0> MeshCollisionTraversalNodeOBB;
247 typedef MeshCollisionTraversalNode<RSS, 0> MeshCollisionTraversalNodeRSS;
248 typedef MeshCollisionTraversalNode<kIOS, 0> MeshCollisionTraversalNodekIOS;
249 typedef MeshCollisionTraversalNode<OBBRSS, 0> MeshCollisionTraversalNodeOBBRSS;
250 
252 
253 namespace details {
254 template <typename BV>
255 struct DistanceTraversalBVDistanceLowerBound_impl {
256  static FCL_REAL run(const BVNode<BV>& b1, const BVNode<BV>& b2) {
257  return b1.distance(b2);
258  }
259  static FCL_REAL run(const Matrix3f& R, const Vec3f& T, const BVNode<BV>& b1,
260  const BVNode<BV>& b2) {
261  return distance(R, T, b1.bv, b2.bv);
262  }
263 };
264 
265 template <>
266 struct DistanceTraversalBVDistanceLowerBound_impl<OBB> {
267  static FCL_REAL run(const BVNode<OBB>& b1, const BVNode<OBB>& b2) {
268  FCL_REAL sqrDistLowerBound;
269  CollisionRequest request(DISTANCE_LOWER_BOUND, 0);
270  // request.break_distance = ?
271  if (b1.overlap(b2, request, sqrDistLowerBound)) {
272  // TODO A penetration upper bound should be computed.
273  return -1;
274  }
275  return sqrt(sqrDistLowerBound);
276  }
277  static FCL_REAL run(const Matrix3f& R, const Vec3f& T, const BVNode<OBB>& b1,
278  const BVNode<OBB>& b2) {
279  FCL_REAL sqrDistLowerBound;
280  CollisionRequest request(DISTANCE_LOWER_BOUND, 0);
281  // request.break_distance = ?
282  if (overlap(R, T, b1.bv, b2.bv, request, sqrDistLowerBound)) {
283  // TODO A penetration upper bound should be computed.
284  return -1;
285  }
286  return sqrt(sqrDistLowerBound);
287  }
288 };
289 
290 template <>
291 struct DistanceTraversalBVDistanceLowerBound_impl<AABB> {
292  static FCL_REAL run(const BVNode<AABB>& b1, const BVNode<AABB>& b2) {
293  FCL_REAL sqrDistLowerBound;
294  CollisionRequest request(DISTANCE_LOWER_BOUND, 0);
295  // request.break_distance = ?
296  if (b1.overlap(b2, request, sqrDistLowerBound)) {
297  // TODO A penetration upper bound should be computed.
298  return -1;
299  }
300  return sqrt(sqrDistLowerBound);
301  }
302  static FCL_REAL run(const Matrix3f& R, const Vec3f& T, const BVNode<AABB>& b1,
303  const BVNode<AABB>& b2) {
304  FCL_REAL sqrDistLowerBound;
305  CollisionRequest request(DISTANCE_LOWER_BOUND, 0);
306  // request.break_distance = ?
307  if (overlap(R, T, b1.bv, b2.bv, request, sqrDistLowerBound)) {
308  // TODO A penetration upper bound should be computed.
309  return -1;
310  }
311  return sqrt(sqrDistLowerBound);
312  }
313 };
314 } // namespace details
315 
318 
320 template <typename BV>
321 class BVHDistanceTraversalNode : public DistanceTraversalNodeBase {
322  public:
323  BVHDistanceTraversalNode() : DistanceTraversalNodeBase() {
324  model1 = NULL;
325  model2 = NULL;
326 
327  num_bv_tests = 0;
328  num_leaf_tests = 0;
329  query_time_seconds = 0.0;
330  }
331 
333  bool isFirstNodeLeaf(unsigned int b) const {
334  return model1->getBV(b).isLeaf();
335  }
336 
338  bool isSecondNodeLeaf(unsigned int b) const {
339  return model2->getBV(b).isLeaf();
340  }
341 
343  bool firstOverSecond(unsigned int b1, unsigned int b2) const {
344  FCL_REAL sz1 = model1->getBV(b1).bv.size();
345  FCL_REAL sz2 = model2->getBV(b2).bv.size();
346 
347  bool l1 = model1->getBV(b1).isLeaf();
348  bool l2 = model2->getBV(b2).isLeaf();
349 
350  if (l2 || (!l1 && (sz1 > sz2))) return true;
351  return false;
352  }
353 
355  int getFirstLeftChild(unsigned int b) const {
356  return model1->getBV(b).leftChild();
357  }
358 
360  int getFirstRightChild(unsigned int b) const {
361  return model1->getBV(b).rightChild();
362  }
363 
365  int getSecondLeftChild(unsigned int b) const {
366  return model2->getBV(b).leftChild();
367  }
368 
370  int getSecondRightChild(unsigned int b) const {
371  return model2->getBV(b).rightChild();
372  }
373 
375  const BVHModel<BV>* model1;
377  const BVHModel<BV>* model2;
378 
380  mutable int num_bv_tests;
381  mutable int num_leaf_tests;
382  mutable FCL_REAL query_time_seconds;
383 };
384 
386 template <typename BV, int _Options = RelativeTransformationIsIdentity>
387 class MeshDistanceTraversalNode : public BVHDistanceTraversalNode<BV> {
388  public:
389  enum {
390  Options = _Options,
391  RTIsIdentity = _Options & RelativeTransformationIsIdentity
392  };
393 
394  using BVHDistanceTraversalNode<BV>::enable_statistics;
395  using BVHDistanceTraversalNode<BV>::request;
396  using BVHDistanceTraversalNode<BV>::result;
397  using BVHDistanceTraversalNode<BV>::tf1;
398  using BVHDistanceTraversalNode<BV>::model1;
399  using BVHDistanceTraversalNode<BV>::model2;
400  using BVHDistanceTraversalNode<BV>::num_bv_tests;
401  using BVHDistanceTraversalNode<BV>::num_leaf_tests;
402 
403  MeshDistanceTraversalNode() : BVHDistanceTraversalNode<BV>() {
404  vertices1 = NULL;
405  vertices2 = NULL;
406  tri_indices1 = NULL;
407  tri_indices2 = NULL;
408 
409  rel_err = this->request.rel_err;
410  abs_err = this->request.abs_err;
411  }
412 
413  void preprocess() {
414  if (!RTIsIdentity) preprocessOrientedNode();
415  }
416 
417  void postprocess() {
418  if (!RTIsIdentity) postprocessOrientedNode();
419  }
420 
422  FCL_REAL BVDistanceLowerBound(unsigned int b1, unsigned int b2) const {
423  if (enable_statistics) num_bv_tests++;
424  if (RTIsIdentity)
425  return details::DistanceTraversalBVDistanceLowerBound_impl<BV>::run(
426  model1->getBV(b1), model2->getBV(b2));
427  else
428  return details::DistanceTraversalBVDistanceLowerBound_impl<BV>::run(
429  RT._R(), RT._T(), model1->getBV(b1), model2->getBV(b2));
430  }
431 
433  void leafComputeDistance(unsigned int b1, unsigned int b2) const {
434  if (this->enable_statistics) this->num_leaf_tests++;
435 
436  const BVNode<BV>& node1 = this->model1->getBV(b1);
437  const BVNode<BV>& node2 = this->model2->getBV(b2);
438 
439  int primitive_id1 = node1.primitiveId();
440  int primitive_id2 = node2.primitiveId();
441 
442  const Triangle& tri_id1 = tri_indices1[primitive_id1];
443  const Triangle& tri_id2 = tri_indices2[primitive_id2];
444 
445  const Vec3f& t11 = vertices1[tri_id1[0]];
446  const Vec3f& t12 = vertices1[tri_id1[1]];
447  const Vec3f& t13 = vertices1[tri_id1[2]];
448 
449  const Vec3f& t21 = vertices2[tri_id2[0]];
450  const Vec3f& t22 = vertices2[tri_id2[1]];
451  const Vec3f& t23 = vertices2[tri_id2[2]];
452 
453  // nearest point pair
454  Vec3f P1, P2, normal;
455 
456  FCL_REAL d2;
457  if (RTIsIdentity)
458  d2 = TriangleDistance::sqrTriDistance(t11, t12, t13, t21, t22, t23, P1,
459  P2);
460  else
461  d2 = TriangleDistance::sqrTriDistance(t11, t12, t13, t21, t22, t23,
462  RT._R(), RT._T(), P1, P2);
463  FCL_REAL d = sqrt(d2);
464 
465  this->result->update(d, this->model1, this->model2, primitive_id1,
466  primitive_id2, P1, P2, normal);
467  }
468 
470  bool canStop(FCL_REAL c) const {
471  if ((c >= this->result->min_distance - abs_err) &&
472  (c * (1 + rel_err) >= this->result->min_distance))
473  return true;
474  return false;
475  }
476 
477  Vec3f* vertices1;
478  Vec3f* vertices2;
479 
480  Triangle* tri_indices1;
481  Triangle* tri_indices2;
482 
484  FCL_REAL rel_err;
485  FCL_REAL abs_err;
486 
487  details::RelativeTransformation<!bool(RTIsIdentity)> RT;
488 
489  private:
490  void preprocessOrientedNode() {
491  const int init_tri_id1 = 0, init_tri_id2 = 0;
492  const Triangle& init_tri1 = tri_indices1[init_tri_id1];
493  const Triangle& init_tri2 = tri_indices2[init_tri_id2];
494 
495  Vec3f init_tri1_points[3];
496  Vec3f init_tri2_points[3];
497 
498  init_tri1_points[0] = vertices1[init_tri1[0]];
499  init_tri1_points[1] = vertices1[init_tri1[1]];
500  init_tri1_points[2] = vertices1[init_tri1[2]];
501 
502  init_tri2_points[0] = vertices2[init_tri2[0]];
503  init_tri2_points[1] = vertices2[init_tri2[1]];
504  init_tri2_points[2] = vertices2[init_tri2[2]];
505 
506  Vec3f p1, p2, normal;
507  FCL_REAL distance = sqrt(TriangleDistance::sqrTriDistance(
508  init_tri1_points[0], init_tri1_points[1], init_tri1_points[2],
509  init_tri2_points[0], init_tri2_points[1], init_tri2_points[2], RT._R(),
510  RT._T(), p1, p2));
511 
512  result->update(distance, model1, model2, init_tri_id1, init_tri_id2, p1, p2,
513  normal);
514  }
515  void postprocessOrientedNode() {
519  if (request.enable_nearest_points && (result->o1 == model1) &&
520  (result->o2 == model2)) {
521  result->nearest_points[0] = tf1.transform(result->nearest_points[0]);
522  result->nearest_points[1] = tf1.transform(result->nearest_points[1]);
523  }
524  }
525 };
526 
529 typedef MeshDistanceTraversalNode<RSS, 0> MeshDistanceTraversalNodeRSS;
530 typedef MeshDistanceTraversalNode<kIOS, 0> MeshDistanceTraversalNodekIOS;
531 typedef MeshDistanceTraversalNode<OBBRSS, 0> MeshDistanceTraversalNodeOBBRSS;
532 
534 
537 namespace details {
538 
539 template <typename BV>
540 inline const Matrix3f& getBVAxes(const BV& bv) {
541  return bv.axes;
542 }
543 
544 template <>
545 inline const Matrix3f& getBVAxes<OBBRSS>(const OBBRSS& bv) {
546  return bv.obb.axes;
547 }
548 
549 } // namespace details
550 
551 } // namespace fcl
552 
553 } // namespace hpp
554 
556 
557 #endif
FCL_REAL distance(const Matrix3f &R0, const Vec3f &T0, const kIOS &b1, const kIOS &b2, Vec3f *P=NULL, Vec3f *Q=NULL)
Approximate distance between two kIOS bounding volumes.
bool overlap(const Matrix3f &R0, const Vec3f &T0, const AABB &b1, const AABB &b2)
Check collision between two aabbs, b1 is in configuration (R0, T0) and b2 is in identity.
void updateDistanceLowerBoundFromLeaf(const CollisionRequest &, CollisionResult &res, const FCL_REAL &distance, const Vec3f &p0, const Vec3f &p1, const Vec3f &normal)
Definition: collision_data.h:1186
void updateDistanceLowerBoundFromBV(const CollisionRequest &, CollisionResult &res, const FCL_REAL sqrDistLowerBound)
Definition: collision_data.h:1177
Eigen::Matrix< FCL_REAL, 3, 3 > Matrix3f
Definition: data_types.h:71
Eigen::Matrix< FCL_REAL, 3, 1 > Vec3f
Definition: data_types.h:67
@ DISTANCE_LOWER_BOUND
Definition: collision_data.h:307
double FCL_REAL
Definition: data_types.h:66
Main namespace.
Definition: broadphase_bruteforce.h:44