GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: test/profiling.cpp Lines: 70 158 44.3 %
Date: 2024-02-09 12:57:42 Branches: 88 444 19.8 %

Line Branch Exec Source
1
// Copyright (c) 2017, Joseph Mirabel
2
// Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
3
//
4
// This file is part of hpp-fcl.
5
// hpp-fcl is free software: you can redistribute it
6
// and/or modify it under the terms of the GNU Lesser General Public
7
// License as published by the Free Software Foundation, either version
8
// 3 of the License, or (at your option) any later version.
9
//
10
// hpp-fcl is distributed in the hope that it will be
11
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
// General Lesser Public License for more details.  You should have
14
// received a copy of the GNU Lesser General Public License along with
15
// hpp-fcl. If not, see <http://www.gnu.org/licenses/>.
16
17
#include <boost/filesystem.hpp>
18
19
#include <hpp/fcl/fwd.hh>
20
#include <hpp/fcl/collision.h>
21
#include <hpp/fcl/BVH/BVH_model.h>
22
#include <hpp/fcl/collision_utility.h>
23
#include <hpp/fcl/shape/geometric_shapes.h>
24
#include <hpp/fcl/collision_func_matrix.h>
25
#include <hpp/fcl/narrowphase/narrowphase.h>
26
#include <hpp/fcl/mesh_loader/assimp.h>
27
#include "utility.h"
28
#include "fcl_resources/config.h"
29
30
using namespace hpp::fcl;
31
32
CollisionFunctionMatrix lookupTable;
33
45
bool supportedPair(const CollisionGeometry* o1, const CollisionGeometry* o2) {
34
45
  OBJECT_TYPE object_type1 = o1->getObjectType();
35
45
  OBJECT_TYPE object_type2 = o2->getObjectType();
36
45
  NODE_TYPE node_type1 = o1->getNodeType();
37
45
  NODE_TYPE node_type2 = o2->getNodeType();
38
39

45
  if (object_type1 == OT_GEOM && object_type2 == OT_BVH)
40
20
    return (lookupTable.collision_matrix[node_type2][node_type1] != NULL);
41
  else
42
25
    return (lookupTable.collision_matrix[node_type1][node_type2] != NULL);
43
}
44
45
template <typename BV /*, SplitMethodType split_method*/>
46
8
CollisionGeometryPtr_t objToGeom(const std::string& filename) {
47
16
  std::vector<Vec3f> pt;
48
16
  std::vector<Triangle> tri;
49
8
  loadOBJFile(filename.c_str(), pt, tri);
50
51

8
  BVHModel<BV>* model(new BVHModel<BV>());
52
  // model->bv_splitter.reset(new BVSplitter<BV>(split_method));
53
54
8
  model->beginModel();
55
8
  model->addSubModel(pt, tri);
56
8
  model->endModel();
57
58
16
  return CollisionGeometryPtr_t(model);
59
}
60
61
template <typename BV /*, SplitMethodType split_method*/>
62
CollisionGeometryPtr_t meshToGeom(const std::string& filename,
63
                                  const Vec3f& scale = Vec3f(1, 1, 1)) {
64
  shared_ptr<BVHModel<BV> > model(new BVHModel<BV>());
65
  loadPolyhedronFromResource(filename, scale, model);
66
  return model;
67
}
68
69
struct Geometry {
70
  std::string type;
71
  CollisionGeometryPtr_t o;
72
73
5
  Geometry(const std::string& t, CollisionGeometry* ob) : type(t), o(ob) {}
74
4
  Geometry(const std::string& t, const CollisionGeometryPtr_t& ob)
75
4
      : type(t), o(ob) {}
76
};
77
78
struct Results {
79
  std::vector<CollisionResult> rs;
80
  Eigen::VectorXd times;  // micro-seconds
81
82

41
  Results(size_t i) : rs(i), times((Eigen::DenseIndex)i) {}
83
};
84
85
41
void collide(const std::vector<Transform3f>& tf, const CollisionGeometry* o1,
86
             const CollisionGeometry* o2, const CollisionRequest& request,
87
             Results& results) {
88
41
  Transform3f Id;
89
82
  BenchTimer timer;
90
82
  for (std::size_t i = 0; i < tf.size(); ++i) {
91
41
    timer.start();
92
    /* int num_contact = */
93
41
    collide(o1, tf[i], o2, Id, request, results.rs[i]);
94
41
    timer.stop();
95

41
    results.times[(Eigen::DenseIndex)i] = timer.getElapsedTimeInMicroSec();
96
  }
97
41
}
98
99
const char* sep = ", ";
100
101
1
void printResultHeaders() {
102
  std::cout << "Type 1" << sep << "Type 2" << sep << "mean time" << sep
103
1
            << "time std dev" << sep << "min time" << sep << "max time"
104
1
            << std::endl;
105
1
}
106
107
41
void printResults(const Geometry& g1, const Geometry& g2, const Results& rs) {
108
41
  double mean = rs.times.mean();
109
41
  double var = rs.times.cwiseAbs2().mean() - mean * mean;
110
41
  std::cout << g1.type << sep << g2.type << sep << mean << sep << std::sqrt(var)
111
41
            << sep << rs.times.minCoeff() << sep << rs.times.maxCoeff()
112
41
            << std::endl;
113
41
}
114
115
#ifndef NDEBUG  // if debug mode
116
size_t Ntransform = 1;
117
#else
118
size_t Ntransform = 100;
119
#endif
120
FCL_REAL limit = 20;
121
bool verbose = false;
122
123
#define OUT(x) \
124
  if (verbose) std::cout << x << std::endl
125
#define CHECK_PARAM_NB(NB, NAME) \
126
  if (iarg + NB >= argc)         \
127
  throw std::invalid_argument(#NAME " requires " #NB " numbers")
128
void handleParam(int& iarg, const int& argc, char** argv,
129
                 CollisionRequest& request) {
130
  while (iarg < argc) {
131
    std::string a(argv[iarg]);
132
    if (a == "-nb_transform") {
133
      CHECK_PARAM_NB(1, nb_transform);
134
      Ntransform = (size_t)atoi(argv[iarg + 1]);
135
      OUT("nb_transform = " << Ntransform);
136
      iarg += 2;
137
    } else if (a == "-enable_distance_lower_bound") {
138
      CHECK_PARAM_NB(1, enable_distance_lower_bound);
139
      request.enable_distance_lower_bound = bool(atoi(argv[iarg + 1]));
140
      iarg += 2;
141
    } else if (a == "-limit") {
142
      CHECK_PARAM_NB(1, limit);
143
      limit = atof(argv[iarg + 1]);
144
      iarg += 2;
145
    } else if (a == "-verbose") {
146
      verbose = true;
147
      iarg += 1;
148
    } else {
149
      break;
150
    }
151
  }
152
}
153
#define CREATE_SHAPE_2(var, Name)                                  \
154
  CHECK_PARAM_NB(2, Name);                                         \
155
  var.reset(new Name(atof(argv[iarg + 1]), atof(argv[iarg + 2]))); \
156
  iarg += 3;
157
Geometry makeGeomFromParam(int& iarg, const int& argc, char** argv) {
158
  if (iarg >= argc) throw std::invalid_argument("An argument is required.");
159
  std::string a(argv[iarg]);
160
  std::string type;
161
  CollisionGeometryPtr_t o;
162
  if (a == "-box") {
163
    CHECK_PARAM_NB(3, Box);
164
    o.reset(new Box(atof(argv[iarg + 1]), atof(argv[iarg + 2]),
165
                    atof(argv[iarg + 3])));
166
    iarg += 4;
167
    type = "box";
168
  } else if (a == "-sphere") {
169
    CHECK_PARAM_NB(1, Sphere);
170
    o.reset(new Sphere(atof(argv[iarg + 1])));
171
    iarg += 2;
172
    type = "sphere";
173
  } else if (a == "-mesh") {
174
    CHECK_PARAM_NB(2, Mesh);
175
    OUT("Loading " << argv[iarg + 2] << " as BVHModel<" << argv[iarg + 1]
176
                   << ">...");
177
    if (strcmp(argv[iarg + 1], "obb") == 0) {
178
      o = meshToGeom<OBB>(argv[iarg + 2]);
179
      OUT("Mesh has " << dynamic_pointer_cast<BVHModel<OBB> >(o)->num_tris
180
                      << " triangles");
181
      type = "mesh_obb";
182
    } else if (strcmp(argv[iarg + 1], "obbrss") == 0) {
183
      o = meshToGeom<OBBRSS>(argv[iarg + 2]);
184
      OUT("Mesh has " << dynamic_pointer_cast<BVHModel<OBBRSS> >(o)->num_tris
185
                      << " triangles");
186
      type = "mesh_obbrss";
187
    } else
188
      throw std::invalid_argument("BV type must be obb or obbrss");
189
    OUT("done.");
190
    iarg += 3;
191
    if (iarg < argc && strcmp(argv[iarg], "crop") == 0) {
192
      CHECK_PARAM_NB(6, Crop);
193
      hpp::fcl::AABB aabb(Vec3f(atof(argv[iarg + 1]), atof(argv[iarg + 2]),
194
                                atof(argv[iarg + 3])),
195
                          Vec3f(atof(argv[iarg + 4]), atof(argv[iarg + 5]),
196
                                atof(argv[iarg + 6])));
197
      OUT("Cropping " << aabb.min_.transpose() << " ---- "
198
                      << aabb.max_.transpose() << " ...");
199
      o->computeLocalAABB();
200
      OUT("Mesh AABB is " << o->aabb_local.min_.transpose() << " ---- "
201
                          << o->aabb_local.max_.transpose() << " ...");
202
      o.reset(extract(o.get(), Transform3f(), aabb));
203
      if (!o) throw std::invalid_argument("Failed to crop.");
204
      OUT("Crop has " << dynamic_pointer_cast<BVHModel<OBB> >(o)->num_tris
205
                      << " triangles");
206
      iarg += 7;
207
    }
208
  } else if (a == "-capsule") {
209
    CREATE_SHAPE_2(o, Capsule);
210
    type = "capsule";
211
  } else if (a == "-cone") {
212
    CREATE_SHAPE_2(o, Cone);
213
    type = "cone";
214
  } else if (a == "-cylinder") {
215
    CREATE_SHAPE_2(o, Cylinder);
216
    type = "cylinder";
217
  } else {
218
    throw std::invalid_argument(std::string("Unknown argument: ") + a);
219
  }
220
  return Geometry(type, o);
221
}
222
223
1
int main(int argc, char** argv) {
224
1
  std::vector<Transform3f> transforms;
225
226
1
  CollisionRequest request;
227
228
1
  if (argc > 1) {
229
    int iarg = 1;
230
    handleParam(iarg, argc, argv, request);
231
    Geometry first = makeGeomFromParam(iarg, argc, argv);
232
    Geometry second = makeGeomFromParam(iarg, argc, argv);
233
234
    FCL_REAL extents[] = {-limit, -limit, -limit, limit, limit, limit};
235
    generateRandomTransforms(extents, transforms, Ntransform);
236
    printResultHeaders();
237
    Results results(Ntransform);
238
    collide(transforms, first.o.get(), second.o.get(), request, results);
239
    printResults(first, second, results);
240
  } else {
241
1
    FCL_REAL extents[] = {-limit, -limit, -limit, limit, limit, limit};
242
1
    generateRandomTransforms(extents, transforms, Ntransform);
243
2
    boost::filesystem::path path(TEST_RESOURCES_DIR);
244
245
2
    std::vector<Geometry> geoms;
246


1
    geoms.push_back(Geometry("Box", new Box(1, 2, 3)));
247


1
    geoms.push_back(Geometry("Sphere", new Sphere(2)));
248


1
    geoms.push_back(Geometry("Capsule", new Capsule(2, 1)));
249


1
    geoms.push_back(Geometry("Cone", new Cone(2, 1)));
250


1
    geoms.push_back(Geometry("Cylinder", new Cylinder(2, 1)));
251
    // geoms.push_back(Geometry ("Plane"     , new Plane
252
    // (Vec3f(1,1,1).normalized(), 0)                  ));
253
    // geoms.push_back(Geometry ("Halfspace" , new Halfspace
254
    // (Vec3f(1,1,1).normalized(), 0)                  ));
255
    //  not implemented // geoms.push_back(Geometry ("TriangleP" , new TriangleP
256
    //  (Vec3f(0,1,0), Vec3f(0,0,1), Vec3f(-1,0,0))     ));
257
258

1
    geoms.push_back(Geometry("rob BVHModel<OBB>",
259

2
                             objToGeom<OBB>((path / "rob.obj").string())));
260
    // geoms.push_back(Geometry ("rob BVHModel<RSS>"   , objToGeom<RSS>   ((path
261
    // / "rob.obj").string()))); geoms.push_back(Geometry ("rob BVHModel<kIOS>"
262
    // , objToGeom<kIOS>  ((path / "rob.obj").string())));
263

1
    geoms.push_back(Geometry("rob BVHModel<OBBRSS>",
264

2
                             objToGeom<OBBRSS>((path / "rob.obj").string())));
265
266

1
    geoms.push_back(Geometry("env BVHModel<OBB>",
267

2
                             objToGeom<OBB>((path / "env.obj").string())));
268
    // geoms.push_back(Geometry ("env BVHModel<RSS>"   , objToGeom<RSS>   ((path
269
    // / "env.obj").string()))); geoms.push_back(Geometry ("env BVHModel<kIOS>"
270
    // , objToGeom<kIOS>  ((path / "env.obj").string())));
271

1
    geoms.push_back(Geometry("env BVHModel<OBBRSS>",
272

2
                             objToGeom<OBBRSS>((path / "env.obj").string())));
273
274
1
    printResultHeaders();
275
276
    // collision
277
10
    for (std::size_t i = 0; i < geoms.size(); ++i) {
278
54
      for (std::size_t j = i; j < geoms.size(); ++j) {
279

45
        if (!supportedPair(geoms[i].o.get(), geoms[j].o.get())) continue;
280
82
        Results results(Ntransform);
281
41
        collide(transforms, geoms[i].o.get(), geoms[j].o.get(), request,
282
                results);
283
41
        printResults(geoms[i], geoms[j], results);
284
      }
285
    }
286
  }
287
288
1
  return 0;
289
}