coal 3.0.2
Coal, The Collision Detection Library. Previously known as HPP-FCL, fork of FCL -- The Flexible Collision Library
Loading...
Searching...
No Matches
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
36
37#ifndef COAL_TRAVERSAL_NODE_HFIELD_SHAPE_H
38#define COAL_TRAVERSAL_NODE_HFIELD_SHAPE_H
39
41
50#include "coal/hfield.h"
51#include "coal/shape/convex.h"
52
53namespace coal {
54
57
58namespace details {
59template <typename BV>
60Convex<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
104enum class FaceOrientationConvexPart1 {
105 BOTTOM = 0,
106 TOP = 1,
107 WEST = 2,
108 SOUTH_EAST = 4,
109 NORTH = 8,
110};
111
112enum class FaceOrientationConvexPart2 {
113 BOTTOM = 0,
114 TOP = 1,
115 SOUTH = 2,
116 NORTH_WEST = 4,
117 EAST = 8,
118};
119
120template <typename BV>
121void 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
233inline 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
244inline 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
257inline 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
269inline 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
282inline 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
290inline 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
320template <typename Polygone, typename Shape>
321bool 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.
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
401template <typename Polygone, typename Shape, int Options>
402bool 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
513template <typename BV, typename S,
514 int _Options = RelativeTransformationIsIdentity>
515class 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
661template <typename BV, typename S,
662 int _Options = RelativeTransformationIsIdentity>
663class 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
#define COAL_UNUSED_VARIABLE(var)
Definition fwd.hh:56
#define COAL_THROW_PRETTY(message, exception)
Definition fwd.hh:64
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.
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 hfield.h:170
Vec3s getSupport(const ShapeBase *shape, const Vec3s &dir, int &hint)
the support function for shape. The output support point is expressed in the local frame of the shape...
Main namespace.
Definition broadphase_bruteforce.h:44
Eigen::Matrix< CoalScalar, Eigen::Dynamic, 1 > VecXs
Definition data_types.h:80
Eigen::Matrix< CoalScalar, Eigen::Dynamic, Eigen::Dynamic > MatrixXs
Definition data_types.h:86
Eigen::Matrix< CoalScalar, 3, 1 > Vec3s
Definition data_types.h:77
double CoalScalar
Definition data_types.h:76
FaceOrientation
Definition hfield.h:56