coal/internal/traversal_node_hfield_shape.h
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2021-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 Open Source Robotics Foundation 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 #ifndef COAL_TRAVERSAL_NODE_HFIELD_SHAPE_H
38 #define COAL_TRAVERSAL_NODE_HFIELD_SHAPE_H
39 
41 
42 #include "coal/collision_data.h"
50 #include "coal/hfield.h"
51 #include "coal/shape/convex.h"
52 
53 namespace coal {
54 
57 
58 namespace details {
59 template <typename BV>
60 Convex<Quadrilateral> buildConvexQuadrilateral(const HFNode<BV>& node,
61  const HeightField<BV>& model) {
62  const MatrixXs& heights = model.getHeights();
63  const VecXs& x_grid = model.getXGrid();
64  const VecXs& y_grid = model.getYGrid();
65 
66  const CoalScalar min_height = model.getMinHeight();
67 
68  const CoalScalar x0 = x_grid[node.x_id], x1 = x_grid[node.x_id + 1],
69  y0 = y_grid[node.y_id], y1 = y_grid[node.y_id + 1];
70  const Eigen::Block<const MatrixXs, 2, 2> cell =
71  heights.block<2, 2>(node.y_id, node.x_id);
72 
73  assert(cell.maxCoeff() > min_height &&
74  "max_height is lower than min_height"); // Check whether the geometry
75  // is degenerated
76 
77  std::shared_ptr<std::vector<Vec3s>> pts(new std::vector<Vec3s>({
78  Vec3s(x0, y0, min_height),
79  Vec3s(x0, y1, min_height),
80  Vec3s(x1, y1, min_height),
81  Vec3s(x1, y0, min_height),
82  Vec3s(x0, y0, cell(0, 0)),
83  Vec3s(x0, y1, cell(1, 0)),
84  Vec3s(x1, y1, cell(1, 1)),
85  Vec3s(x1, y0, cell(0, 1)),
86  }));
87 
88  std::shared_ptr<std::vector<Quadrilateral>> polygons(
89  new std::vector<Quadrilateral>(6));
90  (*polygons)[0].set(0, 3, 2, 1); // x+ side
91  (*polygons)[1].set(0, 1, 5, 4); // y- side
92  (*polygons)[2].set(1, 2, 6, 5); // x- side
93  (*polygons)[3].set(2, 3, 7, 6); // y+ side
94  (*polygons)[4].set(3, 0, 4, 7); // z- side
95  (*polygons)[5].set(4, 5, 6, 7); // z+ side
96 
97  return Convex<Quadrilateral>(pts, // points
98  8, // num points
99  polygons,
100  6 // number of polygons
101  );
102 }
103 
104 enum class FaceOrientationConvexPart1 {
105  BOTTOM = 0,
106  TOP = 1,
107  WEST = 2,
108  SOUTH_EAST = 4,
109  NORTH = 8,
110 };
111 
112 enum class FaceOrientationConvexPart2 {
113  BOTTOM = 0,
114  TOP = 1,
115  SOUTH = 2,
116  NORTH_WEST = 4,
117  EAST = 8,
118 };
119 
120 template <typename BV>
121 void buildConvexTriangles(const HFNode<BV>& node, const HeightField<BV>& model,
122  Convex<Triangle>& convex1, int& convex1_active_faces,
123  Convex<Triangle>& convex2,
124  int& convex2_active_faces) {
125  const MatrixXs& heights = model.getHeights();
126  const VecXs& x_grid = model.getXGrid();
127  const VecXs& y_grid = model.getYGrid();
128 
129  const CoalScalar min_height = model.getMinHeight();
130 
131  const CoalScalar x0 = x_grid[node.x_id], x1 = x_grid[node.x_id + 1],
132  y0 = y_grid[node.y_id], y1 = y_grid[node.y_id + 1];
133  const CoalScalar max_height = node.max_height;
134  const Eigen::Block<const MatrixXs, 2, 2> cell =
135  heights.block<2, 2>(node.y_id, node.x_id);
136 
137  const int contact_active_faces = node.contact_active_faces;
138  convex1_active_faces = 0;
139  convex2_active_faces = 0;
140 
141  typedef HFNodeBase::FaceOrientation FaceOrientation;
142 
143  if (contact_active_faces & FaceOrientation::TOP) {
144  convex1_active_faces |= int(details::FaceOrientationConvexPart1::TOP);
145  convex2_active_faces |= int(details::FaceOrientationConvexPart2::TOP);
146  }
147 
148  if (contact_active_faces & FaceOrientation::BOTTOM) {
149  convex1_active_faces |= int(details::FaceOrientationConvexPart1::BOTTOM);
150  convex2_active_faces |= int(details::FaceOrientationConvexPart2::BOTTOM);
151  }
152 
153  // Specific orientation for Convex1
154  if (contact_active_faces & FaceOrientation::WEST) {
155  convex1_active_faces |= int(details::FaceOrientationConvexPart1::WEST);
156  }
157 
158  if (contact_active_faces & FaceOrientation::NORTH) {
159  convex1_active_faces |= int(details::FaceOrientationConvexPart1::NORTH);
160  }
161 
162  // Specific orientation for Convex2
163  if (contact_active_faces & FaceOrientation::EAST) {
164  convex2_active_faces |= int(details::FaceOrientationConvexPart2::EAST);
165  }
166 
167  if (contact_active_faces & FaceOrientation::SOUTH) {
168  convex2_active_faces |= int(details::FaceOrientationConvexPart2::SOUTH);
169  }
170 
171  assert(max_height > min_height &&
172  "max_height is lower than min_height"); // Check whether the geometry
173  // is degenerated
174  COAL_UNUSED_VARIABLE(max_height);
175 
176  {
177  std::shared_ptr<std::vector<Vec3s>> pts(new std::vector<Vec3s>({
178  Vec3s(x0, y0, min_height), // A
179  Vec3s(x0, y1, min_height), // B
180  Vec3s(x1, y0, min_height), // C
181  Vec3s(x0, y0, cell(0, 0)), // D
182  Vec3s(x0, y1, cell(1, 0)), // E
183  Vec3s(x1, y0, cell(0, 1)), // F
184  }));
185 
186  std::shared_ptr<std::vector<Triangle>> triangles(
187  new std::vector<Triangle>(8));
188  (*triangles)[0].set(0, 2, 1); // bottom
189  (*triangles)[1].set(3, 4, 5); // top
190  (*triangles)[2].set(0, 1, 3); // West 1
191  (*triangles)[3].set(3, 1, 4); // West 2
192  (*triangles)[4].set(1, 2, 5); // South-East 1
193  (*triangles)[5].set(1, 5, 4); // South-East 1
194  (*triangles)[6].set(0, 5, 2); // North 1
195  (*triangles)[7].set(5, 0, 3); // North 2
196 
197  convex1.set(pts, // points
198  6, // num points
199  triangles,
200  8 // number of polygons
201  );
202  }
203 
204  {
205  std::shared_ptr<std::vector<Vec3s>> pts(new std::vector<Vec3s>({
206  Vec3s(x0, y1, min_height), // A
207  Vec3s(x1, y1, min_height), // B
208  Vec3s(x1, y0, min_height), // C
209  Vec3s(x0, y1, cell(1, 0)), // D
210  Vec3s(x1, y1, cell(1, 1)), // E
211  Vec3s(x1, y0, cell(0, 1)), // F
212  }));
213 
214  std::shared_ptr<std::vector<Triangle>> triangles(
215  new std::vector<Triangle>(8));
216  (*triangles)[0].set(2, 1, 0); // bottom
217  (*triangles)[1].set(3, 4, 5); // top
218  (*triangles)[2].set(0, 1, 3); // South 1
219  (*triangles)[3].set(3, 1, 4); // South 2
220  (*triangles)[4].set(0, 5, 2); // North West 1
221  (*triangles)[5].set(0, 3, 5); // North West 2
222  (*triangles)[6].set(1, 2, 5); // East 1
223  (*triangles)[7].set(4, 1, 2); // East 2
224 
225  convex2.set(pts, // points
226  6, // num points
227  triangles,
228  8 // number of polygons
229  );
230  }
231 }
232 
233 inline Vec3s projectTriangle(const Vec3s& pointA, const Vec3s& pointB,
234  const Vec3s& pointC, const Vec3s& point) {
235  const Project::ProjectResult result =
236  Project::projectTriangle(pointA, pointB, pointC, point);
237  Vec3s res = result.parameterization[0] * pointA +
238  result.parameterization[1] * pointB +
239  result.parameterization[2] * pointC;
240 
241  return res;
242 }
243 
244 inline Vec3s projectTetrahedra(const Vec3s& pointA, const Vec3s& pointB,
245  const Vec3s& pointC, const Vec3s& pointD,
246  const Vec3s& point) {
247  const Project::ProjectResult result =
248  Project::projectTetrahedra(pointA, pointB, pointC, pointD, point);
249  Vec3s res = result.parameterization[0] * pointA +
250  result.parameterization[1] * pointB +
251  result.parameterization[2] * pointC +
252  result.parameterization[3] * pointD;
253 
254  return res;
255 }
256 
257 inline Vec3s computeTriangleNormal(const Triangle& triangle,
258  const std::vector<Vec3s>& points) {
259  const Vec3s pointA = points[triangle[0]];
260  const Vec3s pointB = points[triangle[1]];
261  const Vec3s pointC = points[triangle[2]];
262 
263  const Vec3s normal = (pointB - pointA).cross(pointC - pointA).normalized();
264  assert(!normal.array().isNaN().any() && "normal is ill-defined");
265 
266  return normal;
267 }
268 
269 inline Vec3s projectPointOnTriangle(const Vec3s& contact_point,
270  const Triangle& triangle,
271  const std::vector<Vec3s>& points) {
272  const Vec3s pointA = points[triangle[0]];
273  const Vec3s pointB = points[triangle[1]];
274  const Vec3s pointC = points[triangle[2]];
275 
276  const Vec3s contact_point_projected =
277  projectTriangle(pointA, pointB, pointC, contact_point);
278 
279  return contact_point_projected;
280 }
281 
282 inline CoalScalar distanceContactPointToTriangle(
283  const Vec3s& contact_point, const Triangle& triangle,
284  const std::vector<Vec3s>& points) {
285  const Vec3s contact_point_projected =
286  projectPointOnTriangle(contact_point, triangle, points);
287  return (contact_point_projected - contact_point).norm();
288 }
289 
290 inline CoalScalar distanceContactPointToFace(const size_t face_id,
291  const Vec3s& contact_point,
292  const Convex<Triangle>& convex,
293  size_t& closest_face_id) {
294  assert((face_id >= 0 && face_id < 8) && "face_id should be in [0;7]");
295 
296  const std::vector<Vec3s>& points = *(convex.points);
297  if (face_id <= 1) {
298  const Triangle& triangle = (*(convex.polygons))[face_id];
299  closest_face_id = face_id;
300  return distanceContactPointToTriangle(contact_point, triangle, points);
301  } else {
302  const Triangle& triangle1 = (*(convex.polygons))[face_id];
303  const CoalScalar distance_to_triangle1 =
304  distanceContactPointToTriangle(contact_point, triangle1, points);
305 
306  const Triangle& triangle2 = (*(convex.polygons))[face_id + 1];
307  const CoalScalar distance_to_triangle2 =
308  distanceContactPointToTriangle(contact_point, triangle2, points);
309 
310  if (distance_to_triangle1 > distance_to_triangle2) {
311  closest_face_id = face_id + 1;
312  return distance_to_triangle2;
313  } else {
314  closest_face_id = face_id;
315  return distance_to_triangle1;
316  }
317  }
318 }
319 
320 template <typename Polygone, typename Shape>
321 bool binCorrection(const Convex<Polygone>& convex,
322  const int convex_active_faces, const Shape& shape,
323  const Transform3s& shape_pose, CoalScalar& distance,
324  Vec3s& contact_1, Vec3s& contact_2, Vec3s& normal,
325  Vec3s& face_normal, const bool is_collision) {
326  const CoalScalar prec = 1e-12;
327  const std::vector<Vec3s>& points = *(convex.points);
328 
329  bool hfield_witness_is_on_bin_side = true;
330 
331  // int closest_face_id_bottom_face = -1;
332  // int closest_face_id_top_face = -1;
333 
334  std::vector<size_t> active_faces;
335  active_faces.reserve(5);
336  active_faces.push_back(0);
337  active_faces.push_back(1);
338 
339  if (convex_active_faces & 2) active_faces.push_back(2);
340  if (convex_active_faces & 4) active_faces.push_back(4);
341  if (convex_active_faces & 8) active_faces.push_back(6);
342 
343  Triangle face_triangle;
344  CoalScalar shortest_distance_to_face =
345  (std::numeric_limits<CoalScalar>::max)();
346  face_normal = normal;
347  for (const size_t active_face : active_faces) {
348  size_t closest_face_id;
349  const CoalScalar distance_to_face = distanceContactPointToFace(
350  active_face, contact_1, convex, closest_face_id);
351 
352  const bool contact_point_is_on_face = distance_to_face <= prec;
353  if (contact_point_is_on_face) {
354  hfield_witness_is_on_bin_side = false;
355  face_triangle = (*(convex.polygons))[closest_face_id];
356  shortest_distance_to_face = distance_to_face;
357  break;
358  } else if (distance_to_face < shortest_distance_to_face) {
359  face_triangle = (*(convex.polygons))[closest_face_id];
360  shortest_distance_to_face = distance_to_face;
361  }
362  }
363 
364  // We correct only if there is a collision with the bin
365  if (is_collision) {
366  if (!face_triangle.isValid())
367  COAL_THROW_PRETTY("face_triangle is not initialized", std::logic_error);
368 
369  const Vec3s face_pointA = points[face_triangle[0]];
370  face_normal = computeTriangleNormal(face_triangle, points);
371 
372  int hint = 0;
373  // Since we compute the support manually, we need to take into account the
374  // sphere swept radius of the shape.
375  // TODO: take into account the swept-sphere radius of the bin.
376  const Vec3s _support = getSupport<details::SupportOptions::WithSweptSphere>(
377  &shape, -shape_pose.rotation().transpose() * face_normal, hint);
378  const Vec3s support =
379  shape_pose.rotation() * _support + shape_pose.translation();
380 
381  // Project support into the inclined bin having triangle
382  const CoalScalar offset_plane = face_normal.dot(face_pointA);
383  const Plane projection_plane(face_normal, offset_plane);
384  const CoalScalar distance_support_projection_plane =
385  projection_plane.signedDistance(support);
386 
387  const Vec3s projected_support =
388  support - distance_support_projection_plane * face_normal;
389 
390  // We need now to project the projected in the triangle shape
391  contact_1 =
392  projectPointOnTriangle(projected_support, face_triangle, points);
393  contact_2 = contact_1 + distance_support_projection_plane * face_normal;
394  normal = face_normal;
395  distance = -std::fabs(distance_support_projection_plane);
396  }
397 
398  return hfield_witness_is_on_bin_side;
399 }
400 
401 template <typename Polygone, typename Shape, int Options>
402 bool shapeDistance(const GJKSolver* nsolver, const CollisionRequest& request,
403  const Convex<Polygone>& convex1,
404  const int convex1_active_faces,
405  const Convex<Polygone>& convex2,
406  const int convex2_active_faces, const Transform3s& tf1,
407  const Shape& shape, const Transform3s& tf2,
408  CoalScalar& distance, Vec3s& c1, Vec3s& c2, Vec3s& normal,
409  Vec3s& normal_top, bool& hfield_witness_is_on_bin_side) {
410  enum { RTIsIdentity = Options & RelativeTransformationIsIdentity };
411 
412  const Transform3s Id;
413  // The solver `nsolver` has already been set up by the collision request
414  // `request`. If GJK early stopping is enabled through `request`, it will be
415  // used.
416  // The only thing we need to make sure is that in case of collision, the
417  // penetration information is computed (as we do bins comparison).
418  const bool compute_penetration = true;
419  Vec3s contact1_1, contact1_2, contact2_1, contact2_2;
420  Vec3s normal1, normal1_top, normal2, normal2_top;
421  CoalScalar distance1, distance2;
422 
423  if (RTIsIdentity) {
424  distance1 = internal::ShapeShapeDistance<Convex<Polygone>, Shape>(
425  &convex1, Id, &shape, tf2, nsolver, compute_penetration, contact1_1,
426  contact1_2, normal1);
427  } else {
428  distance1 = internal::ShapeShapeDistance<Convex<Polygone>, Shape>(
429  &convex1, tf1, &shape, tf2, nsolver, compute_penetration, contact1_1,
430  contact1_2, normal1);
431  }
432  bool collision1 = (distance1 - request.security_margin <=
433  request.collision_distance_threshold);
434 
435  bool hfield_witness_is_on_bin_side1 =
436  binCorrection(convex1, convex1_active_faces, shape, tf2, distance1,
437  contact1_1, contact1_2, normal1, normal1_top, collision1);
438 
439  if (RTIsIdentity) {
440  distance2 = internal::ShapeShapeDistance<Convex<Polygone>, Shape>(
441  &convex2, Id, &shape, tf2, nsolver, compute_penetration, contact2_1,
442  contact2_2, normal2);
443  } else {
444  distance2 = internal::ShapeShapeDistance<Convex<Polygone>, Shape>(
445  &convex2, tf1, &shape, tf2, nsolver, compute_penetration, contact2_1,
446  contact2_2, normal2);
447  }
448  bool collision2 = (distance2 - request.security_margin <=
449  request.collision_distance_threshold);
450 
451  bool hfield_witness_is_on_bin_side2 =
452  binCorrection(convex2, convex2_active_faces, shape, tf2, distance2,
453  contact2_1, contact2_2, normal2, normal2_top, collision2);
454 
455  if (collision1 && collision2) {
456  if (distance1 > distance2) // switch values
457  {
458  distance = distance2;
459  c1 = contact2_1;
460  c2 = contact2_2;
461  normal = normal2;
462  normal_top = normal2_top;
463  hfield_witness_is_on_bin_side = hfield_witness_is_on_bin_side2;
464  } else {
465  distance = distance1;
466  c1 = contact1_1;
467  c2 = contact1_2;
468  normal = normal1;
469  normal_top = normal1_top;
470  hfield_witness_is_on_bin_side = hfield_witness_is_on_bin_side1;
471  }
472  return true;
473  } else if (collision1) {
474  distance = distance1;
475  c1 = contact1_1;
476  c2 = contact1_2;
477  normal = normal1;
478  normal_top = normal1_top;
479  hfield_witness_is_on_bin_side = hfield_witness_is_on_bin_side1;
480  return true;
481  } else if (collision2) {
482  distance = distance2;
483  c1 = contact2_1;
484  c2 = contact2_2;
485  normal = normal2;
486  normal_top = normal2_top;
487  hfield_witness_is_on_bin_side = hfield_witness_is_on_bin_side2;
488  return true;
489  }
490 
491  if (distance1 > distance2) // switch values
492  {
493  distance = distance2;
494  c1 = contact2_1;
495  c2 = contact2_2;
496  normal = normal2;
497  normal_top = normal2_top;
498  hfield_witness_is_on_bin_side = hfield_witness_is_on_bin_side2;
499  } else {
500  distance = distance1;
501  c1 = contact1_1;
502  c2 = contact1_2;
503  normal = normal1;
504  normal_top = normal1_top;
505  hfield_witness_is_on_bin_side = hfield_witness_is_on_bin_side1;
506  }
507  return false;
508 }
509 
510 } // namespace details
511 
513 template <typename BV, typename S,
514  int _Options = RelativeTransformationIsIdentity>
515 class HeightFieldShapeCollisionTraversalNode
516  : public CollisionTraversalNodeBase {
517  public:
518  typedef CollisionTraversalNodeBase Base;
519  typedef Eigen::Array<CoalScalar, 1, 2> Array2d;
520 
521  enum {
522  Options = _Options,
523  RTIsIdentity = _Options & RelativeTransformationIsIdentity
524  };
525 
526  HeightFieldShapeCollisionTraversalNode(const CollisionRequest& request)
527  : CollisionTraversalNodeBase(request) {
528  model1 = NULL;
529  model2 = NULL;
530 
531  num_bv_tests = 0;
532  num_leaf_tests = 0;
533  query_time_seconds = 0.0;
534 
535  nsolver = NULL;
536  count = 0;
537  }
538 
540  bool isFirstNodeLeaf(unsigned int b) const {
541  return model1->getBV(b).isLeaf();
542  }
543 
545  int getFirstLeftChild(unsigned int b) const {
546  return static_cast<int>(model1->getBV(b).leftChild());
547  }
548 
550  int getFirstRightChild(unsigned int b) const {
551  return static_cast<int>(model1->getBV(b).rightChild());
552  }
553 
559  bool BVDisjoints(unsigned int b1, unsigned int /*b2*/,
560  CoalScalar& sqrDistLowerBound) const {
561  if (this->enable_statistics) this->num_bv_tests++;
562 
563  bool disjoint;
564  if (RTIsIdentity) {
565  assert(false && "must never happened");
566  disjoint = !this->model1->getBV(b1).bv.overlap(
567  this->model2_bv, this->request, sqrDistLowerBound);
568  } else {
569  disjoint = !overlap(this->tf1.getRotation(), this->tf1.getTranslation(),
570  this->model1->getBV(b1).bv, this->model2_bv,
571  this->request, sqrDistLowerBound);
572  }
573 
574  if (disjoint)
575  internal::updateDistanceLowerBoundFromBV(this->request, *this->result,
576  sqrDistLowerBound);
577 
578  assert(!disjoint || sqrDistLowerBound > 0);
579  return disjoint;
580  }
581 
583  void leafCollides(unsigned int b1, unsigned int /*b2*/,
584  CoalScalar& sqrDistLowerBound) const {
585  count++;
586  if (this->enable_statistics) this->num_leaf_tests++;
587  const HFNode<BV>& node = this->model1->getBV(b1);
588 
589  // Split quadrilateral primitives into two convex shapes corresponding to
590  // polyhedron with triangular bases. This is essential to keep the convexity
591 
592  // typedef Convex<Quadrilateral> ConvexQuadrilateral;
593  // const ConvexQuadrilateral convex =
594  // details::buildConvexQuadrilateral(node,*this->model1);
595 
596  typedef Convex<Triangle> ConvexTriangle;
597  ConvexTriangle convex1, convex2;
598  int convex1_active_faces, convex2_active_faces;
599  // TODO: inherit from hfield's inflation here
600  details::buildConvexTriangles(node, *this->model1, convex1,
601  convex1_active_faces, convex2,
602  convex2_active_faces);
603 
604  // Compute aabb_local for BoundingVolumeGuess case in the GJK solver
605  if (nsolver->gjk_initial_guess == GJKInitialGuess::BoundingVolumeGuess) {
606  convex1.computeLocalAABB();
607  convex2.computeLocalAABB();
608  }
609 
611  // Vec3s contact_point, normal;
612  Vec3s c1, c2, normal, normal_face;
613  bool hfield_witness_is_on_bin_side;
614 
615  bool collision = details::shapeDistance<Triangle, S, Options>(
616  nsolver, this->request, convex1, convex1_active_faces, convex2,
617  convex2_active_faces, this->tf1, *(this->model2), this->tf2, distance,
618  c1, c2, normal, normal_face, hfield_witness_is_on_bin_side);
619 
620  CoalScalar distToCollision = distance - this->request.security_margin;
621  if (distToCollision <= this->request.collision_distance_threshold) {
622  sqrDistLowerBound = 0;
623  if (this->result->numContacts() < this->request.num_max_contacts) {
624  if (normal_face.isApprox(normal) &&
625  (collision || !hfield_witness_is_on_bin_side)) {
626  this->result->addContact(Contact(this->model1, this->model2, (int)b1,
627  (int)Contact::NONE, c1, c2, normal,
628  distance));
629  assert(this->result->isCollision());
630  }
631  }
632  } else
633  sqrDistLowerBound = distToCollision * distToCollision;
634 
635  // const Vec3s c1 = contact_point - distance * 0.5 * normal;
636  // const Vec3s c2 = contact_point + distance * 0.5 * normal;
637  internal::updateDistanceLowerBoundFromLeaf(this->request, *this->result,
638  distToCollision, c1, c2, normal);
639 
640  assert(this->result->isCollision() || sqrDistLowerBound > 0);
641  }
642 
643  const GJKSolver* nsolver;
644 
645  const HeightField<BV>* model1;
646  const S* model2;
647  BV model2_bv;
648 
649  mutable int num_bv_tests;
650  mutable int num_leaf_tests;
651  mutable CoalScalar query_time_seconds;
652  mutable int count;
653 };
654 
656 
659 
661 template <typename BV, typename S,
662  int _Options = RelativeTransformationIsIdentity>
663 class HeightFieldShapeDistanceTraversalNode : public DistanceTraversalNodeBase {
664  public:
665  typedef DistanceTraversalNodeBase Base;
666 
667  enum {
668  Options = _Options,
669  RTIsIdentity = _Options & RelativeTransformationIsIdentity
670  };
671 
672  HeightFieldShapeDistanceTraversalNode() : DistanceTraversalNodeBase() {
673  model1 = NULL;
674  model2 = NULL;
675 
676  num_leaf_tests = 0;
677  query_time_seconds = 0.0;
678 
679  rel_err = 0;
680  abs_err = 0;
681  nsolver = NULL;
682  }
683 
685  bool isFirstNodeLeaf(unsigned int b) const {
686  return model1->getBV(b).isLeaf();
687  }
688 
690  int getFirstLeftChild(unsigned int b) const {
691  return model1->getBV(b).leftChild();
692  }
693 
695  int getFirstRightChild(unsigned int b) const {
696  return model1->getBV(b).rightChild();
697  }
698 
700  CoalScalar BVDistanceLowerBound(unsigned int b1, unsigned int /*b2*/) const {
701  return model1->getBV(b1).bv.distance(
702  model2_bv); // TODO(jcarpent): tf1 is not taken into account here.
703  }
704 
709  void leafComputeDistance(unsigned int b1, unsigned int /*b2*/) const {
710  if (this->enable_statistics) this->num_leaf_tests++;
711 
712  const BVNode<BV>& node = this->model1->getBV(b1);
713 
714  typedef Convex<Quadrilateral> ConvexQuadrilateral;
715  const ConvexQuadrilateral convex =
716  details::buildConvexQuadrilateral(node, *this->model1);
717 
718  Vec3s p1, p2, normal;
719  const CoalScalar distance =
720  internal::ShapeShapeDistance<ConvexQuadrilateral, S>(
721  &convex, this->tf1, this->model2, this->tf2, this->nsolver,
722  this->request.enable_signed_distance, p1, p2, normal);
723 
724  this->result->update(distance, this->model1, this->model2, b1,
725  DistanceResult::NONE, p1, p2, normal);
726  }
727 
729  bool canStop(CoalScalar c) const {
730  if ((c >= this->result->min_distance - abs_err) &&
731  (c * (1 + rel_err) >= this->result->min_distance))
732  return true;
733  return false;
734  }
735 
736  CoalScalar rel_err;
737  CoalScalar abs_err;
738 
739  const GJKSolver* nsolver;
740 
741  const HeightField<BV>* model1;
742  const S* model2;
743  BV model2_bv;
744 
745  mutable int num_bv_tests;
746  mutable int num_leaf_tests;
747  mutable CoalScalar query_time_seconds;
748 };
749 
751 
752 } // namespace coal
753 
755 
756 #endif
traversal.h
coal::Vec3s
Eigen::Matrix< CoalScalar, 3, 1 > Vec3s
Definition: coal/data_types.h:77
intersect.h
traversal_node_base.h
coal::internal::updateDistanceLowerBoundFromLeaf
void updateDistanceLowerBoundFromLeaf(const CollisionRequest &, CollisionResult &res, const CoalScalar &distance, const Vec3s &p0, const Vec3s &p1, const Vec3s &normal)
Definition: coal/collision_data.h:1184
gjk.tf1
tuple tf1
Definition: test/scripts/gjk.py:27
collision_data.h
coal
Main namespace.
Definition: coal/broadphase/broadphase_bruteforce.h:44
narrowphase.h
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
convex.h
coal::DistanceResult::NONE
static const int NONE
invalid contact primitive information
Definition: coal/collision_data.h:1086
res
res
shape_shape_func.h
COAL_UNUSED_VARIABLE
#define COAL_UNUSED_VARIABLE(var)
Definition: include/coal/fwd.hh:56
coal::VecXs
Eigen::Matrix< CoalScalar, Eigen::Dynamic, 1 > VecXs
Definition: coal/data_types.h:80
COAL_THROW_PRETTY
#define COAL_THROW_PRETTY(message, exception)
Definition: include/coal/fwd.hh:64
gjk.tf2
tuple tf2
Definition: test/scripts/gjk.py:36
coal::BoundingVolumeGuess
@ BoundingVolumeGuess
Definition: coal/data_types.h:95
octree.p1
tuple p1
Definition: octree.py:54
collision
Definition: python_unit/collision.py:1
coal::overlap
COAL_DLLAPI bool overlap(const Matrix3s &R0, const Vec3s &T0, const AABB &b1, const AABB &b2)
Check collision between two aabbs, b1 is in configuration (R0, T0) and b2 is in identity.
Definition: AABB.cpp:134
coal::MatrixXs
Eigen::Matrix< CoalScalar, Eigen::Dynamic, Eigen::Dynamic > MatrixXs
Definition: coal/data_types.h:86
generate_distance_plot.b
float b
Definition: generate_distance_plot.py:7
coal::HFNodeBase::FaceOrientation
FaceOrientation
Definition: coal/hfield.h:56
coal::internal::updateDistanceLowerBoundFromBV
void updateDistanceLowerBoundFromBV(const CollisionRequest &, CollisionResult &res, const CoalScalar sqrDistLowerBound)
Definition: coal/collision_data.h:1175
hfield.h
x1
x1
geometric_shapes_utility.h
geometric_shapes.h
Base
c2
c2
coal::CoalScalar
double CoalScalar
Definition: coal/data_types.h:76
coal::Contact::NONE
static const int NONE
invalid contact primitive information
Definition: coal/collision_data.h:108


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