GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: include/hpp/fcl/internal/traversal_node_bvh_shape.h Lines: 107 164 65.2 %
Date: 2024-02-09 12:57:42 Branches: 41 116 35.3 %

Line Branch Exec Source
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
36
/** \author Jia Pan */
37
38
#ifndef HPP_FCL_TRAVERSAL_NODE_MESH_SHAPE_H
39
#define HPP_FCL_TRAVERSAL_NODE_MESH_SHAPE_H
40
41
/// @cond INTERNAL
42
43
#include <hpp/fcl/collision_data.h>
44
#include <hpp/fcl/shape/geometric_shapes.h>
45
#include <hpp/fcl/narrowphase/narrowphase.h>
46
#include <hpp/fcl/shape/geometric_shapes_utility.h>
47
#include <hpp/fcl/internal/traversal_node_base.h>
48
#include <hpp/fcl/internal/traversal.h>
49
#include <hpp/fcl/BVH/BVH_model.h>
50
51
namespace hpp {
52
namespace fcl {
53
54
/// @addtogroup Traversal_For_Collision
55
/// @{
56
57
/// @brief Traversal node for collision between BVH and shape
58
template <typename BV, typename S>
59
class BVHShapeCollisionTraversalNode : public CollisionTraversalNodeBase {
60
 public:
61
248
  BVHShapeCollisionTraversalNode(const CollisionRequest& request)
62
248
      : CollisionTraversalNodeBase(request) {
63
248
    model1 = NULL;
64
248
    model2 = NULL;
65
66
248
    num_bv_tests = 0;
67
248
    num_leaf_tests = 0;
68
248
    query_time_seconds = 0.0;
69
  }
70
71
  /// @brief Whether the BV node in the first BVH tree is leaf
72
7596
  bool isFirstNodeLeaf(unsigned int b) const {
73
7596
    return model1->getBV(b).isLeaf();
74
  }
75
76
  /// @brief Obtain the left child of BV node in the first BVH
77
3796
  int getFirstLeftChild(unsigned int b) const {
78
3796
    return model1->getBV(b).leftChild();
79
  }
80
81
  /// @brief Obtain the right child of BV node in the first BVH
82
3796
  int getFirstRightChild(unsigned int b) const {
83
3796
    return model1->getBV(b).rightChild();
84
  }
85
86
  const BVHModel<BV>* model1;
87
  const S* model2;
88
  BV model2_bv;
89
90
  mutable int num_bv_tests;
91
  mutable int num_leaf_tests;
92
  mutable FCL_REAL query_time_seconds;
93
};
94
95
/// @brief Traversal node for collision between shape and BVH
96
template <typename S, typename BV>
97
class ShapeBVHCollisionTraversalNode : public CollisionTraversalNodeBase {
98
 public:
99
  ShapeBVHCollisionTraversalNode(const CollisionRequest& request)
100
      : CollisionTraversalNodeBase(request) {
101
    model1 = NULL;
102
    model2 = NULL;
103
104
    num_bv_tests = 0;
105
    num_leaf_tests = 0;
106
    query_time_seconds = 0.0;
107
  }
108
109
  /// @brief Alway extend the second model, which is a BVH model
110
  bool firstOverSecond(unsigned int, unsigned int) const { return false; }
111
112
  /// @brief Whether the BV node in the second BVH tree is leaf
113
  bool isSecondNodeLeaf(unsigned int b) const {
114
    return model2->getBV(b).isLeaf();
115
  }
116
117
  /// @brief Obtain the left child of BV node in the second BVH
118
  int getSecondLeftChild(unsigned int b) const {
119
    return model2->getBV(b).leftChild();
120
  }
121
122
  /// @brief Obtain the right child of BV node in the second BVH
123
  int getSecondRightChild(unsigned int b) const {
124
    return model2->getBV(b).rightChild();
125
  }
126
127
  const S* model1;
128
  const BVHModel<BV>* model2;
129
  BV model1_bv;
130
131
  mutable int num_bv_tests;
132
  mutable int num_leaf_tests;
133
  mutable FCL_REAL query_time_seconds;
134
};
135
136
/// @brief Traversal node for collision between mesh and shape
137
template <typename BV, typename S,
138
          int _Options = RelativeTransformationIsIdentity>
139
class MeshShapeCollisionTraversalNode
140
    : public BVHShapeCollisionTraversalNode<BV, S> {
141
 public:
142
  enum {
143
    Options = _Options,
144
    RTIsIdentity = _Options & RelativeTransformationIsIdentity
145
  };
146
147
248
  MeshShapeCollisionTraversalNode(const CollisionRequest& request)
148
248
      : BVHShapeCollisionTraversalNode<BV, S>(request) {
149
248
    vertices = NULL;
150
248
    tri_indices = NULL;
151
152
248
    nsolver = NULL;
153
  }
154
155
  /// test between BV b1 and shape
156
  /// @param b1 BV to test,
157
  /// @retval sqrDistLowerBound square of a lower bound of the minimal
158
  ///         distance between bounding volumes.
159
  /// @brief BV culling test in one BVTT node
160
6826
  bool BVDisjoints(unsigned int b1, unsigned int /*b2*/,
161
                   FCL_REAL& sqrDistLowerBound) const {
162
6826
    if (this->enable_statistics) this->num_bv_tests++;
163
    bool disjoint;
164
    if (RTIsIdentity)
165
      disjoint = !this->model1->getBV(b1).bv.overlap(
166
          this->model2_bv, this->request, sqrDistLowerBound);
167
    else
168
6826
      disjoint = !overlap(this->tf1.getRotation(), this->tf1.getTranslation(),
169
6826
                          this->model1->getBV(b1).bv, this->model2_bv,
170
                          this->request, sqrDistLowerBound);
171
6826
    if (disjoint)
172
3030
      internal::updateDistanceLowerBoundFromBV(this->request, *this->result,
173
                                               sqrDistLowerBound);
174

6826
    assert(!disjoint || sqrDistLowerBound > 0);
175
6826
    return disjoint;
176
  }
177
178
  /// @brief Intersection testing between leaves (one triangle and one shape)
179
770
  void leafCollides(unsigned int b1, unsigned int /*b2*/,
180
                    FCL_REAL& sqrDistLowerBound) const {
181
770
    if (this->enable_statistics) this->num_leaf_tests++;
182
770
    const BVNode<BV>& node = this->model1->getBV(b1);
183
184
770
    int primitive_id = node.primitiveId();
185
186
770
    const Triangle& tri_id = tri_indices[primitive_id];
187
188
770
    const Vec3f& p1 = vertices[tri_id[0]];
189
770
    const Vec3f& p2 = vertices[tri_id[1]];
190
770
    const Vec3f& p3 = vertices[tri_id[2]];
191
192
    FCL_REAL distance;
193
770
    Vec3f normal;
194

770
    Vec3f c1, c2;  // closest point
195
196
    bool collision;
197
    if (RTIsIdentity) {
198
      static const Transform3f Id;
199
      collision = nsolver->shapeTriangleInteraction(
200
          *(this->model2), this->tf2, p1, p2, p3, Id, distance, c2, c1, normal);
201
    } else {
202
1540
      collision = nsolver->shapeTriangleInteraction(*(this->model2), this->tf2,
203
770
                                                    p1, p2, p3, this->tf1,
204
                                                    distance, c2, c1, normal);
205
    }
206
207
770
    FCL_REAL distToCollision = distance - this->request.security_margin;
208
770
    if (collision) {
209
48
      sqrDistLowerBound = 0;
210
48
      if (this->request.num_max_contacts > this->result->numContacts()) {
211


48
        this->result->addContact(Contact(this->model1, this->model2,
212
                                         primitive_id, Contact::NONE, c1,
213
                                         -normal, -distance));
214
48
        assert(this->result->isCollision());
215
      }
216
722
    } else if (distToCollision <= this->request.collision_distance_threshold) {
217
      sqrDistLowerBound = 0;
218
      if (this->request.num_max_contacts > this->result->numContacts()) {
219
        this->result->addContact(
220
            Contact(this->model1, this->model2, primitive_id, Contact::NONE,
221
                    .5 * (c1 + c2), (c2 - c1).normalized(), -distance));
222
      }
223
    } else
224
722
      sqrDistLowerBound = distToCollision * distToCollision;
225
226
770
    internal::updateDistanceLowerBoundFromLeaf(this->request, *this->result,
227
                                               distToCollision, c1, c2);
228
229

770
    assert(this->result->isCollision() || sqrDistLowerBound > 0);
230
  }
231
232
  Vec3f* vertices;
233
  Triangle* tri_indices;
234
235
  const GJKSolver* nsolver;
236
};
237
238
/// @brief Traversal node for collision between shape and mesh
239
template <typename S, typename BV,
240
          int _Options = RelativeTransformationIsIdentity>
241
class ShapeMeshCollisionTraversalNode
242
    : public ShapeBVHCollisionTraversalNode<S, BV> {
243
 public:
244
  enum {
245
    Options = _Options,
246
    RTIsIdentity = _Options & RelativeTransformationIsIdentity
247
  };
248
249
  ShapeMeshCollisionTraversalNode() : ShapeBVHCollisionTraversalNode<S, BV>() {
250
    vertices = NULL;
251
    tri_indices = NULL;
252
253
    nsolver = NULL;
254
  }
255
256
  /// BV test between b1 and b2
257
  /// @param b2 Bounding volumes to test,
258
  /// @retval sqrDistLowerBound square of a lower bound of the minimal
259
  ///         distance between bounding volumes.
260
  bool BVDisjoints(unsigned int /*b1*/, unsigned int b2,
261
                   FCL_REAL& sqrDistLowerBound) const {
262
    if (this->enable_statistics) this->num_bv_tests++;
263
    bool disjoint;
264
    if (RTIsIdentity)
265
      disjoint = !this->model2->getBV(b2).bv.overlap(this->model1_bv,
266
                                                     sqrDistLowerBound);
267
    else
268
      disjoint = !overlap(this->tf2.getRotation(), this->tf2.getTranslation(),
269
                          this->model2->getBV(b2).bv, this->model1_bv,
270
                          sqrDistLowerBound);
271
    if (disjoint)
272
      internal::updateDistanceLowerBoundFromBV(this->request, *this->result,
273
                                               sqrDistLowerBound);
274
    assert(!disjoint || sqrDistLowerBound > 0);
275
    return disjoint;
276
  }
277
278
  /// @brief Intersection testing between leaves (one shape and one triangle)
279
  void leafCollides(unsigned int /*b1*/, unsigned int b2,
280
                    FCL_REAL& sqrDistLowerBound) const {
281
    if (this->enable_statistics) this->num_leaf_tests++;
282
    const BVNode<BV>& node = this->model2->getBV(b2);
283
284
    int primitive_id = node.primitiveId();
285
286
    const Triangle& tri_id = tri_indices[primitive_id];
287
288
    const Vec3f& p1 = vertices[tri_id[0]];
289
    const Vec3f& p2 = vertices[tri_id[1]];
290
    const Vec3f& p3 = vertices[tri_id[2]];
291
292
    FCL_REAL distance;
293
    Vec3f normal;
294
    Vec3f c1, c2;  // closest points
295
296
    bool collision;
297
    if (RTIsIdentity) {
298
      static const Transform3f Id;
299
      collision = nsolver->shapeTriangleInteraction(
300
          *(this->model1), this->tf1, p1, p2, p3, Id, c1, c2, distance, normal);
301
    } else {
302
      collision = nsolver->shapeTriangleInteraction(*(this->model1), this->tf1,
303
                                                    p1, p2, p3, this->tf2, c1,
304
                                                    c2, distance, normal);
305
    }
306
307
    FCL_REAL distToCollision = distance - this->request.security_margin;
308
    if (collision) {
309
      sqrDistLowerBound = 0;
310
      if (this->request.num_max_contacts > this->result->numContacts()) {
311
        this->result->addContact(Contact(this->model1, this->model2,
312
                                         Contact::NONE, primitive_id, c1,
313
                                         normal, -distance));
314
        assert(this->result->isCollision());
315
      }
316
    } else if (distToCollision <= this->request.collision_distance_threshold) {
317
      sqrDistLowerBound = 0;
318
      if (this->request.num_max_contacts > this->result->numContacts()) {
319
        this->result->addContact(
320
            Contact(this->model1, this->model2, Contact::NONE, primitive_id,
321
                    .5 * (c1 + c2), (c2 - c1).normalized(), -distance));
322
      }
323
    } else
324
      sqrDistLowerBound = distToCollision * distToCollision;
325
326
    internal::updateDistanceLowerBoundFromLeaf(this->request, *this->result,
327
                                               distToCollision, c1, c2);
328
329
    assert(this->result->isCollision() || sqrDistLowerBound > 0);
330
  }
331
332
  Vec3f* vertices;
333
  Triangle* tri_indices;
334
335
  const GJKSolver* nsolver;
336
};
337
338
/// @}
339
340
/// @addtogroup Traversal_For_Distance
341
/// @{
342
343
/// @brief Traversal node for distance computation between BVH and shape
344
template <typename BV, typename S>
345
class BVHShapeDistanceTraversalNode : public DistanceTraversalNodeBase {
346
 public:
347
200
  BVHShapeDistanceTraversalNode() : DistanceTraversalNodeBase() {
348
200
    model1 = NULL;
349
200
    model2 = NULL;
350
351
200
    num_bv_tests = 0;
352
200
    num_leaf_tests = 0;
353
200
    query_time_seconds = 0.0;
354
  }
355
356
  /// @brief Whether the BV node in the first BVH tree is leaf
357
13650
  bool isFirstNodeLeaf(unsigned int b) const {
358
13650
    return model1->getBV(b).isLeaf();
359
  }
360
361
  /// @brief Obtain the left child of BV node in the first BVH
362
10792
  int getFirstLeftChild(unsigned int b) const {
363
10792
    return model1->getBV(b).leftChild();
364
  }
365
366
  /// @brief Obtain the right child of BV node in the first BVH
367
10792
  int getFirstRightChild(unsigned int b) const {
368
10792
    return model1->getBV(b).rightChild();
369
  }
370
371
  /// @brief BV culling test in one BVTT node
372
  FCL_REAL BVDistanceLowerBound(unsigned int b1, unsigned int /*b2*/) const {
373
    return model1->getBV(b1).bv.distance(model2_bv);
374
  }
375
376
  const BVHModel<BV>* model1;
377
  const S* model2;
378
  BV model2_bv;
379
380
  mutable int num_bv_tests;
381
  mutable int num_leaf_tests;
382
  mutable FCL_REAL query_time_seconds;
383
};
384
385
/// @brief Traversal node for distance computation between shape and BVH
386
template <typename S, typename BV>
387
class ShapeBVHDistanceTraversalNode : public DistanceTraversalNodeBase {
388
 public:
389
  ShapeBVHDistanceTraversalNode() : DistanceTraversalNodeBase() {
390
    model1 = NULL;
391
    model2 = NULL;
392
393
    num_bv_tests = 0;
394
    num_leaf_tests = 0;
395
    query_time_seconds = 0.0;
396
  }
397
398
  /// @brief Whether the BV node in the second BVH tree is leaf
399
  bool isSecondNodeLeaf(unsigned int b) const {
400
    return model2->getBV(b).isLeaf();
401
  }
402
403
  /// @brief Obtain the left child of BV node in the second BVH
404
  int getSecondLeftChild(unsigned int b) const {
405
    return model2->getBV(b).leftChild();
406
  }
407
408
  /// @brief Obtain the right child of BV node in the second BVH
409
  int getSecondRightChild(unsigned int b) const {
410
    return model2->getBV(b).rightChild();
411
  }
412
413
  /// @brief BV culling test in one BVTT node
414
  FCL_REAL BVDistanceLowerBound(unsigned int /*b1*/, unsigned int b2) const {
415
    return model1_bv.distance(model2->getBV(b2).bv);
416
  }
417
418
  const S* model1;
419
  const BVHModel<BV>* model2;
420
  BV model1_bv;
421
422
  mutable int num_bv_tests;
423
  mutable int num_leaf_tests;
424
  mutable FCL_REAL query_time_seconds;
425
};
426
427
/// @brief Traversal node for distance between mesh and shape
428
template <typename BV, typename S>
429
class MeshShapeDistanceTraversalNode
430
    : public BVHShapeDistanceTraversalNode<BV, S> {
431
 public:
432
200
  MeshShapeDistanceTraversalNode() : BVHShapeDistanceTraversalNode<BV, S>() {
433
200
    vertices = NULL;
434
200
    tri_indices = NULL;
435
436
200
    rel_err = 0;
437
200
    abs_err = 0;
438
439
200
    nsolver = NULL;
440
  }
441
442
  /// @brief Distance testing between leaves (one triangle and one shape)
443
  void leafComputeDistance(unsigned int b1, unsigned int /*b2*/) const {
444
    if (this->enable_statistics) this->num_leaf_tests++;
445
446
    const BVNode<BV>& node = this->model1->getBV(b1);
447
448
    int primitive_id = node.primitiveId();
449
450
    const Triangle& tri_id = tri_indices[primitive_id];
451
452
    const Vec3f& p1 = vertices[tri_id[0]];
453
    const Vec3f& p2 = vertices[tri_id[1]];
454
    const Vec3f& p3 = vertices[tri_id[2]];
455
456
    FCL_REAL d;
457
    Vec3f closest_p1, closest_p2, normal;
458
    nsolver->shapeTriangleInteraction(*(this->model2), this->tf2, p1, p2, p3,
459
                                      Transform3f(), d, closest_p2, closest_p1,
460
                                      normal);
461
462
    this->result->update(d, this->model1, this->model2, primitive_id,
463
                         DistanceResult::NONE, closest_p1, closest_p2, normal);
464
  }
465
466
  /// @brief Whether the traversal process can stop early
467
21584
  bool canStop(FCL_REAL c) const {
468
21584
    if ((c >= this->result->min_distance - abs_err) &&
469
8134
        (c * (1 + rel_err) >= this->result->min_distance))
470
8134
      return true;
471
13450
    return false;
472
  }
473
474
  Vec3f* vertices;
475
  Triangle* tri_indices;
476
477
  FCL_REAL rel_err;
478
  FCL_REAL abs_err;
479
480
  const GJKSolver* nsolver;
481
};
482
483
/// @cond IGNORE
484
namespace details {
485
486
template <typename BV, typename S>
487
2858
void meshShapeDistanceOrientedNodeleafComputeDistance(
488
    unsigned int b1, unsigned int /* b2 */, const BVHModel<BV>* model1,
489
    const S& model2, Vec3f* vertices, Triangle* tri_indices,
490
    const Transform3f& tf1, const Transform3f& tf2, const GJKSolver* nsolver,
491
    bool enable_statistics, int& num_leaf_tests,
492
    const DistanceRequest& /* request */, DistanceResult& result) {
493
2858
  if (enable_statistics) num_leaf_tests++;
494
495
2858
  const BVNode<BV>& node = model1->getBV(b1);
496
2858
  int primitive_id = node.primitiveId();
497
498
2858
  const Triangle& tri_id = tri_indices[primitive_id];
499
2858
  const Vec3f& p1 = vertices[tri_id[0]];
500
2858
  const Vec3f& p2 = vertices[tri_id[1]];
501
2858
  const Vec3f& p3 = vertices[tri_id[2]];
502
503
  FCL_REAL distance;
504

2858
  Vec3f closest_p1, closest_p2, normal;
505
2858
  nsolver->shapeTriangleInteraction(model2, tf2, p1, p2, p3, tf1, distance,
506
                                    closest_p2, closest_p1, normal);
507
508
2858
  result.update(distance, model1, &model2, primitive_id, DistanceResult::NONE,
509
                closest_p1, closest_p2, normal);
510
}
511
512
template <typename BV, typename S>
513
200
static inline void distancePreprocessOrientedNode(
514
    const BVHModel<BV>* model1, Vec3f* vertices, Triangle* tri_indices,
515
    int init_tri_id, const S& model2, const Transform3f& tf1,
516
    const Transform3f& tf2, const GJKSolver* nsolver,
517
    const DistanceRequest& /* request */, DistanceResult& result) {
518
200
  const Triangle& init_tri = tri_indices[init_tri_id];
519
520
200
  const Vec3f& p1 = vertices[init_tri[0]];
521
200
  const Vec3f& p2 = vertices[init_tri[1]];
522
200
  const Vec3f& p3 = vertices[init_tri[2]];
523
524
  FCL_REAL distance;
525

200
  Vec3f closest_p1, closest_p2, normal;
526
200
  nsolver->shapeTriangleInteraction(model2, tf2, p1, p2, p3, tf1, distance,
527
                                    closest_p2, closest_p1, normal);
528
529
200
  result.update(distance, model1, &model2, init_tri_id, DistanceResult::NONE,
530
                closest_p1, closest_p2, normal);
531
}
532
533
}  // namespace details
534
535
/// @endcond
536
537
/// @brief Traversal node for distance between mesh and shape, when mesh BVH is
538
/// one of the oriented node (RSS, kIOS, OBBRSS)
539
template <typename S>
540
class MeshShapeDistanceTraversalNodeRSS
541
    : public MeshShapeDistanceTraversalNode<RSS, S> {
542
 public:
543
  MeshShapeDistanceTraversalNodeRSS()
544
      : MeshShapeDistanceTraversalNode<RSS, S>() {}
545
546
  void preprocess() {
547
    details::distancePreprocessOrientedNode(
548
        this->model1, this->vertices, this->tri_indices, 0, *(this->model2),
549
        this->tf1, this->tf2, this->nsolver, this->request, *(this->result));
550
  }
551
552
  void postprocess() {}
553
554
  FCL_REAL BVDistanceLowerBound(unsigned int b1, unsigned int /*b2*/) const {
555
    if (this->enable_statistics) this->num_bv_tests++;
556
    return distance(this->tf1.getRotation(), this->tf1.getTranslation(),
557
                    this->model2_bv, this->model1->getBV(b1).bv);
558
  }
559
560
  void leafComputeDistance(unsigned int b1, unsigned int b2) const {
561
    details::meshShapeDistanceOrientedNodeleafComputeDistance(
562
        b1, b2, this->model1, *(this->model2), this->vertices,
563
        this->tri_indices, this->tf1, this->tf2, this->nsolver,
564
        this->enable_statistics, this->num_leaf_tests, this->request,
565
        *(this->result));
566
  }
567
};
568
569
template <typename S>
570
class MeshShapeDistanceTraversalNodekIOS
571
    : public MeshShapeDistanceTraversalNode<kIOS, S> {
572
 public:
573
  MeshShapeDistanceTraversalNodekIOS()
574
      : MeshShapeDistanceTraversalNode<kIOS, S>() {}
575
576
  void preprocess() {
577
    details::distancePreprocessOrientedNode(
578
        this->model1, this->vertices, this->tri_indices, 0, *(this->model2),
579
        this->tf1, this->tf2, this->nsolver, this->request, *(this->result));
580
  }
581
582
  void postprocess() {}
583
584
  FCL_REAL BVDistanceLowerBound(unsigned int b1, unsigned int /*b2*/) const {
585
    if (this->enable_statistics) this->num_bv_tests++;
586
    return distance(this->tf1.getRotation(), this->tf1.getTranslation(),
587
                    this->model2_bv, this->model1->getBV(b1).bv);
588
  }
589
590
  void leafComputeDistance(unsigned int b1, unsigned int b2) const {
591
    details::meshShapeDistanceOrientedNodeleafComputeDistance(
592
        b1, b2, this->model1, *(this->model2), this->vertices,
593
        this->tri_indices, this->tf1, this->tf2, this->nsolver,
594
        this->enable_statistics, this->num_leaf_tests, this->request,
595
        *(this->result));
596
  }
597
};
598
599
template <typename S>
600
class MeshShapeDistanceTraversalNodeOBBRSS
601
    : public MeshShapeDistanceTraversalNode<OBBRSS, S> {
602
 public:
603
200
  MeshShapeDistanceTraversalNodeOBBRSS()
604
200
      : MeshShapeDistanceTraversalNode<OBBRSS, S>() {}
605
606
200
  void preprocess() {
607
200
    details::distancePreprocessOrientedNode(
608
200
        this->model1, this->vertices, this->tri_indices, 0, *(this->model2),
609
200
        this->tf1, this->tf2, this->nsolver, this->request, *(this->result));
610
  }
611
612
200
  void postprocess() {}
613
614
21584
  FCL_REAL BVDistanceLowerBound(unsigned int b1, unsigned int /*b2*/) const {
615
21584
    if (this->enable_statistics) this->num_bv_tests++;
616
21584
    return distance(this->tf1.getRotation(), this->tf1.getTranslation(),
617
43168
                    this->model2_bv, this->model1->getBV(b1).bv);
618
  }
619
620
2858
  void leafComputeDistance(unsigned int b1, unsigned int b2) const {
621
2858
    details::meshShapeDistanceOrientedNodeleafComputeDistance(
622
2858
        b1, b2, this->model1, *(this->model2), this->vertices,
623
2858
        this->tri_indices, this->tf1, this->tf2, this->nsolver,
624
2858
        this->enable_statistics, this->num_leaf_tests, this->request,
625
2858
        *(this->result));
626
  }
627
};
628
629
/// @brief Traversal node for distance between shape and mesh
630
template <typename S, typename BV>
631
class ShapeMeshDistanceTraversalNode
632
    : public ShapeBVHDistanceTraversalNode<S, BV> {
633
 public:
634
  ShapeMeshDistanceTraversalNode() : ShapeBVHDistanceTraversalNode<S, BV>() {
635
    vertices = NULL;
636
    tri_indices = NULL;
637
638
    rel_err = 0;
639
    abs_err = 0;
640
641
    nsolver = NULL;
642
  }
643
644
  /// @brief Distance testing between leaves (one shape and one triangle)
645
  void leafComputeDistance(unsigned int /*b1*/, unsigned int b2) const {
646
    if (this->enable_statistics) this->num_leaf_tests++;
647
648
    const BVNode<BV>& node = this->model2->getBV(b2);
649
650
    int primitive_id = node.primitiveId();
651
652
    const Triangle& tri_id = tri_indices[primitive_id];
653
654
    const Vec3f& p1 = vertices[tri_id[0]];
655
    const Vec3f& p2 = vertices[tri_id[1]];
656
    const Vec3f& p3 = vertices[tri_id[2]];
657
658
    FCL_REAL distance;
659
    Vec3f closest_p1, closest_p2, normal;
660
    nsolver->shapeTriangleInteraction(*(this->model1), this->tf1, p1, p2, p3,
661
                                      Transform3f(), distance, closest_p1,
662
                                      closest_p2, normal);
663
664
    this->result->update(distance, this->model1, this->model2,
665
                         DistanceResult::NONE, primitive_id, closest_p1,
666
                         closest_p2, normal);
667
  }
668
669
  /// @brief Whether the traversal process can stop early
670
  bool canStop(FCL_REAL c) const {
671
    if ((c >= this->result->min_distance - abs_err) &&
672
        (c * (1 + rel_err) >= this->result->min_distance))
673
      return true;
674
    return false;
675
  }
676
677
  Vec3f* vertices;
678
  Triangle* tri_indices;
679
680
  FCL_REAL rel_err;
681
  FCL_REAL abs_err;
682
683
  const GJKSolver* nsolver;
684
};
685
686
/// @brief Traversal node for distance between shape and mesh, when mesh BVH is
687
/// one of the oriented node (RSS, kIOS, OBBRSS)
688
template <typename S>
689
class ShapeMeshDistanceTraversalNodeRSS
690
    : public ShapeMeshDistanceTraversalNode<S, RSS> {
691
 public:
692
  ShapeMeshDistanceTraversalNodeRSS()
693
      : ShapeMeshDistanceTraversalNode<S, RSS>() {}
694
695
  void preprocess() {
696
    details::distancePreprocessOrientedNode(
697
        this->model2, this->vertices, this->tri_indices, 0, *(this->model1),
698
        this->tf2, this->tf1, this->nsolver, this->request, *(this->result));
699
  }
700
701
  void postprocess() {}
702
703
  FCL_REAL BVDistanceLowerBound(unsigned int /*b1*/, unsigned int b2) const {
704
    if (this->enable_statistics) this->num_bv_tests++;
705
    return distance(this->tf2.getRotation(), this->tf2.getTranslation(),
706
                    this->model1_bv, this->model2->getBV(b2).bv);
707
  }
708
709
  void leafComputeDistance(unsigned int b1, unsigned int b2) const {
710
    details::meshShapeDistanceOrientedNodeleafComputeDistance(
711
        b2, b1, this->model2, *(this->model1), this->vertices,
712
        this->tri_indices, this->tf2, this->tf1, this->nsolver,
713
        this->enable_statistics, this->num_leaf_tests, this->request,
714
        *(this->result));
715
  }
716
};
717
718
template <typename S>
719
class ShapeMeshDistanceTraversalNodekIOS
720
    : public ShapeMeshDistanceTraversalNode<S, kIOS> {
721
 public:
722
  ShapeMeshDistanceTraversalNodekIOS()
723
      : ShapeMeshDistanceTraversalNode<S, kIOS>() {}
724
725
  void preprocess() {
726
    details::distancePreprocessOrientedNode(
727
        this->model2, this->vertices, this->tri_indices, 0, *(this->model1),
728
        this->tf2, this->tf1, this->nsolver, *(this->result));
729
  }
730
731
  void postprocess() {}
732
733
  FCL_REAL BVDistanceLowerBound(unsigned int /*b1*/, unsigned int b2) const {
734
    if (this->enable_statistics) this->num_bv_tests++;
735
    return distance(this->tf2.getRotation(), this->tf2.getTranslation(),
736
                    this->model1_bv, this->model2->getBV(b2).bv);
737
  }
738
739
  void leafComputeDistance(unsigned int b1, unsigned int b2) const {
740
    details::meshShapeDistanceOrientedNodeleafComputeDistance(
741
        b2, b1, this->model2, *(this->model1), this->vertices,
742
        this->tri_indices, this->tf2, this->tf1, this->nsolver,
743
        this->enable_statistics, this->num_leaf_tests, this->request,
744
        *(this->result));
745
  }
746
};
747
748
template <typename S>
749
class ShapeMeshDistanceTraversalNodeOBBRSS
750
    : public ShapeMeshDistanceTraversalNode<S, OBBRSS> {
751
 public:
752
  ShapeMeshDistanceTraversalNodeOBBRSS()
753
      : ShapeMeshDistanceTraversalNode<S, OBBRSS>() {}
754
755
  void preprocess() {
756
    details::distancePreprocessOrientedNode(
757
        this->model2, this->vertices, this->tri_indices, 0, *(this->model1),
758
        this->tf2, this->tf1, this->nsolver, *(this->result));
759
  }
760
761
  void postprocess() {}
762
763
  FCL_REAL BVDistanceLowerBound(unsigned int /*b1*/, unsigned int b2) const {
764
    if (this->enable_statistics) this->num_bv_tests++;
765
    return distance(this->tf2.getRotation(), this->tf2.getTranslation(),
766
                    this->model1_bv, this->model2->getBV(b2).bv);
767
  }
768
769
  void leafComputeDistance(unsigned int b1, unsigned int b2) const {
770
    details::meshShapeDistanceOrientedNodeleafComputeDistance(
771
        b2, b1, this->model2, *(this->model1), this->vertices,
772
        this->tri_indices, this->tf2, this->tf1, this->nsolver,
773
        this->enable_statistics, this->num_leaf_tests, this->request,
774
        *(this->result));
775
  }
776
};
777
778
/// @}
779
780
}  // namespace fcl
781
782
}  // namespace hpp
783
784
/// @endcond
785
786
#endif