src/narrowphase/gjk.cpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2011-2014, Willow Garage, Inc.
5  * Copyright (c) 2014-2015, Open Source Robotics Foundation
6  * Copyright (c) 2021-2024, INRIA
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 Open Source Robotics Foundation 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 
40 #include "coal/narrowphase/gjk.h"
42 #include "coal/internal/tools.h"
45 
46 namespace coal {
47 
48 namespace details {
49 
51  distance_upper_bound = (std::numeric_limits<CoalScalar>::max)();
56 }
57 
58 void GJK::reset(size_t max_iterations_, CoalScalar tolerance_) {
59  max_iterations = max_iterations_;
60  tolerance = tolerance_;
61  COAL_ASSERT(tolerance_ > 0, "Tolerance must be positive.",
62  std::invalid_argument);
63  status = DidNotRun;
64  nfree = 0;
65  simplex = nullptr;
66  iterations = 0;
68 }
69 
70 Vec3s GJK::getGuessFromSimplex() const { return ray; }
71 
72 namespace details {
73 
74 // This function computes the weights associated with projecting the origin
75 // onto the final simplex of GJK or EPA.
76 // The origin is always a convex combination of the supports of the simplex.
77 // The weights are then linearly distributed among the shapes' supports, thanks
78 // to the following property:
79 // if s is a support of the Minkowski difference, then:
80 // w = w.w0 - w.w1, with w.w0 a support of shape0 and w.w1 a support of
81 // shape1.
82 // clang-format off
83 // Suppose the final simplex is of rank 2:
84 // We have 0 = alpha * w[0] + (1 - alpha) * w[1], with alpha the weight of the convex
85 // decomposition, then:
86 // 0 = alpha * (w[0].w0 - w[0].w1) + (1 - alpha) * (w[1].w0 - w[1].w1)
87 // => 0 = alpha * w[0].w0 + (1 - alpha) * w[1].w0
88 // - alpha * w[0].w1 - (1 - alpha) * w[1].w1
89 // Therefore we have two witness points:
90 // w0 = alpha * w[0].w0 + (1 - alpha) * w[1].w0
91 // w1 = alpha * w[0].w1 + (1 - alpha) * w[1].w1
92 // clang-format on
93 void getClosestPoints(const GJK::Simplex& simplex, Vec3s& w0, Vec3s& w1) {
94  GJK::SimplexV* const* vs = simplex.vertex;
95 
96  for (GJK::vertex_id_t i = 0; i < simplex.rank; ++i) {
97  assert(vs[i]->w.isApprox(vs[i]->w0 - vs[i]->w1));
98  }
99 
100  Project::ProjectResult projection;
101  switch (simplex.rank) {
102  case 1:
103  w0 = vs[0]->w0;
104  w1 = vs[0]->w1;
105  return;
106  case 2: {
107  const Vec3s &a = vs[0]->w, a0 = vs[0]->w0, a1 = vs[0]->w1, b = vs[1]->w,
108  b0 = vs[1]->w0, b1 = vs[1]->w1;
109  CoalScalar la, lb;
110  Vec3s N(b - a);
111  la = N.dot(-a);
112  if (la <= 0) {
113  assert(false);
114  w0 = a0;
115  w1 = a1;
116  } else {
117  lb = N.squaredNorm();
118  if (la > lb) {
119  assert(false);
120  w0 = b0;
121  w1 = b1;
122  } else {
123  lb = la / lb;
124  la = 1 - lb;
125  w0 = la * a0 + lb * b0;
126  w1 = la * a1 + lb * b1;
127  }
128  }
129  }
130  return;
131  case 3:
132  // TODO avoid the reprojection
133  projection = Project::projectTriangleOrigin(vs[0]->w, vs[1]->w, vs[2]->w);
134  break;
135  case 4: // We are in collision.
136  projection = Project::projectTetrahedraOrigin(vs[0]->w, vs[1]->w,
137  vs[2]->w, vs[3]->w);
138  break;
139  default:
140  COAL_THROW_PRETTY("The simplex rank must be in [ 1, 4 ]",
141  std::logic_error);
142  }
143  w0.setZero();
144  w1.setZero();
145  for (GJK::vertex_id_t i = 0; i < simplex.rank; ++i) {
146  w0 += projection.parameterization[i] * vs[i]->w0;
147  w1 += projection.parameterization[i] * vs[i]->w1;
148  }
149  return;
150 }
151 
157 template <bool Separated>
158 void inflate(const MinkowskiDiff& shape, const Vec3s& normal, Vec3s& w0,
159  Vec3s& w1) {
160 #ifndef NDEBUG
161  const CoalScalar dummy_precision =
162  Eigen::NumTraits<CoalScalar>::dummy_precision();
163  assert((normal.norm() - 1) < dummy_precision);
164 #endif
165 
166  const Eigen::Array<CoalScalar, 1, 2>& I(shape.swept_sphere_radius);
167  Eigen::Array<bool, 1, 2> inflate(I > 0);
168  if (!inflate.any()) return;
169 
170  if (inflate[0]) w0 += I[0] * normal;
171  if (inflate[1]) w1 -= I[1] * normal;
172 }
173 
174 } // namespace details
175 
177  Vec3s& w1, Vec3s& normal) const {
179  if ((w1 - w0).norm() > Eigen::NumTraits<CoalScalar>::dummy_precision()) {
180  normal = (w1 - w0).normalized();
181  } else {
182  normal = -this->ray.normalized();
183  }
184  details::inflate<true>(shape, normal, w0, w1);
185 }
186 
187 GJK::Status GJK::evaluate(const MinkowskiDiff& shape_, const Vec3s& guess,
188  const support_func_guess_t& supportHint) {
189  CoalScalar alpha = 0;
190  iterations = 0;
191  const CoalScalar swept_sphere_radius = shape_.swept_sphere_radius.sum();
192  const CoalScalar upper_bound = distance_upper_bound + swept_sphere_radius;
193 
194  free_v[0] = &store_v[0];
195  free_v[1] = &store_v[1];
196  free_v[2] = &store_v[2];
197  free_v[3] = &store_v[3];
198 
199  nfree = 4;
201  shape = &shape_;
202  distance = 0.0;
203  current = 0;
204  simplices[current].rank = 0;
205  support_hint = supportHint;
206 
207  CoalScalar rl = guess.norm();
208  if (rl < tolerance) {
209  ray = Vec3s(-1, 0, 0);
210  rl = 1;
211  } else
212  ray = guess;
213 
214  // Momentum
215  GJKVariant current_gjk_variant = gjk_variant;
216  Vec3s w = ray;
217  Vec3s dir = ray;
218  Vec3s y;
219  CoalScalar momentum;
220  bool normalize_support_direction = shape->normalize_support_direction;
221  do {
222  vertex_id_t next = (vertex_id_t)(1 - current);
223  Simplex& curr_simplex = simplices[current];
224  Simplex& next_simplex = simplices[next];
225 
226  // check A: when origin is near the existing simplex, stop
227  if (rl < tolerance) // mean origin is near the face of original simplex,
228  // return touch
229  {
230  // At this point, GJK has converged but we don't know if GJK is enough to
231  // recover penetration information.
232  // EPA needs to be run.
233  // Unless the Minkowski difference is degenerated, EPA will run fine even
234  // if the final simplex of GJK is not a tetrahedron.
235  assert(rl > 0);
236  status = Collision;
237  // GJK is not enough to recover the penetration depth, hence we ignore the
238  // swept-sphere radius for now.
239  // EPA needs to be run to recover the penetration depth.
240  distance = rl;
241  break;
242  }
243 
244  // Compute direction for support call
245  switch (current_gjk_variant) {
246  case DefaultGJK:
247  dir = ray;
248  break;
249 
251  // Normalize heuristic for collision pairs involving convex but not
252  // strictly-convex shapes This corresponds to most use cases.
253  if (normalize_support_direction) {
254  momentum =
255  (CoalScalar(iterations) + 2) / (CoalScalar(iterations) + 3);
256  y = momentum * ray + (1 - momentum) * w;
257  CoalScalar y_norm = y.norm();
258  // ray is the point of the Minkowski difference which currently the
259  // closest to the origin. Therefore, y.norm() > ray.norm() Hence, if
260  // check A above has not stopped the algorithm, we necessarily have
261  // y.norm() > tolerance. The following assert is just a safety check.
262  assert(y_norm > tolerance);
263  dir = momentum * dir / dir.norm() + (1 - momentum) * y / y_norm;
264  } else {
265  momentum =
266  (CoalScalar(iterations) + 1) / (CoalScalar(iterations) + 3);
267  y = momentum * ray + (1 - momentum) * w;
268  dir = momentum * dir + (1 - momentum) * y;
269  }
270  break;
271 
272  case PolyakAcceleration:
273  momentum = 1 / (CoalScalar(iterations) + 1);
274  dir = momentum * dir + (1 - momentum) * ray;
275  break;
276 
277  default:
278  COAL_THROW_PRETTY("Invalid momentum variant.", std::logic_error);
279  }
280 
281  // see below, ray points away from origin
282  appendVertex(curr_simplex, -dir, support_hint);
283 
284  // check removed (by ?): when the new support point is close to previous
285  // support points, stop (as the new simplex is degenerated)
286  w = curr_simplex.vertex[curr_simplex.rank - 1]->w;
287 
288  // check B: no collision if omega > 0
289  CoalScalar omega = dir.dot(w) / dir.norm();
290  if (omega > upper_bound) {
291  distance = omega - swept_sphere_radius;
293  break;
294  }
295 
296  // Check to remove acceleration
297  if (current_gjk_variant != DefaultGJK) {
298  CoalScalar frank_wolfe_duality_gap = 2 * ray.dot(ray - w);
299  if (frank_wolfe_duality_gap - tolerance <= 0) {
301  current_gjk_variant = DefaultGJK; // move back to classic GJK
303  continue; // continue to next iteration
304  }
305  }
306 
307  // check C: when the new support point is close to the sub-simplex where the
308  // ray point lies, stop (as the new simplex again is degenerated)
309  bool cv_check_passed = checkConvergence(w, rl, alpha, omega);
310  if (iterations > 0 && cv_check_passed) {
312  if (current_gjk_variant != DefaultGJK) {
313  current_gjk_variant = DefaultGJK; // move back to classic GJK
315  continue;
316  }
317  // At this point, GJK has converged and we know that rl > tolerance (see
318  // check above). Therefore, penetration information can always be
319  // recovered without running EPA.
320  distance = rl - swept_sphere_radius;
321  if (distance < tolerance) {
323  } else {
325  }
326  break;
327  }
328 
329  // This has been rewritten thanks to the excellent video:
330  // https://youtu.be/Qupqu1xe7Io
331  bool inside;
332  switch (curr_simplex.rank) {
333  case 1: // Only at the first iteration
334  assert(iterations == 0);
335  ray = w;
336  inside = false;
337  next_simplex.rank = 1;
338  next_simplex.vertex[0] = curr_simplex.vertex[0];
339  break;
340  case 2:
341  inside = projectLineOrigin(curr_simplex, next_simplex);
342  break;
343  case 3:
344  inside = projectTriangleOrigin(curr_simplex, next_simplex);
345  break;
346  case 4:
347  inside = projectTetrahedraOrigin(curr_simplex, next_simplex);
348  break;
349  default:
350  COAL_THROW_PRETTY("Invalid simplex rank", std::logic_error);
351  }
352  assert(nfree + next_simplex.rank == 4);
353  current = next;
354  rl = ray.norm();
355  if (inside || rl == 0) {
356  status = Collision;
357  // GJK is not enough to recover the penetration depth, hence we ignore the
358  // swept-sphere radius for now.
359  // EPA needs to be run to recover the penetration depth.
360  distance = rl;
361  break;
362  }
363 
365 
366  } while (status == NoCollision);
367 
369  assert(simplex->rank > 0 && simplex->rank < 5);
370  return status;
371 }
372 
373 bool GJK::checkConvergence(const Vec3s& w, const CoalScalar& rl,
374  CoalScalar& alpha, const CoalScalar& omega) const {
375  // x^* is the optimal solution (projection of origin onto the Minkowski
376  // difference).
377  // x^k is the current iterate (x^k = `ray` in the code).
378  // Each criterion provides a different guarantee on the distance to the
379  // optimal solution.
380  switch (convergence_criterion) {
381  case Default: {
382  // alpha is the distance to the best separating hyperplane found so far
383  alpha = std::max(alpha, omega);
384  // ||x^*|| - ||x^k|| <= diff
385  const CoalScalar diff = rl - alpha;
386  return ((diff - (tolerance + tolerance * rl)) <= 0);
387  } break;
388 
389  case DualityGap: {
390  // ||x^* - x^k||^2 <= diff
391  const CoalScalar diff = 2 * ray.dot(ray - w);
392  switch (convergence_criterion_type) {
393  case Absolute:
394  return ((diff - tolerance) <= 0);
395  break;
396  case Relative:
397  return (((diff / tolerance * rl) - tolerance * rl) <= 0);
398  break;
399  default:
400  COAL_THROW_PRETTY("Invalid convergence criterion type.",
401  std::logic_error);
402  }
403  } break;
404 
405  case Hybrid: {
406  // alpha is the distance to the best separating hyperplane found so far
407  alpha = std::max(alpha, omega);
408  // ||x^* - x^k||^2 <= diff
409  const CoalScalar diff = rl * rl - alpha * alpha;
410  switch (convergence_criterion_type) {
411  case Absolute:
412  return ((diff - tolerance) <= 0);
413  break;
414  case Relative:
415  return (((diff / tolerance * rl) - tolerance * rl) <= 0);
416  break;
417  default:
418  COAL_THROW_PRETTY("Invalid convergence criterion type.",
419  std::logic_error);
420  }
421  } break;
422 
423  default:
424  COAL_THROW_PRETTY("Invalid convergence criterion.", std::logic_error);
425  }
426 }
427 
428 inline void GJK::removeVertex(Simplex& simplex) {
430 }
431 
432 inline void GJK::appendVertex(Simplex& simplex, const Vec3s& v,
433  support_func_guess_t& hint) {
434  simplex.vertex[simplex.rank] = free_v[--nfree]; // set the memory
435  getSupport(v, *simplex.vertex[simplex.rank++], hint);
436 }
437 
439  Vec3s axis(Vec3s::Zero());
440  support_func_guess_t hint = support_func_guess_t::Zero();
441  switch (simplex->rank) {
442  case 1:
443  for (int i = 0; i < 3; ++i) {
444  axis[i] = 1;
445  appendVertex(*simplex, axis, hint);
446  if (encloseOrigin()) return true;
448  axis[i] = -1;
449  appendVertex(*simplex, -axis, hint);
450  if (encloseOrigin()) return true;
452  axis[i] = 0;
453  }
454  break;
455  case 2: {
456  Vec3s d = simplex->vertex[1]->w - simplex->vertex[0]->w;
457  for (int i = 0; i < 3; ++i) {
458  axis[i] = 1;
459  Vec3s p = d.cross(axis);
460  if (!p.isZero()) {
461  appendVertex(*simplex, p, hint);
462  if (encloseOrigin()) return true;
464  appendVertex(*simplex, -p, hint);
465  if (encloseOrigin()) return true;
467  }
468  axis[i] = 0;
469  }
470  } break;
471  case 3:
472  axis.noalias() =
473  (simplex->vertex[1]->w - simplex->vertex[0]->w)
474  .cross(simplex->vertex[2]->w - simplex->vertex[0]->w);
475  if (!axis.isZero()) {
476  appendVertex(*simplex, axis, hint);
477  if (encloseOrigin()) return true;
479  appendVertex(*simplex, -axis, hint);
480  if (encloseOrigin()) return true;
482  }
483  break;
484  case 4:
485  if (std::abs(triple(simplex->vertex[0]->w - simplex->vertex[3]->w,
486  simplex->vertex[1]->w - simplex->vertex[3]->w,
487  simplex->vertex[2]->w - simplex->vertex[3]->w)) > 0)
488  return true;
489  break;
490  }
491 
492  return false;
493 }
494 
495 inline void originToPoint(const GJK::Simplex& current, GJK::vertex_id_t a,
496  const Vec3s& A, GJK::Simplex& next, Vec3s& ray) {
497  // A is the closest to the origin
498  ray = A;
499  next.vertex[0] = current.vertex[a];
500  next.rank = 1;
501 }
502 
503 inline void originToSegment(const GJK::Simplex& current, GJK::vertex_id_t a,
504  GJK::vertex_id_t b, const Vec3s& A, const Vec3s& B,
505  const Vec3s& AB, const CoalScalar& ABdotAO,
506  GJK::Simplex& next, Vec3s& ray) {
507  // ray = - ( AB ^ AO ) ^ AB = (AB.B) A + (-AB.A) B
508  ray = AB.dot(B) * A + ABdotAO * B;
509 
510  next.vertex[0] = current.vertex[b];
511  next.vertex[1] = current.vertex[a];
512  next.rank = 2;
513 
514  // To ensure backward compatibility
515  ray /= AB.squaredNorm();
516 }
517 
518 inline bool originToTriangle(const GJK::Simplex& current, GJK::vertex_id_t a,
520  const Vec3s& ABC, const CoalScalar& ABCdotAO,
521  GJK::Simplex& next, Vec3s& ray) {
522  next.rank = 3;
523  next.vertex[2] = current.vertex[a];
524 
525  if (ABCdotAO == 0) {
526  next.vertex[0] = current.vertex[c];
527  next.vertex[1] = current.vertex[b];
528  ray.setZero();
529  return true;
530  }
531  if (ABCdotAO > 0) { // Above triangle
532  next.vertex[0] = current.vertex[c];
533  next.vertex[1] = current.vertex[b];
534  } else {
535  next.vertex[0] = current.vertex[b];
536  next.vertex[1] = current.vertex[c];
537  }
538 
539  // To ensure backward compatibility
540  ray = -ABCdotAO / ABC.squaredNorm() * ABC;
541  return false;
542 }
543 
544 bool GJK::projectLineOrigin(const Simplex& current, Simplex& next) {
545  const vertex_id_t a = 1, b = 0;
546  // A is the last point we added.
547  const Vec3s& A = current.vertex[a]->w;
548  const Vec3s& B = current.vertex[b]->w;
549 
550  const Vec3s AB = B - A;
551  const CoalScalar d = AB.dot(-A);
552  assert(d <= AB.squaredNorm());
553 
554  if (d == 0) {
555  // Two extremely unlikely cases:
556  // - AB is orthogonal to A: should never happen because it means the support
557  // function did not do any progress and GJK should have stopped.
558  // - A == origin
559  // In any case, A is the closest to the origin
560  originToPoint(current, a, A, next, ray);
561  free_v[nfree++] = current.vertex[b];
562  return A.isZero();
563  } else if (d < 0) {
564  // A is the closest to the origin
565  originToPoint(current, a, A, next, ray);
566  free_v[nfree++] = current.vertex[b];
567  } else
568  originToSegment(current, a, b, A, B, AB, d, next, ray);
569  return false;
570 }
571 
572 bool GJK::projectTriangleOrigin(const Simplex& current, Simplex& next) {
573  const vertex_id_t a = 2, b = 1, c = 0;
574  // A is the last point we added.
575  const Vec3s &A = current.vertex[a]->w, B = current.vertex[b]->w,
576  C = current.vertex[c]->w;
577 
578  const Vec3s AB = B - A, AC = C - A, ABC = AB.cross(AC);
579 
580  CoalScalar edgeAC2o = ABC.cross(AC).dot(-A);
581  if (edgeAC2o >= 0) {
582  CoalScalar towardsC = AC.dot(-A);
583  if (towardsC >= 0) { // Region 1
584  originToSegment(current, a, c, A, C, AC, towardsC, next, ray);
585  free_v[nfree++] = current.vertex[b];
586  } else { // Region 4 or 5
587  CoalScalar towardsB = AB.dot(-A);
588  if (towardsB < 0) { // Region 5
589  // A is the closest to the origin
590  originToPoint(current, a, A, next, ray);
591  free_v[nfree++] = current.vertex[b];
592  } else // Region 4
593  originToSegment(current, a, b, A, B, AB, towardsB, next, ray);
594  free_v[nfree++] = current.vertex[c];
595  }
596  } else {
597  CoalScalar edgeAB2o = AB.cross(ABC).dot(-A);
598  if (edgeAB2o >= 0) { // Region 4 or 5
599  CoalScalar towardsB = AB.dot(-A);
600  if (towardsB < 0) { // Region 5
601  // A is the closest to the origin
602  originToPoint(current, a, A, next, ray);
603  free_v[nfree++] = current.vertex[b];
604  } else // Region 4
605  originToSegment(current, a, b, A, B, AB, towardsB, next, ray);
606  free_v[nfree++] = current.vertex[c];
607  } else {
608  return originToTriangle(current, a, b, c, ABC, ABC.dot(-A), next, ray);
609  }
610  }
611  return false;
612 }
613 
614 bool GJK::projectTetrahedraOrigin(const Simplex& current, Simplex& next) {
615  // The code of this function was generated using doc/gjk.py
616  const vertex_id_t a = 3, b = 2, c = 1, d = 0;
617  const Vec3s& A(current.vertex[a]->w);
618  const Vec3s& B(current.vertex[b]->w);
619  const Vec3s& C(current.vertex[c]->w);
620  const Vec3s& D(current.vertex[d]->w);
621  const CoalScalar aa = A.squaredNorm();
622  const CoalScalar da = D.dot(A);
623  const CoalScalar db = D.dot(B);
624  const CoalScalar dc = D.dot(C);
625  const CoalScalar dd = D.dot(D);
626  const CoalScalar da_aa = da - aa;
627  const CoalScalar ca = C.dot(A);
628  const CoalScalar cb = C.dot(B);
629  const CoalScalar cc = C.dot(C);
630  const CoalScalar& cd = dc;
631  const CoalScalar ca_aa = ca - aa;
632  const CoalScalar ba = B.dot(A);
633  const CoalScalar bb = B.dot(B);
634  const CoalScalar& bc = cb;
635  const CoalScalar& bd = db;
636  const CoalScalar ba_aa = ba - aa;
637  const CoalScalar ba_ca = ba - ca;
638  const CoalScalar ca_da = ca - da;
639  const CoalScalar da_ba = da - ba;
640  const Vec3s a_cross_b = A.cross(B);
641  const Vec3s a_cross_c = A.cross(C);
642 
643  const CoalScalar dummy_precision(
645  COAL_UNUSED_VARIABLE(dummy_precision);
646 
647 #define REGION_INSIDE() \
648  ray.setZero(); \
649  next.vertex[0] = current.vertex[d]; \
650  next.vertex[1] = current.vertex[c]; \
651  next.vertex[2] = current.vertex[b]; \
652  next.vertex[3] = current.vertex[a]; \
653  next.rank = 4; \
654  return true;
655 
656  // clang-format off
657  if (ba_aa <= 0) { // if AB.AO >= 0 / a10
658  if (-D.dot(a_cross_b) <= 0) { // if ADB.AO >= 0 / a10.a3
659  if (ba * da_ba + bd * ba_aa - bb * da_aa <=
660  0) { // if (ADB ^ AB).AO >= 0 / a10.a3.a9
661  if (da_aa <= 0) { // if AD.AO >= 0 / a10.a3.a9.a12
662  assert(da * da_ba + dd * ba_aa - db * da_aa <=
663  dummy_precision); // (ADB ^ AD).AO >= 0 / a10.a3.a9.a12.a8
664  if (ba * ba_ca + bb * ca_aa - bc * ba_aa <=
665  0) { // if (ABC ^ AB).AO >= 0 / a10.a3.a9.a12.a8.a4
666  // Region ABC
667  originToTriangle(current, a, b, c, (B - A).cross(C - A),
668  -C.dot(a_cross_b), next, ray);
669  free_v[nfree++] = current.vertex[d];
670  } else { // not (ABC ^ AB).AO >= 0 / a10.a3.a9.a12.a8.!a4
671  // Region AB
672  originToSegment(current, a, b, A, B, B - A, -ba_aa, next, ray);
673  free_v[nfree++] = current.vertex[c];
674  free_v[nfree++] = current.vertex[d];
675  } // end of (ABC ^ AB).AO >= 0
676  } else { // not AD.AO >= 0 / a10.a3.a9.!a12
677  if (ba * ba_ca + bb * ca_aa - bc * ba_aa <=
678  0) { // if (ABC ^ AB).AO >= 0 / a10.a3.a9.!a12.a4
679  if (ca * ba_ca + cb * ca_aa - cc * ba_aa <=
680  0) { // if (ABC ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.a5
681  if (ca * ca_da + cc * da_aa - cd * ca_aa <=
682  0) { // if (ACD ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.a5.a6
683  // Region ACD
684  originToTriangle(current, a, c, d, (C - A).cross(D - A),
685  -D.dot(a_cross_c), next, ray);
686  free_v[nfree++] = current.vertex[b];
687  } else { // not (ACD ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.a5.!a6
688  // Region AC
689  originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray);
690  free_v[nfree++] = current.vertex[b];
691  free_v[nfree++] = current.vertex[d];
692  } // end of (ACD ^ AC).AO >= 0
693  } else { // not (ABC ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.!a5
694  // Region ABC
695  originToTriangle(current, a, b, c, (B - A).cross(C - A),
696  -C.dot(a_cross_b), next, ray);
697  free_v[nfree++] = current.vertex[d];
698  } // end of (ABC ^ AC).AO >= 0
699  } else { // not (ABC ^ AB).AO >= 0 / a10.a3.a9.!a12.!a4
700  // Region AB
701  originToSegment(current, a, b, A, B, B - A, -ba_aa, next, ray);
702  free_v[nfree++] = current.vertex[c];
703  free_v[nfree++] = current.vertex[d];
704  } // end of (ABC ^ AB).AO >= 0
705  } // end of AD.AO >= 0
706  } else { // not (ADB ^ AB).AO >= 0 / a10.a3.!a9
707  if (da * da_ba + dd * ba_aa - db * da_aa <=
708  0) { // if (ADB ^ AD).AO >= 0 / a10.a3.!a9.a8
709  // Region ADB
710  originToTriangle(current, a, d, b, (D - A).cross(B - A),
711  D.dot(a_cross_b), next, ray);
712  free_v[nfree++] = current.vertex[c];
713  } else { // not (ADB ^ AD).AO >= 0 / a10.a3.!a9.!a8
714  if (ca * ca_da + cc * da_aa - cd * ca_aa <=
715  0) { // if (ACD ^ AC).AO >= 0 / a10.a3.!a9.!a8.a6
716  if (da * ca_da + dc * da_aa - dd * ca_aa <=
717  0) { // if (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.a6.a7
718  // Region AD
719  originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray);
720  free_v[nfree++] = current.vertex[b];
721  free_v[nfree++] = current.vertex[c];
722  } else { // not (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.a6.!a7
723  // Region ACD
724  originToTriangle(current, a, c, d, (C - A).cross(D - A),
725  -D.dot(a_cross_c), next, ray);
726  free_v[nfree++] = current.vertex[b];
727  } // end of (ACD ^ AD).AO >= 0
728  } else { // not (ACD ^ AC).AO >= 0 / a10.a3.!a9.!a8.!a6
729  if (da * ca_da + dc * da_aa - dd * ca_aa <=
730  0) { // if (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.!a6.a7
731  // Region AD
732  originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray);
733  free_v[nfree++] = current.vertex[b];
734  free_v[nfree++] = current.vertex[c];
735  } else { // not (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.!a6.!a7
736  // Region AC
737  originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray);
738  free_v[nfree++] = current.vertex[b];
739  free_v[nfree++] = current.vertex[d];
740  } // end of (ACD ^ AD).AO >= 0
741  } // end of (ACD ^ AC).AO >= 0
742  } // end of (ADB ^ AD).AO >= 0
743  } // end of (ADB ^ AB).AO >= 0
744  } else { // not ADB.AO >= 0 / a10.!a3
745  if (C.dot(a_cross_b) <= 0) { // if ABC.AO >= 0 / a10.!a3.a1
746  if (ba * ba_ca + bb * ca_aa - bc * ba_aa <=
747  0) { // if (ABC ^ AB).AO >= 0 / a10.!a3.a1.a4
748  if (ca * ba_ca + cb * ca_aa - cc * ba_aa <=
749  0) { // if (ABC ^ AC).AO >= 0 / a10.!a3.a1.a4.a5
750  if (ca * ca_da + cc * da_aa - cd * ca_aa <=
751  0) { // if (ACD ^ AC).AO >= 0 / a10.!a3.a1.a4.a5.a6
752  // Region ACD
753  originToTriangle(current, a, c, d, (C - A).cross(D - A),
754  -D.dot(a_cross_c), next, ray);
755  free_v[nfree++] = current.vertex[b];
756  } else { // not (ACD ^ AC).AO >= 0 / a10.!a3.a1.a4.a5.!a6
757  // Region AC
758  originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray);
759  free_v[nfree++] = current.vertex[b];
760  free_v[nfree++] = current.vertex[d];
761  } // end of (ACD ^ AC).AO >= 0
762  } else { // not (ABC ^ AC).AO >= 0 / a10.!a3.a1.a4.!a5
763  // Region ABC
764  originToTriangle(current, a, b, c, (B - A).cross(C - A),
765  -C.dot(a_cross_b), next, ray);
766  free_v[nfree++] = current.vertex[d];
767  } // end of (ABC ^ AC).AO >= 0
768  } else { // not (ABC ^ AB).AO >= 0 / a10.!a3.a1.!a4
769  // Region AB
770  originToSegment(current, a, b, A, B, B - A, -ba_aa, next, ray);
771  free_v[nfree++] = current.vertex[c];
772  free_v[nfree++] = current.vertex[d];
773  } // end of (ABC ^ AB).AO >= 0
774  } else { // not ABC.AO >= 0 / a10.!a3.!a1
775  if (D.dot(a_cross_c) <= 0) { // if ACD.AO >= 0 / a10.!a3.!a1.a2
776  if (ca * ca_da + cc * da_aa - cd * ca_aa <=
777  0) { // if (ACD ^ AC).AO >= 0 / a10.!a3.!a1.a2.a6
778  if (da * ca_da + dc * da_aa - dd * ca_aa <=
779  0) { // if (ACD ^ AD).AO >= 0 / a10.!a3.!a1.a2.a6.a7
780  // Region AD
781  originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray);
782  free_v[nfree++] = current.vertex[b];
783  free_v[nfree++] = current.vertex[c];
784  } else { // not (ACD ^ AD).AO >= 0 / a10.!a3.!a1.a2.a6.!a7
785  // Region ACD
786  originToTriangle(current, a, c, d, (C - A).cross(D - A),
787  -D.dot(a_cross_c), next, ray);
788  free_v[nfree++] = current.vertex[b];
789  } // end of (ACD ^ AD).AO >= 0
790  } else { // not (ACD ^ AC).AO >= 0 / a10.!a3.!a1.a2.!a6
791  if (ca_aa <= 0) { // if AC.AO >= 0 / a10.!a3.!a1.a2.!a6.a11
792  // Region AC
793  originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray);
794  free_v[nfree++] = current.vertex[b];
795  free_v[nfree++] = current.vertex[d];
796  } else { // not AC.AO >= 0 / a10.!a3.!a1.a2.!a6.!a11
797  // Region AD
798  originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray);
799  free_v[nfree++] = current.vertex[b];
800  free_v[nfree++] = current.vertex[c];
801  } // end of AC.AO >= 0
802  } // end of (ACD ^ AC).AO >= 0
803  } else { // not ACD.AO >= 0 / a10.!a3.!a1.!a2
804  // Region Inside
805  REGION_INSIDE()
806  } // end of ACD.AO >= 0
807  } // end of ABC.AO >= 0
808  } // end of ADB.AO >= 0
809  } else { // not AB.AO >= 0 / !a10
810  if (ca_aa <= 0) { // if AC.AO >= 0 / !a10.a11
811  if (D.dot(a_cross_c) <= 0) { // if ACD.AO >= 0 / !a10.a11.a2
812  if (da_aa <= 0) { // if AD.AO >= 0 / !a10.a11.a2.a12
813  if (ca * ca_da + cc * da_aa - cd * ca_aa <=
814  0) { // if (ACD ^ AC).AO >= 0 / !a10.a11.a2.a12.a6
815  if (da * ca_da + dc * da_aa - dd * ca_aa <=
816  0) { // if (ACD ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.a7
817  if (da * da_ba + dd * ba_aa - db * da_aa <=
818  0) { // if (ADB ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.a7.a8
819  // Region ADB
820  originToTriangle(current, a, d, b, (D - A).cross(B - A),
821  D.dot(a_cross_b), next, ray);
822  free_v[nfree++] = current.vertex[c];
823  } else { // not (ADB ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.a7.!a8
824  // Region AD
825  originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray);
826  free_v[nfree++] = current.vertex[b];
827  free_v[nfree++] = current.vertex[c];
828  } // end of (ADB ^ AD).AO >= 0
829  } else { // not (ACD ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.!a7
830  // Region ACD
831  originToTriangle(current, a, c, d, (C - A).cross(D - A),
832  -D.dot(a_cross_c), next, ray);
833  free_v[nfree++] = current.vertex[b];
834  } // end of (ACD ^ AD).AO >= 0
835  } else { // not (ACD ^ AC).AO >= 0 / !a10.a11.a2.a12.!a6
836  assert(!(da * ca_da + dc * da_aa - dd * ca_aa <=
837  -dummy_precision)); // Not (ACD ^ AD).AO >= 0 /
838  // !a10.a11.a2.a12.!a6.!a7
839  if (ca * ba_ca + cb * ca_aa - cc * ba_aa <=
840  0) { // if (ABC ^ AC).AO >= 0 / !a10.a11.a2.a12.!a6.!a7.a5
841  // Region AC
842  originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray);
843  free_v[nfree++] = current.vertex[b];
844  free_v[nfree++] = current.vertex[d];
845  } else { // not (ABC ^ AC).AO >= 0 / !a10.a11.a2.a12.!a6.!a7.!a5
846  // Region ABC
847  originToTriangle(current, a, b, c, (B - A).cross(C - A),
848  -C.dot(a_cross_b), next, ray);
849  free_v[nfree++] = current.vertex[d];
850  } // end of (ABC ^ AC).AO >= 0
851  } // end of (ACD ^ AC).AO >= 0
852  } else { // not AD.AO >= 0 / !a10.a11.a2.!a12
853  if (ca * ba_ca + cb * ca_aa - cc * ba_aa <=
854  0) { // if (ABC ^ AC).AO >= 0 / !a10.a11.a2.!a12.a5
855  if (ca * ca_da + cc * da_aa - cd * ca_aa <=
856  0) { // if (ACD ^ AC).AO >= 0 / !a10.a11.a2.!a12.a5.a6
857  assert(!(da * ca_da + dc * da_aa - dd * ca_aa <=
858  -dummy_precision)); // Not (ACD ^ AD).AO >= 0 /
859  // !a10.a11.a2.!a12.a5.a6.!a7
860  // Region ACD
861  originToTriangle(current, a, c, d, (C - A).cross(D - A),
862  -D.dot(a_cross_c), next, ray);
863  free_v[nfree++] = current.vertex[b];
864  } else { // not (ACD ^ AC).AO >= 0 / !a10.a11.a2.!a12.a5.!a6
865  // Region AC
866  originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray);
867  free_v[nfree++] = current.vertex[b];
868  free_v[nfree++] = current.vertex[d];
869  } // end of (ACD ^ AC).AO >= 0
870  } else { // not (ABC ^ AC).AO >= 0 / !a10.a11.a2.!a12.!a5
871  if (C.dot(a_cross_b) <=
872  0) { // if ABC.AO >= 0 / !a10.a11.a2.!a12.!a5.a1
873  assert(ba * ba_ca + bb * ca_aa - bc * ba_aa <=
874  dummy_precision); // (ABC ^ AB).AO >= 0 /
875  // !a10.a11.a2.!a12.!a5.a1.a4
876  // Region ABC
877  originToTriangle(current, a, b, c, (B - A).cross(C - A),
878  -C.dot(a_cross_b), next, ray);
879  free_v[nfree++] = current.vertex[d];
880  } else { // not ABC.AO >= 0 / !a10.a11.a2.!a12.!a5.!a1
881  assert(!(da * ca_da + dc * da_aa - dd * ca_aa <=
882  -dummy_precision)); // Not (ACD ^ AD).AO >= 0 /
883  // !a10.a11.a2.!a12.!a5.!a1.!a7
884  // Region ACD
885  originToTriangle(current, a, c, d, (C - A).cross(D - A),
886  -D.dot(a_cross_c), next, ray);
887  free_v[nfree++] = current.vertex[b];
888  } // end of ABC.AO >= 0
889  } // end of (ABC ^ AC).AO >= 0
890  } // end of AD.AO >= 0
891  } else { // not ACD.AO >= 0 / !a10.a11.!a2
892  if (C.dot(a_cross_b) <= 0) { // if ABC.AO >= 0 / !a10.a11.!a2.a1
893  if (ca * ba_ca + cb * ca_aa - cc * ba_aa <=
894  0) { // if (ABC ^ AC).AO >= 0 / !a10.a11.!a2.a1.a5
895  // Region AC
896  originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray);
897  free_v[nfree++] = current.vertex[b];
898  free_v[nfree++] = current.vertex[d];
899  } else { // not (ABC ^ AC).AO >= 0 / !a10.a11.!a2.a1.!a5
900  assert(ba * ba_ca + bb * ca_aa - bc * ba_aa <=
901  dummy_precision); // (ABC ^ AB).AO >= 0 /
902  // !a10.a11.!a2.a1.!a5.a4
903  // Region ABC
904  originToTriangle(current, a, b, c, (B - A).cross(C - A),
905  -C.dot(a_cross_b), next, ray);
906  free_v[nfree++] = current.vertex[d];
907  } // end of (ABC ^ AC).AO >= 0
908  } else { // not ABC.AO >= 0 / !a10.a11.!a2.!a1
909  if (-D.dot(a_cross_b) <= 0) { // if ADB.AO >= 0 / !a10.a11.!a2.!a1.a3
910  if (da * da_ba + dd * ba_aa - db * da_aa <=
911  0) { // if (ADB ^ AD).AO >= 0 / !a10.a11.!a2.!a1.a3.a8
912  // Region ADB
913  originToTriangle(current, a, d, b, (D - A).cross(B - A),
914  D.dot(a_cross_b), next, ray);
915  free_v[nfree++] = current.vertex[c];
916  } else { // not (ADB ^ AD).AO >= 0 / !a10.a11.!a2.!a1.a3.!a8
917  // Region AD
918  originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray);
919  free_v[nfree++] = current.vertex[b];
920  free_v[nfree++] = current.vertex[c];
921  } // end of (ADB ^ AD).AO >= 0
922  } else { // not ADB.AO >= 0 / !a10.a11.!a2.!a1.!a3
923  // Region Inside
924  REGION_INSIDE()
925  } // end of ADB.AO >= 0
926  } // end of ABC.AO >= 0
927  } // end of ACD.AO >= 0
928  } else { // not AC.AO >= 0 / !a10.!a11
929  if (da_aa <= 0) { // if AD.AO >= 0 / !a10.!a11.a12
930  if (-D.dot(a_cross_b) <= 0) { // if ADB.AO >= 0 / !a10.!a11.a12.a3
931  if (da * ca_da + dc * da_aa - dd * ca_aa <=
932  0) { // if (ACD ^ AD).AO >= 0 / !a10.!a11.a12.a3.a7
933  if (da * da_ba + dd * ba_aa - db * da_aa <=
934  0) { // if (ADB ^ AD).AO >= 0 / !a10.!a11.a12.a3.a7.a8
935  assert(!(ba * da_ba + bd * ba_aa - bb * da_aa <=
936  -dummy_precision)); // Not (ADB ^ AB).AO >= 0 /
937  // !a10.!a11.a12.a3.a7.a8.!a9
938  // Region ADB
939  originToTriangle(current, a, d, b, (D - A).cross(B - A),
940  D.dot(a_cross_b), next, ray);
941  free_v[nfree++] = current.vertex[c];
942  } else { // not (ADB ^ AD).AO >= 0 / !a10.!a11.a12.a3.a7.!a8
943  // Region AD
944  originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray);
945  free_v[nfree++] = current.vertex[b];
946  free_v[nfree++] = current.vertex[c];
947  } // end of (ADB ^ AD).AO >= 0
948  } else { // not (ACD ^ AD).AO >= 0 / !a10.!a11.a12.a3.!a7
949  if (D.dot(a_cross_c) <=
950  0) { // if ACD.AO >= 0 / !a10.!a11.a12.a3.!a7.a2
951  assert(ca * ca_da + cc * da_aa - cd * ca_aa <=
952  dummy_precision); // (ACD ^ AC).AO >= 0 /
953  // !a10.!a11.a12.a3.!a7.a2.a6
954  // Region ACD
955  originToTriangle(current, a, c, d, (C - A).cross(D - A),
956  -D.dot(a_cross_c), next, ray);
957  free_v[nfree++] = current.vertex[b];
958  } else { // not ACD.AO >= 0 / !a10.!a11.a12.a3.!a7.!a2
959  if (C.dot(a_cross_b) <=
960  0) { // if ABC.AO >= 0 / !a10.!a11.a12.a3.!a7.!a2.a1
961  assert(!(ba * ba_ca + bb * ca_aa - bc * ba_aa <=
962  -dummy_precision)); // Not (ABC ^ AB).AO >= 0 /
963  // !a10.!a11.a12.a3.!a7.!a2.a1.!a4
964  // Region ADB
965  originToTriangle(current, a, d, b, (D - A).cross(B - A),
966  D.dot(a_cross_b), next, ray);
967  free_v[nfree++] = current.vertex[c];
968  } else { // not ABC.AO >= 0 / !a10.!a11.a12.a3.!a7.!a2.!a1
969  // Region ADB
970  originToTriangle(current, a, d, b, (D - A).cross(B - A),
971  D.dot(a_cross_b), next, ray);
972  free_v[nfree++] = current.vertex[c];
973  } // end of ABC.AO >= 0
974  } // end of ACD.AO >= 0
975  } // end of (ACD ^ AD).AO >= 0
976  } else { // not ADB.AO >= 0 / !a10.!a11.a12.!a3
977  if (D.dot(a_cross_c) <= 0) { // if ACD.AO >= 0 / !a10.!a11.a12.!a3.a2
978  if (da * ca_da + dc * da_aa - dd * ca_aa <=
979  0) { // if (ACD ^ AD).AO >= 0 / !a10.!a11.a12.!a3.a2.a7
980  // Region AD
981  originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray);
982  free_v[nfree++] = current.vertex[b];
983  free_v[nfree++] = current.vertex[c];
984  } else { // not (ACD ^ AD).AO >= 0 / !a10.!a11.a12.!a3.a2.!a7
985  assert(ca * ca_da + cc * da_aa - cd * ca_aa <=
986  dummy_precision); // (ACD ^ AC).AO >= 0 /
987  // !a10.!a11.a12.!a3.a2.!a7.a6
988  // Region ACD
989  originToTriangle(current, a, c, d, (C - A).cross(D - A),
990  -D.dot(a_cross_c), next, ray);
991  free_v[nfree++] = current.vertex[b];
992  } // end of (ACD ^ AD).AO >= 0
993  } else { // not ACD.AO >= 0 / !a10.!a11.a12.!a3.!a2
994  // Region Inside
995  REGION_INSIDE()
996  } // end of ACD.AO >= 0
997  } // end of ADB.AO >= 0
998  } else { // not AD.AO >= 0 / !a10.!a11.!a12
999  // Region A
1000  originToPoint(current, a, A, next, ray);
1001  free_v[nfree++] = current.vertex[b];
1002  free_v[nfree++] = current.vertex[c];
1003  free_v[nfree++] = current.vertex[d];
1004  } // end of AD.AO >= 0
1005  } // end of AC.AO >= 0
1006  } // end of AB.AO >= 0
1007  // clang-format on
1008 
1009 #undef REGION_INSIDE
1010  return false;
1011 }
1012 
1014 
1015 void EPA::reset(size_t max_iterations_, CoalScalar tolerance_) {
1016  max_iterations = max_iterations_;
1017  tolerance = tolerance_;
1018  // EPA creates only 2 faces and 1 vertex per iteration.
1019  // (+ the 4 (or 8 in the future) faces at the beginning
1020  // + the 4 vertices (or 6 in the future) at the beginning)
1021  sv_store.resize(max_iterations + 4);
1022  fc_store.resize(2 * max_iterations + 4);
1023  status = DidNotRun;
1024  normal.setZero();
1025  support_hint.setZero();
1026  depth = 0;
1027  closest_face = nullptr;
1028  result.reset();
1029  hull.reset();
1030  num_vertices = 0;
1031  stock.reset();
1032  // The stock is initialized with the faces in reverse order so that the
1033  // hull and the stock do not overlap (the stock will shring as the hull will
1034  // grow).
1035  for (size_t i = 0; i < fc_store.size(); ++i)
1036  stock.append(&fc_store[fc_store.size() - i - 1]);
1037  iterations = 0;
1038 }
1039 
1041  const SimplexVertex& b, CoalScalar& dist) {
1042  Vec3s ab = b.w - a.w;
1043  Vec3s n_ab = ab.cross(face->n);
1044  CoalScalar a_dot_nab = a.w.dot(n_ab);
1045 
1046  if (a_dot_nab < 0) // the origin is on the outside part of ab
1047  {
1048  // following is similar to projectOrigin for two points
1049  // however, as we dont need to compute the parameterization, dont need to
1050  // compute 0 or 1
1051  CoalScalar a_dot_ab = a.w.dot(ab);
1052  CoalScalar b_dot_ab = b.w.dot(ab);
1053 
1054  if (a_dot_ab > 0)
1055  dist = a.w.norm();
1056  else if (b_dot_ab < 0)
1057  dist = b.w.norm();
1058  else {
1059  dist = std::sqrt(std::max(
1060  a.w.squaredNorm() - a_dot_ab * a_dot_ab / ab.squaredNorm(), 0.));
1061  }
1062 
1063  return true;
1064  }
1065 
1066  return false;
1067 }
1068 
1069 EPA::SimplexFace* EPA::newFace(size_t id_a, size_t id_b, size_t id_c,
1070  bool force) {
1071  if (stock.root != nullptr) {
1072  SimplexFace* face = stock.root;
1073  stock.remove(face);
1074  hull.append(face);
1075  face->pass = 0;
1076  face->vertex_id[0] = id_a;
1077  face->vertex_id[1] = id_b;
1078  face->vertex_id[2] = id_c;
1079  const SimplexVertex& a = sv_store[id_a];
1080  const SimplexVertex& b = sv_store[id_b];
1081  const SimplexVertex& c = sv_store[id_c];
1082  face->n = (b.w - a.w).cross(c.w - a.w);
1083 
1084  if (face->n.norm() > Eigen::NumTraits<CoalScalar>::epsilon()) {
1085  face->n.normalize();
1086 
1087  // If the origin projects outside the face, skip it in the
1088  // `findClosestFace` method.
1089  // The origin always projects inside the closest face.
1090  CoalScalar a_dot_nab = a.w.dot((b.w - a.w).cross(face->n));
1091  CoalScalar b_dot_nbc = b.w.dot((c.w - b.w).cross(face->n));
1092  CoalScalar c_dot_nca = c.w.dot((a.w - c.w).cross(face->n));
1093  if (a_dot_nab >= -tolerance && //
1094  b_dot_nbc >= -tolerance && //
1095  c_dot_nca >= -tolerance) {
1096  face->d = a.w.dot(face->n);
1097  face->ignore = false;
1098  } else {
1099  // We will never check this face, so we don't care about
1100  // its true distance to the origin.
1101  face->d = std::numeric_limits<CoalScalar>::max();
1102  face->ignore = true;
1103  }
1104 
1105  // For the initialization of EPA, we need to force the addition of the
1106  // face. This is because the origin can lie outside the initial
1107  // tetrahedron. This is expected. GJK can converge in two different ways:
1108  // either by enclosing the origin with a simplex, or by converging
1109  // sufficiently close to the origin.
1110  // The thing is, "sufficiently close to the origin" depends on the
1111  // tolerance of GJK. So in this case, GJK **cannot** guarantee that the
1112  // shapes are indeed in collision. If it turns out they are not in
1113  // collision, the origin will lie outside of the Minkowski difference and
1114  // thus outside the initial tetrahedron. But EPA is ultimately a
1115  // projection algorithm, so it will work fine!
1116  //
1117  // Actually, the `NonConvex` status is badly named. There should not be
1118  // such a status! Again, if the origin lies outside the Minkowski
1119  // difference, EPA will work fine, and will find the right (signed)
1120  // distance between the shapes as well as the right normal. This is a
1121  // very nice mathematical property, making GJK + EPA a **very** robust set
1122  // of algorithms. :)
1123  // TODO(louis): remove the `NonConvex` status.
1124  if (face->d >= -tolerance || force)
1125  return face;
1126  else
1127  status = NonConvex;
1128  } else
1129  status = Degenerated;
1130 
1131  hull.remove(face);
1132  stock.append(face);
1133  return nullptr;
1134  }
1135 
1136  assert(hull.count >= fc_store.size() && "EPA: should not be out of faces.");
1137  status = OutOfFaces;
1138  return nullptr;
1139 }
1140 
1143  SimplexFace* minf = hull.root;
1144  CoalScalar mind = std::numeric_limits<CoalScalar>::max();
1145  for (SimplexFace* f = minf; f; f = f->next_face) {
1146  if (f->ignore) continue;
1147  CoalScalar sqd = f->d * f->d;
1148  if (sqd < mind) {
1149  minf = f;
1150  mind = sqd;
1151  }
1152  }
1153  assert(minf && !(minf->ignore) && "EPA: minf should not be flagged ignored.");
1154  return minf;
1155 }
1156 
1158  GJK::Simplex& simplex = *gjk.getSimplex();
1159  support_hint = gjk.support_hint;
1160 
1161  // TODO(louis): we might want to start with a hexahedron if the
1162  // simplex given by GJK is of rank <= 3.
1163  bool enclosed_origin = gjk.encloseOrigin();
1164  if ((simplex.rank > 1) && enclosed_origin) {
1165  assert(simplex.rank == 4 &&
1166  "When starting EPA, simplex should be of rank 4.");
1167  while (hull.root) {
1168  SimplexFace* f = hull.root;
1169  hull.remove(f);
1170  stock.append(f);
1171  }
1172  assert(hull.count == 0);
1173  assert(stock.count == fc_store.size());
1174 
1175  status = Valid;
1176  num_vertices = 0;
1177 
1178  // Make sure the tetrahedron has its normals pointing outside.
1179  if ((simplex.vertex[0]->w - simplex.vertex[3]->w)
1180  .dot((simplex.vertex[1]->w - simplex.vertex[3]->w)
1181  .cross(simplex.vertex[2]->w - simplex.vertex[3]->w)) < 0) {
1182  SimplexVertex* tmp = simplex.vertex[0];
1183  simplex.vertex[0] = simplex.vertex[1];
1184  simplex.vertex[1] = tmp;
1185  }
1186 
1187  // Add the 4 vertices to sv_store
1188  for (size_t i = 0; i < 4; ++i) {
1189  sv_store[num_vertices++] = *simplex.vertex[i];
1190  }
1191 
1192  SimplexFace* tetrahedron[] = {newFace(0, 1, 2, true), //
1193  newFace(1, 0, 3, true), //
1194  newFace(2, 1, 3, true), //
1195  newFace(0, 2, 3, true)};
1196 
1197  if (hull.count == 4) {
1198  // set the face connectivity
1199  bind(tetrahedron[0], 0, tetrahedron[1], 0);
1200  bind(tetrahedron[0], 1, tetrahedron[2], 0);
1201  bind(tetrahedron[0], 2, tetrahedron[3], 0);
1202  bind(tetrahedron[1], 1, tetrahedron[3], 2);
1203  bind(tetrahedron[1], 2, tetrahedron[2], 1);
1204  bind(tetrahedron[2], 2, tetrahedron[3], 1);
1205 
1206  closest_face =
1207  findClosestFace(); // find the best face (the face with the
1208  // minimum distance to origin) to split
1209  SimplexFace outer = *closest_face;
1210 
1211  status = Valid;
1212  iterations = 0;
1213  size_t pass = 0;
1214  for (; iterations < max_iterations; ++iterations) {
1215  if (num_vertices >= sv_store.size()) {
1217  break;
1218  }
1219 
1220  // Step 1: find the support point in the direction of the closest_face
1221  // normal.
1222  // --------------------------------------------------------------------------
1223  SimplexHorizon horizon;
1225  bool valid = true;
1226  closest_face->pass = ++pass;
1227  // At the moment, SimplexF.n is always normalized. This could be revised
1228  // in the future...
1229  gjk.getSupport(closest_face->n, w, support_hint);
1230 
1231  // Step 2: check for convergence.
1232  // ------------------------------
1233  // Preambule to understand the convergence criterion of EPA:
1234  // the support we just added is in the direction of the normal of
1235  // the closest_face. Therefore, the support point will **always**
1236  // lie "after" the closest_face, i.e closest_face.n.dot(w.w) > 0.
1237  if (iterations > 0) {
1238  assert(closest_face->n.dot(w.w) > -tolerance &&
1239  "The support is not in the right direction.");
1240  }
1241  //
1242  // 1) First check: `fdist` (see below) is an upper bound of how much
1243  // more penetration depth we can expect to "gain" by adding `w` to EPA's
1244  // polytope. This first check, as any convergence check, should be both
1245  // absolute and relative. This allows to adapt the tolerance to the
1246  // scale of the objects.
1247  const SimplexVertex& vf1 = sv_store[closest_face->vertex_id[0]];
1248  const SimplexVertex& vf2 = sv_store[closest_face->vertex_id[1]];
1249  const SimplexVertex& vf3 = sv_store[closest_face->vertex_id[2]];
1250  CoalScalar fdist = closest_face->n.dot(w.w - vf1.w);
1251  CoalScalar wnorm = w.w.norm();
1252  // TODO(louis): we might want to use tol_abs and tol_rel; this might
1253  // obfuscate the code for the user though.
1254  if (fdist <= tolerance + tolerance * wnorm) {
1256  break;
1257  }
1258  // 2) Second check: the expand function **assumes** that the support we
1259  // just computed is not a vertex of the face. We make sure that this
1260  // is the case:
1261  // TODO(louis): should we use squaredNorm everywhere instead of norm?
1262  if ((w.w - vf1.w).norm() <= tolerance + tolerance * wnorm ||
1263  (w.w - vf2.w).norm() <= tolerance + tolerance * wnorm ||
1264  (w.w - vf3.w).norm() <= tolerance + tolerance * wnorm) {
1266  break;
1267  }
1268 
1269  // Step 3: expand the polytope
1270  // ---------------------------
1271  for (size_t j = 0; (j < 3) && valid; ++j)
1272  valid &= expand(pass, w, closest_face->adjacent_faces[j],
1273  closest_face->adjacent_edge[j], horizon);
1274 
1275  if (!valid || horizon.num_faces < 3) {
1276  // The status has already been set by the expand function.
1277  assert(!(status & Valid));
1278  break;
1279  }
1280  // need to add the edge connectivity between first and last faces
1281  bind(horizon.first_face, 2, horizon.current_face, 1);
1285  outer = *closest_face;
1286  }
1287 
1289  normal = outer.n;
1290  depth = outer.d + gjk.shape->swept_sphere_radius.sum();
1291  result.rank = 3;
1292  result.vertex[0] = &sv_store[outer.vertex_id[0]];
1293  result.vertex[1] = &sv_store[outer.vertex_id[1]];
1294  result.vertex[2] = &sv_store[outer.vertex_id[2]];
1295  return status;
1296  }
1297  assert(false && "The tetrahedron with which EPA started is degenerated.");
1298  }
1299 
1300  // FallBack when the simplex given by GJK is of rank 1.
1301  // Since the simplex only contains support points which convex
1302  // combination describe the origin, the point in the simplex is actually
1303  // the origin.
1304  status = FallBack;
1305  // TODO: define a better normal
1306  assert(simplex.rank == 1 && simplex.vertex[0]->w.isZero(gjk.getTolerance()));
1307  normal = -guess;
1308  CoalScalar nl = normal.norm();
1309  if (nl > 0)
1310  normal /= nl;
1311  else
1312  normal = Vec3s(1, 0, 0);
1313  depth = 0;
1314  result.rank = 1;
1315  result.vertex[0] = simplex.vertex[0];
1316  return status;
1317 }
1318 
1319 // Use this function to debug `EPA::expand` if needed.
1320 // void EPA::PrintExpandLooping(const SimplexFace* f, const SimplexVertex& w) {
1321 // std::cout << "Vertices:\n";
1322 // for (size_t i = 0; i < num_vertices; ++i) {
1323 // std::cout << "[";
1324 // std::cout << sv_store[i].w(0) << ", ";
1325 // std::cout << sv_store[i].w(1) << ", ";
1326 // std::cout << sv_store[i].w(2) << "]\n";
1327 // }
1328 // //
1329 // std::cout << "\nTriangles:\n";
1330 // SimplexFace* face = hull.root;
1331 // for (size_t i = 0; i < hull.count; ++i) {
1332 // std::cout << "[";
1333 // std::cout << face->vertex_id[0] << ", ";
1334 // std::cout << face->vertex_id[1] << ", ";
1335 // std::cout << face->vertex_id[2] << "]\n";
1336 // face = face->next_face;
1337 // }
1338 // //
1339 // std::cout << "\nNormals:\n";
1340 // face = hull.root;
1341 // for (size_t i = 0; i < hull.count; ++i) {
1342 // std::cout << "[";
1343 // std::cout << face->n(0) << ", ";
1344 // std::cout << face->n(1) << ", ";
1345 // std::cout << face->n(2) << "]\n";
1346 // face = face->next_face;
1347 // }
1348 // //
1349 // std::cout << "\nClosest face:\n";
1350 // face = hull.root;
1351 // for (size_t i = 0; i < hull.count; ++i) {
1352 // if (face == closest_face) {
1353 // std::cout << i << "\n";
1354 // }
1355 // face = face->next_face;
1356 // }
1357 // std::cout << "\nSupport point:\n";
1358 // std::cout << "[" << w.w(0) << ", " << w.w(1) << ", " << w.w(2) << "]\n";
1359 // }
1360 
1362 bool EPA::expand(size_t pass, const SimplexVertex& w, SimplexFace* f, size_t e,
1363  SimplexHorizon& horizon) {
1364  static const size_t nexti[] = {1, 2, 0};
1365  static const size_t previ[] = {2, 0, 1};
1366  const size_t id_w =
1367  num_vertices - 1; // w is always the last vertex added to sv_store
1368 
1369  // Check if we loop through expand indefinitely.
1370  if (f->pass == pass) {
1371  // Uncomment the following line and the associated EPA method
1372  // to debug the infinite loop if needed.
1373  // EPAPrintExpandLooping(this, f);
1374  assert(f != closest_face && "EPA is looping indefinitely.");
1375  status = InvalidHull;
1376  return false;
1377  }
1378 
1379  const size_t e1 = nexti[e];
1380 
1381  // Preambule: when expanding the polytope, the `closest_face` is always
1382  // deleted. This is handled in EPA::evaluate after calling the expand
1383  // function. This function handles how the neighboring face `f` of the
1384  // `closest_face` is connected to the new support point. (Note: because
1385  // `expand` is recursive, `f` can also denote a face of a face of the
1386  // `closest_face`, and so on. But the reasoning is the same.)
1387  //
1388  // EPA can handle `f` in two ways, depending on where the new support point
1389  // is located:
1390  // 1) If it is "below" `f`, then `f` is preserved. A new face is created
1391  // and connects to the edge `e` of `f`. This new face is made of the
1392  // two points of the edge `e` of `f` and the new support point `w`.
1393  // Geometrically, this corresponds to the case where the projection of
1394  // the origin on the `closest_face` is **inside** the triangle defined by
1395  // the `closest_face`.
1396  // 2) If it is "above" `f`, then `f` has to be deleted, simply because the
1397  // edge `e` of `f` is not part of the convex hull anymore.
1398  // The two faces adjacent to `f` are thus expanded following
1399  // either 1) or 2).
1400  // Geometrically, this corresponds to the case where the projection of
1401  // the origin on the `closest_face` is on an edge of the triangle defined
1402  // by the `closest_face`. The projection of the origin cannot lie on a
1403  // vertex of the `closest_face` because EPA should have exited before
1404  // reaching this point.
1405  //
1406  // The following checks for these two cases.
1407  // This check is however subject to numerical precision and due to the
1408  // recursive nature of `expand`, it is safer to go through the first case.
1409  // This is because `expand` can potentially loop indefinitly if the
1410  // Minkowski difference is very flat (hence the check above).
1411  const CoalScalar dummy_precision(
1412  3 * std::sqrt(std::numeric_limits<CoalScalar>::epsilon()));
1413  const SimplexVertex& vf = sv_store[f->vertex_id[e]];
1414  if (f->n.dot(w.w - vf.w) < dummy_precision) {
1415  // case 1: the support point is "below" `f`.
1416  SimplexFace* new_face = newFace(f->vertex_id[e1], f->vertex_id[e], id_w);
1417  if (new_face != nullptr) {
1418  // add face-face connectivity
1419  bind(new_face, 0, f, e);
1420 
1421  // if there is last face in the horizon, then need to add another
1422  // connectivity, i.e. the edge connecting the current new add edge and the
1423  // last new add edge. This does not finish all the connectivities because
1424  // the final face need to connect with the first face, this will be
1425  // handled in the evaluate function. Notice the face is anti-clockwise, so
1426  // the edges are 0 (bottom), 1 (right), 2 (left)
1427  if (horizon.current_face != nullptr) {
1428  bind(new_face, 2, horizon.current_face, 1);
1429  } else {
1430  horizon.first_face = new_face;
1431  }
1432 
1433  horizon.current_face = new_face;
1434  ++horizon.num_faces;
1435  return true;
1436  }
1437  return false;
1438  }
1439 
1440  // case 2: the support point is "above" `f`.
1441  const size_t e2 = previ[e];
1442  f->pass = pass;
1443  if (expand(pass, w, f->adjacent_faces[e1], f->adjacent_edge[e1], horizon) &&
1444  expand(pass, w, f->adjacent_faces[e2], f->adjacent_edge[e2], horizon)) {
1445  hull.remove(f);
1446  stock.append(f);
1447  return true;
1448  }
1449  return false;
1450 }
1451 
1453  Vec3s& w1, Vec3s& normal) const {
1455  if ((w0 - w1).norm() > Eigen::NumTraits<CoalScalar>::dummy_precision()) {
1456  if (this->depth >= 0) {
1457  // The shapes are in collision.
1458  normal = (w0 - w1).normalized();
1459  } else {
1460  // The shapes are not in collision.
1461  normal = (w1 - w0).normalized();
1462  }
1463  } else {
1464  normal = this->normal;
1465  }
1466  details::inflate<false>(shape, normal, w0, w1);
1467 }
1468 
1469 } // namespace details
1470 
1473  return;
1474  }
1475 
1477  this->support_warm_starts.indices.reserve(
1479 
1480  Vec3s axiis(0, 0, 0);
1481  details::ShapeSupportData support_data;
1482  int support_hint = 0;
1483  for (int i = 0; i < 3; ++i) {
1484  axiis(i) = 1;
1485  {
1486  Vec3s support;
1487  coal::details::getShapeSupport<false>(this, axiis, support, support_hint,
1488  support_data);
1489  this->support_warm_starts.points.emplace_back(support);
1490  this->support_warm_starts.indices.emplace_back(support_hint);
1491  }
1492 
1493  axiis(i) = -1;
1494  {
1495  Vec3s support;
1496  coal::details::getShapeSupport<false>(this, axiis, support, support_hint,
1497  support_data);
1498  this->support_warm_starts.points.emplace_back(support);
1499  this->support_warm_starts.indices.emplace_back(support_hint);
1500  }
1501 
1502  axiis(i) = 0;
1503  }
1504 
1505  std::array<Vec3s, 4> eis = {Vec3s(1, 1, 1), //
1506  Vec3s(-1, 1, 1), //
1507  Vec3s(-1, -1, 1), //
1508  Vec3s(1, -1, 1)};
1509 
1510  for (size_t ei_index = 0; ei_index < 4; ++ei_index) {
1511  {
1512  Vec3s support;
1513  coal::details::getShapeSupport<false>(this, eis[ei_index], support,
1514  support_hint, support_data);
1515  this->support_warm_starts.points.emplace_back(support);
1516  this->support_warm_starts.indices.emplace_back(support_hint);
1517  }
1518 
1519  {
1520  Vec3s support;
1521  coal::details::getShapeSupport<false>(this, -eis[ei_index], support,
1522  support_hint, support_data);
1523  this->support_warm_starts.points.emplace_back(support);
1524  this->support_warm_starts.indices.emplace_back(support_hint);
1525  }
1526  }
1527 
1528  if (this->support_warm_starts.points.size() !=
1530  this->support_warm_starts.indices.size() !=
1532  COAL_THROW_PRETTY("Wrong number of support warm starts.",
1533  std::runtime_error);
1534  }
1535 }
1536 
1537 } // namespace coal
coal::details::GJK::getWitnessPointsAndNormal
void getWitnessPointsAndNormal(const MinkowskiDiff &shape, Vec3s &w0, Vec3s &w1, Vec3s &normal) const
Definition: src/narrowphase/gjk.cpp:176
coal::details::EPA::SimplexHorizon::current_face
SimplexFace * current_face
Definition: coal/narrowphase/gjk.h:322
coal::details::EPA::Status
Status
Definition: coal/narrowphase/gjk.h:329
coal::details::EPA::NonConvex
@ NonConvex
Definition: coal/narrowphase/gjk.h:335
coal::details::EPA::SimplexFace::next_face
SimplexFace * next_face
Definition: coal/narrowphase/gjk.h:268
coal::details::EPA::SimplexFaceList::count
size_t count
Definition: coal/narrowphase/gjk.h:283
coal::details::EPA::SimplexFaceList::reset
void reset()
Definition: coal/narrowphase/gjk.h:286
coal::Vec3s
Eigen::Matrix< CoalScalar, 3, 1 > Vec3s
Definition: coal/data_types.h:77
coal::details::EPA::SimplexFace::ignore
bool ignore
Definition: coal/narrowphase/gjk.h:263
coal::details::GJK::Failed
@ Failed
Definition: coal/narrowphase/gjk.h:96
coal::details::EPA::fc_store
std::vector< SimplexFace > fc_store
Definition: coal/narrowphase/gjk.h:357
coal::details::EPA::stock
SimplexFaceList stock
Definition: coal/narrowphase/gjk.h:358
intersect.h
coal::details::EPA::num_vertices
size_t num_vertices
Definition: coal/narrowphase/gjk.h:359
coal::Hybrid
@ Hybrid
Definition: coal/data_types.h:104
coal::details::MinkowskiDiff::normalize_support_direction
bool normalize_support_direction
Wether or not to use the normalize heuristic in the GJK Nesterov acceleration. This setting is only a...
Definition: coal/narrowphase/minkowski_difference.h:79
coal::details::GJK::Simplex::reset
void reset()
Definition: coal/narrowphase/gjk.h:79
coal::details::details::getClosestPoints
void getClosestPoints(const GJK::Simplex &simplex, Vec3s &w0, Vec3s &w1)
Definition: src/narrowphase/gjk.cpp:93
coal::details::EPA::Failed
@ Failed
Definition: coal/narrowphase/gjk.h:331
coal::details::GJK::ray
Vec3s ray
Definition: coal/narrowphase/gjk.h:111
coal::details::GJK::shape
MinkowskiDiff const * shape
Definition: coal/narrowphase/gjk.h:110
coal::details::ShapeSupportData
Stores temporary data for the computation of support points.
Definition: coal/narrowphase/support_functions.h:80
coal::details::GJK::iterations_momentum_stop
size_t iterations_momentum_stop
Definition: coal/narrowphase/gjk.h:133
coal::details::MinkowskiDiff
Minkowski difference class of two shapes.
Definition: coal/narrowphase/minkowski_difference.h:53
coal::details::GJK::Status
Status
Status of the GJK algorithm: DidNotRun: GJK has not been run. Failed: GJK did not converge (it exceed...
Definition: coal/narrowphase/gjk.h:94
B
B
coal::details::EPA::initialize
void initialize()
Allocates memory for the EPA algorithm. This function should only be called by the constructor....
Definition: src/narrowphase/gjk.cpp:1013
y
y
COAL_ASSERT
#define COAL_ASSERT(check, message, exception)
Definition: include/coal/fwd.hh:82
coal::details::GJK::gjk_variant
GJKVariant gjk_variant
Definition: coal/narrowphase/gjk.h:106
coal::details::GJK::NoCollisionEarlyStopped
@ NoCollisionEarlyStopped
Definition: coal/narrowphase/gjk.h:97
coal::details::EPA::SimplexFace::adjacent_edge
size_t adjacent_edge[3]
Definition: coal/narrowphase/gjk.h:269
coal::details::EPA::OutOfVertices
@ OutOfVertices
Definition: coal/narrowphase/gjk.h:338
coal::details::EPA::SimplexFace::n
Vec3s n
Definition: coal/narrowphase/gjk.h:261
coal::details::EPA::result
GJK::Simplex result
Definition: coal/narrowphase/gjk.h:344
coal::Relative
@ Relative
Definition: coal/data_types.h:108
coal::details::originToPoint
void originToPoint(const GJK::Simplex &current, GJK::vertex_id_t a, const Vec3s &A, GJK::Simplex &next, Vec3s &ray)
Definition: src/narrowphase/gjk.cpp:495
coal::ConvexBase::num_support_warm_starts
static constexpr size_t num_support_warm_starts
Number of support warm starts.
Definition: coal/shape/geometric_shapes.h:754
coal::details::GJK::projectTetrahedraOrigin
bool projectTetrahedraOrigin(const Simplex &current, Simplex &next)
Project origin (0) onto tetrahedron a-b-c-d See projectLineOrigin for an explanation on simplex proje...
Definition: src/narrowphase/gjk.cpp:614
coal::details::EPA::SimplexHorizon::num_faces
size_t num_faces
Definition: coal/narrowphase/gjk.h:324
coal
Main namespace.
Definition: coal/broadphase/broadphase_bruteforce.h:44
coal::details::EPA::SimplexFace
Definition: coal/narrowphase/gjk.h:260
coal::details::EPA::reset
void reset(size_t max_iterations, CoalScalar tolerance)
resets the EPA algorithm, preparing it for a new run. It potentially reallocates memory for the verti...
Definition: src/narrowphase/gjk.cpp:1015
coal::details::EPA::expand
bool expand(size_t pass, const SimplexVertex &w, SimplexFace *f, size_t e, SimplexHorizon &horizon)
the goal is to add a face connecting vertex w and face edge f[e]
Definition: src/narrowphase/gjk.cpp:1362
coal::details::GJK::tolerance
CoalScalar tolerance
Definition: coal/narrowphase/gjk.h:125
coal::details::GJK::convergence_criterion
GJKConvergenceCriterion convergence_criterion
Definition: coal/narrowphase/gjk.h:107
coal::Default
@ Default
Definition: coal/data_types.h:104
coal::details::EPA::SimplexHorizon::first_face
SimplexFace * first_face
Definition: coal/narrowphase/gjk.h:323
coal::details::GJK::Simplex
A simplex is a set of up to 4 vertices. Its rank is the number of vertices it contains.
Definition: coal/narrowphase/gjk.h:71
coal::details::EPA::evaluate
Status evaluate(GJK &gjk, const Vec3s &guess)
Definition: src/narrowphase/gjk.cpp:1157
coal::details::GJK::distance_upper_bound
CoalScalar distance_upper_bound
Definition: coal/narrowphase/gjk.h:104
coal::DefaultGJK
@ DefaultGJK
Definition: coal/data_types.h:98
coal::details::EPA::OutOfFaces
@ OutOfFaces
Definition: coal/narrowphase/gjk.h:337
coal::GJKVariant
GJKVariant
Variant to use for the GJK algorithm.
Definition: coal/data_types.h:98
coal::details::EPA::SimplexFace::pass
size_t pass
Definition: coal/narrowphase/gjk.h:273
coal::details::GJK::SimplexV::w1
Vec3s w1
Definition: coal/narrowphase/gjk.h:56
coal::details::GJK::reset
void reset(size_t max_iterations_, CoalScalar tolerance_)
resets the GJK algorithm, preparing it for a new run. Other than the maximum number of iterations and...
Definition: src/narrowphase/gjk.cpp:58
coal::details::GJK::SimplexV::w
Vec3s w
support vector (i.e., the furthest point on the shape along the support direction)
Definition: coal/narrowphase/gjk.h:59
narrowphase_defaults.h
a
list a
coal::details::GJK::iterations
size_t iterations
Definition: coal/narrowphase/gjk.h:132
coal::NesterovAcceleration
@ NesterovAcceleration
Definition: coal/data_types.h:98
coal::details::MinkowskiDiff::swept_sphere_radius
Array2d swept_sphere_radius
The radii of the sphere swepted around each shape of the Minkowski difference. The 2 values correspon...
Definition: coal/narrowphase/minkowski_difference.h:74
coal::details::EPA::AccuracyReached
@ AccuracyReached
Definition: coal/narrowphase/gjk.h:333
COAL_UNUSED_VARIABLE
#define COAL_UNUSED_VARIABLE(var)
Definition: include/coal/fwd.hh:56
coal::details::EPA::SimplexFaceList::root
SimplexFace * root
Definition: coal/narrowphase/gjk.h:282
coal::support_func_guess_t
Eigen::Vector2i support_func_guess_t
Definition: coal/data_types.h:87
coal::details::EPA::closest_face
SimplexFace * closest_face
Definition: coal/narrowphase/gjk.h:348
coal::details::EPA::bind
static void bind(SimplexFace *fa, size_t ea, SimplexFace *fb, size_t eb)
We bind the face fa along its edge ea to the face fb along its edge fb.
Definition: coal/narrowphase/gjk.h:311
coal::details::EPA::InvalidHull
@ InvalidHull
Definition: coal/narrowphase/gjk.h:336
d
d
c
c
coal::details::EPA::DidNotRun
@ DidNotRun
Definition: coal/narrowphase/gjk.h:330
coal::details::GJK::distance
CoalScalar distance
The distance between the two shapes, computed by GJK. If the distance is below GJK's threshold,...
Definition: coal/narrowphase/gjk.h:118
COAL_THROW_PRETTY
#define COAL_THROW_PRETTY(message, exception)
Definition: include/coal/fwd.hh:64
coal::details::GJK::Simplex::rank
vertex_id_t rank
size of simplex (number of vertices)
Definition: coal/narrowphase/gjk.h:75
coal::details::GJK::appendVertex
void appendVertex(Simplex &simplex, const Vec3s &v, support_func_guess_t &hint)
append one vertex to the simplex
Definition: src/narrowphase/gjk.cpp:432
geometric_shapes_traits.h
D
D
coal::details::GJK::convergence_criterion_type
GJKConvergenceCriterionType convergence_criterion_type
Definition: coal/narrowphase/gjk.h:108
coal::details::GJK::initialize
void initialize()
Initializes the GJK algorithm. This function should only be called by the constructor....
Definition: src/narrowphase/gjk.cpp:50
coal::details::EPA::newFace
SimplexFace * newFace(size_t id_a, size_t id_b, size_t id_vertex, bool force=false)
Add a new face to the polytope. This function sets the ignore flag to true if the origin does not pro...
Definition: src/narrowphase/gjk.cpp:1069
coal::details::EPA::SimplexFaceList::remove
void remove(SimplexFace *face)
Definition: coal/narrowphase/gjk.h:299
coal::details::GJK::getSupport
void getSupport(const Vec3s &d, SimplexV &sv, support_func_guess_t &hint) const
apply the support function along a direction, the result is return in sv
Definition: coal/narrowphase/gjk.h:162
coal::details::EPA::iterations
size_t iterations
Definition: coal/narrowphase/gjk.h:360
coal::details::GJK::CollisionWithPenetrationInformation
@ CollisionWithPenetrationInformation
Definition: coal/narrowphase/gjk.h:99
axis
axis
coal::details::EPA::SimplexFace::d
CoalScalar d
Definition: coal/narrowphase/gjk.h:262
coal::details::EPA::SimplexFaceList::append
void append(SimplexFace *face)
Definition: coal/narrowphase/gjk.h:291
coal::PolyakAcceleration
@ PolyakAcceleration
Definition: coal/data_types.h:98
coal::details::details::inflate
void inflate(const MinkowskiDiff &shape, const Vec3s &normal, Vec3s &w0, Vec3s &w1)
Definition: src/narrowphase/gjk.cpp:158
coal::details::EPA::Degenerated
@ Degenerated
Definition: coal/narrowphase/gjk.h:334
coal::details::GJK::free_v
SimplexV * free_v[4]
Definition: coal/narrowphase/gjk.h:128
tools.h
coal::details::EPA::SimplexHorizon
Definition: coal/narrowphase/gjk.h:321
coal::details::GJK::nfree
vertex_id_t nfree
Definition: coal/narrowphase/gjk.h:129
coal::details::GJK::encloseOrigin
bool encloseOrigin()
whether the simplex enclose the origin
Definition: src/narrowphase/gjk.cpp:438
coal::details::EPA::status
Status status
Definition: coal/narrowphase/gjk.h:343
coal::details::EPA::SimplexFace::vertex_id
size_t vertex_id[3]
Definition: coal/narrowphase/gjk.h:265
coal::details::GJK::status
Status status
Definition: coal/narrowphase/gjk.h:105
A
A
coal::details::GJK::NoCollision
@ NoCollision
Definition: coal/narrowphase/gjk.h:98
coal::details::EPA::SimplexFace::adjacent_faces
SimplexFace * adjacent_faces[3]
Definition: coal/narrowphase/gjk.h:266
coal::details::GJK::SimplexV::w0
Vec3s w0
support vector for shape 0 and 1.
Definition: coal/narrowphase/gjk.h:56
generate_distance_plot.b
float b
Definition: generate_distance_plot.py:7
coal::details::GJK::getGuessFromSimplex
Vec3s getGuessFromSimplex() const
get the guess from current simplex
Definition: src/narrowphase/gjk.cpp:70
coal::details::GJK::DidNotRun
@ DidNotRun
Definition: coal/narrowphase/gjk.h:95
epsilon
static CoalScalar epsilon
Definition: simple.cpp:12
coal::details::GJK::checkConvergence
bool checkConvergence(const Vec3s &w, const CoalScalar &rl, CoalScalar &alpha, const CoalScalar &omega) const
Convergence check used to stop GJK when shapes are not in collision.
Definition: src/narrowphase/gjk.cpp:373
coal::details::EPA::tolerance
CoalScalar tolerance
Definition: coal/narrowphase/gjk.h:354
coal::ConvexBase::SupportWarmStartPolytope::points
std::vector< Vec3s > points
Array of support points to warm start the support function computation.
Definition: coal/shape/geometric_shapes.h:745
coal::details::EPA::hull
SimplexFaceList hull
Definition: coal/narrowphase/gjk.h:358
coal::details::EPA::normal
Vec3s normal
Definition: coal/narrowphase/gjk.h:345
coal::ConvexBase::buildSupportWarmStart
void buildSupportWarmStart()
Build the support points warm starts.
Definition: src/narrowphase/gjk.cpp:1471
coal::details::GJK::Simplex::vertex
SimplexV * vertex[4]
simplex vertex
Definition: coal/narrowphase/gjk.h:73
coal::details::GJK::simplices
Simplex simplices[2]
Definition: coal/narrowphase/gjk.h:131
coal::details::GJK::evaluate
Status evaluate(const MinkowskiDiff &shape, const Vec3s &guess, const support_func_guess_t &supportHint=support_func_guess_t::Zero())
GJK algorithm, given the initial value guess.
Definition: src/narrowphase/gjk.cpp:187
coal::details::GJK::projectLineOrigin
bool projectLineOrigin(const Simplex &current, Simplex &next)
Project origin (0) onto line a-b For a detailed explanation of how to efficiently project onto a simp...
Definition: src/narrowphase/gjk.cpp:544
coal::details::GJK::SimplexV
Definition: coal/narrowphase/gjk.h:54
coal::details::GJK::vertex_id_t
unsigned char vertex_id_t
Definition: coal/narrowphase/gjk.h:62
coal::details::EPA::Valid
@ Valid
Definition: coal/narrowphase/gjk.h:332
geometric_shapes.h
coal::details::EPA::max_iterations
size_t max_iterations
Definition: coal/narrowphase/gjk.h:353
coal::details::GJK::store_v
SimplexV store_v[4]
Definition: coal/narrowphase/gjk.h:127
coal::ConvexBase::SupportWarmStartPolytope::indices
std::vector< int > indices
Indices of the support points warm starts. These are the indices of the real convex,...
Definition: coal/shape/geometric_shapes.h:750
coal::DualityGap
@ DualityGap
Definition: coal/data_types.h:104
coal::details::EPA::FallBack
@ FallBack
Definition: coal/narrowphase/gjk.h:339
coal::details::GJK::projectTriangleOrigin
bool projectTriangleOrigin(const Simplex &current, Simplex &next)
Project origin (0) onto triangle a-b-c See projectLineOrigin for an explanation on simplex projection...
Definition: src/narrowphase/gjk.cpp:572
coal::details::GJK
class for GJK algorithm
Definition: coal/narrowphase/gjk.h:53
coal::details::EPA::sv_store
std::vector< SimplexVertex > sv_store
Definition: coal/narrowphase/gjk.h:356
coal::details::EPA::findClosestFace
SimplexFace * findClosestFace()
Find the best polytope face to split.
Definition: src/narrowphase/gjk.cpp:1142
coal::details::EPA::getEdgeDist
bool getEdgeDist(SimplexFace *face, const SimplexVertex &a, const SimplexVertex &b, CoalScalar &dist)
Definition: src/narrowphase/gjk.cpp:1040
coal::details::originToSegment
void originToSegment(const GJK::Simplex &current, GJK::vertex_id_t a, GJK::vertex_id_t b, const Vec3s &A, const Vec3s &B, const Vec3s &AB, const CoalScalar &ABdotAO, GJK::Simplex &next, Vec3s &ray)
Definition: src/narrowphase/gjk.cpp:503
coal::details::GJK::current
vertex_id_t current
Definition: coal/narrowphase/gjk.h:130
gjk.h
coal::details::GJK::Collision
@ Collision
Definition: coal/narrowphase/gjk.h:100
coal::details::EPA::getWitnessPointsAndNormal
void getWitnessPointsAndNormal(const MinkowskiDiff &shape, Vec3s &w0, Vec3s &w1, Vec3s &normal) const
Definition: src/narrowphase/gjk.cpp:1452
coal::triple
static Derived::Scalar triple(const Eigen::MatrixBase< Derived > &x, const Eigen::MatrixBase< Derived > &y, const Eigen::MatrixBase< Derived > &z)
Definition: coal/internal/tools.h:52
coal::details::EPA::depth
CoalScalar depth
Definition: coal/narrowphase/gjk.h:347
coal::details::GJK::removeVertex
void removeVertex(Simplex &simplex)
discard one vertex from the simplex
Definition: src/narrowphase/gjk.cpp:428
coal::ConvexBase::support_warm_starts
SupportWarmStartPolytope support_warm_starts
Support warm start polytopes.
Definition: coal/shape/geometric_shapes.h:757
coal::ConvexBase::points
std::shared_ptr< std::vector< Vec3s > > points
An array of the points of the polygon.
Definition: coal/shape/geometric_shapes.h:719
REGION_INSIDE
#define REGION_INSIDE()
coal::CoalScalar
double CoalScalar
Definition: coal/data_types.h:76
coal::details::GJK::support_hint
support_func_guess_t support_hint
Definition: coal/narrowphase/gjk.h:112
coal::details::EPA::support_hint
support_func_guess_t support_hint
Definition: coal/narrowphase/gjk.h:346
coal::details::GJK::simplex
Simplex * simplex
Definition: coal/narrowphase/gjk.h:119
obb.v
list v
Definition: obb.py:48
coal::ConvexBase::num_vertices_large_convex_threshold
static constexpr size_t num_vertices_large_convex_threshold
Above this threshold, the convex polytope is considered large. This influcences the way the support f...
Definition: coal/shape/geometric_shapes.h:716
coal::details::GJK::max_iterations
size_t max_iterations
Definition: coal/narrowphase/gjk.h:124
gjk
Definition: doc/gjk.py:1
coal::Absolute
@ Absolute
Definition: coal/data_types.h:108
coal::details::originToTriangle
bool originToTriangle(const GJK::Simplex &current, GJK::vertex_id_t a, GJK::vertex_id_t b, GJK::vertex_id_t c, const Vec3s &ABC, const CoalScalar &ABCdotAO, GJK::Simplex &next, Vec3s &ray)
Definition: src/narrowphase/gjk.cpp:518


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