GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: include/hpp/fcl/BVH/BVH_model.h Lines: 28 73 38.4 %
Date: 2024-02-09 12:57:42 Branches: 22 144 15.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
 *  Copyright (c) 2020-2022, INRIA
7
 *  All rights reserved.
8
 *
9
 *  Redistribution and use in source and binary forms, with or without
10
 *  modification, are permitted provided that the following conditions
11
 *  are met:
12
 *
13
 *   * Redistributions of source code must retain the above copyright
14
 *     notice, this list of conditions and the following disclaimer.
15
 *   * Redistributions in binary form must reproduce the above
16
 *     copyright notice, this list of conditions and the following
17
 *     disclaimer in the documentation and/or other materials provided
18
 *     with the distribution.
19
 *   * Neither the name of Open Source Robotics Foundation nor the names of its
20
 *     contributors may be used to endorse or promote products derived
21
 *     from this software without specific prior written permission.
22
 *
23
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34
 *  POSSIBILITY OF SUCH DAMAGE.
35
 */
36
37
/** \author Jia Pan */
38
39
#ifndef HPP_FCL_BVH_MODEL_H
40
#define HPP_FCL_BVH_MODEL_H
41
42
#include <hpp/fcl/fwd.hh>
43
#include <hpp/fcl/collision_object.h>
44
#include <hpp/fcl/BVH/BVH_internal.h>
45
#include <hpp/fcl/BV/BV_node.h>
46
#include <vector>
47
48
namespace hpp {
49
namespace fcl {
50
51
/// @addtogroup Construction_Of_BVH
52
/// @{
53
54
class ConvexBase;
55
56
template <typename BV>
57
class BVFitter;
58
template <typename BV>
59
class BVSplitter;
60
61
/// @brief A base class describing the bounding hierarchy of a mesh model or a
62
/// point cloud model (which is viewed as a degraded version of mesh)
63
class HPP_FCL_DLLAPI BVHModelBase : public CollisionGeometry {
64
 public:
65
  /// @brief Geometry point data
66
  Vec3f* vertices;
67
68
  /// @brief Geometry triangle index data, will be NULL for point clouds
69
  Triangle* tri_indices;
70
71
  /// @brief Geometry point data in previous frame
72
  Vec3f* prev_vertices;
73
74
  /// @brief Number of triangles
75
  unsigned int num_tris;
76
77
  /// @brief Number of points
78
  unsigned int num_vertices;
79
80
  /// @brief The state of BVH building process
81
  BVHBuildState build_state;
82
83
  /// @brief Convex<Triangle> representation of this object
84
  shared_ptr<ConvexBase> convex;
85
86
  /// @brief Model type described by the instance
87
2333116
  BVHModelType getModelType() const {
88

2333116
    if (num_tris && num_vertices)
89
2332972
      return BVH_MODEL_TRIANGLES;
90
144
    else if (num_vertices)
91
144
      return BVH_MODEL_POINTCLOUD;
92
    else
93
      return BVH_MODEL_UNKNOWN;
94
  }
95
96
  /// @brief Constructing an empty BVH
97
  BVHModelBase();
98
99
  /// @brief copy from another BVH
100
  BVHModelBase(const BVHModelBase& other);
101
102
  /// @brief deconstruction, delete mesh data related.
103
6154
  virtual ~BVHModelBase() {
104
6154
    delete[] vertices;
105
6154
    delete[] tri_indices;
106
6154
    delete[] prev_vertices;
107
  }
108
109
  /// @brief Get the object type: it is a BVH
110
33582
  OBJECT_TYPE getObjectType() const { return OT_BVH; }
111
112
  /// @brief Compute the AABB for the BVH, used for broad-phase collision
113
  void computeLocalAABB();
114
115
  /// @brief Begin a new BVH model
116
  int beginModel(unsigned int num_tris = 0, unsigned int num_vertices = 0);
117
118
  /// @brief Add one point in the new BVH model
119
  int addVertex(const Vec3f& p);
120
121
  /// @brief Add points in the new BVH model
122
  int addVertices(const Matrixx3f& points);
123
124
  /// @brief Add triangles in the new BVH model
125
  int addTriangles(const Matrixx3i& triangles);
126
127
  /// @brief Add one triangle in the new BVH model
128
  int addTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3);
129
130
  /// @brief Add a set of triangles in the new BVH model
131
  int addSubModel(const std::vector<Vec3f>& ps,
132
                  const std::vector<Triangle>& ts);
133
134
  /// @brief Add a set of points in the new BVH model
135
  int addSubModel(const std::vector<Vec3f>& ps);
136
137
  /// @brief End BVH model construction, will build the bounding volume
138
  /// hierarchy
139
  int endModel();
140
141
  /// @brief Replace the geometry information of current frame (i.e. should have
142
  /// the same mesh topology with the previous frame)
143
  int beginReplaceModel();
144
145
  /// @brief Replace one point in the old BVH model
146
  int replaceVertex(const Vec3f& p);
147
148
  /// @brief Replace one triangle in the old BVH model
149
  int replaceTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3);
150
151
  /// @brief Replace a set of points in the old BVH model
152
  int replaceSubModel(const std::vector<Vec3f>& ps);
153
154
  /// @brief End BVH model replacement, will also refit or rebuild the bounding
155
  /// volume hierarchy
156
  int endReplaceModel(bool refit = true, bool bottomup = true);
157
158
  /// @brief Replace the geometry information of current frame (i.e. should have
159
  /// the same mesh topology with the previous frame). The current frame will be
160
  /// saved as the previous frame in prev_vertices.
161
  int beginUpdateModel();
162
163
  /// @brief Update one point in the old BVH model
164
  int updateVertex(const Vec3f& p);
165
166
  /// @brief Update one triangle in the old BVH model
167
  int updateTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3);
168
169
  /// @brief Update a set of points in the old BVH model
170
  int updateSubModel(const std::vector<Vec3f>& ps);
171
172
  /// @brief End BVH model update, will also refit or rebuild the bounding
173
  /// volume hierarchy
174
  int endUpdateModel(bool refit = true, bool bottomup = true);
175
176
  /// @brief Build this \ref Convex "Convex<Triangle>" representation of this
177
  /// model. The result is stored in attribute \ref convex. \note this only
178
  /// takes the points of this model. It does not check that the
179
  ///       object is convex. It does not compute a convex hull.
180
  void buildConvexRepresentation(bool share_memory);
181
182
  /// @brief Build a convex hull
183
  /// and store it in attribute \ref convex.
184
  /// \param keepTriangle whether the convex should be triangulated.
185
  /// \param qhullCommand see \ref ConvexBase::convexHull.
186
  /// \return \c true if this object is convex, hence the convex hull represents
187
  ///         the same object.
188
  /// \sa ConvexBase::convexHull
189
  /// \warning At the moment, the return value only checks whether there are as
190
  ///          many points in the convex hull as in the original object. This is
191
  ///          neither necessary (duplicated vertices get merged) nor sufficient
192
  ///          (think of a U with 4 vertices and 3 edges).
193
  bool buildConvexHull(bool keepTriangle, const char* qhullCommand = NULL);
194
195
  virtual int memUsage(const bool msg = false) const = 0;
196
197
  /// @brief This is a special acceleration: BVH_model default stores the BV's
198
  /// transform in world coordinate. However, we can also store each BV's
199
  /// transform related to its parent BV node. When traversing the BVH, this can
200
  /// save one matrix transformation.
201
  virtual void makeParentRelative() = 0;
202
203
  Vec3f computeCOM() const {
204
    FCL_REAL vol = 0;
205
    Vec3f com(0, 0, 0);
206
    for (unsigned int i = 0; i < num_tris; ++i) {
207
      const Triangle& tri = tri_indices[i];
208
      FCL_REAL d_six_vol =
209
          (vertices[tri[0]].cross(vertices[tri[1]])).dot(vertices[tri[2]]);
210
      vol += d_six_vol;
211
      com +=
212
          (vertices[tri[0]] + vertices[tri[1]] + vertices[tri[2]]) * d_six_vol;
213
    }
214
215
    return com / (vol * 4);
216
  }
217
218
  FCL_REAL computeVolume() const {
219
    FCL_REAL vol = 0;
220
    for (unsigned int i = 0; i < num_tris; ++i) {
221
      const Triangle& tri = tri_indices[i];
222
      FCL_REAL d_six_vol =
223
          (vertices[tri[0]].cross(vertices[tri[1]])).dot(vertices[tri[2]]);
224
      vol += d_six_vol;
225
    }
226
227
    return vol / 6;
228
  }
229
230
  Matrix3f computeMomentofInertia() const {
231
    Matrix3f C = Matrix3f::Zero();
232
233
    Matrix3f C_canonical;
234
    C_canonical << 1 / 60.0, 1 / 120.0, 1 / 120.0, 1 / 120.0, 1 / 60.0,
235
        1 / 120.0, 1 / 120.0, 1 / 120.0, 1 / 60.0;
236
237
    for (unsigned int i = 0; i < num_tris; ++i) {
238
      const Triangle& tri = tri_indices[i];
239
      const Vec3f& v1 = vertices[tri[0]];
240
      const Vec3f& v2 = vertices[tri[1]];
241
      const Vec3f& v3 = vertices[tri[2]];
242
      Matrix3f A;
243
      A << v1.transpose(), v2.transpose(), v3.transpose();
244
      C += A.derived().transpose() * C_canonical * A * (v1.cross(v2)).dot(v3);
245
    }
246
247
    return C.trace() * Matrix3f::Identity() - C;
248
  }
249
250
 protected:
251
  virtual void deleteBVs() = 0;
252
  virtual bool allocateBVs() = 0;
253
254
  /// @brief Build the bounding volume hierarchy
255
  virtual int buildTree() = 0;
256
257
  /// @brief Refit the bounding volume hierarchy
258
  virtual int refitTree(bool bottomup) = 0;
259
260
  unsigned int num_tris_allocated;
261
  unsigned int num_vertices_allocated;
262
  unsigned int num_vertex_updated;  /// for ccd vertex update
263
264
 protected:
265
  /// \brief Comparison operators
266
  virtual bool isEqual(const CollisionGeometry& other) const;
267
};
268
269
/// @brief A class describing the bounding hierarchy of a mesh model or a point
270
/// cloud model (which is viewed as a degraded version of mesh) \tparam BV one
271
/// of the bounding volume class in \ref Bounding_Volume.
272
template <typename BV>
273
class HPP_FCL_DLLAPI BVHModel : public BVHModelBase {
274
  typedef BVHModelBase Base;
275
276
 public:
277
  /// @brief Split rule to split one BV node into two children
278
  shared_ptr<BVSplitter<BV> > bv_splitter;
279
280
  /// @brief Fitting rule to fit a BV node to a set of geometry primitives
281
  shared_ptr<BVFitter<BV> > bv_fitter;
282
283
  /// @brief Default constructor to build an empty BVH
284
  BVHModel();
285
286
  /// @brief Copy constructor from another BVH
287
  ///
288
  /// \param[in] other BVHModel to copy.
289
  ///
290
  BVHModel(const BVHModel& other);
291
292
  /// @brief Clone *this into a new BVHModel
293
  virtual BVHModel<BV>* clone() const { return new BVHModel(*this); }
294
295
  /// @brief deconstruction, delete mesh data related.
296
11742
  ~BVHModel() {
297
6140
    delete[] bvs;
298
6154
    delete[] primitive_indices;
299
17896
  }
300
301
  /// @brief We provide getBV() and getNumBVs() because BVH may be compressed
302
  /// (in future), so we must provide some flexibility here
303
304
  /// @brief Access the bv giving the its index
305
639671336
  const BVNode<BV>& getBV(unsigned int i) const {
306
639671336
    assert(i < num_bvs);
307
639671336
    return bvs[i];
308
  }
309
310
  /// @brief Access the bv giving the its index
311
  BVNode<BV>& getBV(unsigned int i) {
312
    assert(i < num_bvs);
313
    return bvs[i];
314
  }
315
316
  /// @brief Get the number of bv in the BVH
317
32
  unsigned int getNumBVs() const { return num_bvs; }
318
319
  /// @brief Get the BV type: default is unknown
320
  NODE_TYPE getNodeType() const { return BV_UNKNOWN; }
321
322
  /// @brief Check the number of memory used
323
  int memUsage(const bool msg) const;
324
325
  /// @brief This is a special acceleration: BVH_model default stores the BV's
326
  /// transform in world coordinate. However, we can also store each BV's
327
  /// transform related to its parent BV node. When traversing the BVH, this can
328
  /// save one matrix transformation.
329
  void makeParentRelative() {
330
    Matrix3f I(Matrix3f::Identity());
331
    makeParentRelativeRecurse(0, I, Vec3f::Zero());
332
  }
333
334
 protected:
335
  void deleteBVs();
336
  bool allocateBVs();
337
338
  unsigned int num_bvs_allocated;
339
  unsigned int* primitive_indices;
340
341
  /// @brief Bounding volume hierarchy
342
  BVNode<BV>* bvs;
343
344
  /// @brief Number of BV nodes in bounding volume hierarchy
345
  unsigned int num_bvs;
346
347
  /// @brief Build the bounding volume hierarchy
348
  int buildTree();
349
350
  /// @brief Refit the bounding volume hierarchy
351
  int refitTree(bool bottomup);
352
353
  /// @brief Refit the bounding volume hierarchy in a top-down way (slow but
354
  /// more compact)
355
  int refitTree_topdown();
356
357
  /// @brief Refit the bounding volume hierarchy in a bottom-up way (fast but
358
  /// less compact)
359
  int refitTree_bottomup();
360
361
  /// @brief Recursive kernel for hierarchy construction
362
  int recursiveBuildTree(int bv_id, unsigned int first_primitive,
363
                         unsigned int num_primitives);
364
365
  /// @brief Recursive kernel for bottomup refitting
366
  int recursiveRefitTree_bottomup(int bv_id);
367
368
  /// @ recursively compute each bv's transform related to its parent. For
369
  /// default BV, only the translation works. For oriented BV (OBB, RSS,
370
  /// OBBRSS), special implementation is provided.
371
  void makeParentRelativeRecurse(int bv_id, Matrix3f& parent_axes,
372
                                 const Vec3f& parent_c) {
373
    if (!bvs[bv_id].isLeaf()) {
374
      makeParentRelativeRecurse(bvs[bv_id].first_child, parent_axes,
375
                                bvs[bv_id].getCenter());
376
377
      makeParentRelativeRecurse(bvs[bv_id].first_child + 1, parent_axes,
378
                                bvs[bv_id].getCenter());
379
    }
380
381
    bvs[bv_id].bv = translate(bvs[bv_id].bv, -parent_c);
382
  }
383
384
 private:
385
11
  virtual bool isEqual(const CollisionGeometry& _other) const {
386
11
    const BVHModel* other_ptr = dynamic_cast<const BVHModel*>(&_other);
387
11
    if (other_ptr == nullptr) return false;
388
11
    const BVHModel& other = *other_ptr;
389
390
11
    bool res = Base::isEqual(other);
391
11
    if (!res) return false;
392
393
    // unsigned int other_num_primitives = 0;
394
    // if(other.primitive_indices)
395
    // {
396
397
    //   switch(other.getModelType())
398
    //   {
399
    //     case BVH_MODEL_TRIANGLES:
400
    //       other_num_primitives = num_tris;
401
    //       break;
402
    //     case BVH_MODEL_POINTCLOUD:
403
    //       other_num_primitives = num_vertices;
404
    //       break;
405
    //     default:
406
    //       ;
407
    //   }
408
    // }
409
410
    //    unsigned int num_primitives = 0;
411
    //    if(primitive_indices)
412
    //    {
413
    //
414
    //      switch(other.getModelType())
415
    //      {
416
    //        case BVH_MODEL_TRIANGLES:
417
    //          num_primitives = num_tris;
418
    //          break;
419
    //        case BVH_MODEL_POINTCLOUD:
420
    //          num_primitives = num_vertices;
421
    //          break;
422
    //        default:
423
    //          ;
424
    //      }
425
    //    }
426
    //
427
    //    if(num_primitives != other_num_primitives)
428
    //      return false;
429
    //
430
    //    for(int k = 0; k < num_primitives; ++k)
431
    //    {
432
    //      if(primitive_indices[k] != other.primitive_indices[k])
433
    //        return false;
434
    //    }
435
436
10
    if (num_bvs != other.num_bvs) return false;
437
438
39672
    for (unsigned int k = 0; k < num_bvs; ++k) {
439
39662
      if (bvs[k] != other.bvs[k]) return false;
440
    }
441
442
10
    return true;
443
  }
444
};
445
446
/// @}
447
448
template <>
449
void BVHModel<OBB>::makeParentRelativeRecurse(int bv_id, Matrix3f& parent_axes,
450
                                              const Vec3f& parent_c);
451
452
template <>
453
void BVHModel<RSS>::makeParentRelativeRecurse(int bv_id, Matrix3f& parent_axes,
454
                                              const Vec3f& parent_c);
455
456
template <>
457
void BVHModel<OBBRSS>::makeParentRelativeRecurse(int bv_id,
458
                                                 Matrix3f& parent_axes,
459
                                                 const Vec3f& parent_c);
460
461
/// @brief Specialization of getNodeType() for BVHModel with different BV types
462
template <>
463
NODE_TYPE BVHModel<AABB>::getNodeType() const;
464
465
template <>
466
NODE_TYPE BVHModel<OBB>::getNodeType() const;
467
468
template <>
469
NODE_TYPE BVHModel<RSS>::getNodeType() const;
470
471
template <>
472
NODE_TYPE BVHModel<kIOS>::getNodeType() const;
473
474
template <>
475
NODE_TYPE BVHModel<OBBRSS>::getNodeType() const;
476
477
template <>
478
NODE_TYPE BVHModel<KDOP<16> >::getNodeType() const;
479
480
template <>
481
NODE_TYPE BVHModel<KDOP<18> >::getNodeType() const;
482
483
template <>
484
NODE_TYPE BVHModel<KDOP<24> >::getNodeType() const;
485
486
}  // namespace fcl
487
488
}  // namespace hpp
489
490
#endif