GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: test/obb.cpp Lines: 510 663 76.9 %
Date: 2024-02-09 12:57:42 Branches: 1014 2110 48.1 %

Line Branch Exec Source
1
/*
2
 * Software License Agreement (BSD License)
3
 *
4
 *  Copyright (c) 2014-2016, CNRS-LAAS
5
 *  Copyright (c) 2023, Inria
6
 *  Author: Florent Lamiraux
7
 *  All rights reserved.
8
 *
9
 *  Redistribution and use in source and binary forms, with or without
10
 *  modification, are permitted provided that the following conditions
11
 *  are met:
12
 *
13
 *   * Redistributions of source code must retain the above copyright
14
 *     notice, this list of conditions and the following disclaimer.
15
 *   * Redistributions in binary form must reproduce the above
16
 *     copyright notice, this list of conditions and the following
17
 *     disclaimer in the documentation and/or other materials provided
18
 *     with the distribution.
19
 *   * Neither the name of CNRS nor the names of its
20
 *     contributors may be used to endorse or promote products derived
21
 *     from this software without specific prior written permission.
22
 *
23
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34
 *  POSSIBILITY OF SUCH DAMAGE.
35
 */
36
37
#include <iostream>
38
#include <fstream>
39
#include <sstream>
40
41
#include <chrono>
42
43
#include <hpp/fcl/narrowphase/narrowphase.h>
44
45
#include "../src/BV/OBB.h"
46
#include <hpp/fcl/internal/shape_shape_func.h>
47
#include "utility.h"
48
49
using namespace hpp::fcl;
50
51
10
void randomOBBs(Vec3f& a, Vec3f& b, FCL_REAL extentNorm) {
52
  // Extent norm is between 0 and extentNorm on each axis
53
  // a = (Vec3f::Ones()+Vec3f::Random()) * extentNorm / (2*sqrt(3));
54
  // b = (Vec3f::Ones()+Vec3f::Random()) * extentNorm / (2*sqrt(3));
55
56


10
  a = extentNorm * Vec3f::Random().cwiseAbs().normalized();
57


10
  b = extentNorm * Vec3f::Random().cwiseAbs().normalized();
58
10
}
59
60
100
void randomTransform(Matrix3f& B, Vec3f& T, const Vec3f& a, const Vec3f& b,
61
                     const FCL_REAL extentNorm) {
62
  // TODO Should we scale T to a and b norm ?
63
  (void)a;
64
  (void)b;
65
  (void)extentNorm;
66
67

100
  FCL_REAL N = a.norm() + b.norm();
68
  // A translation of norm N ensures there is no collision.
69
  // Set translation to be between 0 and 2 * N;
70


100
  T = (Vec3f::Random() / sqrt(3)) * 1.5 * N;
71
  // T.setZero();
72
73
100
  Quaternion3f q;
74
100
  q.coeffs().setRandom();
75
100
  q.normalize();
76
100
  B = q;
77
100
}
78
79
#define NB_METHODS 7
80
#define MANUAL_PRODUCT 1
81
82
#if MANUAL_PRODUCT
83
#define PRODUCT(M33, v3) \
84
  (M33.col(0) * v3[0] + M33.col(1) * v3[1] + M33.col(2) * v3[2])
85
#else
86
#define PRODUCT(M33, v3) (M33 * v3)
87
#endif
88
89
typedef std::chrono::high_resolution_clock clock_type;
90
typedef clock_type::duration duration_type;
91
92
const char* sep = ",\t";
93
const FCL_REAL eps = 1.5e-7;
94
95
const Eigen::IOFormat py_fmt(Eigen::FullPrecision, 0,
96
                             ", ",   // Coeff separator
97
                             ",\n",  // Row separator
98
                             "(",    // row prefix
99
                             ",)",   // row suffix
100
                             "( ",   // mat prefix
101
                             ", )"   // mat suffix
102
);
103
104
namespace obbDisjoint_impls {
105
/// @return true if OBB are disjoint.
106
100
bool distance(const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b,
107
              FCL_REAL& distance) {
108
100
  GJKSolver gjk;
109



200
  Box ba(2 * a), bb(2 * b);
110

100
  Transform3f tfa, tfb(B, T);
111
112

100
  Vec3f p1, p2, normal;
113
200
  return gjk.shapeDistance(ba, tfa, bb, tfb, distance, p1, p2, normal);
114
}
115
116
4100
inline FCL_REAL _computeDistanceForCase1(const Vec3f& T, const Vec3f& a,
117
                                         const Vec3f& b, const Matrix3f& Bf) {
118
4100
  Vec3f AABB_corner;
119
  /* This seems to be slower
120
 AABB_corner.noalias() = T.cwiseAbs () - a;
121
 AABB_corner.noalias() -= PRODUCT(Bf,b);
122
 /*/
123
#if MANUAL_PRODUCT
124


4100
  AABB_corner.noalias() = T.cwiseAbs() - a;
125


4100
  AABB_corner.noalias() -= Bf.col(0) * b[0];
126


4100
  AABB_corner.noalias() -= Bf.col(1) * b[1];
127


4100
  AABB_corner.noalias() -= Bf.col(2) * b[2];
128
#else
129
  AABB_corner.noalias() = T.cwiseAbs() - Bf * b - a;
130
#endif
131
  // */
132


4100
  return AABB_corner.array().max(FCL_REAL(0)).matrix().squaredNorm();
133
}
134
135
1435
inline FCL_REAL _computeDistanceForCase2(const Matrix3f& B, const Vec3f& T,
136
                                         const Vec3f& a, const Vec3f& b,
137
                                         const Matrix3f& Bf) {
138
  /*
139
  Vec3f AABB_corner(PRODUCT(B.transpose(), T).cwiseAbs() - b);
140
  AABB_corner.noalias() -= PRODUCT(Bf.transpose(), a);
141
  return AABB_corner.array().max(FCL_REAL(0)).matrix().squaredNorm ();
142
  /*/
143
#if MANUAL_PRODUCT
144
1435
  FCL_REAL s, t = 0;
145


1435
  s = std::abs(B.col(0).dot(T)) - Bf.col(0).dot(a) - b[0];
146
1435
  if (s > 0) t += s * s;
147


1435
  s = std::abs(B.col(1).dot(T)) - Bf.col(1).dot(a) - b[1];
148
1435
  if (s > 0) t += s * s;
149


1435
  s = std::abs(B.col(2).dot(T)) - Bf.col(2).dot(a) - b[2];
150
1435
  if (s > 0) t += s * s;
151
1435
  return t;
152
#else
153
  Vec3f AABB_corner((B.transpose() * T).cwiseAbs() - Bf.transpose() * a - b);
154
  return AABB_corner.array().max(FCL_REAL(0)).matrix().squaredNorm();
155
#endif
156
  // */
157
}
158
159
100
int separatingAxisId(const Matrix3f& B, const Vec3f& T, const Vec3f& a,
160
                     const Vec3f& b, const FCL_REAL& breakDistance2,
161
                     FCL_REAL& squaredLowerBoundDistance) {
162
100
  int id = 0;
163
164

100
  Matrix3f Bf(B.cwiseAbs());
165
166
  // Corner of b axis aligned bounding box the closest to the origin
167
100
  squaredLowerBoundDistance = _computeDistanceForCase1(T, a, b, Bf);
168
100
  if (squaredLowerBoundDistance > breakDistance2) return id;
169
35
  ++id;
170
171
  // | B^T T| - b - Bf^T a
172
35
  squaredLowerBoundDistance = _computeDistanceForCase2(B, T, a, b, Bf);
173
35
  if (squaredLowerBoundDistance > breakDistance2) return id;
174
31
  ++id;
175
176
31
  int ja = 1, ka = 2, jb = 1, kb = 2;
177
120
  for (int ia = 0; ia < 3; ++ia) {
178
362
    for (int ib = 0; ib < 3; ++ib) {
179


273
      const FCL_REAL s = T[ka] * B(ja, ib) - T[ja] * B(ka, ib);
180
181


273
      const FCL_REAL diff = fabs(s) - (a[ja] * Bf(ka, ib) + a[ka] * Bf(ja, ib) +
182


273
                                       b[jb] * Bf(ia, kb) + b[kb] * Bf(ia, jb));
183
      // We need to divide by the norm || Aia x Bib ||
184
      // As ||Aia|| = ||Bib|| = 1, (Aia | Bib)^2  = cosine^2
185
273
      if (diff > 0) {
186

2
        FCL_REAL sinus2 = 1 - Bf(ia, ib) * Bf(ia, ib);
187
2
        if (sinus2 > 1e-6) {
188
2
          squaredLowerBoundDistance = diff * diff / sinus2;
189
2
          if (squaredLowerBoundDistance > breakDistance2) {
190
2
            return id;
191
          }
192
        }
193
        /* // or
194
           FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib);
195
           squaredLowerBoundDistance = diff * diff;
196
           if (squaredLowerBoundDistance > breakDistance2 * sinus2) {
197
           squaredLowerBoundDistance /= sinus2;
198
           return true;
199
           }
200
        // */
201
      }
202
271
      ++id;
203
204
271
      jb = kb;
205
271
      kb = ib;
206
    }
207
89
    ja = ka;
208
89
    ka = ia;
209
  }
210
211
29
  return id;
212
}
213
214
// ------------------------ 0 --------------------------------------
215
1000
bool withRuntimeLoop(const Matrix3f& B, const Vec3f& T, const Vec3f& a,
216
                     const Vec3f& b, const FCL_REAL& breakDistance2,
217
                     FCL_REAL& squaredLowerBoundDistance) {
218

1000
  Matrix3f Bf(B.cwiseAbs());
219
220
  // Corner of b axis aligned bounding box the closest to the origin
221
1000
  squaredLowerBoundDistance = _computeDistanceForCase1(T, a, b, Bf);
222
1000
  if (squaredLowerBoundDistance > breakDistance2) return true;
223
224
  // | B^T T| - b - Bf^T a
225
350
  squaredLowerBoundDistance = _computeDistanceForCase2(B, T, a, b, Bf);
226
350
  if (squaredLowerBoundDistance > breakDistance2) return true;
227
228
310
  int ja = 1, ka = 2, jb = 1, kb = 2;
229
1200
  for (int ia = 0; ia < 3; ++ia) {
230
3620
    for (int ib = 0; ib < 3; ++ib) {
231


2730
      const FCL_REAL s = T[ka] * B(ja, ib) - T[ja] * B(ka, ib);
232
233


2730
      const FCL_REAL diff = fabs(s) - (a[ja] * Bf(ka, ib) + a[ka] * Bf(ja, ib) +
234


2730
                                       b[jb] * Bf(ia, kb) + b[kb] * Bf(ia, jb));
235
      // We need to divide by the norm || Aia x Bib ||
236
      // As ||Aia|| = ||Bib|| = 1, (Aia | Bib)^2  = cosine^2
237
2730
      if (diff > 0) {
238

20
        FCL_REAL sinus2 = 1 - Bf(ia, ib) * Bf(ia, ib);
239
20
        if (sinus2 > 1e-6) {
240
20
          squaredLowerBoundDistance = diff * diff / sinus2;
241
20
          if (squaredLowerBoundDistance > breakDistance2) {
242
20
            return true;
243
          }
244
        }
245
        /* // or
246
           FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib);
247
           squaredLowerBoundDistance = diff * diff;
248
           if (squaredLowerBoundDistance > breakDistance2 * sinus2) {
249
           squaredLowerBoundDistance /= sinus2;
250
           return true;
251
           }
252
        // */
253
      }
254
255
2710
      jb = kb;
256
2710
      kb = ib;
257
    }
258
890
    ja = ka;
259
890
    ka = ia;
260
  }
261
262
290
  return false;
263
}
264
265
// ------------------------ 1 --------------------------------------
266
1000
bool withManualLoopUnrolling_1(const Matrix3f& B, const Vec3f& T,
267
                               const Vec3f& a, const Vec3f& b,
268
                               const FCL_REAL& breakDistance2,
269
                               FCL_REAL& squaredLowerBoundDistance) {
270
  FCL_REAL t, s;
271
  FCL_REAL diff;
272
273
  // Matrix3f Bf = abs(B);
274
  // Bf += reps;
275

1000
  Matrix3f Bf(B.cwiseAbs());
276
277
  // Corner of b axis aligned bounding box the closest to the origin
278


1000
  Vec3f AABB_corner(T.cwiseAbs() - Bf * b);
279

1000
  Vec3f diff3(AABB_corner - a);
280

1000
  diff3 = diff3.cwiseMax(Vec3f::Zero());
281
282
  // for (Vec3f::Index i=0; i<3; ++i) diff3 [i] = std::max (0, diff3 [i]);
283
1000
  squaredLowerBoundDistance = diff3.squaredNorm();
284
1000
  if (squaredLowerBoundDistance > breakDistance2) return true;
285
286



350
  AABB_corner = (B.transpose() * T).cwiseAbs() - Bf.transpose() * a;
287
  // diff3 = | B^T T| - b - Bf^T a
288

350
  diff3 = AABB_corner - b;
289

350
  diff3 = diff3.cwiseMax(Vec3f::Zero());
290
350
  squaredLowerBoundDistance = diff3.squaredNorm();
291
292
350
  if (squaredLowerBoundDistance > breakDistance2) return true;
293
294
  // A0 x B0
295


310
  s = T[2] * B(1, 0) - T[1] * B(2, 0);
296
310
  t = ((s < 0.0) ? -s : s);
297
310
  assert(t == fabs(s));
298
299
  FCL_REAL sinus2;
300



310
  diff = t - (a[1] * Bf(2, 0) + a[2] * Bf(1, 0) + b[1] * Bf(0, 2) +
301

310
              b[2] * Bf(0, 1));
302
  // We need to divide by the norm || A0 x B0 ||
303
  // As ||A0|| = ||B0|| = 1,
304
  //              2            2
305
  // || A0 x B0 ||  + (A0 | B0)  = 1
306
310
  if (diff > 0) {
307
    sinus2 = 1 - Bf(0, 0) * Bf(0, 0);
308
    if (sinus2 > 1e-6) {
309
      squaredLowerBoundDistance = diff * diff / sinus2;
310
      if (squaredLowerBoundDistance > breakDistance2) {
311
        return true;
312
      }
313
    }
314
  }
315
316
  // A0 x B1
317


310
  s = T[2] * B(1, 1) - T[1] * B(2, 1);
318
310
  t = ((s < 0.0) ? -s : s);
319
310
  assert(t == fabs(s));
320
321



310
  diff = t - (a[1] * Bf(2, 1) + a[2] * Bf(1, 1) + b[0] * Bf(0, 2) +
322

310
              b[2] * Bf(0, 0));
323
310
  if (diff > 0) {
324
    sinus2 = 1 - Bf(0, 1) * Bf(0, 1);
325
    if (sinus2 > 1e-6) {
326
      squaredLowerBoundDistance = diff * diff / sinus2;
327
      if (squaredLowerBoundDistance > breakDistance2) {
328
        return true;
329
      }
330
    }
331
  }
332
333
  // A0 x B2
334


310
  s = T[2] * B(1, 2) - T[1] * B(2, 2);
335
310
  t = ((s < 0.0) ? -s : s);
336
310
  assert(t == fabs(s));
337
338



310
  diff = t - (a[1] * Bf(2, 2) + a[2] * Bf(1, 2) + b[0] * Bf(0, 1) +
339

310
              b[1] * Bf(0, 0));
340
310
  if (diff > 0) {
341

10
    sinus2 = 1 - Bf(0, 2) * Bf(0, 2);
342
10
    if (sinus2 > 1e-6) {
343
10
      squaredLowerBoundDistance = diff * diff / sinus2;
344
10
      if (squaredLowerBoundDistance > breakDistance2) {
345
10
        return true;
346
      }
347
    }
348
  }
349
350
  // A1 x B0
351


300
  s = T[0] * B(2, 0) - T[2] * B(0, 0);
352
300
  t = ((s < 0.0) ? -s : s);
353
300
  assert(t == fabs(s));
354
355



300
  diff = t - (a[0] * Bf(2, 0) + a[2] * Bf(0, 0) + b[1] * Bf(1, 2) +
356

300
              b[2] * Bf(1, 1));
357
300
  if (diff > 0) {
358
    sinus2 = 1 - Bf(1, 0) * Bf(1, 0);
359
    if (sinus2 > 1e-6) {
360
      squaredLowerBoundDistance = diff * diff / sinus2;
361
      if (squaredLowerBoundDistance > breakDistance2) {
362
        return true;
363
      }
364
    }
365
  }
366
367
  // A1 x B1
368


300
  s = T[0] * B(2, 1) - T[2] * B(0, 1);
369
300
  t = ((s < 0.0) ? -s : s);
370
300
  assert(t == fabs(s));
371
372



300
  diff = t - (a[0] * Bf(2, 1) + a[2] * Bf(0, 1) + b[0] * Bf(1, 2) +
373

300
              b[2] * Bf(1, 0));
374
300
  if (diff > 0) {
375
    sinus2 = 1 - Bf(1, 1) * Bf(1, 1);
376
    if (sinus2 > 1e-6) {
377
      squaredLowerBoundDistance = diff * diff / sinus2;
378
      if (squaredLowerBoundDistance > breakDistance2) {
379
        return true;
380
      }
381
    }
382
  }
383
384
  // A1 x B2
385


300
  s = T[0] * B(2, 2) - T[2] * B(0, 2);
386
300
  t = ((s < 0.0) ? -s : s);
387
300
  assert(t == fabs(s));
388
389



300
  diff = t - (a[0] * Bf(2, 2) + a[2] * Bf(0, 2) + b[0] * Bf(1, 1) +
390

300
              b[1] * Bf(1, 0));
391
300
  if (diff > 0) {
392
    sinus2 = 1 - Bf(1, 2) * Bf(1, 2);
393
    if (sinus2 > 1e-6) {
394
      squaredLowerBoundDistance = diff * diff / sinus2;
395
      if (squaredLowerBoundDistance > breakDistance2) {
396
        return true;
397
      }
398
    }
399
  }
400
401
  // A2 x B0
402


300
  s = T[1] * B(0, 0) - T[0] * B(1, 0);
403
300
  t = ((s < 0.0) ? -s : s);
404
300
  assert(t == fabs(s));
405
406



300
  diff = t - (a[0] * Bf(1, 0) + a[1] * Bf(0, 0) + b[1] * Bf(2, 2) +
407

300
              b[2] * Bf(2, 1));
408
300
  if (diff > 0) {
409
    sinus2 = 1 - Bf(2, 0) * Bf(2, 0);
410
    if (sinus2 > 1e-6) {
411
      squaredLowerBoundDistance = diff * diff / sinus2;
412
      if (squaredLowerBoundDistance > breakDistance2) {
413
        return true;
414
      }
415
    }
416
  }
417
418
  // A2 x B1
419


300
  s = T[1] * B(0, 1) - T[0] * B(1, 1);
420
300
  t = ((s < 0.0) ? -s : s);
421
300
  assert(t == fabs(s));
422
423



300
  diff = t - (a[0] * Bf(1, 1) + a[1] * Bf(0, 1) + b[0] * Bf(2, 2) +
424

300
              b[2] * Bf(2, 0));
425
300
  if (diff > 0) {
426
    sinus2 = 1 - Bf(2, 1) * Bf(2, 1);
427
    if (sinus2 > 1e-6) {
428
      squaredLowerBoundDistance = diff * diff / sinus2;
429
      if (squaredLowerBoundDistance > breakDistance2) {
430
        return true;
431
      }
432
    }
433
  }
434
435
  // A2 x B2
436


300
  s = T[1] * B(0, 2) - T[0] * B(1, 2);
437
300
  t = ((s < 0.0) ? -s : s);
438
300
  assert(t == fabs(s));
439
440



300
  diff = t - (a[0] * Bf(1, 2) + a[1] * Bf(0, 2) + b[0] * Bf(2, 1) +
441

300
              b[1] * Bf(2, 0));
442
300
  if (diff > 0) {
443

10
    sinus2 = 1 - Bf(2, 2) * Bf(2, 2);
444
10
    if (sinus2 > 1e-6) {
445
10
      squaredLowerBoundDistance = diff * diff / sinus2;
446
10
      if (squaredLowerBoundDistance > breakDistance2) {
447
10
        return true;
448
      }
449
    }
450
  }
451
452
290
  return false;
453
}
454
455
// ------------------------ 2 --------------------------------------
456
1000
bool withManualLoopUnrolling_2(const Matrix3f& B, const Vec3f& T,
457
                               const Vec3f& a, const Vec3f& b,
458
                               const FCL_REAL& breakDistance2,
459
                               FCL_REAL& squaredLowerBoundDistance) {
460

1000
  Matrix3f Bf(B.cwiseAbs());
461
462
  // Corner of b axis aligned bounding box the closest to the origin
463
1000
  squaredLowerBoundDistance = _computeDistanceForCase1(T, a, b, Bf);
464
1000
  if (squaredLowerBoundDistance > breakDistance2) return true;
465
466
350
  squaredLowerBoundDistance = _computeDistanceForCase2(B, T, a, b, Bf);
467
350
  if (squaredLowerBoundDistance > breakDistance2) return true;
468
469
  // A0 x B0
470
  FCL_REAL t, s;
471


310
  s = T[2] * B(1, 0) - T[1] * B(2, 0);
472
310
  t = ((s < 0.0) ? -s : s);
473
310
  assert(t == fabs(s));
474
475
  FCL_REAL sinus2;
476
  FCL_REAL diff;
477



310
  diff = t - (a[1] * Bf(2, 0) + a[2] * Bf(1, 0) + b[1] * Bf(0, 2) +
478

310
              b[2] * Bf(0, 1));
479
  // We need to divide by the norm || A0 x B0 ||
480
  // As ||A0|| = ||B0|| = 1,
481
  //              2            2
482
  // || A0 x B0 ||  + (A0 | B0)  = 1
483
310
  if (diff > 0) {
484
    sinus2 = 1 - Bf(0, 0) * Bf(0, 0);
485
    if (sinus2 > 1e-6) {
486
      squaredLowerBoundDistance = diff * diff / sinus2;
487
      if (squaredLowerBoundDistance > breakDistance2) {
488
        return true;
489
      }
490
    }
491
  }
492
493
  // A0 x B1
494


310
  s = T[2] * B(1, 1) - T[1] * B(2, 1);
495
310
  t = ((s < 0.0) ? -s : s);
496
310
  assert(t == fabs(s));
497
498



310
  diff = t - (a[1] * Bf(2, 1) + a[2] * Bf(1, 1) + b[0] * Bf(0, 2) +
499

310
              b[2] * Bf(0, 0));
500
310
  if (diff > 0) {
501
    sinus2 = 1 - Bf(0, 1) * Bf(0, 1);
502
    if (sinus2 > 1e-6) {
503
      squaredLowerBoundDistance = diff * diff / sinus2;
504
      if (squaredLowerBoundDistance > breakDistance2) {
505
        return true;
506
      }
507
    }
508
  }
509
510
  // A0 x B2
511


310
  s = T[2] * B(1, 2) - T[1] * B(2, 2);
512
310
  t = ((s < 0.0) ? -s : s);
513
310
  assert(t == fabs(s));
514
515



310
  diff = t - (a[1] * Bf(2, 2) + a[2] * Bf(1, 2) + b[0] * Bf(0, 1) +
516

310
              b[1] * Bf(0, 0));
517
310
  if (diff > 0) {
518

10
    sinus2 = 1 - Bf(0, 2) * Bf(0, 2);
519
10
    if (sinus2 > 1e-6) {
520
10
      squaredLowerBoundDistance = diff * diff / sinus2;
521
10
      if (squaredLowerBoundDistance > breakDistance2) {
522
10
        return true;
523
      }
524
    }
525
  }
526
527
  // A1 x B0
528


300
  s = T[0] * B(2, 0) - T[2] * B(0, 0);
529
300
  t = ((s < 0.0) ? -s : s);
530
300
  assert(t == fabs(s));
531
532



300
  diff = t - (a[0] * Bf(2, 0) + a[2] * Bf(0, 0) + b[1] * Bf(1, 2) +
533

300
              b[2] * Bf(1, 1));
534
300
  if (diff > 0) {
535
    sinus2 = 1 - Bf(1, 0) * Bf(1, 0);
536
    if (sinus2 > 1e-6) {
537
      squaredLowerBoundDistance = diff * diff / sinus2;
538
      if (squaredLowerBoundDistance > breakDistance2) {
539
        return true;
540
      }
541
    }
542
  }
543
544
  // A1 x B1
545


300
  s = T[0] * B(2, 1) - T[2] * B(0, 1);
546
300
  t = ((s < 0.0) ? -s : s);
547
300
  assert(t == fabs(s));
548
549



300
  diff = t - (a[0] * Bf(2, 1) + a[2] * Bf(0, 1) + b[0] * Bf(1, 2) +
550

300
              b[2] * Bf(1, 0));
551
300
  if (diff > 0) {
552
    sinus2 = 1 - Bf(1, 1) * Bf(1, 1);
553
    if (sinus2 > 1e-6) {
554
      squaredLowerBoundDistance = diff * diff / sinus2;
555
      if (squaredLowerBoundDistance > breakDistance2) {
556
        return true;
557
      }
558
    }
559
  }
560
561
  // A1 x B2
562


300
  s = T[0] * B(2, 2) - T[2] * B(0, 2);
563
300
  t = ((s < 0.0) ? -s : s);
564
300
  assert(t == fabs(s));
565
566



300
  diff = t - (a[0] * Bf(2, 2) + a[2] * Bf(0, 2) + b[0] * Bf(1, 1) +
567

300
              b[1] * Bf(1, 0));
568
300
  if (diff > 0) {
569
    sinus2 = 1 - Bf(1, 2) * Bf(1, 2);
570
    if (sinus2 > 1e-6) {
571
      squaredLowerBoundDistance = diff * diff / sinus2;
572
      if (squaredLowerBoundDistance > breakDistance2) {
573
        return true;
574
      }
575
    }
576
  }
577
578
  // A2 x B0
579


300
  s = T[1] * B(0, 0) - T[0] * B(1, 0);
580
300
  t = ((s < 0.0) ? -s : s);
581
300
  assert(t == fabs(s));
582
583



300
  diff = t - (a[0] * Bf(1, 0) + a[1] * Bf(0, 0) + b[1] * Bf(2, 2) +
584

300
              b[2] * Bf(2, 1));
585
300
  if (diff > 0) {
586
    sinus2 = 1 - Bf(2, 0) * Bf(2, 0);
587
    if (sinus2 > 1e-6) {
588
      squaredLowerBoundDistance = diff * diff / sinus2;
589
      if (squaredLowerBoundDistance > breakDistance2) {
590
        return true;
591
      }
592
    }
593
  }
594
595
  // A2 x B1
596


300
  s = T[1] * B(0, 1) - T[0] * B(1, 1);
597
300
  t = ((s < 0.0) ? -s : s);
598
300
  assert(t == fabs(s));
599
600



300
  diff = t - (a[0] * Bf(1, 1) + a[1] * Bf(0, 1) + b[0] * Bf(2, 2) +
601

300
              b[2] * Bf(2, 0));
602
300
  if (diff > 0) {
603
    sinus2 = 1 - Bf(2, 1) * Bf(2, 1);
604
    if (sinus2 > 1e-6) {
605
      squaredLowerBoundDistance = diff * diff / sinus2;
606
      if (squaredLowerBoundDistance > breakDistance2) {
607
        return true;
608
      }
609
    }
610
  }
611
612
  // A2 x B2
613


300
  s = T[1] * B(0, 2) - T[0] * B(1, 2);
614
300
  t = ((s < 0.0) ? -s : s);
615
300
  assert(t == fabs(s));
616
617



300
  diff = t - (a[0] * Bf(1, 2) + a[1] * Bf(0, 2) + b[0] * Bf(2, 1) +
618

300
              b[1] * Bf(2, 0));
619
300
  if (diff > 0) {
620

10
    sinus2 = 1 - Bf(2, 2) * Bf(2, 2);
621
10
    if (sinus2 > 1e-6) {
622
10
      squaredLowerBoundDistance = diff * diff / sinus2;
623
10
      if (squaredLowerBoundDistance > breakDistance2) {
624
10
        return true;
625
      }
626
    }
627
  }
628
629
290
  return false;
630
}
631
632
// ------------------------ 3 --------------------------------------
633
template <int ia, int ib, int ja = (ia + 1) % 3, int ka = (ia + 2) % 3,
634
          int jb = (ib + 1) % 3, int kb = (ib + 2) % 3>
635
struct loop_case_1 {
636
5460
  static inline bool run(const Matrix3f& B, const Vec3f& T, const Vec3f& a,
637
                         const Vec3f& b, const Matrix3f& Bf,
638
                         const FCL_REAL& breakDistance2,
639
                         FCL_REAL& squaredLowerBoundDistance) {
640
5460
    const FCL_REAL s = T[ka] * B(ja, ib) - T[ja] * B(ka, ib);
641
642
5460
    const FCL_REAL diff = fabs(s) - (a[ja] * Bf(ka, ib) + a[ka] * Bf(ja, ib) +
643
5460
                                     b[jb] * Bf(ia, kb) + b[kb] * Bf(ia, jb));
644
    // We need to divide by the norm || Aia x Bib ||
645
    // As ||Aia|| = ||Bib|| = 1, (Aia | Bib)^2  = cosine^2
646
5460
    if (diff > 0) {
647
40
      FCL_REAL sinus2 = 1 - Bf(ia, ib) * Bf(ia, ib);
648
40
      if (sinus2 > 1e-6) {
649
40
        squaredLowerBoundDistance = diff * diff / sinus2;
650
40
        if (squaredLowerBoundDistance > breakDistance2) {
651
40
          return true;
652
        }
653
      }
654
      /* // or
655
         FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib);
656
         squaredLowerBoundDistance = diff * diff;
657
         if (squaredLowerBoundDistance > breakDistance2 * sinus2) {
658
         squaredLowerBoundDistance /= sinus2;
659
         return true;
660
         }
661
      // */
662
    }
663
5420
    return false;
664
  }
665
};
666
667
1000
bool withTemplateLoopUnrolling_1(const Matrix3f& B, const Vec3f& T,
668
                                 const Vec3f& a, const Vec3f& b,
669
                                 const FCL_REAL& breakDistance2,
670
                                 FCL_REAL& squaredLowerBoundDistance) {
671

1000
  Matrix3f Bf(B.cwiseAbs());
672
673
  // Corner of b axis aligned bounding box the closest to the origin
674
1000
  squaredLowerBoundDistance = _computeDistanceForCase1(T, a, b, Bf);
675
1000
  if (squaredLowerBoundDistance > breakDistance2) return true;
676
677
350
  squaredLowerBoundDistance = _computeDistanceForCase2(B, T, a, b, Bf);
678
350
  if (squaredLowerBoundDistance > breakDistance2) return true;
679
680
  // Ai x Bj
681

310
  if (loop_case_1<0, 0>::run(B, T, a, b, Bf, breakDistance2,
682
                             squaredLowerBoundDistance))
683
    return true;
684

310
  if (loop_case_1<0, 1>::run(B, T, a, b, Bf, breakDistance2,
685
                             squaredLowerBoundDistance))
686
    return true;
687

310
  if (loop_case_1<0, 2>::run(B, T, a, b, Bf, breakDistance2,
688
                             squaredLowerBoundDistance))
689
10
    return true;
690

300
  if (loop_case_1<1, 0>::run(B, T, a, b, Bf, breakDistance2,
691
                             squaredLowerBoundDistance))
692
    return true;
693

300
  if (loop_case_1<1, 1>::run(B, T, a, b, Bf, breakDistance2,
694
                             squaredLowerBoundDistance))
695
    return true;
696

300
  if (loop_case_1<1, 2>::run(B, T, a, b, Bf, breakDistance2,
697
                             squaredLowerBoundDistance))
698
    return true;
699

300
  if (loop_case_1<2, 0>::run(B, T, a, b, Bf, breakDistance2,
700
                             squaredLowerBoundDistance))
701
    return true;
702

300
  if (loop_case_1<2, 1>::run(B, T, a, b, Bf, breakDistance2,
703
                             squaredLowerBoundDistance))
704
    return true;
705

300
  if (loop_case_1<2, 2>::run(B, T, a, b, Bf, breakDistance2,
706
                             squaredLowerBoundDistance))
707
10
    return true;
708
709
290
  return false;
710
}
711
712
// ------------------------ 4 --------------------------------------
713
714
template <int ib, int jb = (ib + 1) % 3, int kb = (ib + 2) % 3>
715
struct loop_case_2 {
716
5460
  static inline bool run(int ia, int ja, int ka, const Matrix3f& B,
717
                         const Vec3f& T, const Vec3f& a, const Vec3f& b,
718
                         const Matrix3f& Bf, const FCL_REAL& breakDistance2,
719
                         FCL_REAL& squaredLowerBoundDistance) {
720
5460
    const FCL_REAL s = T[ka] * B(ja, ib) - T[ja] * B(ka, ib);
721
722
5460
    const FCL_REAL diff = fabs(s) - (a[ja] * Bf(ka, ib) + a[ka] * Bf(ja, ib) +
723
5460
                                     b[jb] * Bf(ia, kb) + b[kb] * Bf(ia, jb));
724
    // We need to divide by the norm || Aia x Bib ||
725
    // As ||Aia|| = ||Bib|| = 1, (Aia | Bib)^2  = cosine^2
726
5460
    if (diff > 0) {
727
40
      FCL_REAL sinus2 = 1 - Bf(ia, ib) * Bf(ia, ib);
728
40
      if (sinus2 > 1e-6) {
729
40
        squaredLowerBoundDistance = diff * diff / sinus2;
730
40
        if (squaredLowerBoundDistance > breakDistance2) {
731
40
          return true;
732
        }
733
      }
734
      /* // or
735
         FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib);
736
         squaredLowerBoundDistance = diff * diff;
737
         if (squaredLowerBoundDistance > breakDistance2 * sinus2) {
738
         squaredLowerBoundDistance /= sinus2;
739
         return true;
740
         }
741
      // */
742
    }
743
5420
    return false;
744
  }
745
};
746
747
1000
bool withPartialTemplateLoopUnrolling_1(const Matrix3f& B, const Vec3f& T,
748
                                        const Vec3f& a, const Vec3f& b,
749
                                        const FCL_REAL& breakDistance2,
750
                                        FCL_REAL& squaredLowerBoundDistance) {
751

1000
  Matrix3f Bf(B.cwiseAbs());
752
753
  // Corner of b axis aligned bounding box the closest to the origin
754
1000
  squaredLowerBoundDistance = _computeDistanceForCase1(T, a, b, Bf);
755
1000
  if (squaredLowerBoundDistance > breakDistance2) return true;
756
757
350
  squaredLowerBoundDistance = _computeDistanceForCase2(B, T, a, b, Bf);
758
350
  if (squaredLowerBoundDistance > breakDistance2) return true;
759
760
  // Ai x Bj
761
310
  int ja = 1, ka = 2;
762
1200
  for (int ia = 0; ia < 3; ++ia) {
763

910
    if (loop_case_2<0>::run(ia, ja, ka, B, T, a, b, Bf, breakDistance2,
764
                            squaredLowerBoundDistance))
765
      return true;
766

910
    if (loop_case_2<1>::run(ia, ja, ka, B, T, a, b, Bf, breakDistance2,
767
                            squaredLowerBoundDistance))
768
      return true;
769

910
    if (loop_case_2<2>::run(ia, ja, ka, B, T, a, b, Bf, breakDistance2,
770
                            squaredLowerBoundDistance))
771
20
      return true;
772
890
    ja = ka;
773
890
    ka = ia;
774
  }
775
776
290
  return false;
777
}
778
779
// ------------------------ 5 --------------------------------------
780
1000
bool originalWithLowerBound(const Matrix3f& B, const Vec3f& T, const Vec3f& a,
781
                            const Vec3f& b, const FCL_REAL& breakDistance2,
782
                            FCL_REAL& squaredLowerBoundDistance) {
783
  FCL_REAL t, s;
784
  FCL_REAL diff;
785
786

1000
  Matrix3f Bf(B.cwiseAbs());
787
1000
  squaredLowerBoundDistance = 0;
788
789
  // if any of these tests are one-sided, then the polyhedra are disjoint
790
791
  // A1 x A2 = A0
792


1000
  t = ((T[0] < 0.0) ? -T[0] : T[0]);
793
794

1000
  diff = t - (a[0] + Bf.row(0).dot(b));
795
1000
  if (diff > 0) {
796
290
    squaredLowerBoundDistance = diff * diff;
797
  }
798
799
  // A2 x A0 = A1
800


1000
  t = ((T[1] < 0.0) ? -T[1] : T[1]);
801
802

1000
  diff = t - (a[1] + Bf.row(1).dot(b));
803
1000
  if (diff > 0) {
804
350
    squaredLowerBoundDistance += diff * diff;
805
  }
806
807
  // A0 x A1 = A2
808


1000
  t = ((T[2] < 0.0) ? -T[2] : T[2]);
809
810

1000
  diff = t - (a[2] + Bf.row(2).dot(b));
811
1000
  if (diff > 0) {
812
180
    squaredLowerBoundDistance += diff * diff;
813
  }
814
815
1000
  if (squaredLowerBoundDistance > breakDistance2) return true;
816
817
350
  squaredLowerBoundDistance = 0;
818
819
  // B1 x B2 = B0
820

350
  s = B.col(0).dot(T);
821
350
  t = ((s < 0.0) ? -s : s);
822
823

350
  diff = t - (b[0] + Bf.col(0).dot(a));
824
350
  if (diff > 0) {
825
    squaredLowerBoundDistance += diff * diff;
826
  }
827
828
  // B2 x B0 = B1
829

350
  s = B.col(1).dot(T);
830
350
  t = ((s < 0.0) ? -s : s);
831
832

350
  diff = t - (b[1] + Bf.col(1).dot(a));
833
350
  if (diff > 0) {
834
20
    squaredLowerBoundDistance += diff * diff;
835
  }
836
837
  // B0 x B1 = B2
838

350
  s = B.col(2).dot(T);
839
350
  t = ((s < 0.0) ? -s : s);
840
841

350
  diff = t - (b[2] + Bf.col(2).dot(a));
842
350
  if (diff > 0) {
843
20
    squaredLowerBoundDistance += diff * diff;
844
  }
845
846
350
  if (squaredLowerBoundDistance > breakDistance2) return true;
847
848
  // A0 x B0
849


310
  s = T[2] * B(1, 0) - T[1] * B(2, 0);
850
310
  t = ((s < 0.0) ? -s : s);
851
852
  FCL_REAL sinus2;
853



310
  diff = t - (a[1] * Bf(2, 0) + a[2] * Bf(1, 0) + b[1] * Bf(0, 2) +
854

310
              b[2] * Bf(0, 1));
855
  // We need to divide by the norm || A0 x B0 ||
856
  // As ||A0|| = ||B0|| = 1,
857
  //              2            2
858
  // || A0 x B0 ||  + (A0 | B0)  = 1
859
310
  if (diff > 0) {
860
    sinus2 = 1 - Bf(0, 0) * Bf(0, 0);
861
    if (sinus2 > 1e-6) {
862
      squaredLowerBoundDistance = diff * diff / sinus2;
863
      if (squaredLowerBoundDistance > breakDistance2) {
864
        return true;
865
      }
866
    }
867
  }
868
869
  // A0 x B1
870


310
  s = T[2] * B(1, 1) - T[1] * B(2, 1);
871
310
  t = ((s < 0.0) ? -s : s);
872
873



310
  diff = t - (a[1] * Bf(2, 1) + a[2] * Bf(1, 1) + b[0] * Bf(0, 2) +
874

310
              b[2] * Bf(0, 0));
875
310
  if (diff > 0) {
876
    sinus2 = 1 - Bf(0, 1) * Bf(0, 1);
877
    if (sinus2 > 1e-6) {
878
      squaredLowerBoundDistance = diff * diff / sinus2;
879
      if (squaredLowerBoundDistance > breakDistance2) {
880
        return true;
881
      }
882
    }
883
  }
884
885
  // A0 x B2
886


310
  s = T[2] * B(1, 2) - T[1] * B(2, 2);
887
310
  t = ((s < 0.0) ? -s : s);
888
889



310
  diff = t - (a[1] * Bf(2, 2) + a[2] * Bf(1, 2) + b[0] * Bf(0, 1) +
890

310
              b[1] * Bf(0, 0));
891
310
  if (diff > 0) {
892

10
    sinus2 = 1 - Bf(0, 2) * Bf(0, 2);
893
10
    if (sinus2 > 1e-6) {
894
10
      squaredLowerBoundDistance = diff * diff / sinus2;
895
10
      if (squaredLowerBoundDistance > breakDistance2) {
896
10
        return true;
897
      }
898
    }
899
  }
900
901
  // A1 x B0
902


300
  s = T[0] * B(2, 0) - T[2] * B(0, 0);
903
300
  t = ((s < 0.0) ? -s : s);
904
905



300
  diff = t - (a[0] * Bf(2, 0) + a[2] * Bf(0, 0) + b[1] * Bf(1, 2) +
906

300
              b[2] * Bf(1, 1));
907
300
  if (diff > 0) {
908
    sinus2 = 1 - Bf(1, 0) * Bf(1, 0);
909
    if (sinus2 > 1e-6) {
910
      squaredLowerBoundDistance = diff * diff / sinus2;
911
      if (squaredLowerBoundDistance > breakDistance2) {
912
        return true;
913
      }
914
    }
915
  }
916
917
  // A1 x B1
918


300
  s = T[0] * B(2, 1) - T[2] * B(0, 1);
919
300
  t = ((s < 0.0) ? -s : s);
920
921



300
  diff = t - (a[0] * Bf(2, 1) + a[2] * Bf(0, 1) + b[0] * Bf(1, 2) +
922

300
              b[2] * Bf(1, 0));
923
300
  if (diff > 0) {
924
    sinus2 = 1 - Bf(1, 1) * Bf(1, 1);
925
    if (sinus2 > 1e-6) {
926
      squaredLowerBoundDistance = diff * diff / sinus2;
927
      if (squaredLowerBoundDistance > breakDistance2) {
928
        return true;
929
      }
930
    }
931
  }
932
933
  // A1 x B2
934


300
  s = T[0] * B(2, 2) - T[2] * B(0, 2);
935
300
  t = ((s < 0.0) ? -s : s);
936
937



300
  diff = t - (a[0] * Bf(2, 2) + a[2] * Bf(0, 2) + b[0] * Bf(1, 1) +
938

300
              b[1] * Bf(1, 0));
939
300
  if (diff > 0) {
940
    sinus2 = 1 - Bf(1, 2) * Bf(1, 2);
941
    if (sinus2 > 1e-6) {
942
      squaredLowerBoundDistance = diff * diff / sinus2;
943
      if (squaredLowerBoundDistance > breakDistance2) {
944
        return true;
945
      }
946
    }
947
  }
948
949
  // A2 x B0
950


300
  s = T[1] * B(0, 0) - T[0] * B(1, 0);
951
300
  t = ((s < 0.0) ? -s : s);
952
953



300
  diff = t - (a[0] * Bf(1, 0) + a[1] * Bf(0, 0) + b[1] * Bf(2, 2) +
954

300
              b[2] * Bf(2, 1));
955
300
  if (diff > 0) {
956
    sinus2 = 1 - Bf(2, 0) * Bf(2, 0);
957
    if (sinus2 > 1e-6) {
958
      squaredLowerBoundDistance = diff * diff / sinus2;
959
      if (squaredLowerBoundDistance > breakDistance2) {
960
        return true;
961
      }
962
    }
963
  }
964
965
  // A2 x B1
966


300
  s = T[1] * B(0, 1) - T[0] * B(1, 1);
967
300
  t = ((s < 0.0) ? -s : s);
968
969



300
  diff = t - (a[0] * Bf(1, 1) + a[1] * Bf(0, 1) + b[0] * Bf(2, 2) +
970

300
              b[2] * Bf(2, 0));
971
300
  if (diff > 0) {
972
    sinus2 = 1 - Bf(2, 1) * Bf(2, 1);
973
    if (sinus2 > 1e-6) {
974
      squaredLowerBoundDistance = diff * diff / sinus2;
975
      if (squaredLowerBoundDistance > breakDistance2) {
976
        return true;
977
      }
978
    }
979
  }
980
981
  // A2 x B2
982


300
  s = T[1] * B(0, 2) - T[0] * B(1, 2);
983
300
  t = ((s < 0.0) ? -s : s);
984
985



300
  diff = t - (a[0] * Bf(1, 2) + a[1] * Bf(0, 2) + b[0] * Bf(2, 1) +
986

300
              b[1] * Bf(2, 0));
987
300
  if (diff > 0) {
988

10
    sinus2 = 1 - Bf(2, 2) * Bf(2, 2);
989
10
    if (sinus2 > 1e-6) {
990
10
      squaredLowerBoundDistance = diff * diff / sinus2;
991
10
      if (squaredLowerBoundDistance > breakDistance2) {
992
10
        return true;
993
      }
994
    }
995
  }
996
997
290
  return false;
998
}
999
1000
// ------------------------ 6 --------------------------------------
1001
1000
bool originalWithNoLowerBound(const Matrix3f& B, const Vec3f& T, const Vec3f& a,
1002
                              const Vec3f& b, const FCL_REAL&,
1003
                              FCL_REAL& squaredLowerBoundDistance) {
1004
  FCL_REAL t, s;
1005
1000
  const FCL_REAL reps = 1e-6;
1006
1007
1000
  squaredLowerBoundDistance = 0;
1008
1009


1000
  Matrix3f Bf(B.array().abs() + reps);
1010
  // Bf += reps;
1011
1012
  // if any of these tests are one-sided, then the polyhedra are disjoint
1013
1014
  // A1 x A2 = A0
1015


1000
  t = ((T[0] < 0.0) ? -T[0] : T[0]);
1016
1017
  // if(t > (a[0] + Bf.dotX(b)))
1018


1000
  if (t > (a[0] + Bf.row(0).dot(b))) return true;
1019
1020
  // B1 x B2 = B0
1021
  // s =  B.transposeDotX(T);
1022

710
  s = B.col(0).dot(T);
1023
710
  t = ((s < 0.0) ? -s : s);
1024
1025
  // if(t > (b[0] + Bf.transposeDotX(a)))
1026


710
  if (t > (b[0] + Bf.col(0).dot(a))) return true;
1027
1028
  // A2 x A0 = A1
1029


570
  t = ((T[1] < 0.0) ? -T[1] : T[1]);
1030
1031
  // if(t > (a[1] + Bf.dotY(b)))
1032


570
  if (t > (a[1] + Bf.row(1).dot(b))) return true;
1033
1034
  // A0 x A1 = A2
1035


410
  t = ((T[2] < 0.0) ? -T[2] : T[2]);
1036
1037
  // if(t > (a[2] + Bf.dotZ(b)))
1038


410
  if (t > (a[2] + Bf.row(2).dot(b))) return true;
1039
1040
  // B2 x B0 = B1
1041
  // s = B.transposeDotY(T);
1042

350
  s = B.col(1).dot(T);
1043
350
  t = ((s < 0.0) ? -s : s);
1044
1045
  // if(t > (b[1] + Bf.transposeDotY(a)))
1046


350
  if (t > (b[1] + Bf.col(1).dot(a))) return true;
1047
1048
  // B0 x B1 = B2
1049
  // s = B.transposeDotZ(T);
1050

330
  s = B.col(2).dot(T);
1051
330
  t = ((s < 0.0) ? -s : s);
1052
1053
  // if(t > (b[2] + Bf.transposeDotZ(a)))
1054


330
  if (t > (b[2] + Bf.col(2).dot(a))) return true;
1055
1056
  // A0 x B0
1057


310
  s = T[2] * B(1, 0) - T[1] * B(2, 0);
1058
310
  t = ((s < 0.0) ? -s : s);
1059
1060
310
  if (t >
1061




310
      (a[1] * Bf(2, 0) + a[2] * Bf(1, 0) + b[1] * Bf(0, 2) + b[2] * Bf(0, 1)))
1062
    return true;
1063
1064
  // A0 x B1
1065


310
  s = T[2] * B(1, 1) - T[1] * B(2, 1);
1066
310
  t = ((s < 0.0) ? -s : s);
1067
1068
310
  if (t >
1069




310
      (a[1] * Bf(2, 1) + a[2] * Bf(1, 1) + b[0] * Bf(0, 2) + b[2] * Bf(0, 0)))
1070
    return true;
1071
1072
  // A0 x B2
1073


310
  s = T[2] * B(1, 2) - T[1] * B(2, 2);
1074
310
  t = ((s < 0.0) ? -s : s);
1075
1076
310
  if (t >
1077




310
      (a[1] * Bf(2, 2) + a[2] * Bf(1, 2) + b[0] * Bf(0, 1) + b[1] * Bf(0, 0)))
1078
10
    return true;
1079
1080
  // A1 x B0
1081


300
  s = T[0] * B(2, 0) - T[2] * B(0, 0);
1082
300
  t = ((s < 0.0) ? -s : s);
1083
1084
300
  if (t >
1085




300
      (a[0] * Bf(2, 0) + a[2] * Bf(0, 0) + b[1] * Bf(1, 2) + b[2] * Bf(1, 1)))
1086
    return true;
1087
1088
  // A1 x B1
1089


300
  s = T[0] * B(2, 1) - T[2] * B(0, 1);
1090
300
  t = ((s < 0.0) ? -s : s);
1091
1092
300
  if (t >
1093




300
      (a[0] * Bf(2, 1) + a[2] * Bf(0, 1) + b[0] * Bf(1, 2) + b[2] * Bf(1, 0)))
1094
    return true;
1095
1096
  // A1 x B2
1097


300
  s = T[0] * B(2, 2) - T[2] * B(0, 2);
1098
300
  t = ((s < 0.0) ? -s : s);
1099
1100
300
  if (t >
1101




300
      (a[0] * Bf(2, 2) + a[2] * Bf(0, 2) + b[0] * Bf(1, 1) + b[1] * Bf(1, 0)))
1102
    return true;
1103
1104
  // A2 x B0
1105


300
  s = T[1] * B(0, 0) - T[0] * B(1, 0);
1106
300
  t = ((s < 0.0) ? -s : s);
1107
1108
300
  if (t >
1109




300
      (a[0] * Bf(1, 0) + a[1] * Bf(0, 0) + b[1] * Bf(2, 2) + b[2] * Bf(2, 1)))
1110
    return true;
1111
1112
  // A2 x B1
1113


300
  s = T[1] * B(0, 1) - T[0] * B(1, 1);
1114
300
  t = ((s < 0.0) ? -s : s);
1115
1116
300
  if (t >
1117




300
      (a[0] * Bf(1, 1) + a[1] * Bf(0, 1) + b[0] * Bf(2, 2) + b[2] * Bf(2, 0)))
1118
    return true;
1119
1120
  // A2 x B2
1121


300
  s = T[1] * B(0, 2) - T[0] * B(1, 2);
1122
300
  t = ((s < 0.0) ? -s : s);
1123
1124
300
  if (t >
1125




300
      (a[0] * Bf(1, 2) + a[1] * Bf(0, 2) + b[0] * Bf(2, 1) + b[1] * Bf(2, 0)))
1126
10
    return true;
1127
1128
290
  return false;
1129
}
1130
}  // namespace obbDisjoint_impls
1131
1132
struct BenchmarkResult {
1133
  /// The test ID:
1134
  /// - 0-10 identifies a separating axes.
1135
  /// - 11 means no separatins axes could be found. (distance should be <= 0)
1136
  int ifId;
1137
  FCL_REAL distance;
1138
  FCL_REAL squaredLowerBoundDistance;
1139
  duration_type duration[NB_METHODS];
1140
  bool failure;
1141
1142
  static std::ostream& headers(std::ostream& os) {
1143
    const std::string unit = " (us)";
1144
    os << "separating axis" << sep << "distance lower bound" << sep
1145
       << "distance" << sep << "failure" << sep << "Runtime Loop" << unit << sep
1146
       << "Manual Loop Unrolling 1" << unit << sep << "Manual Loop Unrolling 2"
1147
       << unit << sep << "Template Unrolling" << unit << sep
1148
       << "Partial Template Unrolling" << unit << sep << "Original (LowerBound)"
1149
       << unit << sep << "Original (NoLowerBound)" << unit;
1150
    return os;
1151
  }
1152
1153
  std::ostream& print(std::ostream& os) const {
1154
    os << ifId << sep << std::sqrt(squaredLowerBoundDistance) << sep << distance
1155
       << sep << failure;
1156
    for (int i = 0; i < NB_METHODS; ++i)
1157
      os << sep
1158
         << static_cast<double>(
1159
                std::chrono::duration_cast<std::chrono::nanoseconds>(
1160
                    duration[i])
1161
                    .count()) *
1162
                1e-3;
1163
    return os;
1164
  }
1165
};
1166
1167
std::ostream& operator<<(std::ostream& os, const BenchmarkResult& br) {
1168
  return br.print(os);
1169
}
1170
1171
100
BenchmarkResult benchmark_obb_case(const Matrix3f& B, const Vec3f& T,
1172
                                   const Vec3f& a, const Vec3f& b,
1173
                                   const CollisionRequest& request,
1174
                                   std::size_t N) {
1175
100
  const FCL_REAL breakDistance(request.break_distance +
1176
100
                               request.security_margin);
1177
100
  const FCL_REAL breakDistance2 = breakDistance * breakDistance;
1178
1179
  BenchmarkResult result;
1180
  // First determine which axis provide the answer
1181
100
  result.ifId = obbDisjoint_impls::separatingAxisId(
1182
      B, T, a, b, breakDistance2, result.squaredLowerBoundDistance);
1183
100
  bool disjoint = obbDisjoint_impls::distance(B, T, a, b, result.distance);
1184

100
  assert(0 <= result.ifId && result.ifId <= 11);
1185
1186
  // Sanity check
1187
100
  result.failure = true;
1188
100
  bool overlap = (result.ifId == 11);
1189
100
  FCL_REAL dist_thr = request.break_distance + request.security_margin;
1190

100
  if (!overlap && result.distance <= 0) {
1191
    std::cerr << "Failure: negative distance for disjoint OBBs.";
1192

100
  } else if (!overlap && result.squaredLowerBoundDistance < 0) {
1193
    std::cerr << "Failure: negative distance lower bound.";
1194

171
  } else if (!overlap && eps < std::sqrt(result.squaredLowerBoundDistance) -
1195
71
                                   result.distance) {
1196
    std::cerr << "Failure: distance is inferior to its lower bound (diff = "
1197
              << std::sqrt(result.squaredLowerBoundDistance) - result.distance
1198
              << ").";
1199

100
  } else if (overlap != !disjoint && result.distance >= dist_thr - eps) {
1200
    std::cerr << "Failure: overlapping test and distance query mismatch.";
1201

100
  } else if (overlap && result.distance >= dist_thr - eps) {
1202
    std::cerr << "Failure: positive distance for overlapping OBBs.";
1203
  } else {
1204
100
    result.failure = false;
1205
  }
1206
100
  if (result.failure) {
1207
    std::cerr << "\nR = " << Quaternion3f(B).coeffs().transpose().format(py_fmt)
1208
              << "\nT = " << T.transpose().format(py_fmt)
1209
              << "\na = " << a.transpose().format(py_fmt)
1210
              << "\nb = " << b.transpose().format(py_fmt)
1211
              << "\nresult = " << result << '\n'
1212
              << std::endl;
1213
  }
1214
1215
  // Compute time
1216
  FCL_REAL tmp;
1217
100
  clock_type::time_point start, end;
1218
1219
  // ------------------------ 0 --------------------------------------
1220
100
  start = clock_type::now();
1221
1100
  for (std::size_t i = 0; i < N; ++i)
1222
1000
    obbDisjoint_impls::withRuntimeLoop(B, T, a, b, breakDistance2, tmp);
1223
100
  end = clock_type::now();
1224

100
  result.duration[0] = (end - start) / N;
1225
1226
  // ------------------------ 1 --------------------------------------
1227
100
  start = clock_type::now();
1228
1100
  for (std::size_t i = 0; i < N; ++i)
1229
1000
    obbDisjoint_impls::withManualLoopUnrolling_1(B, T, a, b, breakDistance2,
1230
                                                 tmp);
1231
100
  end = clock_type::now();
1232

100
  result.duration[1] = (end - start) / N;
1233
1234
  // ------------------------ 2 --------------------------------------
1235
100
  start = clock_type::now();
1236
1100
  for (std::size_t i = 0; i < N; ++i)
1237
1000
    obbDisjoint_impls::withManualLoopUnrolling_2(B, T, a, b, breakDistance2,
1238
                                                 tmp);
1239
100
  end = clock_type::now();
1240

100
  result.duration[2] = (end - start) / N;
1241
1242
  // ------------------------ 3 --------------------------------------
1243
100
  start = clock_type::now();
1244
1100
  for (std::size_t i = 0; i < N; ++i)
1245
1000
    obbDisjoint_impls::withTemplateLoopUnrolling_1(B, T, a, b, breakDistance2,
1246
                                                   tmp);
1247
100
  end = clock_type::now();
1248

100
  result.duration[3] = (end - start) / N;
1249
1250
  // ------------------------ 4 --------------------------------------
1251
100
  start = clock_type::now();
1252
1100
  for (std::size_t i = 0; i < N; ++i)
1253
1000
    obbDisjoint_impls::withPartialTemplateLoopUnrolling_1(B, T, a, b,
1254
                                                          breakDistance2, tmp);
1255
100
  end = clock_type::now();
1256

100
  result.duration[4] = (end - start) / N;
1257
1258
  // ------------------------ 5 --------------------------------------
1259
100
  start = clock_type::now();
1260
1100
  for (std::size_t i = 0; i < N; ++i)
1261
1000
    obbDisjoint_impls::originalWithLowerBound(B, T, a, b, breakDistance2, tmp);
1262
100
  end = clock_type::now();
1263

100
  result.duration[5] = (end - start) / N;
1264
1265
  // ------------------------ 6 --------------------------------------
1266
100
  start = clock_type::now();
1267
  // The 2 last arguments are unused.
1268
1100
  for (std::size_t i = 0; i < N; ++i)
1269
1000
    obbDisjoint_impls::originalWithNoLowerBound(B, T, a, b, breakDistance2,
1270
                                                tmp);
1271
100
  end = clock_type::now();
1272

100
  result.duration[6] = (end - start) / N;
1273
1274
200
  return result;
1275
}
1276
1277
1
std::size_t obb_overlap_and_lower_bound_distance(std::ostream* output) {
1278
1
  std::size_t nbFailure = 0;
1279
1280
  // Create two OBBs axis
1281

1
  Vec3f a, b;
1282
1
  Matrix3f B;
1283
1
  Vec3f T;
1284
1
  CollisionRequest request;
1285
1286
#ifndef NDEBUG  // if debug mode
1287
  static const size_t nbRandomOBB = 10;
1288
  static const size_t nbTransformPerOBB = 10;
1289
  static const size_t nbRunForTimeMeas = 10;
1290
#else
1291
  static const size_t nbRandomOBB = 100;
1292
  static const size_t nbTransformPerOBB = 100;
1293
  static const size_t nbRunForTimeMeas = 1000;
1294
#endif
1295
  static const FCL_REAL extentNorm = 1.;
1296
1297

1
  if (output != NULL) *output << BenchmarkResult::headers << '\n';
1298
1299
  BenchmarkResult result;
1300
11
  for (std::size_t iobb = 0; iobb < nbRandomOBB; ++iobb) {
1301
10
    randomOBBs(a, b, extentNorm);
1302
110
    for (std::size_t itf = 0; itf < nbTransformPerOBB; ++itf) {
1303
100
      randomTransform(B, T, a, b, extentNorm);
1304
100
      result = benchmark_obb_case(B, T, a, b, request, nbRunForTimeMeas);
1305

100
      if (output != NULL) *output << result << '\n';
1306
100
      if (result.failure) nbFailure++;
1307
    }
1308
  }
1309
1
  return nbFailure;
1310
}
1311
1312
1
int main(int argc, char** argv) {
1313
1
  std::ostream* output = NULL;
1314

1
  if (argc > 1 && strcmp(argv[1], "--generate-output") == 0) {
1315
    output = &std::cout;
1316
  }
1317
1318
  std::cout << "The benchmark real time measurements may be noisy and "
1319
               "will incur extra overhead."
1320
               "\nUse the following commands to turn ON:"
1321
               "\n\tsudo cpufreq-set --governor performance"
1322
               "\nor OFF:"
1323
               "\n\tsudo cpufreq-set --governor powersave"
1324
1
               "\n";
1325
1326
1
  std::size_t nbFailure = obb_overlap_and_lower_bound_distance(output);
1327
1
  if (nbFailure > INT_MAX) return INT_MAX;
1328
1
  return (int)nbFailure;
1329
}