coal 3.0.2
Coal, The Collision Detection Library. Previously known as HPP-FCL, fork of FCL -- The Flexible Collision Library
Loading...
Searching...
No Matches
details.h
Go to the documentation of this file.
1/*
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2011-2014, Willow Garage, Inc.
5 * Copyright (c) 2014-2015, Open Source Robotics Foundation
6 * Copyright (c) 2018-2019, Centre National de la Recherche Scientifique
7 * Copyright (c) 2021-2024, INRIA
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * * Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer in the documentation and/or other materials provided
19 * with the distribution.
20 * * Neither the name of Open Source Robotics Foundation nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
38
39#ifndef COAL_SRC_NARROWPHASE_DETAILS_H
40#define COAL_SRC_NARROWPHASE_DETAILS_H
41
44
45namespace coal {
46namespace details {
47// Compute the point on a line segment that is the closest point on the
48// segment to to another point. The code is inspired by the explanation
49// given by Dan Sunday's page:
50// http://geomalgorithms.com/a02-_lines.html
51static inline void lineSegmentPointClosestToPoint(const Vec3s& p,
52 const Vec3s& s1,
53 const Vec3s& s2, Vec3s& sp) {
54 Vec3s v = s2 - s1;
55 Vec3s w = p - s1;
56
57 CoalScalar c1 = w.dot(v);
58 CoalScalar c2 = v.dot(v);
59
60 if (c1 <= 0) {
61 sp = s1;
62 } else if (c2 <= c1) {
63 sp = s2;
64 } else {
65 CoalScalar b = c1 / c2;
66 Vec3s Pb = s1 + v * b;
67 sp = Pb;
68 }
69}
70
76 const Transform3s& tf1,
77 const Capsule& s2,
78 const Transform3s& tf2, Vec3s& p1,
79 Vec3s& p2, Vec3s& normal) {
80 Vec3s pos1(tf2.transform(Vec3s(0., 0., s2.halfLength)));
81 Vec3s pos2(tf2.transform(Vec3s(0., 0., -s2.halfLength)));
82 Vec3s s_c = tf1.getTranslation();
83
84 Vec3s segment_point;
85
86 lineSegmentPointClosestToPoint(s_c, pos1, pos2, segment_point);
87 normal = segment_point - s_c;
88 CoalScalar norm(normal.norm());
91 CoalScalar dist = norm - r1 - r2;
92
93 static const CoalScalar eps(std::numeric_limits<CoalScalar>::epsilon());
94 if (norm > eps) {
95 normal.normalize();
96 } else {
97 normal << 1, 0, 0;
98 }
99 p1 = s_c + normal * r1;
100 p2 = segment_point - normal * r2;
101 return dist;
102}
103
109 const Transform3s& tf1,
110 const Cylinder& s2,
111 const Transform3s& tf2, Vec3s& p1,
112 Vec3s& p2, Vec3s& normal) {
113 static const CoalScalar eps(sqrt(std::numeric_limits<CoalScalar>::epsilon()));
114 CoalScalar r1(s1.radius);
115 CoalScalar r2(s2.radius);
116 CoalScalar lz2(s2.halfLength);
117 // boundaries of the cylinder axis
118 Vec3s A(tf2.transform(Vec3s(0, 0, -lz2)));
119 Vec3s B(tf2.transform(Vec3s(0, 0, lz2)));
120 // Position of the center of the sphere
121 Vec3s S(tf1.getTranslation());
122 // axis of the cylinder
123 Vec3s u(tf2.getRotation().col(2));
126 assert((B - A - (s2.halfLength * 2) * u).norm() < eps);
127 Vec3s AS(S - A);
128 // abscissa of S on cylinder axis with A as the origin
129 CoalScalar s(u.dot(AS));
130 Vec3s P(A + s * u);
131 Vec3s PS(S - P);
132 CoalScalar dPS = PS.norm();
133 // Normal to cylinder axis such that plane (A, u, v) contains sphere
134 // center
135 Vec3s v(0, 0, 0);
136 CoalScalar dist;
137 if (dPS > eps) {
138 // S is not on cylinder axis
139 v = (1 / dPS) * PS;
140 }
141 if (s <= 0) {
142 if (dPS <= r2) {
143 // closest point on cylinder is on cylinder disc basis
144 dist = -s - r1;
145 p1 = S + r1 * u;
146 p2 = A + dPS * v;
147 normal = u;
148 } else {
149 // closest point on cylinder is on cylinder circle basis
150 p2 = A + r2 * v;
151 Vec3s Sp2(p2 - S);
152 CoalScalar dSp2 = Sp2.norm();
153 if (dSp2 > eps) {
154 normal = (1 / dSp2) * Sp2;
155 p1 = S + r1 * normal;
156 dist = dSp2 - r1;
157 assert(fabs(dist) - (p1 - p2).norm() < eps);
158 } else {
159 // Center of sphere is on cylinder boundary
160 normal = p2 - .5 * (A + B);
161 assert(u.dot(normal) >= 0);
162 normal.normalize();
163 dist = -r1;
164 p1 = S + r1 * normal;
165 }
166 }
167 } else if (s <= (s2.halfLength * 2)) {
168 // 0 < s <= s2.lz
169 normal = -v;
170 dist = dPS - r1 - r2;
171 p2 = P + r2 * v;
172 p1 = S - r1 * v;
173 } else {
174 // lz < s
175 if (dPS <= r2) {
176 // closest point on cylinder is on cylinder disc basis
177 dist = s - (s2.halfLength * 2) - r1;
178 p1 = S - r1 * u;
179 p2 = B + dPS * v;
180 normal = -u;
181 } else {
182 // closest point on cylinder is on cylinder circle basis
183 p2 = B + r2 * v;
184 Vec3s Sp2(p2 - S);
185 CoalScalar dSp2 = Sp2.norm();
186 if (dSp2 > eps) {
187 normal = (1 / dSp2) * Sp2;
188 p1 = S + r1 * normal;
189 dist = dSp2 - r1;
190 assert(fabs(dist) - (p1 - p2).norm() < eps);
191 } else {
192 // Center of sphere is on cylinder boundary
193 normal = p2 - .5 * (A + B);
194 normal.normalize();
195 p1 = S + r1 * normal;
196 dist = -r1;
197 }
198 }
199 }
200
201 // Take swept-sphere radius into account
202 const CoalScalar ssr1 = s1.getSweptSphereRadius();
203 const CoalScalar ssr2 = s2.getSweptSphereRadius();
204 if (ssr1 > 0 || ssr2 > 0) {
205 p1 += ssr1 * normal;
206 p2 -= ssr2 * normal;
207 dist -= (ssr1 + ssr2);
208 }
209
210 return dist;
211}
212
218 const Sphere& s2, const Transform3s& tf2,
219 Vec3s& p1, Vec3s& p2, Vec3s& normal) {
220 const coal::Vec3s& center1 = tf1.getTranslation();
221 const coal::Vec3s& center2 = tf2.getTranslation();
222 CoalScalar r1 = (s1.radius + s1.getSweptSphereRadius());
223 CoalScalar r2 = (s2.radius + s2.getSweptSphereRadius());
224
225 Vec3s c1c2 = center2 - center1;
226 CoalScalar cdist = c1c2.norm();
227 Vec3s unit(1, 0, 0);
228 if (cdist > Eigen::NumTraits<CoalScalar>::epsilon()) unit = c1c2 / cdist;
229 CoalScalar dist = cdist - r1 - r2;
230 normal = unit;
231 p1.noalias() = center1 + r1 * unit;
232 p2.noalias() = center2 - r2 * unit;
233 return dist;
234}
235
237inline CoalScalar segmentSqrDistance(const Vec3s& from, const Vec3s& to,
238 const Vec3s& p, Vec3s& nearest) {
239 Vec3s diff = p - from;
240 Vec3s v = to - from;
241 CoalScalar t = v.dot(diff);
242
243 if (t > 0) {
244 CoalScalar dotVV = v.squaredNorm();
245 if (t < dotVV) {
246 t /= dotVV;
247 diff -= v * t;
248 } else {
249 t = 1;
250 diff -= v;
251 }
252 } else
253 t = 0;
254
255 nearest.noalias() = from + v * t;
256 return diff.squaredNorm();
257}
258
260inline bool projectInTriangle(const Vec3s& p1, const Vec3s& p2, const Vec3s& p3,
261 const Vec3s& normal, const Vec3s& p) {
262 Vec3s edge1(p2 - p1);
263 Vec3s edge2(p3 - p2);
264 Vec3s edge3(p1 - p3);
265
266 Vec3s p1_to_p(p - p1);
267 Vec3s p2_to_p(p - p2);
268 Vec3s p3_to_p(p - p3);
269
270 Vec3s edge1_normal(edge1.cross(normal));
271 Vec3s edge2_normal(edge2.cross(normal));
272 Vec3s edge3_normal(edge3.cross(normal));
273
274 CoalScalar r1, r2, r3;
275 r1 = edge1_normal.dot(p1_to_p);
276 r2 = edge2_normal.dot(p2_to_p);
277 r3 = edge3_normal.dot(p3_to_p);
278 if ((r1 > 0 && r2 > 0 && r3 > 0) || (r1 <= 0 && r2 <= 0 && r3 <= 0)) {
279 return true;
280 }
281 return false;
282}
283
289 const Transform3s& tf1,
290 const TriangleP& tri,
291 const Transform3s& tf2, Vec3s& p1,
292 Vec3s& p2, Vec3s& normal) {
293 const Vec3s& P1 = tf2.transform(tri.a);
294 const Vec3s& P2 = tf2.transform(tri.b);
295 const Vec3s& P3 = tf2.transform(tri.c);
296
297 Vec3s tri_normal = (P2 - P1).cross(P3 - P1);
298 tri_normal.normalize();
299 const Vec3s& center = tf1.getTranslation();
300 // Note: comparing an object with a swept-sphere radius of r1 against another
301 // object with a swept-sphere radius of r2 is equivalent to comparing the
302 // first object with a swept-sphere radius of r1 + r2 against the second
303 // object with a swept-sphere radius of 0.
304 const CoalScalar& radius =
306 assert(radius >= 0);
307 assert(s.radius >= 0);
308 Vec3s p1_to_center = center - P1;
309 CoalScalar distance_from_plane = p1_to_center.dot(tri_normal);
310 Vec3s closest_point(
311 Vec3s::Constant(std::numeric_limits<CoalScalar>::quiet_NaN()));
312 CoalScalar min_distance_sqr, distance_sqr;
313
314 if (distance_from_plane < 0) {
315 distance_from_plane *= -1;
316 tri_normal *= -1;
317 }
318
319 if (projectInTriangle(P1, P2, P3, tri_normal, center)) {
320 closest_point = center - tri_normal * distance_from_plane;
321 min_distance_sqr = distance_from_plane * distance_from_plane;
322 } else {
323 // Compute distance to each edge and take minimal distance
324 Vec3s nearest_on_edge;
325 min_distance_sqr = segmentSqrDistance(P1, P2, center, closest_point);
326
327 distance_sqr = segmentSqrDistance(P2, P3, center, nearest_on_edge);
328 if (distance_sqr < min_distance_sqr) {
329 min_distance_sqr = distance_sqr;
330 closest_point = nearest_on_edge;
331 }
332 distance_sqr = segmentSqrDistance(P3, P1, center, nearest_on_edge);
333 if (distance_sqr < min_distance_sqr) {
334 min_distance_sqr = distance_sqr;
335 closest_point = nearest_on_edge;
336 }
337 }
338
339 normal = (closest_point - center).normalized();
340 p1 = center + normal * (s.radius + s.getSweptSphereRadius());
341 p2 = closest_point - normal * tri.getSweptSphereRadius();
342 const CoalScalar distance = std::sqrt(min_distance_sqr) - radius;
343 return distance;
344}
345
351 const ShapeBase& s, const Transform3s& tf2,
352 Vec3s& p1, Vec3s& p2, Vec3s& normal) {
353 // TODO(louis): handle multiple contact points when the halfspace normal is
354 // parallel to the shape's surface (every primitive except sphere and
355 // ellipsoid).
356
357 // Express halfspace in world frame
358 Halfspace new_h = transform(h, tf1);
359
360 // Express halfspace normal in shape frame
361 Vec3s n_2(tf2.getRotation().transpose() * new_h.n);
362
363 // Compute support of shape in direction of halfspace normal
364 int hint = 0;
365 p2.noalias() =
367 p2 = tf2.transform(p2);
368
369 const CoalScalar dist = new_h.signedDistance(p2);
370 p1.noalias() = p2 - dist * new_h.n;
371 normal.noalias() = new_h.n;
372
373 const CoalScalar dummy_precision =
374 std::sqrt(Eigen::NumTraits<CoalScalar>::dummy_precision());
375 COAL_UNUSED_VARIABLE(dummy_precision);
376 assert(new_h.distance(p1) <= dummy_precision);
377 return dist;
378}
379
384inline CoalScalar planeDistance(const Plane& plane, const Transform3s& tf1,
385 const ShapeBase& s, const Transform3s& tf2,
386 Vec3s& p1, Vec3s& p2, Vec3s& normal) {
387 // TODO(louis): handle multiple contact points when the plane normal is
388 // parallel to the shape's surface (every primitive except sphere and
389 // ellipsoid).
390
391 // Express plane as two halfspaces in world frame
392 std::array<Halfspace, 2> new_h = transformToHalfspaces(plane, tf1);
393
394 // Express halfspace normals in shape frame
395 Vec3s n_h1(tf2.getRotation().transpose() * new_h[0].n);
396 Vec3s n_h2(tf2.getRotation().transpose() * new_h[1].n);
397
398 // Compute support of shape in direction of halfspace normal and its opposite
399 int hint = 0;
400 Vec3s p2h1 =
402 p2h1 = tf2.transform(p2h1);
403
404 hint = 0;
405 Vec3s p2h2 =
407 p2h2 = tf2.transform(p2h2);
408
409 CoalScalar dist1 = new_h[0].signedDistance(p2h1);
410 CoalScalar dist2 = new_h[1].signedDistance(p2h2);
411
412 const CoalScalar dummy_precision =
413 std::sqrt(Eigen::NumTraits<CoalScalar>::dummy_precision());
414 COAL_UNUSED_VARIABLE(dummy_precision);
415
416 CoalScalar dist;
417 if (dist1 >= dist2) {
418 dist = dist1;
419 p2.noalias() = p2h1;
420 p1.noalias() = p2 - dist * new_h[0].n;
421 normal.noalias() = new_h[0].n;
422 assert(new_h[0].distance(p1) <= dummy_precision);
423 } else {
424 dist = dist2;
425 p2.noalias() = p2h2;
426 p1.noalias() = p2 - dist * new_h[1].n;
427 normal.noalias() = new_h[1].n;
428 assert(new_h[1].distance(p1) <= dummy_precision);
429 }
430 return dist;
431}
432
438inline CoalScalar boxSphereDistance(const Box& b, const Transform3s& tfb,
439 const Sphere& s, const Transform3s& tfs,
440 Vec3s& pb, Vec3s& ps, Vec3s& normal) {
441 const Vec3s& os = tfs.getTranslation();
442 const Vec3s& ob = tfb.getTranslation();
443 const Matrix3s& Rb = tfb.getRotation();
444
445 pb = ob;
446
447 bool outside = false;
448 const Vec3s os_in_b_frame(Rb.transpose() * (os - ob));
449 int axis = -1;
450 CoalScalar min_d = (std::numeric_limits<CoalScalar>::max)();
451 for (int i = 0; i < 3; ++i) {
452 CoalScalar facedist;
453 if (os_in_b_frame(i) < -b.halfSide(i)) { // outside
454 pb.noalias() -= b.halfSide(i) * Rb.col(i);
455 outside = true;
456 } else if (os_in_b_frame(i) > b.halfSide(i)) { // outside
457 pb.noalias() += b.halfSide(i) * Rb.col(i);
458 outside = true;
459 } else {
460 pb.noalias() += os_in_b_frame(i) * Rb.col(i);
461 if (!outside &&
462 (facedist = b.halfSide(i) - std::fabs(os_in_b_frame(i))) < min_d) {
463 axis = i;
464 min_d = facedist;
465 }
466 }
467 }
468 normal = pb - os;
469 CoalScalar pdist = normal.norm();
470 CoalScalar dist; // distance between sphere and box
471 if (outside) { // pb is on the box
472 dist = pdist - s.radius;
473 normal /= -pdist;
474 } else { // pb is inside the box
475 if (os_in_b_frame(axis) >= 0) {
476 normal = Rb.col(axis);
477 } else {
478 normal = -Rb.col(axis);
479 }
480 dist = -min_d - s.radius;
481 }
482 ps = os - s.radius * normal;
483 if (!outside || dist <= 0) {
484 // project point pb onto the box's surface
485 pb = ps - dist * normal;
486 }
487
488 // Take swept-sphere radius into account
489 const CoalScalar ssrb = b.getSweptSphereRadius();
490 const CoalScalar ssrs = s.getSweptSphereRadius();
491 if (ssrb > 0 || ssrs > 0) {
492 pb += ssrb * normal;
493 ps -= ssrs * normal;
494 dist -= (ssrb + ssrs);
495 }
496
497 return dist;
498}
499
513 const Transform3s& tf1,
514 const Halfspace& s2,
515 const Transform3s& tf2, Vec3s& p1,
516 Vec3s& p2, Vec3s& normal) {
517 Halfspace new_s1 = transform(s1, tf1);
518 Halfspace new_s2 = transform(s2, tf2);
519
521 Vec3s dir = (new_s1.n).cross(new_s2.n);
522 CoalScalar dir_sq_norm = dir.squaredNorm();
523
524 if (dir_sq_norm < std::numeric_limits<CoalScalar>::epsilon()) // parallel
525 {
526 if (new_s1.n.dot(new_s2.n) > 0) {
527 // If the two halfspaces have the same normal, one is inside the other
528 // and they can't be separated. They have inifinte penetration depth.
529 distance = -(std::numeric_limits<CoalScalar>::max)();
530 if (new_s1.d <= new_s2.d) {
531 normal = new_s1.n;
532 p1 = normal * distance;
533 p2 = new_s2.n * new_s2.d;
534 assert(new_s2.distance(p2) <=
535 Eigen::NumTraits<CoalScalar>::dummy_precision());
536 } else {
537 normal = -new_s1.n;
538 p1 << new_s1.n * new_s1.d;
539 p2 = -(normal * distance);
540 assert(new_s1.distance(p1) <=
541 Eigen::NumTraits<CoalScalar>::dummy_precision());
542 }
543 } else {
544 distance = -(new_s1.d + new_s2.d);
545 normal = new_s1.n;
546 p1 = new_s1.n * new_s1.d;
547 p2 = new_s2.n * new_s2.d;
548 }
549 } else {
550 // If the halfspaces are not parallel, they are in collision.
551 // Their distance, in the sens of the norm of separation vector, is infinite
552 // (it's impossible to find a translation which separates them)
553 distance = -(std::numeric_limits<CoalScalar>::max)();
554 // p1 and p2 are the same point, corresponding to a point on the
555 // intersection line between the two objects. Normal is the direction of
556 // that line.
557 normal = dir;
558 p1 = p2 =
559 ((new_s2.n * new_s1.d - new_s1.n * new_s2.d).cross(dir)) / dir_sq_norm;
560 // Sources: https://en.wikipedia.org/wiki/Plane%E2%80%93plane_intersection
561 // and https://en.wikipedia.org/wiki/Cross_product
562 }
563
564 // Take swept-sphere radius into account
565 const CoalScalar ssr1 = s1.getSweptSphereRadius();
566 const CoalScalar ssr2 = s2.getSweptSphereRadius();
567 if (ssr1 > 0 || ssr2 > 0) {
568 p1 += ssr1 * normal;
569 p2 -= ssr2 * normal;
570 distance -= (ssr1 + ssr2);
571 }
572
573 return distance;
574}
575
589 const Transform3s& tf1,
590 const Plane& s2,
591 const Transform3s& tf2, Vec3s& p1,
592 Vec3s& p2, Vec3s& normal) {
593 Halfspace new_s1 = transform(s1, tf1);
594 Plane new_s2 = transform(s2, tf2);
595
597 Vec3s dir = (new_s1.n).cross(new_s2.n);
598 CoalScalar dir_sq_norm = dir.squaredNorm();
599
600 if (dir_sq_norm < std::numeric_limits<CoalScalar>::epsilon()) // parallel
601 {
602 normal = new_s1.n;
603 distance = new_s1.n.dot(new_s2.n) > 0 ? (new_s2.d - new_s1.d)
604 : -(new_s1.d + new_s2.d);
605 p1 = new_s1.n * new_s1.d;
606 p2 = new_s2.n * new_s2.d;
607 assert(new_s1.distance(p1) <=
608 Eigen::NumTraits<CoalScalar>::dummy_precision());
609 assert(new_s2.distance(p2) <=
610 Eigen::NumTraits<CoalScalar>::dummy_precision());
611 } else {
612 // If the halfspace and plane are not parallel, they are in collision.
613 // Their distance, in the sens of the norm of separation vector, is infinite
614 // (it's impossible to find a translation which separates them)
615 distance = -(std::numeric_limits<CoalScalar>::max)();
616 // p1 and p2 are the same point, corresponding to a point on the
617 // intersection line between the two objects. Normal is the direction of
618 // that line.
619 normal = dir;
620 p1 = p2 =
621 ((new_s2.n * new_s1.d - new_s1.n * new_s2.d).cross(dir)) / dir_sq_norm;
622 // Sources: https://en.wikipedia.org/wiki/Plane%E2%80%93plane_intersection
623 // and https://en.wikipedia.org/wiki/Cross_product
624 }
625
626 // Take swept-sphere radius into account
627 const CoalScalar ssr1 = s1.getSweptSphereRadius();
628 const CoalScalar ssr2 = s2.getSweptSphereRadius();
629 if (ssr1 > 0 || ssr2 > 0) {
630 p1 += ssr1 * normal;
631 p2 -= ssr2 * normal;
632 distance -= (ssr1 + ssr2);
633 }
634
635 return distance;
636}
637
650inline CoalScalar planePlaneDistance(const Plane& s1, const Transform3s& tf1,
651 const Plane& s2, const Transform3s& tf2,
652 Vec3s& p1, Vec3s& p2, Vec3s& normal) {
653 Plane new_s1 = transform(s1, tf1);
654 Plane new_s2 = transform(s2, tf2);
655
657 Vec3s dir = (new_s1.n).cross(new_s2.n);
658 CoalScalar dir_sq_norm = dir.squaredNorm();
659
660 if (dir_sq_norm < std::numeric_limits<CoalScalar>::epsilon()) // parallel
661 {
662 p1 = new_s1.n * new_s1.d;
663 p2 = new_s2.n * new_s2.d;
664 assert(new_s1.distance(p1) <=
665 Eigen::NumTraits<CoalScalar>::dummy_precision());
666 assert(new_s2.distance(p2) <=
667 Eigen::NumTraits<CoalScalar>::dummy_precision());
668 distance = (p1 - p2).norm();
669
670 if (distance > Eigen::NumTraits<CoalScalar>::dummy_precision()) {
671 normal = (p2 - p1).normalized();
672 } else {
673 normal = new_s1.n;
674 }
675 } else {
676 // If the planes are not parallel, they are in collision.
677 // Their distance, in the sens of the norm of separation vector, is infinite
678 // (it's impossible to find a translation which separates them)
679 distance = -(std::numeric_limits<CoalScalar>::max)();
680 // p1 and p2 are the same point, corresponding to a point on the
681 // intersection line between the two objects. Normal is the direction of
682 // that line.
683 normal = dir;
684 p1 = p2 =
685 ((new_s2.n * new_s1.d - new_s1.n * new_s2.d).cross(dir)) / dir_sq_norm;
686 // Sources: https://en.wikipedia.org/wiki/Plane%E2%80%93plane_intersection
687 // and https://en.wikipedia.org/wiki/Cross_product
688 }
689
690 // Take swept-sphere radius into account
691 const CoalScalar ssr1 = s1.getSweptSphereRadius();
692 const CoalScalar ssr2 = s2.getSweptSphereRadius();
693 if (ssr1 > 0 || ssr2 > 0) {
694 p1 += ssr1 * normal;
695 p2 -= ssr2 * normal;
696 distance -= (ssr1 + ssr2);
697 }
698
699 return distance;
700}
701
703inline CoalScalar computePenetration(const Vec3s& P1, const Vec3s& P2,
704 const Vec3s& P3, const Vec3s& Q1,
705 const Vec3s& Q2, const Vec3s& Q3,
706 Vec3s& normal) {
707 Vec3s u((P2 - P1).cross(P3 - P1));
708 normal = u.normalized();
709 CoalScalar depth1((P1 - Q1).dot(normal));
710 CoalScalar depth2((P1 - Q2).dot(normal));
711 CoalScalar depth3((P1 - Q3).dot(normal));
712 return std::max(depth1, std::max(depth2, depth3));
713}
714
715// Compute penetration distance and normal of two triangles in collision
716// Normal is normal of triangle 1 (P1, P2, P3), penetration depth is the
717// minimal distance (Q1, Q2, Q3) should be translated along the normal so
718// that the triangles are collision free.
719//
720// Note that we compute here an upper bound of the penetration distance,
721// not the exact value.
722inline CoalScalar computePenetration(const Vec3s& P1, const Vec3s& P2,
723 const Vec3s& P3, const Vec3s& Q1,
724 const Vec3s& Q2, const Vec3s& Q3,
725 const Transform3s& tf1,
726 const Transform3s& tf2, Vec3s& normal) {
727 Vec3s globalP1(tf1.transform(P1));
728 Vec3s globalP2(tf1.transform(P2));
729 Vec3s globalP3(tf1.transform(P3));
730 Vec3s globalQ1(tf2.transform(Q1));
731 Vec3s globalQ2(tf2.transform(Q2));
732 Vec3s globalQ3(tf2.transform(Q3));
733 return computePenetration(globalP1, globalP2, globalP3, globalQ1, globalQ2,
734 globalQ3, normal);
735}
736
737} // namespace details
738} // namespace coal
739
740#endif // COAL_SRC_NARROWPHASE_DETAILS_H
Center at zero point, axis aligned box.
Definition geometric_shapes.h:166
Capsule It is where is the distance between the point x and the capsule segment AB,...
Definition geometric_shapes.h:383
Cylinder along Z axis. The cylinder is defined at its centroid.
Definition geometric_shapes.h:560
Half Space: this is equivalent to the Plane in ODE. A Half space has a priviledged direction: the dir...
Definition geometric_shapes.h:892
Infinite plane. A plane can be viewed as two half spaces; it has no priviledged direction....
Definition geometric_shapes.h:983
Base class for all basic geometric shapes.
Definition geometric_shapes.h:58
Center at zero point sphere.
Definition geometric_shapes.h:240
Simple transform class used locally by InterpMotion.
Definition transform.h:55
Vec3s transform(const Eigen::MatrixBase< Derived > &v) const
transform a given vector by the transform
Definition transform.h:152
const Matrix3s & getRotation() const
get rotation
Definition transform.h:110
const Vec3s & getTranslation() const
get translation
Definition transform.h:101
Triangle stores the points instead of only indices of points.
Definition geometric_shapes.h:110
#define COAL_UNUSED_VARIABLE(var)
Definition fwd.hh:56
CoalScalar distance(const Matrix3s &R0, const Vec3s &T0, const kIOS &b1, const kIOS &b2, Vec3s *P=NULL, Vec3s *Q=NULL)
Approximate distance between two kIOS bounding volumes.
Vec3s n
Plane normal.
Definition geometric_shapes.h:956
CoalScalar radius
Radius of the sphere.
Definition geometric_shapes.h:253
Vec3s n
Plane normal.
Definition geometric_shapes.h:1034
CoalScalar distance(const Vec3s &p) const
Definition geometric_shapes.h:924
CoalScalar halfLength
Half Length along z axis.
Definition geometric_shapes.h:587
Vec3s halfSide
box side half-length
Definition geometric_shapes.h:189
CoalScalar distance(const Vec3s &p) const
Definition geometric_shapes.h:1023
Vec3s a
Definition geometric_shapes.h:149
Vec3s b
Definition geometric_shapes.h:149
CoalScalar getSweptSphereRadius() const
Get radius of sphere swept around the shape. This radius is always >= 0.
Definition geometric_shapes.h:86
Vec3s c
Definition geometric_shapes.h:149
CoalScalar signedDistance(const Vec3s &p) const
Definition geometric_shapes.h:920
CoalScalar radius
Radius of capsule.
Definition geometric_shapes.h:399
CoalScalar d
Plane offset.
Definition geometric_shapes.h:1037
CoalScalar halfLength
Half Length along z axis.
Definition geometric_shapes.h:402
CoalScalar radius
Radius of the cylinder.
Definition geometric_shapes.h:584
CoalScalar d
Plane offset.
Definition geometric_shapes.h:959
Definition hfield.h:170
CoalScalar computePenetration(const Vec3s &P1, const Vec3s &P2, const Vec3s &P3, const Vec3s &Q1, const Vec3s &Q2, const Vec3s &Q3, Vec3s &normal)
See the prototype below.
Definition details.h:703
CoalScalar sphereCapsuleDistance(const Sphere &s1, const Transform3s &tf1, const Capsule &s2, const Transform3s &tf2, Vec3s &p1, Vec3s &p2, Vec3s &normal)
Definition details.h:75
CoalScalar halfspaceHalfspaceDistance(const Halfspace &s1, const Transform3s &tf1, const Halfspace &s2, const Transform3s &tf2, Vec3s &p1, Vec3s &p2, Vec3s &normal)
return distance between two halfspaces
Definition details.h:512
CoalScalar segmentSqrDistance(const Vec3s &from, const Vec3s &to, const Vec3s &p, Vec3s &nearest)
the minimum distance from a point to a line
Definition details.h:237
CoalScalar planePlaneDistance(const Plane &s1, const Transform3s &tf1, const Plane &s2, const Transform3s &tf2, Vec3s &p1, Vec3s &p2, Vec3s &normal)
return distance between two planes
Definition details.h:650
CoalScalar boxSphereDistance(const Box &b, const Transform3s &tfb, const Sphere &s, const Transform3s &tfs, Vec3s &pb, Vec3s &ps, Vec3s &normal)
Definition details.h:438
CoalScalar sphereTriangleDistance(const Sphere &s, const Transform3s &tf1, const TriangleP &tri, const Transform3s &tf2, Vec3s &p1, Vec3s &p2, Vec3s &normal)
Definition details.h:288
CoalScalar halfspacePlaneDistance(const Halfspace &s1, const Transform3s &tf1, const Plane &s2, const Transform3s &tf2, Vec3s &p1, Vec3s &p2, Vec3s &normal)
return distance between plane and halfspace.
Definition details.h:588
Vec3s getSupport(const ShapeBase *shape, const Vec3s &dir, int &hint)
the support function for shape. The output support point is expressed in the local frame of the shape...
CoalScalar sphereSphereDistance(const Sphere &s1, const Transform3s &tf1, const Sphere &s2, const Transform3s &tf2, Vec3s &p1, Vec3s &p2, Vec3s &normal)
Definition details.h:217
CoalScalar planeDistance(const Plane &plane, const Transform3s &tf1, const ShapeBase &s, const Transform3s &tf2, Vec3s &p1, Vec3s &p2, Vec3s &normal)
Definition details.h:384
CoalScalar halfspaceDistance(const Halfspace &h, const Transform3s &tf1, const ShapeBase &s, const Transform3s &tf2, Vec3s &p1, Vec3s &p2, Vec3s &normal)
Definition details.h:350
CoalScalar sphereCylinderDistance(const Sphere &s1, const Transform3s &tf1, const Cylinder &s2, const Transform3s &tf2, Vec3s &p1, Vec3s &p2, Vec3s &normal)
Definition details.h:108
bool projectInTriangle(const Vec3s &p1, const Vec3s &p2, const Vec3s &p3, const Vec3s &normal, const Vec3s &p)
Whether a point's projection is in a triangle.
Definition details.h:260
Main namespace.
Definition broadphase_bruteforce.h:44
Eigen::Matrix< CoalScalar, 3, 3 > Matrix3s
Definition data_types.h:81
std::array< Halfspace, 2 > transformToHalfspaces(const Plane &a, const Transform3s &tf)
Halfspace transform(const Halfspace &a, const Transform3s &tf)
Eigen::Matrix< CoalScalar, 3, 1 > Vec3s
Definition data_types.h:77
double CoalScalar
Definition data_types.h:76