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  */
39 #ifndef COAL_SRC_NARROWPHASE_DETAILS_H
40 #define COAL_SRC_NARROWPHASE_DETAILS_H
41 
44 
45 namespace coal {
46 namespace 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
51 static 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());
89  CoalScalar r1 = s1.radius + s1.getSweptSphereRadius();
91  CoalScalar dist = norm - r1 - r2;
92 
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) {
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());
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 
237 inline 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 
260 inline 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() =
366  getSupport<details::SupportOptions::WithSweptSphere>(&s, -n_2, hint);
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 
384 inline 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 =
401  getSupport<details::SupportOptions::WithSweptSphere>(&s, -n_h1, hint);
402  p2h1 = tf2.transform(p2h1);
403 
404  hint = 0;
405  Vec3s p2h2 =
406  getSupport<details::SupportOptions::WithSweptSphere>(&s, -n_h2, hint);
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 
438 inline 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 
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 
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.
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
coal::TriangleP::b
Vec3s b
Definition: coal/shape/geometric_shapes.h:149
coal::details::lineSegmentPointClosestToPoint
static void lineSegmentPointClosestToPoint(const Vec3s &p, const Vec3s &s1, const Vec3s &s2, Vec3s &sp)
Definition: details.h:51
coal::Cylinder::halfLength
CoalScalar halfLength
Half Length along z axis.
Definition: coal/shape/geometric_shapes.h:587
coal::Vec3s
Eigen::Matrix< CoalScalar, 3, 1 > Vec3s
Definition: coal/data_types.h:77
coal::details::halfspaceHalfspaceDistance
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
B
B
coal::transformToHalfspaces
COAL_DLLAPI std::array< Halfspace, 2 > transformToHalfspaces(const Plane &a, const Transform3s &tf)
Definition: geometric_shapes_utility.cpp:278
coal::Capsule::halfLength
CoalScalar halfLength
Half Length along z axis.
Definition: coal/shape/geometric_shapes.h:402
coal::Halfspace
Half Space: this is equivalent to the Plane in ODE. A Half space has a priviledged direction: the dir...
Definition: coal/shape/geometric_shapes.h:892
gjk.tf1
tuple tf1
Definition: test/scripts/gjk.py:27
coal::Capsule
Capsule It is where is the distance between the point x and the capsule segment AB,...
Definition: coal/shape/geometric_shapes.h:383
coal::Cylinder::radius
CoalScalar radius
Radius of the cylinder.
Definition: coal/shape/geometric_shapes.h:581
gjk.P2
tuple P2
Definition: test/scripts/gjk.py:22
coal
Main namespace.
Definition: coal/broadphase/broadphase_bruteforce.h:44
narrowphase.h
coal::details::halfspaceDistance
CoalScalar halfspaceDistance(const Halfspace &h, const Transform3s &tf1, const ShapeBase &s, const Transform3s &tf2, Vec3s &p1, Vec3s &p2, Vec3s &normal)
Definition: details.h:350
coal::details::projectInTriangle
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
coal::distance
COAL_DLLAPI CoalScalar distance(const Matrix3s &R0, const Vec3s &T0, const kIOS &b1, const kIOS &b2, Vec3s *P=NULL, Vec3s *Q=NULL)
Approximate distance between two kIOS bounding volumes.
Definition: kIOS.cpp:180
coal::Plane::distance
CoalScalar distance(const Vec3s &p) const
Definition: coal/shape/geometric_shapes.h:1023
eps
const CoalScalar eps
Definition: obb.cpp:93
coal::details::planePlaneDistance
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
coal::Plane
Infinite plane. A plane can be viewed as two half spaces; it has no priviledged direction....
Definition: coal/shape/geometric_shapes.h:983
coal::Box
Center at zero point, axis aligned box.
Definition: coal/shape/geometric_shapes.h:166
coal::Sphere
Center at zero point sphere.
Definition: coal/shape/geometric_shapes.h:240
traversal_node_setup.h
coal::Transform3s
Simple transform class used locally by InterpMotion.
Definition: coal/math/transform.h:55
coal::Halfspace::distance
CoalScalar distance(const Vec3s &p) const
Definition: coal/shape/geometric_shapes.h:924
COAL_UNUSED_VARIABLE
#define COAL_UNUSED_VARIABLE(var)
Definition: include/coal/fwd.hh:56
coal::TriangleP::a
Vec3s a
Definition: coal/shape/geometric_shapes.h:149
gjk.Q1
tuple Q1
Definition: test/scripts/gjk.py:24
gjk.P1
tuple P1
Definition: test/scripts/gjk.py:21
P
P
coal::ShapeBase
Base class for all basic geometric shapes.
Definition: coal/shape/geometric_shapes.h:58
coal::transform
COAL_DLLAPI Halfspace transform(const Halfspace &a, const Transform3s &tf)
Definition: geometric_shapes_utility.cpp:248
coal::details::planeDistance
CoalScalar planeDistance(const Plane &plane, const Transform3s &tf1, const ShapeBase &s, const Transform3s &tf2, Vec3s &p1, Vec3s &p2, Vec3s &normal)
Definition: details.h:384
coal::details::sphereTriangleDistance
CoalScalar sphereTriangleDistance(const Sphere &s, const Transform3s &tf1, const TriangleP &tri, const Transform3s &tf2, Vec3s &p1, Vec3s &p2, Vec3s &normal)
Definition: details.h:288
coal::Halfspace::signedDistance
CoalScalar signedDistance(const Vec3s &p) const
Definition: coal/shape/geometric_shapes.h:920
gjk.tf2
tuple tf2
Definition: test/scripts/gjk.py:36
coal::details::sphereSphereDistance
CoalScalar sphereSphereDistance(const Sphere &s1, const Transform3s &tf1, const Sphere &s2, const Transform3s &tf2, Vec3s &p1, Vec3s &p2, Vec3s &normal)
Definition: details.h:217
coal::Cylinder
Cylinder along Z axis. The cylinder is defined at its centroid.
Definition: coal/shape/geometric_shapes.h:560
axis
axis
coal::Transform3s::getRotation
const Matrix3s & getRotation() const
get rotation
Definition: coal/math/transform.h:110
octree.p1
tuple p1
Definition: octree.py:54
coal::details::computePenetration
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
coal::TriangleP
Triangle stores the points instead of only indices of points.
Definition: coal/shape/geometric_shapes.h:110
A
A
coal::ShapeBase::getSweptSphereRadius
CoalScalar getSweptSphereRadius() const
Get radius of sphere swept around the shape. This radius is always >= 0.
Definition: coal/shape/geometric_shapes.h:86
generate_distance_plot.b
float b
Definition: generate_distance_plot.py:7
epsilon
static CoalScalar epsilon
Definition: simple.cpp:12
coal::Halfspace::n
Vec3s n
Plane normal.
Definition: coal/shape/geometric_shapes.h:956
coal::details::sphereCylinderDistance
CoalScalar sphereCylinderDistance(const Sphere &s1, const Transform3s &tf1, const Cylinder &s2, const Transform3s &tf2, Vec3s &p1, Vec3s &p2, Vec3s &normal)
Definition: details.h:108
coal::details::boxSphereDistance
CoalScalar boxSphereDistance(const Box &b, const Transform3s &tfb, const Sphere &s, const Transform3s &tfs, Vec3s &pb, Vec3s &ps, Vec3s &normal)
Definition: details.h:438
gjk.Q3
tuple Q3
Definition: test/scripts/gjk.py:26
coal::Matrix3s
Eigen::Matrix< CoalScalar, 3, 3 > Matrix3s
Definition: coal/data_types.h:81
coal::Sphere::radius
CoalScalar radius
Radius of the sphere.
Definition: coal/shape/geometric_shapes.h:250
coal::Halfspace::d
CoalScalar d
Plane offset.
Definition: coal/shape/geometric_shapes.h:959
coal::Plane::n
Vec3s n
Plane normal.
Definition: coal/shape/geometric_shapes.h:1034
r2
r2
coal::details::halfspacePlaneDistance
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
coal::Capsule::radius
CoalScalar radius
Radius of capsule.
Definition: coal/shape/geometric_shapes.h:396
coal::details::segmentSqrDistance
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
coal::TriangleP::c
Vec3s c
Definition: coal/shape/geometric_shapes.h:149
gjk.P3
tuple P3
Definition: test/scripts/gjk.py:23
c2
c2
t
dictionary t
coal::details::sphereCapsuleDistance
CoalScalar sphereCapsuleDistance(const Sphere &s1, const Transform3s &tf1, const Capsule &s2, const Transform3s &tf2, Vec3s &p1, Vec3s &p2, Vec3s &normal)
Definition: details.h:75
coal::CoalScalar
double CoalScalar
Definition: coal/data_types.h:76
gjk.Q2
tuple Q2
Definition: test/scripts/gjk.py:25
coal::Plane::d
CoalScalar d
Plane offset.
Definition: coal/shape/geometric_shapes.h:1037
obb.v
list v
Definition: obb.py:48
coal::Transform3s::getTranslation
const Vec3s & getTranslation() const
get translation
Definition: coal/math/transform.h:101


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