GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: test/capsule_capsule.cpp Lines: 190 192 99.0 %
Date: 2024-02-09 12:57:42 Branches: 552 1092 50.5 %

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 Karsten Knese <Karsten.Knese@googlemail.com> */
37
38
#define BOOST_TEST_MODULE FCL_CAPSULE_CAPSULE
39
#include <boost/test/included/unit_test.hpp>
40
41
#define CHECK_CLOSE_TO_0(x, eps) BOOST_CHECK_CLOSE((x + 1.0), (1.0), (eps))
42
43
#include <cmath>
44
#include <iostream>
45
#include <hpp/fcl/distance.h>
46
#include <hpp/fcl/collision.h>
47
#include <hpp/fcl/math/transform.h>
48
#include <hpp/fcl/collision.h>
49
#include <hpp/fcl/collision_object.h>
50
#include <hpp/fcl/shape/geometric_shapes.h>
51
52
#include "utility.h"
53
54
using namespace hpp::fcl;
55
56
















4
BOOST_AUTO_TEST_CASE(collision_capsule_capsule_trivial) {
57
2
  const double radius = 1.;
58
59

4
  CollisionGeometryPtr_t c1(new Capsule(radius, 0.));
60

4
  CollisionGeometryPtr_t c2(new Capsule(radius, 0.));
61
62

4
  CollisionGeometryPtr_t s1(new Sphere(radius));
63

4
  CollisionGeometryPtr_t s2(new Sphere(radius));
64
65
#ifndef NDEBUG
66
2
  int num_tests = 1e3;
67
#else
68
  int num_tests = 1e6;
69
#endif
70
71
2
  Transform3f tf1;
72
2
  Transform3f tf2;
73
74
2002
  for (int i = 0; i < num_tests; ++i) {
75

2000
    Eigen::Vector3d p1 = Eigen::Vector3d::Random() * (2. * radius);
76

2000
    Eigen::Vector3d p2 = Eigen::Vector3d::Random() * (2. * radius);
77
78
    Eigen::Matrix3d rot1 =
79

2000
        Eigen::Quaterniond(Eigen::Vector4d::Random().normalized())
80
2000
            .toRotationMatrix();
81
    Eigen::Matrix3d rot2 =
82

2000
        Eigen::Quaterniond(Eigen::Vector4d::Random().normalized())
83
2000
            .toRotationMatrix();
84
85
2000
    tf1.setTranslation(p1);
86
2000
    tf1.setRotation(rot1);
87
2000
    tf2.setTranslation(p2);
88
2000
    tf2.setRotation(rot2);
89
90
4000
    CollisionObject capsule_o1(c1, tf1);
91
4000
    CollisionObject capsule_o2(c2, tf2);
92
93
4000
    CollisionObject sphere_o1(s1, tf1);
94
4000
    CollisionObject sphere_o2(s2, tf2);
95
96
    // Enable computation of nearest points
97
2000
    CollisionRequest collisionRequest;
98

4000
    CollisionResult capsule_collisionResult, sphere_collisionResult;
99
100
2000
    size_t sphere_num_collisions = collide(
101
2000
        &sphere_o1, &sphere_o2, collisionRequest, sphere_collisionResult);
102
2000
    size_t capsule_num_collisions = collide(
103
2000
        &capsule_o1, &capsule_o2, collisionRequest, capsule_collisionResult);
104
105


2000
    BOOST_CHECK_EQUAL(sphere_num_collisions, capsule_num_collisions);
106

2000
    if (sphere_num_collisions == 0 && capsule_num_collisions == 0)
107



1466
      BOOST_CHECK_CLOSE(sphere_collisionResult.distance_lower_bound,
108
                        capsule_collisionResult.distance_lower_bound, 1e-6);
109
  }
110
2
}
111
112
















4
BOOST_AUTO_TEST_CASE(collision_capsule_capsule_aligned) {
113
2
  const double radius = 0.01;
114
2
  const double length = 0.2;
115
116

4
  CollisionGeometryPtr_t c1(new Capsule(radius, length));
117

4
  CollisionGeometryPtr_t c2(new Capsule(radius, length));
118
#ifndef NDEBUG
119
2
  int num_tests = 1e3;
120
#else
121
  int num_tests = 1e6;
122
#endif
123
124
2
  Transform3f tf1;
125
2
  Transform3f tf2;
126
127

2
  Eigen::Vector3d p1 = Eigen::Vector3d::Zero();
128
  Eigen::Vector3d p2_no_collision =
129
      Eigen::Vector3d(0., 0.,
130
                      2 * (length / 2. + radius) +
131
2
                          1e-3);  // because capsule are along the Z axis
132
133
2002
  for (int i = 0; i < num_tests; ++i) {
134
    Eigen::Matrix3d rot =
135

2000
        Eigen::Quaterniond(Eigen::Vector4d::Random().normalized())
136
2000
            .toRotationMatrix();
137
138
2000
    tf1.setTranslation(p1);
139
2000
    tf1.setRotation(rot);
140
2000
    tf2.setTranslation(p2_no_collision);
141
2000
    tf2.setRotation(rot);
142
143
4000
    CollisionObject capsule_o1(c1, tf1);
144
4000
    CollisionObject capsule_o2(c2, tf2);
145
146
    // Enable computation of nearest points
147
2000
    CollisionRequest collisionRequest;
148
4000
    CollisionResult capsule_collisionResult;
149
150
2000
    size_t capsule_num_collisions = collide(
151
        &capsule_o1, &capsule_o2, collisionRequest, capsule_collisionResult);
152
153



2000
    BOOST_CHECK(capsule_num_collisions == 0);
154
  }
155
156
  Eigen::Vector3d p2_with_collision =
157
2
      Eigen::Vector3d(0., 0., std::min(length / 2., radius) * (1. - 1e-2));
158
2002
  for (int i = 0; i < num_tests; ++i) {
159
    Eigen::Matrix3d rot =
160

2000
        Eigen::Quaterniond(Eigen::Vector4d::Random().normalized())
161
2000
            .toRotationMatrix();
162
163
2000
    tf1.setTranslation(p1);
164
2000
    tf1.setRotation(rot);
165
2000
    tf2.setTranslation(p2_with_collision);
166
2000
    tf2.setRotation(rot);
167
168
4000
    CollisionObject capsule_o1(c1, tf1);
169
4000
    CollisionObject capsule_o2(c2, tf2);
170
171
    // Enable computation of nearest points
172
2000
    CollisionRequest collisionRequest;
173
4000
    CollisionResult capsule_collisionResult;
174
175
2000
    size_t capsule_num_collisions = collide(
176
        &capsule_o1, &capsule_o2, collisionRequest, capsule_collisionResult);
177
178



2000
    BOOST_CHECK(capsule_num_collisions > 0);
179
  }
180
181
2
  p2_no_collision = Eigen::Vector3d(0., 0., 2 * (length / 2. + radius) + 1e-3);
182
183
2
  Transform3f geom1_placement(Eigen::Matrix3d::Identity(),
184

4
                              Eigen::Vector3d::Zero());
185

2
  Transform3f geom2_placement(Eigen::Matrix3d::Identity(), p2_no_collision);
186
187
2002
  for (int i = 0; i < num_tests; ++i) {
188
    Eigen::Matrix3d rot =
189

2000
        Eigen::Quaterniond(Eigen::Vector4d::Random().normalized())
190
2000
            .toRotationMatrix();
191

2000
    Eigen::Vector3d trans = Eigen::Vector3d::Random();
192
193
2000
    Transform3f displacement(rot, trans);
194
2000
    Transform3f tf1 = displacement * geom1_placement;
195
2000
    Transform3f tf2 = displacement * geom2_placement;
196
197
4000
    CollisionObject capsule_o1(c1, tf1);
198
4000
    CollisionObject capsule_o2(c2, tf2);
199
200
    // Enable computation of nearest points
201
2000
    CollisionRequest collisionRequest;
202
4000
    CollisionResult capsule_collisionResult;
203
204
2000
    size_t capsule_num_collisions = collide(
205
        &capsule_o1, &capsule_o2, collisionRequest, capsule_collisionResult);
206
207



2000
    BOOST_CHECK(capsule_num_collisions == 0);
208
  }
209
210
  //  p2_with_collision =
211
  //  Eigen::Vector3d(0.,0.,std::min(length/2.,radius)*(1.-1e-2));
212
2
  p2_with_collision = Eigen::Vector3d(0., 0., 0.01);
213
2
  geom2_placement.setTranslation(p2_with_collision);
214
215
2002
  for (int i = 0; i < num_tests; ++i) {
216
    Eigen::Matrix3d rot =
217

2000
        Eigen::Quaterniond(Eigen::Vector4d::Random().normalized())
218
2000
            .toRotationMatrix();
219

2000
    Eigen::Vector3d trans = Eigen::Vector3d::Random();
220
221
2000
    Transform3f displacement(rot, trans);
222
2000
    Transform3f tf1 = displacement * geom1_placement;
223
2000
    Transform3f tf2 = displacement * geom2_placement;
224
225
4000
    CollisionObject capsule_o1(c1, tf1);
226
4000
    CollisionObject capsule_o2(c2, tf2);
227
228
    // Enable computation of nearest points
229
2000
    CollisionRequest collisionRequest;
230
4000
    CollisionResult capsule_collisionResult;
231
232
2000
    size_t capsule_num_collisions = collide(
233
        &capsule_o1, &capsule_o2, collisionRequest, capsule_collisionResult);
234
235



2000
    BOOST_CHECK(capsule_num_collisions > 0);
236
  }
237
2
}
238
239
















4
BOOST_AUTO_TEST_CASE(distance_capsulecapsule_origin) {
240

4
  CollisionGeometryPtr_t s1(new Capsule(5, 10));
241

4
  CollisionGeometryPtr_t s2(new Capsule(5, 10));
242
243
2
  Transform3f tf1;
244

2
  Transform3f tf2(Vec3f(20.1, 0, 0));
245
246
4
  CollisionObject o1(s1, tf1);
247
4
  CollisionObject o2(s2, tf2);
248
249
  // Enable computation of nearest points
250
2
  DistanceRequest distanceRequest(true);
251
2
  DistanceResult distanceResult;
252
253
2
  distance(&o1, &o2, distanceRequest, distanceResult);
254
255
2
  std::cerr << "Applied translation on two capsules";
256

2
  std::cerr << " T1 = " << tf1.getTranslation()
257

2
            << ", T2 = " << tf2.getTranslation() << std::endl;
258

2
  std::cerr << "Closest points: p1 = " << distanceResult.nearest_points[0]
259

2
            << ", p2 = " << distanceResult.nearest_points[1]
260

2
            << ", distance = " << distanceResult.min_distance << std::endl;
261
262



2
  BOOST_CHECK_CLOSE(distanceResult.min_distance, 10.1, 1e-6);
263
2
}
264
265
















4
BOOST_AUTO_TEST_CASE(distance_capsulecapsule_transformXY) {
266

4
  CollisionGeometryPtr_t s1(new Capsule(5, 10));
267

4
  CollisionGeometryPtr_t s2(new Capsule(5, 10));
268
269
2
  Transform3f tf1;
270

2
  Transform3f tf2(Vec3f(20, 20, 0));
271
272
4
  CollisionObject o1(s1, tf1);
273
4
  CollisionObject o2(s2, tf2);
274
275
  // Enable computation of nearest points
276
2
  DistanceRequest distanceRequest(true);
277
2
  DistanceResult distanceResult;
278
279
2
  distance(&o1, &o2, distanceRequest, distanceResult);
280
281
2
  std::cerr << "Applied translation on two capsules";
282

2
  std::cerr << " T1 = " << tf1.getTranslation()
283

2
            << ", T2 = " << tf2.getTranslation() << std::endl;
284

2
  std::cerr << "Closest points: p1 = " << distanceResult.nearest_points[0]
285

2
            << ", p2 = " << distanceResult.nearest_points[1]
286

2
            << ", distance = " << distanceResult.min_distance << std::endl;
287
288
2
  FCL_REAL expected = sqrt(800) - 10;
289



2
  BOOST_CHECK_CLOSE(distanceResult.min_distance, expected, 1e-6);
290
2
}
291
292
















4
BOOST_AUTO_TEST_CASE(distance_capsulecapsule_transformZ) {
293

4
  CollisionGeometryPtr_t s1(new Capsule(5, 10));
294

4
  CollisionGeometryPtr_t s2(new Capsule(5, 10));
295
296
2
  Transform3f tf1;
297

2
  Transform3f tf2(Vec3f(0, 0, 20.1));
298
299
4
  CollisionObject o1(s1, tf1);
300
4
  CollisionObject o2(s2, tf2);
301
302
  // Enable computation of nearest points
303
2
  DistanceRequest distanceRequest(true);
304
2
  DistanceResult distanceResult;
305
306
2
  distance(&o1, &o2, distanceRequest, distanceResult);
307
308
2
  std::cerr << "Applied translation on two capsules";
309

2
  std::cerr << " T1 = " << tf1.getTranslation()
310

2
            << ", T2 = " << tf2.getTranslation() << std::endl;
311

2
  std::cerr << "Closest points: p1 = " << distanceResult.nearest_points[0]
312

2
            << ", p2 = " << distanceResult.nearest_points[1]
313

2
            << ", distance = " << distanceResult.min_distance << std::endl;
314
315



2
  BOOST_CHECK_CLOSE(distanceResult.min_distance, 0.1, 1e-6);
316
2
}
317
318
















4
BOOST_AUTO_TEST_CASE(distance_capsulecapsule_transformZ2) {
319

4
  CollisionGeometryPtr_t s1(new Capsule(5, 10));
320

4
  CollisionGeometryPtr_t s2(new Capsule(5, 10));
321
322
2
  Transform3f tf1;
323

2
  Transform3f tf2(makeQuat(sqrt(2) / 2, 0, sqrt(2) / 2, 0), Vec3f(0, 0, 25.1));
324
325
4
  CollisionObject o1(s1, tf1);
326
4
  CollisionObject o2(s2, tf2);
327
328
  // Enable computation of nearest points
329
2
  DistanceRequest distanceRequest(true);
330
2
  DistanceResult distanceResult;
331
332
2
  distance(&o1, &o2, distanceRequest, distanceResult);
333
334

2
  std::cerr << "Applied rotation and translation on two capsules" << std::endl;
335

2
  std::cerr << "R1 = " << tf1.getRotation() << std::endl
336


2
            << "T1 = " << tf1.getTranslation().transpose() << std::endl
337

2
            << "R2 = " << tf2.getRotation() << std::endl
338


2
            << "T2 = " << tf2.getTranslation().transpose() << std::endl;
339

2
  std::cerr << "Closest points:" << std::endl
340

2
            << "p1 = " << distanceResult.nearest_points[0].transpose()
341
2
            << std::endl
342

2
            << "p2 = " << distanceResult.nearest_points[1].transpose()
343
2
            << std::endl
344

2
            << "distance = " << distanceResult.min_distance << std::endl;
345
346
2
  const Vec3f& p1 = distanceResult.nearest_points[0];
347
2
  const Vec3f& p2 = distanceResult.nearest_points[1];
348
349



2
  BOOST_CHECK_CLOSE(distanceResult.min_distance, 10.1, 1e-6);
350



2
  CHECK_CLOSE_TO_0(p1[0], 1e-4);
351



2
  CHECK_CLOSE_TO_0(p1[1], 1e-4);
352



2
  BOOST_CHECK_CLOSE(p1[2], 10, 1e-4);
353



2
  CHECK_CLOSE_TO_0(p2[0], 1e-4);
354



2
  CHECK_CLOSE_TO_0(p2[1], 1e-4);
355



2
  BOOST_CHECK_CLOSE(p2[2], 20.1, 1e-4);
356
2
}