GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: include/hpp/fcl/shape/geometric_shapes.h Lines: 244 289 84.4 %
Date: 2024-02-09 12:57:42 Branches: 274 640 42.8 %

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_GEOMETRIC_SHAPES_H
39
#define HPP_FCL_GEOMETRIC_SHAPES_H
40
41
#include <boost/math/constants/constants.hpp>
42
43
#include <hpp/fcl/collision_object.h>
44
#include <hpp/fcl/data_types.h>
45
#include <string.h>
46
47
namespace hpp {
48
namespace fcl {
49
50
/// @brief Base class for all basic geometric shapes
51
1
class HPP_FCL_DLLAPI ShapeBase : public CollisionGeometry {
52
 public:
53
116887093
  ShapeBase() {}
54
55
  ///  \brief Copy constructor
56
36
  ShapeBase(const ShapeBase& other) : CollisionGeometry(other) {}
57
58
  ShapeBase& operator=(const ShapeBase& other) = default;
59
60
233774126
  virtual ~ShapeBase(){};
61
62
  /// @brief Get object type: a geometric shape
63
2480222
  OBJECT_TYPE getObjectType() const { return OT_GEOM; }
64
};
65
66
/// @defgroup Geometric_Shapes Geometric shapes
67
/// Classes of different types of geometric shapes.
68
/// @{
69
70
/// @brief Triangle stores the points instead of only indices of points
71
class HPP_FCL_DLLAPI TriangleP : public ShapeBase {
72
 public:
73
  TriangleP(){};
74
75
116806559
  TriangleP(const Vec3f& a_, const Vec3f& b_, const Vec3f& c_)
76

116806559
      : ShapeBase(), a(a_), b(b_), c(c_) {}
77
78
  TriangleP(const TriangleP& other)
79
      : ShapeBase(other), a(other.a), b(other.b), c(other.c) {}
80
81
  /// @brief Clone *this into a new TriangleP
82
  virtual TriangleP* clone() const { return new TriangleP(*this); };
83
84
  /// @brief virtual function of compute AABB in local coordinate
85
  void computeLocalAABB();
86
87
87614083
  NODE_TYPE getNodeType() const { return GEOM_TRIANGLE; }
88
89
  //  std::pair<ShapeBase*, Transform3f> inflated(const FCL_REAL value) const {
90
  //    if (value == 0) return std::make_pair(new TriangleP(*this),
91
  //    Transform3f()); Vec3f AB(b - a), BC(c - b), CA(a - c); AB.normalize();
92
  //    BC.normalize();
93
  //    CA.normalize();
94
  //
95
  //    Vec3f new_a(a + value * Vec3f(-AB + CA).normalized());
96
  //    Vec3f new_b(b + value * Vec3f(-BC + AB).normalized());
97
  //    Vec3f new_c(c + value * Vec3f(-CA + BC).normalized());
98
  //
99
  //    return std::make_pair(new TriangleP(new_a, new_b, new_c),
100
  //    Transform3f());
101
  //  }
102
  //
103
  //  FCL_REAL minInflationValue() const
104
  //  {
105
  //    return (std::numeric_limits<FCL_REAL>::max)(); // TODO(jcarpent):
106
  //    implement
107
  //  }
108
109
  Vec3f a, b, c;
110
111
 private:
112
6
  virtual bool isEqual(const CollisionGeometry& _other) const {
113
6
    const TriangleP* other_ptr = dynamic_cast<const TriangleP*>(&_other);
114
6
    if (other_ptr == nullptr) return false;
115
6
    const TriangleP& other = *other_ptr;
116
117

6
    return a == other.a && b == other.b && c == other.c;
118
  }
119
120
 public:
121
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
122
};
123
124
/// @brief Center at zero point, axis aligned box
125
class HPP_FCL_DLLAPI Box : public ShapeBase {
126
 public:
127
7753
  Box(FCL_REAL x, FCL_REAL y, FCL_REAL z)
128
7753
      : ShapeBase(), halfSide(x / 2, y / 2, z / 2) {}
129
130

1821
  Box(const Vec3f& side_) : ShapeBase(), halfSide(side_ / 2) {}
131
132
5
  Box(const Box& other) : ShapeBase(other), halfSide(other.halfSide) {}
133
134
1581
  Box& operator=(const Box& other) {
135
1581
    if (this == &other) return *this;
136
137
1581
    this->halfSide = other.halfSide;
138
1581
    return *this;
139
  }
140
141
  /// @brief Clone *this into a new Box
142
  virtual Box* clone() const { return new Box(*this); };
143
144
  /// @brief Default constructor
145
1582
  Box() {}
146
147
  /// @brief box side half-length
148
  Vec3f halfSide;
149
150
  /// @brief Compute AABB
151
  void computeLocalAABB();
152
153
  /// @brief Get node type: a box
154
2663103
  NODE_TYPE getNodeType() const { return GEOM_BOX; }
155
156
4
  FCL_REAL computeVolume() const { return 8 * halfSide.prod(); }
157
158
2
  Matrix3f computeMomentofInertia() const {
159
2
    FCL_REAL V = computeVolume();
160

2
    Vec3f s(halfSide.cwiseAbs2() * V);
161





4
    return (Vec3f(s[1] + s[2], s[0] + s[2], s[0] + s[1]) / 3).asDiagonal();
162
  }
163
164
7
  FCL_REAL minInflationValue() const { return -halfSide.minCoeff(); }
165
166
  /// \brief Inflate the box by an amount given by value
167
  ///
168
  /// \param[in] value of the shape inflation.
169
  ///
170
  /// \returns a new inflated box and the related transform to account for the
171
  /// change of shape frame
172
6
  std::pair<Box, Transform3f> inflated(const FCL_REAL value) const {
173
6
    if (value <= minInflationValue())
174










1
      HPP_FCL_THROW_PRETTY("value (" << value << ") "
175
                                     << "is two small. It should be at least: "
176
                                     << minInflationValue(),
177
                           std::invalid_argument);
178


10
    return std::make_pair(Box(2 * (halfSide + Vec3f::Constant(value))),
179
15
                          Transform3f());
180
  }
181
182
 private:
183
7
  virtual bool isEqual(const CollisionGeometry& _other) const {
184
7
    const Box* other_ptr = dynamic_cast<const Box*>(&_other);
185
7
    if (other_ptr == nullptr) return false;
186
7
    const Box& other = *other_ptr;
187
188
7
    return halfSide == other.halfSide;
189
  }
190
191
 public:
192
23888
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
193
};
194
195
/// @brief Center at zero point sphere
196
class HPP_FCL_DLLAPI Sphere : public ShapeBase {
197
 public:
198
  /// @brief Default constructor
199
1
  Sphere() {}
200
201
5569
  explicit Sphere(FCL_REAL radius_) : ShapeBase(), radius(radius_) {}
202
203
6
  Sphere(const Sphere& other) : ShapeBase(other), radius(other.radius) {}
204
205
  /// @brief Clone *this into a new Sphere
206
  virtual Sphere* clone() const { return new Sphere(*this); };
207
208
  /// @brief Radius of the sphere
209
  FCL_REAL radius;
210
211
  /// @brief Compute AABB
212
  void computeLocalAABB();
213
214
  /// @brief Get node type: a sphere
215
707071
  NODE_TYPE getNodeType() const { return GEOM_SPHERE; }
216
217
2
  Matrix3f computeMomentofInertia() const {
218
2
    FCL_REAL I = 0.4 * radius * radius * computeVolume();
219

4
    return I * Matrix3f::Identity();
220
  }
221
222
4
  FCL_REAL computeVolume() const {
223
4
    return 4 * boost::math::constants::pi<FCL_REAL>() * radius * radius *
224
4
           radius / 3;
225
  }
226
227
8
  FCL_REAL minInflationValue() const { return -radius; }
228
229
  /// \brief Inflate the sphere by an amount given by value
230
  ///
231
  /// \param[in] value of the shape inflation.
232
  ///
233
  /// \returns a new inflated sphere and the related transform to account for
234
  /// the change of shape frame
235
7
  std::pair<Sphere, Transform3f> inflated(const FCL_REAL value) const {
236
7
    if (value <= minInflationValue())
237









1
      HPP_FCL_THROW_PRETTY(
238
          "value (" << value << ") is two small. It should be at least: "
239
                    << minInflationValue(),
240
          std::invalid_argument);
241

12
    return std::make_pair(Sphere(radius + value), Transform3f());
242
  }
243
244
 private:
245
7
  virtual bool isEqual(const CollisionGeometry& _other) const {
246
7
    const Sphere* other_ptr = dynamic_cast<const Sphere*>(&_other);
247
7
    if (other_ptr == nullptr) return false;
248
7
    const Sphere& other = *other_ptr;
249
250
7
    return radius == other.radius;
251
  }
252
253
 public:
254
17808
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
255
};
256
257
/// @brief Ellipsoid centered at point zero
258
class HPP_FCL_DLLAPI Ellipsoid : public ShapeBase {
259
 public:
260
  /// @brief Default constructor
261
1
  Ellipsoid() {}
262
263
19
  Ellipsoid(FCL_REAL rx, FCL_REAL ry, FCL_REAL rz)
264
19
      : ShapeBase(), radii(rx, ry, rz) {}
265
266
5
  explicit Ellipsoid(const Vec3f& radii) : radii(radii) {}
267
268
5
  Ellipsoid(const Ellipsoid& other) : ShapeBase(other), radii(other.radii) {}
269
270
  /// @brief Clone *this into a new Ellipsoid
271
  virtual Ellipsoid* clone() const { return new Ellipsoid(*this); };
272
273
  /// @brief Radii of the Ellipsoid (such that on boundary: x^2/rx^2 + y^2/ry^2
274
  /// + z^2/rz^2 = 1)
275
  Vec3f radii;
276
277
  /// @brief Compute AABB
278
  void computeLocalAABB();
279
280
  /// @brief Get node type: an ellipsoid
281
30005
  NODE_TYPE getNodeType() const { return GEOM_ELLIPSOID; }
282
283
  Matrix3f computeMomentofInertia() const {
284
    FCL_REAL V = computeVolume();
285
    FCL_REAL a2 = V * radii[0] * radii[0];
286
    FCL_REAL b2 = V * radii[1] * radii[1];
287
    FCL_REAL c2 = V * radii[2] * radii[2];
288
    return (Matrix3f() << 0.2 * (b2 + c2), 0, 0, 0, 0.2 * (a2 + c2), 0, 0, 0,
289
            0.2 * (a2 + b2))
290
        .finished();
291
  }
292
293
  FCL_REAL computeVolume() const {
294
    return 4 * boost::math::constants::pi<FCL_REAL>() * radii[0] * radii[1] *
295
           radii[2] / 3;
296
  }
297
298
7
  FCL_REAL minInflationValue() const { return -radii.minCoeff(); }
299
300
  /// \brief Inflate the ellipsoid by an amount given by value
301
  ///
302
  /// \param[in] value of the shape inflation.
303
  ///
304
  /// \returns a new inflated ellipsoid and the related transform to account for
305
  /// the change of shape frame
306
6
  std::pair<Ellipsoid, Transform3f> inflated(const FCL_REAL value) const {
307
6
    if (value <= minInflationValue())
308









1
      HPP_FCL_THROW_PRETTY(
309
          "value (" << value << ") is two small. It should be at least: "
310
                    << minInflationValue(),
311
          std::invalid_argument);
312


10
    return std::make_pair(Ellipsoid(radii + Vec3f::Constant(value)),
313
15
                          Transform3f());
314
  }
315
316
 private:
317
7
  virtual bool isEqual(const CollisionGeometry& _other) const {
318
7
    const Ellipsoid* other_ptr = dynamic_cast<const Ellipsoid*>(&_other);
319
7
    if (other_ptr == nullptr) return false;
320
7
    const Ellipsoid& other = *other_ptr;
321
322
7
    return radii == other.radii;
323
  }
324
325
 public:
326
8
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
327
};
328
329
/// @brief Capsule
330
/// It is \f$ { x~\in~\mathbb{R}^3, d(x, AB) \leq radius } \f$
331
/// where \f$ d(x, AB) \f$ is the distance between the point x and the capsule
332
/// segment AB, with \f$ A = (0,0,-halfLength), B = (0,0,halfLength) \f$.
333
class HPP_FCL_DLLAPI Capsule : public ShapeBase {
334
 public:
335
  /// @brief Default constructor
336
1
  Capsule() {}
337
338
1046
  Capsule(FCL_REAL radius_, FCL_REAL lz_) : ShapeBase(), radius(radius_) {
339
1046
    halfLength = lz_ / 2;
340
1046
  }
341
342
5
  Capsule(const Capsule& other)
343
5
      : ShapeBase(other), radius(other.radius), halfLength(other.halfLength) {}
344
345
  /// @brief Clone *this into a new Capsule
346
  virtual Capsule* clone() const { return new Capsule(*this); };
347
348
  /// @brief Radius of capsule
349
  FCL_REAL radius;
350
351
  /// @brief Half Length along z axis
352
  FCL_REAL halfLength;
353
354
  /// @brief Compute AABB
355
  void computeLocalAABB();
356
357
  /// @brief Get node type: a capsule
358
32264
  NODE_TYPE getNodeType() const { return GEOM_CAPSULE; }
359
360
2
  FCL_REAL computeVolume() const {
361
2
    return boost::math::constants::pi<FCL_REAL>() * radius * radius *
362
2
           ((halfLength * 2) + radius * 4 / 3.0);
363
  }
364
365
2
  Matrix3f computeMomentofInertia() const {
366
2
    FCL_REAL v_cyl = radius * radius * (halfLength * 2) *
367
2
                     boost::math::constants::pi<FCL_REAL>();
368
4
    FCL_REAL v_sph = radius * radius * radius *
369
2
                     boost::math::constants::pi<FCL_REAL>() * 4 / 3.0;
370
371
2
    FCL_REAL h2 = halfLength * halfLength;
372
2
    FCL_REAL r2 = radius * radius;
373
2
    FCL_REAL ix = v_cyl * (h2 / 3. + r2 / 4.) +
374
2
                  v_sph * (0.4 * r2 + h2 + 0.75 * radius * halfLength);
375
2
    FCL_REAL iz = (0.5 * v_cyl + 0.4 * v_sph) * radius * radius;
376
377






4
    return (Matrix3f() << ix, 0, 0, 0, ix, 0, 0, 0, iz).finished();
378
  }
379
380
7
  FCL_REAL minInflationValue() const { return -radius; }
381
382
  /// \brief Inflate the capsule by an amount given by value
383
  ///
384
  /// \param[in] value of the shape inflation.
385
  ///
386
  /// \returns a new inflated capsule and the related transform to account for
387
  /// the change of shape frame
388
6
  std::pair<Capsule, Transform3f> inflated(const FCL_REAL value) const {
389
6
    if (value <= minInflationValue())
390









1
      HPP_FCL_THROW_PRETTY(
391
          "value (" << value << ") is two small. It should be at least: "
392
                    << minInflationValue(),
393
          std::invalid_argument);
394
10
    return std::make_pair(Capsule(radius + value, 2 * halfLength),
395
15
                          Transform3f());
396
  }
397
398
 private:
399
7
  virtual bool isEqual(const CollisionGeometry& _other) const {
400
7
    const Capsule* other_ptr = dynamic_cast<const Capsule*>(&_other);
401
7
    if (other_ptr == nullptr) return false;
402
7
    const Capsule& other = *other_ptr;
403
404

7
    return radius == other.radius && halfLength == other.halfLength;
405
  }
406
407
 public:
408
88
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
409
};
410
411
/// @brief Cone
412
/// The base of the cone is at \f$ z = - halfLength \f$ and the top is at
413
/// \f$ z = halfLength \f$.
414
class HPP_FCL_DLLAPI Cone : public ShapeBase {
415
 public:
416
  /// @brief Default constructor
417
  Cone() {}
418
419
1022
  Cone(FCL_REAL radius_, FCL_REAL lz_) : ShapeBase(), radius(radius_) {
420
1022
    halfLength = lz_ / 2;
421
1022
  }
422
423
5
  Cone(const Cone& other)
424
5
      : ShapeBase(other), radius(other.radius), halfLength(other.halfLength) {}
425
426
  /// @brief Clone *this into a new Cone
427
  virtual Cone* clone() const { return new Cone(*this); };
428
429
  /// @brief Radius of the cone
430
  FCL_REAL radius;
431
432
  /// @brief Half Length along z axis
433
  FCL_REAL halfLength;
434
435
  /// @brief Compute AABB
436
  void computeLocalAABB();
437
438
  /// @brief Get node type: a cone
439
1355
  NODE_TYPE getNodeType() const { return GEOM_CONE; }
440
441
4
  FCL_REAL computeVolume() const {
442
4
    return boost::math::constants::pi<FCL_REAL>() * radius * radius *
443
4
           (halfLength * 2) / 3;
444
  }
445
446
2
  Matrix3f computeMomentofInertia() const {
447
2
    FCL_REAL V = computeVolume();
448
2
    FCL_REAL ix =
449
2
        V * (0.4 * halfLength * halfLength + 3 * radius * radius / 20);
450
2
    FCL_REAL iz = 0.3 * V * radius * radius;
451
452






4
    return (Matrix3f() << ix, 0, 0, 0, ix, 0, 0, 0, iz).finished();
453
  }
454
455
2
  Vec3f computeCOM() const { return Vec3f(0, 0, -0.5 * halfLength); }
456
457
7
  FCL_REAL minInflationValue() const { return -(std::min)(radius, halfLength); }
458
459
  /// \brief Inflate the cone by an amount given by value
460
  ///
461
  /// \param[in] value of the shape inflation.
462
  ///
463
  /// \returns a new inflated cone and the related transform to account for the
464
  /// change of shape frame
465
6
  std::pair<Cone, Transform3f> inflated(const FCL_REAL value) const {
466

6
    if (value <= minInflationValue())
467









1
      HPP_FCL_THROW_PRETTY(
468
          "value (" << value << ") is two small. It should be at least: "
469
                    << minInflationValue(),
470
          std::invalid_argument);
471
472
    // tan(alpha) = 2*halfLength/radius;
473
5
    const FCL_REAL tan_alpha = 2 * halfLength / radius;
474
5
    const FCL_REAL sin_alpha = tan_alpha / std::sqrt(1 + tan_alpha * tan_alpha);
475
5
    const FCL_REAL top_inflation = value / sin_alpha;
476
5
    const FCL_REAL bottom_inflation = value;
477
478
5
    const FCL_REAL new_lz = 2 * halfLength + top_inflation + bottom_inflation;
479
5
    const FCL_REAL new_cz = (top_inflation + bottom_inflation) / 2.;
480
5
    const FCL_REAL new_radius = new_lz / tan_alpha;
481
482
10
    return std::make_pair(Cone(new_radius, new_lz),
483

15
                          Transform3f(Vec3f(0., 0., new_cz)));
484
  }
485
486
 private:
487
6
  virtual bool isEqual(const CollisionGeometry& _other) const {
488
6
    const Cone* other_ptr = dynamic_cast<const Cone*>(&_other);
489
6
    if (other_ptr == nullptr) return false;
490
6
    const Cone& other = *other_ptr;
491
492

6
    return radius == other.radius && halfLength == other.halfLength;
493
  }
494
495
 public:
496
8
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
497
};
498
499
/// @brief Cylinder along Z axis.
500
/// The cylinder is defined at its centroid.
501
class HPP_FCL_DLLAPI Cylinder : public ShapeBase {
502
 public:
503
  /// @brief Default constructor
504
1
  Cylinder() {}
505
506
5529
  Cylinder(FCL_REAL radius_, FCL_REAL lz_) : ShapeBase(), radius(radius_) {
507
5529
    halfLength = lz_ / 2;
508
5529
  }
509
510
5
  Cylinder(const Cylinder& other)
511
5
      : ShapeBase(other), radius(other.radius), halfLength(other.halfLength) {}
512
513
1
  Cylinder& operator=(const Cylinder& other) {
514
1
    if (this == &other) return *this;
515
516
1
    this->radius = other.radius;
517
1
    this->halfLength = other.halfLength;
518
1
    return *this;
519
  }
520
521
  /// @brief Clone *this into a new Cylinder
522
  virtual Cylinder* clone() const { return new Cylinder(*this); };
523
524
  /// @brief Radius of the cylinder
525
  FCL_REAL radius;
526
527
  /// @brief Half Length along z axis
528
  FCL_REAL halfLength;
529
530
  /// @brief Compute AABB
531
  void computeLocalAABB();
532
533
  /// @brief Get node type: a cylinder
534
1406186
  NODE_TYPE getNodeType() const { return GEOM_CYLINDER; }
535
536
4
  FCL_REAL computeVolume() const {
537
4
    return boost::math::constants::pi<FCL_REAL>() * radius * radius *
538
4
           (halfLength * 2);
539
  }
540
541
2
  Matrix3f computeMomentofInertia() const {
542
2
    FCL_REAL V = computeVolume();
543
2
    FCL_REAL ix = V * (radius * radius / 4 + halfLength * halfLength / 3);
544
2
    FCL_REAL iz = V * radius * radius / 2;
545






4
    return (Matrix3f() << ix, 0, 0, 0, ix, 0, 0, 0, iz).finished();
546
  }
547
548
7
  FCL_REAL minInflationValue() const { return -(std::min)(radius, halfLength); }
549
550
  /// \brief Inflate the cylinder by an amount given by value
551
  ///
552
  /// \param[in] value of the shape inflation.
553
  ///
554
  /// \returns a new inflated cylinder and the related transform to account for
555
  /// the change of shape frame
556
6
  std::pair<Cylinder, Transform3f> inflated(const FCL_REAL value) const {
557
6
    if (value <= minInflationValue())
558









1
      HPP_FCL_THROW_PRETTY(
559
          "value (" << value << ") is two small. It should be at least: "
560
                    << minInflationValue(),
561
          std::invalid_argument);
562
10
    return std::make_pair(Cylinder(radius + value, 2 * (halfLength + value)),
563
15
                          Transform3f());
564
  }
565
566
 private:
567
7
  virtual bool isEqual(const CollisionGeometry& _other) const {
568
7
    const Cylinder* other_ptr = dynamic_cast<const Cylinder*>(&_other);
569
7
    if (other_ptr == nullptr) return false;
570
7
    const Cylinder& other = *other_ptr;
571
572

7
    return radius == other.radius && halfLength == other.halfLength;
573
  }
574
575
 public:
576
17780
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
577
};
578
579
/// @brief Base for convex polytope.
580
/// @note Inherited classes are responsible for filling ConvexBase::neighbors;
581
class HPP_FCL_DLLAPI ConvexBase : public ShapeBase {
582
 public:
583
  /// @brief Build a convex hull based on Qhull library
584
  /// and store the vertices and optionally the triangles
585
  /// \param points, num_points the points whose convex hull should be computed.
586
  /// \param keepTriangles if \c true, returns a Convex<Triangle> object which
587
  ///        contains the triangle of the shape.
588
  /// \param qhullCommand the command sent to qhull.
589
  ///        - if \c keepTriangles is \c true, this parameter should include
590
  ///          "Qt". If \c NULL, "Qt" is passed to Qhull.
591
  ///        - if \c keepTriangles is \c false, an empty string is passed to
592
  ///          Qhull.
593
  /// \note hpp-fcl must have been compiled with option \c HPP_FCL_HAS_QHULL set
594
  ///       to \c ON.
595
  static ConvexBase* convexHull(const Vec3f* points, unsigned int num_points,
596
                                bool keepTriangles,
597
                                const char* qhullCommand = NULL);
598
599
  virtual ~ConvexBase();
600
601
  ///  @brief Clone (deep copy).
602
  virtual ConvexBase* clone() const {
603
    ConvexBase* copy_ptr = new ConvexBase(*this);
604
    ConvexBase& copy = *copy_ptr;
605
606
    if (!copy.own_storage_) {
607
      copy.points = new Vec3f[copy.num_points];
608
      std::copy(points, points + num_points, copy.points);
609
    }
610
    copy.own_storage_ = true;
611
    copy.ShapeBase::operator=(*this);
612
613
    return copy_ptr;
614
  }
615
616
  /// @brief Compute AABB
617
  void computeLocalAABB();
618
619
  /// @brief Get node type: a conex polytope
620
147363
  NODE_TYPE getNodeType() const { return GEOM_CONVEX; }
621
622
  /// @brief An array of the points of the polygon.
623
  Vec3f* points;
624
  unsigned int num_points;
625
626
  struct HPP_FCL_DLLAPI Neighbors {
627
    unsigned char count_;
628
    unsigned int* n_;
629
630
8
    unsigned char const& count() const { return count_; }
631
24
    unsigned int& operator[](int i) {
632
24
      assert(i < count_);
633
24
      return n_[i];
634
    }
635
    unsigned int const& operator[](int i) const {
636
      assert(i < count_);
637
      return n_[i];
638
    }
639
640
12
    bool operator==(const Neighbors& other) const {
641
12
      if (count_ != other.count_) return false;
642
643
60
      for (int i = 0; i < count_; ++i) {
644
48
        if (n_[i] != other.n_[i]) return false;
645
      }
646
647
12
      return true;
648
    }
649
650
12
    bool operator!=(const Neighbors& other) const { return !(*this == other); }
651
  };
652
  /// Neighbors of each vertex.
653
  /// It is an array of size num_points. For each vertex, it contains the number
654
  /// of neighbors and a list of indices to them.
655
  Neighbors* neighbors;
656
657
  /// @brief center of the convex polytope, this is used for collision: center
658
  /// is guaranteed in the internal of the polytope (as it is convex)
659
  Vec3f center;
660
661
 protected:
662
  /// @brief Construct an uninitialized convex object
663
  /// Initialization is done with ConvexBase::initialize.
664
55674
  ConvexBase()
665
55674
      : ShapeBase(),
666
        points(NULL),
667
        num_points(0),
668
        neighbors(NULL),
669
        nneighbors_(NULL),
670
55674
        own_storage_(false) {}
671
672
  /// @brief Initialize the points of the convex shape
673
  /// This also initializes the ConvexBase::center.
674
  ///
675
  /// \param ownStorage weither the ConvexBase owns the data.
676
  /// \param points_ list of 3D points  ///
677
  /// \param num_points_ number of 3D points
678
  void initialize(bool ownStorage, Vec3f* points_, unsigned int num_points_);
679
680
  /// @brief Set the points of the convex shape.
681
  ///
682
  /// \param ownStorage weither the ConvexBase owns the data.
683
  /// \param points_ list of 3D points  ///
684
  /// \param num_points_ number of 3D points
685
  void set(bool ownStorage, Vec3f* points_, unsigned int num_points_);
686
687
  /// @brief Copy constructor
688
  /// Only the list of neighbors is copied.
689
  ConvexBase(const ConvexBase& other);
690
691
  unsigned int* nneighbors_;
692
693
  bool own_storage_;
694
695
 private:
696
  void computeCenter();
697
698
 private:
699
2
  virtual bool isEqual(const CollisionGeometry& _other) const {
700
2
    const ConvexBase* other_ptr = dynamic_cast<const ConvexBase*>(&_other);
701
2
    if (other_ptr == nullptr) return false;
702
2
    const ConvexBase& other = *other_ptr;
703
704
2
    if (num_points != other.num_points) return false;
705
706
14
    for (unsigned int i = 0; i < num_points; ++i) {
707
12
      if (points[i] != other.points[i]) return false;
708
    }
709
710
14
    for (unsigned int i = 0; i < num_points; ++i) {
711
12
      if (neighbors[i] != other.neighbors[i]) return false;
712
    }
713
714
2
    return center == other.center;
715
  }
716
717
 public:
718
28
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
719
};
720
721
template <typename PolygonT>
722
class Convex;
723
724
/// @brief Half Space: this is equivalent to the Plane in ODE. The separation
725
/// plane is defined as n * x = d; Points in the negative side of the separation
726
/// plane (i.e. {x | n * x < d}) are inside the half space and points in the
727
/// positive side of the separation plane (i.e. {x | n * x > d}) are outside the
728
/// half space
729
class HPP_FCL_DLLAPI Halfspace : public ShapeBase {
730
 public:
731
  /// @brief Construct a half space with normal direction and offset
732
258
  Halfspace(const Vec3f& n_, FCL_REAL d_) : ShapeBase(), n(n_), d(d_) {
733
258
    unitNormalTest();
734
258
  }
735
736
  /// @brief Construct a plane with normal direction and offset
737
  Halfspace(FCL_REAL a, FCL_REAL b, FCL_REAL c, FCL_REAL d_)
738
      : ShapeBase(), n(a, b, c), d(d_) {
739
    unitNormalTest();
740
  }
741
742
1
  Halfspace() : ShapeBase(), n(1, 0, 0), d(0) {}
743
744
5
  Halfspace(const Halfspace& other)
745
5
      : ShapeBase(other), n(other.n), d(other.d) {}
746
747
  /// @brief operator =
748
6
  Halfspace& operator=(const Halfspace& other) {
749
6
    n = other.n;
750
6
    d = other.d;
751
6
    return *this;
752
  }
753
754
  /// @brief Clone *this into a new Halfspace
755
  virtual Halfspace* clone() const { return new Halfspace(*this); };
756
757
278
  FCL_REAL signedDistance(const Vec3f& p) const { return n.dot(p) - d; }
758
759
  FCL_REAL distance(const Vec3f& p) const { return std::abs(n.dot(p) - d); }
760
761
  /// @brief Compute AABB
762
  void computeLocalAABB();
763
764
  /// @brief Get node type: a half space
765
226
  NODE_TYPE getNodeType() const { return GEOM_HALFSPACE; }
766
767
5
  FCL_REAL minInflationValue() const {
768
5
    return std::numeric_limits<FCL_REAL>::lowest();
769
  }
770
771
  /// \brief Inflate the cylinder by an amount given by value
772
  ///
773
  /// \param[in] value of the shape inflation.
774
  ///
775
  /// \returns a new inflated cylinder and the related transform to account for
776
  /// the change of shape frame
777
5
  std::pair<Halfspace, Transform3f> inflated(const FCL_REAL value) const {
778
5
    if (value <= minInflationValue())
779
      HPP_FCL_THROW_PRETTY(
780
          "value (" << value << ") is two small. It should be at least: "
781
                    << minInflationValue(),
782
          std::invalid_argument);
783

10
    return std::make_pair(Halfspace(n, d + value), Transform3f());
784
  }
785
786
  /// @brief Plane normal
787
  Vec3f n;
788
789
  /// @brief Plane offset
790
  FCL_REAL d;
791
792
 protected:
793
  /// @brief Turn non-unit normal into unit
794
  void unitNormalTest();
795
796
 private:
797
7
  virtual bool isEqual(const CollisionGeometry& _other) const {
798
7
    const Halfspace* other_ptr = dynamic_cast<const Halfspace*>(&_other);
799
7
    if (other_ptr == nullptr) return false;
800
7
    const Halfspace& other = *other_ptr;
801
802

7
    return n == other.n && d == other.d;
803
  }
804
805
 public:
806
12
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
807
};
808
809
/// @brief Infinite plane
810
class HPP_FCL_DLLAPI Plane : public ShapeBase {
811
 public:
812
  /// @brief Construct a plane with normal direction and offset
813
250
  Plane(const Vec3f& n_, FCL_REAL d_) : ShapeBase(), n(n_), d(d_) {
814
250
    unitNormalTest();
815
250
  }
816
817
  /// @brief Construct a plane with normal direction and offset
818
  Plane(FCL_REAL a, FCL_REAL b, FCL_REAL c, FCL_REAL d_)
819
      : ShapeBase(), n(a, b, c), d(d_) {
820
    unitNormalTest();
821
  }
822
823
1
  Plane() : ShapeBase(), n(1, 0, 0), d(0) {}
824
825
  Plane(const Plane& other) : ShapeBase(other), n(other.n), d(other.d) {}
826
827
  /// @brief operator =
828
6
  Plane& operator=(const Plane& other) {
829
6
    n = other.n;
830
6
    d = other.d;
831
6
    return *this;
832
  }
833
834
  /// @brief Clone *this into a new Plane
835
  virtual Plane* clone() const { return new Plane(*this); };
836
837
389
  FCL_REAL signedDistance(const Vec3f& p) const { return n.dot(p) - d; }
838
839
8
  FCL_REAL distance(const Vec3f& p) const { return std::abs(n.dot(p) - d); }
840
841
  /// @brief Compute AABB
842
  void computeLocalAABB();
843
844
  /// @brief Get node type: a plane
845
222
  NODE_TYPE getNodeType() const { return GEOM_PLANE; }
846
847
  /// @brief Plane normal
848
  Vec3f n;
849
850
  /// @brief Plane offset
851
  FCL_REAL d;
852
853
 protected:
854
  /// @brief Turn non-unit normal into unit
855
  void unitNormalTest();
856
857
 private:
858
7
  virtual bool isEqual(const CollisionGeometry& _other) const {
859
7
    const Plane* other_ptr = dynamic_cast<const Plane*>(&_other);
860
7
    if (other_ptr == nullptr) return false;
861
7
    const Plane& other = *other_ptr;
862
863

7
    return n == other.n && d == other.d;
864
  }
865
866
 public:
867
8
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
868
};
869
870
}  // namespace fcl
871
872
}  // namespace hpp
873
874
#endif