1 /*
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2011-2014, Willow Garage, Inc.
5 * Copyright (c) 2014-2016, Open Source Robotics Foundation
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 * * Neither the name of Open Source Robotics Foundation nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 /** @author Jia Pan */
37
38 #ifndef FCL_NARROWPHASE_DETAIL_GJKLIBCCD_INL_H
39 #define FCL_NARROWPHASE_DETAIL_GJKLIBCCD_INL_H
40
41 #include "fcl/narrowphase/detail/convexity_based_algorithm/gjk_libccd.h"
42 #include "fcl/narrowphase/detail/failed_at_this_configuration.h"
43
44 #include <array>
45 #include <unordered_map>
46 #include <unordered_set>
47
48 #include "fcl/common/unused.h"
49 #include "fcl/common/warning.h"
50
51 namespace fcl
52 {
53
54 namespace detail
55 {
56
57 //==============================================================================
58 extern template
59 class FCL_EXPORT GJKInitializer<double, Cylinder<double>>;
60
61 //==============================================================================
62 extern template
63 class FCL_EXPORT GJKInitializer<double, Sphere<double>>;
64
65 //==============================================================================
66 extern template
67 class FCL_EXPORT GJKInitializer<double, Ellipsoid<double>>;
68
69 //==============================================================================
70 extern template
71 class FCL_EXPORT GJKInitializer<double, Box<double>>;
72
73 //==============================================================================
74 extern template
75 class FCL_EXPORT GJKInitializer<double, Capsule<double>>;
76
77 //==============================================================================
78 extern template
79 class FCL_EXPORT GJKInitializer<double, Cone<double>>;
80
81 //==============================================================================
82 extern template
83 class FCL_EXPORT GJKInitializer<double, Convex<double>>;
84
85 //==============================================================================
86 extern template
87 void* triCreateGJKObject(
88 const Vector3d& P1, const Vector3d& P2, const Vector3d& P3);
89
90 //==============================================================================
91 extern template
92 void* triCreateGJKObject(
93 const Vector3d& P1,
94 const Vector3d& P2,
95 const Vector3d& P3,
96 const Transform3d& tf);
97
98 //==============================================================================
99 extern template
100 bool GJKCollide(
101 void* obj1,
102 ccd_support_fn supp1,
103 ccd_center_fn cen1,
104 void* obj2,
105 ccd_support_fn supp2,
106 ccd_center_fn cen2,
107 unsigned int max_iterations,
108 double tolerance,
109 Vector3d* contact_points,
110 double* penetration_depth,
111 Vector3d* normal);
112
113 //==============================================================================
114 extern template
115 bool GJKDistance(
116 void* obj1,
117 ccd_support_fn supp1,
118 void* obj2,
119 ccd_support_fn supp2,
120 unsigned int max_iterations,
121 double tolerance,
122 double* dist,
123 Vector3d* p1,
124 Vector3d* p2);
125
126 extern template
127 bool GJKSignedDistance(
128 void* obj1,
129 ccd_support_fn supp1,
130 void* obj2,
131 ccd_support_fn supp2,
132 unsigned int max_iterations,
133 double tolerance,
134 double* dist,
135 Vector3d* p1,
136 Vector3d* p2);
137
138 struct ccd_obj_t
139 {
140 ccd_vec3_t pos;
141 ccd_quat_t rot, rot_inv;
142 };
143
144 struct ccd_box_t : public ccd_obj_t
145 {
146 ccd_real_t dim[3];
147 };
148
149 struct ccd_cap_t : public ccd_obj_t
150 {
151 ccd_real_t radius, height;
152 };
153
154 struct ccd_cyl_t : public ccd_obj_t
155 {
156 ccd_real_t radius, height;
157 };
158
159 struct ccd_cone_t : public ccd_obj_t
160 {
161 ccd_real_t radius, height;
162 };
163
164 struct ccd_sphere_t : public ccd_obj_t
165 {
166 ccd_real_t radius;
167 };
168
169 struct ccd_ellipsoid_t : public ccd_obj_t
170 {
171 ccd_real_t radii[3];
172 };
173
174 template <typename S>
175 struct ccd_convex_t : public ccd_obj_t
176 {
177 const Convex<S>* convex;
178 };
179
180 struct ccd_triangle_t : public ccd_obj_t
181 {
182 ccd_vec3_t p[3];
183 ccd_vec3_t c;
184 };
185
186 namespace libccd_extension
187 {
188
simplexReduceToTriangle(ccd_simplex_t * simplex,ccd_real_t dist,ccd_vec3_t * best_witness)189 static ccd_real_t simplexReduceToTriangle(ccd_simplex_t *simplex,
190 ccd_real_t dist,
191 ccd_vec3_t *best_witness)
192 {
193 ccd_real_t newdist;
194 ccd_vec3_t witness;
195 int best = -1;
196 int i;
197
198 // try the fourth point in all three positions
199 for (i = 0; i < 3; i++){
200 newdist = ccdVec3PointTriDist2(ccd_vec3_origin,
201 &ccdSimplexPoint(simplex, (i == 0 ? 3 : 0))->v,
202 &ccdSimplexPoint(simplex, (i == 1 ? 3 : 1))->v,
203 &ccdSimplexPoint(simplex, (i == 2 ? 3 : 2))->v,
204 &witness);
205 newdist = CCD_SQRT(newdist);
206
207 // record the best triangle
208 if (newdist < dist){
209 dist = newdist;
210 best = i;
211 ccdVec3Copy(best_witness, &witness);
212 }
213 }
214
215 if (best >= 0){
216 ccdSimplexSet(simplex, best, ccdSimplexPoint(simplex, 3));
217 }
218 ccdSimplexSetSize(simplex, 3);
219
220 return dist;
221 }
222
tripleCross(const ccd_vec3_t * a,const ccd_vec3_t * b,const ccd_vec3_t * c,ccd_vec3_t * d)223 _ccd_inline void tripleCross(const ccd_vec3_t *a, const ccd_vec3_t *b,
224 const ccd_vec3_t *c, ccd_vec3_t *d)
225 {
226 ccd_vec3_t e;
227 ccdVec3Cross(&e, a, b);
228 ccdVec3Cross(d, &e, c);
229 }
230
231 /* This is *not* an implementation of the general function: what's the nearest
232 point on the line segment AB to the origin O? It is not intended to be.
233 This is a limited, special case which exploits the known (or at least
234 expected) construction history of AB. The history is as follows:
235
236 1. We originally started with the Minkowski support point B (p_OB), which
237 was *not* the origin.
238 2. We define a support direction as p_BO = -p_OB and use that to get the
239 Minkowski support point A.
240 3. We confirm that O is not strictly beyond A in the direction p_BO
241 (confirming separation).
242 4. Then, and only then, do we invoke this method.
243
244 The method will do one of two things:
245
246 - determine if the origin lies within the simplex (i.e. lies on the line
247 segment, confirming non-separation) and reports if this is the case,
248 - otherwise it computes a new support direction: a vector pointing to the
249 origin from the nearest point on the segment AB. The direction is
250 guaranteed; the only guarantee about the magnitude is that it is
251 numerically viable (i.e. greater than epsilon).
252
253 The algorithm exploits the construction history as outlined below. Without
254 loss of generality, we place B some non-zero distance away from the origin
255 along the î direction (all other orientations can be rigidly transformed to
256 this canonical example). The diagram below shows the origin O and the point
257 B. It also shows three regions: 1, 2, and 3.
258
259 ĵ
260 1 ⯅ 2 3
261 │░░░░░░░░░░┆▒▒▒▒▒
262 │░░░░░░░░░░┆▒▒▒▒▒
263 │░░░░░░░░░░┆▒▒▒▒▒
264 │░░░░░░░░░░┆▒▒▒▒▒
265 │░░░░░░░░░░┆▒▒▒▒▒
266 ───────────O──────────B────⯈ î
267 │░░░░░░░░░░┆▒▒▒▒▒
268 │░░░░░░░░░░┆▒▒▒▒▒
269 │░░░░░░░░░░┆▒▒▒▒▒
270 │░░░░░░░░░░┆▒▒▒▒▒
271 │░░░░░░░░░░┆▒▒▒▒▒
272
273 The point A cannot lie in region 3.
274
275 - B is a support point of the Minkowski difference. p_BO defines the
276 support vector that produces the support point A. Vertex A must lie at
277 least as far in the p_BO as B otherwise A is not actually a valid support
278 point for that direction. It could lie on the boundary of regions 2 & 3
279 and still be a valid support point.
280
281 The point A cannot lie in region 2 (or on the boundary between 2 & 3).
282 - We confirm that O is not strictly beyond A in the direction p_BO. For all
283 A in region 2, O lies beyond A (when projected onto the p_BO vector).
284
285 The point A _must_ lie in region 1 (including the boundary between regions 1 &
286 2) by process of elimination.
287
288 The implication of this is that the O must project onto the _interior_ of the
289 line segment AB (with one notable exception). If A = O, then the projection of
290 O is at the end point and, is in fact, itself.
291
292 Therefore, this function can only have two possible outcomes:
293
294 1. In the case where p_BA = k⋅p_BO (i.e., they are co-linear), we know the
295 origin lies "in" the simplex. If A = O, it lies on the simplex's surface
296 and the objects are touching, otherwise, the objects are penetrating.
297 Either way, we can report that they are definitely *not* separated.
298 2. p_BA ≠ k⋅p_BO, we define the new support direction as perpendicular to the
299 line segment AB, pointing to O from the nearest point on the segment to O.
300
301 Return value indicates concrete knowledge that the origin lies "in" the
302 2-simplex (encoded as a 1), or indication that computation should continue (0).
303
304 @note: doSimplex2 should _only_ be called with the construction history
305 outlined above: promotion of a 1-simplex. doSimplex2() is only invoked by
306 doSimplex(). This follows the computation of A and the promotion of the
307 simplex. Therefore, the history is always valid. Even though doSimplex3() can
308 demote itself to a 2-simplex, that 2-simplex immediately gets promoted back to
309 a 3-simplex via the same construction process. Therefore, as long as
310 doSimplex2() is only called from doSimplex() its region 1 assumption _should_
311 remain valid.
312 */
doSimplex2(ccd_simplex_t * simplex,ccd_vec3_t * dir)313 static int doSimplex2(ccd_simplex_t *simplex, ccd_vec3_t *dir) {
314 // Used to define numerical thresholds near zero; typically scaled to the size
315 // of the quantities being tested.
316 constexpr ccd_real_t eps = constants<ccd_real_t>::eps();
317
318 const Vector3<ccd_real_t> p_OA(simplex->ps[simplex->last].v.v);
319 const Vector3<ccd_real_t> p_OB(simplex->ps[0].v.v);
320
321 // Confirm that A is in region 1. Given that A may be very near to the origin,
322 // we must avoid normalizing p_OA. So, we use this instead.
323 // let A' be the projection of A onto the line defined by O and B.
324 // |A'B| >= |OB| iff A is in region 1.
325 // Numerically, we can express it as follows (allowing for |A'B| to be ever
326 // so slightly *less* than |OB|):
327 // p_AB ⋅ phat_OB >= |p_OB| - |p_OB| * ε = |p_OB| * (1 - ε)
328 // p_AB ⋅ phat_OB ⋅ |p_OB| >= |p_OB|⋅|p_OB| * (1 - ε)
329 // p_AB ⋅ p_OB >= |p_OB|² * (1 - ε)
330 // (p_OB - p_OA) ⋅ p_OB >= |p_OB|² * (1 - ε)
331 // p_OB ⋅ p_OB - p_OA ⋅ p_OB >= |p_OB|² * (1 - ε)
332 // |p_OB|² - p_OA ⋅ p_OB >= |p_OB|² * (1 - ε)
333 // -p_OA ⋅ p_OB >= -|p_OB|²ε
334 // p_OA ⋅ p_OB <= |p_OB|²ε
335 assert(p_OA.dot(p_OB) <= p_OB.squaredNorm() * eps && "A is not in region 1");
336
337 // Test for co-linearity. Given A is in region 1, co-linearity --> O is "in"
338 // the simplex.
339 // We'll use the angle between two vectors to determine co-linearity: p_AB
340 // and p_OB. If they are co-linear, then the angle between them (θ) is zero.
341 // Similarly, sin(θ) is zero. Ideally, it can be expressed as:
342 // |p_AB × p_OB| = |p_AB||p_OB||sin(θ)| = 0
343 // Numerically, we allow θ (and sin(θ)) to be slightly larger than zero
344 // leading to a numerical formulation as:
345 // |p_AB × p_OB| = |p_AB||p_OB||sin(θ)| < |p_AB||p_OB|ε
346 // Finally, to reduce the computational cost, we eliminate the square roots by
347 // evaluating the equivalently discriminating test:
348 // |p_AB × p_OB|² < |p_AB|²|p_OB|²ε²
349 //
350 // In addition to providing a measure of co-linearity, the cross product gives
351 // us the normal to the plane on which points A, B, and O lie (which we will
352 // use later to compute a new support direction, as necessary).
353 const Vector3<ccd_real_t> p_AB = p_OB - p_OA;
354 const Vector3<ccd_real_t> plane_normal = p_OB.cross(p_AB);
355 if (plane_normal.squaredNorm() <
356 p_AB.squaredNorm() * p_OB.squaredNorm() * eps * eps) {
357 return 1;
358 }
359
360 // O is not co-linear with AB, so dist(O, AB) > ε. Define `dir` as the
361 // direction to O from the nearest point on AB.
362 // Note: We use the normalized `plane_normal` (n̂) because we've already
363 // concluded that the origin is farther from AB than ε. We want to make sure
364 // `dir` likewise has a magnitude larger than ε. With normalization, we know
365 // |dir| = |n̂ × AB| = |AB| > dist(O, AB) > ε.
366 // Without normalizing, if |OA| and |OB| were smaller than ³√ε but
367 // sufficiently larger than ε, dist(O, AB) > ε, but |dir| < ε.
368 const Vector3<ccd_real_t> new_dir = plane_normal.normalized().cross(p_AB);
369 ccdVec3Set(dir, new_dir(0), new_dir(1), new_dir(2));
370 return 0;
371 }
372
373 // Compares the given `value` against a _squared epsilon_. This is particularly
374 // important when testing some quantity (e.g., distance) to see if it
375 // is _functionally_ zero but using its _squared_ value in the test. Comparing
376 // _squared distance_ directly against epsilon is equivalent to comparing
377 // distance to sqrt(epsilon) -- we classify the distance as zero or not using
378 // only half the available precision.
isAbsValueLessThanEpsSquared(ccd_real_t val)379 static bool isAbsValueLessThanEpsSquared(ccd_real_t val) {
380 return std::abs(val) < std::numeric_limits<ccd_real_t>::epsilon() *
381 std::numeric_limits<ccd_real_t>::epsilon();
382 }
383
384 // TODO(SeanCurtis-TRI): Define the return value:
385 // 1: (like doSimplex2) --> origin is "in" the simplex.
386 // 0:
387 // -1: If the 3-simplex is degenerate. How is this intepreted?
doSimplex3(ccd_simplex_t * simplex,ccd_vec3_t * dir)388 static int doSimplex3(ccd_simplex_t *simplex, ccd_vec3_t *dir)
389 {
390 const ccd_support_t *A, *B, *C;
391 ccd_vec3_t AO, AB, AC, ABC, tmp;
392 ccd_real_t dot;
393
394 // get last added as A
395 A = ccdSimplexLast(simplex);
396 // get the other points
397 B = ccdSimplexPoint(simplex, 1);
398 C = ccdSimplexPoint(simplex, 0);
399
400 // check touching contact
401 // Compute origin_projection as well. Without computing the origin projection,
402 // libccd could give inaccurate result. See
403 // https://github.com/danfis/libccd/issues/55.
404 ccd_vec3_t origin_projection_unused;
405
406 const ccd_real_t dist_squared = ccdVec3PointTriDist2(
407 ccd_vec3_origin, &A->v, &B->v, &C->v, &origin_projection_unused);
408 if (isAbsValueLessThanEpsSquared(dist_squared)) {
409 return 1;
410 }
411
412 // check if triangle is really triangle (has area > 0)
413 // if not simplex can't be expanded and thus no intersection is found
414 // TODO(SeanCurtis-TRI): Coincident points is sufficient but not necessary
415 // for a zero-area triangle. What about co-linearity? Can we guarantee that
416 // co-linearity can't happen? See the `triangle_area_is_zero()` method in
417 // this same file.
418 if (ccdVec3Eq(&A->v, &B->v) || ccdVec3Eq(&A->v, &C->v)){
419 // TODO(SeanCurtis-TRI): Why do we simply quit if the simplex is degenerate?
420 return -1;
421 }
422
423 // compute AO vector
424 ccdVec3Copy(&AO, &A->v);
425 ccdVec3Scale(&AO, -CCD_ONE);
426
427 // compute AB and AC segments and ABC vector (perpendircular to triangle)
428 ccdVec3Sub2(&AB, &B->v, &A->v);
429 ccdVec3Sub2(&AC, &C->v, &A->v);
430 ccdVec3Cross(&ABC, &AB, &AC);
431
432 ccdVec3Cross(&tmp, &ABC, &AC);
433 dot = ccdVec3Dot(&tmp, &AO);
434 if (ccdIsZero(dot) || dot > CCD_ZERO){
435 dot = ccdVec3Dot(&AC, &AO);
436 if (ccdIsZero(dot) || dot > CCD_ZERO){
437 // C is already in place
438 ccdSimplexSet(simplex, 1, A);
439 ccdSimplexSetSize(simplex, 2);
440 tripleCross(&AC, &AO, &AC, dir);
441 }else{
442 ccd_do_simplex3_45:
443 dot = ccdVec3Dot(&AB, &AO);
444 if (ccdIsZero(dot) || dot > CCD_ZERO){
445 ccdSimplexSet(simplex, 0, B);
446 ccdSimplexSet(simplex, 1, A);
447 ccdSimplexSetSize(simplex, 2);
448 tripleCross(&AB, &AO, &AB, dir);
449 }else{
450 ccdSimplexSet(simplex, 0, A);
451 ccdSimplexSetSize(simplex, 1);
452 ccdVec3Copy(dir, &AO);
453 }
454 }
455 }else{
456 ccdVec3Cross(&tmp, &AB, &ABC);
457 dot = ccdVec3Dot(&tmp, &AO);
458 if (ccdIsZero(dot) || dot > CCD_ZERO){
459 goto ccd_do_simplex3_45;
460 }else{
461 dot = ccdVec3Dot(&ABC, &AO);
462 if (ccdIsZero(dot) || dot > CCD_ZERO){
463 ccdVec3Copy(dir, &ABC);
464 }else{
465 ccd_support_t Ctmp;
466 ccdSupportCopy(&Ctmp, C);
467 ccdSimplexSet(simplex, 0, B);
468 ccdSimplexSet(simplex, 1, &Ctmp);
469
470 ccdVec3Copy(dir, &ABC);
471 ccdVec3Scale(dir, -CCD_ONE);
472 }
473 }
474 }
475
476 return 0;
477 }
478
doSimplex4(ccd_simplex_t * simplex,ccd_vec3_t * dir)479 static int doSimplex4(ccd_simplex_t *simplex, ccd_vec3_t *dir)
480 {
481 const ccd_support_t *A, *B, *C, *D;
482 ccd_vec3_t AO, AB, AC, AD, ABC, ACD, ADB;
483 int B_on_ACD, C_on_ADB, D_on_ABC;
484 int AB_O, AC_O, AD_O;
485
486 // get last added as A
487 A = ccdSimplexLast(simplex);
488 // get the other points
489 B = ccdSimplexPoint(simplex, 2);
490 C = ccdSimplexPoint(simplex, 1);
491 D = ccdSimplexPoint(simplex, 0);
492
493 // check if tetrahedron is really tetrahedron (has volume > 0)
494 // if it is not simplex can't be expanded and thus no intersection is
495 // found.
496 // point_projection_on_triangle_unused is not used. We ask
497 // ccdVec3PointTriDist2 to compute this witness point, so as to get a
498 // numerical robust dist_squared. See
499 // https://github.com/danfis/libccd/issues/55 for an explanation.
500 ccd_vec3_t point_projection_on_triangle_unused;
501 ccd_real_t dist_squared = ccdVec3PointTriDist2(
502 &A->v, &B->v, &C->v, &D->v, &point_projection_on_triangle_unused);
503 if (isAbsValueLessThanEpsSquared(dist_squared)) {
504 return -1;
505 }
506
507 // check if origin lies on some of tetrahedron's face - if so objects
508 // intersect
509 dist_squared = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &B->v, &C->v,
510 &point_projection_on_triangle_unused);
511 if (isAbsValueLessThanEpsSquared((dist_squared))) return 1;
512 dist_squared = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &C->v, &D->v,
513 &point_projection_on_triangle_unused);
514 if (isAbsValueLessThanEpsSquared((dist_squared))) return 1;
515 dist_squared = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &B->v, &D->v,
516 &point_projection_on_triangle_unused);
517 if (isAbsValueLessThanEpsSquared(dist_squared)) return 1;
518 dist_squared = ccdVec3PointTriDist2(ccd_vec3_origin, &B->v, &C->v, &D->v,
519 &point_projection_on_triangle_unused);
520 if (isAbsValueLessThanEpsSquared(dist_squared)) return 1;
521
522 // compute AO, AB, AC, AD segments and ABC, ACD, ADB normal vectors
523 ccdVec3Copy(&AO, &A->v);
524 ccdVec3Scale(&AO, -CCD_ONE);
525 ccdVec3Sub2(&AB, &B->v, &A->v);
526 ccdVec3Sub2(&AC, &C->v, &A->v);
527 ccdVec3Sub2(&AD, &D->v, &A->v);
528 ccdVec3Cross(&ABC, &AB, &AC);
529 ccdVec3Cross(&ACD, &AC, &AD);
530 ccdVec3Cross(&ADB, &AD, &AB);
531
532 // side (positive or negative) of B, C, D relative to planes ACD, ADB
533 // and ABC respectively
534 B_on_ACD = ccdSign(ccdVec3Dot(&ACD, &AB));
535 C_on_ADB = ccdSign(ccdVec3Dot(&ADB, &AC));
536 D_on_ABC = ccdSign(ccdVec3Dot(&ABC, &AD));
537
538 // whether origin is on same side of ACD, ADB, ABC as B, C, D
539 // respectively
540 AB_O = ccdSign(ccdVec3Dot(&ACD, &AO)) == B_on_ACD;
541 AC_O = ccdSign(ccdVec3Dot(&ADB, &AO)) == C_on_ADB;
542 AD_O = ccdSign(ccdVec3Dot(&ABC, &AO)) == D_on_ABC;
543
544 if (AB_O && AC_O && AD_O){
545 // origin is in tetrahedron
546 return 1;
547
548 // rearrange simplex to triangle and call doSimplex3()
549 }else if (!AB_O){
550 // B is farthest from the origin among all of the tetrahedron's
551 // points, so remove it from the list and go on with the triangle
552 // case
553
554 // D and C are in place
555 ccdSimplexSet(simplex, 2, A);
556 ccdSimplexSetSize(simplex, 3);
557 }else if (!AC_O){
558 // C is farthest
559 ccdSimplexSet(simplex, 1, D);
560 ccdSimplexSet(simplex, 0, B);
561 ccdSimplexSet(simplex, 2, A);
562 ccdSimplexSetSize(simplex, 3);
563 }else{ // (!AD_O)
564 ccdSimplexSet(simplex, 0, C);
565 ccdSimplexSet(simplex, 1, B);
566 ccdSimplexSet(simplex, 2, A);
567 ccdSimplexSetSize(simplex, 3);
568 }
569
570 return doSimplex3(simplex, dir);
571 }
572
doSimplex(ccd_simplex_t * simplex,ccd_vec3_t * dir)573 static int doSimplex(ccd_simplex_t *simplex, ccd_vec3_t *dir)
574 {
575 if (ccdSimplexSize(simplex) == 2){
576 // simplex contains segment only one segment
577 return doSimplex2(simplex, dir);
578 }else if (ccdSimplexSize(simplex) == 3){
579 // simplex contains triangle
580 return doSimplex3(simplex, dir);
581 }else{ // ccdSimplexSize(simplex) == 4
582 // tetrahedron - this is the only shape which can encapsule origin
583 // so doSimplex4() also contains test on it
584 return doSimplex4(simplex, dir);
585 }
586 }
587
588 /** Transforms simplex to polytope, two vertices required */
simplexToPolytope2(const void * obj1,const void * obj2,const ccd_t * ccd,const ccd_simplex_t * simplex,ccd_pt_t * pt,ccd_pt_el_t ** nearest)589 static int simplexToPolytope2(const void *obj1, const void *obj2,
590 const ccd_t *ccd,
591 const ccd_simplex_t *simplex,
592 ccd_pt_t *pt, ccd_pt_el_t **nearest)
593 {
594 const ccd_support_t *a, *b;
595 ccd_vec3_t ab, ac, dir;
596 ccd_support_t supp[4];
597 ccd_pt_vertex_t *v[6];
598 ccd_pt_edge_t *e[12];
599 size_t i;
600 int found;
601
602 a = ccdSimplexPoint(simplex, 0);
603 b = ccdSimplexPoint(simplex, 1);
604
605 // This situation is a bit tricky. If only one segment comes from
606 // previous run of GJK - it means that either this segment is on
607 // minkowski edge (and thus we have touch contact) or it it isn't and
608 // therefore segment is somewhere *inside* minkowski sum and it *must*
609 // be possible to fully enclose this segment with polyhedron formed by
610 // at least 8 triangle faces.
611
612 // get first support point (any)
613 found = 0;
614 for (i = 0; i < ccd_points_on_sphere_len; i++){
615 __ccdSupport(obj1, obj2, &ccd_points_on_sphere[i], ccd, &supp[0]);
616 if (!ccdVec3Eq(&a->v, &supp[0].v) && !ccdVec3Eq(&b->v, &supp[0].v)){
617 found = 1;
618 break;
619 }
620 }
621 if (!found)
622 goto simplexToPolytope2_touching_contact;
623
624 // get second support point in opposite direction than supp[0]
625 ccdVec3Copy(&dir, &supp[0].v);
626 ccdVec3Scale(&dir, -CCD_ONE);
627 __ccdSupport(obj1, obj2, &dir, ccd, &supp[1]);
628 if (ccdVec3Eq(&a->v, &supp[1].v) || ccdVec3Eq(&b->v, &supp[1].v))
629 goto simplexToPolytope2_touching_contact;
630
631 // next will be in direction of normal of triangle a,supp[0],supp[1]
632 ccdVec3Sub2(&ab, &supp[0].v, &a->v);
633 ccdVec3Sub2(&ac, &supp[1].v, &a->v);
634 ccdVec3Cross(&dir, &ab, &ac);
635 __ccdSupport(obj1, obj2, &dir, ccd, &supp[2]);
636 if (ccdVec3Eq(&a->v, &supp[2].v) || ccdVec3Eq(&b->v, &supp[2].v))
637 goto simplexToPolytope2_touching_contact;
638
639 // and last one will be in opposite direction
640 ccdVec3Scale(&dir, -CCD_ONE);
641 __ccdSupport(obj1, obj2, &dir, ccd, &supp[3]);
642 if (ccdVec3Eq(&a->v, &supp[3].v) || ccdVec3Eq(&b->v, &supp[3].v))
643 goto simplexToPolytope2_touching_contact;
644
645 goto simplexToPolytope2_not_touching_contact;
646 simplexToPolytope2_touching_contact:
647 v[0] = ccdPtAddVertex(pt, a);
648 v[1] = ccdPtAddVertex(pt, b);
649 *nearest = (ccd_pt_el_t *)ccdPtAddEdge(pt, v[0], v[1]);
650 if (*nearest == NULL)
651 return -2;
652
653 return -1;
654
655 simplexToPolytope2_not_touching_contact:
656 // form polyhedron
657 v[0] = ccdPtAddVertex(pt, a);
658 v[1] = ccdPtAddVertex(pt, &supp[0]);
659 v[2] = ccdPtAddVertex(pt, b);
660 v[3] = ccdPtAddVertex(pt, &supp[1]);
661 v[4] = ccdPtAddVertex(pt, &supp[2]);
662 v[5] = ccdPtAddVertex(pt, &supp[3]);
663
664 e[0] = ccdPtAddEdge(pt, v[0], v[1]);
665 e[1] = ccdPtAddEdge(pt, v[1], v[2]);
666 e[2] = ccdPtAddEdge(pt, v[2], v[3]);
667 e[3] = ccdPtAddEdge(pt, v[3], v[0]);
668
669 e[4] = ccdPtAddEdge(pt, v[4], v[0]);
670 e[5] = ccdPtAddEdge(pt, v[4], v[1]);
671 e[6] = ccdPtAddEdge(pt, v[4], v[2]);
672 e[7] = ccdPtAddEdge(pt, v[4], v[3]);
673
674 e[8] = ccdPtAddEdge(pt, v[5], v[0]);
675 e[9] = ccdPtAddEdge(pt, v[5], v[1]);
676 e[10] = ccdPtAddEdge(pt, v[5], v[2]);
677 e[11] = ccdPtAddEdge(pt, v[5], v[3]);
678
679 if (ccdPtAddFace(pt, e[4], e[5], e[0]) == NULL
680 || ccdPtAddFace(pt, e[5], e[6], e[1]) == NULL
681 || ccdPtAddFace(pt, e[6], e[7], e[2]) == NULL
682 || ccdPtAddFace(pt, e[7], e[4], e[3]) == NULL
683
684 || ccdPtAddFace(pt, e[8], e[9], e[0]) == NULL
685 || ccdPtAddFace(pt, e[9], e[10], e[1]) == NULL
686 || ccdPtAddFace(pt, e[10], e[11], e[2]) == NULL
687 || ccdPtAddFace(pt, e[11], e[8], e[3]) == NULL){
688 return -2;
689 }
690
691 return 0;
692 }
693
694 #ifndef NDEBUG
isPolytopeEmpty(const ccd_pt_t & polytope)695 static bool isPolytopeEmpty(const ccd_pt_t& polytope) {
696 ccd_pt_vertex_t* v = nullptr;
697 ccdListForEachEntry(&polytope.vertices, v, ccd_pt_vertex_t, list) {
698 if (v) {
699 return false;
700 }
701 }
702 ccd_pt_edge_t* e = nullptr;
703 ccdListForEachEntry(&polytope.edges, e, ccd_pt_edge_t, list) {
704 if (e) {
705 return false;
706 }
707 }
708 ccd_pt_face_t* f = nullptr;
709 ccdListForEachEntry(&polytope.faces, f, ccd_pt_face_t, list) {
710 if (f) {
711 return false;
712 }
713 }
714 return true;
715 }
716 #endif
717
718 /** Transforms a 2-simplex (triangle) to a polytope (tetrahedron), three
719 * vertices required.
720 * Both the simplex and the transformed polytope contain the origin. The simplex
721 * vertices lie on the surface of the Minkowski difference obj1 ⊖ obj2.
722 * @param[in] obj1 object 1 on which the distance is queried.
723 * @param[in] obj2 object 2 on which the distance is queried.
724 * @param[in] ccd The ccd solver.
725 * @param[in] simplex The simplex (with three vertices) that contains the
726 * origin.
727 * @param[out] polytope The polytope (tetrahedron) that also contains the origin
728 * on one of its faces. At input, the polytope should be empty.
729 * @param[out] nearest If the function detects that obj1 and obj2 are touching,
730 * then set *nearest to be the nearest points on obj1 and obj2 respectively;
731 * otherwise set *nearest to NULL. @note nearest cannot be NULL.
732 * @retval status return 0 on success, -1 if touching contact is detected, and
733 * -2 on non-recoverable failure (mostly due to memory allocation bug).
734 */
convert2SimplexToTetrahedron(const void * obj1,const void * obj2,const ccd_t * ccd,const ccd_simplex_t * simplex,ccd_pt_t * polytope,ccd_pt_el_t ** nearest)735 static int convert2SimplexToTetrahedron(const void* obj1, const void* obj2,
736 const ccd_t* ccd, const ccd_simplex_t* simplex,
737 ccd_pt_t* polytope, ccd_pt_el_t** nearest) {
738 assert(nearest);
739 assert(isPolytopeEmpty(*polytope));
740 assert(simplex->last == 2); // a 2-simplex.
741 const ccd_support_t *a, *b, *c;
742 ccd_support_t d, d2;
743 ccd_vec3_t ab, ac, dir;
744 ccd_pt_vertex_t* v[4];
745 ccd_pt_edge_t* e[6];
746
747 *nearest = NULL;
748
749 a = ccdSimplexPoint(simplex, 0);
750 b = ccdSimplexPoint(simplex, 1);
751 c = ccdSimplexPoint(simplex, 2);
752
753 // The 2-simplex is just a triangle containing the origin. We will expand this
754 // triangle to a tetrahedron, by adding the support point along the normal
755 // direction of the triangle.
756 ccdVec3Sub2(&ab, &b->v, &a->v);
757 ccdVec3Sub2(&ac, &c->v, &a->v);
758 ccdVec3Cross(&dir, &ab, &ac);
759 __ccdSupport(obj1, obj2, &dir, ccd, &d);
760 ccd_vec3_t point_projection_on_triangle_unused;
761 const ccd_real_t dist_squared = ccdVec3PointTriDist2(
762 &d.v, &a->v, &b->v, &c->v, &point_projection_on_triangle_unused);
763
764 // and second one take in opposite direction
765 ccdVec3Scale(&dir, -CCD_ONE);
766 __ccdSupport(obj1, obj2, &dir, ccd, &d2);
767 const ccd_real_t dist_squared_opposite = ccdVec3PointTriDist2(
768 &d2.v, &a->v, &b->v, &c->v, &point_projection_on_triangle_unused);
769
770 // check if face isn't already on edge of minkowski sum and thus we
771 // have touching contact
772 if (ccdIsZero(dist_squared) || ccdIsZero(dist_squared_opposite)) {
773 v[0] = ccdPtAddVertex(polytope, a);
774 v[1] = ccdPtAddVertex(polytope, b);
775 v[2] = ccdPtAddVertex(polytope, c);
776 e[0] = ccdPtAddEdge(polytope, v[0], v[1]);
777 e[1] = ccdPtAddEdge(polytope, v[1], v[2]);
778 e[2] = ccdPtAddEdge(polytope, v[2], v[0]);
779 *nearest = (ccd_pt_el_t*)ccdPtAddFace(polytope, e[0], e[1], e[2]);
780 if (*nearest == NULL) return -2;
781
782 return -1;
783 }
784 // Form a tetrahedron with abc as one face, pick either d or d2, based
785 // on which one has larger distance to the face abc. We pick the larger
786 // distance because it gives a tetrahedron with larger volume, so potentially
787 // more "expanded" than the one with the smaller volume.
788 auto FormTetrahedron = [polytope, a, b, c, &v,
789 &e](const ccd_support_t& new_support) -> int {
790 v[0] = ccdPtAddVertex(polytope, a);
791 v[1] = ccdPtAddVertex(polytope, b);
792 v[2] = ccdPtAddVertex(polytope, c);
793 v[3] = ccdPtAddVertex(polytope, &new_support);
794
795 e[0] = ccdPtAddEdge(polytope, v[0], v[1]);
796 e[1] = ccdPtAddEdge(polytope, v[1], v[2]);
797 e[2] = ccdPtAddEdge(polytope, v[2], v[0]);
798 e[3] = ccdPtAddEdge(polytope, v[0], v[3]);
799 e[4] = ccdPtAddEdge(polytope, v[1], v[3]);
800 e[5] = ccdPtAddEdge(polytope, v[2], v[3]);
801
802 // ccdPtAdd*() functions return NULL either if the memory allocation
803 // failed of if any of the input pointers are NULL, so the bad
804 // allocation can be checked by the last calls of ccdPtAddFace()
805 // because the rest of the bad allocations eventually "bubble up" here
806 // Note, there is no requirement on the winding of the face, namely we do
807 // not guarantee if all f.e(0).cross(f.e(1)) points outward (or inward) for
808 // all the faces added below.
809 if (ccdPtAddFace(polytope, e[0], e[1], e[2]) == NULL ||
810 ccdPtAddFace(polytope, e[3], e[4], e[0]) == NULL ||
811 ccdPtAddFace(polytope, e[4], e[5], e[1]) == NULL ||
812 ccdPtAddFace(polytope, e[5], e[3], e[2]) == NULL) {
813 return -2;
814 }
815 return 0;
816 };
817
818 if (std::abs(dist_squared) > std::abs(dist_squared_opposite)) {
819 return FormTetrahedron(d);
820 } else {
821 return FormTetrahedron(d2);
822 }
823 }
824
825 /** Transforms simplex to polytope. It is assumed that simplex has 4
826 * vertices! */
simplexToPolytope4(const void * obj1,const void * obj2,const ccd_t * ccd,ccd_simplex_t * simplex,ccd_pt_t * pt,ccd_pt_el_t ** nearest)827 static int simplexToPolytope4(const void* obj1, const void* obj2,
828 const ccd_t* ccd, ccd_simplex_t* simplex,
829 ccd_pt_t* pt, ccd_pt_el_t** nearest) {
830 const ccd_support_t *a, *b, *c, *d;
831 bool use_polytope3{false};
832 ccd_pt_vertex_t* v[4];
833 ccd_pt_edge_t* e[6];
834 size_t i;
835
836 a = ccdSimplexPoint(simplex, 0);
837 b = ccdSimplexPoint(simplex, 1);
838 c = ccdSimplexPoint(simplex, 2);
839 d = ccdSimplexPoint(simplex, 3);
840
841 // The origin can lie on any of the tetrahedra faces. In fact, for a
842 // degenerate tetrahedron, it could be considered to lie on multiple faces
843 // simultaneously. If it lies on any face, we can simply reduce the dimension
844 // of the simplex to that face and then attempt to construct the polytope from
845 // the resulting face. We simply take the first face which exhibited the
846 // trait.
847 ccd_real_t dist_squared =
848 ccdVec3PointTriDist2(ccd_vec3_origin, &a->v, &b->v, &c->v, NULL);
849 if (isAbsValueLessThanEpsSquared(dist_squared)) {
850 use_polytope3 = true;
851 }
852 if (!use_polytope3) {
853 dist_squared =
854 ccdVec3PointTriDist2(ccd_vec3_origin, &a->v, &c->v, &d->v, NULL);
855 if (isAbsValueLessThanEpsSquared(dist_squared)) {
856 use_polytope3 = true;
857 ccdSimplexSet(simplex, 1, c);
858 ccdSimplexSet(simplex, 2, d);
859 }
860 }
861 if (!use_polytope3) {
862 dist_squared =
863 ccdVec3PointTriDist2(ccd_vec3_origin, &a->v, &b->v, &d->v, NULL);
864 if (isAbsValueLessThanEpsSquared(dist_squared)) {
865 use_polytope3 = true;
866 ccdSimplexSet(simplex, 2, d);
867 }
868 }
869 if (!use_polytope3) {
870 dist_squared =
871 ccdVec3PointTriDist2(ccd_vec3_origin, &b->v, &c->v, &d->v, NULL);
872 if (isAbsValueLessThanEpsSquared(dist_squared)) {
873 use_polytope3 = true;
874 ccdSimplexSet(simplex, 0, b);
875 ccdSimplexSet(simplex, 1, c);
876 ccdSimplexSet(simplex, 2, d);
877 }
878 }
879
880 if (use_polytope3) {
881 ccdSimplexSetSize(simplex, 3);
882 return convert2SimplexToTetrahedron(obj1, obj2, ccd, simplex, pt, nearest);
883 }
884
885 // no touching contact - simply create tetrahedron
886 for (i = 0; i < 4; i++) {
887 v[i] = ccdPtAddVertex(pt, ccdSimplexPoint(simplex, i));
888 }
889
890 e[0] = ccdPtAddEdge(pt, v[0], v[1]);
891 e[1] = ccdPtAddEdge(pt, v[1], v[2]);
892 e[2] = ccdPtAddEdge(pt, v[2], v[0]);
893 e[3] = ccdPtAddEdge(pt, v[3], v[0]);
894 e[4] = ccdPtAddEdge(pt, v[3], v[1]);
895 e[5] = ccdPtAddEdge(pt, v[3], v[2]);
896
897 // ccdPtAdd*() functions return NULL either if the memory allocation
898 // failed of if any of the input pointers are NULL, so the bad
899 // allocation can be checked by the last calls of ccdPtAddFace()
900 // because the rest of the bad allocations eventually "bubble up" here
901 if (ccdPtAddFace(pt, e[0], e[1], e[2]) == NULL ||
902 ccdPtAddFace(pt, e[3], e[4], e[0]) == NULL ||
903 ccdPtAddFace(pt, e[4], e[5], e[1]) == NULL ||
904 ccdPtAddFace(pt, e[5], e[3], e[2]) == NULL) {
905 return -2;
906 }
907
908 return 0;
909 }
910
911 /** Reports true if p and q are coincident. */
are_coincident(const ccd_vec3_t & p,const ccd_vec3_t & q)912 static bool are_coincident(const ccd_vec3_t& p, const ccd_vec3_t& q) {
913 // This uses a scale-dependent basis for determining coincidence. It examines
914 // each axis independently, and only, if all three axes are sufficiently
915 // close (relative to its own scale), are the two points considered
916 // coincident.
917 //
918 // For dimension i, two values are considered the same if:
919 // |pᵢ - qᵢ| <= ε·max(1, |pᵢ|, |qᵢ|)
920 // And the points are coincident if the previous condition holds for all
921 // `i ∈ {0, 1, 2}` (i.e. the x-, y-, *and* z-dimensions).
922 using std::abs;
923 using std::max;
924
925 constexpr ccd_real_t eps = constants<ccd_real_t>::eps();
926 // NOTE: Wrapping "1.0" with ccd_real_t accounts for mac problems where ccd
927 // is actually float based.
928 for (int i = 0; i < 3; ++i) {
929 const ccd_real_t tolerance =
930 max({ccd_real_t{1}, abs(p.v[i]), abs(q.v[i])}) * eps;
931 const ccd_real_t delta = abs(p.v[i] - q.v[i]);
932 if (delta > tolerance) return false;
933 }
934 return true;
935 }
936
937 /** Determines if the the triangle defined by the three vertices has zero area.
938 Area can be zero for one of two reasons:
939 - the triangle is so small that the vertices are functionally coincident, or
940 - the vertices are co-linear.
941 Both conditions are computed with respect to machine precision.
942 @returns true if the area is zero. */
triangle_area_is_zero(const ccd_vec3_t & a,const ccd_vec3_t & b,const ccd_vec3_t & c)943 static bool triangle_area_is_zero(const ccd_vec3_t& a, const ccd_vec3_t& b,
944 const ccd_vec3_t& c) {
945 // First coincidence condition. This doesn't *explicitly* test for b and c
946 // being coincident. That will be captured in the subsequent co-linearity
947 // test. If b and c *were* coincident, it would be cheaper to perform the
948 // coincidence test than the co-linearity test.
949 // However, the expectation is that typically the triangle will not have zero
950 // area. In that case, we want to minimize the number of tests performed on
951 // the average, so we prefer to eliminate one coincidence test.
952 if (are_coincident(a, b) || are_coincident(a, c)) return true;
953
954 // We're going to compute the *sine* of the angle θ between edges (given that
955 // the vertices are *not* coincident). If the sin(θ) < ε, the edges are
956 // co-linear.
957 ccd_vec3_t AB, AC, n;
958 ccdVec3Sub2(&AB, &b, &a);
959 ccdVec3Sub2(&AC, &c, &a);
960 ccdVec3Normalize(&AB);
961 ccdVec3Normalize(&AC);
962 ccdVec3Cross(&n, &AB, &AC);
963 constexpr ccd_real_t eps = constants<ccd_real_t>::eps();
964 // Second co-linearity condition.
965 if (ccdVec3Len2(&n) < eps * eps) return true;
966 return false;
967 }
968
969 /**
970 * Computes the normal vector of a triangular face on a polytope, and the normal
971 * vector points outward from the polytope. Notice we assume that the origin
972 * lives within the polytope, and the normal vector may not have unit length.
973 * @param[in] polytope The polytope on which the face lives. We assume that the
974 * origin also lives inside the polytope.
975 * @param[in] face The face for which the normal vector is computed.
976 * @retval dir The vector normal to the face, and points outward from the
977 * polytope. `dir` is unnormalized, that it does not necessarily have a unit
978 * length.
979 * @throws UnexpectedConfigurationException if built in debug mode _and_ the
980 * triangle has zero area (either by being too small, or being co-linear).
981 */
faceNormalPointingOutward(const ccd_pt_t * polytope,const ccd_pt_face_t * face)982 static ccd_vec3_t faceNormalPointingOutward(const ccd_pt_t* polytope,
983 const ccd_pt_face_t* face) {
984 // This doesn't necessarily define a triangle; I don't know that the third
985 // vertex added here is unique from the other two.
986 #ifndef NDEBUG
987 // quick test for degeneracy
988 const ccd_vec3_t& a = face->edge[0]->vertex[1]->v.v;
989 const ccd_vec3_t& b = face->edge[0]->vertex[0]->v.v;
990 const ccd_vec3_t& test_v = face->edge[1]->vertex[0]->v.v;
991 const ccd_vec3_t& c = are_coincident(test_v, a) || are_coincident(test_v, b) ?
992 face->edge[1]->vertex[1]->v.v : test_v;
993 if (triangle_area_is_zero(a, b, c)) {
994 FCL_THROW_FAILED_AT_THIS_CONFIGURATION(
995 "Cannot compute face normal for a degenerate (zero-area) triangle");
996 }
997 #endif
998 // We find two edges of the triangle as e1 and e2, and the normal vector
999 // of the face is e1.cross(e2).
1000 ccd_vec3_t e1, e2;
1001 ccdVec3Sub2(&e1, &(face->edge[0]->vertex[1]->v.v),
1002 &(face->edge[0]->vertex[0]->v.v));
1003 ccdVec3Sub2(&e2, &(face->edge[1]->vertex[1]->v.v),
1004 &(face->edge[1]->vertex[0]->v.v));
1005 ccd_vec3_t dir;
1006 // TODO(hongkai.dai): we ignore the degeneracy here, namely we assume e1 and
1007 // e2 are not colinear. We should check if e1 and e2 are colinear, and handle
1008 // this corner case.
1009 ccdVec3Cross(&dir, &e1, &e2);
1010 const ccd_real_t dir_norm = std::sqrt(ccdVec3Len2(&dir));
1011 ccd_vec3_t unit_dir = dir;
1012 ccdVec3Scale(&unit_dir, 1.0 / dir_norm);
1013 // The winding of the triangle is *not* guaranteed. The normal `n = e₁ × e₂`
1014 // may point inside or outside. We rely on the fact that the origin lies
1015 // within the polytope to resolve this ambiguity. A vector from the origin to
1016 // any point on the triangle must point in the "same" direction as the normal
1017 // (positive dot product).
1018
1019 // However, the distance to the origin may be too small for the origin to
1020 // serve as a reliable witness of inside-ness. In that case, we examine the
1021 // polytope's *other* vertices; they should all lie on the "inside" of the
1022 // current triangle. If at least one is a reliable distance, then that is
1023 // considered to be the inside. If all vertices are "too close" (like the
1024 // origin), then "inside" is defined as the side of the triangle that had the
1025 // most distant vertex.
1026
1027 // For these tests, we use the arbitrary distance of 0.01 unit length as a
1028 // "reliable" distance for both the origin and other vertices. Even if it
1029 // seems large, the fall through case of comparing the maximum distance will
1030 // always guarantee correctness.
1031 const ccd_real_t dist_tol = 0.01;
1032 // origin_distance_to_plane computes the signed distance from the origin to
1033 // the plane nᵀ * (x - v) = 0 coinciding with the triangle, where v is a
1034 // point on the triangle.
1035 const ccd_real_t origin_distance_to_plane =
1036 ccdVec3Dot(&unit_dir, &(face->edge[0]->vertex[0]->v.v));
1037 if (origin_distance_to_plane < -dist_tol) {
1038 // Origin is more than `dist_tol` away from the plane, but the negative
1039 // value implies that the normal vector is pointing in the wrong direction;
1040 // flip it.
1041 ccdVec3Scale(&dir, ccd_real_t(-1));
1042 } else if (-dist_tol <= origin_distance_to_plane &&
1043 origin_distance_to_plane <= dist_tol) {
1044 // The origin is close to the plane of the face. Pick another vertex to test
1045 // the normal direction.
1046 ccd_real_t max_distance_to_plane = -CCD_REAL_MAX;
1047 ccd_real_t min_distance_to_plane = CCD_REAL_MAX;
1048 ccd_pt_vertex_t* v;
1049 // If the magnitude of the distance_to_plane is larger than dist_tol,
1050 // then it means one of the vertices is at least `dist_tol` away from the
1051 // plane coinciding with the face.
1052 ccdListForEachEntry(&polytope->vertices, v, ccd_pt_vertex_t, list) {
1053 // distance_to_plane is the signed distance from the
1054 // vertex v->v.v to the face, i.e., distance_to_plane = nᵀ *
1055 // (v->v.v - face_point). Note that origin_distance_to_plane = nᵀ *
1056 // face_point.
1057 const ccd_real_t distance_to_plane =
1058 ccdVec3Dot(&unit_dir, &(v->v.v)) - origin_distance_to_plane;
1059 if (distance_to_plane > dist_tol) {
1060 // The vertex is at least dist_tol away from the face plane, on the same
1061 // direction of `dir`. So we flip dir to point it outward from the
1062 // polytope.
1063 ccdVec3Scale(&dir, ccd_real_t(-1));
1064 return dir;
1065 } else if (distance_to_plane < -dist_tol) {
1066 // The vertex is at least `dist_tol` away from the face plane, on the
1067 // opposite direction of `dir`. So `dir` points outward already.
1068 return dir;
1069 } else {
1070 max_distance_to_plane =
1071 std::max(max_distance_to_plane, distance_to_plane);
1072 min_distance_to_plane =
1073 std::min(min_distance_to_plane, distance_to_plane);
1074 }
1075 }
1076 // If max_distance_to_plane > |min_distance_to_plane|, it means that the
1077 // vertices that are on the positive side of the plane, has a larger maximal
1078 // distance than the vertices on the negative side of the plane. Thus we
1079 // regard that `dir` points into the polytope. Hence we flip `dir`.
1080 if (max_distance_to_plane > std::abs(min_distance_to_plane)) {
1081 ccdVec3Scale(&dir, ccd_real_t(-1));
1082 }
1083 }
1084 return dir;
1085 }
1086
1087 // Return true if the point `pt` is on the outward side of the half-plane, on
1088 // which the triangle `f1 lives. Notice if the point `pt` is exactly on the
1089 // half-plane, the return is false.
1090 // @param f A triangle on a polytope.
1091 // @param pt A point.
isOutsidePolytopeFace(const ccd_pt_t * polytope,const ccd_pt_face_t * f,const ccd_vec3_t * pt)1092 static bool isOutsidePolytopeFace(const ccd_pt_t* polytope,
1093 const ccd_pt_face_t* f, const ccd_vec3_t* pt) {
1094 ccd_vec3_t n = faceNormalPointingOutward(polytope, f);
1095 // r_VP is the vector from a vertex V on the face `f`, to the point P `pt`.
1096 ccd_vec3_t r_VP;
1097 ccdVec3Sub2(&r_VP, pt, &(f->edge[0]->vertex[0]->v.v));
1098 return ccdVec3Dot(&n, &r_VP) > 0;
1099 }
1100
1101 #ifndef NDEBUG
1102 // The function ComputeVisiblePatchRecursiveSanityCheck() is only called in the
1103 // debug mode. In the release mode, this function is declared/defined but not
1104 // used. Without this NDEBUG macro, the function will cause a -Wunused-function
1105 // error on CI's release builds.
1106 /**
1107 * Reports true if the visible patch is valid.
1108 * The invariant for computing the visible patch is that for each edge in the
1109 * polytope, if both neighbouring faces are visible, then the edge is an
1110 * internal edge; if only one neighbouring face is visible, then the edge
1111 * is a border edge.
1112 * For each face, if one of its edges is an internal edge, then the face is
1113 * visible.
1114 */
ComputeVisiblePatchRecursiveSanityCheck(const ccd_pt_t & polytope,const std::unordered_set<ccd_pt_edge_t * > & border_edges,const std::unordered_set<ccd_pt_face_t * > & visible_faces,const std::unordered_set<ccd_pt_edge_t * > & internal_edges)1115 static bool ComputeVisiblePatchRecursiveSanityCheck(
1116 const ccd_pt_t& polytope,
1117 const std::unordered_set<ccd_pt_edge_t*>& border_edges,
1118 const std::unordered_set<ccd_pt_face_t*>& visible_faces,
1119 const std::unordered_set<ccd_pt_edge_t*>& internal_edges) {
1120 ccd_pt_face_t* f;
1121 // TODO(SeanCurtis-TRI): Instead of returning false, have this throw the
1122 // exception itself so that it can provide additional information.
1123 ccdListForEachEntry(&polytope.faces, f, ccd_pt_face_t, list) {
1124 bool has_edge_internal = false;
1125 for (int i = 0; i < 3; ++i) {
1126 // Since internal_edges is a set, internal_edges.count(e) means that e
1127 // is contained in the set internal_edges.
1128 if (internal_edges.count(f->edge[i]) > 0) {
1129 has_edge_internal = true;
1130 break;
1131 }
1132 }
1133 if (has_edge_internal) {
1134 if (visible_faces.count(f) == 0) {
1135 return false;
1136 }
1137 }
1138 }
1139 ccd_pt_edge_t* e;
1140 ccdListForEachEntry(&polytope.edges, e, ccd_pt_edge_t, list) {
1141 if (visible_faces.count(e->faces[0]) > 0 &&
1142 visible_faces.count(e->faces[1]) > 0) {
1143 if (internal_edges.count(e) == 0) {
1144 return false;
1145 }
1146 } else if (visible_faces.count(e->faces[0]) +
1147 visible_faces.count(e->faces[1]) ==
1148 1) {
1149 if (border_edges.count(e) == 0) {
1150 return false;
1151 }
1152 }
1153 }
1154 for (const auto b : border_edges) {
1155 if (internal_edges.count(b) > 0) {
1156 return false;
1157 }
1158 }
1159 return true;
1160 }
1161 #endif
1162
1163 /** Attempts to classify the given `edge` as a border edge, confirming it hasn't
1164 already been classified as an internal edge.
1165 @param edge The edge to classify.
1166 @param border_edges The set of edges already classified as border.
1167 @param internal_edges The set of edges already classified as internal.
1168 @throws ThrowFailedAtThisConfiguration if the edge is being re-classified.
1169 */
ClassifyBorderEdge(ccd_pt_edge_t * edge,std::unordered_set<ccd_pt_edge_t * > * border_edges,std::unordered_set<ccd_pt_edge_t * > * internal_edges)1170 static void ClassifyBorderEdge(ccd_pt_edge_t* edge,
1171 std::unordered_set<ccd_pt_edge_t*>* border_edges,
1172 std::unordered_set<ccd_pt_edge_t*>* internal_edges) {
1173 border_edges->insert(edge);
1174 if (internal_edges->count(edge) > 0) {
1175 FCL_THROW_FAILED_AT_THIS_CONFIGURATION(
1176 "An edge is being classified as border that has already been "
1177 "classifed as internal");
1178 }
1179 }
1180
1181 /** Attempts to classify the given `edge` as an internal edge, confirming it
1182 hasn't already been classified as a border edge.
1183 @param edge The edge to classify.
1184 @param border_edges The set of edges already classified as border.
1185 @param internal_edges The set of edges already classified as internal.
1186 @throws ThrowFailedAtThisConfiguration if the edge is being re-classified.
1187 */
ClassifyInternalEdge(ccd_pt_edge_t * edge,std::unordered_set<ccd_pt_edge_t * > * border_edges,std::unordered_set<ccd_pt_edge_t * > * internal_edges)1188 static void ClassifyInternalEdge(ccd_pt_edge_t* edge,
1189 std::unordered_set<ccd_pt_edge_t*>* border_edges,
1190 std::unordered_set<ccd_pt_edge_t*>* internal_edges) {
1191 internal_edges->insert(edge);
1192 if (border_edges->count(edge) > 0) {
1193 FCL_THROW_FAILED_AT_THIS_CONFIGURATION(
1194 "An edge is being classified as internal that has already been "
1195 "classified as border");
1196 }
1197 }
1198
1199 /**
1200 * This function contains the implementation detail of ComputeVisiblePatch()
1201 * function. It should not be called by any function other than
1202 * ComputeVisiblePatch().
1203 * The parameters are documented as in ComputeVisiblePatch() but has the
1204 * additional parameter: hidden_faces. Every visited face will be categorized
1205 * explicitly as either visible or hidden.
1206 * By design, whatever classification is _first_ given to a face (visible or
1207 * hidden) it can't change. This doesn't purport that the first classification
1208 * is more correct than any subsequent code that might otherwise classify it
1209 * differently. This simply precludes the possibility of classifying edges
1210 * multiple ways.
1211 */
ComputeVisiblePatchRecursive(const ccd_pt_t & polytope,ccd_pt_face_t & f,int edge_index,const ccd_vec3_t & query_point,std::unordered_set<ccd_pt_edge_t * > * border_edges,std::unordered_set<ccd_pt_face_t * > * visible_faces,std::unordered_set<ccd_pt_face_t * > * hidden_faces,std::unordered_set<ccd_pt_edge_t * > * internal_edges)1212 static void ComputeVisiblePatchRecursive(
1213 const ccd_pt_t& polytope, ccd_pt_face_t& f, int edge_index,
1214 const ccd_vec3_t& query_point,
1215 std::unordered_set<ccd_pt_edge_t*>* border_edges,
1216 std::unordered_set<ccd_pt_face_t*>* visible_faces,
1217 std::unordered_set<ccd_pt_face_t*>* hidden_faces,
1218 std::unordered_set<ccd_pt_edge_t*>* internal_edges) {
1219 ccd_pt_edge_t* edge = f.edge[edge_index];
1220
1221 ccd_pt_face_t* g = edge->faces[0] == &f ? edge->faces[1] : edge->faces[0];
1222 assert(g != nullptr);
1223
1224 bool is_visible = visible_faces->count(g) > 0;
1225 bool is_hidden = hidden_faces->count(g) > 0;
1226 assert(!(is_visible && is_hidden));
1227
1228 // First check to see if face `g` has been classifed already.
1229 if (is_visible) {
1230 // Face f is visible (prerequisite), and g has been previously
1231 // marked visible (via a different path); their shared edge should be
1232 // marked internal.
1233 ClassifyInternalEdge(edge, border_edges, internal_edges);
1234 return;
1235 }
1236
1237 if (is_hidden) {
1238 // Face *has* already been classified as hidden; we just need to classify
1239 // the edge.
1240 ClassifyBorderEdge(edge, border_edges, internal_edges);
1241 return;
1242 }
1243
1244 // Face `g` has not been classified yet. Try to classify it as visible (i.e.,
1245 // the `query_point` lies outside of this face).
1246 is_visible = isOutsidePolytopeFace(&polytope, g, &query_point);
1247 if (!is_visible) {
1248 // Face `g` is *apparently* not visible from the query point. However, it
1249 // might _still_ be considered visible. The query point could be co-linear
1250 // with `edge` which, by definition means that `g` *is* visible and
1251 // numerical error led to considering it hidden. We can detect this case
1252 // if the triangle formed by edge and query point has zero area.
1253 //
1254 // It may be that the previous designation that `f` was visible was a
1255 // mistake and now face `g` is inheriting that visible status. This is a
1256 // conservative resolution that will prevent us from creating co-planar
1257 // faces (at the cost of a longer border).
1258 is_visible = triangle_area_is_zero(query_point, edge->vertex[0]->v.v,
1259 edge->vertex[1]->v.v);
1260 }
1261
1262 if (is_visible) {
1263 visible_faces->insert(g);
1264 ClassifyInternalEdge(edge, border_edges, internal_edges);
1265 for (int i = 0; i < 3; ++i) {
1266 if (g->edge[i] != edge) {
1267 // One of the neighbouring face is `f`, so do not need to visit again.
1268 ComputeVisiblePatchRecursive(polytope, *g, i, query_point, border_edges,
1269 visible_faces, hidden_faces,
1270 internal_edges);
1271 }
1272 }
1273 } else {
1274 // No logic could classify the face as visible, so mark it hidden and
1275 // mark the edge as a border edge.
1276 ClassifyBorderEdge(edge, border_edges, internal_edges);
1277 hidden_faces->insert(g);
1278 }
1279 }
1280
1281 /** Defines the "visible" patch on the given convex `polytope` (with respect to
1282 * the given `query_vertex` which is a point outside the polytope.)
1283 *
1284 * A patch is characterized by:
1285 * - a contiguous set of visible faces
1286 * - internal edges (the edges for which *both* adjacent faces are in the
1287 * patch)
1288 * - border edges (edges for which only *one* adjacent face is in the patch)
1289 *
1290 * A face `f` (with vertices `(v₀, v₁, v₂)` and outward pointing normal `n̂`) is
1291 * "visible" and included in the patch if, for query vertex `q`:
1292 *
1293 * `n̂ ⋅ (q - v₀) > 0`
1294 *
1295 * Namely the query vertex `q` is on the "outer" side of the face `f`.
1296 *
1297 * @param polytope The polytope to evaluate.
1298 * @param f A face known to be visible to the query point.
1299 * @param query_point The point from which visibility is evaluated.
1300 * @param[out] border_edges The collection of patch border edges.
1301 * @param[out] visible_faces The collection of patch faces.
1302 * @param[out] internal_edges The collection of internal edges.
1303 * @throws UnexpectedConfigurationException in debug builds if the resulting
1304 * patch is not consistent.
1305 *
1306 * @pre The `polytope` is convex.
1307 * @pre The face `f` is visible from `query_point`.
1308 * @pre Output parameters are non-null.
1309 * TODO(hongkai.dai@tri.global) Replace patch computation with patch deletion
1310 * and return border edges as an optimization.
1311 * TODO(hongkai.dai@tri.global) Consider caching results of per-face visibility
1312 * status to prevent redundant recalculation -- or by associating the face
1313 * normal with the face.
1314 */
ComputeVisiblePatch(const ccd_pt_t & polytope,ccd_pt_face_t & f,const ccd_vec3_t & query_point,std::unordered_set<ccd_pt_edge_t * > * border_edges,std::unordered_set<ccd_pt_face_t * > * visible_faces,std::unordered_set<ccd_pt_edge_t * > * internal_edges)1315 static void ComputeVisiblePatch(
1316 const ccd_pt_t& polytope, ccd_pt_face_t& f,
1317 const ccd_vec3_t& query_point,
1318 std::unordered_set<ccd_pt_edge_t*>* border_edges,
1319 std::unordered_set<ccd_pt_face_t*>* visible_faces,
1320 std::unordered_set<ccd_pt_edge_t*>* internal_edges) {
1321 assert(border_edges);
1322 assert(visible_faces);
1323 assert(internal_edges);
1324 assert(border_edges->empty());
1325 assert(visible_faces->empty());
1326 assert(internal_edges->empty());
1327 assert(isOutsidePolytopeFace(&polytope, &f, &query_point));
1328 std::unordered_set<ccd_pt_face_t*> hidden_faces;
1329 visible_faces->insert(&f);
1330 for (int edge_index = 0; edge_index < 3; ++edge_index) {
1331 ComputeVisiblePatchRecursive(polytope, f, edge_index, query_point,
1332 border_edges, visible_faces, &hidden_faces,
1333 internal_edges);
1334 }
1335 #ifndef NDEBUG
1336 // TODO(SeanCurtis-TRI): Extend the sanity check to include hidden_faces.
1337 if (!ComputeVisiblePatchRecursiveSanityCheck(
1338 polytope, *border_edges, *visible_faces, *internal_edges)) {
1339 FCL_THROW_FAILED_AT_THIS_CONFIGURATION(
1340 "The visible patch failed its sanity check");
1341 }
1342 #endif
1343 }
1344
1345 /** Expands the polytope by adding a new vertex `newv` to the polytope. The
1346 * new polytope is the convex hull of the new vertex together with the old
1347 * polytope. This new polytope includes new edges (by connecting the new vertex
1348 * with existing vertices) and new faces (by connecting the new vertex with
1349 * existing edges). We only keep the edges and faces that are on the boundary
1350 * of the new polytope. The edges/faces on the original polytope that would be
1351 * interior to the new convex hull are discarded.
1352 * @param[in/out] polytope The polytope.
1353 * @param[in] el A feature that is visible from the point `newv` and contains
1354 * the polytope boundary point that is closest to the origin. This feature
1355 * should be either a face or an edge. A face is visible from a point outside
1356 * the original polytope, if the point is on the "outer" side of the face. If an
1357 * edge is visible from that point, at least one of its neighbouring faces is
1358 * visible. This feature contains the point that is closest to the origin on
1359 * the boundary of the polytope. If the feature is an edge, and the two
1360 * neighbouring faces of that edge are not co-planar, then the origin must lie
1361 * on that edge. The feature should not be a vertex, as that would imply the two
1362 * objects are in touching contact, causing the algorithm to exit before calling
1363 * expandPolytope() function.
1364 * @param[in] newv The new vertex add to the polytope.
1365 * @retval status Returns 0 on success. Returns -2 otherwise.
1366 * @throws UnexpectedConfigurationException if expanding is meaningless either
1367 * because 1) the nearest feature is a vertex, 2) the new vertex lies on
1368 * an edge of the current polytope, or 3) the visible feature is an edge with
1369 * one or more adjacent faces with no area.
1370 */
expandPolytope(ccd_pt_t * polytope,ccd_pt_el_t * el,const ccd_support_t * newv)1371 static int expandPolytope(ccd_pt_t *polytope, ccd_pt_el_t *el,
1372 const ccd_support_t *newv)
1373 {
1374 // The outline of the algorithm is as follows:
1375 // 1. Compute the visible patch relative to the new vertex (See
1376 // ComputeVisiblePatch() for details).
1377 // 2. Delete the faces and internal edges.
1378 // 3. Build a new face from each border edge and the new vertex.
1379
1380 // To remove all faces that can be seen from the new vertex, we start with the
1381 // face on which the closest point lives, and then do a depth-first search on
1382 // its neighbouring triangles, until the triangle cannot be seen from the new
1383 // vertex.
1384 // TODO(hongkai.dai@tri.global): it is inefficient to store visible
1385 // faces/edges. A better implementation should remove visible faces and
1386 // internal edges inside ComputeVisiblePatch() function, when traversing the
1387 // faces on the polytope. We focus on the correctness in the first place.
1388 // Later when we make sure that the whole EPA implementation is bug free, we
1389 // will improve the performance.
1390
1391 ccd_pt_face_t* start_face = NULL;
1392
1393 if (el->type == CCD_PT_VERTEX) {
1394 FCL_THROW_FAILED_AT_THIS_CONFIGURATION(
1395 "The visible feature is a vertex. This should already have been "
1396 "identified as a touching contact");
1397 }
1398 // Start with the face on which the closest point lives
1399 if (el->type == CCD_PT_FACE) {
1400 start_face = reinterpret_cast<ccd_pt_face_t*>(el);
1401 } else if (el->type == CCD_PT_EDGE) {
1402 // Check the two neighbouring faces of the edge.
1403 ccd_pt_face_t* f[2];
1404 ccdPtEdgeFaces(reinterpret_cast<ccd_pt_edge_t*>(el), &f[0], &f[1]);
1405 if (isOutsidePolytopeFace(polytope, f[0], &newv->v)) {
1406 start_face = f[0];
1407 } else if (isOutsidePolytopeFace(polytope, f[1], &newv->v)) {
1408 start_face = f[1];
1409 } else {
1410 FCL_THROW_FAILED_AT_THIS_CONFIGURATION(
1411 "Both the nearest point and the new vertex are on an edge, thus the "
1412 "nearest distance should be 0. This is touching contact, and should "
1413 "already have been identified");
1414 }
1415 }
1416
1417 std::unordered_set<ccd_pt_face_t*> visible_faces;
1418 std::unordered_set<ccd_pt_edge_t*> internal_edges;
1419 std::unordered_set<ccd_pt_edge_t*> border_edges;
1420 ComputeVisiblePatch(*polytope, *start_face, newv->v, &border_edges,
1421 &visible_faces, &internal_edges);
1422
1423 // Now remove all the obsolete faces.
1424 // TODO(hongkai.dai@tri.global): currently we need to loop through each face
1425 // in visible_faces, and then do a linear search in the list pt->faces to
1426 // delete `face`. It would be better if we only loop through the list
1427 // polytope->faces for once. Same for the edges.
1428 for (const auto& f : visible_faces) {
1429 ccdPtDelFace(polytope, f);
1430 }
1431
1432 // Now remove all the obsolete edges.
1433 for (const auto& e : internal_edges) {
1434 ccdPtDelEdge(polytope, e);
1435 }
1436
1437 // Note: this does not delete any vertices that were on the interior of the
1438 // deleted patch. There are no longer any faces or edges that reference them.
1439 // Technically, they are still part of the polytope but have no effect (except
1440 // for footprint in memory). It's just as simple to leave them, knowing the
1441 // whole polytope will be destroyed when we're done with the query.
1442
1443 // A vertex cannot be obsolete, since a vertex is always on the boundary of
1444 // the Minkowski difference A ⊖ B.
1445 // TODO(hongkai.dai@tri.global): as a sanity check, we should make sure that
1446 // all vertices has at least one face/edge invisible from the new vertex
1447 // `newv`.
1448
1449 // Now add the new vertex.
1450 ccd_pt_vertex_t* new_vertex = ccdPtAddVertex(polytope, newv);
1451
1452 // Now add the new edges and faces, by connecting the new vertex with vertices
1453 // on border_edges. map_vertex_to_new_edge maps a vertex on the silhouette
1454 // edges to a new edge, with one end being the new vertex, and the other end
1455 // being that vertex on the silhouette edges.
1456 std::unordered_map<ccd_pt_vertex_t*, ccd_pt_edge_t*> map_vertex_to_new_edge;
1457 for (const auto& border_edge : border_edges) {
1458 ccd_pt_edge_t* e[2]; // The two new edges added by connecting new_vertex
1459 // to the two vertices on border_edge.
1460 for (int i = 0; i < 2; ++i) {
1461 auto it = map_vertex_to_new_edge.find(border_edge->vertex[i]);
1462 if (it == map_vertex_to_new_edge.end()) {
1463 // This edge has not been added yet.
1464 e[i] = ccdPtAddEdge(polytope, new_vertex, border_edge->vertex[i]);
1465 map_vertex_to_new_edge.emplace_hint(it, border_edge->vertex[i],
1466 e[i]);
1467 } else {
1468 e[i] = it->second;
1469 }
1470 }
1471 // Now add the face.
1472 ccdPtAddFace(polytope, border_edge, e[0], e[1]);
1473 }
1474
1475 return 0;
1476 }
1477
1478 /** In each iteration of EPA algorithm, given the nearest point on the polytope
1479 * boundary to the origin, a support direction will be computed, to find the
1480 * support of the Minkowski difference A ⊖ B along that direction, so as to
1481 * expand the polytope.
1482 * @param polytope The polytope contained in A ⊖ B.
1483 * @param nearest_feature The feature containing the nearest point on the
1484 * boundary of the polytope to the origin.
1485 * @retval dir The support direction along which to expand the polytope. Notice
1486 * that dir is a normalized vector.
1487 * @throws UnexpectedConfigurationException if the nearest feature is a vertex.
1488 */
supportEPADirection(const ccd_pt_t * polytope,const ccd_pt_el_t * nearest_feature)1489 static ccd_vec3_t supportEPADirection(const ccd_pt_t* polytope,
1490 const ccd_pt_el_t* nearest_feature) {
1491 /*
1492 If we denote the nearest point as v, when v is not the origin, then the
1493 support direction is v. If v is the origin, then v should be an interior
1494 point on a face, and the support direction is the normal of that face,
1495 pointing outward from the polytope.
1496 */
1497 ccd_vec3_t dir;
1498 if (ccdIsZero(nearest_feature->dist)) {
1499 // nearest point is the origin.
1500 switch (nearest_feature->type) {
1501 case CCD_PT_VERTEX: {
1502 FCL_THROW_FAILED_AT_THIS_CONFIGURATION(
1503 "The nearest point to the origin is a vertex of the polytope. This "
1504 "should be identified as a touching contact");
1505 break;
1506 }
1507 case CCD_PT_EDGE: {
1508 // When the nearest point is on an edge, the origin must be on that
1509 // edge. The support direction could be in the range between
1510 // edge.faces[0].normal and edge.faces[1].normal, where the face normals
1511 // point outward from the polytope. In this implementation, we
1512 // arbitrarily choose faces[0] normal.
1513 const ccd_pt_edge_t* edge =
1514 reinterpret_cast<const ccd_pt_edge_t*>(nearest_feature);
1515 dir = faceNormalPointingOutward(polytope, edge->faces[0]);
1516 break;
1517 }
1518 case CCD_PT_FACE: {
1519 // If origin is an interior point of a face, then choose the normal of
1520 // that face as the sample direction.
1521 const ccd_pt_face_t* face =
1522 reinterpret_cast<const ccd_pt_face_t*>(nearest_feature);
1523 dir = faceNormalPointingOutward(polytope, face);
1524 break;
1525 }
1526 }
1527 } else {
1528 ccdVec3Copy(&dir, &(nearest_feature->witness));
1529 }
1530 ccdVec3Normalize(&dir);
1531 return dir;
1532 }
1533
1534 /** Finds next support point (and stores it in out argument).
1535 * @param[in] polytope The current polytope contained inside the Minkowski
1536 * difference A ⊖ B.
1537 * @param[in] obj1 Geometric object A.
1538 * @param[in] obj2 Geometric object B.
1539 * @param[in] ccd The libccd solver.
1540 * @param[in] el The polytope boundary feature that contains the point nearest
1541 * to the origin.
1542 * @param[out] out The next support point.
1543 * @retval status If the next support point is found, then returns 0; otherwise
1544 * returns -1. There are several reasons why the next support point is not
1545 * found:
1546 * 1. If the nearest point on the boundary of the polytope to the origin is a
1547 * vertex of the polytope. Then we know the two objects A and B are in touching
1548 * contact.
1549 * 2. If the difference between the upper bound and lower bound of the distance
1550 * is below ccd->epa_tolerance, then we converge to a distance whose
1551 * difference from the real distance is less than ccd->epa_tolerance.
1552 */
nextSupport(const ccd_pt_t * polytope,const void * obj1,const void * obj2,const ccd_t * ccd,const ccd_pt_el_t * el,ccd_support_t * out)1553 static int nextSupport(const ccd_pt_t* polytope, const void* obj1,
1554 const void* obj2, const ccd_t* ccd,
1555 const ccd_pt_el_t* el, ccd_support_t* out) {
1556 ccd_vec3_t *a, *b, *c;
1557
1558 if (el->type == CCD_PT_VERTEX) return -1;
1559
1560 const ccd_vec3_t dir = supportEPADirection(polytope, el);
1561
1562 __ccdSupport(obj1, obj2, &dir, ccd, out);
1563
1564 // Compute distance of support point in the support direction, so we can
1565 // determine whether we expanded a polytope surrounding the origin a bit.
1566 const ccd_real_t dist = ccdVec3Dot(&out->v, &dir);
1567
1568 // el->dist is the squared distance from the feature "el" to the origin..
1569 // dist is an upper bound on the distance from the boundary of the Minkowski
1570 // difference to the origin, and sqrt(el->dist) is a lower bound of that
1571 // distance.
1572 if (dist - std::sqrt(el->dist) < ccd->epa_tolerance) return -1;
1573
1574 ccd_real_t dist_squared{};
1575 if (el->type == CCD_PT_EDGE) {
1576 // fetch end points of edge
1577 ccdPtEdgeVec3(reinterpret_cast<const ccd_pt_edge_t*>(el), &a, &b);
1578
1579 // get distance from segment
1580 dist_squared = ccdVec3PointSegmentDist2(&out->v, a, b, NULL);
1581 } else { // el->type == CCD_PT_FACE
1582 // fetch vertices of triangle face
1583 ccdPtFaceVec3(reinterpret_cast<const ccd_pt_face_t*>(el), &a, &b, &c);
1584
1585 // check if new point can significantly expand polytope
1586 ccd_vec3_t point_projection_on_triangle_unused;
1587 dist_squared = ccdVec3PointTriDist2(&out->v, a, b, c,
1588 &point_projection_on_triangle_unused);
1589 }
1590
1591 if (std::sqrt(dist_squared) < ccd->epa_tolerance) return -1;
1592
1593 return 0;
1594 }
1595
1596
__ccdGJK(const void * obj1,const void * obj2,const ccd_t * ccd,ccd_simplex_t * simplex)1597 static int __ccdGJK(const void *obj1, const void *obj2,
1598 const ccd_t *ccd, ccd_simplex_t *simplex)
1599 {
1600 unsigned long iterations;
1601 ccd_vec3_t dir; // direction vector
1602 ccd_support_t last; // last support point
1603 int do_simplex_res;
1604
1605 // initialize simplex struct
1606 ccdSimplexInit(simplex);
1607
1608 // get first direction
1609 ccd->first_dir(obj1, obj2, &dir);
1610 // get first support point
1611 __ccdSupport(obj1, obj2, &dir, ccd, &last);
1612 // and add this point to simplex as last one
1613 ccdSimplexAdd(simplex, &last);
1614
1615 // set up direction vector to as (O - last) which is exactly -last
1616 ccdVec3Copy(&dir, &last.v);
1617 ccdVec3Scale(&dir, -CCD_ONE);
1618
1619 // start iterations
1620 for (iterations = 0UL; iterations < ccd->max_iterations; ++iterations) {
1621 // obtain support point
1622 __ccdSupport(obj1, obj2, &dir, ccd, &last);
1623
1624 // check if farthest point in Minkowski difference in direction dir
1625 // isn't somewhere before origin (the test on negative dot product)
1626 // - because if it is, objects are not intersecting at all.
1627 if (ccdVec3Dot(&last.v, &dir) < CCD_ZERO){
1628 return -1; // intersection not found
1629 }
1630
1631 // add last support vector to simplex
1632 ccdSimplexAdd(simplex, &last);
1633
1634 // if doSimplex returns 1 if objects intersect, -1 if objects don't
1635 // intersect and 0 if algorithm should continue
1636 do_simplex_res = doSimplex(simplex, &dir);
1637 if (do_simplex_res == 1){
1638 return 0; // intersection found
1639 }else if (do_simplex_res == -1){
1640 return -1; // intersection not found
1641 }
1642
1643 if (ccdIsZero(ccdVec3Len2(&dir))){
1644 return -1; // intersection not found
1645 }
1646 }
1647
1648 // intersection wasn't found
1649 return -1;
1650 }
1651
1652 /**
1653 * When the nearest feature of a polytope to the origin is an edge, and the
1654 * origin is inside the polytope, it implies one of the following conditions
1655 * 1. The origin lies exactly on that edge
1656 * 2. The two neighbouring faces of that edge are coplanar, and the projection
1657 * of the origin onto that plane is on the edge.
1658 * At times libccd incorrectly claims that the nearest feature is an edge.
1659 * Inside this function, we will verify if one of these two conditions are true.
1660 * If not, we will modify the nearest feature stored inside @p polytope, such
1661 * that it stores the correct nearest feature and distance.
1662 * @note we assume that even if the edge is not the correct nearest feature, the
1663 * correct one should be one of the neighbouring faces of that edge. Namely the
1664 * libccd solution is just slightly wrong.
1665 * @param polytope The polytope whose nearest feature is being verified (and
1666 * corrected if the edge should not be nearest feature).
1667 * @note Only call this function in the EPA functions, where the origin should
1668 * be inside the polytope.
1669 */
validateNearestFeatureOfPolytopeBeingEdge(ccd_pt_t * polytope)1670 static void validateNearestFeatureOfPolytopeBeingEdge(ccd_pt_t* polytope) {
1671 assert(polytope->nearest_type == CCD_PT_EDGE);
1672
1673 // We define epsilon to include an additional bit of noise. The goal is to
1674 // pick the smallest epsilon possible. This factor of two proved necessary
1675 // due to unit test behavior on the mac. In the future, as we collect
1676 // more evidence, it may be necessary to increase to more bits. But the need
1677 // should always be demonstrable and not purely theoretical.
1678 constexpr ccd_real_t kEps = 2 * constants<ccd_real_t>::eps();
1679
1680 // Only verify the feature if the nearest feature is an edge.
1681
1682 const ccd_pt_edge_t* const nearest_edge =
1683 reinterpret_cast<ccd_pt_edge_t*>(polytope->nearest);
1684 // Find the outward normals on the two neighbouring faces of the edge, if
1685 // the origin is on the "inner" side of these two faces, then we regard the
1686 // origin to be inside the polytope. Note that these face_normals are
1687 // normalized.
1688 std::array<ccd_vec3_t, 2> face_normals;
1689 std::array<double, 2> origin_to_face_distance;
1690
1691 // We define the plane equation using vertex[0]. If vertex[0] is far away
1692 // from the origin, it can magnify rounding error. We scale epsilon to account
1693 // for this possibility.
1694 const ccd_real_t v0_dist =
1695 std::sqrt(ccdVec3Len2(&nearest_edge->vertex[0]->v.v));
1696 const ccd_real_t plane_threshold =
1697 kEps * std::max(static_cast<ccd_real_t>(1.0), v0_dist);
1698
1699 for (int i = 0; i < 2; ++i) {
1700 face_normals[i] =
1701 faceNormalPointingOutward(polytope, nearest_edge->faces[i]);
1702 ccdVec3Normalize(&face_normals[i]);
1703 // If the origin o is on the "inner" side of the face, then
1704 // n̂ ⋅ (o - vₑ) ≤ 0 or, with simplification, -n̂ ⋅ vₑ ≤ 0 (since n̂ ⋅ o = 0).
1705 origin_to_face_distance[i] =
1706 -ccdVec3Dot(&face_normals[i], &nearest_edge->vertex[0]->v.v);
1707 // If the origin lies *on* the edge, then it also lies on the two adjacent
1708 // faces. Rather than failing on strictly *positive* signed distance, we
1709 // introduce an epsilon threshold. This usage of epsilon is to account for a
1710 // discrepancy in the signed distance computation. How GJK (and partially
1711 // EPA) compute the signed distance from origin to face may *not* be exactly
1712 // the same as done in this test (i.e. for a given set of vertices, the
1713 // plane equation can be defined various ways. Those ways are
1714 // *mathematically* equivalent but numerically will differ due to rounding).
1715 // We account for those differences by allowing a very small positive signed
1716 // distance to be considered zero. We assume that the GJK/EPA code
1717 // ultimately classifies inside/outside around *zero* and *not* epsilon.
1718 if (origin_to_face_distance[i] > plane_threshold) {
1719 FCL_THROW_FAILED_AT_THIS_CONFIGURATION(
1720 "The origin is outside of the polytope. This should already have "
1721 "been identified as separating.");
1722 }
1723 }
1724
1725 // We know the reported squared distance to the edge. If that distance is
1726 // functionally zero, then the edge must *truly* be the nearest feature.
1727 // If it isn't, then it must be one of the adjacent faces.
1728 const bool is_edge_closest_feature = nearest_edge->dist < kEps * kEps;
1729
1730 if (!is_edge_closest_feature) {
1731 // We assume that libccd is not crazily wrong. Although the closest
1732 // feature is not the edge, it is near that edge. Hence we select the
1733 // neighboring face that is closest to the origin.
1734 polytope->nearest_type = CCD_PT_FACE;
1735 // Note origin_to_face_distance is the *signed* distance and it is
1736 // guaranteed to be negative if we are here, hence sense of this
1737 // comparison is reversed.
1738 const int closest_face =
1739 origin_to_face_distance[0] < origin_to_face_distance[1] ? 1 : 0;
1740 polytope->nearest =
1741 reinterpret_cast<ccd_pt_el_t*>(nearest_edge->faces[closest_face]);
1742 // polytope->nearest_dist stores the SQUARED distance.
1743 polytope->nearest_dist = pow(origin_to_face_distance[closest_face], 2);
1744 }
1745 }
1746
__ccdEPA(const void * obj1,const void * obj2,const ccd_t * ccd,ccd_simplex_t * simplex,ccd_pt_t * polytope,ccd_pt_el_t ** nearest)1747 static int __ccdEPA(const void *obj1, const void *obj2,
1748 const ccd_t *ccd,
1749 ccd_simplex_t* simplex,
1750 ccd_pt_t *polytope, ccd_pt_el_t **nearest)
1751 {
1752 ccd_support_t supp; // support point
1753 int ret, size;
1754
1755
1756 ret = 0;
1757 *nearest = NULL;
1758
1759 // transform simplex to polytope - simplex won't be used anymore
1760 size = ccdSimplexSize(simplex);
1761 if (size == 4){
1762 ret = simplexToPolytope4(obj1, obj2, ccd, simplex, polytope, nearest);
1763 } else if (size == 3) {
1764 ret = convert2SimplexToTetrahedron(obj1, obj2, ccd, simplex, polytope,
1765 nearest);
1766 }else{ // size == 2
1767 ret = simplexToPolytope2(obj1, obj2, ccd, simplex, polytope, nearest);
1768 }
1769
1770
1771 if (ret == -1){
1772 // touching contact
1773 return 0;
1774 }else if (ret == -2){
1775 // failed memory allocation
1776 return -2;
1777 }
1778
1779 while (1) {
1780 // get triangle nearest to origin
1781 *nearest = ccdPtNearest(polytope);
1782 if (polytope->nearest_type == CCD_PT_EDGE) {
1783 // When libccd thinks the nearest feature is an edge, that is often
1784 // wrong, hence we validate the nearest feature by ourselves.
1785 // TODO remove this validation step when we can reliably compute the
1786 // nearest feature of a polytope.
1787 validateNearestFeatureOfPolytopeBeingEdge(polytope);
1788 *nearest = ccdPtNearest(polytope);
1789 }
1790
1791 // get next support point
1792 if (nextSupport(polytope, obj1, obj2, ccd, *nearest, &supp) != 0) {
1793 break;
1794 }
1795
1796 // expand nearest triangle using new point - supp
1797 if (expandPolytope(polytope, *nearest, &supp) != 0) return -2;
1798 }
1799
1800 return 0;
1801 }
1802
1803 /** Given a single support point, `q`, extract the point `p1` and `p2`, the
1804 points on object 1 and 2, respectively, in the support data of `q`. */
extractObjectPointsFromPoint(ccd_support_t * q,ccd_vec3_t * p1,ccd_vec3_t * p2)1805 static void extractObjectPointsFromPoint(ccd_support_t *q, ccd_vec3_t *p1,
1806 ccd_vec3_t *p2) {
1807 // TODO(SeanCurtis-TRI): Determine if I should be demanding that p1 and p2
1808 // are defined.
1809 // Closest points are the ones stored in the simplex
1810 if (p1) *p1 = q->v1;
1811 if (p2) *p2 = q->v2;
1812 }
1813
1814 /** Given two support points which define a line segment (`a` and `b`), and a
1815 point on that line segment `p`, computes the points `p1` and `p2`, the points
1816 on object 1 and 2, respectively, in the support data which correspond to `p`.
1817 @pre `p = a + s(b - a), 0 <= s <= 1` */
extractObjectPointsFromSegment(ccd_support_t * a,ccd_support_t * b,ccd_vec3_t * p1,ccd_vec3_t * p2,ccd_vec3_t * p)1818 static void extractObjectPointsFromSegment(ccd_support_t *a, ccd_support_t *b,
1819 ccd_vec3_t *p1, ccd_vec3_t *p2,
1820 ccd_vec3_t *p) {
1821 // Closest points lie on the segment defined by the points in the simplex
1822 // Let the segment be defined by points A and B. We can write p as
1823 //
1824 // p = A + s*AB, 0 <= s <= 1
1825 // p - A = s*AB
1826 ccd_vec3_t AB;
1827 ccdVec3Sub2(&AB, &(b->v), &(a->v));
1828
1829 // This defines three equations, but we only need one. Taking the i-th
1830 // component gives
1831 //
1832 // p_i - A_i = s*AB_i.
1833 //
1834 // Thus, s is given by
1835 //
1836 // s = (p_i - A_i)/AB_i.
1837 //
1838 // To avoid dividing by an AB_i ≪ 1, we choose i such that |AB_i| is
1839 // maximized
1840 ccd_real_t abs_AB_x{std::abs(ccdVec3X(&AB))};
1841 ccd_real_t abs_AB_y{std::abs(ccdVec3Y(&AB))};
1842 ccd_real_t abs_AB_z{std::abs(ccdVec3Z(&AB))};
1843
1844 ccd_real_t A_i, AB_i, p_i;
1845 if (abs_AB_x >= abs_AB_y && abs_AB_x >= abs_AB_z) {
1846 A_i = ccdVec3X(&(a->v));
1847 AB_i = ccdVec3X(&AB);
1848 p_i = ccdVec3X(p);
1849 } else if (abs_AB_y >= abs_AB_z) {
1850 A_i = ccdVec3Y(&(a->v));
1851 AB_i = ccdVec3Y(&AB);
1852 p_i = ccdVec3Y(p);
1853 } else {
1854 A_i = ccdVec3Z(&(a->v));
1855 AB_i = ccdVec3Z(&AB);
1856 p_i = ccdVec3Z(p);
1857 }
1858
1859 if (std::abs(AB_i) < constants<ccd_real_t>::eps()) {
1860 // Points are coincident; treat as a single point.
1861 extractObjectPointsFromPoint(a, p1, p2);
1862 return;
1863 }
1864
1865 auto calc_p = [](ccd_vec3_t *p_a, ccd_vec3_t *p_b, ccd_vec3_t *p,
1866 ccd_real_t s) {
1867 ccd_vec3_t sAB;
1868 ccdVec3Sub2(&sAB, p_b, p_a);
1869 ccdVec3Scale(&sAB, s);
1870 ccdVec3Copy(p, p_a);
1871 ccdVec3Add(p, &sAB);
1872 };
1873
1874 // TODO(SeanCurtis-TRI): If p1 or p2 is null, there seems little point in
1875 // calling this method. It seems that both of these being non-null should be
1876 // a *requirement*. Determine that this is the case and do so.
1877 ccd_real_t s = (p_i - A_i) / AB_i;
1878
1879 if (p1) {
1880 // p1 = A1 + s*A1B1
1881 calc_p(&(a->v1), &(b->v1), p1, s);
1882 }
1883 if (p2) {
1884 // p2 = A2 + s*A2B2
1885 calc_p(&(a->v2), &(b->v2), p2, s);
1886 }
1887 }
1888
1889 /** Returns the points `p1` and `p2` on the original shapes that correspond to
1890 point `p` in the given simplex.
1891 @pre simplex size <= 3.
1892 @pre p lies _on_ the simplex (i.e., within the triangle, line segment, or is
1893 coincident with the point). */
extractClosestPoints(ccd_simplex_t * simplex,ccd_vec3_t * p1,ccd_vec3_t * p2,ccd_vec3_t * p)1894 static void extractClosestPoints(ccd_simplex_t *simplex, ccd_vec3_t *p1,
1895 ccd_vec3_t *p2, ccd_vec3_t *p) {
1896 const int simplex_size = ccdSimplexSize(simplex);
1897 assert(simplex_size <= 3);
1898 if (simplex_size == 1)
1899 {
1900 extractObjectPointsFromPoint(&simplex->ps[0], p1, p2);
1901 }
1902 else if (simplex_size == 2)
1903 {
1904 extractObjectPointsFromSegment(&simplex->ps[0], &simplex->ps[1], p1, p2, p);
1905 }
1906 else // simplex_size == 3
1907 {
1908 if (triangle_area_is_zero(simplex->ps[0].v, simplex->ps[1].v,
1909 simplex->ps[2].v)) {
1910 // The triangle is degenerate; compute the nearest point to a line
1911 // segment. The segment is defined by the most-distant vertex pair.
1912 int a_index, b_index;
1913 ccd_vec3_t AB, AC, BC;
1914 ccdVec3Sub2(&AB, &(simplex->ps[1].v), &(simplex->ps[0].v));
1915 ccdVec3Sub2(&AC, &(simplex->ps[2].v), &(simplex->ps[0].v));
1916 ccdVec3Sub2(&BC, &(simplex->ps[2].v), &(simplex->ps[1].v));
1917 ccd_real_t AB_len2 = ccdVec3Len2(&AB);
1918 ccd_real_t AC_len2 = ccdVec3Len2(&AC);
1919 ccd_real_t BC_len2 = ccdVec3Len2(&BC);
1920 if (AB_len2 >= AC_len2 && AB_len2 >= BC_len2) {
1921 a_index = 0;
1922 b_index = 1;
1923 } else if (AC_len2 >= AB_len2 && AC_len2 >= BC_len2) {
1924 a_index = 0;
1925 b_index = 2;
1926 } else {
1927 a_index = 1;
1928 b_index = 2;
1929 }
1930 extractObjectPointsFromSegment(&simplex->ps[a_index],
1931 &simplex->ps[b_index], p1, p2, p);
1932 return;
1933 }
1934
1935 // Compute the barycentric coordinates of point p in triangle ABC.
1936 //
1937 // A
1938 // ╱╲ p = αA + βB + γC
1939 // ╱ |╲
1940 // ╱ | ╲ α = 1 - β - γ
1941 // ╱ p | ╲ β = AREA(pAC) / AREA(ABC)
1942 // ╱ / \ ╲ γ = AREA(pAB) / AREA(ABC)
1943 // ╱__/_____\_╲
1944 // B C AREA(XYZ) = |r_XY × r_XZ| / 2
1945 //
1946 // Rewrite coordinates in terms of cross products.
1947 //
1948 // β = AREA(pAC) / AREA(ABC) = |r_Ap × r_AC| / |r_AB × r_AC|
1949 // γ = AREA(pAB) / AREA(ABC) = |r_AB × r_Ap| / |r_AB × r_AC|
1950 //
1951 // NOTE: There are multiple options for the cross products, these have been
1952 // selected to re-use as many symbols as possible.
1953 //
1954 // Solving for β and γ:
1955 //
1956 // β = |r_Ap × r_AC| / |r_AB × r_AC|
1957 // β = |r_Ap × r_AC| / |n| n ≙ r_AB × r_AC, n̂ = n / |n|
1958 // β = n̂·(r_Ap × r_AC) / n̂·n This step arises from the fact
1959 // that (r_Ap × r_AC) and n point
1960 // in the same direction. It
1961 // allows us to take a single sqrt
1962 // instead of three.
1963 // β = (n/|n|)·(r_Ap × r_AC) / (n/|n|)·n
1964 // β = n·(r_Ap × r_AC) / n·n
1965 // β = n·(r_Ap × r_AC) / |n|²
1966 //
1967 // A similar process to solve for gamma
1968 // γ = n·(r_AB × r_Ap) / |n|²
1969
1970 // Compute n and |n|².
1971 ccd_vec3_t r_AB, r_AC, n;
1972 ccdVec3Sub2(&r_AB, &(simplex->ps[1].v), &(simplex->ps[0].v));
1973 ccdVec3Sub2(&r_AC, &(simplex->ps[2].v), &(simplex->ps[0].v));
1974 ccdVec3Cross(&n, &r_AB, &r_AC);
1975 ccd_real_t norm_squared_n{ccdVec3Len2(&n)};
1976
1977 // Compute r_Ap.
1978 ccd_vec3_t r_Ap;
1979 ccdVec3Sub2(&r_Ap, p, &(simplex->ps[0].v));
1980
1981 // Compute the cross products in the numerators.
1982 ccd_vec3_t r_Ap_cross_r_AC, r_AB_cross_r_Ap;
1983 ccdVec3Cross(&r_Ap_cross_r_AC, &r_Ap, &r_AC); // r_Ap × r_AC
1984 ccdVec3Cross(&r_AB_cross_r_Ap, &r_AB, &r_Ap); // r_AB × r_Ap
1985
1986 // Compute beta and gamma.
1987 ccd_real_t beta{ccdVec3Dot(&n, &r_Ap_cross_r_AC) / norm_squared_n};
1988 ccd_real_t gamma{ccdVec3Dot(&n, &r_AB_cross_r_Ap) / norm_squared_n};
1989
1990 // Evaluate barycentric interpolation (with the locally defined barycentric
1991 // coordinates).
1992 auto interpolate = [&beta, &gamma](const ccd_vec3_t& r_WA,
1993 const ccd_vec3_t& r_WB,
1994 const ccd_vec3_t& r_WC,
1995 ccd_vec3_t* r_WP) {
1996 // r_WP = r_WA + β * r_AB + γ * r_AC
1997 ccdVec3Copy(r_WP, &r_WA);
1998
1999 ccd_vec3_t beta_r_AB;
2000 ccdVec3Sub2(&beta_r_AB, &r_WB, &r_WA);
2001 ccdVec3Scale(&beta_r_AB, beta);
2002 ccdVec3Add(r_WP, &beta_r_AB);
2003
2004 ccd_vec3_t gamma_r_AC;
2005 ccdVec3Sub2(&gamma_r_AC, &r_WC, &r_WA);
2006 ccdVec3Scale(&gamma_r_AC, gamma);
2007 ccdVec3Add(r_WP, &gamma_r_AC);
2008 };
2009
2010 if (p1) {
2011 interpolate(simplex->ps[0].v1, simplex->ps[1].v1, simplex->ps[2].v1, p1);
2012 }
2013
2014 if (p2) {
2015 interpolate(simplex->ps[0].v2, simplex->ps[1].v2, simplex->ps[2].v2, p2);
2016 }
2017 }
2018 }
2019
2020 // Computes the distance between two non-penetrating convex objects, `obj1` and
2021 // `obj2` based on the warm-started witness simplex, returning the distance and
2022 // nearest points on each object.
2023 // @param obj1 The first convex object.
2024 // @param obj2 The second convex object.
2025 // @param ccd The libccd configuration.
2026 // @param simplex A witness to the objects' separation generated by the GJK
2027 // algorithm. NOTE: the simplex is not necessarily sufficiently refined to
2028 // report the actual distance and may be further refined in this method.
2029 // @param p1 If the objects are non-penetrating, the point on the surface of
2030 // obj1 closest to obj2 (expressed in the world frame).
2031 // @param p2 If the objects are non-penetrating, the point on the surface of
2032 // obj2 closest to obj1 (expressed in the world frame).
2033 // @returns The minimum distance between the two objects. If they are
2034 // penetrating, -1 is returned.
_ccdDist(const void * obj1,const void * obj2,const ccd_t * ccd,ccd_simplex_t * simplex,ccd_vec3_t * p1,ccd_vec3_t * p2)2035 static inline ccd_real_t _ccdDist(const void *obj1, const void *obj2,
2036 const ccd_t *ccd,
2037 ccd_simplex_t* simplex,
2038 ccd_vec3_t* p1, ccd_vec3_t* p2)
2039 {
2040 ccd_real_t last_dist = CCD_REAL_MAX;
2041
2042 for (unsigned long iterations = 0UL; iterations < ccd->max_iterations;
2043 ++iterations) {
2044 ccd_vec3_t closest_p; // The point on the simplex that is closest to the
2045 // origin.
2046 ccd_real_t dist;
2047 // get a next direction vector
2048 // we are trying to find out a point on the minkowski difference
2049 // that is nearest to the origin, so we obtain a point on the
2050 // simplex that is nearest and try to exapand the simplex towards
2051 // the origin
2052 if (ccdSimplexSize(simplex) == 1)
2053 {
2054 ccdVec3Copy(&closest_p, &ccdSimplexPoint(simplex, 0)->v);
2055 dist = ccdVec3Len2(&ccdSimplexPoint(simplex, 0)->v);
2056 dist = CCD_SQRT(dist);
2057 }
2058 else if (ccdSimplexSize(simplex) == 2)
2059 {
2060 dist = ccdVec3PointSegmentDist2(ccd_vec3_origin,
2061 &ccdSimplexPoint(simplex, 0)->v,
2062 &ccdSimplexPoint(simplex, 1)->v,
2063 &closest_p);
2064 dist = CCD_SQRT(dist);
2065 }
2066 else if (ccdSimplexSize(simplex) == 3)
2067 {
2068 dist = ccdVec3PointTriDist2(ccd_vec3_origin,
2069 &ccdSimplexPoint(simplex, 0)->v,
2070 &ccdSimplexPoint(simplex, 1)->v,
2071 &ccdSimplexPoint(simplex, 2)->v,
2072 &closest_p);
2073 dist = CCD_SQRT(dist);
2074 }
2075 else
2076 { // ccdSimplexSize(&simplex) == 4
2077 dist = simplexReduceToTriangle(simplex, last_dist, &closest_p);
2078 }
2079
2080 // check whether we improved for at least a minimum tolerance
2081 if ((last_dist - dist) < ccd->dist_tolerance)
2082 {
2083 extractClosestPoints(simplex, p1, p2, &closest_p);
2084 return dist;
2085 }
2086
2087 // point direction towards the origin
2088 ccd_vec3_t dir; // direction vector
2089 ccdVec3Copy(&dir, &closest_p);
2090 ccdVec3Scale(&dir, -CCD_ONE);
2091 ccdVec3Normalize(&dir);
2092
2093 // find out support point
2094 ccd_support_t last; // last support point
2095 __ccdSupport(obj1, obj2, &dir, ccd, &last);
2096
2097 // record last distance
2098 last_dist = dist;
2099
2100 // check whether we improved for at least a minimum tolerance
2101 // this is here probably only for a degenerate cases when we got a
2102 // point that is already in the simplex
2103 dist = ccdVec3Len2(&last.v);
2104 dist = CCD_SQRT(dist);
2105 if (CCD_FABS(last_dist - dist) < ccd->dist_tolerance)
2106 {
2107 extractClosestPoints(simplex, p1, p2, &closest_p);
2108 return last_dist;
2109 }
2110
2111 // add a point to simplex
2112 ccdSimplexAdd(simplex, &last);
2113 }
2114
2115 return -CCD_REAL(1.);
2116 }
2117
2118 /**
2119 * Given the nearest point on the polytope inside the Minkowski difference
2120 * A ⊖ B, returns the point p1 on geometric object A and p2 on geometric object
2121 * B, such that p1 is the deepest penetration point on A, and p2 is the deepest
2122 * penetration point on B.
2123 * @param[in] nearest The feature with the point that is nearest to the origin
2124 * on the boundary of the polytope.
2125 * @param[out] p1 the deepest penetration point on A, measured and expressed in
2126 * the world frame.
2127 * @param[out] p2 the deepest penetration point on B, measured and expressed in
2128 * the world frame.
2129 * @retval status Return 0 on success, and -1 on failure.
2130 */
penEPAPosClosest(const ccd_pt_el_t * nearest,ccd_vec3_t * p1,ccd_vec3_t * p2)2131 static int penEPAPosClosest(const ccd_pt_el_t* nearest, ccd_vec3_t* p1,
2132 ccd_vec3_t* p2) {
2133 // We reconstruct the simplex on which the nearest point lives, and then
2134 // compute the deepest penetration point on each geometric objects. Note that
2135 // the reconstructed simplex has size up to 3 (at most 3 vertices).
2136 if (nearest->type == CCD_PT_VERTEX) {
2137 ccd_pt_vertex_t* v = (ccd_pt_vertex_t*)nearest;
2138 ccdVec3Copy(p1, &v->v.v1);
2139 ccdVec3Copy(p2, &v->v.v2);
2140 return 0;
2141 } else {
2142 ccd_simplex_t s;
2143 ccdSimplexInit(&s);
2144 if (nearest->type == CCD_PT_EDGE) {
2145 const ccd_pt_edge_t* e = reinterpret_cast<const ccd_pt_edge_t*>(nearest);
2146 ccdSimplexAdd(&s, &(e->vertex[0]->v));
2147 ccdSimplexAdd(&s, &(e->vertex[1]->v));
2148 } else if (nearest->type == CCD_PT_FACE) {
2149 const ccd_pt_face_t* f = reinterpret_cast<const ccd_pt_face_t*>(nearest);
2150 // The face triangle has three edges, each edge consists of two end
2151 // points, so there are 6 end points in total, each vertex of the triangle
2152 // appears twice among the 6 end points. We need to choose the three
2153 // distinctive vertices out of these 6 end points.
2154 // First we pick edge0, the two end points of edge0 are distinct.
2155 ccdSimplexAdd(&s, &(f->edge[0]->vertex[0]->v));
2156 ccdSimplexAdd(&s, &(f->edge[0]->vertex[1]->v));
2157 // Next we pick edge1, one of the two end points on edge1 is distinct from
2158 // the end points in edge0, we will add this distinct vertex to the
2159 // simplex.
2160 for (int i = 0; i < 2; ++i) {
2161 ccd_pt_vertex_t* third_vertex = f->edge[1]->vertex[i];
2162 if (third_vertex != f->edge[0]->vertex[0] &&
2163 third_vertex != f->edge[0]->vertex[1]) {
2164 ccdSimplexAdd(&s, &(third_vertex->v));
2165 break;
2166 }
2167 }
2168 } else {
2169 throw std::logic_error(
2170 "FCL penEPAPosClosest(): Unsupported feature type. The closest point "
2171 "should be either a vertex, on an edge, or on a face.");
2172 }
2173 // Now compute the closest point in the simplex.
2174 // TODO(hongkai.dai@tri.global): we do not need to compute the closest point
2175 // on the simplex, as that is already given in `nearest`. We only need to
2176 // extract the deepest penetration points on each geometric object.
2177 // Sean.Curtis@tri.global and I will refactor this code in the future, to
2178 // avoid calling extractClosestPoints.
2179 ccd_vec3_t p;
2180 ccdVec3Copy(&p, &(nearest->witness));
2181 extractClosestPoints(&s, p1, p2, &p);
2182 return 0;
2183 }
2184 }
2185
ccdGJKSignedDist(const void * obj1,const void * obj2,const ccd_t * ccd,ccd_vec3_t * p1,ccd_vec3_t * p2)2186 static inline ccd_real_t ccdGJKSignedDist(const void* obj1, const void* obj2,
2187 const ccd_t* ccd, ccd_vec3_t* p1,
2188 ccd_vec3_t* p2)
2189 {
2190 ccd_simplex_t simplex;
2191
2192 if (__ccdGJK(obj1, obj2, ccd, &simplex) == 0) // in collision, then using the EPA
2193 {
2194 ccd_pt_t polytope;
2195 ccd_pt_el_t *nearest;
2196 ccd_real_t depth;
2197
2198 ccdPtInit(&polytope);
2199 int ret = __ccdEPA(obj1, obj2, ccd, &simplex, &polytope, &nearest);
2200 if (ret == 0 && nearest)
2201 {
2202 depth = -CCD_SQRT(nearest->dist);
2203
2204 ccd_vec3_t pos1, pos2;
2205 penEPAPosClosest(nearest, &pos1, &pos2);
2206
2207 if (p1) *p1 = pos1;
2208 if (p2) *p2 = pos2;
2209
2210 //ccd_vec3_t dir; // direction vector
2211 //ccdVec3Copy(&dir, &nearest->witness);
2212 //std::cout << dir.v[0] << " " << dir.v[1] << " " << dir.v[2] << std::endl;
2213 //ccd_support_t last;
2214 //__ccdSupport(obj1, obj2, &dir, ccd, &last);
2215
2216 //if (p1) *p1 = last.v1;
2217 //if (p2) *p2 = last.v2;
2218 }
2219 else
2220 {
2221 depth = -CCD_ONE;
2222 }
2223
2224 ccdPtDestroy(&polytope);
2225
2226 return depth;
2227 }
2228 else // not in collision
2229 {
2230 return _ccdDist(obj1, obj2, ccd, &simplex, p1, p2);
2231 }
2232 }
2233
2234
2235 // Computes the distance between two non-penetrating convex objects, `obj1` and
2236 // `obj2`, returning the distance and
2237 // nearest points on each object.
2238 // @param obj1 The first convex object.
2239 // @param obj2 The second convex object.
2240 // @param ccd The libccd configuration.
2241 // @param p1 If the objects are non-penetrating, the point on the surface of
2242 // obj1 closest to obj2 (expressed in the world frame).
2243 // @param p2 If the objects are non-penetrating, the point on the surface of
2244 // obj2 closest to obj1 (expressed in the world frame).
2245 // @returns The minimum distance between the two objects. If they are
2246 // penetrating, -1 is returned.
2247 // @note Unlike _ccdDist function, this function does not need a warm-started
2248 // simplex as the input argument.
ccdGJKDist2(const void * obj1,const void * obj2,const ccd_t * ccd,ccd_vec3_t * p1,ccd_vec3_t * p2)2249 static inline ccd_real_t ccdGJKDist2(const void *obj1, const void *obj2,
2250 const ccd_t *ccd, ccd_vec3_t* p1,
2251 ccd_vec3_t* p2)
2252 {
2253 ccd_simplex_t simplex;
2254 // first find an intersection
2255 if (__ccdGJK(obj1, obj2, ccd, &simplex) == 0)
2256 return -CCD_ONE;
2257
2258 return _ccdDist(obj1, obj2, ccd, &simplex, p1, p2);
2259 }
2260
2261 } // namespace libccd_extension
2262
2263 /** Basic shape to ccd shape */
2264 template <typename S>
shapeToGJK(const ShapeBase<S> & s,const Transform3<S> & tf,ccd_obj_t * o)2265 static void shapeToGJK(const ShapeBase<S>& s, const Transform3<S>& tf,
2266 ccd_obj_t* o)
2267 {
2268 FCL_UNUSED(s);
2269
2270 const Quaternion<S> q(tf.linear());
2271 const Vector3<S>& T = tf.translation();
2272 ccdVec3Set(&o->pos, T[0], T[1], T[2]);
2273 ccdQuatSet(&o->rot, q.x(), q.y(), q.z(), q.w());
2274 ccdQuatInvert2(&o->rot_inv, &o->rot);
2275 }
2276
2277 template <typename S>
boxToGJK(const Box<S> & s,const Transform3<S> & tf,ccd_box_t * box)2278 static void boxToGJK(const Box<S>& s, const Transform3<S>& tf, ccd_box_t* box)
2279 {
2280 shapeToGJK(s, tf, box);
2281 box->dim[0] = s.side[0] / 2.0;
2282 box->dim[1] = s.side[1] / 2.0;
2283 box->dim[2] = s.side[2] / 2.0;
2284 }
2285
2286 template <typename S>
capToGJK(const Capsule<S> & s,const Transform3<S> & tf,ccd_cap_t * cap)2287 static void capToGJK(const Capsule<S>& s, const Transform3<S>& tf,
2288 ccd_cap_t* cap)
2289 {
2290 shapeToGJK(s, tf, cap);
2291 cap->radius = s.radius;
2292 cap->height = s.lz / 2;
2293 }
2294
2295 template <typename S>
cylToGJK(const Cylinder<S> & s,const Transform3<S> & tf,ccd_cyl_t * cyl)2296 static void cylToGJK(const Cylinder<S>& s, const Transform3<S>& tf,
2297 ccd_cyl_t* cyl)
2298 {
2299 shapeToGJK(s, tf, cyl);
2300 cyl->radius = s.radius;
2301 cyl->height = s.lz / 2;
2302 }
2303
2304 template <typename S>
coneToGJK(const Cone<S> & s,const Transform3<S> & tf,ccd_cone_t * cone)2305 static void coneToGJK(const Cone<S>& s, const Transform3<S>& tf,
2306 ccd_cone_t* cone)
2307 {
2308 shapeToGJK(s, tf, cone);
2309 cone->radius = s.radius;
2310 cone->height = s.lz / 2;
2311 }
2312
2313 template <typename S>
sphereToGJK(const Sphere<S> & s,const Transform3<S> & tf,ccd_sphere_t * sph)2314 static void sphereToGJK(const Sphere<S>& s, const Transform3<S>& tf,
2315 ccd_sphere_t* sph)
2316 {
2317 shapeToGJK(s, tf, sph);
2318 sph->radius = s.radius;
2319 }
2320
2321 template <typename S>
ellipsoidToGJK(const Ellipsoid<S> & s,const Transform3<S> & tf,ccd_ellipsoid_t * ellipsoid)2322 static void ellipsoidToGJK(const Ellipsoid<S>& s, const Transform3<S>& tf,
2323 ccd_ellipsoid_t* ellipsoid)
2324 {
2325 shapeToGJK(s, tf, ellipsoid);
2326 ellipsoid->radii[0] = s.radii[0];
2327 ellipsoid->radii[1] = s.radii[1];
2328 ellipsoid->radii[2] = s.radii[2];
2329 }
2330
2331 template <typename S>
convexToGJK(const Convex<S> & s,const Transform3<S> & tf,ccd_convex_t<S> * conv)2332 static void convexToGJK(const Convex<S>& s, const Transform3<S>& tf,
2333 ccd_convex_t<S>* conv)
2334 {
2335 shapeToGJK(s, tf, conv);
2336 conv->convex = &s;
2337 }
2338
2339 /** Support functions */
supportBox(const void * obj,const ccd_vec3_t * dir_,ccd_vec3_t * v)2340 static inline void supportBox(const void* obj, const ccd_vec3_t* dir_,
2341 ccd_vec3_t* v)
2342 {
2343 // Use a customized sign function, so that the support of the box always
2344 // appears in one of the box vertices.
2345 // Picking support vertices on the interior of faces/edges can lead to
2346 // degenerate triangles in the EPA algorithm and are no more correct than just
2347 // picking box corners.
2348 auto sign = [](ccd_real_t x) -> ccd_real_t {
2349 return x >= 0 ? ccd_real_t(1.0) : ccd_real_t(-1.0);
2350 };
2351 const ccd_box_t* o = static_cast<const ccd_box_t*>(obj);
2352 ccd_vec3_t dir;
2353 ccdVec3Copy(&dir, dir_);
2354 ccdQuatRotVec(&dir, &o->rot_inv);
2355 ccdVec3Set(v, sign(ccdVec3X(&dir)) * o->dim[0],
2356 sign(ccdVec3Y(&dir)) * o->dim[1],
2357 sign(ccdVec3Z(&dir)) * o->dim[2]);
2358 ccdQuatRotVec(v, &o->rot);
2359 ccdVec3Add(v, &o->pos);
2360 }
2361
supportCap(const void * obj,const ccd_vec3_t * dir_,ccd_vec3_t * v)2362 static inline void supportCap(const void* obj, const ccd_vec3_t* dir_,
2363 ccd_vec3_t* v)
2364 {
2365 const ccd_cap_t* o = static_cast<const ccd_cap_t*>(obj);
2366 ccd_vec3_t dir, pos1, pos2;
2367
2368 ccdVec3Copy(&dir, dir_);
2369 ccdQuatRotVec(&dir, &o->rot_inv);
2370
2371 ccdVec3Set(&pos1, CCD_ZERO, CCD_ZERO, o->height);
2372 ccdVec3Set(&pos2, CCD_ZERO, CCD_ZERO, -o->height);
2373
2374 ccdVec3Copy(v, &dir);
2375 ccdVec3Normalize (v);
2376 ccdVec3Scale(v, o->radius);
2377 ccdVec3Add(&pos1, v);
2378 ccdVec3Add(&pos2, v);
2379
2380 if (ccdVec3Z (&dir) > 0)
2381 ccdVec3Copy(v, &pos1);
2382 else
2383 ccdVec3Copy(v, &pos2);
2384
2385 // transform support vertex
2386 ccdQuatRotVec(v, &o->rot);
2387 ccdVec3Add(v, &o->pos);
2388 }
2389
supportCyl(const void * obj,const ccd_vec3_t * dir_,ccd_vec3_t * v)2390 static inline void supportCyl(const void* obj, const ccd_vec3_t* dir_,
2391 ccd_vec3_t* v)
2392 {
2393 const ccd_cyl_t* cyl = static_cast<const ccd_cyl_t*>(obj);
2394 ccd_vec3_t dir;
2395 double zdist, rad;
2396
2397 ccdVec3Copy(&dir, dir_);
2398 ccdQuatRotVec(&dir, &cyl->rot_inv);
2399
2400 zdist = dir.v[0] * dir.v[0] + dir.v[1] * dir.v[1];
2401 zdist = sqrt(zdist);
2402 if (ccdIsZero(zdist))
2403 ccdVec3Set(v, 0., 0., ccdSign(ccdVec3Z(&dir)) * cyl->height);
2404 else
2405 {
2406 rad = cyl->radius / zdist;
2407
2408 ccdVec3Set(v, rad * ccdVec3X(&dir),
2409 rad * ccdVec3Y(&dir),
2410 ccdSign(ccdVec3Z(&dir)) * cyl->height);
2411 }
2412
2413 // transform support vertex
2414 ccdQuatRotVec(v, &cyl->rot);
2415 ccdVec3Add(v, &cyl->pos);
2416 }
2417
supportCone(const void * obj,const ccd_vec3_t * dir_,ccd_vec3_t * v)2418 static inline void supportCone(const void* obj, const ccd_vec3_t* dir_,
2419 ccd_vec3_t* v)
2420 {
2421 const ccd_cone_t* cone = static_cast<const ccd_cone_t*>(obj);
2422 ccd_vec3_t dir;
2423
2424 ccdVec3Copy(&dir, dir_);
2425 ccdQuatRotVec(&dir, &cone->rot_inv);
2426
2427 double zdist, len, rad;
2428 zdist = dir.v[0] * dir.v[0] + dir.v[1] * dir.v[1];
2429 len = zdist + dir.v[2] * dir.v[2];
2430 zdist = sqrt(zdist);
2431 len = sqrt(len);
2432
2433 double sin_a = cone->radius / sqrt(cone->radius * cone->radius + 4 * cone->height * cone->height);
2434
2435 if (dir.v[2] > len * sin_a)
2436 ccdVec3Set(v, 0., 0., cone->height);
2437 else if (zdist > 0)
2438 {
2439 rad = cone->radius / zdist;
2440 ccdVec3Set(v, rad * ccdVec3X(&dir), rad * ccdVec3Y(&dir), -cone->height);
2441 }
2442 else
2443 ccdVec3Set(v, 0, 0, -cone->height);
2444
2445 // transform support vertex
2446 ccdQuatRotVec(v, &cone->rot);
2447 ccdVec3Add(v, &cone->pos);
2448 }
2449
supportSphere(const void * obj,const ccd_vec3_t * dir_,ccd_vec3_t * v)2450 static inline void supportSphere(const void* obj, const ccd_vec3_t* dir_,
2451 ccd_vec3_t* v)
2452 {
2453 const ccd_sphere_t* s = static_cast<const ccd_sphere_t*>(obj);
2454 ccd_vec3_t dir;
2455
2456 ccdVec3Copy(&dir, dir_);
2457 ccdQuatRotVec(&dir, &s->rot_inv);
2458
2459 ccdVec3Copy(v, &dir);
2460 ccdVec3Scale(v, s->radius);
2461 ccdVec3Scale(v, CCD_ONE / CCD_SQRT(ccdVec3Len2(&dir)));
2462
2463 // transform support vertex
2464 ccdQuatRotVec(v, &s->rot);
2465 ccdVec3Add(v, &s->pos);
2466 }
2467
supportEllipsoid(const void * obj,const ccd_vec3_t * dir_,ccd_vec3_t * v)2468 static inline void supportEllipsoid(const void* obj, const ccd_vec3_t* dir_,
2469 ccd_vec3_t* v)
2470 {
2471 const ccd_ellipsoid_t* s = static_cast<const ccd_ellipsoid_t*>(obj);
2472 ccd_vec3_t dir;
2473
2474 ccdVec3Copy(&dir, dir_);
2475 ccdQuatRotVec(&dir, &s->rot_inv);
2476
2477 ccd_vec3_t abc2;
2478 abc2.v[0] = s->radii[0] * s->radii[0];
2479 abc2.v[1] = s->radii[1] * s->radii[1];
2480 abc2.v[2] = s->radii[2] * s->radii[2];
2481
2482 v->v[0] = abc2.v[0] * dir.v[0];
2483 v->v[1] = abc2.v[1] * dir.v[1];
2484 v->v[2] = abc2.v[2] * dir.v[2];
2485
2486 ccdVec3Scale(v, CCD_ONE / CCD_SQRT(ccdVec3Dot(v, &dir)));
2487
2488 // transform support vertex
2489 ccdQuatRotVec(v, &s->rot);
2490 ccdVec3Add(v, &s->pos);
2491 }
2492
2493 template <typename S>
supportConvex(const void * obj,const ccd_vec3_t * dir_,ccd_vec3_t * v)2494 static void supportConvex(const void* obj, const ccd_vec3_t* dir_,
2495 ccd_vec3_t* v)
2496 {
2497 const auto* c = (const ccd_convex_t<S>*)obj;
2498
2499 // Transform the support direction vector from the query frame Q to the
2500 // convex mesh's local frame C. I.e., dir_Q -> dir_C.
2501 ccd_vec3_t dir;
2502 ccdVec3Copy(&dir, dir_);
2503 ccdQuatRotVec(&dir, &c->rot_inv);
2504 // Note: The scalar type ccd_real_t is fixed w.r.t. S. That means if S is
2505 // float and ccd_real_t is double, this conversion requires narrowing. To
2506 // avoid warning/errors about implicit narrowing, we explicitly convert.
2507 Vector3<S> dir_C{S(dir.v[0]), S(dir.v[1]), S(dir.v[2])};
2508
2509 // The extremal point E measured and expressed in Frame C.
2510 const Vector3<S>& p_CE = c->convex->findExtremeVertex(dir_C);
2511
2512 // Now measure and express E in the original query frame Q: p_CE -> p_QE.
2513 v->v[0] = p_CE(0);
2514 v->v[1] = p_CE(1);
2515 v->v[2] = p_CE(2);
2516 ccdQuatRotVec(v, &c->rot);
2517 ccdVec3Add(v, &c->pos);
2518 }
2519
supportTriangle(const void * obj,const ccd_vec3_t * dir_,ccd_vec3_t * v)2520 static void supportTriangle(const void* obj, const ccd_vec3_t* dir_,
2521 ccd_vec3_t* v)
2522 {
2523 const ccd_triangle_t* tri = static_cast<const ccd_triangle_t*>(obj);
2524 ccd_vec3_t dir, p;
2525 ccd_real_t maxdot, dot;
2526 int i;
2527
2528 ccdVec3Copy(&dir, dir_);
2529 ccdQuatRotVec(&dir, &tri->rot_inv);
2530
2531 maxdot = -CCD_REAL_MAX;
2532
2533 for (i = 0; i < 3; ++i)
2534 {
2535 ccdVec3Set(&p, tri->p[i].v[0] - tri->c.v[0], tri->p[i].v[1] - tri->c.v[1],
2536 tri->p[i].v[2] - tri->c.v[2]);
2537 dot = ccdVec3Dot(&dir, &p);
2538 if (dot > maxdot)
2539 {
2540 ccdVec3Copy(v, &tri->p[i]);
2541 maxdot = dot;
2542 }
2543 }
2544
2545 // transform support vertex
2546 ccdQuatRotVec(v, &tri->rot);
2547 ccdVec3Add(v, &tri->pos);
2548 }
2549
centerShape(const void * obj,ccd_vec3_t * c)2550 static inline void centerShape(const void* obj, ccd_vec3_t* c)
2551 {
2552 const ccd_obj_t *o = static_cast<const ccd_obj_t*>(obj);
2553 ccdVec3Copy(c, &o->pos);
2554 }
2555
2556 template <typename S>
centerConvex(const void * obj,ccd_vec3_t * c)2557 static void centerConvex(const void* obj, ccd_vec3_t* c)
2558 {
2559 const auto *o = static_cast<const ccd_convex_t<S>*>(obj);
2560 const Vector3<S>& p = o->convex->getInteriorPoint();
2561 ccdVec3Set(c, p[0], p[1], p[2]);
2562 ccdQuatRotVec(c, &o->rot);
2563 ccdVec3Add(c, &o->pos);
2564 }
2565
centerTriangle(const void * obj,ccd_vec3_t * c)2566 static void centerTriangle(const void* obj, ccd_vec3_t* c)
2567 {
2568 const ccd_triangle_t *o = static_cast<const ccd_triangle_t*>(obj);
2569 ccdVec3Copy(c, &o->c);
2570 ccdQuatRotVec(c, &o->rot);
2571 ccdVec3Add(c, &o->pos);
2572 }
2573
2574 template <typename S>
GJKCollide(void * obj1,ccd_support_fn supp1,ccd_center_fn cen1,void * obj2,ccd_support_fn supp2,ccd_center_fn cen2,unsigned int max_iterations,S tolerance,Vector3<S> * contact_points,S * penetration_depth,Vector3<S> * normal)2575 bool GJKCollide(void* obj1, ccd_support_fn supp1, ccd_center_fn cen1,
2576 void* obj2, ccd_support_fn supp2, ccd_center_fn cen2,
2577 unsigned int max_iterations, S tolerance,
2578 Vector3<S>* contact_points, S* penetration_depth,
2579 Vector3<S>* normal)
2580 {
2581 ccd_t ccd;
2582 int res;
2583 ccd_real_t depth;
2584 ccd_vec3_t dir, pos;
2585
2586
2587 CCD_INIT(&ccd);
2588 ccd.support1 = supp1;
2589 ccd.support2 = supp2;
2590 ccd.center1 = cen1;
2591 ccd.center2 = cen2;
2592 ccd.max_iterations = max_iterations;
2593 ccd.mpr_tolerance = tolerance;
2594
2595 if (!contact_points)
2596 {
2597 return ccdMPRIntersect(obj1, obj2, &ccd);
2598 }
2599
2600
2601 /// libccd returns dir and pos in world space and dir is pointing from
2602 /// object 1 to object 2
2603 res = ccdMPRPenetration(obj1, obj2, &ccd, &depth, &dir, &pos);
2604 if (res == 0)
2605 {
2606 *contact_points << ccdVec3X(&pos), ccdVec3Y(&pos), ccdVec3Z(&pos);
2607 *penetration_depth = depth;
2608 *normal << ccdVec3X(&dir), ccdVec3Y(&dir), ccdVec3Z(&dir);
2609
2610 return true;
2611 }
2612
2613 return false;
2614 }
2615
2616 // For two geometric objects, computes the distance between the two objects and
2617 // returns the closest points. The return argument is the distance when the two
2618 // objects are not colliding, thus a non-negative number; it is a negative
2619 // number when the object is colliding, though the meaning of that negative
2620 // number depends on the implementation.
2621 using DistanceFn = std::function<ccd_real_t (
2622 const void*, const void*, const ccd_t*, ccd_vec3_t*, ccd_vec3_t*)>;
2623
2624 /** Compute the distance between two objects using GJK algorithm.
2625 * @param[in] obj1 A convex geometric object.
2626 * @param[in] supp1 A function to compute the support of obj1 along some
2627 * direction.
2628 * @param[in] obj2 A convex geometric object.
2629 * @param[in] supp2 A function to compute the support of obj2 along some
2630 * direction.
2631 * @param max_iterations The maximal iterations before the GJK algorithm
2632 * terminates.
2633 * @param[in] tolerance The tolerance used in GJK. When the change of distance
2634 * is smaller than this tolerance, the algorithm terminates.
2635 * @param[in] distance_func The actual function that computes the distance.
2636 * Different functions should be passed in, depending on whether the user wants
2637 * to compute a signed distance (with penetration depth) or not.
2638 * @param[out] res The distance between the objects. When the two objects are
2639 * not colliding, this is the actual distance, a positive number. When the two
2640 * objects are colliding, it is a negative value. The actual meaning of the
2641 * negative distance is defined by `distance_func`.
2642 * @param[out] p1 The closest point on object 1 in the world frame.
2643 * @param[out] p2 The closest point on object 2 in the world frame.
2644 * @retval is_separated True if the objects are separated, false otherwise.
2645 */
2646 template <typename S>
GJKDistanceImpl(void * obj1,ccd_support_fn supp1,void * obj2,ccd_support_fn supp2,unsigned int max_iterations,S tolerance,detail::DistanceFn distance_func,S * res,Vector3<S> * p1,Vector3<S> * p2)2647 bool GJKDistanceImpl(void* obj1, ccd_support_fn supp1, void* obj2,
2648 ccd_support_fn supp2, unsigned int max_iterations,
2649 S tolerance, detail::DistanceFn distance_func, S* res,
2650 Vector3<S>* p1, Vector3<S>* p2) {
2651 ccd_t ccd;
2652 ccd_real_t dist;
2653 CCD_INIT(&ccd);
2654 ccd.support1 = supp1;
2655 ccd.support2 = supp2;
2656
2657 ccd.max_iterations = max_iterations;
2658 ccd.dist_tolerance = tolerance;
2659 ccd.epa_tolerance = tolerance;
2660
2661 ccd_vec3_t p1_, p2_;
2662 // NOTE(JS): p1_ and p2_ are set to zeros in order to suppress uninitialized
2663 // warning. It seems the warnings occur since libccd_extension::ccdGJKDist2
2664 // conditionally set p1_ and p2_. If this wasn't intentional then please
2665 // remove the initialization of p1_ and p2_, and change the function
2666 // libccd_extension::ccdGJKDist2(...) to always set p1_ and p2_.
2667 ccdVec3Set(&p1_, 0.0, 0.0, 0.0);
2668 ccdVec3Set(&p2_, 0.0, 0.0, 0.0);
2669 dist = distance_func(obj1, obj2, &ccd, &p1_, &p2_);
2670 if (p1) *p1 << ccdVec3X(&p1_), ccdVec3Y(&p1_), ccdVec3Z(&p1_);
2671 if (p2) *p2 << ccdVec3X(&p2_), ccdVec3Y(&p2_), ccdVec3Z(&p2_);
2672 if (res) *res = dist;
2673 if (dist < 0)
2674 return false;
2675 else
2676 return true;
2677 }
2678
2679 template <typename S>
GJKDistance(void * obj1,ccd_support_fn supp1,void * obj2,ccd_support_fn supp2,unsigned int max_iterations,S tolerance,S * res,Vector3<S> * p1,Vector3<S> * p2)2680 bool GJKDistance(void* obj1, ccd_support_fn supp1,
2681 void* obj2, ccd_support_fn supp2,
2682 unsigned int max_iterations, S tolerance,
2683 S* res, Vector3<S>* p1, Vector3<S>* p2) {
2684 return detail::GJKDistanceImpl(obj1, supp1, obj2, supp2, max_iterations,
2685 tolerance, libccd_extension::ccdGJKDist2, res,
2686 p1, p2);
2687 }
2688
2689 /**
2690 * Compute the signed distance between two mesh objects. When the objects are
2691 * separating, the signed distance is > 0. When the objects are touching or
2692 * penetrating, the signed distance is <= 0.
2693 * @param tolerance. When the objects are separating, the GJK algorithm
2694 * terminates when the change of distance between iterations is smaller than
2695 * this tolerance. Note that this does NOT necessarily mean that the computed
2696 * distance is within @p tolerance to the actual distance. On the other hand,
2697 * when the objects are penetrating, the EPA algorithm terminates when the
2698 * difference between the upper bound and the lower bound of the penetration
2699 * depth is smaller than @p tolerance. Hence the computed penetration depth is
2700 * within @p tolerance to the true depth.
2701 */
2702 template <typename S>
GJKSignedDistance(void * obj1,ccd_support_fn supp1,void * obj2,ccd_support_fn supp2,unsigned int max_iterations,S tolerance,S * res,Vector3<S> * p1,Vector3<S> * p2)2703 bool GJKSignedDistance(void* obj1, ccd_support_fn supp1,
2704 void* obj2, ccd_support_fn supp2,
2705 unsigned int max_iterations,
2706 S tolerance, S* res, Vector3<S>* p1, Vector3<S>* p2) {
2707 return detail::GJKDistanceImpl(
2708 obj1, supp1, obj2, supp2, max_iterations, tolerance,
2709 libccd_extension::ccdGJKSignedDist, res, p1, p2);
2710 }
2711
2712 template <typename S>
getSupportFunction()2713 GJKSupportFunction GJKInitializer<S, Cylinder<S>>::getSupportFunction()
2714 {
2715 return &supportCyl;
2716 }
2717
2718 template <typename S>
getCenterFunction()2719 GJKCenterFunction GJKInitializer<S, Cylinder<S>>::getCenterFunction()
2720 {
2721 return ¢erShape;
2722 }
2723
2724 template <typename S>
createGJKObject(const Cylinder<S> & s,const Transform3<S> & tf)2725 void* GJKInitializer<S, Cylinder<S>>::createGJKObject(const Cylinder<S>& s,
2726 const Transform3<S>& tf)
2727 {
2728 ccd_cyl_t* o = new ccd_cyl_t;
2729 cylToGJK(s, tf, o);
2730 return o;
2731 }
2732
2733 template <typename S>
deleteGJKObject(void * o_)2734 void GJKInitializer<S, Cylinder<S>>::deleteGJKObject(void* o_)
2735 {
2736 ccd_cyl_t* o = static_cast<ccd_cyl_t*>(o_);
2737 delete o;
2738 }
2739
2740 template <typename S>
getSupportFunction()2741 GJKSupportFunction GJKInitializer<S, Sphere<S>>::getSupportFunction()
2742 {
2743 return &supportSphere;
2744 }
2745
2746 template <typename S>
getCenterFunction()2747 GJKCenterFunction GJKInitializer<S, Sphere<S>>::getCenterFunction()
2748 {
2749 return ¢erShape;
2750 }
2751
2752 template <typename S>
createGJKObject(const Sphere<S> & s,const Transform3<S> & tf)2753 void* GJKInitializer<S, Sphere<S>>::createGJKObject(const Sphere<S>& s,
2754 const Transform3<S>& tf)
2755 {
2756 ccd_sphere_t* o = new ccd_sphere_t;
2757 sphereToGJK(s, tf, o);
2758 return o;
2759 }
2760
2761 template <typename S>
deleteGJKObject(void * o_)2762 void GJKInitializer<S, Sphere<S>>::deleteGJKObject(void* o_)
2763 {
2764 ccd_sphere_t* o = static_cast<ccd_sphere_t*>(o_);
2765 delete o;
2766 }
2767
2768 template <typename S>
getSupportFunction()2769 GJKSupportFunction GJKInitializer<S, Ellipsoid<S>>::getSupportFunction()
2770 {
2771 return &supportEllipsoid;
2772 }
2773
2774 template <typename S>
getCenterFunction()2775 GJKCenterFunction GJKInitializer<S, Ellipsoid<S>>::getCenterFunction()
2776 {
2777 return ¢erShape;
2778 }
2779
2780 template <typename S>
createGJKObject(const Ellipsoid<S> & s,const Transform3<S> & tf)2781 void* GJKInitializer<S, Ellipsoid<S>>::createGJKObject(const Ellipsoid<S>& s,
2782 const Transform3<S>& tf)
2783 {
2784 ccd_ellipsoid_t* o = new ccd_ellipsoid_t;
2785 ellipsoidToGJK(s, tf, o);
2786 return o;
2787 }
2788
2789 template <typename S>
deleteGJKObject(void * o_)2790 void GJKInitializer<S, Ellipsoid<S>>::deleteGJKObject(void* o_)
2791 {
2792 ccd_ellipsoid_t* o = static_cast<ccd_ellipsoid_t*>(o_);
2793 delete o;
2794 }
2795
2796 template <typename S>
getSupportFunction()2797 GJKSupportFunction GJKInitializer<S, Box<S>>::getSupportFunction()
2798 {
2799 return &supportBox;
2800 }
2801
2802 template <typename S>
getCenterFunction()2803 GJKCenterFunction GJKInitializer<S, Box<S>>::getCenterFunction()
2804 {
2805 return ¢erShape;
2806 }
2807
2808 template <typename S>
createGJKObject(const Box<S> & s,const Transform3<S> & tf)2809 void* GJKInitializer<S, Box<S>>::createGJKObject(const Box<S>& s,
2810 const Transform3<S>& tf)
2811 {
2812 ccd_box_t* o = new ccd_box_t;
2813 boxToGJK(s, tf, o);
2814 return o;
2815 }
2816
2817 template <typename S>
deleteGJKObject(void * o_)2818 void GJKInitializer<S, Box<S>>::deleteGJKObject(void* o_)
2819 {
2820 ccd_box_t* o = static_cast<ccd_box_t*>(o_);
2821 delete o;
2822 }
2823
2824 template <typename S>
getSupportFunction()2825 GJKSupportFunction GJKInitializer<S, Capsule<S>>::getSupportFunction()
2826 {
2827 return &supportCap;
2828 }
2829
2830 template <typename S>
getCenterFunction()2831 GJKCenterFunction GJKInitializer<S, Capsule<S>>::getCenterFunction()
2832 {
2833 return ¢erShape;
2834 }
2835
2836 template <typename S>
createGJKObject(const Capsule<S> & s,const Transform3<S> & tf)2837 void* GJKInitializer<S, Capsule<S>>::createGJKObject(const Capsule<S>& s,
2838 const Transform3<S>& tf)
2839 {
2840 ccd_cap_t* o = new ccd_cap_t;
2841 capToGJK(s, tf, o);
2842 return o;
2843 }
2844
2845 template <typename S>
deleteGJKObject(void * o_)2846 void GJKInitializer<S, Capsule<S>>::deleteGJKObject(void* o_)
2847 {
2848 ccd_cap_t* o = static_cast<ccd_cap_t*>(o_);
2849 delete o;
2850 }
2851
2852 template <typename S>
getSupportFunction()2853 GJKSupportFunction GJKInitializer<S, Cone<S>>::getSupportFunction()
2854 {
2855 return &supportCone;
2856 }
2857
2858 template <typename S>
getCenterFunction()2859 GJKCenterFunction GJKInitializer<S, Cone<S>>::getCenterFunction()
2860 {
2861 return ¢erShape;
2862 }
2863
2864 template <typename S>
createGJKObject(const Cone<S> & s,const Transform3<S> & tf)2865 void* GJKInitializer<S, Cone<S>>::createGJKObject(const Cone<S>& s,
2866 const Transform3<S>& tf)
2867 {
2868 ccd_cone_t* o = new ccd_cone_t;
2869 coneToGJK(s, tf, o);
2870 return o;
2871 }
2872
2873 template <typename S>
deleteGJKObject(void * o_)2874 void GJKInitializer<S, Cone<S>>::deleteGJKObject(void* o_)
2875 {
2876 ccd_cone_t* o = static_cast<ccd_cone_t*>(o_);
2877 delete o;
2878 }
2879
2880 template <typename S>
getSupportFunction()2881 GJKSupportFunction GJKInitializer<S, Convex<S>>::getSupportFunction()
2882 {
2883 return &supportConvex<S>;
2884 }
2885
2886 template <typename S>
getCenterFunction()2887 GJKCenterFunction GJKInitializer<S, Convex<S>>::getCenterFunction()
2888 {
2889 return ¢erConvex<S>;
2890 }
2891
2892 template <typename S>
createGJKObject(const Convex<S> & s,const Transform3<S> & tf)2893 void* GJKInitializer<S, Convex<S>>::createGJKObject(const Convex<S>& s,
2894 const Transform3<S>& tf)
2895 {
2896 auto* o = new ccd_convex_t<S>;
2897 convexToGJK(s, tf, o);
2898 return o;
2899 }
2900
2901 template <typename S>
deleteGJKObject(void * o_)2902 void GJKInitializer<S, Convex<S>>::deleteGJKObject(void* o_)
2903 {
2904 auto* o = static_cast<ccd_convex_t<S>*>(o_);
2905 delete o;
2906 }
2907
triGetSupportFunction()2908 inline GJKSupportFunction triGetSupportFunction()
2909 {
2910 return &supportTriangle;
2911 }
2912
triGetCenterFunction()2913 inline GJKCenterFunction triGetCenterFunction()
2914 {
2915 return ¢erTriangle;
2916 }
2917
2918 template <typename S>
triCreateGJKObject(const Vector3<S> & P1,const Vector3<S> & P2,const Vector3<S> & P3)2919 void* triCreateGJKObject(const Vector3<S>& P1, const Vector3<S>& P2,
2920 const Vector3<S>& P3)
2921 {
2922 ccd_triangle_t* o = new ccd_triangle_t;
2923 Vector3<S> center((P1[0] + P2[0] + P3[0]) / 3, (P1[1] + P2[1] + P3[1]) / 3,
2924 (P1[2] + P2[2] + P3[2]) / 3);
2925
2926 ccdVec3Set(&o->p[0], P1[0], P1[1], P1[2]);
2927 ccdVec3Set(&o->p[1], P2[0], P2[1], P2[2]);
2928 ccdVec3Set(&o->p[2], P3[0], P3[1], P3[2]);
2929 ccdVec3Set(&o->c, center[0], center[1], center[2]);
2930 ccdVec3Set(&o->pos, 0., 0., 0.);
2931 ccdQuatSet(&o->rot, 0., 0., 0., 1.);
2932 ccdQuatInvert2(&o->rot_inv, &o->rot);
2933
2934 return o;
2935 }
2936
2937 template <typename S>
triCreateGJKObject(const Vector3<S> & P1,const Vector3<S> & P2,const Vector3<S> & P3,const Transform3<S> & tf)2938 void* triCreateGJKObject(const Vector3<S>& P1, const Vector3<S>& P2,
2939 const Vector3<S>& P3, const Transform3<S>& tf)
2940 {
2941 ccd_triangle_t* o = new ccd_triangle_t;
2942 Vector3<S> center((P1[0] + P2[0] + P3[0]) / 3, (P1[1] + P2[1] + P3[1]) / 3,
2943 (P1[2] + P2[2] + P3[2]) / 3);
2944
2945 ccdVec3Set(&o->p[0], P1[0], P1[1], P1[2]);
2946 ccdVec3Set(&o->p[1], P2[0], P2[1], P2[2]);
2947 ccdVec3Set(&o->p[2], P3[0], P3[1], P3[2]);
2948 ccdVec3Set(&o->c, center[0], center[1], center[2]);
2949 const Quaternion<S> q(tf.linear());
2950 const Vector3<S>& T = tf.translation();
2951 ccdVec3Set(&o->pos, T[0], T[1], T[2]);
2952 ccdQuatSet(&o->rot, q.x(), q.y(), q.z(), q.w());
2953 ccdQuatInvert2(&o->rot_inv, &o->rot);
2954
2955 return o;
2956 }
2957
triDeleteGJKObject(void * o_)2958 inline void triDeleteGJKObject(void* o_)
2959 {
2960 ccd_triangle_t* o = static_cast<ccd_triangle_t*>(o_);
2961 delete o;
2962 }
2963
2964 } // namespace detail
2965 } // namespace fcl
2966
2967 #endif
2968