obb.cpp
Go to the documentation of this file.
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 
44 
45 #include "../src/BV/OBB.h"
47 #include "utility.h"
48 
49 using namespace coal;
50 
51 void randomOBBs(Vec3s& a, Vec3s& b, CoalScalar extentNorm) {
52  // Extent norm is between 0 and extentNorm on each axis
53  // a = (Vec3s::Ones()+Vec3s::Random()) * extentNorm / (2*sqrt(3));
54  // b = (Vec3s::Ones()+Vec3s::Random()) * extentNorm / (2*sqrt(3));
55 
56  a = extentNorm * Vec3s::Random().cwiseAbs().normalized();
57  b = extentNorm * Vec3s::Random().cwiseAbs().normalized();
58 }
59 
60 void randomTransform(Matrix3s& B, Vec3s& T, const Vec3s& a, const Vec3s& b,
61  const CoalScalar extentNorm) {
62  // TODO Should we scale T to a and b norm ?
63  (void)a;
64  (void)b;
65  (void)extentNorm;
66 
67  CoalScalar 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  T = (Vec3s::Random() / sqrt(3)) * 1.5 * N;
71  // T.setZero();
72 
73  Quatf q;
74  q.coeffs().setRandom();
75  q.normalize();
76  B = q;
77 }
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 CoalScalar 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 {
106 bool distance(const Matrix3s& B, const Vec3s& T, const Vec3s& a, const Vec3s& b,
107  CoalScalar& distance) {
108  GJKSolver gjk;
109  Box ba(2 * a), bb(2 * b);
110  Transform3s tfa, tfb(B, T);
111 
112  Vec3s p1, p2, normal;
113  bool compute_penetration = true;
114  distance =
115  gjk.shapeDistance(ba, tfa, bb, tfb, compute_penetration, p1, p2, normal);
116  return (distance > gjk.getDistancePrecision(compute_penetration));
117 }
118 
119 inline CoalScalar _computeDistanceForCase1(const Vec3s& T, const Vec3s& a,
120  const Vec3s& b, const Matrix3s& Bf) {
121  Vec3s AABB_corner;
122  /* This seems to be slower
123  AABB_corner.noalias() = T.cwiseAbs () - a;
124  AABB_corner.noalias() -= PRODUCT(Bf,b);
125  /*/
126 #if MANUAL_PRODUCT
127  AABB_corner.noalias() = T.cwiseAbs() - a;
128  AABB_corner.noalias() -= Bf.col(0) * b[0];
129  AABB_corner.noalias() -= Bf.col(1) * b[1];
130  AABB_corner.noalias() -= Bf.col(2) * b[2];
131 #else
132  AABB_corner.noalias() = T.cwiseAbs() - Bf * b - a;
133 #endif
134  // */
135  return AABB_corner.array().max(CoalScalar(0)).matrix().squaredNorm();
136 }
137 
139  const Vec3s& a, const Vec3s& b,
140  const Matrix3s& Bf) {
141  /*
142  Vec3s AABB_corner(PRODUCT(B.transpose(), T).cwiseAbs() - b);
143  AABB_corner.noalias() -= PRODUCT(Bf.transpose(), a);
144  return AABB_corner.array().max(CoalScalar(0)).matrix().squaredNorm ();
145  /*/
146 #if MANUAL_PRODUCT
147  CoalScalar s, t = 0;
148  s = std::abs(B.col(0).dot(T)) - Bf.col(0).dot(a) - b[0];
149  if (s > 0) t += s * s;
150  s = std::abs(B.col(1).dot(T)) - Bf.col(1).dot(a) - b[1];
151  if (s > 0) t += s * s;
152  s = std::abs(B.col(2).dot(T)) - Bf.col(2).dot(a) - b[2];
153  if (s > 0) t += s * s;
154  return t;
155 #else
156  Vec3s AABB_corner((B.transpose() * T).cwiseAbs() - Bf.transpose() * a - b);
157  return AABB_corner.array().max(CoalScalar(0)).matrix().squaredNorm();
158 #endif
159  // */
160 }
161 
162 int separatingAxisId(const Matrix3s& B, const Vec3s& T, const Vec3s& a,
163  const Vec3s& b, const CoalScalar& breakDistance2,
164  CoalScalar& squaredLowerBoundDistance) {
165  int id = 0;
166 
167  Matrix3s Bf(B.cwiseAbs());
168 
169  // Corner of b axis aligned bounding box the closest to the origin
170  squaredLowerBoundDistance = _computeDistanceForCase1(T, a, b, Bf);
171  if (squaredLowerBoundDistance > breakDistance2) return id;
172  ++id;
173 
174  // | B^T T| - b - Bf^T a
175  squaredLowerBoundDistance = _computeDistanceForCase2(B, T, a, b, Bf);
176  if (squaredLowerBoundDistance > breakDistance2) return id;
177  ++id;
178 
179  int ja = 1, ka = 2, jb = 1, kb = 2;
180  for (int ia = 0; ia < 3; ++ia) {
181  for (int ib = 0; ib < 3; ++ib) {
182  const CoalScalar s = T[ka] * B(ja, ib) - T[ja] * B(ka, ib);
183 
184  const CoalScalar diff =
185  fabs(s) - (a[ja] * Bf(ka, ib) + a[ka] * Bf(ja, ib) +
186  b[jb] * Bf(ia, kb) + b[kb] * Bf(ia, jb));
187  // We need to divide by the norm || Aia x Bib ||
188  // As ||Aia|| = ||Bib|| = 1, (Aia | Bib)^2 = cosine^2
189  if (diff > 0) {
190  CoalScalar sinus2 = 1 - Bf(ia, ib) * Bf(ia, ib);
191  if (sinus2 > 1e-6) {
192  squaredLowerBoundDistance = diff * diff / sinus2;
193  if (squaredLowerBoundDistance > breakDistance2) {
194  return id;
195  }
196  }
197  /* // or
198  CoalScalar sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib);
199  squaredLowerBoundDistance = diff * diff;
200  if (squaredLowerBoundDistance > breakDistance2 * sinus2) {
201  squaredLowerBoundDistance /= sinus2;
202  return true;
203  }
204  // */
205  }
206  ++id;
207 
208  jb = kb;
209  kb = ib;
210  }
211  ja = ka;
212  ka = ia;
213  }
214 
215  return id;
216 }
217 
218 // ------------------------ 0 --------------------------------------
219 bool withRuntimeLoop(const Matrix3s& B, const Vec3s& T, const Vec3s& a,
220  const Vec3s& b, const CoalScalar& breakDistance2,
221  CoalScalar& squaredLowerBoundDistance) {
222  Matrix3s Bf(B.cwiseAbs());
223 
224  // Corner of b axis aligned bounding box the closest to the origin
225  squaredLowerBoundDistance = _computeDistanceForCase1(T, a, b, Bf);
226  if (squaredLowerBoundDistance > breakDistance2) return true;
227 
228  // | B^T T| - b - Bf^T a
229  squaredLowerBoundDistance = _computeDistanceForCase2(B, T, a, b, Bf);
230  if (squaredLowerBoundDistance > breakDistance2) return true;
231 
232  int ja = 1, ka = 2, jb = 1, kb = 2;
233  for (int ia = 0; ia < 3; ++ia) {
234  for (int ib = 0; ib < 3; ++ib) {
235  const CoalScalar s = T[ka] * B(ja, ib) - T[ja] * B(ka, ib);
236 
237  const CoalScalar diff =
238  fabs(s) - (a[ja] * Bf(ka, ib) + a[ka] * Bf(ja, ib) +
239  b[jb] * Bf(ia, kb) + b[kb] * Bf(ia, jb));
240  // We need to divide by the norm || Aia x Bib ||
241  // As ||Aia|| = ||Bib|| = 1, (Aia | Bib)^2 = cosine^2
242  if (diff > 0) {
243  CoalScalar sinus2 = 1 - Bf(ia, ib) * Bf(ia, ib);
244  if (sinus2 > 1e-6) {
245  squaredLowerBoundDistance = diff * diff / sinus2;
246  if (squaredLowerBoundDistance > breakDistance2) {
247  return true;
248  }
249  }
250  /* // or
251  CoalScalar sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib);
252  squaredLowerBoundDistance = diff * diff;
253  if (squaredLowerBoundDistance > breakDistance2 * sinus2) {
254  squaredLowerBoundDistance /= sinus2;
255  return true;
256  }
257  // */
258  }
259 
260  jb = kb;
261  kb = ib;
262  }
263  ja = ka;
264  ka = ia;
265  }
266 
267  return false;
268 }
269 
270 // ------------------------ 1 --------------------------------------
271 bool withManualLoopUnrolling_1(const Matrix3s& B, const Vec3s& T,
272  const Vec3s& a, const Vec3s& b,
273  const CoalScalar& breakDistance2,
274  CoalScalar& squaredLowerBoundDistance) {
275  CoalScalar t, s;
276  CoalScalar diff;
277 
278  // Matrix3s Bf = abs(B);
279  // Bf += reps;
280  Matrix3s Bf(B.cwiseAbs());
281 
282  // Corner of b axis aligned bounding box the closest to the origin
283  Vec3s AABB_corner(T.cwiseAbs() - Bf * b);
284  Vec3s diff3(AABB_corner - a);
285  diff3 = diff3.cwiseMax(Vec3s::Zero());
286 
287  // for (Vec3s::Index i=0; i<3; ++i) diff3 [i] = std::max (0, diff3 [i]);
288  squaredLowerBoundDistance = diff3.squaredNorm();
289  if (squaredLowerBoundDistance > breakDistance2) return true;
290 
291  AABB_corner = (B.transpose() * T).cwiseAbs() - Bf.transpose() * a;
292  // diff3 = | B^T T| - b - Bf^T a
293  diff3 = AABB_corner - b;
294  diff3 = diff3.cwiseMax(Vec3s::Zero());
295  squaredLowerBoundDistance = diff3.squaredNorm();
296 
297  if (squaredLowerBoundDistance > breakDistance2) return true;
298 
299  // A0 x B0
300  s = T[2] * B(1, 0) - T[1] * B(2, 0);
301  t = ((s < 0.0) ? -s : s);
302  assert(t == fabs(s));
303 
304  CoalScalar sinus2;
305  diff = t - (a[1] * Bf(2, 0) + a[2] * Bf(1, 0) + b[1] * Bf(0, 2) +
306  b[2] * Bf(0, 1));
307  // We need to divide by the norm || A0 x B0 ||
308  // As ||A0|| = ||B0|| = 1,
309  // 2 2
310  // || A0 x B0 || + (A0 | B0) = 1
311  if (diff > 0) {
312  sinus2 = 1 - Bf(0, 0) * Bf(0, 0);
313  if (sinus2 > 1e-6) {
314  squaredLowerBoundDistance = diff * diff / sinus2;
315  if (squaredLowerBoundDistance > breakDistance2) {
316  return true;
317  }
318  }
319  }
320 
321  // A0 x B1
322  s = T[2] * B(1, 1) - T[1] * B(2, 1);
323  t = ((s < 0.0) ? -s : s);
324  assert(t == fabs(s));
325 
326  diff = t - (a[1] * Bf(2, 1) + a[2] * Bf(1, 1) + b[0] * Bf(0, 2) +
327  b[2] * Bf(0, 0));
328  if (diff > 0) {
329  sinus2 = 1 - Bf(0, 1) * Bf(0, 1);
330  if (sinus2 > 1e-6) {
331  squaredLowerBoundDistance = diff * diff / sinus2;
332  if (squaredLowerBoundDistance > breakDistance2) {
333  return true;
334  }
335  }
336  }
337 
338  // A0 x B2
339  s = T[2] * B(1, 2) - T[1] * B(2, 2);
340  t = ((s < 0.0) ? -s : s);
341  assert(t == fabs(s));
342 
343  diff = t - (a[1] * Bf(2, 2) + a[2] * Bf(1, 2) + b[0] * Bf(0, 1) +
344  b[1] * Bf(0, 0));
345  if (diff > 0) {
346  sinus2 = 1 - Bf(0, 2) * Bf(0, 2);
347  if (sinus2 > 1e-6) {
348  squaredLowerBoundDistance = diff * diff / sinus2;
349  if (squaredLowerBoundDistance > breakDistance2) {
350  return true;
351  }
352  }
353  }
354 
355  // A1 x B0
356  s = T[0] * B(2, 0) - T[2] * B(0, 0);
357  t = ((s < 0.0) ? -s : s);
358  assert(t == fabs(s));
359 
360  diff = t - (a[0] * Bf(2, 0) + a[2] * Bf(0, 0) + b[1] * Bf(1, 2) +
361  b[2] * Bf(1, 1));
362  if (diff > 0) {
363  sinus2 = 1 - Bf(1, 0) * Bf(1, 0);
364  if (sinus2 > 1e-6) {
365  squaredLowerBoundDistance = diff * diff / sinus2;
366  if (squaredLowerBoundDistance > breakDistance2) {
367  return true;
368  }
369  }
370  }
371 
372  // A1 x B1
373  s = T[0] * B(2, 1) - T[2] * B(0, 1);
374  t = ((s < 0.0) ? -s : s);
375  assert(t == fabs(s));
376 
377  diff = t - (a[0] * Bf(2, 1) + a[2] * Bf(0, 1) + b[0] * Bf(1, 2) +
378  b[2] * Bf(1, 0));
379  if (diff > 0) {
380  sinus2 = 1 - Bf(1, 1) * Bf(1, 1);
381  if (sinus2 > 1e-6) {
382  squaredLowerBoundDistance = diff * diff / sinus2;
383  if (squaredLowerBoundDistance > breakDistance2) {
384  return true;
385  }
386  }
387  }
388 
389  // A1 x B2
390  s = T[0] * B(2, 2) - T[2] * B(0, 2);
391  t = ((s < 0.0) ? -s : s);
392  assert(t == fabs(s));
393 
394  diff = t - (a[0] * Bf(2, 2) + a[2] * Bf(0, 2) + b[0] * Bf(1, 1) +
395  b[1] * Bf(1, 0));
396  if (diff > 0) {
397  sinus2 = 1 - Bf(1, 2) * Bf(1, 2);
398  if (sinus2 > 1e-6) {
399  squaredLowerBoundDistance = diff * diff / sinus2;
400  if (squaredLowerBoundDistance > breakDistance2) {
401  return true;
402  }
403  }
404  }
405 
406  // A2 x B0
407  s = T[1] * B(0, 0) - T[0] * B(1, 0);
408  t = ((s < 0.0) ? -s : s);
409  assert(t == fabs(s));
410 
411  diff = t - (a[0] * Bf(1, 0) + a[1] * Bf(0, 0) + b[1] * Bf(2, 2) +
412  b[2] * Bf(2, 1));
413  if (diff > 0) {
414  sinus2 = 1 - Bf(2, 0) * Bf(2, 0);
415  if (sinus2 > 1e-6) {
416  squaredLowerBoundDistance = diff * diff / sinus2;
417  if (squaredLowerBoundDistance > breakDistance2) {
418  return true;
419  }
420  }
421  }
422 
423  // A2 x B1
424  s = T[1] * B(0, 1) - T[0] * B(1, 1);
425  t = ((s < 0.0) ? -s : s);
426  assert(t == fabs(s));
427 
428  diff = t - (a[0] * Bf(1, 1) + a[1] * Bf(0, 1) + b[0] * Bf(2, 2) +
429  b[2] * Bf(2, 0));
430  if (diff > 0) {
431  sinus2 = 1 - Bf(2, 1) * Bf(2, 1);
432  if (sinus2 > 1e-6) {
433  squaredLowerBoundDistance = diff * diff / sinus2;
434  if (squaredLowerBoundDistance > breakDistance2) {
435  return true;
436  }
437  }
438  }
439 
440  // A2 x B2
441  s = T[1] * B(0, 2) - T[0] * B(1, 2);
442  t = ((s < 0.0) ? -s : s);
443  assert(t == fabs(s));
444 
445  diff = t - (a[0] * Bf(1, 2) + a[1] * Bf(0, 2) + b[0] * Bf(2, 1) +
446  b[1] * Bf(2, 0));
447  if (diff > 0) {
448  sinus2 = 1 - Bf(2, 2) * Bf(2, 2);
449  if (sinus2 > 1e-6) {
450  squaredLowerBoundDistance = diff * diff / sinus2;
451  if (squaredLowerBoundDistance > breakDistance2) {
452  return true;
453  }
454  }
455  }
456 
457  return false;
458 }
459 
460 // ------------------------ 2 --------------------------------------
461 bool withManualLoopUnrolling_2(const Matrix3s& B, const Vec3s& T,
462  const Vec3s& a, const Vec3s& b,
463  const CoalScalar& breakDistance2,
464  CoalScalar& squaredLowerBoundDistance) {
465  Matrix3s Bf(B.cwiseAbs());
466 
467  // Corner of b axis aligned bounding box the closest to the origin
468  squaredLowerBoundDistance = _computeDistanceForCase1(T, a, b, Bf);
469  if (squaredLowerBoundDistance > breakDistance2) return true;
470 
471  squaredLowerBoundDistance = _computeDistanceForCase2(B, T, a, b, Bf);
472  if (squaredLowerBoundDistance > breakDistance2) return true;
473 
474  // A0 x B0
475  CoalScalar t, s;
476  s = T[2] * B(1, 0) - T[1] * B(2, 0);
477  t = ((s < 0.0) ? -s : s);
478  assert(t == fabs(s));
479 
480  CoalScalar sinus2;
481  CoalScalar diff;
482  diff = t - (a[1] * Bf(2, 0) + a[2] * Bf(1, 0) + b[1] * Bf(0, 2) +
483  b[2] * Bf(0, 1));
484  // We need to divide by the norm || A0 x B0 ||
485  // As ||A0|| = ||B0|| = 1,
486  // 2 2
487  // || A0 x B0 || + (A0 | B0) = 1
488  if (diff > 0) {
489  sinus2 = 1 - Bf(0, 0) * Bf(0, 0);
490  if (sinus2 > 1e-6) {
491  squaredLowerBoundDistance = diff * diff / sinus2;
492  if (squaredLowerBoundDistance > breakDistance2) {
493  return true;
494  }
495  }
496  }
497 
498  // A0 x B1
499  s = T[2] * B(1, 1) - T[1] * B(2, 1);
500  t = ((s < 0.0) ? -s : s);
501  assert(t == fabs(s));
502 
503  diff = t - (a[1] * Bf(2, 1) + a[2] * Bf(1, 1) + b[0] * Bf(0, 2) +
504  b[2] * Bf(0, 0));
505  if (diff > 0) {
506  sinus2 = 1 - Bf(0, 1) * Bf(0, 1);
507  if (sinus2 > 1e-6) {
508  squaredLowerBoundDistance = diff * diff / sinus2;
509  if (squaredLowerBoundDistance > breakDistance2) {
510  return true;
511  }
512  }
513  }
514 
515  // A0 x B2
516  s = T[2] * B(1, 2) - T[1] * B(2, 2);
517  t = ((s < 0.0) ? -s : s);
518  assert(t == fabs(s));
519 
520  diff = t - (a[1] * Bf(2, 2) + a[2] * Bf(1, 2) + b[0] * Bf(0, 1) +
521  b[1] * Bf(0, 0));
522  if (diff > 0) {
523  sinus2 = 1 - Bf(0, 2) * Bf(0, 2);
524  if (sinus2 > 1e-6) {
525  squaredLowerBoundDistance = diff * diff / sinus2;
526  if (squaredLowerBoundDistance > breakDistance2) {
527  return true;
528  }
529  }
530  }
531 
532  // A1 x B0
533  s = T[0] * B(2, 0) - T[2] * B(0, 0);
534  t = ((s < 0.0) ? -s : s);
535  assert(t == fabs(s));
536 
537  diff = t - (a[0] * Bf(2, 0) + a[2] * Bf(0, 0) + b[1] * Bf(1, 2) +
538  b[2] * Bf(1, 1));
539  if (diff > 0) {
540  sinus2 = 1 - Bf(1, 0) * Bf(1, 0);
541  if (sinus2 > 1e-6) {
542  squaredLowerBoundDistance = diff * diff / sinus2;
543  if (squaredLowerBoundDistance > breakDistance2) {
544  return true;
545  }
546  }
547  }
548 
549  // A1 x B1
550  s = T[0] * B(2, 1) - T[2] * B(0, 1);
551  t = ((s < 0.0) ? -s : s);
552  assert(t == fabs(s));
553 
554  diff = t - (a[0] * Bf(2, 1) + a[2] * Bf(0, 1) + b[0] * Bf(1, 2) +
555  b[2] * Bf(1, 0));
556  if (diff > 0) {
557  sinus2 = 1 - Bf(1, 1) * Bf(1, 1);
558  if (sinus2 > 1e-6) {
559  squaredLowerBoundDistance = diff * diff / sinus2;
560  if (squaredLowerBoundDistance > breakDistance2) {
561  return true;
562  }
563  }
564  }
565 
566  // A1 x B2
567  s = T[0] * B(2, 2) - T[2] * B(0, 2);
568  t = ((s < 0.0) ? -s : s);
569  assert(t == fabs(s));
570 
571  diff = t - (a[0] * Bf(2, 2) + a[2] * Bf(0, 2) + b[0] * Bf(1, 1) +
572  b[1] * Bf(1, 0));
573  if (diff > 0) {
574  sinus2 = 1 - Bf(1, 2) * Bf(1, 2);
575  if (sinus2 > 1e-6) {
576  squaredLowerBoundDistance = diff * diff / sinus2;
577  if (squaredLowerBoundDistance > breakDistance2) {
578  return true;
579  }
580  }
581  }
582 
583  // A2 x B0
584  s = T[1] * B(0, 0) - T[0] * B(1, 0);
585  t = ((s < 0.0) ? -s : s);
586  assert(t == fabs(s));
587 
588  diff = t - (a[0] * Bf(1, 0) + a[1] * Bf(0, 0) + b[1] * Bf(2, 2) +
589  b[2] * Bf(2, 1));
590  if (diff > 0) {
591  sinus2 = 1 - Bf(2, 0) * Bf(2, 0);
592  if (sinus2 > 1e-6) {
593  squaredLowerBoundDistance = diff * diff / sinus2;
594  if (squaredLowerBoundDistance > breakDistance2) {
595  return true;
596  }
597  }
598  }
599 
600  // A2 x B1
601  s = T[1] * B(0, 1) - T[0] * B(1, 1);
602  t = ((s < 0.0) ? -s : s);
603  assert(t == fabs(s));
604 
605  diff = t - (a[0] * Bf(1, 1) + a[1] * Bf(0, 1) + b[0] * Bf(2, 2) +
606  b[2] * Bf(2, 0));
607  if (diff > 0) {
608  sinus2 = 1 - Bf(2, 1) * Bf(2, 1);
609  if (sinus2 > 1e-6) {
610  squaredLowerBoundDistance = diff * diff / sinus2;
611  if (squaredLowerBoundDistance > breakDistance2) {
612  return true;
613  }
614  }
615  }
616 
617  // A2 x B2
618  s = T[1] * B(0, 2) - T[0] * B(1, 2);
619  t = ((s < 0.0) ? -s : s);
620  assert(t == fabs(s));
621 
622  diff = t - (a[0] * Bf(1, 2) + a[1] * Bf(0, 2) + b[0] * Bf(2, 1) +
623  b[1] * Bf(2, 0));
624  if (diff > 0) {
625  sinus2 = 1 - Bf(2, 2) * Bf(2, 2);
626  if (sinus2 > 1e-6) {
627  squaredLowerBoundDistance = diff * diff / sinus2;
628  if (squaredLowerBoundDistance > breakDistance2) {
629  return true;
630  }
631  }
632  }
633 
634  return false;
635 }
636 
637 // ------------------------ 3 --------------------------------------
638 template <int ia, int ib, int ja = (ia + 1) % 3, int ka = (ia + 2) % 3,
639  int jb = (ib + 1) % 3, int kb = (ib + 2) % 3>
640 struct loop_case_1 {
641  static inline bool run(const Matrix3s& B, const Vec3s& T, const Vec3s& a,
642  const Vec3s& b, const Matrix3s& Bf,
643  const CoalScalar& breakDistance2,
644  CoalScalar& squaredLowerBoundDistance) {
645  const CoalScalar s = T[ka] * B(ja, ib) - T[ja] * B(ka, ib);
646 
647  const CoalScalar diff = fabs(s) - (a[ja] * Bf(ka, ib) + a[ka] * Bf(ja, ib) +
648  b[jb] * Bf(ia, kb) + b[kb] * Bf(ia, jb));
649  // We need to divide by the norm || Aia x Bib ||
650  // As ||Aia|| = ||Bib|| = 1, (Aia | Bib)^2 = cosine^2
651  if (diff > 0) {
652  CoalScalar sinus2 = 1 - Bf(ia, ib) * Bf(ia, ib);
653  if (sinus2 > 1e-6) {
654  squaredLowerBoundDistance = diff * diff / sinus2;
655  if (squaredLowerBoundDistance > breakDistance2) {
656  return true;
657  }
658  }
659  /* // or
660  CoalScalar sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib);
661  squaredLowerBoundDistance = diff * diff;
662  if (squaredLowerBoundDistance > breakDistance2 * sinus2) {
663  squaredLowerBoundDistance /= sinus2;
664  return true;
665  }
666  // */
667  }
668  return false;
669  }
670 };
671 
673  const Vec3s& a, const Vec3s& b,
674  const CoalScalar& breakDistance2,
675  CoalScalar& squaredLowerBoundDistance) {
676  Matrix3s Bf(B.cwiseAbs());
677 
678  // Corner of b axis aligned bounding box the closest to the origin
679  squaredLowerBoundDistance = _computeDistanceForCase1(T, a, b, Bf);
680  if (squaredLowerBoundDistance > breakDistance2) return true;
681 
682  squaredLowerBoundDistance = _computeDistanceForCase2(B, T, a, b, Bf);
683  if (squaredLowerBoundDistance > breakDistance2) return true;
684 
685  // Ai x Bj
686  if (loop_case_1<0, 0>::run(B, T, a, b, Bf, breakDistance2,
687  squaredLowerBoundDistance))
688  return true;
689  if (loop_case_1<0, 1>::run(B, T, a, b, Bf, breakDistance2,
690  squaredLowerBoundDistance))
691  return true;
692  if (loop_case_1<0, 2>::run(B, T, a, b, Bf, breakDistance2,
693  squaredLowerBoundDistance))
694  return true;
695  if (loop_case_1<1, 0>::run(B, T, a, b, Bf, breakDistance2,
696  squaredLowerBoundDistance))
697  return true;
698  if (loop_case_1<1, 1>::run(B, T, a, b, Bf, breakDistance2,
699  squaredLowerBoundDistance))
700  return true;
701  if (loop_case_1<1, 2>::run(B, T, a, b, Bf, breakDistance2,
702  squaredLowerBoundDistance))
703  return true;
704  if (loop_case_1<2, 0>::run(B, T, a, b, Bf, breakDistance2,
705  squaredLowerBoundDistance))
706  return true;
707  if (loop_case_1<2, 1>::run(B, T, a, b, Bf, breakDistance2,
708  squaredLowerBoundDistance))
709  return true;
710  if (loop_case_1<2, 2>::run(B, T, a, b, Bf, breakDistance2,
711  squaredLowerBoundDistance))
712  return true;
713 
714  return false;
715 }
716 
717 // ------------------------ 4 --------------------------------------
718 
719 template <int ib, int jb = (ib + 1) % 3, int kb = (ib + 2) % 3>
720 struct loop_case_2 {
721  static inline bool run(int ia, int ja, int ka, const Matrix3s& B,
722  const Vec3s& T, const Vec3s& a, const Vec3s& b,
723  const Matrix3s& Bf, const CoalScalar& breakDistance2,
724  CoalScalar& squaredLowerBoundDistance) {
725  const CoalScalar s = T[ka] * B(ja, ib) - T[ja] * B(ka, ib);
726 
727  const CoalScalar diff = fabs(s) - (a[ja] * Bf(ka, ib) + a[ka] * Bf(ja, ib) +
728  b[jb] * Bf(ia, kb) + b[kb] * Bf(ia, jb));
729  // We need to divide by the norm || Aia x Bib ||
730  // As ||Aia|| = ||Bib|| = 1, (Aia | Bib)^2 = cosine^2
731  if (diff > 0) {
732  CoalScalar sinus2 = 1 - Bf(ia, ib) * Bf(ia, ib);
733  if (sinus2 > 1e-6) {
734  squaredLowerBoundDistance = diff * diff / sinus2;
735  if (squaredLowerBoundDistance > breakDistance2) {
736  return true;
737  }
738  }
739  /* // or
740  CoalScalar sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib);
741  squaredLowerBoundDistance = diff * diff;
742  if (squaredLowerBoundDistance > breakDistance2 * sinus2) {
743  squaredLowerBoundDistance /= sinus2;
744  return true;
745  }
746  // */
747  }
748  return false;
749  }
750 };
751 
753  const Vec3s& a, const Vec3s& b,
754  const CoalScalar& breakDistance2,
755  CoalScalar& squaredLowerBoundDistance) {
756  Matrix3s Bf(B.cwiseAbs());
757 
758  // Corner of b axis aligned bounding box the closest to the origin
759  squaredLowerBoundDistance = _computeDistanceForCase1(T, a, b, Bf);
760  if (squaredLowerBoundDistance > breakDistance2) return true;
761 
762  squaredLowerBoundDistance = _computeDistanceForCase2(B, T, a, b, Bf);
763  if (squaredLowerBoundDistance > breakDistance2) return true;
764 
765  // Ai x Bj
766  int ja = 1, ka = 2;
767  for (int ia = 0; ia < 3; ++ia) {
768  if (loop_case_2<0>::run(ia, ja, ka, B, T, a, b, Bf, breakDistance2,
769  squaredLowerBoundDistance))
770  return true;
771  if (loop_case_2<1>::run(ia, ja, ka, B, T, a, b, Bf, breakDistance2,
772  squaredLowerBoundDistance))
773  return true;
774  if (loop_case_2<2>::run(ia, ja, ka, B, T, a, b, Bf, breakDistance2,
775  squaredLowerBoundDistance))
776  return true;
777  ja = ka;
778  ka = ia;
779  }
780 
781  return false;
782 }
783 
784 // ------------------------ 5 --------------------------------------
785 bool originalWithLowerBound(const Matrix3s& B, const Vec3s& T, const Vec3s& a,
786  const Vec3s& b, const CoalScalar& breakDistance2,
787  CoalScalar& squaredLowerBoundDistance) {
788  CoalScalar t, s;
789  CoalScalar diff;
790 
791  Matrix3s Bf(B.cwiseAbs());
792  squaredLowerBoundDistance = 0;
793 
794  // if any of these tests are one-sided, then the polyhedra are disjoint
795 
796  // A1 x A2 = A0
797  t = ((T[0] < 0.0) ? -T[0] : T[0]);
798 
799  diff = t - (a[0] + Bf.row(0).dot(b));
800  if (diff > 0) {
801  squaredLowerBoundDistance = diff * diff;
802  }
803 
804  // A2 x A0 = A1
805  t = ((T[1] < 0.0) ? -T[1] : T[1]);
806 
807  diff = t - (a[1] + Bf.row(1).dot(b));
808  if (diff > 0) {
809  squaredLowerBoundDistance += diff * diff;
810  }
811 
812  // A0 x A1 = A2
813  t = ((T[2] < 0.0) ? -T[2] : T[2]);
814 
815  diff = t - (a[2] + Bf.row(2).dot(b));
816  if (diff > 0) {
817  squaredLowerBoundDistance += diff * diff;
818  }
819 
820  if (squaredLowerBoundDistance > breakDistance2) return true;
821 
822  squaredLowerBoundDistance = 0;
823 
824  // B1 x B2 = B0
825  s = B.col(0).dot(T);
826  t = ((s < 0.0) ? -s : s);
827 
828  diff = t - (b[0] + Bf.col(0).dot(a));
829  if (diff > 0) {
830  squaredLowerBoundDistance += diff * diff;
831  }
832 
833  // B2 x B0 = B1
834  s = B.col(1).dot(T);
835  t = ((s < 0.0) ? -s : s);
836 
837  diff = t - (b[1] + Bf.col(1).dot(a));
838  if (diff > 0) {
839  squaredLowerBoundDistance += diff * diff;
840  }
841 
842  // B0 x B1 = B2
843  s = B.col(2).dot(T);
844  t = ((s < 0.0) ? -s : s);
845 
846  diff = t - (b[2] + Bf.col(2).dot(a));
847  if (diff > 0) {
848  squaredLowerBoundDistance += diff * diff;
849  }
850 
851  if (squaredLowerBoundDistance > breakDistance2) return true;
852 
853  // A0 x B0
854  s = T[2] * B(1, 0) - T[1] * B(2, 0);
855  t = ((s < 0.0) ? -s : s);
856 
857  CoalScalar sinus2;
858  diff = t - (a[1] * Bf(2, 0) + a[2] * Bf(1, 0) + b[1] * Bf(0, 2) +
859  b[2] * Bf(0, 1));
860  // We need to divide by the norm || A0 x B0 ||
861  // As ||A0|| = ||B0|| = 1,
862  // 2 2
863  // || A0 x B0 || + (A0 | B0) = 1
864  if (diff > 0) {
865  sinus2 = 1 - Bf(0, 0) * Bf(0, 0);
866  if (sinus2 > 1e-6) {
867  squaredLowerBoundDistance = diff * diff / sinus2;
868  if (squaredLowerBoundDistance > breakDistance2) {
869  return true;
870  }
871  }
872  }
873 
874  // A0 x B1
875  s = T[2] * B(1, 1) - T[1] * B(2, 1);
876  t = ((s < 0.0) ? -s : s);
877 
878  diff = t - (a[1] * Bf(2, 1) + a[2] * Bf(1, 1) + b[0] * Bf(0, 2) +
879  b[2] * Bf(0, 0));
880  if (diff > 0) {
881  sinus2 = 1 - Bf(0, 1) * Bf(0, 1);
882  if (sinus2 > 1e-6) {
883  squaredLowerBoundDistance = diff * diff / sinus2;
884  if (squaredLowerBoundDistance > breakDistance2) {
885  return true;
886  }
887  }
888  }
889 
890  // A0 x B2
891  s = T[2] * B(1, 2) - T[1] * B(2, 2);
892  t = ((s < 0.0) ? -s : s);
893 
894  diff = t - (a[1] * Bf(2, 2) + a[2] * Bf(1, 2) + b[0] * Bf(0, 1) +
895  b[1] * Bf(0, 0));
896  if (diff > 0) {
897  sinus2 = 1 - Bf(0, 2) * Bf(0, 2);
898  if (sinus2 > 1e-6) {
899  squaredLowerBoundDistance = diff * diff / sinus2;
900  if (squaredLowerBoundDistance > breakDistance2) {
901  return true;
902  }
903  }
904  }
905 
906  // A1 x B0
907  s = T[0] * B(2, 0) - T[2] * B(0, 0);
908  t = ((s < 0.0) ? -s : s);
909 
910  diff = t - (a[0] * Bf(2, 0) + a[2] * Bf(0, 0) + b[1] * Bf(1, 2) +
911  b[2] * Bf(1, 1));
912  if (diff > 0) {
913  sinus2 = 1 - Bf(1, 0) * Bf(1, 0);
914  if (sinus2 > 1e-6) {
915  squaredLowerBoundDistance = diff * diff / sinus2;
916  if (squaredLowerBoundDistance > breakDistance2) {
917  return true;
918  }
919  }
920  }
921 
922  // A1 x B1
923  s = T[0] * B(2, 1) - T[2] * B(0, 1);
924  t = ((s < 0.0) ? -s : s);
925 
926  diff = t - (a[0] * Bf(2, 1) + a[2] * Bf(0, 1) + b[0] * Bf(1, 2) +
927  b[2] * Bf(1, 0));
928  if (diff > 0) {
929  sinus2 = 1 - Bf(1, 1) * Bf(1, 1);
930  if (sinus2 > 1e-6) {
931  squaredLowerBoundDistance = diff * diff / sinus2;
932  if (squaredLowerBoundDistance > breakDistance2) {
933  return true;
934  }
935  }
936  }
937 
938  // A1 x B2
939  s = T[0] * B(2, 2) - T[2] * B(0, 2);
940  t = ((s < 0.0) ? -s : s);
941 
942  diff = t - (a[0] * Bf(2, 2) + a[2] * Bf(0, 2) + b[0] * Bf(1, 1) +
943  b[1] * Bf(1, 0));
944  if (diff > 0) {
945  sinus2 = 1 - Bf(1, 2) * Bf(1, 2);
946  if (sinus2 > 1e-6) {
947  squaredLowerBoundDistance = diff * diff / sinus2;
948  if (squaredLowerBoundDistance > breakDistance2) {
949  return true;
950  }
951  }
952  }
953 
954  // A2 x B0
955  s = T[1] * B(0, 0) - T[0] * B(1, 0);
956  t = ((s < 0.0) ? -s : s);
957 
958  diff = t - (a[0] * Bf(1, 0) + a[1] * Bf(0, 0) + b[1] * Bf(2, 2) +
959  b[2] * Bf(2, 1));
960  if (diff > 0) {
961  sinus2 = 1 - Bf(2, 0) * Bf(2, 0);
962  if (sinus2 > 1e-6) {
963  squaredLowerBoundDistance = diff * diff / sinus2;
964  if (squaredLowerBoundDistance > breakDistance2) {
965  return true;
966  }
967  }
968  }
969 
970  // A2 x B1
971  s = T[1] * B(0, 1) - T[0] * B(1, 1);
972  t = ((s < 0.0) ? -s : s);
973 
974  diff = t - (a[0] * Bf(1, 1) + a[1] * Bf(0, 1) + b[0] * Bf(2, 2) +
975  b[2] * Bf(2, 0));
976  if (diff > 0) {
977  sinus2 = 1 - Bf(2, 1) * Bf(2, 1);
978  if (sinus2 > 1e-6) {
979  squaredLowerBoundDistance = diff * diff / sinus2;
980  if (squaredLowerBoundDistance > breakDistance2) {
981  return true;
982  }
983  }
984  }
985 
986  // A2 x B2
987  s = T[1] * B(0, 2) - T[0] * B(1, 2);
988  t = ((s < 0.0) ? -s : s);
989 
990  diff = t - (a[0] * Bf(1, 2) + a[1] * Bf(0, 2) + b[0] * Bf(2, 1) +
991  b[1] * Bf(2, 0));
992  if (diff > 0) {
993  sinus2 = 1 - Bf(2, 2) * Bf(2, 2);
994  if (sinus2 > 1e-6) {
995  squaredLowerBoundDistance = diff * diff / sinus2;
996  if (squaredLowerBoundDistance > breakDistance2) {
997  return true;
998  }
999  }
1000  }
1001 
1002  return false;
1003 }
1004 
1005 // ------------------------ 6 --------------------------------------
1006 bool originalWithNoLowerBound(const Matrix3s& B, const Vec3s& T, const Vec3s& a,
1007  const Vec3s& b, const CoalScalar&,
1008  CoalScalar& squaredLowerBoundDistance) {
1009  CoalScalar t, s;
1010  const CoalScalar reps = 1e-6;
1011 
1012  squaredLowerBoundDistance = 0;
1013 
1014  Matrix3s Bf(B.array().abs() + reps);
1015  // Bf += reps;
1016 
1017  // if any of these tests are one-sided, then the polyhedra are disjoint
1018 
1019  // A1 x A2 = A0
1020  t = ((T[0] < 0.0) ? -T[0] : T[0]);
1021 
1022  // if(t > (a[0] + Bf.dotX(b)))
1023  if (t > (a[0] + Bf.row(0).dot(b))) return true;
1024 
1025  // B1 x B2 = B0
1026  // s = B.transposeDotX(T);
1027  s = B.col(0).dot(T);
1028  t = ((s < 0.0) ? -s : s);
1029 
1030  // if(t > (b[0] + Bf.transposeDotX(a)))
1031  if (t > (b[0] + Bf.col(0).dot(a))) return true;
1032 
1033  // A2 x A0 = A1
1034  t = ((T[1] < 0.0) ? -T[1] : T[1]);
1035 
1036  // if(t > (a[1] + Bf.dotY(b)))
1037  if (t > (a[1] + Bf.row(1).dot(b))) return true;
1038 
1039  // A0 x A1 = A2
1040  t = ((T[2] < 0.0) ? -T[2] : T[2]);
1041 
1042  // if(t > (a[2] + Bf.dotZ(b)))
1043  if (t > (a[2] + Bf.row(2).dot(b))) return true;
1044 
1045  // B2 x B0 = B1
1046  // s = B.transposeDotY(T);
1047  s = B.col(1).dot(T);
1048  t = ((s < 0.0) ? -s : s);
1049 
1050  // if(t > (b[1] + Bf.transposeDotY(a)))
1051  if (t > (b[1] + Bf.col(1).dot(a))) return true;
1052 
1053  // B0 x B1 = B2
1054  // s = B.transposeDotZ(T);
1055  s = B.col(2).dot(T);
1056  t = ((s < 0.0) ? -s : s);
1057 
1058  // if(t > (b[2] + Bf.transposeDotZ(a)))
1059  if (t > (b[2] + Bf.col(2).dot(a))) return true;
1060 
1061  // A0 x B0
1062  s = T[2] * B(1, 0) - T[1] * B(2, 0);
1063  t = ((s < 0.0) ? -s : s);
1064 
1065  if (t >
1066  (a[1] * Bf(2, 0) + a[2] * Bf(1, 0) + b[1] * Bf(0, 2) + b[2] * Bf(0, 1)))
1067  return true;
1068 
1069  // A0 x B1
1070  s = T[2] * B(1, 1) - T[1] * B(2, 1);
1071  t = ((s < 0.0) ? -s : s);
1072 
1073  if (t >
1074  (a[1] * Bf(2, 1) + a[2] * Bf(1, 1) + b[0] * Bf(0, 2) + b[2] * Bf(0, 0)))
1075  return true;
1076 
1077  // A0 x B2
1078  s = T[2] * B(1, 2) - T[1] * B(2, 2);
1079  t = ((s < 0.0) ? -s : s);
1080 
1081  if (t >
1082  (a[1] * Bf(2, 2) + a[2] * Bf(1, 2) + b[0] * Bf(0, 1) + b[1] * Bf(0, 0)))
1083  return true;
1084 
1085  // A1 x B0
1086  s = T[0] * B(2, 0) - T[2] * B(0, 0);
1087  t = ((s < 0.0) ? -s : s);
1088 
1089  if (t >
1090  (a[0] * Bf(2, 0) + a[2] * Bf(0, 0) + b[1] * Bf(1, 2) + b[2] * Bf(1, 1)))
1091  return true;
1092 
1093  // A1 x B1
1094  s = T[0] * B(2, 1) - T[2] * B(0, 1);
1095  t = ((s < 0.0) ? -s : s);
1096 
1097  if (t >
1098  (a[0] * Bf(2, 1) + a[2] * Bf(0, 1) + b[0] * Bf(1, 2) + b[2] * Bf(1, 0)))
1099  return true;
1100 
1101  // A1 x B2
1102  s = T[0] * B(2, 2) - T[2] * B(0, 2);
1103  t = ((s < 0.0) ? -s : s);
1104 
1105  if (t >
1106  (a[0] * Bf(2, 2) + a[2] * Bf(0, 2) + b[0] * Bf(1, 1) + b[1] * Bf(1, 0)))
1107  return true;
1108 
1109  // A2 x B0
1110  s = T[1] * B(0, 0) - T[0] * B(1, 0);
1111  t = ((s < 0.0) ? -s : s);
1112 
1113  if (t >
1114  (a[0] * Bf(1, 0) + a[1] * Bf(0, 0) + b[1] * Bf(2, 2) + b[2] * Bf(2, 1)))
1115  return true;
1116 
1117  // A2 x B1
1118  s = T[1] * B(0, 1) - T[0] * B(1, 1);
1119  t = ((s < 0.0) ? -s : s);
1120 
1121  if (t >
1122  (a[0] * Bf(1, 1) + a[1] * Bf(0, 1) + b[0] * Bf(2, 2) + b[2] * Bf(2, 0)))
1123  return true;
1124 
1125  // A2 x B2
1126  s = T[1] * B(0, 2) - T[0] * B(1, 2);
1127  t = ((s < 0.0) ? -s : s);
1128 
1129  if (t >
1130  (a[0] * Bf(1, 2) + a[1] * Bf(0, 2) + b[0] * Bf(2, 1) + b[1] * Bf(2, 0)))
1131  return true;
1132 
1133  return false;
1134 }
1135 } // namespace obbDisjoint_impls
1136 
1141  int ifId;
1145  bool failure;
1146 
1147  static std::ostream& headers(std::ostream& os) {
1148  const std::string unit = " (us)";
1149  os << "separating axis" << sep << "distance lower bound" << sep
1150  << "distance" << sep << "failure" << sep << "Runtime Loop" << unit << sep
1151  << "Manual Loop Unrolling 1" << unit << sep << "Manual Loop Unrolling 2"
1152  << unit << sep << "Template Unrolling" << unit << sep
1153  << "Partial Template Unrolling" << unit << sep << "Original (LowerBound)"
1154  << unit << sep << "Original (NoLowerBound)" << unit;
1155  return os;
1156  }
1157 
1158  std::ostream& print(std::ostream& os) const {
1159  os << ifId << sep << std::sqrt(squaredLowerBoundDistance) << sep << distance
1160  << sep << failure;
1161  for (int i = 0; i < NB_METHODS; ++i)
1162  os << sep
1163  << static_cast<double>(
1164  std::chrono::duration_cast<std::chrono::nanoseconds>(
1165  duration[i])
1166  .count()) *
1167  1e-3;
1168  return os;
1169  }
1170 };
1171 
1172 std::ostream& operator<<(std::ostream& os, const BenchmarkResult& br) {
1173  return br.print(os);
1174 }
1175 
1177  const Vec3s& a, const Vec3s& b,
1178  const CollisionRequest& request,
1179  std::size_t N) {
1180  const CoalScalar breakDistance(request.break_distance +
1181  request.security_margin);
1182  const CoalScalar breakDistance2 = breakDistance * breakDistance;
1183 
1184  BenchmarkResult result;
1185  // First determine which axis provide the answer
1187  B, T, a, b, breakDistance2, result.squaredLowerBoundDistance);
1188  bool disjoint = obbDisjoint_impls::distance(B, T, a, b, result.distance);
1189  assert(0 <= result.ifId && result.ifId <= 11);
1190 
1191  // Sanity check
1192  result.failure = true;
1193  bool overlap = (result.ifId == 11);
1194  CoalScalar dist_thr = request.break_distance + request.security_margin;
1195  if (!overlap && result.distance <= 0) {
1196  std::cerr << "Failure: negative distance for disjoint OBBs.";
1197  } else if (!overlap && result.squaredLowerBoundDistance < 0) {
1198  std::cerr << "Failure: negative distance lower bound.";
1199  } else if (!overlap && eps < std::sqrt(result.squaredLowerBoundDistance) -
1200  result.distance) {
1201  std::cerr << "Failure: distance is inferior to its lower bound (diff = "
1202  << std::sqrt(result.squaredLowerBoundDistance) - result.distance
1203  << ").";
1204  } else if (overlap != !disjoint && result.distance >= dist_thr - eps) {
1205  std::cerr << "Failure: overlapping test and distance query mismatch.";
1206  } else if (overlap && result.distance >= dist_thr - eps) {
1207  std::cerr << "Failure: positive distance for overlapping OBBs.";
1208  } else {
1209  result.failure = false;
1210  }
1211  if (result.failure) {
1212  std::cerr << "\nR = " << Quatf(B).coeffs().transpose().format(py_fmt)
1213  << "\nT = " << T.transpose().format(py_fmt)
1214  << "\na = " << a.transpose().format(py_fmt)
1215  << "\nb = " << b.transpose().format(py_fmt)
1216  << "\nresult = " << result << '\n'
1217  << std::endl;
1218  }
1219 
1220  // Compute time
1221  CoalScalar tmp;
1222  clock_type::time_point start, end;
1223 
1224  // ------------------------ 0 --------------------------------------
1225  start = clock_type::now();
1226  for (std::size_t i = 0; i < N; ++i)
1227  obbDisjoint_impls::withRuntimeLoop(B, T, a, b, breakDistance2, tmp);
1228  end = clock_type::now();
1229  result.duration[0] = (end - start) / N;
1230 
1231  // ------------------------ 1 --------------------------------------
1232  start = clock_type::now();
1233  for (std::size_t i = 0; i < N; ++i)
1234  obbDisjoint_impls::withManualLoopUnrolling_1(B, T, a, b, breakDistance2,
1235  tmp);
1236  end = clock_type::now();
1237  result.duration[1] = (end - start) / N;
1238 
1239  // ------------------------ 2 --------------------------------------
1240  start = clock_type::now();
1241  for (std::size_t i = 0; i < N; ++i)
1242  obbDisjoint_impls::withManualLoopUnrolling_2(B, T, a, b, breakDistance2,
1243  tmp);
1244  end = clock_type::now();
1245  result.duration[2] = (end - start) / N;
1246 
1247  // ------------------------ 3 --------------------------------------
1248  start = clock_type::now();
1249  for (std::size_t i = 0; i < N; ++i)
1250  obbDisjoint_impls::withTemplateLoopUnrolling_1(B, T, a, b, breakDistance2,
1251  tmp);
1252  end = clock_type::now();
1253  result.duration[3] = (end - start) / N;
1254 
1255  // ------------------------ 4 --------------------------------------
1256  start = clock_type::now();
1257  for (std::size_t i = 0; i < N; ++i)
1259  breakDistance2, tmp);
1260  end = clock_type::now();
1261  result.duration[4] = (end - start) / N;
1262 
1263  // ------------------------ 5 --------------------------------------
1264  start = clock_type::now();
1265  for (std::size_t i = 0; i < N; ++i)
1266  obbDisjoint_impls::originalWithLowerBound(B, T, a, b, breakDistance2, tmp);
1267  end = clock_type::now();
1268  result.duration[5] = (end - start) / N;
1269 
1270  // ------------------------ 6 --------------------------------------
1271  start = clock_type::now();
1272  // The 2 last arguments are unused.
1273  for (std::size_t i = 0; i < N; ++i)
1274  obbDisjoint_impls::originalWithNoLowerBound(B, T, a, b, breakDistance2,
1275  tmp);
1276  end = clock_type::now();
1277  result.duration[6] = (end - start) / N;
1278 
1279  return result;
1280 }
1281 
1282 std::size_t obb_overlap_and_lower_bound_distance(std::ostream* output) {
1283  std::size_t nbFailure = 0;
1284 
1285  // Create two OBBs axis
1286  Vec3s a, b;
1287  Matrix3s B;
1288  Vec3s T;
1289  CollisionRequest request;
1290 
1291 #ifndef NDEBUG // if debug mode
1292  static const size_t nbRandomOBB = 10;
1293  static const size_t nbTransformPerOBB = 10;
1294  static const size_t nbRunForTimeMeas = 10;
1295 #else
1296  static const size_t nbRandomOBB = 100;
1297  static const size_t nbTransformPerOBB = 100;
1298  static const size_t nbRunForTimeMeas = 1000;
1299 #endif
1300  static const CoalScalar extentNorm = 1.;
1301 
1302  if (output != NULL) *output << BenchmarkResult::headers << '\n';
1303 
1304  BenchmarkResult result;
1305  for (std::size_t iobb = 0; iobb < nbRandomOBB; ++iobb) {
1306  randomOBBs(a, b, extentNorm);
1307  for (std::size_t itf = 0; itf < nbTransformPerOBB; ++itf) {
1308  randomTransform(B, T, a, b, extentNorm);
1309  result = benchmark_obb_case(B, T, a, b, request, nbRunForTimeMeas);
1310  if (output != NULL) *output << result << '\n';
1311  if (result.failure) nbFailure++;
1312  }
1313  }
1314  return nbFailure;
1315 }
1316 
1317 int main(int argc, char** argv) {
1318  std::ostream* output = NULL;
1319  if (argc > 1 && strcmp(argv[1], "--generate-output") == 0) {
1320  output = &std::cout;
1321  }
1322 
1323  std::cout << "The benchmark real time measurements may be noisy and "
1324  "will incur extra overhead."
1325  "\nUse the following commands to turn ON:"
1326  "\n\tsudo cpufreq-set --governor performance"
1327  "\nor OFF:"
1328  "\n\tsudo cpufreq-set --governor powersave"
1329  "\n";
1330 
1331  std::size_t nbFailure = obb_overlap_and_lower_bound_distance(output);
1332  if (nbFailure > INT_MAX) return INT_MAX;
1333  return (int)nbFailure;
1334 }
obbDisjoint_impls::loop_case_2
Definition: obb.cpp:720
coal::Vec3s
Eigen::Matrix< CoalScalar, 3, 1 > Vec3s
Definition: coal/data_types.h:77
benchmark_obb_case
BenchmarkResult benchmark_obb_case(const Matrix3s &B, const Vec3s &T, const Vec3s &a, const Vec3s &b, const CollisionRequest &request, std::size_t N)
Definition: obb.cpp:1176
randomOBBs
void randomOBBs(Vec3s &a, Vec3s &b, CoalScalar extentNorm)
Definition: obb.cpp:51
obbDisjoint_impls::loop_case_1::run
static bool run(const Matrix3s &B, const Vec3s &T, const Vec3s &a, const Vec3s &b, const Matrix3s &Bf, const CoalScalar &breakDistance2, CoalScalar &squaredLowerBoundDistance)
Definition: obb.cpp:641
obbDisjoint_impls::withManualLoopUnrolling_1
bool withManualLoopUnrolling_1(const Matrix3s &B, const Vec3s &T, const Vec3s &a, const Vec3s &b, const CoalScalar &breakDistance2, CoalScalar &squaredLowerBoundDistance)
Definition: obb.cpp:271
sep
const char * sep
Definition: obb.cpp:92
obbDisjoint_impls::separatingAxisId
int separatingAxisId(const Matrix3s &B, const Vec3s &T, const Vec3s &a, const Vec3s &b, const CoalScalar &breakDistance2, CoalScalar &squaredLowerBoundDistance)
Definition: obb.cpp:162
duration_type
clock_type::duration duration_type
Definition: obb.cpp:90
B
B
BenchmarkResult
Definition: obb.cpp:1137
coal::CollisionRequest::security_margin
CoalScalar security_margin
Distance below which objects are considered in collision. See Collision.
Definition: coal/collision_data.h:328
coal
Main namespace.
Definition: coal/broadphase/broadphase_bruteforce.h:44
narrowphase.h
coal::Quatf
Eigen::Quaternion< CoalScalar > Quatf
Definition: coal/math/transform.h:47
utility.h
coal::GJKSolver
collision and distance solver based on the GJK and EPA algorithms. Originally, GJK and EPA were imple...
Definition: coal/narrowphase/narrowphase.h:57
coal::distance
COAL_DLLAPI CoalScalar distance(const Matrix3s &R0, const Vec3s &T0, const kIOS &b1, const kIOS &b2, Vec3s *P=NULL, Vec3s *Q=NULL)
Approximate distance between two kIOS bounding volumes.
Definition: kIOS.cpp:180
BenchmarkResult::failure
bool failure
Definition: obb.cpp:1145
eps
const CoalScalar eps
Definition: obb.cpp:93
a
list a
coal::Box
Center at zero point, axis aligned box.
Definition: coal/shape/geometric_shapes.h:166
coal::Transform3s
Simple transform class used locally by InterpMotion.
Definition: coal/math/transform.h:55
obb_overlap_and_lower_bound_distance
std::size_t obb_overlap_and_lower_bound_distance(std::ostream *output)
Definition: obb.cpp:1282
obbDisjoint_impls::originalWithLowerBound
bool originalWithLowerBound(const Matrix3s &B, const Vec3s &T, const Vec3s &a, const Vec3s &b, const CoalScalar &breakDistance2, CoalScalar &squaredLowerBoundDistance)
Definition: obb.cpp:785
coal::operator<<
static std::ostream & operator<<(std::ostream &o, const Quatf &q)
Definition: coal/math/transform.h:49
randomTransform
void randomTransform(Matrix3s &B, Vec3s &T, const Vec3s &a, const Vec3s &b, const CoalScalar extentNorm)
Definition: obb.cpp:60
BenchmarkResult::headers
static std::ostream & headers(std::ostream &os)
Definition: obb.cpp:1147
shape_shape_func.h
obbDisjoint_impls::_computeDistanceForCase2
CoalScalar _computeDistanceForCase2(const Matrix3s &B, const Vec3s &T, const Vec3s &a, const Vec3s &b, const Matrix3s &Bf)
Definition: obb.cpp:138
main
int main(int argc, char **argv)
Definition: obb.cpp:1317
obbDisjoint_impls::withRuntimeLoop
bool withRuntimeLoop(const Matrix3s &B, const Vec3s &T, const Vec3s &a, const Vec3s &b, const CoalScalar &breakDistance2, CoalScalar &squaredLowerBoundDistance)
Definition: obb.cpp:219
obbDisjoint_impls::_computeDistanceForCase1
CoalScalar _computeDistanceForCase1(const Vec3s &T, const Vec3s &a, const Vec3s &b, const Matrix3s &Bf)
Definition: obb.cpp:119
coal::CollisionRequest
request to the collision algorithm
Definition: coal/collision_data.h:311
BenchmarkResult::duration
duration_type duration[NB_METHODS]
Definition: obb.cpp:1144
obbDisjoint_impls::distance
bool distance(const Matrix3s &B, const Vec3s &T, const Vec3s &a, const Vec3s &b, CoalScalar &distance)
Definition: obb.cpp:106
q
q
octree.p1
tuple p1
Definition: octree.py:54
coal::overlap
COAL_DLLAPI bool overlap(const Matrix3s &R0, const Vec3s &T0, const AABB &b1, const AABB &b2)
Check collision between two aabbs, b1 is in configuration (R0, T0) and b2 is in identity.
Definition: AABB.cpp:134
NB_METHODS
#define NB_METHODS
Definition: obb.cpp:79
clock_type
std::chrono::high_resolution_clock clock_type
Definition: obb.cpp:89
obbDisjoint_impls::withManualLoopUnrolling_2
bool withManualLoopUnrolling_2(const Matrix3s &B, const Vec3s &T, const Vec3s &a, const Vec3s &b, const CoalScalar &breakDistance2, CoalScalar &squaredLowerBoundDistance)
Definition: obb.cpp:461
generate_distance_plot.b
float b
Definition: generate_distance_plot.py:7
BenchmarkResult::distance
CoalScalar distance
Definition: obb.cpp:1142
coal::Matrix3s
Eigen::Matrix< CoalScalar, 3, 3 > Matrix3s
Definition: coal/data_types.h:81
obbDisjoint_impls::withTemplateLoopUnrolling_1
bool withTemplateLoopUnrolling_1(const Matrix3s &B, const Vec3s &T, const Vec3s &a, const Vec3s &b, const CoalScalar &breakDistance2, CoalScalar &squaredLowerBoundDistance)
Definition: obb.cpp:672
BenchmarkResult::print
std::ostream & print(std::ostream &os) const
Definition: obb.cpp:1158
obbDisjoint_impls::loop_case_1
Definition: obb.cpp:640
BenchmarkResult::ifId
int ifId
The test ID:
Definition: obb.cpp:1141
obbDisjoint_impls::loop_case_2::run
static bool run(int ia, int ja, int ka, const Matrix3s &B, const Vec3s &T, const Vec3s &a, const Vec3s &b, const Matrix3s &Bf, const CoalScalar &breakDistance2, CoalScalar &squaredLowerBoundDistance)
Definition: obb.cpp:721
obbDisjoint_impls::originalWithNoLowerBound
bool originalWithNoLowerBound(const Matrix3s &B, const Vec3s &T, const Vec3s &a, const Vec3s &b, const CoalScalar &, CoalScalar &squaredLowerBoundDistance)
Definition: obb.cpp:1006
py_fmt
const Eigen::IOFormat py_fmt(Eigen::FullPrecision, 0, ", ", ",\n", "(", ",)", "( ", ", )")
BenchmarkResult::squaredLowerBoundDistance
CoalScalar squaredLowerBoundDistance
Definition: obb.cpp:1143
t
dictionary t
coal::CoalScalar
double CoalScalar
Definition: coal/data_types.h:76
obbDisjoint_impls
Definition: obb.cpp:104
coal::CollisionRequest::break_distance
CoalScalar break_distance
Distance below which bounding volumes are broken down. See Collision.
Definition: coal/collision_data.h:332
obbDisjoint_impls::withPartialTemplateLoopUnrolling_1
bool withPartialTemplateLoopUnrolling_1(const Matrix3s &B, const Vec3s &T, const Vec3s &a, const Vec3s &b, const CoalScalar &breakDistance2, CoalScalar &squaredLowerBoundDistance)
Definition: obb.cpp:752
gjk
Definition: doc/gjk.py:1


hpp-fcl
Author(s):
autogenerated on Sat Nov 23 2024 03:44:58