test/contact_patch.cpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2024, INRIA
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of INRIA nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
37 #define BOOST_TEST_MODULE COAL_CONTACT_PATCH
38 #include <boost/test/included/unit_test.hpp>
39 
40 #include "coal/contact_patch.h"
41 
42 #include "utility.h"
43 
44 using namespace coal;
45 
46 BOOST_AUTO_TEST_CASE(box_box_no_collision) {
47  const CoalScalar halfside = 0.5;
48  const Box box1(2 * halfside, 2 * halfside, 2 * halfside);
49  const Box box2(2 * halfside, 2 * halfside, 2 * halfside);
50 
51  const Transform3s tf1;
53  // set translation to separate the shapes
54  const CoalScalar offset = 0.001;
55  tf2.setTranslation(Vec3s(0, 0, 2 * halfside + offset));
56 
57  const size_t num_max_contact = 1;
59  num_max_contact);
60  CollisionResult col_res;
61 
62  coal::collide(&box1, tf1, &box2, tf2, col_req, col_res);
63 
64  BOOST_CHECK(!col_res.isCollision());
65 
66  const ContactPatchRequest patch_req;
67  ContactPatchResult patch_res(patch_req);
68  coal::computeContactPatch(&box1, tf1, &box2, tf2, col_res, patch_req,
69  patch_res);
70  BOOST_CHECK(patch_res.numContactPatches() == 0);
71 }
72 
73 BOOST_AUTO_TEST_CASE(box_sphere) {
74  const CoalScalar halfside = 0.5;
75  const Box box(2 * halfside, 2 * halfside, 2 * halfside);
76  const Sphere sphere(halfside);
77 
78  const Transform3s tf1;
80  // set translation to have a collision
81  const CoalScalar offset = 0.001;
82  tf2.setTranslation(Vec3s(0, 0, 2 * halfside - offset));
83 
84  const size_t num_max_contact = 1;
86  num_max_contact);
87  CollisionResult col_res;
88 
89  coal::collide(&box, tf1, &sphere, tf2, col_req, col_res);
90 
91  BOOST_CHECK(col_res.isCollision());
92 
93  const ContactPatchRequest patch_req;
94  ContactPatchResult patch_res(patch_req);
95  coal::computeContactPatch(&box, tf1, &sphere, tf2, col_res, patch_req,
96  patch_res);
97  BOOST_CHECK(patch_res.numContactPatches() == 1);
98  if (patch_res.numContactPatches() > 0 && col_res.isCollision()) {
99  const Contact& contact = col_res.getContact(0);
100  const ContactPatch& contact_patch = patch_res.getContactPatch(0);
101  BOOST_CHECK(contact_patch.size() == 1);
102  const CoalScalar tol = 1e-8;
103  EIGEN_VECTOR_IS_APPROX(contact_patch.getPoint(0), contact.pos, tol);
104  EIGEN_VECTOR_IS_APPROX(contact_patch.tf.translation(), contact.pos, tol);
105  EIGEN_VECTOR_IS_APPROX(contact_patch.getNormal(), contact.normal, tol);
106  BOOST_CHECK(std::abs(contact_patch.penetration_depth -
107  contact.penetration_depth) < tol);
108  }
109 }
110 
112  const CoalScalar halfside = 0.5;
113  const Box box1(2 * halfside, 2 * halfside, 2 * halfside);
114  const Box box2(2 * halfside, 2 * halfside, 2 * halfside);
115 
116  const Transform3s tf1;
118  // set translation to have a collision
119  const CoalScalar offset = 0.001;
120  tf2.setTranslation(Vec3s(0, 0, 2 * halfside - offset));
121 
122  const size_t num_max_contact = 1;
124  num_max_contact);
125  CollisionResult col_res;
126 
127  coal::collide(&box1, tf1, &box2, tf2, col_req, col_res);
128 
129  BOOST_CHECK(col_res.isCollision());
130 
131  const ContactPatchRequest patch_req;
132  ContactPatchResult patch_res1(patch_req);
133  ContactPatchResult patch_res2(patch_req);
134  coal::computeContactPatch(&box1, tf1, &box2, tf2, col_res, patch_req,
135  patch_res1);
136  coal::computeContactPatch(&box1, tf1, &box2, tf2, col_res, patch_req,
137  patch_res2);
138  BOOST_CHECK(patch_res1.numContactPatches() == 1);
139  BOOST_CHECK(patch_res2.numContactPatches() == 1);
140 
141  if (patch_res1.numContactPatches() > 0 &&
142  patch_res2.numContactPatches() > 0 && col_res.isCollision()) {
143  const Contact& contact = col_res.getContact(0);
144  const CoalScalar tol = 1e-6;
145  EIGEN_VECTOR_IS_APPROX(contact.normal, Vec3s(0, 0, 1), tol);
146 
147  const size_t expected_size = 4;
148  ContactPatch expected(expected_size);
149  expected.tf.rotation() =
151  expected.tf.translation() = contact.pos;
152  expected.penetration_depth = contact.penetration_depth;
153  const std::array<Vec3s, 4> corners = {
154  Vec3s(halfside, halfside, halfside),
155  Vec3s(halfside, -halfside, halfside),
156  Vec3s(-halfside, -halfside, halfside),
157  Vec3s(-halfside, halfside, halfside),
158  };
159  for (size_t i = 0; i < expected_size; ++i) {
160  expected.addPoint(corners[i] +
161  (contact.penetration_depth * contact.normal) / 2);
162  }
163 
164  BOOST_CHECK(patch_res1.getContactPatch(0).isSame(expected, tol));
165  BOOST_CHECK(patch_res2.getContactPatch(0).isSame(expected, tol));
166  }
167 }
168 
169 BOOST_AUTO_TEST_CASE(halfspace_box) {
170  const Halfspace hspace(0, 0, 1, 0);
171  const CoalScalar halfside = 0.5;
172  const Box box(2 * halfside, 2 * halfside, 2 * halfside);
173 
174  const Transform3s tf1;
176  // set translation to have a collision
177  const CoalScalar offset = 0.001;
178  tf2.setTranslation(Vec3s(0, 0, halfside - offset));
179 
180  const size_t num_max_contact = 1;
182  num_max_contact);
183  CollisionResult col_res;
184 
185  coal::collide(&hspace, tf1, &box, tf2, col_req, col_res);
186 
187  BOOST_CHECK(col_res.isCollision());
188 
189  const ContactPatchRequest patch_req;
190  ContactPatchResult patch_res1(patch_req);
191  ContactPatchResult patch_res2(patch_req);
192  coal::computeContactPatch(&hspace, tf1, &box, tf2, col_res, patch_req,
193  patch_res1);
194  coal::computeContactPatch(&hspace, tf1, &box, tf2, col_res, patch_req,
195  patch_res2);
196  BOOST_CHECK(patch_res1.numContactPatches() == 1);
197  BOOST_CHECK(patch_res2.numContactPatches() == 1);
198 
199  if (patch_res1.numContactPatches() > 0 &&
200  patch_res2.numContactPatches() > 0 && col_res.isCollision()) {
201  const Contact& contact = col_res.getContact(0);
202  const CoalScalar tol = 1e-6;
203  EIGEN_VECTOR_IS_APPROX(contact.normal, hspace.n, tol);
204  EIGEN_VECTOR_IS_APPROX(hspace.n, Vec3s(0, 0, 1), tol);
205 
206  const size_t expected_size = 4;
207  ContactPatch expected(expected_size);
208  expected.tf.rotation() =
210  expected.tf.translation() = contact.pos;
211  expected.penetration_depth = contact.penetration_depth;
212  const std::array<Vec3s, 4> corners = {
213  tf2.transform(Vec3s(halfside, halfside, -halfside)),
214  tf2.transform(Vec3s(halfside, -halfside, -halfside)),
215  tf2.transform(Vec3s(-halfside, -halfside, -halfside)),
216  tf2.transform(Vec3s(-halfside, halfside, -halfside)),
217  };
218  for (size_t i = 0; i < expected_size; ++i) {
219  expected.addPoint(corners[i] -
220  (contact.penetration_depth * contact.normal) / 2);
221  }
222 
223  BOOST_CHECK(patch_res1.getContactPatch(0).isSame(expected, tol));
224  BOOST_CHECK(patch_res2.getContactPatch(0).isSame(expected, tol));
225  }
226 }
227 
228 BOOST_AUTO_TEST_CASE(halfspace_capsule) {
229  const Halfspace hspace(0, 0, 1, 0);
230  const CoalScalar radius = 0.25;
231  const CoalScalar height = 1.;
232  const Capsule capsule(radius, height);
233 
234  const Transform3s tf1;
236  // set translation to have a collision
237  const CoalScalar offset = 0.001;
238  tf2.setTranslation(Vec3s(0, 0, height / 2 - offset));
239 
240  const size_t num_max_contact = 1;
242  num_max_contact);
243  CollisionResult col_res;
244  coal::collide(&hspace, tf1, &capsule, tf2, col_req, col_res);
245  BOOST_CHECK(col_res.isCollision());
246 
247  const ContactPatchRequest patch_req;
248  BOOST_CHECK(patch_req.getNumSamplesCurvedShapes() ==
250  ContactPatchResult patch_res(patch_req);
251  coal::computeContactPatch(&hspace, tf1, &capsule, tf2, col_res, patch_req,
252  patch_res);
253  BOOST_CHECK(patch_res.numContactPatches() == 1);
254 
255  if (patch_res.numContactPatches() > 0 && col_res.isCollision()) {
256  const Contact& contact = col_res.getContact(0);
257  const CoalScalar tol = 1e-6;
258  EIGEN_VECTOR_IS_APPROX(contact.normal, hspace.n, tol);
259 
260  const size_t expected_size = 1;
261  ContactPatch expected(expected_size);
262  expected.tf.rotation() =
264  expected.tf.translation() = contact.pos;
265  expected.penetration_depth = contact.penetration_depth;
266  const Vec3s capsule_end(0, 0, -capsule.halfLength);
267  expected.addPoint(tf2.transform(capsule_end));
268 
269  const ContactPatch& contact_patch = patch_res.getContactPatch(0);
270  BOOST_CHECK(expected.tf == contact_patch.tf);
271  BOOST_CHECK(expected.isSame(contact_patch, tol));
272  }
273 
274  // Rotate capsule 180 degrees around y-axis
275  // Should only have one contact.
276  tf2.rotation().col(0) << -1, 0, 0;
277  tf2.rotation().col(1) << 0, 1, 0;
278  tf2.rotation().col(2) << 0, 0, -1;
279  col_res.clear();
280  coal::collide(&hspace, tf1, &capsule, tf2, col_req, col_res);
281  BOOST_CHECK(col_res.isCollision());
282  patch_res.clear();
283  coal::computeContactPatch(&hspace, tf1, &capsule, tf2, col_res, patch_req,
284  patch_res);
285  BOOST_CHECK(patch_res.numContactPatches() == 1);
286  if (patch_res.numContactPatches() > 0 && col_res.isCollision()) {
287  const Contact& contact = col_res.getContact(0);
288  const CoalScalar tol = 1e-6;
289  EIGEN_VECTOR_IS_APPROX(contact.normal, hspace.n, tol);
290 
291  const size_t expected_size = 1;
292  ContactPatch expected(expected_size);
293  expected.tf.rotation() =
295  expected.tf.translation() = contact.pos;
296  expected.penetration_depth = contact.penetration_depth;
297  const Vec3s capsule_end(0, 0, capsule.halfLength);
298  expected.addPoint(tf2.transform(capsule_end));
299 
300  const ContactPatch& contact_patch = patch_res.getContactPatch(0);
301  BOOST_CHECK(expected.tf == contact_patch.tf);
302  BOOST_CHECK(expected.isSame(contact_patch, tol));
303  }
304 
305  // Rotate cone 90 degrees around y-axis
306  // Should only have two contacts.
307  tf2.rotation().col(0) << 0, 0, 1;
308  tf2.rotation().col(1) << 0, 1, 0;
309  tf2.rotation().col(2) << -1, 0, 0;
310  tf2.translation() << 0, 0, capsule.radius - offset;
311  col_res.clear();
312  coal::collide(&hspace, tf1, &capsule, tf2, col_req, col_res);
313  BOOST_CHECK(col_res.isCollision());
314  patch_res.clear();
315  coal::computeContactPatch(&hspace, tf1, &capsule, tf2, col_res, patch_req,
316  patch_res);
317  BOOST_CHECK(patch_res.numContactPatches() == 1);
318  if (patch_res.numContactPatches() > 0 && col_res.isCollision()) {
319  const Contact& contact = col_res.getContact(0);
320  const CoalScalar tol = 1e-6;
321  EIGEN_VECTOR_IS_APPROX(contact.normal, hspace.n, tol);
322 
323  const size_t expected_size = 2;
324  ContactPatch expected(expected_size);
325  expected.tf.rotation() =
327  expected.tf.translation() = contact.pos;
328  expected.penetration_depth = contact.penetration_depth;
329  const Vec3s p1(-capsule.radius, 0, capsule.halfLength);
330  const Vec3s p2(-capsule.radius, 0, -capsule.halfLength);
331  expected.addPoint(tf2.transform(p1));
332  expected.addPoint(tf2.transform(p2));
333 
334  const ContactPatch& contact_patch = patch_res.getContactPatch(0);
335  BOOST_CHECK(expected.tf == contact_patch.tf);
336  BOOST_CHECK(expected.isSame(contact_patch, tol));
337  }
338 }
339 
340 BOOST_AUTO_TEST_CASE(halfspace_cone) {
341  const Halfspace hspace(0, 0, 1, 0);
342  const CoalScalar radius = 0.25;
343  const CoalScalar height = 1.;
344  const Cone cone(radius, height);
345 
346  const Transform3s tf1;
348  // set translation to have a collision
349  const CoalScalar offset = 0.001;
350  tf2.setTranslation(Vec3s(0, 0, height / 2 - offset));
351 
352  const size_t num_max_contact = 1;
354  num_max_contact);
355  CollisionResult col_res;
356  coal::collide(&hspace, tf1, &cone, tf2, col_req, col_res);
357  BOOST_CHECK(col_res.isCollision());
358 
359  const ContactPatchRequest patch_req;
360  BOOST_CHECK(patch_req.getNumSamplesCurvedShapes() ==
362  ContactPatchResult patch_res(patch_req);
363  coal::computeContactPatch(&hspace, tf1, &cone, tf2, col_res, patch_req,
364  patch_res);
365  BOOST_CHECK(patch_res.numContactPatches() == 1);
366 
367  if (patch_res.numContactPatches() > 0 && col_res.isCollision()) {
368  const Contact& contact = col_res.getContact(0);
369  const CoalScalar tol = 1e-6;
370  EIGEN_VECTOR_IS_APPROX(contact.normal, hspace.n, tol);
371 
372  const size_t expected_size = ContactPatch::default_preallocated_size;
373  ContactPatch expected(expected_size);
374  expected.tf.rotation() =
376  expected.tf.translation() = contact.pos;
377  expected.penetration_depth = contact.penetration_depth;
378  std::array<Vec3s, ContactPatch::default_preallocated_size> points;
379  const CoalScalar angle_increment =
380  2.0 * (CoalScalar)(EIGEN_PI) / ((CoalScalar)(6));
381  for (size_t i = 0; i < ContactPatch::default_preallocated_size; ++i) {
382  const CoalScalar theta = (CoalScalar)(i)*angle_increment;
383  Vec3s point_on_cone_base(std::cos(theta) * cone.radius,
384  std::sin(theta) * cone.radius, -cone.halfLength);
385  expected.addPoint(tf2.transform(point_on_cone_base));
386  }
387 
388  const ContactPatch& contact_patch = patch_res.getContactPatch(0);
389  BOOST_CHECK(expected.tf == contact_patch.tf);
390  BOOST_CHECK(expected.isSame(contact_patch, tol));
391  }
392 
393  // Rotate cone 180 degrees around y-axis
394  // Should only have one contact, due to cone-tip/halfspace collision.
395  tf2.rotation().col(0) << -1, 0, 0;
396  tf2.rotation().col(1) << 0, 1, 0;
397  tf2.rotation().col(2) << 0, 0, -1;
398  col_res.clear();
399  coal::collide(&hspace, tf1, &cone, tf2, col_req, col_res);
400  BOOST_CHECK(col_res.isCollision());
401  patch_res.clear();
402  coal::computeContactPatch(&hspace, tf1, &cone, tf2, col_res, patch_req,
403  patch_res);
404  BOOST_CHECK(patch_res.numContactPatches() == 1);
405  if (patch_res.numContactPatches() > 0 && col_res.isCollision()) {
406  const Contact& contact = col_res.getContact(0);
407  const ContactPatch& contact_patch = patch_res.getContactPatch(0);
408  BOOST_CHECK(contact_patch.size() == 1);
409  const CoalScalar tol = 1e-8;
410  EIGEN_VECTOR_IS_APPROX(contact_patch.getPoint(0), contact.pos, tol);
411  EIGEN_VECTOR_IS_APPROX(contact_patch.tf.translation(), contact.pos, tol);
412  EIGEN_VECTOR_IS_APPROX(contact_patch.getNormal(), contact.normal, tol);
413  BOOST_CHECK(std::abs(contact_patch.penetration_depth -
414  contact.penetration_depth) < tol);
415 
416  const size_t expected_size = 1;
417  ContactPatch expected(expected_size);
418  expected.tf.rotation() =
420  expected.tf.translation() = contact.pos;
421  expected.penetration_depth = contact.penetration_depth;
422  const Vec3s cone_tip(0, 0, cone.halfLength);
423  expected.addPoint(tf2.transform(cone_tip));
424 
425  BOOST_CHECK(contact_patch.isSame(expected, tol));
426  }
427 
428  // Rotate cone 90 degrees around y-axis
429  // Should only have one contact, on cone circle basis.
430  tf2.rotation().col(0) << 0, 0, 1;
431  tf2.rotation().col(1) << 0, 1, 0;
432  tf2.rotation().col(2) << -1, 0, 0;
433  tf2.translation() << 0, 0, cone.radius - offset;
434  col_res.clear();
435  coal::collide(&hspace, tf1, &cone, tf2, col_req, col_res);
436  BOOST_CHECK(col_res.isCollision());
437  patch_res.clear();
438  coal::computeContactPatch(&hspace, tf1, &cone, tf2, col_res, patch_req,
439  patch_res);
440  BOOST_CHECK(patch_res.numContactPatches() == 1);
441  if (patch_res.numContactPatches() > 0 && col_res.isCollision()) {
442  const Contact& contact = col_res.getContact(0);
443  const ContactPatch& contact_patch = patch_res.getContactPatch(0);
444  BOOST_CHECK(contact_patch.size() == 1);
445  const CoalScalar tol = 1e-8;
446  EIGEN_VECTOR_IS_APPROX(contact_patch.getPoint(0), contact.pos, tol);
447  EIGEN_VECTOR_IS_APPROX(contact_patch.tf.translation(), contact.pos, tol);
448  EIGEN_VECTOR_IS_APPROX(contact_patch.getNormal(), contact.normal, tol);
449  BOOST_CHECK(std::abs(contact_patch.penetration_depth -
450  contact.penetration_depth) < tol);
451 
452  const size_t expected_size = 1;
453  ContactPatch expected(expected_size);
454  expected.tf.rotation() =
456  expected.tf.translation() = contact.pos;
457  expected.penetration_depth = contact.penetration_depth;
458  const Vec3s point_on_circle_basis(-cone.radius, 0, -cone.halfLength);
459  expected.addPoint(tf2.transform(point_on_circle_basis));
460 
461  BOOST_CHECK(contact_patch.isSame(expected, tol));
462  }
463 }
464 
465 BOOST_AUTO_TEST_CASE(halfspace_cylinder) {
466  const Halfspace hspace(0, 0, 1, 0);
467  const CoalScalar radius = 0.25;
468  const CoalScalar height = 1.;
469  const Cylinder cylinder(radius, height);
470 
471  const Transform3s tf1;
473  // set translation to have a collision
474  const CoalScalar offset = 0.001;
475  tf2.setTranslation(Vec3s(0, 0, height / 2 - offset));
476 
477  const size_t num_max_contact = 1;
479  num_max_contact);
480  CollisionResult col_res;
481  coal::collide(&hspace, tf1, &cylinder, tf2, col_req, col_res);
482  BOOST_CHECK(col_res.isCollision());
483 
484  if (col_res.isCollision()) {
485  const Contact& contact = col_res.getContact(0);
486  const size_t expected_size = ContactPatch::default_preallocated_size;
487  const CoalScalar tol = 1e-6;
488  ContactPatch expected(expected_size);
489  expected.tf.rotation() =
491  expected.tf.translation() = contact.pos;
492  expected.penetration_depth = contact.penetration_depth;
493  std::array<Vec3s, ContactPatch::default_preallocated_size> points;
494  const CoalScalar angle_increment =
495  2.0 * (CoalScalar)(EIGEN_PI) / ((CoalScalar)(6));
496  for (size_t i = 0; i < ContactPatch::default_preallocated_size; ++i) {
497  const CoalScalar theta = (CoalScalar)(i)*angle_increment;
498  Vec3s point_on_cone_base(std::cos(theta) * cylinder.radius,
499  std::sin(theta) * cylinder.radius,
500  -cylinder.halfLength);
501  expected.addPoint(tf2.transform(point_on_cone_base));
502  }
503 
504  const ContactPatchRequest patch_req;
505  BOOST_CHECK(patch_req.getNumSamplesCurvedShapes() ==
507  ContactPatchResult patch_res(patch_req);
508  coal::computeContactPatch(&hspace, tf1, &cylinder, tf2, col_res, patch_req,
509  patch_res);
510  BOOST_CHECK(patch_res.numContactPatches() == 1);
511 
512  if (patch_res.numContactPatches() > 0) {
513  EIGEN_VECTOR_IS_APPROX(contact.normal, hspace.n, tol);
514  const ContactPatch& contact_patch = patch_res.getContactPatch(0);
515  BOOST_CHECK(expected.tf == contact_patch.tf);
516  BOOST_CHECK(expected.isSame(contact_patch, tol));
517  }
518 
519  // Rotate cylinder 180 degrees around y-axis.
520  // Should only have the same contact-patch, due to cylinder symmetry.
521  tf2.rotation().col(0) << -1, 0, 0;
522  tf2.rotation().col(1) << 0, 1, 0;
523  tf2.rotation().col(2) << 0, 0, -1;
524  col_res.clear();
525  coal::collide(&hspace, tf1, &cylinder, tf2, col_req, col_res);
526  BOOST_CHECK(col_res.isCollision());
527  patch_res.clear();
528  coal::computeContactPatch(&hspace, tf1, &cylinder, tf2, col_res, patch_req,
529  patch_res);
530  BOOST_CHECK(patch_res.numContactPatches() == 1);
531  if (patch_res.numContactPatches() > 0 && col_res.isCollision()) {
532  EIGEN_VECTOR_IS_APPROX(contact.normal, hspace.n, tol);
533  const ContactPatch& contact_patch = patch_res.getContactPatch(0);
534  BOOST_CHECK(expected.tf == contact_patch.tf);
535  BOOST_CHECK(expected.isSame(contact_patch, tol));
536  }
537  }
538 
539  // Rotate cylinder 90 degrees around y-axis.
540  // Should have 2 contact points.
541  tf2.rotation().col(0) << 0, 0, 1;
542  tf2.rotation().col(1) << 0, 1, 0;
543  tf2.rotation().col(2) << -1, 0, 0;
544  tf2.translation() << 0, 0, cylinder.radius - offset;
545 
546  col_res.clear();
547  coal::collide(&hspace, tf1, &cylinder, tf2, col_req, col_res);
548  BOOST_CHECK(col_res.isCollision());
549 
550  const ContactPatchRequest patch_req;
551  ContactPatchResult patch_res(patch_req);
552  coal::computeContactPatch(&hspace, tf1, &cylinder, tf2, col_res, patch_req,
553  patch_res);
554  BOOST_CHECK(patch_res.numContactPatches() == 1);
555  if (col_res.isCollision() && patch_res.numContactPatches() > 0) {
556  const Contact& contact = col_res.getContact(0);
557  const CoalScalar tol = 1e-6;
558 
559  const size_t expected_size = 2;
560  ContactPatch expected(expected_size);
561  expected.tf.rotation() =
563  expected.tf.translation() = contact.pos;
564  expected.penetration_depth = contact.penetration_depth;
565  expected.addPoint(
566  tf2.transform(Vec3s(cylinder.radius, 0, cylinder.halfLength)));
567  expected.addPoint(
568  tf2.transform(Vec3s(cylinder.radius, 0, -cylinder.halfLength)));
569 
570  const ContactPatch& contact_patch = patch_res.getContactPatch(0);
571  BOOST_CHECK(expected.isSame(contact_patch, tol));
572  }
573 }
574 
575 BOOST_AUTO_TEST_CASE(convex_convex) {
576  const CoalScalar halfside = 0.5;
577  const Convex<Quadrilateral> box1(buildBox(halfside, halfside, halfside));
578  const Convex<Quadrilateral> box2(buildBox(halfside, halfside, halfside));
579 
580  const Transform3s tf1;
582  // set translation to have a collision
583  const CoalScalar offset = 0.001;
584  tf2.setTranslation(Vec3s(0, 0, 2 * halfside - offset));
585 
586  const size_t num_max_contact = 1;
588  num_max_contact);
589  CollisionResult col_res;
590 
591  coal::collide(&box1, tf1, &box2, tf2, col_req, col_res);
592 
593  BOOST_CHECK(col_res.isCollision());
594 
595  const ContactPatchRequest patch_req;
596  ContactPatchResult patch_res1(patch_req);
597  ContactPatchResult patch_res2(patch_req);
598  coal::computeContactPatch(&box1, tf1, &box2, tf2, col_res, patch_req,
599  patch_res1);
600  coal::computeContactPatch(&box1, tf1, &box2, tf2, col_res, patch_req,
601  patch_res2);
602  BOOST_CHECK(patch_res1.numContactPatches() == 1);
603  BOOST_CHECK(patch_res2.numContactPatches() == 1);
604 
605  if (patch_res1.numContactPatches() > 0 &&
606  patch_res2.numContactPatches() > 0 && col_res.isCollision()) {
607  const Contact& contact = col_res.getContact(0);
608  const CoalScalar tol = 1e-6;
609  EIGEN_VECTOR_IS_APPROX(contact.normal, Vec3s(0, 0, 1), tol);
610 
611  const size_t expected_size = 4;
612  ContactPatch expected(expected_size);
613  expected.tf.rotation() =
615  expected.tf.translation() = contact.pos;
616  expected.penetration_depth = contact.penetration_depth;
617  const std::array<Vec3s, 4> corners = {
618  Vec3s(halfside, halfside, halfside),
619  Vec3s(halfside, -halfside, halfside),
620  Vec3s(-halfside, -halfside, halfside),
621  Vec3s(-halfside, halfside, halfside),
622  };
623  for (size_t i = 0; i < expected_size; ++i) {
624  expected.addPoint(corners[i] +
625  (contact.penetration_depth * contact.normal) / 2);
626  }
627 
628  BOOST_CHECK(patch_res1.getContactPatch(0).isSame(expected, tol));
629  BOOST_CHECK(patch_res2.getContactPatch(0).isSame(expected, tol));
630  }
631 }
632 
633 BOOST_AUTO_TEST_CASE(edge_case_segment_segment) {
634  // This case covers the segment-segment edge case of contact patches.
635  // Two tetrahedrons make contact on one of their edge.
636 
637  const size_t expected_size = 2;
638  const Vec3s expected_cp1(0, 0.5, 0);
639  const Vec3s expected_cp2(0, 1, 0);
640 
641  const Transform3s tf1; // identity
642  const Transform3s tf2; // identity
643 
644  const size_t num_max_contact = 1;
646  num_max_contact);
647  CollisionResult col_res;
648  const ContactPatchRequest patch_req;
649  ContactPatchResult patch_res(patch_req);
650 
651  {
652  // Case 1 - Face-Face contact
653  std::shared_ptr<std::vector<Vec3s>> pts1(new std::vector<Vec3s>({
654  Vec3s(-1, 0, 0),
655  Vec3s(0, 0, 0),
656  Vec3s(0, 1, 0),
657  Vec3s(-1, -1, -1),
658  }));
659  std::shared_ptr<std::vector<Triangle>> tris1(
660  new std::vector<Triangle>({Triangle(0, 1, 2), Triangle(0, 2, 3),
661  Triangle(0, 3, 1), Triangle(2, 1, 3)}));
662  Convex<Triangle> tetra1(pts1, 4, tris1, 4);
663 
664  std::shared_ptr<std::vector<Vec3s>> pts2(new std::vector<Vec3s>({
665  Vec3s(0, 0.5, 0),
666  Vec3s(0, 1.5, 0),
667  Vec3s(1, 0.5, 0),
668  Vec3s(1, 1, 1),
669  }));
670  std::shared_ptr<std::vector<Triangle>> tris2(
671  new std::vector<Triangle>({Triangle(0, 1, 2), Triangle(0, 2, 3),
672  Triangle(0, 3, 1), Triangle(2, 1, 3)}));
673  Convex<Triangle> tetra2(pts2, 4, tris2, 4);
674 
675  col_res.clear();
676  coal::collide(&tetra1, tf1, &tetra2, tf2, col_req, col_res);
677  BOOST_CHECK(col_res.isCollision());
678  patch_res.clear();
679  coal::computeContactPatch(&tetra1, tf1, &tetra2, tf2, col_res, patch_req,
680  patch_res);
681  BOOST_CHECK(patch_res.numContactPatches() == 1);
682 
683  if (patch_res.numContactPatches() > 0) {
684  const Contact& contact = col_res.getContact(0);
685  const CoalScalar tol = 1e-6;
686 
687  ContactPatch expected(expected_size);
688  // GJK/EPA can return any normal which is in the dual cone
689  // of the cone {(-1, 0, 0)}.
690  expected.tf.rotation() =
692  expected.tf.translation() = contact.pos;
693  expected.penetration_depth = contact.penetration_depth;
694  expected.addPoint(expected_cp1);
695  expected.addPoint(expected_cp2);
696 
697  const ContactPatch& contact_patch = patch_res.getContactPatch(0);
698  BOOST_CHECK(expected.isSame(contact_patch, tol));
699  }
700  }
701 
702  {
703  // Case 2 - Face-Segment contact
704  std::shared_ptr<std::vector<Vec3s>> pts1(new std::vector<Vec3s>({
705  Vec3s(-1, 0, -0.2),
706  Vec3s(0, 0, 0),
707  Vec3s(0, 1, 0),
708  Vec3s(-1, -1, -1),
709  }));
710  std::shared_ptr<std::vector<Triangle>> tris1(
711  new std::vector<Triangle>({Triangle(0, 1, 2), Triangle(0, 2, 3),
712  Triangle(0, 3, 1), Triangle(2, 1, 3)}));
713  Convex<Triangle> tetra1(pts1, 4, tris1, 4);
714 
715  std::shared_ptr<std::vector<Vec3s>> pts2(new std::vector<Vec3s>({
716  Vec3s(0, 0.5, 0),
717  Vec3s(0, 1.5, 0),
718  Vec3s(1, 0.5, 0),
719  Vec3s(1, 1, 1),
720  }));
721  std::shared_ptr<std::vector<Triangle>> tris2(
722  new std::vector<Triangle>({Triangle(0, 1, 2), Triangle(0, 2, 3),
723  Triangle(0, 3, 1), Triangle(2, 1, 3)}));
724  Convex<Triangle> tetra2(pts2, 4, tris2, 4);
725 
726  col_res.clear();
727  coal::collide(&tetra1, tf1, &tetra2, tf2, col_req, col_res);
728  BOOST_CHECK(col_res.isCollision());
729  patch_res.clear();
730  coal::computeContactPatch(&tetra1, tf1, &tetra2, tf2, col_res, patch_req,
731  patch_res);
732  BOOST_CHECK(patch_res.numContactPatches() == 1);
733 
734  if (patch_res.numContactPatches() > 0) {
735  const Contact& contact = col_res.getContact(0);
736  const CoalScalar tol = 1e-6;
737 
738  ContactPatch expected(expected_size);
739  expected.tf.rotation() =
741  expected.tf.translation() = contact.pos;
742  expected.penetration_depth = contact.penetration_depth;
743  expected.addPoint(expected_cp1);
744  expected.addPoint(expected_cp2);
745 
746  const ContactPatch& contact_patch = patch_res.getContactPatch(0);
747  BOOST_CHECK(expected.isSame(contact_patch, tol));
748  }
749  }
750 
751  {
752  // Case 3 - Segment-Segment contact
753  std::shared_ptr<std::vector<Vec3s>> pts1(new std::vector<Vec3s>({
754  Vec3s(-1, 0, -0.2),
755  Vec3s(0, 0, 0),
756  Vec3s(0, 1, 0),
757  Vec3s(-1, -1, -1),
758  }));
759  std::shared_ptr<std::vector<Triangle>> tris1(
760  new std::vector<Triangle>({Triangle(0, 1, 2), Triangle(0, 2, 3),
761  Triangle(0, 3, 1), Triangle(2, 1, 3)}));
762  Convex<Triangle> tetra1(pts1, 4, tris1, 4);
763 
764  std::shared_ptr<std::vector<Vec3s>> pts2(new std::vector<Vec3s>({
765  Vec3s(0, 0.5, 0),
766  Vec3s(0, 1.5, 0),
767  Vec3s(1, 0.5, 0.5),
768  Vec3s(1, 1, 1),
769  }));
770  std::shared_ptr<std::vector<Triangle>> tris2(
771  new std::vector<Triangle>({Triangle(0, 1, 2), Triangle(0, 2, 3),
772  Triangle(0, 3, 1), Triangle(2, 1, 3)}));
773  Convex<Triangle> tetra2(pts2, 4, tris2, 4);
774 
775  col_res.clear();
776  coal::collide(&tetra1, tf1, &tetra2, tf2, col_req, col_res);
777  BOOST_CHECK(col_res.isCollision());
778  patch_res.clear();
779  coal::computeContactPatch(&tetra1, tf1, &tetra2, tf2, col_res, patch_req,
780  patch_res);
781  BOOST_CHECK(patch_res.numContactPatches() == 1);
782 
783  if (patch_res.numContactPatches() > 0) {
784  const Contact& contact = col_res.getContact(0);
785  const CoalScalar tol = 1e-6;
786 
787  ContactPatch expected(expected_size);
788  expected.tf.rotation() =
790  expected.tf.translation() = contact.pos;
791  expected.penetration_depth = contact.penetration_depth;
792  expected.addPoint(expected_cp1);
793  expected.addPoint(expected_cp2);
794 
795  const ContactPatch& contact_patch = patch_res.getContactPatch(0);
796  BOOST_CHECK(expected.isSame(contact_patch, tol));
797  }
798  }
799 }
800 
801 BOOST_AUTO_TEST_CASE(edge_case_vertex_vertex) {
802  // This case covers the vertex-vertex edge case of contact patches.
803  // Two tetrahedrons make contact on one of their vertex.
804  const size_t expected_size = 1;
805  const Vec3s expected_cp(0, 0, 0);
806 
807  const Transform3s tf1; // identity
808  const Transform3s tf2; // identity
809 
810  const size_t num_max_contact = 1;
812  num_max_contact);
813  CollisionResult col_res;
814  const ContactPatchRequest patch_req;
815  ContactPatchResult patch_res(patch_req);
816 
817  {
818  // Case 1 - Face-Face contact
819  std::shared_ptr<std::vector<Vec3s>> pts1(new std::vector<Vec3s>({
820  Vec3s(-1, 0, 0),
821  Vec3s(0, 0, 0),
822  Vec3s(0, 1, 0),
823  Vec3s(-1, -1, -1),
824  }));
825  std::shared_ptr<std::vector<Triangle>> tris1(
826  new std::vector<Triangle>({Triangle(0, 1, 2), Triangle(0, 2, 3),
827  Triangle(0, 3, 1), Triangle(2, 1, 3)}));
828  Convex<Triangle> tetra1(pts1, 4, tris1, 4);
829 
830  std::shared_ptr<std::vector<Vec3s>> pts2(new std::vector<Vec3s>({
831  Vec3s(1, 0, 0),
832  Vec3s(0, 0, 0),
833  Vec3s(0, -1, 0),
834  Vec3s(1, 1, 1),
835  }));
836  std::shared_ptr<std::vector<Triangle>> tris2(
837  new std::vector<Triangle>({Triangle(0, 1, 2), Triangle(0, 2, 3),
838  Triangle(0, 3, 1), Triangle(2, 1, 3)}));
839  Convex<Triangle> tetra2(pts2, 4, tris2, 4);
840 
841  col_res.clear();
842  coal::collide(&tetra1, tf1, &tetra2, tf2, col_req, col_res);
843  BOOST_CHECK(col_res.isCollision());
844  patch_res.clear();
845  coal::computeContactPatch(&tetra1, tf1, &tetra2, tf2, col_res, patch_req,
846  patch_res);
847  BOOST_CHECK(patch_res.numContactPatches() == 1);
848 
849  if (patch_res.numContactPatches() > 0) {
850  const Contact& contact = col_res.getContact(0);
851  const CoalScalar tol = 1e-6;
852 
853  ContactPatch expected(expected_size);
854  expected.tf.rotation() =
856  expected.tf.translation() = contact.pos;
857  expected.penetration_depth = contact.penetration_depth;
858  expected.addPoint(expected_cp);
859 
860  const ContactPatch& contact_patch = patch_res.getContactPatch(0);
861  BOOST_CHECK(expected.isSame(contact_patch, tol));
862  }
863  }
864 
865  {
866  // Case 2 - Segment-Face contact
867  std::shared_ptr<std::vector<Vec3s>> pts1(new std::vector<Vec3s>({
868  Vec3s(-1, 0, -0.5),
869  Vec3s(0, 0, 0),
870  Vec3s(0, 1, 0),
871  Vec3s(-1, -1, -1),
872  }));
873  std::shared_ptr<std::vector<Triangle>> tris1(
874  new std::vector<Triangle>({Triangle(0, 1, 2), Triangle(0, 2, 3),
875  Triangle(0, 3, 1), Triangle(2, 1, 3)}));
876  Convex<Triangle> tetra1(pts1, 4, tris1, 4);
877 
878  std::shared_ptr<std::vector<Vec3s>> pts2(new std::vector<Vec3s>({
879  Vec3s(1, 0, 0),
880  Vec3s(0, 0, 0),
881  Vec3s(0, -1, 0),
882  Vec3s(1, 1, 1),
883  }));
884  std::shared_ptr<std::vector<Triangle>> tris2(
885  new std::vector<Triangle>({Triangle(0, 1, 2), Triangle(0, 2, 3),
886  Triangle(0, 3, 1), Triangle(2, 1, 3)}));
887  Convex<Triangle> tetra2(pts2, 4, tris2, 4);
888 
889  col_res.clear();
890  coal::collide(&tetra1, tf1, &tetra2, tf2, col_req, col_res);
891  BOOST_CHECK(col_res.isCollision());
892  patch_res.clear();
893  coal::computeContactPatch(&tetra1, tf1, &tetra2, tf2, col_res, patch_req,
894  patch_res);
895  BOOST_CHECK(patch_res.numContactPatches() == 1);
896 
897  if (patch_res.numContactPatches() > 0) {
898  const Contact& contact = col_res.getContact(0);
899  const CoalScalar tol = 1e-6;
900 
901  ContactPatch expected(expected_size);
902  expected.tf.rotation() =
904  expected.tf.translation() = contact.pos;
905  expected.penetration_depth = contact.penetration_depth;
906  expected.addPoint(expected_cp);
907 
908  const ContactPatch& contact_patch = patch_res.getContactPatch(0);
909  BOOST_CHECK(expected.isSame(contact_patch, tol));
910  }
911  }
912 
913  {
914  // Case 2 - Segment-Segment contact
915  std::shared_ptr<std::vector<Vec3s>> pts1(new std::vector<Vec3s>({
916  Vec3s(-1, 0, -0.2),
917  Vec3s(0, 0, 0),
918  Vec3s(0, 1, 0),
919  Vec3s(-1, -1, -1),
920  }));
921  std::shared_ptr<std::vector<Triangle>> tris1(
922  new std::vector<Triangle>({Triangle(0, 1, 2), Triangle(0, 2, 3),
923  Triangle(0, 3, 1), Triangle(2, 1, 3)}));
924  Convex<Triangle> tetra1(pts1, 4, tris1, 4);
925 
926  std::shared_ptr<std::vector<Vec3s>> pts2(new std::vector<Vec3s>({
927  Vec3s(1, 0, 0),
928  Vec3s(0, 0, 0),
929  Vec3s(0, -1, 0.5),
930  Vec3s(1, 1, 1),
931  }));
932  std::shared_ptr<std::vector<Triangle>> tris2(
933  new std::vector<Triangle>({Triangle(0, 1, 2), Triangle(0, 2, 3),
934  Triangle(0, 3, 1), Triangle(2, 1, 3)}));
935  Convex<Triangle> tetra2(pts2, 4, tris2, 4);
936 
937  col_res.clear();
938  coal::collide(&tetra1, tf1, &tetra2, tf2, col_req, col_res);
939  BOOST_CHECK(col_res.isCollision());
940  patch_res.clear();
941  coal::computeContactPatch(&tetra1, tf1, &tetra2, tf2, col_res, patch_req,
942  patch_res);
943  BOOST_CHECK(patch_res.numContactPatches() == 1);
944 
945  if (patch_res.numContactPatches() > 0) {
946  const Contact& contact = col_res.getContact(0);
947  const CoalScalar tol = 1e-6;
948 
949  ContactPatch expected(expected_size);
950  expected.tf.rotation() =
952  expected.tf.translation() = contact.pos;
953  expected.penetration_depth = contact.penetration_depth;
954  expected.addPoint(expected_cp);
955 
956  const ContactPatch& contact_patch = patch_res.getContactPatch(0);
957  BOOST_CHECK(expected.isSame(contact_patch, tol));
958  }
959  }
960 }
961 
962 BOOST_AUTO_TEST_CASE(edge_case_segment_face) {
963  // This case covers the segment-face edge case of contact patches.
964  // Two tetrahedrons make contact on one of their segment/face respectively.
965  const size_t expected_size = 2;
966  const Vec3s expected_cp1(0, 0, 0);
967  const Vec3s expected_cp2(-0.5, 0.5, 0);
968 
969  const Transform3s tf1; // identity
970  const Transform3s tf2; // identity
971 
972  const size_t num_max_contact = 1;
974  num_max_contact);
975  CollisionResult col_res;
976  const ContactPatchRequest patch_req;
977  ContactPatchResult patch_res(patch_req);
978 
979  {
980  std::shared_ptr<std::vector<Vec3s>> pts1(new std::vector<Vec3s>({
981  Vec3s(-1, 0, -0),
982  Vec3s(0, 0, 0),
983  Vec3s(0, 1, 0),
984  Vec3s(-1, -1, -1),
985  }));
986  std::shared_ptr<std::vector<Triangle>> tris1(
987  new std::vector<Triangle>({Triangle(0, 1, 2), Triangle(0, 2, 3),
988  Triangle(0, 3, 1), Triangle(2, 1, 3)}));
989  Convex<Triangle> tetra1(pts1, 4, tris1, 4);
990 
991  std::shared_ptr<std::vector<Vec3s>> pts2(new std::vector<Vec3s>({
992  Vec3s(-0.5, 0.5, 0),
993  Vec3s(0.5, -0.5, 0),
994  Vec3s(1, 0.5, 0.5),
995  Vec3s(1, 1, 1),
996  }));
997  std::shared_ptr<std::vector<Triangle>> tris2(
998  new std::vector<Triangle>({Triangle(0, 1, 2), Triangle(0, 2, 3),
999  Triangle(0, 3, 1), Triangle(2, 1, 3)}));
1000  Convex<Triangle> tetra2(pts2, 4, tris2, 4);
1001 
1002  col_res.clear();
1003  coal::collide(&tetra1, tf1, &tetra2, tf2, col_req, col_res);
1004  BOOST_CHECK(col_res.isCollision());
1005  patch_res.clear();
1006  coal::computeContactPatch(&tetra1, tf1, &tetra2, tf2, col_res, patch_req,
1007  patch_res);
1008  BOOST_CHECK(patch_res.numContactPatches() == 1);
1009 
1010  if (patch_res.numContactPatches() > 0) {
1011  const Contact& contact = col_res.getContact(0);
1012  const CoalScalar tol = 1e-6;
1013 
1014  ContactPatch expected(expected_size);
1015  expected.tf.rotation() =
1017  expected.tf.translation() = contact.pos;
1018  expected.penetration_depth = contact.penetration_depth;
1019  expected.addPoint(expected_cp1);
1020  expected.addPoint(expected_cp2);
1021 
1022  const ContactPatch& contact_patch = patch_res.getContactPatch(0);
1023  BOOST_CHECK(expected.isSame(contact_patch, tol));
1024  }
1025  }
1026 }
coal::Contact::pos
Vec3s pos
contact position, in world space
Definition: coal/collision_data.h:102
coal::ContactPatch::penetration_depth
CoalScalar penetration_depth
Penetration depth of the contact patch. This value corresponds to the signed distance d between the s...
Definition: coal/collision_data.h:545
coal::ContactPatch::default_preallocated_size
static constexpr size_t default_preallocated_size
Default maximum size of the polygon representing the contact patch. Used to pre-allocate memory for t...
Definition: coal/collision_data.h:549
coal::CONTACT
@ CONTACT
Definition: coal/collision_data.h:305
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::ContactPatch::getPoint
Vec3s getPoint(const size_t i) const
Get the i-th point of the set, expressed in the 3D world frame.
Definition: coal/collision_data.h:590
collision_manager.box
box
Definition: collision_manager.py:11
coal::CollisionResult::isCollision
bool isCollision() const
return binary collision result
Definition: coal/collision_data.h:443
coal::ContactPatch::getNormal
Vec3s getNormal() const
Normal of the contact patch, expressed in the WORLD frame.
Definition: coal/collision_data.h:569
coal::Contact::normal
Vec3s normal
contact normal, pointing from o1 to o2. The normal defined as the normalized separation vector: norma...
Definition: coal/collision_data.h:88
coal::Capsule::halfLength
CoalScalar halfLength
Half Length along z axis.
Definition: coal/shape/geometric_shapes.h:402
collision_manager.sphere
sphere
Definition: collision_manager.py:4
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
BOOST_AUTO_TEST_CASE
BOOST_AUTO_TEST_CASE(box_box_no_collision)
Definition: test/contact_patch.cpp:46
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
coal
Main namespace.
Definition: coal/broadphase/broadphase_bruteforce.h:44
coal::ContactPatchResult::numContactPatches
size_t numContactPatches() const
Number of contact patches in the result.
Definition: coal/collision_data.h:859
utility.h
coal::buildBox
Convex< Quadrilateral > buildBox(CoalScalar l, CoalScalar w, CoalScalar d)
Constructs a box with halfsides (l, w, d), centered around 0. The box is 2*l wide on the x-axis,...
Definition: utility.cpp:460
coal::ContactPatchResult::getContactPatch
const ContactPatch & getContactPatch(const size_t i) const
Const getter for the i-th contact patch of the result.
Definition: coal/collision_data.h:882
coal::ContactPatch
This structure allows to encode contact patches. A contact patch is defined by a set of points belong...
Definition: coal/collision_data.h:512
coal::Contact::penetration_depth
CoalScalar penetration_depth
penetration depth
Definition: coal/collision_data.h:105
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
EIGEN_VECTOR_IS_APPROX
#define EIGEN_VECTOR_IS_APPROX(Va, Vb, precision)
Definition: utility.h:59
coal::Transform3s
Simple transform class used locally by InterpMotion.
Definition: coal/math/transform.h:55
contact_patch.h
coal::CollisionResult::clear
void clear()
clear the results obtained
Definition: coal/collision_data.h:483
coal::Transform3s::translation
const Vec3s & translation() const
get translation
Definition: coal/math/transform.h:104
coal::Cone::halfLength
CoalScalar halfLength
Half Length along z axis.
Definition: coal/shape/geometric_shapes.h:486
coal::CollisionResult
collision result
Definition: coal/collision_data.h:390
coal::ContactPatch::isSame
bool isSame(const ContactPatch &other, const CoalScalar tol=Eigen::NumTraits< CoalScalar >::dummy_precision()) const
Whether two contact patches are the same or not. Checks for different order of the points.
Definition: coal/collision_data.h:658
coal::computeContactPatch
COAL_DLLAPI void computeContactPatch(const CollisionGeometry *o1, const Transform3s &tf1, const CollisionGeometry *o2, const Transform3s &tf2, const CollisionResult &collision_result, const ContactPatchRequest &request, ContactPatchResult &result)
Main contact patch computation interface.
Definition: src/contact_patch.cpp:47
coal::CollisionRequest
request to the collision algorithm
Definition: coal/collision_data.h:311
gjk.tf2
tuple tf2
Definition: test/scripts/gjk.py:36
coal::Convex
Convex polytope.
Definition: coal/serialization/collision_object.h:51
coal::Transform3s::rotation
const Matrix3s & rotation() const
get rotation
Definition: coal/math/transform.h:113
coal::Cylinder
Cylinder along Z axis. The cylinder is defined at its centroid.
Definition: coal/shape/geometric_shapes.h:560
coal::ContactPatchResult
Result for a contact patch computation.
Definition: coal/collision_data.h:822
coal::Contact
Contact information returned by collision.
Definition: coal/collision_data.h:58
coal::ContactPatchRequest
Request for a contact patch computation.
Definition: coal/collision_data.h:724
coal::ContactPatchRequest::getNumSamplesCurvedShapes
size_t getNumSamplesCurvedShapes() const
Maximum samples to compute the support sets of curved shapes, i.e. when the normal is perpendicular t...
Definition: coal/collision_data.h:793
coal::ContactPatch::tf
Transform3s tf
Frame of the set, expressed in the world coordinates. The z-axis of the frame's rotation is the conta...
Definition: coal/collision_data.h:518
octree.p1
tuple p1
Definition: octree.py:54
coal::Cone
Cone The base of the cone is at and the top is at .
Definition: coal/shape/geometric_shapes.h:467
coal::Halfspace::n
Vec3s n
Plane normal.
Definition: coal/shape/geometric_shapes.h:956
coal::Cone::radius
CoalScalar radius
Radius of the cone.
Definition: coal/shape/geometric_shapes.h:480
coal::constructOrthonormalBasisFromVector
Matrix3s constructOrthonormalBasisFromVector(const Vec3s &vec)
Construct othonormal basis from vector. The z-axis is the normalized input vector.
Definition: coal/math/transform.h:262
coal::Capsule::radius
CoalScalar radius
Radius of capsule.
Definition: coal/shape/geometric_shapes.h:396
coal::CollisionResult::getContact
const Contact & getContact(size_t i) const
get the i-th contact calculated
Definition: coal/collision_data.h:449
coal::collide
COAL_DLLAPI std::size_t collide(const CollisionObject *o1, const CollisionObject *o2, const CollisionRequest &request, CollisionResult &result)
Main collision interface: given two collision objects, and the requirements for contacts,...
Definition: src/collision.cpp:61
coal::ContactPatchResult::clear
void clear()
Clears the contact patch result.
Definition: coal/collision_data.h:910
coal::Triangle
Triangle with 3 indices for points.
Definition: coal/data_types.h:111
coal::ContactPatch::size
size_t size() const
Returns the number of points in the contact patch.
Definition: coal/collision_data.h:577
coal::CoalScalar
double CoalScalar
Definition: coal/data_types.h:76
coal::ContactPatch::addPoint
void addPoint(const Vec3s &point_3d)
Add a 3D point to the set, expressed in the world frame.
Definition: coal/collision_data.h:584


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