hpp-fcl  3.0.0
HPP fork of FCL -- The Flexible Collision Library
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 HPP_FCL_SRC_NARROWPHASE_DETAILS_H
40 #define HPP_FCL_SRC_NARROWPHASE_DETAILS_H
41 
44 
45 namespace hpp {
46 namespace fcl {
47 namespace details {
48 // Compute the point on a line segment that is the closest point on the
49 // segment to to another point. The code is inspired by the explanation
50 // given by Dan Sunday's page:
51 // http://geomalgorithms.com/a02-_lines.html
52 static inline void lineSegmentPointClosestToPoint(const Vec3f& p,
53  const Vec3f& s1,
54  const Vec3f& s2, Vec3f& sp) {
55  Vec3f v = s2 - s1;
56  Vec3f w = p - s1;
57 
58  FCL_REAL c1 = w.dot(v);
59  FCL_REAL c2 = v.dot(v);
60 
61  if (c1 <= 0) {
62  sp = s1;
63  } else if (c2 <= c1) {
64  sp = s2;
65  } else {
66  FCL_REAL b = c1 / c2;
67  Vec3f Pb = s1 + v * b;
68  sp = Pb;
69  }
70 }
71 
76 inline FCL_REAL sphereCapsuleDistance(const Sphere& s1, const Transform3f& tf1,
77  const Capsule& s2, const Transform3f& tf2,
78  Vec3f& p1, Vec3f& p2, Vec3f& normal) {
79  Vec3f pos1(tf2.transform(Vec3f(0., 0., s2.halfLength)));
80  Vec3f pos2(tf2.transform(Vec3f(0., 0., -s2.halfLength)));
81  Vec3f s_c = tf1.getTranslation();
82 
83  Vec3f segment_point;
84 
85  lineSegmentPointClosestToPoint(s_c, pos1, pos2, segment_point);
86  normal = segment_point - s_c;
87  FCL_REAL norm(normal.norm());
88  FCL_REAL r1 = s1.radius + s1.getSweptSphereRadius();
89  FCL_REAL r2 = s2.radius + s2.getSweptSphereRadius();
90  FCL_REAL dist = norm - r1 - r2;
91 
92  static const FCL_REAL eps(std::numeric_limits<FCL_REAL>::epsilon());
93  if (norm > eps) {
94  normal.normalize();
95  } else {
96  normal << 1, 0, 0;
97  }
98  p1 = s_c + normal * r1;
99  p2 = segment_point - normal * r2;
100  return dist;
101 }
102 
107 inline FCL_REAL sphereCylinderDistance(const Sphere& s1, const Transform3f& tf1,
108  const Cylinder& s2,
109  const Transform3f& tf2, Vec3f& p1,
110  Vec3f& p2, Vec3f& normal) {
111  static const FCL_REAL eps(sqrt(std::numeric_limits<FCL_REAL>::epsilon()));
112  FCL_REAL r1(s1.radius);
113  FCL_REAL r2(s2.radius);
114  FCL_REAL lz2(s2.halfLength);
115  // boundaries of the cylinder axis
116  Vec3f A(tf2.transform(Vec3f(0, 0, -lz2)));
117  Vec3f B(tf2.transform(Vec3f(0, 0, lz2)));
118  // Position of the center of the sphere
119  Vec3f S(tf1.getTranslation());
120  // axis of the cylinder
121  Vec3f u(tf2.getRotation().col(2));
124  assert((B - A - (s2.halfLength * 2) * u).norm() < eps);
125  Vec3f AS(S - A);
126  // abscissa of S on cylinder axis with A as the origin
127  FCL_REAL s(u.dot(AS));
128  Vec3f P(A + s * u);
129  Vec3f PS(S - P);
130  FCL_REAL dPS = PS.norm();
131  // Normal to cylinder axis such that plane (A, u, v) contains sphere
132  // center
133  Vec3f v(0, 0, 0);
134  FCL_REAL dist;
135  if (dPS > eps) {
136  // S is not on cylinder axis
137  v = (1 / dPS) * PS;
138  }
139  if (s <= 0) {
140  if (dPS <= r2) {
141  // closest point on cylinder is on cylinder disc basis
142  dist = -s - r1;
143  p1 = S + r1 * u;
144  p2 = A + dPS * v;
145  normal = u;
146  } else {
147  // closest point on cylinder is on cylinder circle basis
148  p2 = A + r2 * v;
149  Vec3f Sp2(p2 - S);
150  FCL_REAL dSp2 = Sp2.norm();
151  if (dSp2 > eps) {
152  normal = (1 / dSp2) * Sp2;
153  p1 = S + r1 * normal;
154  dist = dSp2 - r1;
155  assert(fabs(dist) - (p1 - p2).norm() < eps);
156  } else {
157  // Center of sphere is on cylinder boundary
158  normal = p2 - .5 * (A + B);
159  assert(u.dot(normal) >= 0);
160  normal.normalize();
161  dist = -r1;
162  p1 = S + r1 * normal;
163  }
164  }
165  } else if (s <= (s2.halfLength * 2)) {
166  // 0 < s <= s2.lz
167  normal = -v;
168  dist = dPS - r1 - r2;
169  p2 = P + r2 * v;
170  p1 = S - r1 * v;
171  } else {
172  // lz < s
173  if (dPS <= r2) {
174  // closest point on cylinder is on cylinder disc basis
175  dist = s - (s2.halfLength * 2) - r1;
176  p1 = S - r1 * u;
177  p2 = B + dPS * v;
178  normal = -u;
179  } else {
180  // closest point on cylinder is on cylinder circle basis
181  p2 = B + r2 * v;
182  Vec3f Sp2(p2 - S);
183  FCL_REAL dSp2 = Sp2.norm();
184  if (dSp2 > eps) {
185  normal = (1 / dSp2) * Sp2;
186  p1 = S + r1 * normal;
187  dist = dSp2 - r1;
188  assert(fabs(dist) - (p1 - p2).norm() < eps);
189  } else {
190  // Center of sphere is on cylinder boundary
191  normal = p2 - .5 * (A + B);
192  normal.normalize();
193  p1 = S + r1 * normal;
194  dist = -r1;
195  }
196  }
197  }
198 
199  // Take swept-sphere radius into account
200  const FCL_REAL ssr1 = s1.getSweptSphereRadius();
201  const FCL_REAL ssr2 = s2.getSweptSphereRadius();
202  if (ssr1 > 0 || ssr2 > 0) {
203  p1 += ssr1 * normal;
204  p2 -= ssr2 * normal;
205  dist -= (ssr1 + ssr2);
206  }
207 
208  return dist;
209 }
210 
215 inline FCL_REAL sphereSphereDistance(const Sphere& s1, const Transform3f& tf1,
216  const Sphere& s2, const Transform3f& tf2,
217  Vec3f& p1, Vec3f& p2, Vec3f& normal) {
218  const fcl::Vec3f& center1 = tf1.getTranslation();
219  const fcl::Vec3f& center2 = tf2.getTranslation();
220  FCL_REAL r1 = (s1.radius + s1.getSweptSphereRadius());
221  FCL_REAL r2 = (s2.radius + s2.getSweptSphereRadius());
222 
223  Vec3f c1c2 = center2 - center1;
224  FCL_REAL cdist = c1c2.norm();
225  Vec3f unit(1, 0, 0);
226  if (cdist > Eigen::NumTraits<FCL_REAL>::epsilon()) unit = c1c2 / cdist;
227  FCL_REAL dist = cdist - r1 - r2;
228  normal = unit;
229  p1.noalias() = center1 + r1 * unit;
230  p2.noalias() = center2 - r2 * unit;
231  return dist;
232 }
233 
235 inline FCL_REAL segmentSqrDistance(const Vec3f& from, const Vec3f& to,
236  const Vec3f& p, Vec3f& nearest) {
237  Vec3f diff = p - from;
238  Vec3f v = to - from;
239  FCL_REAL t = v.dot(diff);
240 
241  if (t > 0) {
242  FCL_REAL dotVV = v.squaredNorm();
243  if (t < dotVV) {
244  t /= dotVV;
245  diff -= v * t;
246  } else {
247  t = 1;
248  diff -= v;
249  }
250  } else
251  t = 0;
252 
253  nearest.noalias() = from + v * t;
254  return diff.squaredNorm();
255 }
256 
258 inline bool projectInTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3,
259  const Vec3f& normal, const Vec3f& p) {
260  Vec3f edge1(p2 - p1);
261  Vec3f edge2(p3 - p2);
262  Vec3f edge3(p1 - p3);
263 
264  Vec3f p1_to_p(p - p1);
265  Vec3f p2_to_p(p - p2);
266  Vec3f p3_to_p(p - p3);
267 
268  Vec3f edge1_normal(edge1.cross(normal));
269  Vec3f edge2_normal(edge2.cross(normal));
270  Vec3f edge3_normal(edge3.cross(normal));
271 
272  FCL_REAL r1, r2, r3;
273  r1 = edge1_normal.dot(p1_to_p);
274  r2 = edge2_normal.dot(p2_to_p);
275  r3 = edge3_normal.dot(p3_to_p);
276  if ((r1 > 0 && r2 > 0 && r3 > 0) || (r1 <= 0 && r2 <= 0 && r3 <= 0)) {
277  return true;
278  }
279  return false;
280 }
281 
286 inline FCL_REAL sphereTriangleDistance(const Sphere& s, const Transform3f& tf1,
287  const TriangleP& tri,
288  const Transform3f& tf2, Vec3f& p1,
289  Vec3f& p2, Vec3f& normal) {
290  const Vec3f& P1 = tf2.transform(tri.a);
291  const Vec3f& P2 = tf2.transform(tri.b);
292  const Vec3f& P3 = tf2.transform(tri.c);
293 
294  Vec3f tri_normal = (P2 - P1).cross(P3 - P1);
295  tri_normal.normalize();
296  const Vec3f& center = tf1.getTranslation();
297  // Note: comparing an object with a swept-sphere radius of r1 against another
298  // object with a swept-sphere radius of r2 is equivalent to comparing the
299  // first object with a swept-sphere radius of r1 + r2 against the second
300  // object with a swept-sphere radius of 0.
301  const FCL_REAL& radius =
303  assert(radius >= 0);
304  assert(s.radius >= 0);
305  Vec3f p1_to_center = center - P1;
306  FCL_REAL distance_from_plane = p1_to_center.dot(tri_normal);
307  Vec3f closest_point(
308  Vec3f::Constant(std::numeric_limits<FCL_REAL>::quiet_NaN()));
309  FCL_REAL min_distance_sqr, distance_sqr;
310 
311  if (distance_from_plane < 0) {
312  distance_from_plane *= -1;
313  tri_normal *= -1;
314  }
315 
316  if (projectInTriangle(P1, P2, P3, tri_normal, center)) {
317  closest_point = center - tri_normal * distance_from_plane;
318  min_distance_sqr = distance_from_plane * distance_from_plane;
319  } else {
320  // Compute distance to each edge and take minimal distance
321  Vec3f nearest_on_edge;
322  min_distance_sqr = segmentSqrDistance(P1, P2, center, closest_point);
323 
324  distance_sqr = segmentSqrDistance(P2, P3, center, nearest_on_edge);
325  if (distance_sqr < min_distance_sqr) {
326  min_distance_sqr = distance_sqr;
327  closest_point = nearest_on_edge;
328  }
329  distance_sqr = segmentSqrDistance(P3, P1, center, nearest_on_edge);
330  if (distance_sqr < min_distance_sqr) {
331  min_distance_sqr = distance_sqr;
332  closest_point = nearest_on_edge;
333  }
334  }
335 
336  normal = (closest_point - center).normalized();
337  p1 = center + normal * (s.radius + s.getSweptSphereRadius());
338  p2 = closest_point - normal * tri.getSweptSphereRadius();
339  const FCL_REAL distance = std::sqrt(min_distance_sqr) - radius;
340  return distance;
341 }
342 
347 inline FCL_REAL halfspaceDistance(const Halfspace& h, const Transform3f& tf1,
348  const ShapeBase& s, const Transform3f& tf2,
349  Vec3f& p1, Vec3f& p2, Vec3f& normal) {
350  // TODO(louis): handle multiple contact points when the halfspace normal is
351  // parallel to the shape's surface (every primitive except sphere and
352  // ellipsoid).
353 
354  // Express halfspace in world frame
355  Halfspace new_h = transform(h, tf1);
356 
357  // Express halfspace normal in shape frame
358  Vec3f n_2(tf2.getRotation().transpose() * new_h.n);
359 
360  // Compute support of shape in direction of halfspace normal
361  int hint = 0;
362  p2.noalias() =
363  getSupport<details::SupportOptions::WithSweptSphere>(&s, -n_2, hint);
364  p2 = tf2.transform(p2);
365 
366  const FCL_REAL dist = new_h.signedDistance(p2);
367  p1.noalias() = p2 - dist * new_h.n;
368  normal.noalias() = new_h.n;
369 
370  const FCL_REAL dummy_precision =
371  std::sqrt(Eigen::NumTraits<FCL_REAL>::dummy_precision());
372  HPP_FCL_UNUSED_VARIABLE(dummy_precision);
373  assert(new_h.distance(p1) <= dummy_precision);
374  return dist;
375 }
376 
381 inline FCL_REAL planeDistance(const Plane& plane, const Transform3f& tf1,
382  const ShapeBase& s, const Transform3f& tf2,
383  Vec3f& p1, Vec3f& p2, Vec3f& normal) {
384  // TODO(louis): handle multiple contact points when the plane normal is
385  // parallel to the shape's surface (every primitive except sphere and
386  // ellipsoid).
387 
388  // Express plane as two halfspaces in world frame
389  std::array<Halfspace, 2> new_h = transformToHalfspaces(plane, tf1);
390 
391  // Express halfspace normals in shape frame
392  Vec3f n_h1(tf2.getRotation().transpose() * new_h[0].n);
393  Vec3f n_h2(tf2.getRotation().transpose() * new_h[1].n);
394 
395  // Compute support of shape in direction of halfspace normal and its opposite
396  int hint = 0;
397  Vec3f p2h1 =
398  getSupport<details::SupportOptions::WithSweptSphere>(&s, -n_h1, hint);
399  p2h1 = tf2.transform(p2h1);
400 
401  hint = 0;
402  Vec3f p2h2 =
403  getSupport<details::SupportOptions::WithSweptSphere>(&s, -n_h2, hint);
404  p2h2 = tf2.transform(p2h2);
405 
406  FCL_REAL dist1 = new_h[0].signedDistance(p2h1);
407  FCL_REAL dist2 = new_h[1].signedDistance(p2h2);
408 
409  const FCL_REAL dummy_precision =
410  std::sqrt(Eigen::NumTraits<FCL_REAL>::dummy_precision());
411  HPP_FCL_UNUSED_VARIABLE(dummy_precision);
412 
413  FCL_REAL dist;
414  if (dist1 >= dist2) {
415  dist = dist1;
416  p2.noalias() = p2h1;
417  p1.noalias() = p2 - dist * new_h[0].n;
418  normal.noalias() = new_h[0].n;
419  assert(new_h[0].distance(p1) <= dummy_precision);
420  } else {
421  dist = dist2;
422  p2.noalias() = p2h2;
423  p1.noalias() = p2 - dist * new_h[1].n;
424  normal.noalias() = new_h[1].n;
425  assert(new_h[1].distance(p1) <= dummy_precision);
426  }
427  return dist;
428 }
429 
435 inline FCL_REAL boxSphereDistance(const Box& b, const Transform3f& tfb,
436  const Sphere& s, const Transform3f& tfs,
437  Vec3f& pb, Vec3f& ps, Vec3f& normal) {
438  const Vec3f& os = tfs.getTranslation();
439  const Vec3f& ob = tfb.getTranslation();
440  const Matrix3f& Rb = tfb.getRotation();
441 
442  pb = ob;
443 
444  bool outside = false;
445  const Vec3f os_in_b_frame(Rb.transpose() * (os - ob));
446  int axis = -1;
447  FCL_REAL min_d = (std::numeric_limits<FCL_REAL>::max)();
448  for (int i = 0; i < 3; ++i) {
449  FCL_REAL facedist;
450  if (os_in_b_frame(i) < -b.halfSide(i)) { // outside
451  pb.noalias() -= b.halfSide(i) * Rb.col(i);
452  outside = true;
453  } else if (os_in_b_frame(i) > b.halfSide(i)) { // outside
454  pb.noalias() += b.halfSide(i) * Rb.col(i);
455  outside = true;
456  } else {
457  pb.noalias() += os_in_b_frame(i) * Rb.col(i);
458  if (!outside &&
459  (facedist = b.halfSide(i) - std::fabs(os_in_b_frame(i))) < min_d) {
460  axis = i;
461  min_d = facedist;
462  }
463  }
464  }
465  normal = pb - os;
466  FCL_REAL pdist = normal.norm();
467  FCL_REAL dist; // distance between sphere and box
468  if (outside) { // pb is on the box
469  dist = pdist - s.radius;
470  normal /= -pdist;
471  } else { // pb is inside the box
472  if (os_in_b_frame(axis) >= 0) {
473  normal = Rb.col(axis);
474  } else {
475  normal = -Rb.col(axis);
476  }
477  dist = -min_d - s.radius;
478  }
479  ps = os - s.radius * normal;
480  if (!outside || dist <= 0) {
481  // project point pb onto the box's surface
482  pb = ps - dist * normal;
483  }
484 
485  // Take swept-sphere radius into account
486  const FCL_REAL ssrb = b.getSweptSphereRadius();
487  const FCL_REAL ssrs = s.getSweptSphereRadius();
488  if (ssrb > 0 || ssrs > 0) {
489  pb += ssrb * normal;
490  ps -= ssrs * normal;
491  dist -= (ssrb + ssrs);
492  }
493 
494  return dist;
495 }
496 
510  const Transform3f& tf1,
511  const Halfspace& s2,
512  const Transform3f& tf2, Vec3f& p1,
513  Vec3f& p2, Vec3f& normal) {
514  Halfspace new_s1 = transform(s1, tf1);
515  Halfspace new_s2 = transform(s2, tf2);
516 
518  Vec3f dir = (new_s1.n).cross(new_s2.n);
519  FCL_REAL dir_sq_norm = dir.squaredNorm();
520 
521  if (dir_sq_norm < std::numeric_limits<FCL_REAL>::epsilon()) // parallel
522  {
523  if (new_s1.n.dot(new_s2.n) > 0) {
524  // If the two halfspaces have the same normal, one is inside the other
525  // and they can't be separated. They have inifinte penetration depth.
526  distance = -(std::numeric_limits<FCL_REAL>::max)();
527  if (new_s1.d <= new_s2.d) {
528  normal = new_s1.n;
529  p1 = normal * distance;
530  p2 = new_s2.n * new_s2.d;
531  assert(new_s2.distance(p2) <=
532  Eigen::NumTraits<FCL_REAL>::dummy_precision());
533  } else {
534  normal = -new_s1.n;
535  p1 << new_s1.n * new_s1.d;
536  p2 = -(normal * distance);
537  assert(new_s1.distance(p1) <=
538  Eigen::NumTraits<FCL_REAL>::dummy_precision());
539  }
540  } else {
541  distance = -(new_s1.d + new_s2.d);
542  normal = new_s1.n;
543  p1 = new_s1.n * new_s1.d;
544  p2 = new_s2.n * new_s2.d;
545  }
546  } else {
547  // If the halfspaces are not parallel, they are in collision.
548  // Their distance, in the sens of the norm of separation vector, is infinite
549  // (it's impossible to find a translation which separates them)
550  distance = -(std::numeric_limits<FCL_REAL>::max)();
551  // p1 and p2 are the same point, corresponding to a point on the
552  // intersection line between the two objects. Normal is the direction of
553  // that line.
554  normal = dir;
555  p1 = p2 =
556  ((new_s2.n * new_s1.d - new_s1.n * new_s2.d).cross(dir)) / dir_sq_norm;
557  // Sources: https://en.wikipedia.org/wiki/Plane%E2%80%93plane_intersection
558  // and https://en.wikipedia.org/wiki/Cross_product
559  }
560 
561  // Take swept-sphere radius into account
562  const FCL_REAL ssr1 = s1.getSweptSphereRadius();
563  const FCL_REAL ssr2 = s2.getSweptSphereRadius();
564  if (ssr1 > 0 || ssr2 > 0) {
565  p1 += ssr1 * normal;
566  p2 -= ssr2 * normal;
567  distance -= (ssr1 + ssr2);
568  }
569 
570  return distance;
571 }
572 
586  const Transform3f& tf1, const Plane& s2,
587  const Transform3f& tf2, Vec3f& p1,
588  Vec3f& p2, Vec3f& normal) {
589  Halfspace new_s1 = transform(s1, tf1);
590  Plane new_s2 = transform(s2, tf2);
591 
593  Vec3f dir = (new_s1.n).cross(new_s2.n);
594  FCL_REAL dir_sq_norm = dir.squaredNorm();
595 
596  if (dir_sq_norm < std::numeric_limits<FCL_REAL>::epsilon()) // parallel
597  {
598  normal = new_s1.n;
599  distance = new_s1.n.dot(new_s2.n) > 0 ? (new_s2.d - new_s1.d)
600  : -(new_s1.d + new_s2.d);
601  p1 = new_s1.n * new_s1.d;
602  p2 = new_s2.n * new_s2.d;
603  assert(new_s1.distance(p1) <=
604  Eigen::NumTraits<FCL_REAL>::dummy_precision());
605  assert(new_s2.distance(p2) <=
606  Eigen::NumTraits<FCL_REAL>::dummy_precision());
607  } else {
608  // If the halfspace and plane are not parallel, they are in collision.
609  // Their distance, in the sens of the norm of separation vector, is infinite
610  // (it's impossible to find a translation which separates them)
611  distance = -(std::numeric_limits<FCL_REAL>::max)();
612  // p1 and p2 are the same point, corresponding to a point on the
613  // intersection line between the two objects. Normal is the direction of
614  // that line.
615  normal = dir;
616  p1 = p2 =
617  ((new_s2.n * new_s1.d - new_s1.n * new_s2.d).cross(dir)) / dir_sq_norm;
618  // Sources: https://en.wikipedia.org/wiki/Plane%E2%80%93plane_intersection
619  // and https://en.wikipedia.org/wiki/Cross_product
620  }
621 
622  // Take swept-sphere radius into account
623  const FCL_REAL ssr1 = s1.getSweptSphereRadius();
624  const FCL_REAL ssr2 = s2.getSweptSphereRadius();
625  if (ssr1 > 0 || ssr2 > 0) {
626  p1 += ssr1 * normal;
627  p2 -= ssr2 * normal;
628  distance -= (ssr1 + ssr2);
629  }
630 
631  return distance;
632 }
633 
646 inline FCL_REAL planePlaneDistance(const Plane& s1, const Transform3f& tf1,
647  const Plane& s2, const Transform3f& tf2,
648  Vec3f& p1, Vec3f& p2, Vec3f& normal) {
649  Plane new_s1 = transform(s1, tf1);
650  Plane new_s2 = transform(s2, tf2);
651 
653  Vec3f dir = (new_s1.n).cross(new_s2.n);
654  FCL_REAL dir_sq_norm = dir.squaredNorm();
655 
656  if (dir_sq_norm < std::numeric_limits<FCL_REAL>::epsilon()) // parallel
657  {
658  p1 = new_s1.n * new_s1.d;
659  p2 = new_s2.n * new_s2.d;
660  assert(new_s1.distance(p1) <=
661  Eigen::NumTraits<FCL_REAL>::dummy_precision());
662  assert(new_s2.distance(p2) <=
663  Eigen::NumTraits<FCL_REAL>::dummy_precision());
664  distance = (p1 - p2).norm();
665 
666  if (distance > Eigen::NumTraits<FCL_REAL>::dummy_precision()) {
667  normal = (p2 - p1).normalized();
668  } else {
669  normal = new_s1.n;
670  }
671  } else {
672  // If the planes are not parallel, they are in collision.
673  // Their distance, in the sens of the norm of separation vector, is infinite
674  // (it's impossible to find a translation which separates them)
675  distance = -(std::numeric_limits<FCL_REAL>::max)();
676  // p1 and p2 are the same point, corresponding to a point on the
677  // intersection line between the two objects. Normal is the direction of
678  // that line.
679  normal = dir;
680  p1 = p2 =
681  ((new_s2.n * new_s1.d - new_s1.n * new_s2.d).cross(dir)) / dir_sq_norm;
682  // Sources: https://en.wikipedia.org/wiki/Plane%E2%80%93plane_intersection
683  // and https://en.wikipedia.org/wiki/Cross_product
684  }
685 
686  // Take swept-sphere radius into account
687  const FCL_REAL ssr1 = s1.getSweptSphereRadius();
688  const FCL_REAL ssr2 = s2.getSweptSphereRadius();
689  if (ssr1 > 0 || ssr2 > 0) {
690  p1 += ssr1 * normal;
691  p2 -= ssr2 * normal;
692  distance -= (ssr1 + ssr2);
693  }
694 
695  return distance;
696 }
697 
699 inline FCL_REAL computePenetration(const Vec3f& P1, const Vec3f& P2,
700  const Vec3f& P3, const Vec3f& Q1,
701  const Vec3f& Q2, const Vec3f& Q3,
702  Vec3f& normal) {
703  Vec3f u((P2 - P1).cross(P3 - P1));
704  normal = u.normalized();
705  FCL_REAL depth1((P1 - Q1).dot(normal));
706  FCL_REAL depth2((P1 - Q2).dot(normal));
707  FCL_REAL depth3((P1 - Q3).dot(normal));
708  return std::max(depth1, std::max(depth2, depth3));
709 }
710 
711 // Compute penetration distance and normal of two triangles in collision
712 // Normal is normal of triangle 1 (P1, P2, P3), penetration depth is the
713 // minimal distance (Q1, Q2, Q3) should be translated along the normal so
714 // that the triangles are collision free.
715 //
716 // Note that we compute here an upper bound of the penetration distance,
717 // not the exact value.
718 inline FCL_REAL computePenetration(const Vec3f& P1, const Vec3f& P2,
719  const Vec3f& P3, const Vec3f& Q1,
720  const Vec3f& Q2, const Vec3f& Q3,
721  const Transform3f& tf1,
722  const Transform3f& tf2, Vec3f& normal) {
723  Vec3f globalP1(tf1.transform(P1));
724  Vec3f globalP2(tf1.transform(P2));
725  Vec3f globalP3(tf1.transform(P3));
726  Vec3f globalQ1(tf2.transform(Q1));
727  Vec3f globalQ2(tf2.transform(Q2));
728  Vec3f globalQ3(tf2.transform(Q3));
729  return computePenetration(globalP1, globalP2, globalP3, globalQ1, globalQ2,
730  globalQ3, normal);
731 }
732 
733 } // namespace details
734 } // namespace fcl
735 } // namespace hpp
736 
737 #endif // HPP_FCL_SRC_NARROWPHASE_DETAILS_H
Center at zero point, axis aligned box.
Definition: geometric_shapes.h:164
Capsule It is where is the distance between the point x and the capsule segment AB,...
Definition: geometric_shapes.h:381
Cylinder along Z axis. The cylinder is defined at its centroid.
Definition: geometric_shapes.h:555
Half Space: this is equivalent to the Plane in ODE. A Half space has a priviledged direction: the dir...
Definition: geometric_shapes.h:885
Infinite plane. A plane can be viewed as two half spaces; it has no priviledged direction....
Definition: geometric_shapes.h:976
Base class for all basic geometric shapes.
Definition: geometric_shapes.h:59
Center at zero point sphere.
Definition: geometric_shapes.h:238
Simple transform class used locally by InterpMotion.
Definition: transform.h:56
const Vec3f & getTranslation() const
get translation
Definition: transform.h:102
const Matrix3f & getRotation() const
get rotation
Definition: transform.h:111
Vec3f transform(const Eigen::MatrixBase< Derived > &v) const
transform a given vector by the transform
Definition: transform.h:153
Triangle stores the points instead of only indices of points.
Definition: geometric_shapes.h:109
#define HPP_FCL_UNUSED_VARIABLE(var)
Definition: fwd.hh:56
FCL_REAL distance(const Matrix3f &R0, const Vec3f &T0, const kIOS &b1, const kIOS &b2, Vec3f *P=NULL, Vec3f *Q=NULL)
Approximate distance between two kIOS bounding volumes.
Vec3f c
Definition: geometric_shapes.h:147
FCL_REAL halfLength
Half Length along z axis.
Definition: geometric_shapes.h:400
FCL_REAL getSweptSphereRadius() const
Get radius of sphere swept around the shape. This radius is always >= 0.
Definition: geometric_shapes.h:87
FCL_REAL distance(const Vec3f &p) const
Definition: geometric_shapes.h:917
Vec3f a
Definition: geometric_shapes.h:147
FCL_REAL halfLength
Half Length along z axis.
Definition: geometric_shapes.h:582
Vec3f n
Plane normal.
Definition: geometric_shapes.h:1027
FCL_REAL radius
Radius of capsule.
Definition: geometric_shapes.h:394
Vec3f n
Plane normal.
Definition: geometric_shapes.h:949
FCL_REAL signedDistance(const Vec3f &p) const
Definition: geometric_shapes.h:913
FCL_REAL distance(const Vec3f &p) const
Definition: geometric_shapes.h:1016
FCL_REAL d
Plane offset.
Definition: geometric_shapes.h:1030
FCL_REAL radius
Radius of the sphere.
Definition: geometric_shapes.h:248
Vec3f halfSide
box side half-length
Definition: geometric_shapes.h:187
FCL_REAL radius
Radius of the cylinder.
Definition: geometric_shapes.h:576
Vec3f b
Definition: geometric_shapes.h:147
FCL_REAL d
Plane offset.
Definition: geometric_shapes.h:952
FCL_REAL halfspaceHalfspaceDistance(const Halfspace &s1, const Transform3f &tf1, const Halfspace &s2, const Transform3f &tf2, Vec3f &p1, Vec3f &p2, Vec3f &normal)
return distance between two halfspaces
Definition: details.h:509
FCL_REAL sphereCapsuleDistance(const Sphere &s1, const Transform3f &tf1, const Capsule &s2, const Transform3f &tf2, Vec3f &p1, Vec3f &p2, Vec3f &normal)
Definition: details.h:76
FCL_REAL sphereCylinderDistance(const Sphere &s1, const Transform3f &tf1, const Cylinder &s2, const Transform3f &tf2, Vec3f &p1, Vec3f &p2, Vec3f &normal)
Definition: details.h:107
FCL_REAL sphereSphereDistance(const Sphere &s1, const Transform3f &tf1, const Sphere &s2, const Transform3f &tf2, Vec3f &p1, Vec3f &p2, Vec3f &normal)
Definition: details.h:215
FCL_REAL boxSphereDistance(const Box &b, const Transform3f &tfb, const Sphere &s, const Transform3f &tfs, Vec3f &pb, Vec3f &ps, Vec3f &normal)
Definition: details.h:435
FCL_REAL computePenetration(const Vec3f &P1, const Vec3f &P2, const Vec3f &P3, const Vec3f &Q1, const Vec3f &Q2, const Vec3f &Q3, Vec3f &normal)
See the prototype below.
Definition: details.h:699
FCL_REAL halfspaceDistance(const Halfspace &h, const Transform3f &tf1, const ShapeBase &s, const Transform3f &tf2, Vec3f &p1, Vec3f &p2, Vec3f &normal)
Definition: details.h:347
FCL_REAL planeDistance(const Plane &plane, const Transform3f &tf1, const ShapeBase &s, const Transform3f &tf2, Vec3f &p1, Vec3f &p2, Vec3f &normal)
Definition: details.h:381
FCL_REAL planePlaneDistance(const Plane &s1, const Transform3f &tf1, const Plane &s2, const Transform3f &tf2, Vec3f &p1, Vec3f &p2, Vec3f &normal)
return distance between two planes
Definition: details.h:646
FCL_REAL halfspacePlaneDistance(const Halfspace &s1, const Transform3f &tf1, const Plane &s2, const Transform3f &tf2, Vec3f &p1, Vec3f &p2, Vec3f &normal)
return distance between plane and halfspace.
Definition: details.h:585
bool projectInTriangle(const Vec3f &p1, const Vec3f &p2, const Vec3f &p3, const Vec3f &normal, const Vec3f &p)
Whether a point's projection is in a triangle.
Definition: details.h:258
FCL_REAL sphereTriangleDistance(const Sphere &s, const Transform3f &tf1, const TriangleP &tri, const Transform3f &tf2, Vec3f &p1, Vec3f &p2, Vec3f &normal)
Definition: details.h:286
FCL_REAL segmentSqrDistance(const Vec3f &from, const Vec3f &to, const Vec3f &p, Vec3f &nearest)
the minimum distance from a point to a line
Definition: details.h:235
Eigen::Matrix< FCL_REAL, 3, 3 > Matrix3f
Definition: data_types.h:71
Eigen::Matrix< FCL_REAL, 3, 1 > Vec3f
Definition: data_types.h:67
std::array< Halfspace, 2 > transformToHalfspaces(const Plane &a, const Transform3f &tf)
Halfspace transform(const Halfspace &a, const Transform3f &tf)
double FCL_REAL
Definition: data_types.h:66
Main namespace.
Definition: broadphase_bruteforce.h:44