37 #ifndef COAL_TRAVERSAL_NODE_HFIELD_SHAPE_H 
   38 #define COAL_TRAVERSAL_NODE_HFIELD_SHAPE_H 
   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();
 
   66   const CoalScalar min_height = model.getMinHeight();
 
   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);
 
   73   assert(cell.maxCoeff() > min_height &&
 
   74          "max_height is lower than min_height");  
 
   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)),
 
   88   std::shared_ptr<std::vector<Quadrilateral>> polygons(
 
   89       new std::vector<Quadrilateral>(6));
 
   90   (*polygons)[0].set(0, 3, 2, 1);  
 
   91   (*polygons)[1].set(0, 1, 5, 4);  
 
   92   (*polygons)[2].set(1, 2, 6, 5);  
 
   93   (*polygons)[3].set(2, 3, 7, 6);  
 
   94   (*polygons)[4].set(3, 0, 4, 7);  
 
   95   (*polygons)[5].set(4, 5, 6, 7);  
 
   97   return Convex<Quadrilateral>(pts,  
 
  104 enum class FaceOrientationConvexPart1 {
 
  112 enum class FaceOrientationConvexPart2 {
 
  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();
 
  129   const CoalScalar min_height = model.getMinHeight();
 
  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);
 
  137   const int contact_active_faces = node.contact_active_faces;
 
  138   convex1_active_faces = 0;
 
  139   convex2_active_faces = 0;
 
  143   if (contact_active_faces & FaceOrientation::TOP) {
 
  144     convex1_active_faces |= int(details::FaceOrientationConvexPart1::TOP);
 
  145     convex2_active_faces |= int(details::FaceOrientationConvexPart2::TOP);
 
  148   if (contact_active_faces & FaceOrientation::BOTTOM) {
 
  149     convex1_active_faces |= int(details::FaceOrientationConvexPart1::BOTTOM);
 
  150     convex2_active_faces |= int(details::FaceOrientationConvexPart2::BOTTOM);
 
  154   if (contact_active_faces & FaceOrientation::WEST) {
 
  155     convex1_active_faces |= int(details::FaceOrientationConvexPart1::WEST);
 
  158   if (contact_active_faces & FaceOrientation::NORTH) {
 
  159     convex1_active_faces |= int(details::FaceOrientationConvexPart1::NORTH);
 
  163   if (contact_active_faces & FaceOrientation::EAST) {
 
  164     convex2_active_faces |= int(details::FaceOrientationConvexPart2::EAST);
 
  167   if (contact_active_faces & FaceOrientation::SOUTH) {
 
  168     convex2_active_faces |= int(details::FaceOrientationConvexPart2::SOUTH);
 
  171   assert(max_height > min_height &&
 
  172          "max_height is lower than min_height");  
 
  177     std::shared_ptr<std::vector<Vec3s>> pts(
new std::vector<Vec3s>({
 
  178         Vec3s(x0, y0, min_height),  
 
  179         Vec3s(x0, y1, min_height),  
 
  180         Vec3s(x1, y0, min_height),  
 
  181         Vec3s(x0, y0, cell(0, 0)),  
 
  182         Vec3s(x0, y1, cell(1, 0)),  
 
  183         Vec3s(x1, y0, cell(0, 1)),  
 
  186     std::shared_ptr<std::vector<Triangle>> triangles(
 
  187         new std::vector<Triangle>(8));
 
  188     (*triangles)[0].set(0, 2, 1);  
 
  189     (*triangles)[1].set(3, 4, 5);  
 
  190     (*triangles)[2].set(0, 1, 3);  
 
  191     (*triangles)[3].set(3, 1, 4);  
 
  192     (*triangles)[4].set(1, 2, 5);  
 
  193     (*triangles)[5].set(1, 5, 4);  
 
  194     (*triangles)[6].set(0, 5, 2);  
 
  195     (*triangles)[7].set(5, 0, 3);  
 
  205     std::shared_ptr<std::vector<Vec3s>> pts(
new std::vector<Vec3s>({
 
  206         Vec3s(x0, y1, min_height),  
 
  207         Vec3s(x1, y1, min_height),  
 
  208         Vec3s(x1, y0, min_height),  
 
  209         Vec3s(x0, y1, cell(1, 0)),  
 
  210         Vec3s(x1, y1, cell(1, 1)),  
 
  211         Vec3s(x1, y0, cell(0, 1)),  
 
  214     std::shared_ptr<std::vector<Triangle>> triangles(
 
  215         new std::vector<Triangle>(8));
 
  216     (*triangles)[0].set(2, 1, 0);  
 
  217     (*triangles)[1].set(3, 4, 5);  
 
  218     (*triangles)[2].set(0, 1, 3);  
 
  219     (*triangles)[3].set(3, 1, 4);  
 
  220     (*triangles)[4].set(0, 5, 2);  
 
  221     (*triangles)[5].set(0, 3, 5);  
 
  222     (*triangles)[6].set(1, 2, 5);  
 
  223     (*triangles)[7].set(4, 1, 2);  
 
  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;
 
  244 inline Vec3s projectTetrahedra(
const Vec3s& pointA, 
const Vec3s& pointB,
 
  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;
 
  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]];
 
  263   const Vec3s normal = (pointB - pointA).cross(pointC - pointA).normalized();
 
  264   assert(!normal.array().isNaN().any() && 
"normal is ill-defined");
 
  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]];
 
  276   const Vec3s contact_point_projected =
 
  277       projectTriangle(pointA, pointB, pointC, contact_point);
 
  279   return contact_point_projected;
 
  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();
 
  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]");
 
  296   const std::vector<Vec3s>& points = *(convex.points);
 
  298     const Triangle& triangle = (*(convex.polygons))[face_id];
 
  299     closest_face_id = face_id;
 
  300     return distanceContactPointToTriangle(contact_point, triangle, points);
 
  302     const Triangle& triangle1 = (*(convex.polygons))[face_id];
 
  304         distanceContactPointToTriangle(contact_point, triangle1, points);
 
  306     const Triangle& triangle2 = (*(convex.polygons))[face_id + 1];
 
  308         distanceContactPointToTriangle(contact_point, triangle2, points);
 
  310     if (distance_to_triangle1 > distance_to_triangle2) {
 
  311       closest_face_id = face_id + 1;
 
  312       return distance_to_triangle2;
 
  314       closest_face_id = face_id;
 
  315       return distance_to_triangle1;
 
  320 template <
typename Polygone, 
typename Shape>
 
  321 bool binCorrection(
const Convex<Polygone>& convex,
 
  322                    const int convex_active_faces, 
const Shape& shape,
 
  325                    Vec3s& face_normal, 
const bool is_collision) {
 
  327   const std::vector<Vec3s>& points = *(convex.points);
 
  329   bool hfield_witness_is_on_bin_side = 
true;
 
  334   std::vector<size_t> active_faces;
 
  335   active_faces.reserve(5);
 
  336   active_faces.push_back(0);
 
  337   active_faces.push_back(1);
 
  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);
 
  343   Triangle face_triangle;
 
  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);
 
  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;
 
  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;
 
  366     if (!face_triangle.isValid())
 
  369     const Vec3s face_pointA = points[face_triangle[0]];
 
  370     face_normal = computeTriangleNormal(face_triangle, points);
 
  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();
 
  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);
 
  387     const Vec3s projected_support =
 
  388         support - distance_support_projection_plane * face_normal;
 
  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);
 
  398   return hfield_witness_is_on_bin_side;
 
  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,
 
  409                    Vec3s& normal_top, 
bool& hfield_witness_is_on_bin_side) {
 
  410   enum { RTIsIdentity = Options & RelativeTransformationIsIdentity };
 
  412   const Transform3s Id;
 
  418   const bool compute_penetration = 
true;
 
  419   Vec3s contact1_1, contact1_2, contact2_1, contact2_2;
 
  420   Vec3s normal1, normal1_top, normal2, normal2_top;
 
  424     distance1 = internal::ShapeShapeDistance<Convex<Polygone>, Shape>(
 
  425         &convex1, Id, &shape, 
tf2, nsolver, compute_penetration, contact1_1,
 
  426         contact1_2, normal1);
 
  428     distance1 = internal::ShapeShapeDistance<Convex<Polygone>, Shape>(
 
  429         &convex1, 
tf1, &shape, 
tf2, nsolver, compute_penetration, contact1_1,
 
  430         contact1_2, normal1);
 
  432   bool collision1 = (distance1 - request.security_margin <=
 
  433                      request.collision_distance_threshold);
 
  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);
 
  440     distance2 = internal::ShapeShapeDistance<Convex<Polygone>, Shape>(
 
  441         &convex2, Id, &shape, 
tf2, nsolver, compute_penetration, contact2_1,
 
  442         contact2_2, normal2);
 
  444     distance2 = internal::ShapeShapeDistance<Convex<Polygone>, Shape>(
 
  445         &convex2, 
tf1, &shape, 
tf2, nsolver, compute_penetration, contact2_1,
 
  446         contact2_2, normal2);
 
  448   bool collision2 = (distance2 - request.security_margin <=
 
  449                      request.collision_distance_threshold);
 
  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);
 
  455   if (collision1 && collision2) {
 
  456     if (distance1 > distance2)  
 
  462       normal_top = normal2_top;
 
  463       hfield_witness_is_on_bin_side = hfield_witness_is_on_bin_side2;
 
  469       normal_top = normal1_top;
 
  470       hfield_witness_is_on_bin_side = hfield_witness_is_on_bin_side1;
 
  473   } 
else if (collision1) {
 
  478     normal_top = normal1_top;
 
  479     hfield_witness_is_on_bin_side = hfield_witness_is_on_bin_side1;
 
  481   } 
else if (collision2) {
 
  486     normal_top = normal2_top;
 
  487     hfield_witness_is_on_bin_side = hfield_witness_is_on_bin_side2;
 
  491   if (distance1 > distance2)  
 
  497     normal_top = normal2_top;
 
  498     hfield_witness_is_on_bin_side = hfield_witness_is_on_bin_side2;
 
  504     normal_top = normal1_top;
 
  505     hfield_witness_is_on_bin_side = hfield_witness_is_on_bin_side1;
 
  513 template <
typename BV, 
typename S,
 
  514           int _Options = RelativeTransformationIsIdentity>
 
  515 class HeightFieldShapeCollisionTraversalNode
 
  516     : 
public CollisionTraversalNodeBase {
 
  518   typedef CollisionTraversalNodeBase 
Base;
 
  519   typedef Eigen::Array<CoalScalar, 1, 2> Array2d;
 
  523     RTIsIdentity = _Options & RelativeTransformationIsIdentity
 
  526   HeightFieldShapeCollisionTraversalNode(
const CollisionRequest& request)
 
  527       : CollisionTraversalNodeBase(request) {
 
  533     query_time_seconds = 0.0;
 
  540   bool isFirstNodeLeaf(
unsigned int b)
 const {
 
  541     return model1->getBV(
b).isLeaf();
 
  545   int getFirstLeftChild(
unsigned int b)
 const {
 
  546     return static_cast<int>(model1->getBV(
b).leftChild());
 
  550   int getFirstRightChild(
unsigned int b)
 const {
 
  551     return static_cast<int>(model1->getBV(
b).rightChild());
 
  559   bool BVDisjoints(
unsigned int b1, 
unsigned int ,
 
  561     if (this->enable_statistics) this->num_bv_tests++;
 
  565       assert(
false && 
"must never happened");
 
  566       disjoint = !this->model1->getBV(b1).bv.overlap(
 
  567           this->model2_bv, this->request, sqrDistLowerBound);
 
  569       disjoint = !
overlap(this->tf1.getRotation(), this->tf1.getTranslation(),
 
  570                           this->model1->getBV(b1).bv, this->model2_bv,
 
  571                           this->request, sqrDistLowerBound);
 
  578     assert(!disjoint || sqrDistLowerBound > 0);
 
  583   void leafCollides(
unsigned int b1, 
unsigned int ,
 
  586     if (this->enable_statistics) this->num_leaf_tests++;
 
  587     const HFNode<BV>& node = this->model1->getBV(b1);
 
  596     typedef Convex<Triangle> ConvexTriangle;
 
  597     ConvexTriangle convex1, convex2;
 
  598     int convex1_active_faces, convex2_active_faces;
 
  600     details::buildConvexTriangles(node, *this->model1, convex1,
 
  601                                   convex1_active_faces, convex2,
 
  602                                   convex2_active_faces);
 
  606       convex1.computeLocalAABB();
 
  607       convex2.computeLocalAABB();
 
  612     Vec3s c1, 
c2, normal, normal_face;
 
  613     bool hfield_witness_is_on_bin_side;
 
  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);
 
  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,
 
  629           assert(this->result->isCollision());
 
  633       sqrDistLowerBound = distToCollision * distToCollision;
 
  638                                                distToCollision, c1, c2, normal);
 
  640     assert(this->result->isCollision() || sqrDistLowerBound > 0);
 
  643   const GJKSolver* nsolver;
 
  645   const HeightField<BV>* model1;
 
  649   mutable int num_bv_tests;
 
  650   mutable int num_leaf_tests;
 
  661 template <
typename BV, 
typename S,
 
  662           int _Options = RelativeTransformationIsIdentity>
 
  663 class HeightFieldShapeDistanceTraversalNode : 
public DistanceTraversalNodeBase {
 
  665   typedef DistanceTraversalNodeBase 
Base;
 
  669     RTIsIdentity = _Options & RelativeTransformationIsIdentity
 
  672   HeightFieldShapeDistanceTraversalNode() : DistanceTraversalNodeBase() {
 
  677     query_time_seconds = 0.0;
 
  685   bool isFirstNodeLeaf(
unsigned int b)
 const {
 
  686     return model1->getBV(
b).isLeaf();
 
  690   int getFirstLeftChild(
unsigned int b)
 const {
 
  691     return model1->getBV(
b).leftChild();
 
  695   int getFirstRightChild(
unsigned int b)
 const {
 
  696     return model1->getBV(
b).rightChild();
 
  700   CoalScalar BVDistanceLowerBound(
unsigned int b1, 
unsigned int )
 const {
 
  701     return model1->getBV(b1).bv.distance(
 
  709   void leafComputeDistance(
unsigned int b1, 
unsigned int )
 const {
 
  710     if (this->enable_statistics) this->num_leaf_tests++;
 
  712     const BVNode<BV>& node = this->model1->getBV(b1);
 
  714     typedef Convex<Quadrilateral> ConvexQuadrilateral;
 
  715     const ConvexQuadrilateral convex =
 
  716         details::buildConvexQuadrilateral(node, *this->model1);
 
  720         internal::ShapeShapeDistance<ConvexQuadrilateral, S>(
 
  721             &convex, this->tf1, this->model2, this->tf2, this->nsolver,
 
  722             this->request.enable_signed_distance, 
p1, p2, normal);
 
  724     this->result->update(
distance, this->model1, this->model2, b1,
 
  730     if ((c >= this->result->min_distance - abs_err) &&
 
  731         (c * (1 + rel_err) >= this->result->min_distance))
 
  739   const GJKSolver* nsolver;
 
  741   const HeightField<BV>* model1;
 
  745   mutable int num_bv_tests;
 
  746   mutable int num_leaf_tests;