GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/narrowphase/gjk.cpp Lines: 861 1001 86.0 %
Date: 2024-02-09 12:57:42 Branches: 824 1543 53.4 %

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
#include <hpp/fcl/narrowphase/gjk.h>
39
#include <hpp/fcl/internal/intersect.h>
40
#include <hpp/fcl/internal/tools.h>
41
#include <hpp/fcl/shape/geometric_shapes_traits.h>
42
43
namespace hpp {
44
namespace fcl {
45
46
namespace details {
47
48
189794971
void getShapeSupport(const TriangleP* triangle, const Vec3f& dir,
49
                     Vec3f& support, int&, MinkowskiDiff::ShapeData*) {
50
189794971
  FCL_REAL dota = dir.dot(triangle->a);
51
189794971
  FCL_REAL dotb = dir.dot(triangle->b);
52
189794971
  FCL_REAL dotc = dir.dot(triangle->c);
53
189794971
  if (dota > dotb) {
54
91199175
    if (dotc > dota)
55
32667413
      support = triangle->c;
56
    else
57
58531762
      support = triangle->a;
58
  } else {
59
98595796
    if (dotc > dotb)
60
23103379
      support = triangle->c;
61
    else
62
75492417
      support = triangle->b;
63
  }
64
189794971
}
65
66
3840389
inline void getShapeSupport(const Box* box, const Vec3f& dir, Vec3f& support,
67
                            int&, MinkowskiDiff::ShapeData*) {
68


3840389
  const FCL_REAL inflate = (dir.array() == 0).any() ? 1.00000001 : 1.;
69
3840389
  support.noalias() =
70

3840389
      (dir.array() > 0)
71


7680778
          .select(inflate * box->halfSide, -inflate * box->halfSide);
72
3840389
}
73
74
171185
inline void getShapeSupport(const Sphere*, const Vec3f& /*dir*/, Vec3f& support,
75
                            int&, MinkowskiDiff::ShapeData*) {
76
171185
  support.setZero();
77
171185
}
78
79
715318
inline void getShapeSupport(const Ellipsoid* ellipsoid, const Vec3f& dir,
80
                            Vec3f& support, int&, MinkowskiDiff::ShapeData*) {
81

715318
  FCL_REAL a2 = ellipsoid->radii[0] * ellipsoid->radii[0];
82

715318
  FCL_REAL b2 = ellipsoid->radii[1] * ellipsoid->radii[1];
83

715318
  FCL_REAL c2 = ellipsoid->radii[2] * ellipsoid->radii[2];
84
85


715318
  Vec3f v(a2 * dir[0], b2 * dir[1], c2 * dir[2]);
86
87
715318
  FCL_REAL d = std::sqrt(v.dot(dir));
88
89

715318
  support = v / d;
90
715318
}
91
92
340705
inline void getShapeSupport(const Capsule* capsule, const Vec3f& dir,
93
                            Vec3f& support, int&, MinkowskiDiff::ShapeData*) {
94
340705
  support.head<2>().setZero();
95
340705
  if (dir[2] > 0)
96
187795
    support[2] = capsule->halfLength;
97
  else
98
152910
    support[2] = -capsule->halfLength;
99
340705
}
100
101
11184
void getShapeSupport(const Cone* cone, const Vec3f& dir, Vec3f& support, int&,
102
                     MinkowskiDiff::ShapeData*) {
103
  // The cone radius is, for -h < z < h, (h - z) * r / (2*h)
104
  static const FCL_REAL inflate = 1.00001;
105
11184
  FCL_REAL h = cone->halfLength;
106
11184
  FCL_REAL r = cone->radius;
107
108

11184
  if (dir.head<2>().isZero()) {
109

94
    support.head<2>().setZero();
110

94
    if (dir[2] > 0)
111
36
      support[2] = h;
112
    else
113
58
      support[2] = -inflate * h;
114
5153
    return;
115
  }
116


11090
  FCL_REAL zdist = dir[0] * dir[0] + dir[1] * dir[1];
117

11090
  FCL_REAL len = zdist + dir[2] * dir[2];
118
11090
  zdist = std::sqrt(zdist);
119
120

11090
  if (dir[2] <= 0) {
121
5059
    FCL_REAL rad = r / zdist;
122


5059
    support.head<2>() = rad * dir.head<2>();
123
5059
    support[2] = -h;
124
5059
    return;
125
  }
126
127
6031
  len = std::sqrt(len);
128
6031
  FCL_REAL sin_a = r / std::sqrt(r * r + 4 * h * h);
129
130

6031
  if (dir[2] > len * sin_a)
131

1960
    support << 0, 0, h;
132
  else {
133
4071
    FCL_REAL rad = r / zdist;
134


4071
    support.head<2>() = rad * dir.head<2>();
135
4071
    support[2] = -h;
136
  }
137
}
138
139
1797686
void getShapeSupport(const Cylinder* cylinder, const Vec3f& dir, Vec3f& support,
140
                     int&, MinkowskiDiff::ShapeData*) {
141
  // The inflation makes the object look strictly convex to GJK and EPA. This
142
  // helps solving particular cases (e.g. a cylinder with itself at the same
143
  // position...)
144
  static const FCL_REAL inflate = 1.00001;
145
1797686
  FCL_REAL half_h = cylinder->halfLength;
146
1797686
  FCL_REAL r = cylinder->radius;
147
148


1797686
  if (dir.head<2>() == Eigen::Matrix<FCL_REAL, 2, 1>::Zero()) half_h *= inflate;
149
150

1797686
  if (dir[2] > 0)
151
741107
    support[2] = half_h;
152

1056579
  else if (dir[2] < 0)
153
745468
    support[2] = -half_h;
154
  else {
155
311111
    support[2] = 0;
156
311111
    r *= inflate;
157
  }
158


1797686
  if (dir.head<2>() == Eigen::Matrix<FCL_REAL, 2, 1>::Zero())
159

350
    support.head<2>().setZero();
160
  else
161


1797336
    support.head<2>() = dir.head<2>().normalized() * r;
162


1797686
  assert(fabs(support[0] * dir[1] - support[1] * dir[0]) <
163
         sqrt(std::numeric_limits<FCL_REAL>::epsilon()));
164
1797686
}
165
166
struct SmallConvex : ShapeBase {};
167
struct LargeConvex : ShapeBase {};
168
169
void getShapeSupportLog(const ConvexBase* convex, const Vec3f& dir,
170
                        Vec3f& support, int& hint,
171
                        MinkowskiDiff::ShapeData* data) {
172
  assert(data != NULL);
173
174
  const Vec3f* pts = convex->points;
175
  const ConvexBase::Neighbors* nn = convex->neighbors;
176
177
  if (hint < 0 || hint >= (int)convex->num_points) hint = 0;
178
  FCL_REAL maxdot = pts[hint].dot(dir);
179
  std::vector<int8_t>& visited = data->visited;
180
  visited.assign(convex->num_points, false);
181
  visited[static_cast<std::size_t>(hint)] = true;
182
  // when the first face is orthogonal to dir, all the dot products will be
183
  // equal. Yet, the neighbors must be visited.
184
  bool found = true, loose_check = true;
185
  while (found) {
186
    const ConvexBase::Neighbors& n = nn[hint];
187
    found = false;
188
    for (int in = 0; in < n.count(); ++in) {
189
      const unsigned int ip = n[in];
190
      if (visited[ip]) continue;
191
      visited[ip] = true;
192
      const FCL_REAL dot = pts[ip].dot(dir);
193
      bool better = false;
194
      if (dot > maxdot) {
195
        better = true;
196
        loose_check = false;
197
      } else if (loose_check && dot == maxdot)
198
        better = true;
199
      if (better) {
200
        maxdot = dot;
201
        hint = static_cast<int>(ip);
202
        found = true;
203
      }
204
    }
205
  }
206
207
  support = pts[hint];
208
}
209
210
673294
void getShapeSupportLinear(const ConvexBase* convex, const Vec3f& dir,
211
                           Vec3f& support, int& hint,
212
                           MinkowskiDiff::ShapeData*) {
213
673294
  const Vec3f* pts = convex->points;
214
215
673294
  hint = 0;
216
673294
  FCL_REAL maxdot = pts[0].dot(dir);
217
7329176
  for (int i = 1; i < (int)convex->num_points; ++i) {
218
6655882
    FCL_REAL dot = pts[i].dot(dir);
219
6655882
    if (dot > maxdot) {
220
1382198
      maxdot = dot;
221
1382198
      hint = i;
222
    }
223
  }
224
673294
  support = pts[hint];
225
673294
}
226
227
4
void getShapeSupport(const ConvexBase* convex, const Vec3f& dir, Vec3f& support,
228
                     int& hint, MinkowskiDiff::ShapeData*) {
229
  // TODO add benchmark to set a proper value for switching between linear and
230
  // logarithmic.
231
4
  if (convex->num_points > 32) {
232
    MinkowskiDiff::ShapeData data;
233
    getShapeSupportLog(convex, dir, support, hint, &data);
234
  } else
235
4
    getShapeSupportLinear(convex, dir, support, hint, NULL);
236
4
}
237
238
673290
inline void getShapeSupport(const SmallConvex* convex, const Vec3f& dir,
239
                            Vec3f& support, int& hint,
240
                            MinkowskiDiff::ShapeData* data) {
241
673290
  getShapeSupportLinear(reinterpret_cast<const ConvexBase*>(convex), dir,
242
                        support, hint, data);
243
673290
}
244
245
inline void getShapeSupport(const LargeConvex* convex, const Vec3f& dir,
246
                            Vec3f& support, int& hint,
247
                            MinkowskiDiff::ShapeData* data) {
248
  getShapeSupportLog(reinterpret_cast<const ConvexBase*>(convex), dir, support,
249
                     hint, data);
250
}
251
252
#define CALL_GET_SHAPE_SUPPORT(ShapeType)                              \
253
  getShapeSupport(                                                     \
254
      static_cast<const ShapeType*>(shape),                            \
255
      (shape_traits<ShapeType>::NeedNormalizedDir && !dirIsNormalized) \
256
          ? dir.normalized()                                           \
257
          : dir,                                                       \
258
      support, hint, NULL)
259
260
4
Vec3f getSupport(const ShapeBase* shape, const Vec3f& dir, bool dirIsNormalized,
261
                 int& hint) {
262
4
  Vec3f support;
263


4
  switch (shape->getNodeType()) {
264
    case GEOM_TRIANGLE:
265
      CALL_GET_SHAPE_SUPPORT(TriangleP);
266
      break;
267
    case GEOM_BOX:
268
      CALL_GET_SHAPE_SUPPORT(Box);
269
      break;
270
    case GEOM_SPHERE:
271
      CALL_GET_SHAPE_SUPPORT(Sphere);
272
      break;
273
    case GEOM_ELLIPSOID:
274
      CALL_GET_SHAPE_SUPPORT(Ellipsoid);
275
      break;
276
    case GEOM_CAPSULE:
277
      CALL_GET_SHAPE_SUPPORT(Capsule);
278
      break;
279
    case GEOM_CONE:
280
      CALL_GET_SHAPE_SUPPORT(Cone);
281
      break;
282
    case GEOM_CYLINDER:
283
      CALL_GET_SHAPE_SUPPORT(Cylinder);
284
      break;
285
4
    case GEOM_CONVEX:
286
4
      CALL_GET_SHAPE_SUPPORT(ConvexBase);
287
4
      break;
288
    case GEOM_PLANE:
289
    case GEOM_HALFSPACE:
290
    default:
291
      support.setZero();
292
      ;  // nothing
293
  }
294
295
4
  return support;
296
}
297
298
#undef CALL_GET_SHAPE_SUPPORT
299
300
template <typename Shape0, typename Shape1, bool TransformIsIdentity>
301
197344728
void getSupportTpl(const Shape0* s0, const Shape1* s1, const Matrix3f& oR1,
302
                   const Vec3f& ot1, const Vec3f& dir, Vec3f& support0,
303
                   Vec3f& support1, support_func_guess_t& hint,
304
                   MinkowskiDiff::ShapeData data[2]) {
305
197344728
  getShapeSupport(s0, dir, support0, hint[0], &(data[0]));
306
  if (TransformIsIdentity)
307

189811266
    getShapeSupport(s1, -dir, support1, hint[1], &(data[1]));
308
  else {
309


7533462
    getShapeSupport(s1, -oR1.transpose() * dir, support1, hint[1], &(data[1]));
310

7533462
    support1 = oR1 * support1 + ot1;
311
  }
312
}
313
314
template <typename Shape0, typename Shape1, bool TransformIsIdentity>
315
197344728
void getSupportFuncTpl(const MinkowskiDiff& md, const Vec3f& dir,
316
                       bool dirIsNormalized, Vec3f& support0, Vec3f& support1,
317
                       support_func_guess_t& hint,
318
                       MinkowskiDiff::ShapeData data[2]) {
319
  enum {
320
    NeedNormalizedDir = bool((bool)shape_traits<Shape0>::NeedNormalizedDir ||
321
                             (bool)shape_traits<Shape1>::NeedNormalizedDir)
322
  };
323
#ifndef NDEBUG
324
  // Need normalized direction and direction is normalized
325

1183916
  assert(!NeedNormalizedDir || !dirIsNormalized ||
326
         fabs(dir.squaredNorm() - 1) < 1e-6);
327
  // Need normalized direction but direction is not normalized.
328


1183916
  assert(!NeedNormalizedDir || dirIsNormalized ||
329
         fabs(dir.normalized().squaredNorm() - 1) < 1e-6);
330
  // Don't need normalized direction. Check that dir is not zero.
331

196160812
  assert(NeedNormalizedDir || dir.cwiseAbs().maxCoeff() >= 1e-6);
332
#endif
333
197344728
  getSupportTpl<Shape0, Shape1, TransformIsIdentity>(
334
197344728
      static_cast<const Shape0*>(md.shapes[0]),
335
197344728
      static_cast<const Shape1*>(md.shapes[1]), md.oR1, md.ot1,
336
197344728
      (NeedNormalizedDir && !dirIsNormalized) ? dir.normalized() : dir,
337
      support0, support1, hint, data);
338
}
339
340
template <typename Shape0>
341
60030946
MinkowskiDiff::GetSupportFunction makeGetSupportFunction1(
342
    const ShapeBase* s1, bool identity, Eigen::Array<FCL_REAL, 1, 2>& inflation,
343
    int linear_log_convex_threshold) {
344
60030946
  inflation[1] = 0;
345


60030946
  switch (s1->getNodeType()) {
346
58412958
    case GEOM_TRIANGLE:
347
58412958
      if (identity)
348
58412946
        return getSupportFuncTpl<Shape0, TriangleP, true>;
349
      else
350
12
        return getSupportFuncTpl<Shape0, TriangleP, false>;
351
1132914
    case GEOM_BOX:
352
1132914
      if (identity)
353
36
        return getSupportFuncTpl<Shape0, Box, true>;
354
      else
355
1132878
        return getSupportFuncTpl<Shape0, Box, false>;
356
111354
    case GEOM_SPHERE:
357
111354
      inflation[1] = static_cast<const Sphere*>(s1)->radius;
358
111354
      if (identity)
359
        return getSupportFuncTpl<Shape0, Sphere, true>;
360
      else
361
111354
        return getSupportFuncTpl<Shape0, Sphere, false>;
362
4002
    case GEOM_ELLIPSOID:
363
4002
      if (identity)
364
2
        return getSupportFuncTpl<Shape0, Ellipsoid, true>;
365
      else
366
4000
        return getSupportFuncTpl<Shape0, Ellipsoid, false>;
367
16002
    case GEOM_CAPSULE:
368
16002
      inflation[1] = static_cast<const Capsule*>(s1)->radius;
369
16002
      if (identity)
370
        return getSupportFuncTpl<Shape0, Capsule, true>;
371
      else
372
16002
        return getSupportFuncTpl<Shape0, Capsule, false>;
373
2116
    case GEOM_CONE:
374
2116
      if (identity)
375
28
        return getSupportFuncTpl<Shape0, Cone, true>;
376
      else
377
2088
        return getSupportFuncTpl<Shape0, Cone, false>;
378
317590
    case GEOM_CYLINDER:
379
317590
      if (identity)
380
24
        return getSupportFuncTpl<Shape0, Cylinder, true>;
381
      else
382
317566
        return getSupportFuncTpl<Shape0, Cylinder, false>;
383
34010
    case GEOM_CONVEX:
384
34010
      if ((int)static_cast<const ConvexBase*>(s1)->num_points >
385
          linear_log_convex_threshold) {
386
        if (identity)
387
          return getSupportFuncTpl<Shape0, LargeConvex, true>;
388
        else
389
          return getSupportFuncTpl<Shape0, LargeConvex, false>;
390
      } else {
391
34010
        if (identity)
392
6
          return getSupportFuncTpl<Shape0, SmallConvex, true>;
393
        else
394
34004
          return getSupportFuncTpl<Shape0, SmallConvex, false>;
395
      }
396
    default:
397
      throw std::logic_error("Unsupported geometric shape");
398
  }
399
}
400
401
30015473
MinkowskiDiff::GetSupportFunction makeGetSupportFunction0(
402
    const ShapeBase* s0, const ShapeBase* s1, bool identity,
403
    Eigen::Array<FCL_REAL, 1, 2>& inflation, int linear_log_convex_threshold) {
404
30015473
  inflation[0] = 0;
405


30015473
  switch (s0->getNodeType()) {
406
29203802
    case GEOM_TRIANGLE:
407
29203802
      return makeGetSupportFunction1<TriangleP>(s1, identity, inflation,
408
29203802
                                                linear_log_convex_threshold);
409
      break;
410
419581
    case GEOM_BOX:
411
419581
      return makeGetSupportFunction1<Box>(s1, identity, inflation,
412
419581
                                          linear_log_convex_threshold);
413
      break;
414
17
    case GEOM_SPHERE:
415
17
      inflation[0] = static_cast<const Sphere*>(s0)->radius;
416
17
      return makeGetSupportFunction1<Sphere>(s1, identity, inflation,
417
17
                                             linear_log_convex_threshold);
418
      break;
419
14002
    case GEOM_ELLIPSOID:
420
14002
      return makeGetSupportFunction1<Ellipsoid>(s1, identity, inflation,
421
14002
                                                linear_log_convex_threshold);
422
      break;
423
7034
    case GEOM_CAPSULE:
424
7034
      inflation[0] = static_cast<const Capsule*>(s0)->radius;
425
7034
      return makeGetSupportFunction1<Capsule>(s1, identity, inflation,
426
7034
                                              linear_log_convex_threshold);
427
      break;
428
52
    case GEOM_CONE:
429
52
      return makeGetSupportFunction1<Cone>(s1, identity, inflation,
430
52
                                           linear_log_convex_threshold);
431
      break;
432
310319
    case GEOM_CYLINDER:
433
310319
      return makeGetSupportFunction1<Cylinder>(s1, identity, inflation,
434
310319
                                               linear_log_convex_threshold);
435
      break;
436
60666
    case GEOM_CONVEX:
437
60666
      if ((int)static_cast<const ConvexBase*>(s0)->num_points >
438
          linear_log_convex_threshold)
439
        return makeGetSupportFunction1<LargeConvex>(
440
            s1, identity, inflation, linear_log_convex_threshold);
441
      else
442
60666
        return makeGetSupportFunction1<SmallConvex>(
443
60666
            s1, identity, inflation, linear_log_convex_threshold);
444
      break;
445
    default:
446
      throw std::logic_error("Unsupported geometric shape");
447
  }
448
}
449
450
30076139
bool getNormalizeSupportDirection(const ShapeBase* shape) {
451


30076139
  switch (shape->getNodeType()) {
452
29203802
    case GEOM_TRIANGLE:
453
29203802
      return (bool)shape_traits<TriangleP>::NeedNesterovNormalizeHeuristic;
454
      break;
455
419581
    case GEOM_BOX:
456
419581
      return (bool)shape_traits<Box>::NeedNesterovNormalizeHeuristic;
457
      break;
458
55678
    case GEOM_SPHERE:
459
55678
      return (bool)shape_traits<Sphere>::NeedNesterovNormalizeHeuristic;
460
      break;
461
14002
    case GEOM_ELLIPSOID:
462
14002
      return (bool)shape_traits<Ellipsoid>::NeedNesterovNormalizeHeuristic;
463
      break;
464
7034
    case GEOM_CAPSULE:
465
7034
      return (bool)shape_traits<Capsule>::NeedNesterovNormalizeHeuristic;
466
      break;
467
52
    case GEOM_CONE:
468
52
      return (bool)shape_traits<Cone>::NeedNesterovNormalizeHeuristic;
469
      break;
470
310319
    case GEOM_CYLINDER:
471
310319
      return (bool)shape_traits<Cylinder>::NeedNesterovNormalizeHeuristic;
472
      break;
473
65671
    case GEOM_CONVEX:
474
65671
      return (bool)shape_traits<ConvexBase>::NeedNesterovNormalizeHeuristic;
475
      break;
476
    default:
477
      throw std::logic_error("Unsupported geometric shape");
478
  }
479
}
480
481
30015473
void getNormalizeSupportDirectionFromShapes(const ShapeBase* shape0,
482
                                            const ShapeBase* shape1,
483
                                            bool& normalize_support_direction) {
484
30076139
  normalize_support_direction = getNormalizeSupportDirection(shape0) &&
485
60666
                                getNormalizeSupportDirection(shape1);
486
30015473
}
487
488
808997
void MinkowskiDiff::set(const ShapeBase* shape0, const ShapeBase* shape1,
489
                        const Transform3f& tf0, const Transform3f& tf1) {
490
808997
  shapes[0] = shape0;
491
808997
  shapes[1] = shape1;
492
808997
  getNormalizeSupportDirectionFromShapes(shape0, shape1,
493
808997
                                         normalize_support_direction);
494
495

808997
  oR1.noalias() = tf0.getRotation().transpose() * tf1.getRotation();
496

808997
  ot1.noalias() = tf0.getRotation().transpose() *
497
1617994
                  (tf1.getTranslation() - tf0.getTranslation());
498
499


808997
  bool identity = (oR1.isIdentity() && ot1.isZero());
500
501
808997
  getSupportFunc = makeGetSupportFunction0(shape0, shape1, identity, inflation,
502
                                           linear_log_convex_threshold);
503
808997
}
504
505
29206476
void MinkowskiDiff::set(const ShapeBase* shape0, const ShapeBase* shape1) {
506
29206476
  shapes[0] = shape0;
507
29206476
  shapes[1] = shape1;
508
29206476
  getNormalizeSupportDirectionFromShapes(shape0, shape1,
509
29206476
                                         normalize_support_direction);
510
511
29206476
  oR1.setIdentity();
512
29206476
  ot1.setZero();
513
514
29206476
  getSupportFunc = makeGetSupportFunction0(shape0, shape1, true, inflation,
515
                                           linear_log_convex_threshold);
516
29206476
}
517
518
29982542
void GJK::initialize() {
519
29982542
  nfree = 0;
520
29982542
  status = Failed;
521
29982542
  distance_upper_bound = (std::numeric_limits<FCL_REAL>::max)();
522
29982542
  simplex = NULL;
523
29982542
  gjk_variant = GJKVariant::DefaultGJK;
524
29982542
  convergence_criterion = GJKConvergenceCriterion::VDB;
525
29982542
  convergence_criterion_type = GJKConvergenceCriterionType::Relative;
526
29982542
}
527
528
6
Vec3f GJK::getGuessFromSimplex() const { return ray; }
529
530
namespace details {
531
532
29978468
bool getClosestPoints(const GJK::Simplex& simplex, Vec3f& w0, Vec3f& w1) {
533
29978468
  GJK::SimplexV* const* vs = simplex.vertex;
534
535
68244312
  for (GJK::vertex_id_t i = 0; i < simplex.rank; ++i) {
536

38265844
    assert(vs[i]->w.isApprox(vs[i]->w0 - vs[i]->w1));
537
  }
538
539
29978468
  Project::ProjectResult projection;
540

29978468
  switch (simplex.rank) {
541
22102257
    case 1:
542
22102257
      w0 = vs[0]->w0;
543
22102257
      w1 = vs[0]->w1;
544
22102257
      return true;
545
7486073
    case 2: {
546

7486073
      const Vec3f &a = vs[0]->w, a0 = vs[0]->w0, a1 = vs[0]->w1, b = vs[1]->w,
547

7486073
                  b0 = vs[1]->w0, b1 = vs[1]->w1;
548
      FCL_REAL la, lb;
549

7486073
      Vec3f N(b - a);
550

7486073
      la = N.dot(-a);
551
7486073
      if (la <= 0) {
552
        assert(false);
553
        w0 = a0;
554
        w1 = a1;
555
      } else {
556
7486073
        lb = N.squaredNorm();
557
7486073
        if (la > lb) {
558
          assert(false);
559
          w0 = b0;
560
          w1 = b1;
561
        } else {
562
7486073
          lb = la / lb;
563
7486073
          la = 1 - lb;
564


7486073
          w0 = la * a0 + lb * b0;
565


7486073
          w1 = la * a1 + lb * b1;
566
        }
567
      }
568
    }
569
7486073
      return true;
570
369111
    case 3:
571
      // TODO avoid the reprojection
572
369111
      projection = Project::projectTriangleOrigin(vs[0]->w, vs[1]->w, vs[2]->w);
573
369111
      break;
574
21027
    case 4:  // We are in collision.
575
42054
      projection = Project::projectTetrahedraOrigin(vs[0]->w, vs[1]->w,
576
21027
                                                    vs[2]->w, vs[3]->w);
577
21027
      break;
578
    default:
579
      throw std::logic_error("The simplex rank must be in [ 1, 4 ]");
580
  }
581
390138
  w0.setZero();
582
390138
  w1.setZero();
583
1581579
  for (GJK::vertex_id_t i = 0; i < simplex.rank; ++i) {
584

1191441
    w0 += projection.parameterization[i] * vs[i]->w0;
585

1191441
    w1 += projection.parameterization[i] * vs[i]->w1;
586
  }
587
390138
  return true;
588
}
589
590
/// Inflate the points
591
template <bool Separated>
592
59956936
void inflate(const MinkowskiDiff& shape, Vec3f& w0, Vec3f& w1) {
593
59956936
  const Eigen::Array<FCL_REAL, 1, 2>& I(shape.inflation);
594

59956936
  Eigen::Array<bool, 1, 2> inflate(I > 0);
595

59956936
  if (!inflate.any()) return;
596

111426
  Vec3f w(w0 - w1);
597
111426
  FCL_REAL n2 = w.squaredNorm();
598
  // TODO should be use a threshold (Eigen::NumTraits<FCL_REAL>::epsilon()) ?
599
111426
  if (n2 == 0.) {
600
    if (inflate[0]) w0[0] += I[0] * (Separated ? -1 : 1);
601
    if (inflate[1]) w1[0] += I[1] * (Separated ? 1 : -1);
602
    return;
603
  }
604
605
111426
  w /= std::sqrt(n2);
606
  if (Separated) {
607


111422
    if (inflate[0]) w0 -= I[0] * w;
608


111422
    if (inflate[1]) w1 += I[1] * w;
609
  } else {
610


4
    if (inflate[0]) w0 += I[0] * w;
611


4
    if (inflate[1]) w1 -= I[1] * w;
612
  }
613
}
614
615
}  // namespace details
616
617
29977904
bool GJK::getClosestPoints(const MinkowskiDiff& shape, Vec3f& w0, Vec3f& w1) {
618
29977904
  bool res = details::getClosestPoints(*simplex, w0, w1);
619
29977904
  if (!res) return false;
620
29977904
  details::inflate<true>(shape, w0, w1);
621
29977904
  return true;
622
}
623
624
30118472
GJK::Status GJK::evaluate(const MinkowskiDiff& shape_, const Vec3f& guess,
625
                          const support_func_guess_t& supportHint) {
626
30118472
  FCL_REAL alpha = 0;
627
30118472
  iterations = 0;
628
30118472
  const FCL_REAL inflation = shape_.inflation.sum();
629
30118472
  const FCL_REAL upper_bound = distance_upper_bound + inflation;
630
631
30118472
  free_v[0] = &store_v[0];
632
30118472
  free_v[1] = &store_v[1];
633
30118472
  free_v[2] = &store_v[2];
634
30118472
  free_v[3] = &store_v[3];
635
636
30118472
  nfree = 4;
637
30118472
  current = 0;
638
30118472
  status = Valid;
639
30118472
  shape = &shape_;
640
30118472
  distance = 0.0;
641
30118472
  simplices[0].rank = 0;
642
30118472
  support_hint = supportHint;
643
644
30118472
  FCL_REAL rl = guess.norm();
645
30118472
  if (rl < tolerance) {
646
2
    ray = Vec3f(-1, 0, 0);
647
2
    rl = 1;
648
  } else
649
30118470
    ray = guess;
650
651
  // Momentum
652
30118472
  GJKVariant current_gjk_variant = gjk_variant;
653
30118472
  Vec3f w = ray;
654
30118472
  Vec3f dir = ray;
655
30118472
  Vec3f y;
656
  FCL_REAL momentum;
657
30118472
  bool normalize_support_direction = shape->normalize_support_direction;
658
68547499
  do {
659
98665971
    vertex_id_t next = (vertex_id_t)(1 - current);
660
98665971
    Simplex& curr_simplex = simplices[current];
661
98665971
    Simplex& next_simplex = simplices[next];
662
663
    // check A: when origin is near the existing simplex, stop
664
    // TODO this is an early stop which may cause the following issue.
665
    // - EPA will not run correctly because it starts with a tetrahedron which
666
    //   does not include the origin. Note that, at this stage, we do not know
667
    //   whether a tetrahedron including the origin exists.
668
98665971
    if (rl < tolerance)  // mean origin is near the face of original simplex,
669
                         // return touch
670
    {
671
21
      assert(rl > 0);
672
21
      status = Inside;
673
21
      distance = -inflation;  // should we take rl into account ?
674
30118472
      break;
675
    }
676
677
    // Compute direction for support call
678
98665950
    switch (current_gjk_variant) {
679
98230949
      case DefaultGJK:
680
98230949
        dir = ray;
681
98230949
        break;
682
683
435001
      case NesterovAcceleration:
684
        // Normalize heuristic for collision pairs involving convex but not
685
        // strictly-convex shapes This corresponds to most use cases.
686
435001
        if (normalize_support_direction) {
687
19470
          momentum = (FCL_REAL(iterations) + 2) / (FCL_REAL(iterations) + 3);
688


19470
          y = momentum * ray + (1 - momentum) * w;
689
19470
          FCL_REAL y_norm = y.norm();
690
          // ray is the point of the Minkowski difference which currently the
691
          // closest to the origin. Therefore, y.norm() > ray.norm() Hence, if
692
          // check A above has not stopped the algorithm, we necessarily have
693
          // y.norm() > tolerance. The following assert is just a safety check.
694
19470
          assert(y_norm > tolerance);
695



19470
          dir = momentum * dir / dir.norm() + (1 - momentum) * y / y_norm;
696
        } else {
697
415531
          momentum = (FCL_REAL(iterations) + 1) / (FCL_REAL(iterations) + 3);
698


415531
          y = momentum * ray + (1 - momentum) * w;
699


415531
          dir = momentum * dir + (1 - momentum) * y;
700
        }
701
435001
        break;
702
703
      default:
704
        throw std::logic_error("Invalid momentum variant.");
705
    }
706
707

98665950
    appendVertex(curr_simplex, -dir, false,
708
98665950
                 support_hint);  // see below, ray points away from origin
709
710
    // check removed (by ?): when the new support point is close to previous
711
    // support points, stop (as the new simplex is degenerated)
712
98665950
    w = curr_simplex.vertex[curr_simplex.rank - 1]->w;
713
714
    // check B: no collision if omega > 0
715

98665950
    FCL_REAL omega = dir.dot(w) / dir.norm();
716
98665950
    if (omega > upper_bound) {
717
2
      distance = omega - inflation;
718
2
      status = EarlyStopped;
719
2
      break;
720
    }
721
722
    // Check to remove acceleration
723
98665948
    if (current_gjk_variant != DefaultGJK) {
724

435001
      FCL_REAL frank_wolfe_duality_gap = 2 * ray.dot(ray - w);
725
435001
      if (frank_wolfe_duality_gap - tolerance <= 0) {
726
66487
        removeVertex(simplices[current]);
727
66487
        current_gjk_variant = DefaultGJK;  // move back to classic GJK
728
71925
        continue;                          // continue to next iteration
729
      }
730
    }
731
732
    // check C: when the new support point is close to the sub-simplex where the
733
    // ray point lies, stop (as the new simplex again is degenerated)
734
98599461
    bool cv_check_passed = checkConvergence(w, rl, alpha, omega);
735
    // TODO here, we can stop at iteration 0 if this condition is met.
736
    // We stopping at iteration 0, the closest point will not be valid.
737
    // if(diff - tolerance * rl <= 0)
738

98599461
    if (iterations > 0 && cv_check_passed) {
739
30092644
      if (iterations > 0) removeVertex(simplices[current]);
740
30092644
      if (current_gjk_variant != DefaultGJK) {
741
5438
        current_gjk_variant = DefaultGJK;  // move back to classic GJK
742
5438
        continue;
743
      }
744
30087206
      distance = rl - inflation;
745
      // TODO When inflation is strictly positive, the distance may be exactly
746
      // zero (so the ray is not zero) and we are not in the case rl <
747
      // tolerance.
748
30087206
      if (distance < tolerance) status = Inside;
749
30087206
      break;
750
    }
751
752
    // This has been rewritten thanks to the excellent video:
753
    // https://youtu.be/Qupqu1xe7Io
754
    bool inside;
755

68506817
    switch (curr_simplex.rank) {
756
30118471
      case 1:  // Only at the first iteration
757
30118471
        assert(iterations == 0);
758
30118471
        ray = w;
759
30118471
        inside = false;
760
30118471
        next_simplex.rank = 1;
761
30118471
        next_simplex.vertex[0] = curr_simplex.vertex[0];
762
30118471
        break;
763
33932306
      case 2:
764
33932306
        inside = projectLineOrigin(curr_simplex, next_simplex);
765
33932306
        break;
766
4167321
      case 3:
767
4167321
        inside = projectTriangleOrigin(curr_simplex, next_simplex);
768
4167321
        break;
769
288719
      case 4:
770
288719
        inside = projectTetrahedraOrigin(curr_simplex, next_simplex);
771
288719
        break;
772
      default:
773
        throw std::logic_error("Invalid simplex rank");
774
    }
775
68506817
    assert(nfree + next_simplex.rank == 4);
776
68506817
    current = next;
777

68506817
    if (!inside) rl = ray.norm();
778

68506817
    if (inside || rl == 0) {
779
31243
      status = Inside;
780
31243
      distance = -inflation - 1.;
781
31243
      break;
782
    }
783
784
68475574
    status = ((++iterations) < max_iterations) ? status : Failed;
785
786
68547499
  } while (status == Valid);
787
788
30118472
  simplex = &simplices[current];
789

30118472
  assert(simplex->rank > 0 && simplex->rank < 5);
790
30118472
  return status;
791
}
792
793
98599461
bool GJK::checkConvergence(const Vec3f& w, const FCL_REAL& rl, FCL_REAL& alpha,
794
                           const FCL_REAL& omega) {
795
  FCL_REAL diff;
796
  bool check_passed;
797
  // x^* is the optimal solution (projection of origin onto the Minkowski
798
  // difference).
799
  //  x^k is the current iterate (x^k = `ray` in the code).
800
  // Each criterion provides a different guarantee on the distance to the
801
  // optimal solution.
802

98599461
  switch (convergence_criterion) {
803
98564697
    case VDB:
804
      // alpha is the distance to the best separating hyperplane found so far
805
98564697
      alpha = std::max(alpha, omega);
806
      // ||x^*|| - ||x^k|| <= diff
807
98564697
      diff = rl - alpha;
808
98564697
      switch (convergence_criterion_type) {
809
        case Absolute:
810
          throw std::logic_error("VDB convergence criterion is relative.");
811
          break;
812
98564697
        case Relative:
813
98564697
          check_passed = (diff - tolerance * rl) <= 0;
814
98564697
          break;
815
        default:
816
          throw std::logic_error("Invalid convergence criterion type.");
817
      }
818
98564697
      break;
819
820
17388
    case DualityGap:
821
      // ||x^* - x^k||^2 <= diff
822
17388
      diff = 2 * ray.dot(ray - w);
823
17388
      switch (convergence_criterion_type) {
824
8560
        case Absolute:
825
8560
          check_passed = (diff - tolerance) <= 0;
826
8560
          break;
827
8828
        case Relative:
828
8828
          check_passed = ((diff / tolerance * rl) - tolerance * rl) <= 0;
829
8828
          break;
830
        default:
831
          throw std::logic_error("Invalid convergence criterion type.");
832
      }
833
17388
      break;
834
835
17376
    case Hybrid:
836
      // alpha is the distance to the best separating hyperplane found so far
837
17376
      alpha = std::max(alpha, omega);
838
      // ||x^* - x^k||^2 <= diff
839
17376
      diff = rl * rl - alpha * alpha;
840
17376
      switch (convergence_criterion_type) {
841
8552
        case Absolute:
842
8552
          check_passed = (diff - tolerance) <= 0;
843
8552
          break;
844
8824
        case Relative:
845
8824
          check_passed = ((diff / tolerance * rl) - tolerance * rl) <= 0;
846
8824
          break;
847
        default:
848
          throw std::logic_error("Invalid convergence criterion type.");
849
      }
850
17376
      break;
851
852
    default:
853
      throw std::logic_error("Invalid convergence criterion.");
854
  }
855
98599461
  return check_passed;
856
}
857
858
30159131
inline void GJK::removeVertex(Simplex& simplex) {
859
30159131
  free_v[nfree++] = simplex.vertex[--simplex.rank];
860
30159131
}
861
862
98666072
inline void GJK::appendVertex(Simplex& simplex, const Vec3f& v,
863
                              bool isNormalized, support_func_guess_t& hint) {
864
98666072
  simplex.vertex[simplex.rank] = free_v[--nfree];  // set the memory
865
98666072
  getSupport(v, isNormalized, *simplex.vertex[simplex.rank++], hint);
866
98666072
}
867
868
694
bool GJK::encloseOrigin() {
869

694
  Vec3f axis(Vec3f::Zero());
870

694
  support_func_guess_t hint = support_func_guess_t::Zero();
871

694
  switch (simplex->rank) {
872
    case 1:
873
      for (int i = 0; i < 3; ++i) {
874
        axis[i] = 1;
875
        appendVertex(*simplex, axis, true, hint);
876
        if (encloseOrigin()) return true;
877
        removeVertex(*simplex);
878
        axis[i] = -1;
879
        appendVertex(*simplex, -axis, true, hint);
880
        if (encloseOrigin()) return true;
881
        removeVertex(*simplex);
882
        axis[i] = 0;
883
      }
884
      break;
885
45
    case 2: {
886

45
      Vec3f d = simplex->vertex[1]->w - simplex->vertex[0]->w;
887
84
      for (int i = 0; i < 3; ++i) {
888
84
        axis[i] = 1;
889
84
        Vec3f p = d.cross(axis);
890

84
        if (!p.isZero()) {
891
45
          appendVertex(*simplex, p, false, hint);
892

45
          if (encloseOrigin()) return true;
893
          removeVertex(*simplex);
894
          appendVertex(*simplex, -p, false, hint);
895
          if (encloseOrigin()) return true;
896
          removeVertex(*simplex);
897
        }
898
39
        axis[i] = 0;
899
      }
900
    } break;
901
77
    case 3:
902
77
      axis.noalias() =
903
77
          (simplex->vertex[1]->w - simplex->vertex[0]->w)
904

154
              .cross(simplex->vertex[2]->w - simplex->vertex[0]->w);
905

77
      if (!axis.isZero()) {
906
77
        appendVertex(*simplex, axis, false, hint);
907

77
        if (encloseOrigin()) return true;
908
        removeVertex(*simplex);
909
        appendVertex(*simplex, -axis, false, hint);
910
        if (encloseOrigin()) return true;
911
        removeVertex(*simplex);
912
      }
913
      break;
914
572
    case 4:
915

572
      if (std::abs(triple(simplex->vertex[0]->w - simplex->vertex[3]->w,
916
572
                          simplex->vertex[1]->w - simplex->vertex[3]->w,
917

1144
                          simplex->vertex[2]->w - simplex->vertex[3]->w)) > 0)
918
572
        return true;
919
      break;
920
  }
921
922
  return false;
923
}
924
925
25980570
inline void originToPoint(const GJK::Simplex& current, GJK::vertex_id_t a,
926
                          const Vec3f& A, GJK::Simplex& next, Vec3f& ray) {
927
  // A is the closest to the origin
928
25980570
  ray = A;
929
25980570
  next.vertex[0] = current.vertex[a];
930
25980570
  next.rank = 1;
931
25980570
}
932
933
11698703
inline void originToSegment(const GJK::Simplex& current, GJK::vertex_id_t a,
934
                            GJK::vertex_id_t b, const Vec3f& A, const Vec3f& B,
935
                            const Vec3f& AB, const FCL_REAL& ABdotAO,
936
                            GJK::Simplex& next, Vec3f& ray) {
937
  // ray = - ( AB ^ AO ) ^ AB = (AB.B) A + (-AB.A) B
938


11698703
  ray = AB.dot(B) * A + ABdotAO * B;
939
940
11698703
  next.vertex[0] = current.vertex[b];
941
11698703
  next.vertex[1] = current.vertex[a];
942
11698703
  next.rank = 2;
943
944
  // To ensure backward compatibility
945
11698703
  ray /= AB.squaredNorm();
946
11698703
}
947
948
677890
inline bool originToTriangle(const GJK::Simplex& current, GJK::vertex_id_t a,
949
                             GJK::vertex_id_t b, GJK::vertex_id_t c,
950
                             const Vec3f& ABC, const FCL_REAL& ABCdotAO,
951
                             GJK::Simplex& next, Vec3f& ray) {
952
677890
  next.rank = 3;
953
677890
  next.vertex[2] = current.vertex[a];
954
955
677890
  if (ABCdotAO == 0) {
956
18
    next.vertex[0] = current.vertex[c];
957
18
    next.vertex[1] = current.vertex[b];
958
18
    ray.setZero();
959
18
    return true;
960
  }
961
677872
  if (ABCdotAO > 0) {  // Above triangle
962
460983
    next.vertex[0] = current.vertex[c];
963
460983
    next.vertex[1] = current.vertex[b];
964
  } else {
965
216889
    next.vertex[0] = current.vertex[b];
966
216889
    next.vertex[1] = current.vertex[c];
967
  }
968
969
  // To ensure backward compatibility
970

677872
  ray = -ABCdotAO / ABC.squaredNorm() * ABC;
971
677872
  return false;
972
}
973
974
33932306
bool GJK::projectLineOrigin(const Simplex& current, Simplex& next) {
975
33932306
  const vertex_id_t a = 1, b = 0;
976
  // A is the last point we added.
977
33932306
  const Vec3f& A = current.vertex[a]->w;
978
33932306
  const Vec3f& B = current.vertex[b]->w;
979
980

33932306
  const Vec3f AB = B - A;
981

33932306
  const FCL_REAL d = AB.dot(-A);
982

33932306
  assert(d <= AB.squaredNorm());
983
984
33932306
  if (d == 0) {
985
    // Two extremely unlikely cases:
986
    // - AB is orthogonal to A: should never happen because it means the support
987
    //   function did not do any progress and GJK should have stopped.
988
    // - A == origin
989
    // In any case, A is the closest to the origin
990
3322
    originToPoint(current, a, A, next, ray);
991
3322
    free_v[nfree++] = current.vertex[b];
992
3322
    return A.isZero();
993
33928984
  } else if (d < 0) {
994
    // A is the closest to the origin
995
25343039
    originToPoint(current, a, A, next, ray);
996
25343039
    free_v[nfree++] = current.vertex[b];
997
  } else
998
8585945
    originToSegment(current, a, b, A, B, AB, d, next, ray);
999
33928984
  return false;
1000
}
1001
1002
4167321
bool GJK::projectTriangleOrigin(const Simplex& current, Simplex& next) {
1003
4167321
  const vertex_id_t a = 2, b = 1, c = 0;
1004
  // A is the last point we added.
1005
4167321
  const Vec3f &A = current.vertex[a]->w, B = current.vertex[b]->w,
1006
4167321
              C = current.vertex[c]->w;
1007
1008


4167321
  const Vec3f AB = B - A, AC = C - A, ABC = AB.cross(AC);
1009
1010

4167321
  FCL_REAL edgeAC2o = ABC.cross(AC).dot(-A);
1011
4167321
  if (edgeAC2o >= 0) {
1012

2072582
    FCL_REAL towardsC = AC.dot(-A);
1013
2072582
    if (towardsC >= 0) {  // Region 1
1014
401007
      originToSegment(current, a, c, A, C, AC, towardsC, next, ray);
1015
401007
      free_v[nfree++] = current.vertex[b];
1016
    } else {  // Region 4 or 5
1017

1671575
      FCL_REAL towardsB = AB.dot(-A);
1018
1671575
      if (towardsB < 0) {  // Region 5
1019
        // A is the closest to the origin
1020
633367
        originToPoint(current, a, A, next, ray);
1021
633367
        free_v[nfree++] = current.vertex[b];
1022
      } else  // Region 4
1023
1038208
        originToSegment(current, a, b, A, B, AB, towardsB, next, ray);
1024
1671575
      free_v[nfree++] = current.vertex[c];
1025
    }
1026
  } else {
1027

2094739
    FCL_REAL edgeAB2o = AB.cross(ABC).dot(-A);
1028
2094739
    if (edgeAB2o >= 0) {  // Region 4 or 5
1029

1648155
      FCL_REAL towardsB = AB.dot(-A);
1030
1648155
      if (towardsB < 0) {  // Region 5
1031
        // A is the closest to the origin
1032
158
        originToPoint(current, a, A, next, ray);
1033
158
        free_v[nfree++] = current.vertex[b];
1034
      } else  // Region 4
1035
1647997
        originToSegment(current, a, b, A, B, AB, towardsB, next, ray);
1036
1648155
      free_v[nfree++] = current.vertex[c];
1037
    } else {
1038

446584
      return originToTriangle(current, a, b, c, ABC, ABC.dot(-A), next, ray);
1039
    }
1040
  }
1041
3720737
  return false;
1042
}
1043
1044
288719
bool GJK::projectTetrahedraOrigin(const Simplex& current, Simplex& next) {
1045
  // The code of this function was generated using doc/gjk.py
1046
288719
  const vertex_id_t a = 3, b = 2, c = 1, d = 0;
1047
288719
  const Vec3f& A(current.vertex[a]->w);
1048
288719
  const Vec3f& B(current.vertex[b]->w);
1049
288719
  const Vec3f& C(current.vertex[c]->w);
1050
288719
  const Vec3f& D(current.vertex[d]->w);
1051
288719
  const FCL_REAL aa = A.squaredNorm();
1052
288719
  const FCL_REAL da = D.dot(A);
1053
288719
  const FCL_REAL db = D.dot(B);
1054
288719
  const FCL_REAL dc = D.dot(C);
1055
288719
  const FCL_REAL dd = D.dot(D);
1056
288719
  const FCL_REAL da_aa = da - aa;
1057
288719
  const FCL_REAL ca = C.dot(A);
1058
288719
  const FCL_REAL cb = C.dot(B);
1059
288719
  const FCL_REAL cc = C.dot(C);
1060
288719
  const FCL_REAL& cd = dc;
1061
288719
  const FCL_REAL ca_aa = ca - aa;
1062
288719
  const FCL_REAL ba = B.dot(A);
1063
288719
  const FCL_REAL bb = B.dot(B);
1064
288719
  const FCL_REAL& bc = cb;
1065
288719
  const FCL_REAL& bd = db;
1066
288719
  const FCL_REAL ba_aa = ba - aa;
1067
288719
  const FCL_REAL ba_ca = ba - ca;
1068
288719
  const FCL_REAL ca_da = ca - da;
1069
288719
  const FCL_REAL da_ba = da - ba;
1070
288719
  const Vec3f a_cross_b = A.cross(B);
1071
288719
  const Vec3f a_cross_c = A.cross(C);
1072
1073
288719
  const FCL_REAL dummy_precision = Eigen::NumTraits<FCL_REAL>::epsilon();
1074
  HPP_FCL_UNUSED_VARIABLE(dummy_precision);
1075
1076
#define REGION_INSIDE()               \
1077
  ray.setZero();                      \
1078
  next.vertex[0] = current.vertex[d]; \
1079
  next.vertex[1] = current.vertex[c]; \
1080
  next.vertex[2] = current.vertex[b]; \
1081
  next.vertex[3] = current.vertex[a]; \
1082
  next.rank = 4;                      \
1083
  return true;
1084
1085
288719
  if (ba_aa <= 0) {                // if AB.AO >= 0 / a10
1086

243268
    if (-D.dot(a_cross_b) <= 0) {  // if ADB.AO >= 0 / a10.a3
1087
171822
      if (ba * da_ba + bd * ba_aa - bb * da_aa <=
1088
          0) {             // if (ADB ^ AB).AO >= 0 / a10.a3.a9
1089
71581
        if (da_aa <= 0) {  // if AD.AO >= 0 / a10.a3.a9.a12
1090
22349
          assert(da * da_ba + dd * ba_aa - db * da_aa <=
1091
                 dummy_precision);  // (ADB ^ AD).AO >= 0 / a10.a3.a9.a12.a8
1092
22349
          if (ba * ba_ca + bb * ca_aa - bc * ba_aa <=
1093
              0) {  // if (ABC ^ AB).AO >= 0 / a10.a3.a9.a12.a8.a4
1094
            // Region ABC
1095

16319
            originToTriangle(current, a, b, c, (B - A).cross(C - A),
1096

16319
                             -C.dot(a_cross_b), next, ray);
1097
16319
            free_v[nfree++] = current.vertex[d];
1098
          } else {  // not (ABC ^ AB).AO >= 0 / a10.a3.a9.a12.a8.!a4
1099
            // Region AB
1100

6030
            originToSegment(current, a, b, A, B, B - A, -ba_aa, next, ray);
1101
6030
            free_v[nfree++] = current.vertex[c];
1102
6030
            free_v[nfree++] = current.vertex[d];
1103
          }       // end of (ABC ^ AB).AO >= 0
1104
        } else {  // not AD.AO >= 0 / a10.a3.a9.!a12
1105
49232
          if (ba * ba_ca + bb * ca_aa - bc * ba_aa <=
1106
              0) {  // if (ABC ^ AB).AO >= 0 / a10.a3.a9.!a12.a4
1107
42186
            if (ca * ba_ca + cb * ca_aa - cc * ba_aa <=
1108
                0) {  // if (ABC ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.a5
1109
1004
              if (ca * ca_da + cc * da_aa - cd * ca_aa <=
1110
                  0) {  // if (ACD ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.a5.a6
1111
                // Region ACD
1112

342
                originToTriangle(current, a, c, d, (C - A).cross(D - A),
1113

342
                                 -D.dot(a_cross_c), next, ray);
1114
342
                free_v[nfree++] = current.vertex[b];
1115
              } else {  // not (ACD ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.a5.!a6
1116
                // Region AC
1117

662
                originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray);
1118
662
                free_v[nfree++] = current.vertex[b];
1119
662
                free_v[nfree++] = current.vertex[d];
1120
              }       // end of (ACD ^ AC).AO >= 0
1121
            } else {  // not (ABC ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.!a5
1122
              // Region ABC
1123

41182
              originToTriangle(current, a, b, c, (B - A).cross(C - A),
1124

41182
                               -C.dot(a_cross_b), next, ray);
1125
41182
              free_v[nfree++] = current.vertex[d];
1126
            }       // end of (ABC ^ AC).AO >= 0
1127
          } else {  // not (ABC ^ AB).AO >= 0 / a10.a3.a9.!a12.!a4
1128
            // Region AB
1129

7046
            originToSegment(current, a, b, A, B, B - A, -ba_aa, next, ray);
1130
7046
            free_v[nfree++] = current.vertex[c];
1131
7046
            free_v[nfree++] = current.vertex[d];
1132
          }     // end of (ABC ^ AB).AO >= 0
1133
        }       // end of AD.AO >= 0
1134
      } else {  // not (ADB ^ AB).AO >= 0 / a10.a3.!a9
1135
100241
        if (da * da_ba + dd * ba_aa - db * da_aa <=
1136
            0) {  // if (ADB ^ AD).AO >= 0 / a10.a3.!a9.a8
1137
          // Region ADB
1138

97453
          originToTriangle(current, a, d, b, (D - A).cross(B - A),
1139

97453
                           D.dot(a_cross_b), next, ray);
1140
97453
          free_v[nfree++] = current.vertex[c];
1141
        } else {  // not (ADB ^ AD).AO >= 0 / a10.a3.!a9.!a8
1142
2788
          if (ca * ca_da + cc * da_aa - cd * ca_aa <=
1143
              0) {  // if (ACD ^ AC).AO >= 0 / a10.a3.!a9.!a8.a6
1144
2735
            if (da * ca_da + dc * da_aa - dd * ca_aa <=
1145
                0) {  // if (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.a6.a7
1146
              // Region AD
1147

1448
              originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray);
1148
1448
              free_v[nfree++] = current.vertex[b];
1149
1448
              free_v[nfree++] = current.vertex[c];
1150
            } else {  // not (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.a6.!a7
1151
              // Region ACD
1152

1287
              originToTriangle(current, a, c, d, (C - A).cross(D - A),
1153

1287
                               -D.dot(a_cross_c), next, ray);
1154
1287
              free_v[nfree++] = current.vertex[b];
1155
            }       // end of (ACD ^ AD).AO >= 0
1156
          } else {  // not (ACD ^ AC).AO >= 0 / a10.a3.!a9.!a8.!a6
1157
53
            if (da * ca_da + dc * da_aa - dd * ca_aa <=
1158
                0) {  // if (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.!a6.a7
1159
              // Region AD
1160

53
              originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray);
1161
53
              free_v[nfree++] = current.vertex[b];
1162
53
              free_v[nfree++] = current.vertex[c];
1163
            } else {  // not (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.!a6.!a7
1164
              // Region AC
1165
              originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray);
1166
              free_v[nfree++] = current.vertex[b];
1167
              free_v[nfree++] = current.vertex[d];
1168
            }                       // end of (ACD ^ AD).AO >= 0
1169
          }                         // end of (ACD ^ AC).AO >= 0
1170
        }                           // end of (ADB ^ AD).AO >= 0
1171
      }                             // end of (ADB ^ AB).AO >= 0
1172
    } else {                        // not ADB.AO >= 0 / a10.!a3
1173

71446
      if (C.dot(a_cross_b) <= 0) {  // if ABC.AO >= 0 / a10.!a3.a1
1174
41489
        if (ba * ba_ca + bb * ca_aa - bc * ba_aa <=
1175
            0) {  // if (ABC ^ AB).AO >= 0 / a10.!a3.a1.a4
1176
41479
          if (ca * ba_ca + cb * ca_aa - cc * ba_aa <=
1177
              0) {  // if (ABC ^ AC).AO >= 0 / a10.!a3.a1.a4.a5
1178
2211
            if (ca * ca_da + cc * da_aa - cd * ca_aa <=
1179
                0) {  // if (ACD ^ AC).AO >= 0 / a10.!a3.a1.a4.a5.a6
1180
              // Region ACD
1181

1319
              originToTriangle(current, a, c, d, (C - A).cross(D - A),
1182

1319
                               -D.dot(a_cross_c), next, ray);
1183
1319
              free_v[nfree++] = current.vertex[b];
1184
            } else {  // not (ACD ^ AC).AO >= 0 / a10.!a3.a1.a4.a5.!a6
1185
              // Region AC
1186

892
              originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray);
1187
892
              free_v[nfree++] = current.vertex[b];
1188
892
              free_v[nfree++] = current.vertex[d];
1189
            }       // end of (ACD ^ AC).AO >= 0
1190
          } else {  // not (ABC ^ AC).AO >= 0 / a10.!a3.a1.a4.!a5
1191
            // Region ABC
1192

39268
            originToTriangle(current, a, b, c, (B - A).cross(C - A),
1193

39268
                             -C.dot(a_cross_b), next, ray);
1194
39268
            free_v[nfree++] = current.vertex[d];
1195
          }       // end of (ABC ^ AC).AO >= 0
1196
        } else {  // not (ABC ^ AB).AO >= 0 / a10.!a3.a1.!a4
1197
          // Region AB
1198

10
          originToSegment(current, a, b, A, B, B - A, -ba_aa, next, ray);
1199
10
          free_v[nfree++] = current.vertex[c];
1200
10
          free_v[nfree++] = current.vertex[d];
1201
        }                             // end of (ABC ^ AB).AO >= 0
1202
      } else {                        // not ABC.AO >= 0 / a10.!a3.!a1
1203

29957
        if (D.dot(a_cross_c) <= 0) {  // if ACD.AO >= 0 / a10.!a3.!a1.a2
1204
1900
          if (ca * ca_da + cc * da_aa - cd * ca_aa <=
1205
              0) {  // if (ACD ^ AC).AO >= 0 / a10.!a3.!a1.a2.a6
1206
1900
            if (da * ca_da + dc * da_aa - dd * ca_aa <=
1207
                0) {  // if (ACD ^ AD).AO >= 0 / a10.!a3.!a1.a2.a6.a7
1208
              // Region AD
1209
              originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray);
1210
              free_v[nfree++] = current.vertex[b];
1211
              free_v[nfree++] = current.vertex[c];
1212
            } else {  // not (ACD ^ AD).AO >= 0 / a10.!a3.!a1.a2.a6.!a7
1213
              // Region ACD
1214

1900
              originToTriangle(current, a, c, d, (C - A).cross(D - A),
1215

1900
                               -D.dot(a_cross_c), next, ray);
1216
1900
              free_v[nfree++] = current.vertex[b];
1217
            }                  // end of (ACD ^ AD).AO >= 0
1218
          } else {             // not (ACD ^ AC).AO >= 0 / a10.!a3.!a1.a2.!a6
1219
            if (ca_aa <= 0) {  // if AC.AO >= 0 / a10.!a3.!a1.a2.!a6.a11
1220
              // Region AC
1221
              originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray);
1222
              free_v[nfree++] = current.vertex[b];
1223
              free_v[nfree++] = current.vertex[d];
1224
            } else {  // not AC.AO >= 0 / a10.!a3.!a1.a2.!a6.!a11
1225
              // Region AD
1226
              originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray);
1227
              free_v[nfree++] = current.vertex[b];
1228
              free_v[nfree++] = current.vertex[c];
1229
            }     // end of AC.AO >= 0
1230
          }       // end of (ACD ^ AC).AO >= 0
1231
        } else {  // not ACD.AO >= 0 / a10.!a3.!a1.!a2
1232
          // Region Inside
1233
28057
          REGION_INSIDE()
1234
        }                           // end of ACD.AO >= 0
1235
      }                             // end of ABC.AO >= 0
1236
    }                               // end of ADB.AO >= 0
1237
  } else {                          // not AB.AO >= 0 / !a10
1238
45451
    if (ca_aa <= 0) {               // if AC.AO >= 0 / !a10.a11
1239

33328
      if (D.dot(a_cross_c) <= 0) {  // if ACD.AO >= 0 / !a10.a11.a2
1240
29434
        if (da_aa <= 0) {           // if AD.AO >= 0 / !a10.a11.a2.a12
1241
18819
          if (ca * ca_da + cc * da_aa - cd * ca_aa <=
1242
              0) {  // if (ACD ^ AC).AO >= 0 / !a10.a11.a2.a12.a6
1243
17690
            if (da * ca_da + dc * da_aa - dd * ca_aa <=
1244
                0) {  // if (ACD ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.a7
1245
1212
              if (da * da_ba + dd * ba_aa - db * da_aa <=
1246
                  0) {  // if (ADB ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.a7.a8
1247
                // Region ADB
1248

441
                originToTriangle(current, a, d, b, (D - A).cross(B - A),
1249

441
                                 D.dot(a_cross_b), next, ray);
1250
441
                free_v[nfree++] = current.vertex[c];
1251
              } else {  // not (ADB ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.a7.!a8
1252
                // Region AD
1253

771
                originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray);
1254
771
                free_v[nfree++] = current.vertex[b];
1255
771
                free_v[nfree++] = current.vertex[c];
1256
              }       // end of (ADB ^ AD).AO >= 0
1257
            } else {  // not (ACD ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.!a7
1258
              // Region ACD
1259

16478
              originToTriangle(current, a, c, d, (C - A).cross(D - A),
1260

16478
                               -D.dot(a_cross_c), next, ray);
1261
16478
              free_v[nfree++] = current.vertex[b];
1262
            }       // end of (ACD ^ AD).AO >= 0
1263
          } else {  // not (ACD ^ AC).AO >= 0 / !a10.a11.a2.a12.!a6
1264
1129
            assert(!(da * ca_da + dc * da_aa - dd * ca_aa <=
1265
                     dummy_precision));  // Not (ACD ^ AD).AO >= 0 /
1266
                                         // !a10.a11.a2.a12.!a6.!a7
1267
1129
            if (ca * ba_ca + cb * ca_aa - cc * ba_aa <=
1268
                0) {  // if (ABC ^ AC).AO >= 0 / !a10.a11.a2.a12.!a6.!a7.a5
1269
              // Region AC
1270

701
              originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray);
1271
701
              free_v[nfree++] = current.vertex[b];
1272
701
              free_v[nfree++] = current.vertex[d];
1273
            } else {  // not (ABC ^ AC).AO >= 0 / !a10.a11.a2.a12.!a6.!a7.!a5
1274
              // Region ABC
1275

428
              originToTriangle(current, a, b, c, (B - A).cross(C - A),
1276

428
                               -C.dot(a_cross_b), next, ray);
1277
428
              free_v[nfree++] = current.vertex[d];
1278
            }     // end of (ABC ^ AC).AO >= 0
1279
          }       // end of (ACD ^ AC).AO >= 0
1280
        } else {  // not AD.AO >= 0 / !a10.a11.a2.!a12
1281
10615
          if (ca * ba_ca + cb * ca_aa - cc * ba_aa <=
1282
              0) {  // if (ABC ^ AC).AO >= 0 / !a10.a11.a2.!a12.a5
1283
7438
            if (ca * ca_da + cc * da_aa - cd * ca_aa <=
1284
                0) {  // if (ACD ^ AC).AO >= 0 / !a10.a11.a2.!a12.a5.a6
1285
3776
              assert(!(da * ca_da + dc * da_aa - dd * ca_aa <=
1286
                       -dummy_precision));  // Not (ACD ^ AD).AO >= 0 /
1287
                                            // !a10.a11.a2.!a12.a5.a6.!a7
1288
              // Region ACD
1289

3776
              originToTriangle(current, a, c, d, (C - A).cross(D - A),
1290

3776
                               -D.dot(a_cross_c), next, ray);
1291
3776
              free_v[nfree++] = current.vertex[b];
1292
            } else {  // not (ACD ^ AC).AO >= 0 / !a10.a11.a2.!a12.a5.!a6
1293
              // Region AC
1294

3662
              originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray);
1295
3662
              free_v[nfree++] = current.vertex[b];
1296
3662
              free_v[nfree++] = current.vertex[d];
1297
            }       // end of (ACD ^ AC).AO >= 0
1298
          } else {  // not (ABC ^ AC).AO >= 0 / !a10.a11.a2.!a12.!a5
1299

3177
            if (C.dot(a_cross_b) <=
1300
                0) {  // if ABC.AO >= 0 / !a10.a11.a2.!a12.!a5.a1
1301
2693
              assert(ba * ba_ca + bb * ca_aa - bc * ba_aa <=
1302
                     dummy_precision);  // (ABC ^ AB).AO >= 0 /
1303
                                        // !a10.a11.a2.!a12.!a5.a1.a4
1304
              // Region ABC
1305

2693
              originToTriangle(current, a, b, c, (B - A).cross(C - A),
1306

2693
                               -C.dot(a_cross_b), next, ray);
1307
2693
              free_v[nfree++] = current.vertex[d];
1308
            } else {  // not ABC.AO >= 0 / !a10.a11.a2.!a12.!a5.!a1
1309
484
              assert(!(da * ca_da + dc * da_aa - dd * ca_aa <=
1310
                       -dummy_precision));  // Not (ACD ^ AD).AO >= 0 /
1311
                                            // !a10.a11.a2.!a12.!a5.!a1.!a7
1312
              // Region ACD
1313

484
              originToTriangle(current, a, c, d, (C - A).cross(D - A),
1314

484
                               -D.dot(a_cross_c), next, ray);
1315
484
              free_v[nfree++] = current.vertex[b];
1316
            }                         // end of ABC.AO >= 0
1317
          }                           // end of (ABC ^ AC).AO >= 0
1318
        }                             // end of AD.AO >= 0
1319
      } else {                        // not ACD.AO >= 0 / !a10.a11.!a2
1320

3894
        if (C.dot(a_cross_b) <= 0) {  // if ABC.AO >= 0 / !a10.a11.!a2.a1
1321
1593
          if (ca * ba_ca + cb * ca_aa - cc * ba_aa <=
1322
              0) {  // if (ABC ^ AC).AO >= 0 / !a10.a11.!a2.a1.a5
1323
            // Region AC
1324

77
            originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray);
1325
77
            free_v[nfree++] = current.vertex[b];
1326
77
            free_v[nfree++] = current.vertex[d];
1327
          } else {  // not (ABC ^ AC).AO >= 0 / !a10.a11.!a2.a1.!a5
1328
1516
            assert(ba * ba_ca + bb * ca_aa - bc * ba_aa <=
1329
                   dummy_precision);  // (ABC ^ AB).AO >= 0 /
1330
                                      // !a10.a11.!a2.a1.!a5.a4
1331
            // Region ABC
1332

1516
            originToTriangle(current, a, b, c, (B - A).cross(C - A),
1333

1516
                             -C.dot(a_cross_b), next, ray);
1334
1516
            free_v[nfree++] = current.vertex[d];
1335
          }                              // end of (ABC ^ AC).AO >= 0
1336
        } else {                         // not ABC.AO >= 0 / !a10.a11.!a2.!a1
1337

2301
          if (-D.dot(a_cross_b) <= 0) {  // if ADB.AO >= 0 / !a10.a11.!a2.!a1.a3
1338
18
            if (da * da_ba + dd * ba_aa - db * da_aa <=
1339
                0) {  // if (ADB ^ AD).AO >= 0 / !a10.a11.!a2.!a1.a3.a8
1340
              // Region ADB
1341

18
              originToTriangle(current, a, d, b, (D - A).cross(B - A),
1342

18
                               D.dot(a_cross_b), next, ray);
1343
18
              free_v[nfree++] = current.vertex[c];
1344
            } else {  // not (ADB ^ AD).AO >= 0 / !a10.a11.!a2.!a1.a3.!a8
1345
              // Region AD
1346
              originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray);
1347
              free_v[nfree++] = current.vertex[b];
1348
              free_v[nfree++] = current.vertex[c];
1349
            }       // end of (ADB ^ AD).AO >= 0
1350
          } else {  // not ADB.AO >= 0 / !a10.a11.!a2.!a1.!a3
1351
            // Region Inside
1352
2283
            REGION_INSIDE()
1353
          }                            // end of ADB.AO >= 0
1354
        }                              // end of ABC.AO >= 0
1355
      }                                // end of ACD.AO >= 0
1356
    } else {                           // not AC.AO >= 0 / !a10.!a11
1357
12123
      if (da_aa <= 0) {                // if AD.AO >= 0 / !a10.!a11.a12
1358

11439
        if (-D.dot(a_cross_b) <= 0) {  // if ADB.AO >= 0 / !a10.!a11.a12.a3
1359
9544
          if (da * ca_da + dc * da_aa - dd * ca_aa <=
1360
              0) {  // if (ACD ^ AD).AO >= 0 / !a10.!a11.a12.a3.a7
1361
7084
            if (da * da_ba + dd * ba_aa - db * da_aa <=
1362
                0) {  // if (ADB ^ AD).AO >= 0 / !a10.!a11.a12.a3.a7.a8
1363
2926
              assert(!(ba * da_ba + bd * ba_aa - bb * da_aa <=
1364
                       -dummy_precision));  // Not (ADB ^ AB).AO >= 0 /
1365
                                            // !a10.!a11.a12.a3.a7.a8.!a9
1366
              // Region ADB
1367

2926
              originToTriangle(current, a, d, b, (D - A).cross(B - A),
1368

2926
                               D.dot(a_cross_b), next, ray);
1369
2926
              free_v[nfree++] = current.vertex[c];
1370
            } else {  // not (ADB ^ AD).AO >= 0 / !a10.!a11.a12.a3.a7.!a8
1371
              // Region AD
1372

4158
              originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray);
1373
4158
              free_v[nfree++] = current.vertex[b];
1374
4158
              free_v[nfree++] = current.vertex[c];
1375
            }       // end of (ADB ^ AD).AO >= 0
1376
          } else {  // not (ACD ^ AD).AO >= 0 / !a10.!a11.a12.a3.!a7
1377

2460
            if (D.dot(a_cross_c) <=
1378
                0) {  // if ACD.AO >= 0 / !a10.!a11.a12.a3.!a7.a2
1379
2389
              assert(ca * ca_da + cc * da_aa - cd * ca_aa <=
1380
                     dummy_precision);  // (ACD ^ AC).AO >= 0 /
1381
                                        // !a10.!a11.a12.a3.!a7.a2.a6
1382
              // Region ACD
1383

2389
              originToTriangle(current, a, c, d, (C - A).cross(D - A),
1384

2389
                               -D.dot(a_cross_c), next, ray);
1385
2389
              free_v[nfree++] = current.vertex[b];
1386
            } else {  // not ACD.AO >= 0 / !a10.!a11.a12.a3.!a7.!a2
1387

71
              if (C.dot(a_cross_b) <=
1388
                  0) {  // if ABC.AO >= 0 / !a10.!a11.a12.a3.!a7.!a2.a1
1389
46
                assert(!(ba * ba_ca + bb * ca_aa - bc * ba_aa <=
1390
                         -dummy_precision));  // Not (ABC ^ AB).AO >= 0 /
1391
                                              // !a10.!a11.a12.a3.!a7.!a2.a1.!a4
1392
                // Region ADB
1393

46
                originToTriangle(current, a, d, b, (D - A).cross(B - A),
1394

46
                                 D.dot(a_cross_b), next, ray);
1395
46
                free_v[nfree++] = current.vertex[c];
1396
              } else {  // not ABC.AO >= 0 / !a10.!a11.a12.a3.!a7.!a2.!a1
1397
                // Region ADB
1398

25
                originToTriangle(current, a, d, b, (D - A).cross(B - A),
1399

25
                                 D.dot(a_cross_b), next, ray);
1400
25
                free_v[nfree++] = current.vertex[c];
1401
              }                         // end of ABC.AO >= 0
1402
            }                           // end of ACD.AO >= 0
1403
          }                             // end of (ACD ^ AD).AO >= 0
1404
        } else {                        // not ADB.AO >= 0 / !a10.!a11.a12.!a3
1405

1895
          if (D.dot(a_cross_c) <= 0) {  // if ACD.AO >= 0 / !a10.!a11.a12.!a3.a2
1406
1052
            if (da * ca_da + dc * da_aa - dd * ca_aa <=
1407
                0) {  // if (ACD ^ AD).AO >= 0 / !a10.!a11.a12.!a3.a2.a7
1408
              // Region AD
1409

36
              originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray);
1410
36
              free_v[nfree++] = current.vertex[b];
1411
36
              free_v[nfree++] = current.vertex[c];
1412
            } else {  // not (ACD ^ AD).AO >= 0 / !a10.!a11.a12.!a3.a2.!a7
1413
1016
              assert(ca * ca_da + cc * da_aa - cd * ca_aa <=
1414
                     dummy_precision);  // (ACD ^ AC).AO >= 0 /
1415
                                        // !a10.!a11.a12.!a3.a2.!a7.a6
1416
              // Region ACD
1417

1016
              originToTriangle(current, a, c, d, (C - A).cross(D - A),
1418

1016
                               -D.dot(a_cross_c), next, ray);
1419
1016
              free_v[nfree++] = current.vertex[b];
1420
            }       // end of (ACD ^ AD).AO >= 0
1421
          } else {  // not ACD.AO >= 0 / !a10.!a11.a12.!a3.!a2
1422
            // Region Inside
1423
843
            REGION_INSIDE()
1424
          }     // end of ACD.AO >= 0
1425
        }       // end of ADB.AO >= 0
1426
      } else {  // not AD.AO >= 0 / !a10.!a11.!a12
1427
        // Region A
1428
684
        originToPoint(current, a, A, next, ray);
1429
684
        free_v[nfree++] = current.vertex[b];
1430
684
        free_v[nfree++] = current.vertex[c];
1431
684
        free_v[nfree++] = current.vertex[d];
1432
      }  // end of AD.AO >= 0
1433
    }    // end of AC.AO >= 0
1434
  }      // end of AB.AO >= 0
1435
1436
#undef REGION_INSIDE
1437
257536
  return false;
1438
}
1439
1440
574
void EPA::initialize() {
1441

37310
  sv_store = new SimplexV[max_vertex_num];
1442

74046
  fc_store = new SimplexF[max_face_num];
1443
574
  status = Failed;
1444
574
  normal = Vec3f(0, 0, 0);
1445
574
  depth = 0;
1446
574
  nextsv = 0;
1447
74046
  for (size_t i = 0; i < max_face_num; ++i)
1448
73472
    stock.append(&fc_store[max_face_num - i - 1]);
1449
574
}
1450
1451
74776
bool EPA::getEdgeDist(SimplexF* face, SimplexV* a, SimplexV* b,
1452
                      FCL_REAL& dist) {
1453

74776
  Vec3f ab = b->w - a->w;
1454
74776
  Vec3f n_ab = ab.cross(face->n);
1455
74776
  FCL_REAL a_dot_nab = a->w.dot(n_ab);
1456
1457
74776
  if (a_dot_nab < 0)  // the origin is on the outside part of ab
1458
  {
1459
    // following is similar to projectOrigin for two points
1460
    // however, as we dont need to compute the parameterization, dont need to
1461
    // compute 0 or 1
1462
14932
    FCL_REAL a_dot_ab = a->w.dot(ab);
1463
14932
    FCL_REAL b_dot_ab = b->w.dot(ab);
1464
1465
14932
    if (a_dot_ab > 0)
1466
1176
      dist = a->w.norm();
1467
13756
    else if (b_dot_ab < 0)
1468
1578
      dist = b->w.norm();
1469
    else {
1470
12178
      dist = std::sqrt(std::max(
1471

12178
          a->w.squaredNorm() - a_dot_ab * a_dot_ab / ab.squaredNorm(), 0.));
1472
    }
1473
1474
14932
    return true;
1475
  }
1476
1477
59844
  return false;
1478
}
1479
1480
29644
EPA::SimplexF* EPA::newFace(SimplexV* a, SimplexV* b, SimplexV* c,
1481
                            bool forced) {
1482
29644
  if (stock.root) {
1483
29618
    SimplexF* face = stock.root;
1484
29618
    stock.remove(face);
1485
29618
    hull.append(face);
1486
29618
    face->pass = 0;
1487
29618
    face->vertex[0] = a;
1488
29618
    face->vertex[1] = b;
1489
29618
    face->vertex[2] = c;
1490

29618
    face->n = (b->w - a->w).cross(c->w - a->w);
1491
29618
    FCL_REAL l = face->n.norm();
1492
1493
29618
    if (l > Eigen::NumTraits<FCL_REAL>::epsilon()) {
1494
29618
      face->n /= l;
1495
1496

55126
      if (!(getEdgeDist(face, a, b, face->d) ||
1497

25508
            getEdgeDist(face, b, c, face->d) ||
1498

19650
            getEdgeDist(face, c, a, face->d))) {
1499
14686
        face->d = a->w.dot(face->n);
1500
      }
1501
1502

29618
      if (forced || face->d >= -tolerance)
1503
29618
        return face;
1504
      else
1505
        status = NonConvex;
1506
    } else
1507
      status = Degenerated;
1508
1509
    hull.remove(face);
1510
    stock.append(face);
1511
    return NULL;
1512
  }
1513
1514
26
  status = stock.root ? OutOfVertices : OutOfFaces;
1515
26
  return NULL;
1516
}
1517
1518
/** @brief Find the best polytope face to split */
1519
6292
EPA::SimplexF* EPA::findBest() {
1520
6292
  SimplexF* minf = hull.root;
1521
6292
  FCL_REAL mind = minf->d * minf->d;
1522
189440
  for (SimplexF* f = minf->l[1]; f; f = f->l[1]) {
1523
183148
    FCL_REAL sqd = f->d * f->d;
1524
183148
    if (sqd < mind) {
1525
12603
      minf = f;
1526
12603
      mind = sqd;
1527
    }
1528
  }
1529
6292
  return minf;
1530
}
1531
1532
574
EPA::Status EPA::evaluate(GJK& gjk, const Vec3f& guess) {
1533
574
  GJK::Simplex& simplex = *gjk.getSimplex();
1534
574
  support_func_guess_t hint(gjk.support_hint);
1535


574
  if ((simplex.rank > 1) && gjk.encloseOrigin()) {
1536
572
    while (hull.root) {
1537
      SimplexF* f = hull.root;
1538
      hull.remove(f);
1539
      stock.append(f);
1540
    }
1541
1542
572
    status = Valid;
1543
572
    nextsv = 0;
1544
1545
572
    if ((simplex.vertex[0]->w - simplex.vertex[3]->w)
1546

1144
            .dot((simplex.vertex[1]->w - simplex.vertex[3]->w)
1547

1144
                     .cross(simplex.vertex[2]->w - simplex.vertex[3]->w)) < 0) {
1548
77
      SimplexV* tmp = simplex.vertex[0];
1549
77
      simplex.vertex[0] = simplex.vertex[1];
1550
77
      simplex.vertex[1] = tmp;
1551
    }
1552
1553
    SimplexF* tetrahedron[] = {
1554
572
        newFace(simplex.vertex[0], simplex.vertex[1], simplex.vertex[2], true),
1555
1144
        newFace(simplex.vertex[1], simplex.vertex[0], simplex.vertex[3], true),
1556
1144
        newFace(simplex.vertex[2], simplex.vertex[1], simplex.vertex[3], true),
1557

572
        newFace(simplex.vertex[0], simplex.vertex[2], simplex.vertex[3], true)};
1558
1559
572
    if (hull.count == 4) {
1560
572
      SimplexF* best = findBest();  // find the best face (the face with the
1561
                                    // minimum distance to origin) to split
1562
572
      SimplexF outer = *best;
1563
572
      size_t pass = 0;
1564
572
      size_t iterations = 0;
1565
1566
      // set the face connectivity
1567
572
      bind(tetrahedron[0], 0, tetrahedron[1], 0);
1568
572
      bind(tetrahedron[0], 1, tetrahedron[2], 0);
1569
572
      bind(tetrahedron[0], 2, tetrahedron[3], 0);
1570
572
      bind(tetrahedron[1], 1, tetrahedron[3], 2);
1571
572
      bind(tetrahedron[1], 2, tetrahedron[2], 1);
1572
572
      bind(tetrahedron[2], 2, tetrahedron[3], 1);
1573
1574
572
      status = Valid;
1575
6292
      for (; iterations < max_iterations; ++iterations) {
1576
6292
        if (nextsv >= max_vertex_num) {
1577
          status = OutOfVertices;
1578
572
          break;
1579
        }
1580
1581
6292
        SimplexHorizon horizon;
1582
6292
        SimplexV* w = &sv_store[nextsv++];
1583
6292
        bool valid = true;
1584
6292
        best->pass = ++pass;
1585
        // At the moment, SimplexF.n is always normalized. This could be revised
1586
        // in the future...
1587
6292
        gjk.getSupport(best->n, true, *w, hint);
1588
6292
        FCL_REAL wdist = best->n.dot(w->w) - best->d;
1589
6292
        if (wdist <= tolerance) {
1590
536
          status = AccuracyReached;
1591
536
          break;
1592
        }
1593

22990
        for (size_t j = 0; (j < 3) && valid; ++j)
1594
17234
          valid &= expand(pass, w, best->f[j], best->e[j], horizon);
1595
1596

5756
        if (!valid || horizon.nf < 3) {
1597
          // The status has already been set by the expand function.
1598
36
          assert(!(status & Valid));
1599
36
          break;
1600
        }
1601
        // need to add the edge connectivity between first and last faces
1602
5720
        bind(horizon.ff, 2, horizon.cf, 1);
1603
5720
        hull.remove(best);
1604
5720
        stock.append(best);
1605
5720
        best = findBest();
1606
5720
        outer = *best;
1607
      }
1608
1609
572
      normal = outer.n;
1610
572
      depth = outer.d;
1611
572
      result.rank = 3;
1612
572
      result.vertex[0] = outer.vertex[0];
1613
572
      result.vertex[1] = outer.vertex[1];
1614
572
      result.vertex[2] = outer.vertex[2];
1615
572
      return status;
1616
    }
1617
  }
1618
1619
  // FallBack when the simplex given by GJK is of rank 1.
1620
  // Since the simplex only contains support points which convex
1621
  // combination describe the origin, the point in the simplex is actually
1622
  // the origin.
1623
2
  status = FallBack;
1624
  // TODO: define a better normal
1625

2
  assert(simplex.rank == 1 && simplex.vertex[0]->w.isZero(gjk.getTolerance()));
1626

2
  normal = -guess;
1627
2
  FCL_REAL nl = normal.norm();
1628
2
  if (nl > 0)
1629
2
    normal /= nl;
1630
  else
1631
    normal = Vec3f(1, 0, 0);
1632
2
  depth = 0;
1633
2
  result.rank = 1;
1634
2
  result.vertex[0] = simplex.vertex[0];
1635
2
  return status;
1636
}
1637
1638
/** @brief the goal is to add a face connecting vertex w and face edge f[e] */
1639
37536
bool EPA::expand(size_t pass, SimplexV* w, SimplexF* f, size_t e,
1640
                 SimplexHorizon& horizon) {
1641
  static const size_t nexti[] = {1, 2, 0};
1642
  static const size_t previ[] = {2, 0, 1};
1643
1644
37536
  if (f->pass == pass) {
1645
10
    status = InvalidHull;
1646
10
    return false;
1647
  }
1648
1649
37526
  const size_t e1 = nexti[e];
1650
1651
  // case 1: the new face is not degenerated, i.e., the new face is not coplanar
1652
  // with the old face f.
1653
37526
  if (f->n.dot(w->w - f->vertex[e]->w) <
1654
37526
      -Eigen::NumTraits<FCL_REAL>::epsilon()) {
1655
27356
    SimplexF* nf = newFace(f->vertex[e1], f->vertex[e], w, false);
1656
27356
    if (nf) {
1657
      // add face-face connectivity
1658
27330
      bind(nf, 0, f, e);
1659
1660
      // if there is last face in the horizon, then need to add another
1661
      // connectivity, i.e. the edge connecting the current new add edge and the
1662
      // last new add edge. This does not finish all the connectivities because
1663
      // the final face need to connect with the first face, this will be
1664
      // handled in the evaluate function. Notice the face is anti-clockwise, so
1665
      // the edges are 0 (bottom), 1 (right), 2 (left)
1666
27330
      if (horizon.cf)
1667
21578
        bind(nf, 2, horizon.cf, 1);
1668
      else
1669
5752
        horizon.ff = nf;
1670
1671
27330
      horizon.cf = nf;
1672
27330
      ++horizon.nf;
1673
27330
      return true;
1674
    }
1675
26
    return false;
1676
  }
1677
1678
  // case 2: the new face is coplanar with the old face f. We need to add two
1679
  // faces and delete the old face
1680
10170
  const size_t e2 = previ[e];
1681
10170
  f->pass = pass;
1682

20302
  if (expand(pass, w, f->f[e1], f->e[e1], horizon) &&
1683
10132
      expand(pass, w, f->f[e2], f->e[e2], horizon)) {
1684
10068
    hull.remove(f);
1685
10068
    stock.append(f);
1686
10068
    return true;
1687
  }
1688
102
  return false;
1689
}
1690
1691
564
bool EPA::getClosestPoints(const MinkowskiDiff& shape, Vec3f& w0, Vec3f& w1) {
1692
564
  bool res = details::getClosestPoints(result, w0, w1);
1693
564
  if (!res) return false;
1694
564
  details::inflate<false>(shape, w0, w1);
1695
564
  return true;
1696
}
1697
1698
}  // namespace details
1699
1700
}  // namespace fcl
1701
1702
}  // namespace hpp