38 #ifndef COAL_TRAVERSAL_NODE_MESHES_H
39 #define COAL_TRAVERSAL_NODE_MESHES_H
62 template <
typename BV>
63 class BVHCollisionTraversalNode :
public CollisionTraversalNodeBase {
65 BVHCollisionTraversalNode(
const CollisionRequest& request)
66 : CollisionTraversalNodeBase(request) {
72 query_time_seconds = 0.0;
76 bool isFirstNodeLeaf(
unsigned int b)
const {
77 assert(model1 != NULL &&
"model1 is NULL");
78 return model1->getBV(
b).isLeaf();
82 bool isSecondNodeLeaf(
unsigned int b)
const {
83 assert(model2 != NULL &&
"model2 is NULL");
84 return model2->getBV(
b).isLeaf();
88 bool firstOverSecond(
unsigned int b1,
unsigned int b2)
const {
92 bool l1 = model1->getBV(b1).isLeaf();
93 bool l2 = model2->getBV(b2).isLeaf();
95 if (l2 || (!l1 && (sz1 > sz2)))
return true;
100 int getFirstLeftChild(
unsigned int b)
const {
101 return model1->getBV(
b).leftChild();
105 int getFirstRightChild(
unsigned int b)
const {
106 return model1->getBV(
b).rightChild();
110 int getSecondLeftChild(
unsigned int b)
const {
111 return model2->getBV(
b).leftChild();
115 int getSecondRightChild(
unsigned int b)
const {
116 return model2->getBV(
b).rightChild();
120 const BVHModel<BV>* model1;
122 const BVHModel<BV>* model2;
125 mutable int num_bv_tests;
126 mutable int num_leaf_tests;
131 template <
typename BV,
int _Options = RelativeTransformationIsIdentity>
132 class MeshCollisionTraversalNode :
public BVHCollisionTraversalNode<BV> {
136 RTIsIdentity = _Options & RelativeTransformationIsIdentity
139 MeshCollisionTraversalNode(
const CollisionRequest& request)
140 : BVHCollisionTraversalNode<BV>(request) {
151 bool BVDisjoints(
unsigned int b1,
unsigned int b2,
153 if (this->enable_statistics) this->num_bv_tests++;
156 disjoint = !this->model1->getBV(b1).overlap(
157 this->model2->getBV(b2), this->request, sqrDistLowerBound);
159 disjoint = !
overlap(RT._R(), RT._T(), this->model2->getBV(b2).bv,
160 this->model1->getBV(b1).bv, this->request,
183 void leafCollides(
unsigned int b1,
unsigned int b2,
185 if (this->enable_statistics) this->num_leaf_tests++;
187 const BVNode<BV>& node1 = this->model1->getBV(b1);
188 const BVNode<BV>& node2 = this->model2->getBV(b2);
190 int primitive_id1 = node1.primitiveId();
191 int primitive_id2 = node2.primitiveId();
193 const Triangle& tri_id1 = tri_indices1[primitive_id1];
194 const Triangle& tri_id2 = tri_indices2[primitive_id2];
196 const Vec3s&
P1 = vertices1[tri_id1[0]];
197 const Vec3s&
P2 = vertices1[tri_id1[1]];
198 const Vec3s&
P3 = vertices1[tri_id1[2]];
199 const Vec3s&
Q1 = vertices2[tri_id2[0]];
200 const Vec3s&
Q2 = vertices2[tri_id2[1]];
201 const Vec3s&
Q3 = vertices2[tri_id2[2]];
203 TriangleP tri1(
P1,
P2,
P3);
204 TriangleP tri2(
Q1,
Q2,
Q3);
207 GJKSolver solver(this->request);
209 const bool compute_penetration =
210 this->request.enable_contact || (this->request.security_margin < 0);
212 DistanceResult distanceResult;
214 &tri1, this->
tf1, &tri2, this->
tf2, &solver, compute_penetration,
p1,
220 distToCollision,
p1, p2, normal);
222 if (distToCollision <=
223 this->request.collision_distance_threshold) {
224 sqrDistLowerBound = 0;
225 if (this->result->numContacts() < this->request.num_max_contacts) {
226 this->result->addContact(Contact(this->model1, this->model2,
227 primitive_id1, primitive_id2,
p1, p2,
231 sqrDistLowerBound = distToCollision * distToCollision;
237 Triangle* tri_indices1;
238 Triangle* tri_indices2;
240 details::RelativeTransformation<!bool(RTIsIdentity)> RT;
245 typedef MeshCollisionTraversalNode<OBB, 0> MeshCollisionTraversalNodeOBB;
246 typedef MeshCollisionTraversalNode<RSS, 0> MeshCollisionTraversalNodeRSS;
247 typedef MeshCollisionTraversalNode<kIOS, 0> MeshCollisionTraversalNodekIOS;
248 typedef MeshCollisionTraversalNode<OBBRSS, 0> MeshCollisionTraversalNodeOBBRSS;
253 template <
typename BV>
254 struct DistanceTraversalBVDistanceLowerBound_impl {
255 static CoalScalar run(
const BVNode<BV>& b1,
const BVNode<BV>& b2) {
256 return b1.distance(b2);
259 const BVNode<BV>& b2) {
260 return distance(R, T, b1.bv, b2.bv);
265 struct DistanceTraversalBVDistanceLowerBound_impl<OBB> {
266 static CoalScalar run(
const BVNode<OBB>& b1,
const BVNode<OBB>& b2) {
270 if (b1.overlap(b2, request, sqrDistLowerBound)) {
274 return sqrt(sqrDistLowerBound);
277 const BVNode<OBB>& b1,
const BVNode<OBB>& b2) {
281 if (
overlap(R, T, b1.bv, b2.bv, request, sqrDistLowerBound)) {
285 return sqrt(sqrDistLowerBound);
290 struct DistanceTraversalBVDistanceLowerBound_impl<AABB> {
291 static CoalScalar run(
const BVNode<AABB>& b1,
const BVNode<AABB>& b2) {
295 if (b1.overlap(b2, request, sqrDistLowerBound)) {
299 return sqrt(sqrDistLowerBound);
302 const BVNode<AABB>& b1,
const BVNode<AABB>& b2) {
306 if (
overlap(R, T, b1.bv, b2.bv, request, sqrDistLowerBound)) {
310 return sqrt(sqrDistLowerBound);
319 template <
typename BV>
320 class BVHDistanceTraversalNode :
public DistanceTraversalNodeBase {
322 BVHDistanceTraversalNode() : DistanceTraversalNodeBase() {
328 query_time_seconds = 0.0;
332 bool isFirstNodeLeaf(
unsigned int b)
const {
333 return model1->getBV(
b).isLeaf();
337 bool isSecondNodeLeaf(
unsigned int b)
const {
338 return model2->getBV(
b).isLeaf();
342 bool firstOverSecond(
unsigned int b1,
unsigned int b2)
const {
346 bool l1 = model1->getBV(b1).isLeaf();
347 bool l2 = model2->getBV(b2).isLeaf();
349 if (l2 || (!l1 && (sz1 > sz2)))
return true;
354 int getFirstLeftChild(
unsigned int b)
const {
355 return model1->getBV(
b).leftChild();
359 int getFirstRightChild(
unsigned int b)
const {
360 return model1->getBV(
b).rightChild();
364 int getSecondLeftChild(
unsigned int b)
const {
365 return model2->getBV(
b).leftChild();
369 int getSecondRightChild(
unsigned int b)
const {
370 return model2->getBV(
b).rightChild();
374 const BVHModel<BV>* model1;
376 const BVHModel<BV>* model2;
379 mutable int num_bv_tests;
380 mutable int num_leaf_tests;
385 template <
typename BV,
int _Options = RelativeTransformationIsIdentity>
386 class MeshDistanceTraversalNode :
public BVHDistanceTraversalNode<BV> {
390 RTIsIdentity = _Options & RelativeTransformationIsIdentity
393 using BVHDistanceTraversalNode<BV>::enable_statistics;
394 using BVHDistanceTraversalNode<BV>::request;
395 using BVHDistanceTraversalNode<BV>::result;
397 using BVHDistanceTraversalNode<BV>::model1;
398 using BVHDistanceTraversalNode<BV>::model2;
399 using BVHDistanceTraversalNode<BV>::num_bv_tests;
400 using BVHDistanceTraversalNode<BV>::num_leaf_tests;
402 MeshDistanceTraversalNode() : BVHDistanceTraversalNode<BV>() {
408 rel_err = this->request.rel_err;
409 abs_err = this->request.abs_err;
413 if (!RTIsIdentity) preprocessOrientedNode();
417 if (!RTIsIdentity) postprocessOrientedNode();
421 CoalScalar BVDistanceLowerBound(
unsigned int b1,
unsigned int b2)
const {
422 if (enable_statistics) num_bv_tests++;
425 model1->getBV(b1), model2->getBV(b2));
428 RT._R(), RT._T(), model1->getBV(b1), model2->getBV(b2));
432 void leafComputeDistance(
unsigned int b1,
unsigned int b2)
const {
433 if (this->enable_statistics) this->num_leaf_tests++;
435 const BVNode<BV>& node1 = this->model1->getBV(b1);
436 const BVNode<BV>& node2 = this->model2->getBV(b2);
438 int primitive_id1 = node1.primitiveId();
439 int primitive_id2 = node2.primitiveId();
441 const Triangle& tri_id1 = tri_indices1[primitive_id1];
442 const Triangle& tri_id2 = tri_indices2[primitive_id2];
444 const Vec3s& t11 = vertices1[tri_id1[0]];
445 const Vec3s& t12 = vertices1[tri_id1[1]];
446 const Vec3s& t13 = vertices1[tri_id1[2]];
448 const Vec3s& t21 = vertices2[tri_id2[0]];
449 const Vec3s& t22 = vertices2[tri_id2[1]];
450 const Vec3s& t23 = vertices2[tri_id2[2]];
457 d2 = TriangleDistance::sqrTriDistance(t11, t12, t13, t21, t22, t23,
P1,
460 d2 = TriangleDistance::sqrTriDistance(t11, t12, t13, t21, t22, t23,
461 RT._R(), RT._T(),
P1,
P2);
464 this->result->update(d, this->model1, this->model2, primitive_id1,
465 primitive_id2,
P1,
P2, normal);
470 if ((c >= this->result->min_distance - abs_err) &&
471 (c * (1 + rel_err) >= this->result->min_distance))
479 Triangle* tri_indices1;
480 Triangle* tri_indices2;
486 details::RelativeTransformation<!bool(RTIsIdentity)> RT;
489 void preprocessOrientedNode() {
490 const int init_tri_id1 = 0, init_tri_id2 = 0;
491 const Triangle& init_tri1 = tri_indices1[init_tri_id1];
492 const Triangle& init_tri2 = tri_indices2[init_tri_id2];
494 Vec3s init_tri1_points[3];
495 Vec3s init_tri2_points[3];
497 init_tri1_points[0] = vertices1[init_tri1[0]];
498 init_tri1_points[1] = vertices1[init_tri1[1]];
499 init_tri1_points[2] = vertices1[init_tri1[2]];
501 init_tri2_points[0] = vertices2[init_tri2[0]];
502 init_tri2_points[1] = vertices2[init_tri2[1]];
503 init_tri2_points[2] = vertices2[init_tri2[2]];
507 init_tri1_points[0], init_tri1_points[1], init_tri1_points[2],
508 init_tri2_points[0], init_tri2_points[1], init_tri2_points[2], RT._R(),
511 result->update(
distance, model1, model2, init_tri_id1, init_tri_id2,
p1, p2,
514 void postprocessOrientedNode() {
518 if (request.enable_nearest_points && (result->o1 == model1) &&
519 (result->o2 == model2)) {
520 result->nearest_points[0] =
tf1.transform(result->nearest_points[0]);
521 result->nearest_points[1] =
tf1.transform(result->nearest_points[1]);
528 typedef MeshDistanceTraversalNode<RSS, 0> MeshDistanceTraversalNodeRSS;
529 typedef MeshDistanceTraversalNode<kIOS, 0> MeshDistanceTraversalNodekIOS;
530 typedef MeshDistanceTraversalNode<OBBRSS, 0> MeshDistanceTraversalNodeOBBRSS;
538 template <
typename BV>
539 inline const Matrix3s& getBVAxes(
const BV& bv) {
544 inline const Matrix3s& getBVAxes<OBBRSS>(
const OBBRSS& bv) {