1 |
|
|
/* |
2 |
|
|
* Software License Agreement (BSD License) |
3 |
|
|
* |
4 |
|
|
* Copyright (c) 2011-2014, Willow Garage, Inc. |
5 |
|
|
* Copyright (c) 2014-2015, Open Source Robotics Foundation |
6 |
|
|
* All rights reserved. |
7 |
|
|
* |
8 |
|
|
* Redistribution and use in source and binary forms, with or without |
9 |
|
|
* modification, are permitted provided that the following conditions |
10 |
|
|
* are met: |
11 |
|
|
* |
12 |
|
|
* * Redistributions of source code must retain the above copyright |
13 |
|
|
* notice, this list of conditions and the following disclaimer. |
14 |
|
|
* * Redistributions in binary form must reproduce the above |
15 |
|
|
* copyright notice, this list of conditions and the following |
16 |
|
|
* disclaimer in the documentation and/or other materials provided |
17 |
|
|
* with the distribution. |
18 |
|
|
* * Neither the name of Open Source Robotics Foundation nor the names of its |
19 |
|
|
* contributors may be used to endorse or promote products derived |
20 |
|
|
* from this software without specific prior written permission. |
21 |
|
|
* |
22 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
23 |
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
24 |
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
25 |
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
26 |
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
27 |
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
28 |
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
29 |
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
30 |
|
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
31 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
32 |
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
33 |
|
|
* POSSIBILITY OF SUCH DAMAGE. |
34 |
|
|
*/ |
35 |
|
|
|
36 |
|
|
/** \author Jia Pan */ |
37 |
|
|
|
38 |
|
|
#ifndef HPP_FCL_TRAVERSAL_NODE_MESH_SHAPE_H |
39 |
|
|
#define HPP_FCL_TRAVERSAL_NODE_MESH_SHAPE_H |
40 |
|
|
|
41 |
|
|
/// @cond INTERNAL |
42 |
|
|
|
43 |
|
|
#include <hpp/fcl/collision_data.h> |
44 |
|
|
#include <hpp/fcl/shape/geometric_shapes.h> |
45 |
|
|
#include <hpp/fcl/narrowphase/narrowphase.h> |
46 |
|
|
#include <hpp/fcl/shape/geometric_shapes_utility.h> |
47 |
|
|
#include <hpp/fcl/internal/traversal_node_base.h> |
48 |
|
|
#include <hpp/fcl/internal/traversal.h> |
49 |
|
|
#include <hpp/fcl/BVH/BVH_model.h> |
50 |
|
|
|
51 |
|
|
namespace hpp { |
52 |
|
|
namespace fcl { |
53 |
|
|
|
54 |
|
|
/// @addtogroup Traversal_For_Collision |
55 |
|
|
/// @{ |
56 |
|
|
|
57 |
|
|
/// @brief Traversal node for collision between BVH and shape |
58 |
|
|
template <typename BV, typename S> |
59 |
|
|
class BVHShapeCollisionTraversalNode : public CollisionTraversalNodeBase { |
60 |
|
|
public: |
61 |
|
248 |
BVHShapeCollisionTraversalNode(const CollisionRequest& request) |
62 |
✓✗ |
248 |
: CollisionTraversalNodeBase(request) { |
63 |
|
248 |
model1 = NULL; |
64 |
|
248 |
model2 = NULL; |
65 |
|
|
|
66 |
|
248 |
num_bv_tests = 0; |
67 |
|
248 |
num_leaf_tests = 0; |
68 |
|
248 |
query_time_seconds = 0.0; |
69 |
|
|
} |
70 |
|
|
|
71 |
|
|
/// @brief Whether the BV node in the first BVH tree is leaf |
72 |
|
7596 |
bool isFirstNodeLeaf(unsigned int b) const { |
73 |
|
7596 |
return model1->getBV(b).isLeaf(); |
74 |
|
|
} |
75 |
|
|
|
76 |
|
|
/// @brief Obtain the left child of BV node in the first BVH |
77 |
|
3796 |
int getFirstLeftChild(unsigned int b) const { |
78 |
|
3796 |
return model1->getBV(b).leftChild(); |
79 |
|
|
} |
80 |
|
|
|
81 |
|
|
/// @brief Obtain the right child of BV node in the first BVH |
82 |
|
3796 |
int getFirstRightChild(unsigned int b) const { |
83 |
|
3796 |
return model1->getBV(b).rightChild(); |
84 |
|
|
} |
85 |
|
|
|
86 |
|
|
const BVHModel<BV>* model1; |
87 |
|
|
const S* model2; |
88 |
|
|
BV model2_bv; |
89 |
|
|
|
90 |
|
|
mutable int num_bv_tests; |
91 |
|
|
mutable int num_leaf_tests; |
92 |
|
|
mutable FCL_REAL query_time_seconds; |
93 |
|
|
}; |
94 |
|
|
|
95 |
|
|
/// @brief Traversal node for collision between shape and BVH |
96 |
|
|
template <typename S, typename BV> |
97 |
|
|
class ShapeBVHCollisionTraversalNode : public CollisionTraversalNodeBase { |
98 |
|
|
public: |
99 |
|
|
ShapeBVHCollisionTraversalNode(const CollisionRequest& request) |
100 |
|
|
: CollisionTraversalNodeBase(request) { |
101 |
|
|
model1 = NULL; |
102 |
|
|
model2 = NULL; |
103 |
|
|
|
104 |
|
|
num_bv_tests = 0; |
105 |
|
|
num_leaf_tests = 0; |
106 |
|
|
query_time_seconds = 0.0; |
107 |
|
|
} |
108 |
|
|
|
109 |
|
|
/// @brief Alway extend the second model, which is a BVH model |
110 |
|
|
bool firstOverSecond(unsigned int, unsigned int) const { return false; } |
111 |
|
|
|
112 |
|
|
/// @brief Whether the BV node in the second BVH tree is leaf |
113 |
|
|
bool isSecondNodeLeaf(unsigned int b) const { |
114 |
|
|
return model2->getBV(b).isLeaf(); |
115 |
|
|
} |
116 |
|
|
|
117 |
|
|
/// @brief Obtain the left child of BV node in the second BVH |
118 |
|
|
int getSecondLeftChild(unsigned int b) const { |
119 |
|
|
return model2->getBV(b).leftChild(); |
120 |
|
|
} |
121 |
|
|
|
122 |
|
|
/// @brief Obtain the right child of BV node in the second BVH |
123 |
|
|
int getSecondRightChild(unsigned int b) const { |
124 |
|
|
return model2->getBV(b).rightChild(); |
125 |
|
|
} |
126 |
|
|
|
127 |
|
|
const S* model1; |
128 |
|
|
const BVHModel<BV>* model2; |
129 |
|
|
BV model1_bv; |
130 |
|
|
|
131 |
|
|
mutable int num_bv_tests; |
132 |
|
|
mutable int num_leaf_tests; |
133 |
|
|
mutable FCL_REAL query_time_seconds; |
134 |
|
|
}; |
135 |
|
|
|
136 |
|
|
/// @brief Traversal node for collision between mesh and shape |
137 |
|
|
template <typename BV, typename S, |
138 |
|
|
int _Options = RelativeTransformationIsIdentity> |
139 |
|
|
class MeshShapeCollisionTraversalNode |
140 |
|
|
: public BVHShapeCollisionTraversalNode<BV, S> { |
141 |
|
|
public: |
142 |
|
|
enum { |
143 |
|
|
Options = _Options, |
144 |
|
|
RTIsIdentity = _Options & RelativeTransformationIsIdentity |
145 |
|
|
}; |
146 |
|
|
|
147 |
|
248 |
MeshShapeCollisionTraversalNode(const CollisionRequest& request) |
148 |
|
248 |
: BVHShapeCollisionTraversalNode<BV, S>(request) { |
149 |
|
248 |
vertices = NULL; |
150 |
|
248 |
tri_indices = NULL; |
151 |
|
|
|
152 |
|
248 |
nsolver = NULL; |
153 |
|
|
} |
154 |
|
|
|
155 |
|
|
/// test between BV b1 and shape |
156 |
|
|
/// @param b1 BV to test, |
157 |
|
|
/// @retval sqrDistLowerBound square of a lower bound of the minimal |
158 |
|
|
/// distance between bounding volumes. |
159 |
|
|
/// @brief BV culling test in one BVTT node |
160 |
|
6826 |
bool BVDisjoints(unsigned int b1, unsigned int /*b2*/, |
161 |
|
|
FCL_REAL& sqrDistLowerBound) const { |
162 |
✗✓ |
6826 |
if (this->enable_statistics) this->num_bv_tests++; |
163 |
|
|
bool disjoint; |
164 |
|
|
if (RTIsIdentity) |
165 |
|
|
disjoint = !this->model1->getBV(b1).bv.overlap( |
166 |
|
|
this->model2_bv, this->request, sqrDistLowerBound); |
167 |
|
|
else |
168 |
|
6826 |
disjoint = !overlap(this->tf1.getRotation(), this->tf1.getTranslation(), |
169 |
|
6826 |
this->model1->getBV(b1).bv, this->model2_bv, |
170 |
|
|
this->request, sqrDistLowerBound); |
171 |
✓✓ |
6826 |
if (disjoint) |
172 |
|
3030 |
internal::updateDistanceLowerBoundFromBV(this->request, *this->result, |
173 |
|
|
sqrDistLowerBound); |
174 |
✓✓✗✓
|
6826 |
assert(!disjoint || sqrDistLowerBound > 0); |
175 |
|
6826 |
return disjoint; |
176 |
|
|
} |
177 |
|
|
|
178 |
|
|
/// @brief Intersection testing between leaves (one triangle and one shape) |
179 |
|
770 |
void leafCollides(unsigned int b1, unsigned int /*b2*/, |
180 |
|
|
FCL_REAL& sqrDistLowerBound) const { |
181 |
✗✓ |
770 |
if (this->enable_statistics) this->num_leaf_tests++; |
182 |
|
770 |
const BVNode<BV>& node = this->model1->getBV(b1); |
183 |
|
|
|
184 |
|
770 |
int primitive_id = node.primitiveId(); |
185 |
|
|
|
186 |
|
770 |
const Triangle& tri_id = tri_indices[primitive_id]; |
187 |
|
|
|
188 |
|
770 |
const Vec3f& p1 = vertices[tri_id[0]]; |
189 |
|
770 |
const Vec3f& p2 = vertices[tri_id[1]]; |
190 |
|
770 |
const Vec3f& p3 = vertices[tri_id[2]]; |
191 |
|
|
|
192 |
|
|
FCL_REAL distance; |
193 |
✓✗ |
770 |
Vec3f normal; |
194 |
✓✗✓✗
|
770 |
Vec3f c1, c2; // closest point |
195 |
|
|
|
196 |
|
|
bool collision; |
197 |
|
|
if (RTIsIdentity) { |
198 |
|
|
static const Transform3f Id; |
199 |
|
|
collision = nsolver->shapeTriangleInteraction( |
200 |
|
|
*(this->model2), this->tf2, p1, p2, p3, Id, distance, c2, c1, normal); |
201 |
|
|
} else { |
202 |
|
1540 |
collision = nsolver->shapeTriangleInteraction(*(this->model2), this->tf2, |
203 |
✓✗ |
770 |
p1, p2, p3, this->tf1, |
204 |
|
|
distance, c2, c1, normal); |
205 |
|
|
} |
206 |
|
|
|
207 |
|
770 |
FCL_REAL distToCollision = distance - this->request.security_margin; |
208 |
✓✓ |
770 |
if (collision) { |
209 |
|
48 |
sqrDistLowerBound = 0; |
210 |
✓✗ |
48 |
if (this->request.num_max_contacts > this->result->numContacts()) { |
211 |
✓✗✓✗ ✓✗✓✗
|
48 |
this->result->addContact(Contact(this->model1, this->model2, |
212 |
|
|
primitive_id, Contact::NONE, c1, |
213 |
|
|
-normal, -distance)); |
214 |
✗✓ |
48 |
assert(this->result->isCollision()); |
215 |
|
|
} |
216 |
✗✓ |
722 |
} else if (distToCollision <= this->request.collision_distance_threshold) { |
217 |
|
|
sqrDistLowerBound = 0; |
218 |
|
|
if (this->request.num_max_contacts > this->result->numContacts()) { |
219 |
|
|
this->result->addContact( |
220 |
|
|
Contact(this->model1, this->model2, primitive_id, Contact::NONE, |
221 |
|
|
.5 * (c1 + c2), (c2 - c1).normalized(), -distance)); |
222 |
|
|
} |
223 |
|
|
} else |
224 |
|
722 |
sqrDistLowerBound = distToCollision * distToCollision; |
225 |
|
|
|
226 |
✓✗ |
770 |
internal::updateDistanceLowerBoundFromLeaf(this->request, *this->result, |
227 |
|
|
distToCollision, c1, c2); |
228 |
|
|
|
229 |
✓✓✗✓
|
770 |
assert(this->result->isCollision() || sqrDistLowerBound > 0); |
230 |
|
|
} |
231 |
|
|
|
232 |
|
|
Vec3f* vertices; |
233 |
|
|
Triangle* tri_indices; |
234 |
|
|
|
235 |
|
|
const GJKSolver* nsolver; |
236 |
|
|
}; |
237 |
|
|
|
238 |
|
|
/// @brief Traversal node for collision between shape and mesh |
239 |
|
|
template <typename S, typename BV, |
240 |
|
|
int _Options = RelativeTransformationIsIdentity> |
241 |
|
|
class ShapeMeshCollisionTraversalNode |
242 |
|
|
: public ShapeBVHCollisionTraversalNode<S, BV> { |
243 |
|
|
public: |
244 |
|
|
enum { |
245 |
|
|
Options = _Options, |
246 |
|
|
RTIsIdentity = _Options & RelativeTransformationIsIdentity |
247 |
|
|
}; |
248 |
|
|
|
249 |
|
|
ShapeMeshCollisionTraversalNode() : ShapeBVHCollisionTraversalNode<S, BV>() { |
250 |
|
|
vertices = NULL; |
251 |
|
|
tri_indices = NULL; |
252 |
|
|
|
253 |
|
|
nsolver = NULL; |
254 |
|
|
} |
255 |
|
|
|
256 |
|
|
/// BV test between b1 and b2 |
257 |
|
|
/// @param b2 Bounding volumes to test, |
258 |
|
|
/// @retval sqrDistLowerBound square of a lower bound of the minimal |
259 |
|
|
/// distance between bounding volumes. |
260 |
|
|
bool BVDisjoints(unsigned int /*b1*/, unsigned int b2, |
261 |
|
|
FCL_REAL& sqrDistLowerBound) const { |
262 |
|
|
if (this->enable_statistics) this->num_bv_tests++; |
263 |
|
|
bool disjoint; |
264 |
|
|
if (RTIsIdentity) |
265 |
|
|
disjoint = !this->model2->getBV(b2).bv.overlap(this->model1_bv, |
266 |
|
|
sqrDistLowerBound); |
267 |
|
|
else |
268 |
|
|
disjoint = !overlap(this->tf2.getRotation(), this->tf2.getTranslation(), |
269 |
|
|
this->model2->getBV(b2).bv, this->model1_bv, |
270 |
|
|
sqrDistLowerBound); |
271 |
|
|
if (disjoint) |
272 |
|
|
internal::updateDistanceLowerBoundFromBV(this->request, *this->result, |
273 |
|
|
sqrDistLowerBound); |
274 |
|
|
assert(!disjoint || sqrDistLowerBound > 0); |
275 |
|
|
return disjoint; |
276 |
|
|
} |
277 |
|
|
|
278 |
|
|
/// @brief Intersection testing between leaves (one shape and one triangle) |
279 |
|
|
void leafCollides(unsigned int /*b1*/, unsigned int b2, |
280 |
|
|
FCL_REAL& sqrDistLowerBound) const { |
281 |
|
|
if (this->enable_statistics) this->num_leaf_tests++; |
282 |
|
|
const BVNode<BV>& node = this->model2->getBV(b2); |
283 |
|
|
|
284 |
|
|
int primitive_id = node.primitiveId(); |
285 |
|
|
|
286 |
|
|
const Triangle& tri_id = tri_indices[primitive_id]; |
287 |
|
|
|
288 |
|
|
const Vec3f& p1 = vertices[tri_id[0]]; |
289 |
|
|
const Vec3f& p2 = vertices[tri_id[1]]; |
290 |
|
|
const Vec3f& p3 = vertices[tri_id[2]]; |
291 |
|
|
|
292 |
|
|
FCL_REAL distance; |
293 |
|
|
Vec3f normal; |
294 |
|
|
Vec3f c1, c2; // closest points |
295 |
|
|
|
296 |
|
|
bool collision; |
297 |
|
|
if (RTIsIdentity) { |
298 |
|
|
static const Transform3f Id; |
299 |
|
|
collision = nsolver->shapeTriangleInteraction( |
300 |
|
|
*(this->model1), this->tf1, p1, p2, p3, Id, c1, c2, distance, normal); |
301 |
|
|
} else { |
302 |
|
|
collision = nsolver->shapeTriangleInteraction(*(this->model1), this->tf1, |
303 |
|
|
p1, p2, p3, this->tf2, c1, |
304 |
|
|
c2, distance, normal); |
305 |
|
|
} |
306 |
|
|
|
307 |
|
|
FCL_REAL distToCollision = distance - this->request.security_margin; |
308 |
|
|
if (collision) { |
309 |
|
|
sqrDistLowerBound = 0; |
310 |
|
|
if (this->request.num_max_contacts > this->result->numContacts()) { |
311 |
|
|
this->result->addContact(Contact(this->model1, this->model2, |
312 |
|
|
Contact::NONE, primitive_id, c1, |
313 |
|
|
normal, -distance)); |
314 |
|
|
assert(this->result->isCollision()); |
315 |
|
|
} |
316 |
|
|
} else if (distToCollision <= this->request.collision_distance_threshold) { |
317 |
|
|
sqrDistLowerBound = 0; |
318 |
|
|
if (this->request.num_max_contacts > this->result->numContacts()) { |
319 |
|
|
this->result->addContact( |
320 |
|
|
Contact(this->model1, this->model2, Contact::NONE, primitive_id, |
321 |
|
|
.5 * (c1 + c2), (c2 - c1).normalized(), -distance)); |
322 |
|
|
} |
323 |
|
|
} else |
324 |
|
|
sqrDistLowerBound = distToCollision * distToCollision; |
325 |
|
|
|
326 |
|
|
internal::updateDistanceLowerBoundFromLeaf(this->request, *this->result, |
327 |
|
|
distToCollision, c1, c2); |
328 |
|
|
|
329 |
|
|
assert(this->result->isCollision() || sqrDistLowerBound > 0); |
330 |
|
|
} |
331 |
|
|
|
332 |
|
|
Vec3f* vertices; |
333 |
|
|
Triangle* tri_indices; |
334 |
|
|
|
335 |
|
|
const GJKSolver* nsolver; |
336 |
|
|
}; |
337 |
|
|
|
338 |
|
|
/// @} |
339 |
|
|
|
340 |
|
|
/// @addtogroup Traversal_For_Distance |
341 |
|
|
/// @{ |
342 |
|
|
|
343 |
|
|
/// @brief Traversal node for distance computation between BVH and shape |
344 |
|
|
template <typename BV, typename S> |
345 |
|
|
class BVHShapeDistanceTraversalNode : public DistanceTraversalNodeBase { |
346 |
|
|
public: |
347 |
✓✗ |
200 |
BVHShapeDistanceTraversalNode() : DistanceTraversalNodeBase() { |
348 |
|
200 |
model1 = NULL; |
349 |
|
200 |
model2 = NULL; |
350 |
|
|
|
351 |
|
200 |
num_bv_tests = 0; |
352 |
|
200 |
num_leaf_tests = 0; |
353 |
|
200 |
query_time_seconds = 0.0; |
354 |
|
|
} |
355 |
|
|
|
356 |
|
|
/// @brief Whether the BV node in the first BVH tree is leaf |
357 |
|
13650 |
bool isFirstNodeLeaf(unsigned int b) const { |
358 |
|
13650 |
return model1->getBV(b).isLeaf(); |
359 |
|
|
} |
360 |
|
|
|
361 |
|
|
/// @brief Obtain the left child of BV node in the first BVH |
362 |
|
10792 |
int getFirstLeftChild(unsigned int b) const { |
363 |
|
10792 |
return model1->getBV(b).leftChild(); |
364 |
|
|
} |
365 |
|
|
|
366 |
|
|
/// @brief Obtain the right child of BV node in the first BVH |
367 |
|
10792 |
int getFirstRightChild(unsigned int b) const { |
368 |
|
10792 |
return model1->getBV(b).rightChild(); |
369 |
|
|
} |
370 |
|
|
|
371 |
|
|
/// @brief BV culling test in one BVTT node |
372 |
|
|
FCL_REAL BVDistanceLowerBound(unsigned int b1, unsigned int /*b2*/) const { |
373 |
|
|
return model1->getBV(b1).bv.distance(model2_bv); |
374 |
|
|
} |
375 |
|
|
|
376 |
|
|
const BVHModel<BV>* model1; |
377 |
|
|
const S* model2; |
378 |
|
|
BV model2_bv; |
379 |
|
|
|
380 |
|
|
mutable int num_bv_tests; |
381 |
|
|
mutable int num_leaf_tests; |
382 |
|
|
mutable FCL_REAL query_time_seconds; |
383 |
|
|
}; |
384 |
|
|
|
385 |
|
|
/// @brief Traversal node for distance computation between shape and BVH |
386 |
|
|
template <typename S, typename BV> |
387 |
|
|
class ShapeBVHDistanceTraversalNode : public DistanceTraversalNodeBase { |
388 |
|
|
public: |
389 |
|
|
ShapeBVHDistanceTraversalNode() : DistanceTraversalNodeBase() { |
390 |
|
|
model1 = NULL; |
391 |
|
|
model2 = NULL; |
392 |
|
|
|
393 |
|
|
num_bv_tests = 0; |
394 |
|
|
num_leaf_tests = 0; |
395 |
|
|
query_time_seconds = 0.0; |
396 |
|
|
} |
397 |
|
|
|
398 |
|
|
/// @brief Whether the BV node in the second BVH tree is leaf |
399 |
|
|
bool isSecondNodeLeaf(unsigned int b) const { |
400 |
|
|
return model2->getBV(b).isLeaf(); |
401 |
|
|
} |
402 |
|
|
|
403 |
|
|
/// @brief Obtain the left child of BV node in the second BVH |
404 |
|
|
int getSecondLeftChild(unsigned int b) const { |
405 |
|
|
return model2->getBV(b).leftChild(); |
406 |
|
|
} |
407 |
|
|
|
408 |
|
|
/// @brief Obtain the right child of BV node in the second BVH |
409 |
|
|
int getSecondRightChild(unsigned int b) const { |
410 |
|
|
return model2->getBV(b).rightChild(); |
411 |
|
|
} |
412 |
|
|
|
413 |
|
|
/// @brief BV culling test in one BVTT node |
414 |
|
|
FCL_REAL BVDistanceLowerBound(unsigned int /*b1*/, unsigned int b2) const { |
415 |
|
|
return model1_bv.distance(model2->getBV(b2).bv); |
416 |
|
|
} |
417 |
|
|
|
418 |
|
|
const S* model1; |
419 |
|
|
const BVHModel<BV>* model2; |
420 |
|
|
BV model1_bv; |
421 |
|
|
|
422 |
|
|
mutable int num_bv_tests; |
423 |
|
|
mutable int num_leaf_tests; |
424 |
|
|
mutable FCL_REAL query_time_seconds; |
425 |
|
|
}; |
426 |
|
|
|
427 |
|
|
/// @brief Traversal node for distance between mesh and shape |
428 |
|
|
template <typename BV, typename S> |
429 |
|
|
class MeshShapeDistanceTraversalNode |
430 |
|
|
: public BVHShapeDistanceTraversalNode<BV, S> { |
431 |
|
|
public: |
432 |
|
200 |
MeshShapeDistanceTraversalNode() : BVHShapeDistanceTraversalNode<BV, S>() { |
433 |
|
200 |
vertices = NULL; |
434 |
|
200 |
tri_indices = NULL; |
435 |
|
|
|
436 |
|
200 |
rel_err = 0; |
437 |
|
200 |
abs_err = 0; |
438 |
|
|
|
439 |
|
200 |
nsolver = NULL; |
440 |
|
|
} |
441 |
|
|
|
442 |
|
|
/// @brief Distance testing between leaves (one triangle and one shape) |
443 |
|
|
void leafComputeDistance(unsigned int b1, unsigned int /*b2*/) const { |
444 |
|
|
if (this->enable_statistics) this->num_leaf_tests++; |
445 |
|
|
|
446 |
|
|
const BVNode<BV>& node = this->model1->getBV(b1); |
447 |
|
|
|
448 |
|
|
int primitive_id = node.primitiveId(); |
449 |
|
|
|
450 |
|
|
const Triangle& tri_id = tri_indices[primitive_id]; |
451 |
|
|
|
452 |
|
|
const Vec3f& p1 = vertices[tri_id[0]]; |
453 |
|
|
const Vec3f& p2 = vertices[tri_id[1]]; |
454 |
|
|
const Vec3f& p3 = vertices[tri_id[2]]; |
455 |
|
|
|
456 |
|
|
FCL_REAL d; |
457 |
|
|
Vec3f closest_p1, closest_p2, normal; |
458 |
|
|
nsolver->shapeTriangleInteraction(*(this->model2), this->tf2, p1, p2, p3, |
459 |
|
|
Transform3f(), d, closest_p2, closest_p1, |
460 |
|
|
normal); |
461 |
|
|
|
462 |
|
|
this->result->update(d, this->model1, this->model2, primitive_id, |
463 |
|
|
DistanceResult::NONE, closest_p1, closest_p2, normal); |
464 |
|
|
} |
465 |
|
|
|
466 |
|
|
/// @brief Whether the traversal process can stop early |
467 |
|
21584 |
bool canStop(FCL_REAL c) const { |
468 |
✓✓ |
21584 |
if ((c >= this->result->min_distance - abs_err) && |
469 |
✓✗ |
8134 |
(c * (1 + rel_err) >= this->result->min_distance)) |
470 |
|
8134 |
return true; |
471 |
|
13450 |
return false; |
472 |
|
|
} |
473 |
|
|
|
474 |
|
|
Vec3f* vertices; |
475 |
|
|
Triangle* tri_indices; |
476 |
|
|
|
477 |
|
|
FCL_REAL rel_err; |
478 |
|
|
FCL_REAL abs_err; |
479 |
|
|
|
480 |
|
|
const GJKSolver* nsolver; |
481 |
|
|
}; |
482 |
|
|
|
483 |
|
|
/// @cond IGNORE |
484 |
|
|
namespace details { |
485 |
|
|
|
486 |
|
|
template <typename BV, typename S> |
487 |
|
2858 |
void meshShapeDistanceOrientedNodeleafComputeDistance( |
488 |
|
|
unsigned int b1, unsigned int /* b2 */, const BVHModel<BV>* model1, |
489 |
|
|
const S& model2, Vec3f* vertices, Triangle* tri_indices, |
490 |
|
|
const Transform3f& tf1, const Transform3f& tf2, const GJKSolver* nsolver, |
491 |
|
|
bool enable_statistics, int& num_leaf_tests, |
492 |
|
|
const DistanceRequest& /* request */, DistanceResult& result) { |
493 |
✗✓ |
2858 |
if (enable_statistics) num_leaf_tests++; |
494 |
|
|
|
495 |
|
2858 |
const BVNode<BV>& node = model1->getBV(b1); |
496 |
|
2858 |
int primitive_id = node.primitiveId(); |
497 |
|
|
|
498 |
|
2858 |
const Triangle& tri_id = tri_indices[primitive_id]; |
499 |
|
2858 |
const Vec3f& p1 = vertices[tri_id[0]]; |
500 |
|
2858 |
const Vec3f& p2 = vertices[tri_id[1]]; |
501 |
|
2858 |
const Vec3f& p3 = vertices[tri_id[2]]; |
502 |
|
|
|
503 |
|
|
FCL_REAL distance; |
504 |
✓✗✓✗ ✓✗ |
2858 |
Vec3f closest_p1, closest_p2, normal; |
505 |
✓✗ |
2858 |
nsolver->shapeTriangleInteraction(model2, tf2, p1, p2, p3, tf1, distance, |
506 |
|
|
closest_p2, closest_p1, normal); |
507 |
|
|
|
508 |
✓✗ |
2858 |
result.update(distance, model1, &model2, primitive_id, DistanceResult::NONE, |
509 |
|
|
closest_p1, closest_p2, normal); |
510 |
|
|
} |
511 |
|
|
|
512 |
|
|
template <typename BV, typename S> |
513 |
|
200 |
static inline void distancePreprocessOrientedNode( |
514 |
|
|
const BVHModel<BV>* model1, Vec3f* vertices, Triangle* tri_indices, |
515 |
|
|
int init_tri_id, const S& model2, const Transform3f& tf1, |
516 |
|
|
const Transform3f& tf2, const GJKSolver* nsolver, |
517 |
|
|
const DistanceRequest& /* request */, DistanceResult& result) { |
518 |
|
200 |
const Triangle& init_tri = tri_indices[init_tri_id]; |
519 |
|
|
|
520 |
|
200 |
const Vec3f& p1 = vertices[init_tri[0]]; |
521 |
|
200 |
const Vec3f& p2 = vertices[init_tri[1]]; |
522 |
|
200 |
const Vec3f& p3 = vertices[init_tri[2]]; |
523 |
|
|
|
524 |
|
|
FCL_REAL distance; |
525 |
✓✗✓✗ ✓✗ |
200 |
Vec3f closest_p1, closest_p2, normal; |
526 |
✓✗ |
200 |
nsolver->shapeTriangleInteraction(model2, tf2, p1, p2, p3, tf1, distance, |
527 |
|
|
closest_p2, closest_p1, normal); |
528 |
|
|
|
529 |
✓✗ |
200 |
result.update(distance, model1, &model2, init_tri_id, DistanceResult::NONE, |
530 |
|
|
closest_p1, closest_p2, normal); |
531 |
|
|
} |
532 |
|
|
|
533 |
|
|
} // namespace details |
534 |
|
|
|
535 |
|
|
/// @endcond |
536 |
|
|
|
537 |
|
|
/// @brief Traversal node for distance between mesh and shape, when mesh BVH is |
538 |
|
|
/// one of the oriented node (RSS, kIOS, OBBRSS) |
539 |
|
|
template <typename S> |
540 |
|
|
class MeshShapeDistanceTraversalNodeRSS |
541 |
|
|
: public MeshShapeDistanceTraversalNode<RSS, S> { |
542 |
|
|
public: |
543 |
|
|
MeshShapeDistanceTraversalNodeRSS() |
544 |
|
|
: MeshShapeDistanceTraversalNode<RSS, S>() {} |
545 |
|
|
|
546 |
|
|
void preprocess() { |
547 |
|
|
details::distancePreprocessOrientedNode( |
548 |
|
|
this->model1, this->vertices, this->tri_indices, 0, *(this->model2), |
549 |
|
|
this->tf1, this->tf2, this->nsolver, this->request, *(this->result)); |
550 |
|
|
} |
551 |
|
|
|
552 |
|
|
void postprocess() {} |
553 |
|
|
|
554 |
|
|
FCL_REAL BVDistanceLowerBound(unsigned int b1, unsigned int /*b2*/) const { |
555 |
|
|
if (this->enable_statistics) this->num_bv_tests++; |
556 |
|
|
return distance(this->tf1.getRotation(), this->tf1.getTranslation(), |
557 |
|
|
this->model2_bv, this->model1->getBV(b1).bv); |
558 |
|
|
} |
559 |
|
|
|
560 |
|
|
void leafComputeDistance(unsigned int b1, unsigned int b2) const { |
561 |
|
|
details::meshShapeDistanceOrientedNodeleafComputeDistance( |
562 |
|
|
b1, b2, this->model1, *(this->model2), this->vertices, |
563 |
|
|
this->tri_indices, this->tf1, this->tf2, this->nsolver, |
564 |
|
|
this->enable_statistics, this->num_leaf_tests, this->request, |
565 |
|
|
*(this->result)); |
566 |
|
|
} |
567 |
|
|
}; |
568 |
|
|
|
569 |
|
|
template <typename S> |
570 |
|
|
class MeshShapeDistanceTraversalNodekIOS |
571 |
|
|
: public MeshShapeDistanceTraversalNode<kIOS, S> { |
572 |
|
|
public: |
573 |
|
|
MeshShapeDistanceTraversalNodekIOS() |
574 |
|
|
: MeshShapeDistanceTraversalNode<kIOS, S>() {} |
575 |
|
|
|
576 |
|
|
void preprocess() { |
577 |
|
|
details::distancePreprocessOrientedNode( |
578 |
|
|
this->model1, this->vertices, this->tri_indices, 0, *(this->model2), |
579 |
|
|
this->tf1, this->tf2, this->nsolver, this->request, *(this->result)); |
580 |
|
|
} |
581 |
|
|
|
582 |
|
|
void postprocess() {} |
583 |
|
|
|
584 |
|
|
FCL_REAL BVDistanceLowerBound(unsigned int b1, unsigned int /*b2*/) const { |
585 |
|
|
if (this->enable_statistics) this->num_bv_tests++; |
586 |
|
|
return distance(this->tf1.getRotation(), this->tf1.getTranslation(), |
587 |
|
|
this->model2_bv, this->model1->getBV(b1).bv); |
588 |
|
|
} |
589 |
|
|
|
590 |
|
|
void leafComputeDistance(unsigned int b1, unsigned int b2) const { |
591 |
|
|
details::meshShapeDistanceOrientedNodeleafComputeDistance( |
592 |
|
|
b1, b2, this->model1, *(this->model2), this->vertices, |
593 |
|
|
this->tri_indices, this->tf1, this->tf2, this->nsolver, |
594 |
|
|
this->enable_statistics, this->num_leaf_tests, this->request, |
595 |
|
|
*(this->result)); |
596 |
|
|
} |
597 |
|
|
}; |
598 |
|
|
|
599 |
|
|
template <typename S> |
600 |
|
|
class MeshShapeDistanceTraversalNodeOBBRSS |
601 |
|
|
: public MeshShapeDistanceTraversalNode<OBBRSS, S> { |
602 |
|
|
public: |
603 |
|
200 |
MeshShapeDistanceTraversalNodeOBBRSS() |
604 |
|
200 |
: MeshShapeDistanceTraversalNode<OBBRSS, S>() {} |
605 |
|
|
|
606 |
|
200 |
void preprocess() { |
607 |
|
200 |
details::distancePreprocessOrientedNode( |
608 |
|
200 |
this->model1, this->vertices, this->tri_indices, 0, *(this->model2), |
609 |
|
200 |
this->tf1, this->tf2, this->nsolver, this->request, *(this->result)); |
610 |
|
|
} |
611 |
|
|
|
612 |
|
200 |
void postprocess() {} |
613 |
|
|
|
614 |
|
21584 |
FCL_REAL BVDistanceLowerBound(unsigned int b1, unsigned int /*b2*/) const { |
615 |
✗✓ |
21584 |
if (this->enable_statistics) this->num_bv_tests++; |
616 |
|
21584 |
return distance(this->tf1.getRotation(), this->tf1.getTranslation(), |
617 |
|
43168 |
this->model2_bv, this->model1->getBV(b1).bv); |
618 |
|
|
} |
619 |
|
|
|
620 |
|
2858 |
void leafComputeDistance(unsigned int b1, unsigned int b2) const { |
621 |
|
2858 |
details::meshShapeDistanceOrientedNodeleafComputeDistance( |
622 |
|
2858 |
b1, b2, this->model1, *(this->model2), this->vertices, |
623 |
|
2858 |
this->tri_indices, this->tf1, this->tf2, this->nsolver, |
624 |
|
2858 |
this->enable_statistics, this->num_leaf_tests, this->request, |
625 |
|
2858 |
*(this->result)); |
626 |
|
|
} |
627 |
|
|
}; |
628 |
|
|
|
629 |
|
|
/// @brief Traversal node for distance between shape and mesh |
630 |
|
|
template <typename S, typename BV> |
631 |
|
|
class ShapeMeshDistanceTraversalNode |
632 |
|
|
: public ShapeBVHDistanceTraversalNode<S, BV> { |
633 |
|
|
public: |
634 |
|
|
ShapeMeshDistanceTraversalNode() : ShapeBVHDistanceTraversalNode<S, BV>() { |
635 |
|
|
vertices = NULL; |
636 |
|
|
tri_indices = NULL; |
637 |
|
|
|
638 |
|
|
rel_err = 0; |
639 |
|
|
abs_err = 0; |
640 |
|
|
|
641 |
|
|
nsolver = NULL; |
642 |
|
|
} |
643 |
|
|
|
644 |
|
|
/// @brief Distance testing between leaves (one shape and one triangle) |
645 |
|
|
void leafComputeDistance(unsigned int /*b1*/, unsigned int b2) const { |
646 |
|
|
if (this->enable_statistics) this->num_leaf_tests++; |
647 |
|
|
|
648 |
|
|
const BVNode<BV>& node = this->model2->getBV(b2); |
649 |
|
|
|
650 |
|
|
int primitive_id = node.primitiveId(); |
651 |
|
|
|
652 |
|
|
const Triangle& tri_id = tri_indices[primitive_id]; |
653 |
|
|
|
654 |
|
|
const Vec3f& p1 = vertices[tri_id[0]]; |
655 |
|
|
const Vec3f& p2 = vertices[tri_id[1]]; |
656 |
|
|
const Vec3f& p3 = vertices[tri_id[2]]; |
657 |
|
|
|
658 |
|
|
FCL_REAL distance; |
659 |
|
|
Vec3f closest_p1, closest_p2, normal; |
660 |
|
|
nsolver->shapeTriangleInteraction(*(this->model1), this->tf1, p1, p2, p3, |
661 |
|
|
Transform3f(), distance, closest_p1, |
662 |
|
|
closest_p2, normal); |
663 |
|
|
|
664 |
|
|
this->result->update(distance, this->model1, this->model2, |
665 |
|
|
DistanceResult::NONE, primitive_id, closest_p1, |
666 |
|
|
closest_p2, normal); |
667 |
|
|
} |
668 |
|
|
|
669 |
|
|
/// @brief Whether the traversal process can stop early |
670 |
|
|
bool canStop(FCL_REAL c) const { |
671 |
|
|
if ((c >= this->result->min_distance - abs_err) && |
672 |
|
|
(c * (1 + rel_err) >= this->result->min_distance)) |
673 |
|
|
return true; |
674 |
|
|
return false; |
675 |
|
|
} |
676 |
|
|
|
677 |
|
|
Vec3f* vertices; |
678 |
|
|
Triangle* tri_indices; |
679 |
|
|
|
680 |
|
|
FCL_REAL rel_err; |
681 |
|
|
FCL_REAL abs_err; |
682 |
|
|
|
683 |
|
|
const GJKSolver* nsolver; |
684 |
|
|
}; |
685 |
|
|
|
686 |
|
|
/// @brief Traversal node for distance between shape and mesh, when mesh BVH is |
687 |
|
|
/// one of the oriented node (RSS, kIOS, OBBRSS) |
688 |
|
|
template <typename S> |
689 |
|
|
class ShapeMeshDistanceTraversalNodeRSS |
690 |
|
|
: public ShapeMeshDistanceTraversalNode<S, RSS> { |
691 |
|
|
public: |
692 |
|
|
ShapeMeshDistanceTraversalNodeRSS() |
693 |
|
|
: ShapeMeshDistanceTraversalNode<S, RSS>() {} |
694 |
|
|
|
695 |
|
|
void preprocess() { |
696 |
|
|
details::distancePreprocessOrientedNode( |
697 |
|
|
this->model2, this->vertices, this->tri_indices, 0, *(this->model1), |
698 |
|
|
this->tf2, this->tf1, this->nsolver, this->request, *(this->result)); |
699 |
|
|
} |
700 |
|
|
|
701 |
|
|
void postprocess() {} |
702 |
|
|
|
703 |
|
|
FCL_REAL BVDistanceLowerBound(unsigned int /*b1*/, unsigned int b2) const { |
704 |
|
|
if (this->enable_statistics) this->num_bv_tests++; |
705 |
|
|
return distance(this->tf2.getRotation(), this->tf2.getTranslation(), |
706 |
|
|
this->model1_bv, this->model2->getBV(b2).bv); |
707 |
|
|
} |
708 |
|
|
|
709 |
|
|
void leafComputeDistance(unsigned int b1, unsigned int b2) const { |
710 |
|
|
details::meshShapeDistanceOrientedNodeleafComputeDistance( |
711 |
|
|
b2, b1, this->model2, *(this->model1), this->vertices, |
712 |
|
|
this->tri_indices, this->tf2, this->tf1, this->nsolver, |
713 |
|
|
this->enable_statistics, this->num_leaf_tests, this->request, |
714 |
|
|
*(this->result)); |
715 |
|
|
} |
716 |
|
|
}; |
717 |
|
|
|
718 |
|
|
template <typename S> |
719 |
|
|
class ShapeMeshDistanceTraversalNodekIOS |
720 |
|
|
: public ShapeMeshDistanceTraversalNode<S, kIOS> { |
721 |
|
|
public: |
722 |
|
|
ShapeMeshDistanceTraversalNodekIOS() |
723 |
|
|
: ShapeMeshDistanceTraversalNode<S, kIOS>() {} |
724 |
|
|
|
725 |
|
|
void preprocess() { |
726 |
|
|
details::distancePreprocessOrientedNode( |
727 |
|
|
this->model2, this->vertices, this->tri_indices, 0, *(this->model1), |
728 |
|
|
this->tf2, this->tf1, this->nsolver, *(this->result)); |
729 |
|
|
} |
730 |
|
|
|
731 |
|
|
void postprocess() {} |
732 |
|
|
|
733 |
|
|
FCL_REAL BVDistanceLowerBound(unsigned int /*b1*/, unsigned int b2) const { |
734 |
|
|
if (this->enable_statistics) this->num_bv_tests++; |
735 |
|
|
return distance(this->tf2.getRotation(), this->tf2.getTranslation(), |
736 |
|
|
this->model1_bv, this->model2->getBV(b2).bv); |
737 |
|
|
} |
738 |
|
|
|
739 |
|
|
void leafComputeDistance(unsigned int b1, unsigned int b2) const { |
740 |
|
|
details::meshShapeDistanceOrientedNodeleafComputeDistance( |
741 |
|
|
b2, b1, this->model2, *(this->model1), this->vertices, |
742 |
|
|
this->tri_indices, this->tf2, this->tf1, this->nsolver, |
743 |
|
|
this->enable_statistics, this->num_leaf_tests, this->request, |
744 |
|
|
*(this->result)); |
745 |
|
|
} |
746 |
|
|
}; |
747 |
|
|
|
748 |
|
|
template <typename S> |
749 |
|
|
class ShapeMeshDistanceTraversalNodeOBBRSS |
750 |
|
|
: public ShapeMeshDistanceTraversalNode<S, OBBRSS> { |
751 |
|
|
public: |
752 |
|
|
ShapeMeshDistanceTraversalNodeOBBRSS() |
753 |
|
|
: ShapeMeshDistanceTraversalNode<S, OBBRSS>() {} |
754 |
|
|
|
755 |
|
|
void preprocess() { |
756 |
|
|
details::distancePreprocessOrientedNode( |
757 |
|
|
this->model2, this->vertices, this->tri_indices, 0, *(this->model1), |
758 |
|
|
this->tf2, this->tf1, this->nsolver, *(this->result)); |
759 |
|
|
} |
760 |
|
|
|
761 |
|
|
void postprocess() {} |
762 |
|
|
|
763 |
|
|
FCL_REAL BVDistanceLowerBound(unsigned int /*b1*/, unsigned int b2) const { |
764 |
|
|
if (this->enable_statistics) this->num_bv_tests++; |
765 |
|
|
return distance(this->tf2.getRotation(), this->tf2.getTranslation(), |
766 |
|
|
this->model1_bv, this->model2->getBV(b2).bv); |
767 |
|
|
} |
768 |
|
|
|
769 |
|
|
void leafComputeDistance(unsigned int b1, unsigned int b2) const { |
770 |
|
|
details::meshShapeDistanceOrientedNodeleafComputeDistance( |
771 |
|
|
b2, b1, this->model2, *(this->model1), this->vertices, |
772 |
|
|
this->tri_indices, this->tf2, this->tf1, this->nsolver, |
773 |
|
|
this->enable_statistics, this->num_leaf_tests, this->request, |
774 |
|
|
*(this->result)); |
775 |
|
|
} |
776 |
|
|
}; |
777 |
|
|
|
778 |
|
|
/// @} |
779 |
|
|
|
780 |
|
|
} // namespace fcl |
781 |
|
|
|
782 |
|
|
} // namespace hpp |
783 |
|
|
|
784 |
|
|
/// @endcond |
785 |
|
|
|
786 |
|
|
#endif |