GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
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 |
#include <hpp/fcl/narrowphase/gjk.h> |
||
39 |
#include <hpp/fcl/internal/intersect.h> |
||
40 |
#include <hpp/fcl/internal/tools.h> |
||
41 |
#include <hpp/fcl/shape/geometric_shapes_traits.h> |
||
42 |
|||
43 |
namespace hpp { |
||
44 |
namespace fcl { |
||
45 |
|||
46 |
namespace details { |
||
47 |
|||
48 |
189794971 |
void getShapeSupport(const TriangleP* triangle, const Vec3f& dir, |
|
49 |
Vec3f& support, int&, MinkowskiDiff::ShapeData*) { |
||
50 |
189794971 |
FCL_REAL dota = dir.dot(triangle->a); |
|
51 |
189794971 |
FCL_REAL dotb = dir.dot(triangle->b); |
|
52 |
189794971 |
FCL_REAL dotc = dir.dot(triangle->c); |
|
53 |
✓✓ | 189794971 |
if (dota > dotb) { |
54 |
✓✓ | 91199175 |
if (dotc > dota) |
55 |
32667413 |
support = triangle->c; |
|
56 |
else |
||
57 |
58531762 |
support = triangle->a; |
|
58 |
} else { |
||
59 |
✓✓ | 98595796 |
if (dotc > dotb) |
60 |
23103379 |
support = triangle->c; |
|
61 |
else |
||
62 |
75492417 |
support = triangle->b; |
|
63 |
} |
||
64 |
189794971 |
} |
|
65 |
|||
66 |
3840389 |
inline void getShapeSupport(const Box* box, const Vec3f& dir, Vec3f& support, |
|
67 |
int&, MinkowskiDiff::ShapeData*) { |
||
68 |
✓✗✓✗ ✓✗✓✓ |
3840389 |
const FCL_REAL inflate = (dir.array() == 0).any() ? 1.00000001 : 1.; |
69 |
✓✗ | 3840389 |
support.noalias() = |
70 |
✓✗✓✗ |
3840389 |
(dir.array() > 0) |
71 |
✓✗✓✗ ✓✗✓✗ |
7680778 |
.select(inflate * box->halfSide, -inflate * box->halfSide); |
72 |
3840389 |
} |
|
73 |
|||
74 |
171185 |
inline void getShapeSupport(const Sphere*, const Vec3f& /*dir*/, Vec3f& support, |
|
75 |
int&, MinkowskiDiff::ShapeData*) { |
||
76 |
171185 |
support.setZero(); |
|
77 |
171185 |
} |
|
78 |
|||
79 |
715318 |
inline void getShapeSupport(const Ellipsoid* ellipsoid, const Vec3f& dir, |
|
80 |
Vec3f& support, int&, MinkowskiDiff::ShapeData*) { |
||
81 |
✓✗✓✗ |
715318 |
FCL_REAL a2 = ellipsoid->radii[0] * ellipsoid->radii[0]; |
82 |
✓✗✓✗ |
715318 |
FCL_REAL b2 = ellipsoid->radii[1] * ellipsoid->radii[1]; |
83 |
✓✗✓✗ |
715318 |
FCL_REAL c2 = ellipsoid->radii[2] * ellipsoid->radii[2]; |
84 |
|||
85 |
✓✗✓✗ ✓✗✓✗ |
715318 |
Vec3f v(a2 * dir[0], b2 * dir[1], c2 * dir[2]); |
86 |
|||
87 |
✓✗ | 715318 |
FCL_REAL d = std::sqrt(v.dot(dir)); |
88 |
|||
89 |
✓✗✓✗ |
715318 |
support = v / d; |
90 |
715318 |
} |
|
91 |
|||
92 |
340705 |
inline void getShapeSupport(const Capsule* capsule, const Vec3f& dir, |
|
93 |
Vec3f& support, int&, MinkowskiDiff::ShapeData*) { |
||
94 |
✓✗ | 340705 |
support.head<2>().setZero(); |
95 |
✓✓ | 340705 |
if (dir[2] > 0) |
96 |
187795 |
support[2] = capsule->halfLength; |
|
97 |
else |
||
98 |
152910 |
support[2] = -capsule->halfLength; |
|
99 |
340705 |
} |
|
100 |
|||
101 |
11184 |
void getShapeSupport(const Cone* cone, const Vec3f& dir, Vec3f& support, int&, |
|
102 |
MinkowskiDiff::ShapeData*) { |
||
103 |
// The cone radius is, for -h < z < h, (h - z) * r / (2*h) |
||
104 |
static const FCL_REAL inflate = 1.00001; |
||
105 |
11184 |
FCL_REAL h = cone->halfLength; |
|
106 |
11184 |
FCL_REAL r = cone->radius; |
|
107 |
|||
108 |
✓✗✓✗ ✓✓ |
11184 |
if (dir.head<2>().isZero()) { |
109 |
✓✗✓✗ |
94 |
support.head<2>().setZero(); |
110 |
✓✗✓✓ |
94 |
if (dir[2] > 0) |
111 |
✓✗ | 36 |
support[2] = h; |
112 |
else |
||
113 |
✓✗ | 58 |
support[2] = -inflate * h; |
114 |
5153 |
return; |
|
115 |
} |
||
116 |
✓✗✓✗ ✓✗✓✗ |
11090 |
FCL_REAL zdist = dir[0] * dir[0] + dir[1] * dir[1]; |
117 |
✓✗✓✗ |
11090 |
FCL_REAL len = zdist + dir[2] * dir[2]; |
118 |
11090 |
zdist = std::sqrt(zdist); |
|
119 |
|||
120 |
✓✗✓✓ |
11090 |
if (dir[2] <= 0) { |
121 |
5059 |
FCL_REAL rad = r / zdist; |
|
122 |
✓✗✓✗ ✓✗✓✗ |
5059 |
support.head<2>() = rad * dir.head<2>(); |
123 |
✓✗ | 5059 |
support[2] = -h; |
124 |
5059 |
return; |
|
125 |
} |
||
126 |
|||
127 |
6031 |
len = std::sqrt(len); |
|
128 |
6031 |
FCL_REAL sin_a = r / std::sqrt(r * r + 4 * h * h); |
|
129 |
|||
130 |
✓✗✓✓ |
6031 |
if (dir[2] > len * sin_a) |
131 |
✓✗✓✗ ✓✗ |
1960 |
support << 0, 0, h; |
132 |
else { |
||
133 |
4071 |
FCL_REAL rad = r / zdist; |
|
134 |
✓✗✓✗ ✓✗✓✗ |
4071 |
support.head<2>() = rad * dir.head<2>(); |
135 |
✓✗ | 4071 |
support[2] = -h; |
136 |
} |
||
137 |
} |
||
138 |
|||
139 |
1797686 |
void getShapeSupport(const Cylinder* cylinder, const Vec3f& dir, Vec3f& support, |
|
140 |
int&, MinkowskiDiff::ShapeData*) { |
||
141 |
// The inflation makes the object look strictly convex to GJK and EPA. This |
||
142 |
// helps solving particular cases (e.g. a cylinder with itself at the same |
||
143 |
// position...) |
||
144 |
static const FCL_REAL inflate = 1.00001; |
||
145 |
1797686 |
FCL_REAL half_h = cylinder->halfLength; |
|
146 |
1797686 |
FCL_REAL r = cylinder->radius; |
|
147 |
|||
148 |
✓✗✓✗ ✓✗✓✓ |
1797686 |
if (dir.head<2>() == Eigen::Matrix<FCL_REAL, 2, 1>::Zero()) half_h *= inflate; |
149 |
|||
150 |
✓✗✓✓ |
1797686 |
if (dir[2] > 0) |
151 |
✓✗ | 741107 |
support[2] = half_h; |
152 |
✓✗✓✓ |
1056579 |
else if (dir[2] < 0) |
153 |
✓✗ | 745468 |
support[2] = -half_h; |
154 |
else { |
||
155 |
✓✗ | 311111 |
support[2] = 0; |
156 |
311111 |
r *= inflate; |
|
157 |
} |
||
158 |
✓✗✓✗ ✓✗✓✓ |
1797686 |
if (dir.head<2>() == Eigen::Matrix<FCL_REAL, 2, 1>::Zero()) |
159 |
✓✗✓✗ |
350 |
support.head<2>().setZero(); |
160 |
else |
||
161 |
✓✗✓✗ ✓✗✓✗ ✓✗ |
1797336 |
support.head<2>() = dir.head<2>().normalized() * r; |
162 |
✓✗✓✗ ✓✗✓✗ ✗✓ |
1797686 |
assert(fabs(support[0] * dir[1] - support[1] * dir[0]) < |
163 |
sqrt(std::numeric_limits<FCL_REAL>::epsilon())); |
||
164 |
1797686 |
} |
|
165 |
|||
166 |
struct SmallConvex : ShapeBase {}; |
||
167 |
struct LargeConvex : ShapeBase {}; |
||
168 |
|||
169 |
void getShapeSupportLog(const ConvexBase* convex, const Vec3f& dir, |
||
170 |
Vec3f& support, int& hint, |
||
171 |
MinkowskiDiff::ShapeData* data) { |
||
172 |
assert(data != NULL); |
||
173 |
|||
174 |
const Vec3f* pts = convex->points; |
||
175 |
const ConvexBase::Neighbors* nn = convex->neighbors; |
||
176 |
|||
177 |
if (hint < 0 || hint >= (int)convex->num_points) hint = 0; |
||
178 |
FCL_REAL maxdot = pts[hint].dot(dir); |
||
179 |
std::vector<int8_t>& visited = data->visited; |
||
180 |
visited.assign(convex->num_points, false); |
||
181 |
visited[static_cast<std::size_t>(hint)] = true; |
||
182 |
// when the first face is orthogonal to dir, all the dot products will be |
||
183 |
// equal. Yet, the neighbors must be visited. |
||
184 |
bool found = true, loose_check = true; |
||
185 |
while (found) { |
||
186 |
const ConvexBase::Neighbors& n = nn[hint]; |
||
187 |
found = false; |
||
188 |
for (int in = 0; in < n.count(); ++in) { |
||
189 |
const unsigned int ip = n[in]; |
||
190 |
if (visited[ip]) continue; |
||
191 |
visited[ip] = true; |
||
192 |
const FCL_REAL dot = pts[ip].dot(dir); |
||
193 |
bool better = false; |
||
194 |
if (dot > maxdot) { |
||
195 |
better = true; |
||
196 |
loose_check = false; |
||
197 |
} else if (loose_check && dot == maxdot) |
||
198 |
better = true; |
||
199 |
if (better) { |
||
200 |
maxdot = dot; |
||
201 |
hint = static_cast<int>(ip); |
||
202 |
found = true; |
||
203 |
} |
||
204 |
} |
||
205 |
} |
||
206 |
|||
207 |
support = pts[hint]; |
||
208 |
} |
||
209 |
|||
210 |
673294 |
void getShapeSupportLinear(const ConvexBase* convex, const Vec3f& dir, |
|
211 |
Vec3f& support, int& hint, |
||
212 |
MinkowskiDiff::ShapeData*) { |
||
213 |
673294 |
const Vec3f* pts = convex->points; |
|
214 |
|||
215 |
673294 |
hint = 0; |
|
216 |
673294 |
FCL_REAL maxdot = pts[0].dot(dir); |
|
217 |
✓✓ | 7329176 |
for (int i = 1; i < (int)convex->num_points; ++i) { |
218 |
6655882 |
FCL_REAL dot = pts[i].dot(dir); |
|
219 |
✓✓ | 6655882 |
if (dot > maxdot) { |
220 |
1382198 |
maxdot = dot; |
|
221 |
1382198 |
hint = i; |
|
222 |
} |
||
223 |
} |
||
224 |
673294 |
support = pts[hint]; |
|
225 |
673294 |
} |
|
226 |
|||
227 |
4 |
void getShapeSupport(const ConvexBase* convex, const Vec3f& dir, Vec3f& support, |
|
228 |
int& hint, MinkowskiDiff::ShapeData*) { |
||
229 |
// TODO add benchmark to set a proper value for switching between linear and |
||
230 |
// logarithmic. |
||
231 |
✗✓ | 4 |
if (convex->num_points > 32) { |
232 |
MinkowskiDiff::ShapeData data; |
||
233 |
getShapeSupportLog(convex, dir, support, hint, &data); |
||
234 |
} else |
||
235 |
4 |
getShapeSupportLinear(convex, dir, support, hint, NULL); |
|
236 |
4 |
} |
|
237 |
|||
238 |
673290 |
inline void getShapeSupport(const SmallConvex* convex, const Vec3f& dir, |
|
239 |
Vec3f& support, int& hint, |
||
240 |
MinkowskiDiff::ShapeData* data) { |
||
241 |
673290 |
getShapeSupportLinear(reinterpret_cast<const ConvexBase*>(convex), dir, |
|
242 |
support, hint, data); |
||
243 |
673290 |
} |
|
244 |
|||
245 |
inline void getShapeSupport(const LargeConvex* convex, const Vec3f& dir, |
||
246 |
Vec3f& support, int& hint, |
||
247 |
MinkowskiDiff::ShapeData* data) { |
||
248 |
getShapeSupportLog(reinterpret_cast<const ConvexBase*>(convex), dir, support, |
||
249 |
hint, data); |
||
250 |
} |
||
251 |
|||
252 |
#define CALL_GET_SHAPE_SUPPORT(ShapeType) \ |
||
253 |
getShapeSupport( \ |
||
254 |
static_cast<const ShapeType*>(shape), \ |
||
255 |
(shape_traits<ShapeType>::NeedNormalizedDir && !dirIsNormalized) \ |
||
256 |
? dir.normalized() \ |
||
257 |
: dir, \ |
||
258 |
support, hint, NULL) |
||
259 |
|||
260 |
4 |
Vec3f getSupport(const ShapeBase* shape, const Vec3f& dir, bool dirIsNormalized, |
|
261 |
int& hint) { |
||
262 |
4 |
Vec3f support; |
|
263 |
✗✗✗✗ ✗✗✗✓ ✗ |
4 |
switch (shape->getNodeType()) { |
264 |
case GEOM_TRIANGLE: |
||
265 |
CALL_GET_SHAPE_SUPPORT(TriangleP); |
||
266 |
break; |
||
267 |
case GEOM_BOX: |
||
268 |
CALL_GET_SHAPE_SUPPORT(Box); |
||
269 |
break; |
||
270 |
case GEOM_SPHERE: |
||
271 |
CALL_GET_SHAPE_SUPPORT(Sphere); |
||
272 |
break; |
||
273 |
case GEOM_ELLIPSOID: |
||
274 |
CALL_GET_SHAPE_SUPPORT(Ellipsoid); |
||
275 |
break; |
||
276 |
case GEOM_CAPSULE: |
||
277 |
CALL_GET_SHAPE_SUPPORT(Capsule); |
||
278 |
break; |
||
279 |
case GEOM_CONE: |
||
280 |
CALL_GET_SHAPE_SUPPORT(Cone); |
||
281 |
break; |
||
282 |
case GEOM_CYLINDER: |
||
283 |
CALL_GET_SHAPE_SUPPORT(Cylinder); |
||
284 |
break; |
||
285 |
4 |
case GEOM_CONVEX: |
|
286 |
✓✗ | 4 |
CALL_GET_SHAPE_SUPPORT(ConvexBase); |
287 |
4 |
break; |
|
288 |
case GEOM_PLANE: |
||
289 |
case GEOM_HALFSPACE: |
||
290 |
default: |
||
291 |
support.setZero(); |
||
292 |
; // nothing |
||
293 |
} |
||
294 |
|||
295 |
4 |
return support; |
|
296 |
} |
||
297 |
|||
298 |
#undef CALL_GET_SHAPE_SUPPORT |
||
299 |
|||
300 |
template <typename Shape0, typename Shape1, bool TransformIsIdentity> |
||
301 |
197344728 |
void getSupportTpl(const Shape0* s0, const Shape1* s1, const Matrix3f& oR1, |
|
302 |
const Vec3f& ot1, const Vec3f& dir, Vec3f& support0, |
||
303 |
Vec3f& support1, support_func_guess_t& hint, |
||
304 |
MinkowskiDiff::ShapeData data[2]) { |
||
305 |
197344728 |
getShapeSupport(s0, dir, support0, hint[0], &(data[0])); |
|
306 |
if (TransformIsIdentity) |
||
307 |
✓✗✓✗ |
189811266 |
getShapeSupport(s1, -dir, support1, hint[1], &(data[1])); |
308 |
else { |
||
309 |
✓✗✓✗ ✓✗✓✗ |
7533462 |
getShapeSupport(s1, -oR1.transpose() * dir, support1, hint[1], &(data[1])); |
310 |
✓✗✓✗ |
7533462 |
support1 = oR1 * support1 + ot1; |
311 |
} |
||
312 |
} |
||
313 |
|||
314 |
template <typename Shape0, typename Shape1, bool TransformIsIdentity> |
||
315 |
197344728 |
void getSupportFuncTpl(const MinkowskiDiff& md, const Vec3f& dir, |
|
316 |
bool dirIsNormalized, Vec3f& support0, Vec3f& support1, |
||
317 |
support_func_guess_t& hint, |
||
318 |
MinkowskiDiff::ShapeData data[2]) { |
||
319 |
enum { |
||
320 |
NeedNormalizedDir = bool((bool)shape_traits<Shape0>::NeedNormalizedDir || |
||
321 |
(bool)shape_traits<Shape1>::NeedNormalizedDir) |
||
322 |
}; |
||
323 |
#ifndef NDEBUG |
||
324 |
// Need normalized direction and direction is normalized |
||
325 |
✓✓✗✓ |
1183916 |
assert(!NeedNormalizedDir || !dirIsNormalized || |
326 |
fabs(dir.squaredNorm() - 1) < 1e-6); |
||
327 |
// Need normalized direction but direction is not normalized. |
||
328 |
✓✓✓✗ ✓✗✗✓ |
1183916 |
assert(!NeedNormalizedDir || dirIsNormalized || |
329 |
fabs(dir.normalized().squaredNorm() - 1) < 1e-6); |
||
330 |
// Don't need normalized direction. Check that dir is not zero. |
||
331 |
✓✗✗✓ |
196160812 |
assert(NeedNormalizedDir || dir.cwiseAbs().maxCoeff() >= 1e-6); |
332 |
#endif |
||
333 |
197344728 |
getSupportTpl<Shape0, Shape1, TransformIsIdentity>( |
|
334 |
197344728 |
static_cast<const Shape0*>(md.shapes[0]), |
|
335 |
✓✗ | 197344728 |
static_cast<const Shape1*>(md.shapes[1]), md.oR1, md.ot1, |
336 |
✓✓ | 197344728 |
(NeedNormalizedDir && !dirIsNormalized) ? dir.normalized() : dir, |
337 |
support0, support1, hint, data); |
||
338 |
} |
||
339 |
|||
340 |
template <typename Shape0> |
||
341 |
60030946 |
MinkowskiDiff::GetSupportFunction makeGetSupportFunction1( |
|
342 |
const ShapeBase* s1, bool identity, Eigen::Array<FCL_REAL, 1, 2>& inflation, |
||
343 |
int linear_log_convex_threshold) { |
||
344 |
60030946 |
inflation[1] = 0; |
|
345 |
✓✓✓✓ ✓✓✓✓ ✗ |
60030946 |
switch (s1->getNodeType()) { |
346 |
58412958 |
case GEOM_TRIANGLE: |
|
347 |
✓✓ | 58412958 |
if (identity) |
348 |
58412946 |
return getSupportFuncTpl<Shape0, TriangleP, true>; |
|
349 |
else |
||
350 |
12 |
return getSupportFuncTpl<Shape0, TriangleP, false>; |
|
351 |
1132914 |
case GEOM_BOX: |
|
352 |
✓✓ | 1132914 |
if (identity) |
353 |
36 |
return getSupportFuncTpl<Shape0, Box, true>; |
|
354 |
else |
||
355 |
1132878 |
return getSupportFuncTpl<Shape0, Box, false>; |
|
356 |
111354 |
case GEOM_SPHERE: |
|
357 |
111354 |
inflation[1] = static_cast<const Sphere*>(s1)->radius; |
|
358 |
✗✓ | 111354 |
if (identity) |
359 |
return getSupportFuncTpl<Shape0, Sphere, true>; |
||
360 |
else |
||
361 |
111354 |
return getSupportFuncTpl<Shape0, Sphere, false>; |
|
362 |
4002 |
case GEOM_ELLIPSOID: |
|
363 |
✓✓ | 4002 |
if (identity) |
364 |
2 |
return getSupportFuncTpl<Shape0, Ellipsoid, true>; |
|
365 |
else |
||
366 |
4000 |
return getSupportFuncTpl<Shape0, Ellipsoid, false>; |
|
367 |
16002 |
case GEOM_CAPSULE: |
|
368 |
16002 |
inflation[1] = static_cast<const Capsule*>(s1)->radius; |
|
369 |
✗✓ | 16002 |
if (identity) |
370 |
return getSupportFuncTpl<Shape0, Capsule, true>; |
||
371 |
else |
||
372 |
16002 |
return getSupportFuncTpl<Shape0, Capsule, false>; |
|
373 |
2116 |
case GEOM_CONE: |
|
374 |
✓✓ | 2116 |
if (identity) |
375 |
28 |
return getSupportFuncTpl<Shape0, Cone, true>; |
|
376 |
else |
||
377 |
2088 |
return getSupportFuncTpl<Shape0, Cone, false>; |
|
378 |
317590 |
case GEOM_CYLINDER: |
|
379 |
✓✓ | 317590 |
if (identity) |
380 |
24 |
return getSupportFuncTpl<Shape0, Cylinder, true>; |
|
381 |
else |
||
382 |
317566 |
return getSupportFuncTpl<Shape0, Cylinder, false>; |
|
383 |
34010 |
case GEOM_CONVEX: |
|
384 |
✗✓ | 34010 |
if ((int)static_cast<const ConvexBase*>(s1)->num_points > |
385 |
linear_log_convex_threshold) { |
||
386 |
if (identity) |
||
387 |
return getSupportFuncTpl<Shape0, LargeConvex, true>; |
||
388 |
else |
||
389 |
return getSupportFuncTpl<Shape0, LargeConvex, false>; |
||
390 |
} else { |
||
391 |
✓✓ | 34010 |
if (identity) |
392 |
6 |
return getSupportFuncTpl<Shape0, SmallConvex, true>; |
|
393 |
else |
||
394 |
34004 |
return getSupportFuncTpl<Shape0, SmallConvex, false>; |
|
395 |
} |
||
396 |
default: |
||
397 |
throw std::logic_error("Unsupported geometric shape"); |
||
398 |
} |
||
399 |
} |
||
400 |
|||
401 |
30015473 |
MinkowskiDiff::GetSupportFunction makeGetSupportFunction0( |
|
402 |
const ShapeBase* s0, const ShapeBase* s1, bool identity, |
||
403 |
Eigen::Array<FCL_REAL, 1, 2>& inflation, int linear_log_convex_threshold) { |
||
404 |
30015473 |
inflation[0] = 0; |
|
405 |
✓✓✓✓ ✓✓✓✓ ✗ |
30015473 |
switch (s0->getNodeType()) { |
406 |
29203802 |
case GEOM_TRIANGLE: |
|
407 |
29203802 |
return makeGetSupportFunction1<TriangleP>(s1, identity, inflation, |
|
408 |
29203802 |
linear_log_convex_threshold); |
|
409 |
break; |
||
410 |
419581 |
case GEOM_BOX: |
|
411 |
419581 |
return makeGetSupportFunction1<Box>(s1, identity, inflation, |
|
412 |
419581 |
linear_log_convex_threshold); |
|
413 |
break; |
||
414 |
17 |
case GEOM_SPHERE: |
|
415 |
17 |
inflation[0] = static_cast<const Sphere*>(s0)->radius; |
|
416 |
17 |
return makeGetSupportFunction1<Sphere>(s1, identity, inflation, |
|
417 |
17 |
linear_log_convex_threshold); |
|
418 |
break; |
||
419 |
14002 |
case GEOM_ELLIPSOID: |
|
420 |
14002 |
return makeGetSupportFunction1<Ellipsoid>(s1, identity, inflation, |
|
421 |
14002 |
linear_log_convex_threshold); |
|
422 |
break; |
||
423 |
7034 |
case GEOM_CAPSULE: |
|
424 |
7034 |
inflation[0] = static_cast<const Capsule*>(s0)->radius; |
|
425 |
7034 |
return makeGetSupportFunction1<Capsule>(s1, identity, inflation, |
|
426 |
7034 |
linear_log_convex_threshold); |
|
427 |
break; |
||
428 |
52 |
case GEOM_CONE: |
|
429 |
52 |
return makeGetSupportFunction1<Cone>(s1, identity, inflation, |
|
430 |
52 |
linear_log_convex_threshold); |
|
431 |
break; |
||
432 |
310319 |
case GEOM_CYLINDER: |
|
433 |
310319 |
return makeGetSupportFunction1<Cylinder>(s1, identity, inflation, |
|
434 |
310319 |
linear_log_convex_threshold); |
|
435 |
break; |
||
436 |
60666 |
case GEOM_CONVEX: |
|
437 |
✗✓ | 60666 |
if ((int)static_cast<const ConvexBase*>(s0)->num_points > |
438 |
linear_log_convex_threshold) |
||
439 |
return makeGetSupportFunction1<LargeConvex>( |
||
440 |
s1, identity, inflation, linear_log_convex_threshold); |
||
441 |
else |
||
442 |
60666 |
return makeGetSupportFunction1<SmallConvex>( |
|
443 |
60666 |
s1, identity, inflation, linear_log_convex_threshold); |
|
444 |
break; |
||
445 |
default: |
||
446 |
throw std::logic_error("Unsupported geometric shape"); |
||
447 |
} |
||
448 |
} |
||
449 |
|||
450 |
30076139 |
bool getNormalizeSupportDirection(const ShapeBase* shape) { |
|
451 |
✓✓✓✓ ✓✓✓✓ ✗ |
30076139 |
switch (shape->getNodeType()) { |
452 |
29203802 |
case GEOM_TRIANGLE: |
|
453 |
29203802 |
return (bool)shape_traits<TriangleP>::NeedNesterovNormalizeHeuristic; |
|
454 |
break; |
||
455 |
419581 |
case GEOM_BOX: |
|
456 |
419581 |
return (bool)shape_traits<Box>::NeedNesterovNormalizeHeuristic; |
|
457 |
break; |
||
458 |
55678 |
case GEOM_SPHERE: |
|
459 |
55678 |
return (bool)shape_traits<Sphere>::NeedNesterovNormalizeHeuristic; |
|
460 |
break; |
||
461 |
14002 |
case GEOM_ELLIPSOID: |
|
462 |
14002 |
return (bool)shape_traits<Ellipsoid>::NeedNesterovNormalizeHeuristic; |
|
463 |
break; |
||
464 |
7034 |
case GEOM_CAPSULE: |
|
465 |
7034 |
return (bool)shape_traits<Capsule>::NeedNesterovNormalizeHeuristic; |
|
466 |
break; |
||
467 |
52 |
case GEOM_CONE: |
|
468 |
52 |
return (bool)shape_traits<Cone>::NeedNesterovNormalizeHeuristic; |
|
469 |
break; |
||
470 |
310319 |
case GEOM_CYLINDER: |
|
471 |
310319 |
return (bool)shape_traits<Cylinder>::NeedNesterovNormalizeHeuristic; |
|
472 |
break; |
||
473 |
65671 |
case GEOM_CONVEX: |
|
474 |
65671 |
return (bool)shape_traits<ConvexBase>::NeedNesterovNormalizeHeuristic; |
|
475 |
break; |
||
476 |
default: |
||
477 |
throw std::logic_error("Unsupported geometric shape"); |
||
478 |
} |
||
479 |
} |
||
480 |
|||
481 |
30015473 |
void getNormalizeSupportDirectionFromShapes(const ShapeBase* shape0, |
|
482 |
const ShapeBase* shape1, |
||
483 |
bool& normalize_support_direction) { |
||
484 |
✓✓ | 30076139 |
normalize_support_direction = getNormalizeSupportDirection(shape0) && |
485 |
✓✓ | 60666 |
getNormalizeSupportDirection(shape1); |
486 |
30015473 |
} |
|
487 |
|||
488 |
808997 |
void MinkowskiDiff::set(const ShapeBase* shape0, const ShapeBase* shape1, |
|
489 |
const Transform3f& tf0, const Transform3f& tf1) { |
||
490 |
808997 |
shapes[0] = shape0; |
|
491 |
808997 |
shapes[1] = shape1; |
|
492 |
808997 |
getNormalizeSupportDirectionFromShapes(shape0, shape1, |
|
493 |
808997 |
normalize_support_direction); |
|
494 |
|||
495 |
✓✗✓✗ ✓✗ |
808997 |
oR1.noalias() = tf0.getRotation().transpose() * tf1.getRotation(); |
496 |
✓✗✓✗ ✓✗ |
808997 |
ot1.noalias() = tf0.getRotation().transpose() * |
497 |
✓✗ | 1617994 |
(tf1.getTranslation() - tf0.getTranslation()); |
498 |
|||
499 |
✓✗✓✓ ✓✗✓✓ |
808997 |
bool identity = (oR1.isIdentity() && ot1.isZero()); |
500 |
|||
501 |
808997 |
getSupportFunc = makeGetSupportFunction0(shape0, shape1, identity, inflation, |
|
502 |
linear_log_convex_threshold); |
||
503 |
808997 |
} |
|
504 |
|||
505 |
29206476 |
void MinkowskiDiff::set(const ShapeBase* shape0, const ShapeBase* shape1) { |
|
506 |
29206476 |
shapes[0] = shape0; |
|
507 |
29206476 |
shapes[1] = shape1; |
|
508 |
29206476 |
getNormalizeSupportDirectionFromShapes(shape0, shape1, |
|
509 |
29206476 |
normalize_support_direction); |
|
510 |
|||
511 |
29206476 |
oR1.setIdentity(); |
|
512 |
29206476 |
ot1.setZero(); |
|
513 |
|||
514 |
29206476 |
getSupportFunc = makeGetSupportFunction0(shape0, shape1, true, inflation, |
|
515 |
linear_log_convex_threshold); |
||
516 |
29206476 |
} |
|
517 |
|||
518 |
29982542 |
void GJK::initialize() { |
|
519 |
29982542 |
nfree = 0; |
|
520 |
29982542 |
status = Failed; |
|
521 |
29982542 |
distance_upper_bound = (std::numeric_limits<FCL_REAL>::max)(); |
|
522 |
29982542 |
simplex = NULL; |
|
523 |
29982542 |
gjk_variant = GJKVariant::DefaultGJK; |
|
524 |
29982542 |
convergence_criterion = GJKConvergenceCriterion::VDB; |
|
525 |
29982542 |
convergence_criterion_type = GJKConvergenceCriterionType::Relative; |
|
526 |
29982542 |
} |
|
527 |
|||
528 |
6 |
Vec3f GJK::getGuessFromSimplex() const { return ray; } |
|
529 |
|||
530 |
namespace details { |
||
531 |
|||
532 |
29978468 |
bool getClosestPoints(const GJK::Simplex& simplex, Vec3f& w0, Vec3f& w1) { |
|
533 |
29978468 |
GJK::SimplexV* const* vs = simplex.vertex; |
|
534 |
|||
535 |
✓✓ | 68244312 |
for (GJK::vertex_id_t i = 0; i < simplex.rank; ++i) { |
536 |
✓✗✓✗ ✗✓ |
38265844 |
assert(vs[i]->w.isApprox(vs[i]->w0 - vs[i]->w1)); |
537 |
} |
||
538 |
|||
539 |
29978468 |
Project::ProjectResult projection; |
|
540 |
✓✓✓✓ ✗ |
29978468 |
switch (simplex.rank) { |
541 |
22102257 |
case 1: |
|
542 |
✓✗ | 22102257 |
w0 = vs[0]->w0; |
543 |
✓✗ | 22102257 |
w1 = vs[0]->w1; |
544 |
22102257 |
return true; |
|
545 |
7486073 |
case 2: { |
|
546 |
✓✗✓✗ ✓✗ |
7486073 |
const Vec3f &a = vs[0]->w, a0 = vs[0]->w0, a1 = vs[0]->w1, b = vs[1]->w, |
547 |
✓✗✓✗ |
7486073 |
b0 = vs[1]->w0, b1 = vs[1]->w1; |
548 |
FCL_REAL la, lb; |
||
549 |
✓✗✓✗ |
7486073 |
Vec3f N(b - a); |
550 |
✓✗✓✗ |
7486073 |
la = N.dot(-a); |
551 |
✗✓ | 7486073 |
if (la <= 0) { |
552 |
assert(false); |
||
553 |
w0 = a0; |
||
554 |
w1 = a1; |
||
555 |
} else { |
||
556 |
✓✗ | 7486073 |
lb = N.squaredNorm(); |
557 |
✗✓ | 7486073 |
if (la > lb) { |
558 |
assert(false); |
||
559 |
w0 = b0; |
||
560 |
w1 = b1; |
||
561 |
} else { |
||
562 |
7486073 |
lb = la / lb; |
|
563 |
7486073 |
la = 1 - lb; |
|
564 |
✓✗✓✗ ✓✗✓✗ |
7486073 |
w0 = la * a0 + lb * b0; |
565 |
✓✗✓✗ ✓✗✓✗ |
7486073 |
w1 = la * a1 + lb * b1; |
566 |
} |
||
567 |
} |
||
568 |
} |
||
569 |
7486073 |
return true; |
|
570 |
369111 |
case 3: |
|
571 |
// TODO avoid the reprojection |
||
572 |
✓✗ | 369111 |
projection = Project::projectTriangleOrigin(vs[0]->w, vs[1]->w, vs[2]->w); |
573 |
369111 |
break; |
|
574 |
21027 |
case 4: // We are in collision. |
|
575 |
42054 |
projection = Project::projectTetrahedraOrigin(vs[0]->w, vs[1]->w, |
|
576 |
✓✗ | 21027 |
vs[2]->w, vs[3]->w); |
577 |
21027 |
break; |
|
578 |
default: |
||
579 |
throw std::logic_error("The simplex rank must be in [ 1, 4 ]"); |
||
580 |
} |
||
581 |
✓✗ | 390138 |
w0.setZero(); |
582 |
✓✗ | 390138 |
w1.setZero(); |
583 |
✓✓ | 1581579 |
for (GJK::vertex_id_t i = 0; i < simplex.rank; ++i) { |
584 |
✓✗✓✗ |
1191441 |
w0 += projection.parameterization[i] * vs[i]->w0; |
585 |
✓✗✓✗ |
1191441 |
w1 += projection.parameterization[i] * vs[i]->w1; |
586 |
} |
||
587 |
390138 |
return true; |
|
588 |
} |
||
589 |
|||
590 |
/// Inflate the points |
||
591 |
template <bool Separated> |
||
592 |
59956936 |
void inflate(const MinkowskiDiff& shape, Vec3f& w0, Vec3f& w1) { |
|
593 |
59956936 |
const Eigen::Array<FCL_REAL, 1, 2>& I(shape.inflation); |
|
594 |
✓✗✓✗ |
59956936 |
Eigen::Array<bool, 1, 2> inflate(I > 0); |
595 |
✓✗✓✓ |
59956936 |
if (!inflate.any()) return; |
596 |
✓✗✓✗ |
111426 |
Vec3f w(w0 - w1); |
597 |
✓✗ | 111426 |
FCL_REAL n2 = w.squaredNorm(); |
598 |
// TODO should be use a threshold (Eigen::NumTraits<FCL_REAL>::epsilon()) ? |
||
599 |
✗✓ | 111426 |
if (n2 == 0.) { |
600 |
if (inflate[0]) w0[0] += I[0] * (Separated ? -1 : 1); |
||
601 |
if (inflate[1]) w1[0] += I[1] * (Separated ? 1 : -1); |
||
602 |
return; |
||
603 |
} |
||
604 |
|||
605 |
✓✗ | 111426 |
w /= std::sqrt(n2); |
606 |
if (Separated) { |
||
607 |
✓✗✓✓ ✓✗✓✗ ✓✗ |
111422 |
if (inflate[0]) w0 -= I[0] * w; |
608 |
✓✗✓✓ ✓✗✓✗ ✓✗ |
111422 |
if (inflate[1]) w1 += I[1] * w; |
609 |
} else { |
||
610 |
✓✗✓✗ ✓✗✓✗ ✓✗ |
4 |
if (inflate[0]) w0 += I[0] * w; |
611 |
✓✗✗✓ ✗✗✗✗ ✗✗ |
4 |
if (inflate[1]) w1 -= I[1] * w; |
612 |
} |
||
613 |
} |
||
614 |
|||
615 |
} // namespace details |
||
616 |
|||
617 |
29977904 |
bool GJK::getClosestPoints(const MinkowskiDiff& shape, Vec3f& w0, Vec3f& w1) { |
|
618 |
29977904 |
bool res = details::getClosestPoints(*simplex, w0, w1); |
|
619 |
✗✓ | 29977904 |
if (!res) return false; |
620 |
29977904 |
details::inflate<true>(shape, w0, w1); |
|
621 |
29977904 |
return true; |
|
622 |
} |
||
623 |
|||
624 |
30118472 |
GJK::Status GJK::evaluate(const MinkowskiDiff& shape_, const Vec3f& guess, |
|
625 |
const support_func_guess_t& supportHint) { |
||
626 |
30118472 |
FCL_REAL alpha = 0; |
|
627 |
30118472 |
iterations = 0; |
|
628 |
✓✗ | 30118472 |
const FCL_REAL inflation = shape_.inflation.sum(); |
629 |
30118472 |
const FCL_REAL upper_bound = distance_upper_bound + inflation; |
|
630 |
|||
631 |
30118472 |
free_v[0] = &store_v[0]; |
|
632 |
30118472 |
free_v[1] = &store_v[1]; |
|
633 |
30118472 |
free_v[2] = &store_v[2]; |
|
634 |
30118472 |
free_v[3] = &store_v[3]; |
|
635 |
|||
636 |
30118472 |
nfree = 4; |
|
637 |
30118472 |
current = 0; |
|
638 |
30118472 |
status = Valid; |
|
639 |
30118472 |
shape = &shape_; |
|
640 |
30118472 |
distance = 0.0; |
|
641 |
30118472 |
simplices[0].rank = 0; |
|
642 |
✓✗ | 30118472 |
support_hint = supportHint; |
643 |
|||
644 |
✓✗ | 30118472 |
FCL_REAL rl = guess.norm(); |
645 |
✓✓ | 30118472 |
if (rl < tolerance) { |
646 |
✓✗ | 2 |
ray = Vec3f(-1, 0, 0); |
647 |
2 |
rl = 1; |
|
648 |
} else |
||
649 |
✓✗ | 30118470 |
ray = guess; |
650 |
|||
651 |
// Momentum |
||
652 |
30118472 |
GJKVariant current_gjk_variant = gjk_variant; |
|
653 |
✓✗ | 30118472 |
Vec3f w = ray; |
654 |
✓✗ | 30118472 |
Vec3f dir = ray; |
655 |
✓✗ | 30118472 |
Vec3f y; |
656 |
FCL_REAL momentum; |
||
657 |
30118472 |
bool normalize_support_direction = shape->normalize_support_direction; |
|
658 |
68547499 |
do { |
|
659 |
98665971 |
vertex_id_t next = (vertex_id_t)(1 - current); |
|
660 |
98665971 |
Simplex& curr_simplex = simplices[current]; |
|
661 |
98665971 |
Simplex& next_simplex = simplices[next]; |
|
662 |
|||
663 |
// check A: when origin is near the existing simplex, stop |
||
664 |
// TODO this is an early stop which may cause the following issue. |
||
665 |
// - EPA will not run correctly because it starts with a tetrahedron which |
||
666 |
// does not include the origin. Note that, at this stage, we do not know |
||
667 |
// whether a tetrahedron including the origin exists. |
||
668 |
✓✓ | 98665971 |
if (rl < tolerance) // mean origin is near the face of original simplex, |
669 |
// return touch |
||
670 |
{ |
||
671 |
✗✓ | 21 |
assert(rl > 0); |
672 |
21 |
status = Inside; |
|
673 |
21 |
distance = -inflation; // should we take rl into account ? |
|
674 |
30118472 |
break; |
|
675 |
} |
||
676 |
|||
677 |
// Compute direction for support call |
||
678 |
✓✓✗ | 98665950 |
switch (current_gjk_variant) { |
679 |
98230949 |
case DefaultGJK: |
|
680 |
✓✗ | 98230949 |
dir = ray; |
681 |
98230949 |
break; |
|
682 |
|||
683 |
435001 |
case NesterovAcceleration: |
|
684 |
// Normalize heuristic for collision pairs involving convex but not |
||
685 |
// strictly-convex shapes This corresponds to most use cases. |
||
686 |
✓✓ | 435001 |
if (normalize_support_direction) { |
687 |
19470 |
momentum = (FCL_REAL(iterations) + 2) / (FCL_REAL(iterations) + 3); |
|
688 |
✓✗✓✗ ✓✗✓✗ |
19470 |
y = momentum * ray + (1 - momentum) * w; |
689 |
✓✗ | 19470 |
FCL_REAL y_norm = y.norm(); |
690 |
// ray is the point of the Minkowski difference which currently the |
||
691 |
// closest to the origin. Therefore, y.norm() > ray.norm() Hence, if |
||
692 |
// check A above has not stopped the algorithm, we necessarily have |
||
693 |
// y.norm() > tolerance. The following assert is just a safety check. |
||
694 |
✗✓ | 19470 |
assert(y_norm > tolerance); |
695 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗ |
19470 |
dir = momentum * dir / dir.norm() + (1 - momentum) * y / y_norm; |
696 |
} else { |
||
697 |
415531 |
momentum = (FCL_REAL(iterations) + 1) / (FCL_REAL(iterations) + 3); |
|
698 |
✓✗✓✗ ✓✗✓✗ |
415531 |
y = momentum * ray + (1 - momentum) * w; |
699 |
✓✗✓✗ ✓✗✓✗ |
415531 |
dir = momentum * dir + (1 - momentum) * y; |
700 |
} |
||
701 |
435001 |
break; |
|
702 |
|||
703 |
default: |
||
704 |
throw std::logic_error("Invalid momentum variant."); |
||
705 |
} |
||
706 |
|||
707 |
✓✗✓✗ |
98665950 |
appendVertex(curr_simplex, -dir, false, |
708 |
✓✗ | 98665950 |
support_hint); // see below, ray points away from origin |
709 |
|||
710 |
// check removed (by ?): when the new support point is close to previous |
||
711 |
// support points, stop (as the new simplex is degenerated) |
||
712 |
✓✗ | 98665950 |
w = curr_simplex.vertex[curr_simplex.rank - 1]->w; |
713 |
|||
714 |
// check B: no collision if omega > 0 |
||
715 |
✓✗✓✗ |
98665950 |
FCL_REAL omega = dir.dot(w) / dir.norm(); |
716 |
✓✓ | 98665950 |
if (omega > upper_bound) { |
717 |
2 |
distance = omega - inflation; |
|
718 |
2 |
status = EarlyStopped; |
|
719 |
2 |
break; |
|
720 |
} |
||
721 |
|||
722 |
// Check to remove acceleration |
||
723 |
✓✓ | 98665948 |
if (current_gjk_variant != DefaultGJK) { |
724 |
✓✗✓✗ |
435001 |
FCL_REAL frank_wolfe_duality_gap = 2 * ray.dot(ray - w); |
725 |
✓✓ | 435001 |
if (frank_wolfe_duality_gap - tolerance <= 0) { |
726 |
66487 |
removeVertex(simplices[current]); |
|
727 |
66487 |
current_gjk_variant = DefaultGJK; // move back to classic GJK |
|
728 |
71925 |
continue; // continue to next iteration |
|
729 |
} |
||
730 |
} |
||
731 |
|||
732 |
// check C: when the new support point is close to the sub-simplex where the |
||
733 |
// ray point lies, stop (as the new simplex again is degenerated) |
||
734 |
✓✗ | 98599461 |
bool cv_check_passed = checkConvergence(w, rl, alpha, omega); |
735 |
// TODO here, we can stop at iteration 0 if this condition is met. |
||
736 |
// We stopping at iteration 0, the closest point will not be valid. |
||
737 |
// if(diff - tolerance * rl <= 0) |
||
738 |
✓✓✓✓ |
98599461 |
if (iterations > 0 && cv_check_passed) { |
739 |
✓✗ | 30092644 |
if (iterations > 0) removeVertex(simplices[current]); |
740 |
✓✓ | 30092644 |
if (current_gjk_variant != DefaultGJK) { |
741 |
5438 |
current_gjk_variant = DefaultGJK; // move back to classic GJK |
|
742 |
5438 |
continue; |
|
743 |
} |
||
744 |
30087206 |
distance = rl - inflation; |
|
745 |
// TODO When inflation is strictly positive, the distance may be exactly |
||
746 |
// zero (so the ray is not zero) and we are not in the case rl < |
||
747 |
// tolerance. |
||
748 |
✓✓ | 30087206 |
if (distance < tolerance) status = Inside; |
749 |
30087206 |
break; |
|
750 |
} |
||
751 |
|||
752 |
// This has been rewritten thanks to the excellent video: |
||
753 |
// https://youtu.be/Qupqu1xe7Io |
||
754 |
bool inside; |
||
755 |
✓✓✓✓ ✗ |
68506817 |
switch (curr_simplex.rank) { |
756 |
30118471 |
case 1: // Only at the first iteration |
|
757 |
✗✓ | 30118471 |
assert(iterations == 0); |
758 |
✓✗ | 30118471 |
ray = w; |
759 |
30118471 |
inside = false; |
|
760 |
30118471 |
next_simplex.rank = 1; |
|
761 |
30118471 |
next_simplex.vertex[0] = curr_simplex.vertex[0]; |
|
762 |
30118471 |
break; |
|
763 |
33932306 |
case 2: |
|
764 |
✓✗ | 33932306 |
inside = projectLineOrigin(curr_simplex, next_simplex); |
765 |
33932306 |
break; |
|
766 |
4167321 |
case 3: |
|
767 |
✓✗ | 4167321 |
inside = projectTriangleOrigin(curr_simplex, next_simplex); |
768 |
4167321 |
break; |
|
769 |
288719 |
case 4: |
|
770 |
✓✗ | 288719 |
inside = projectTetrahedraOrigin(curr_simplex, next_simplex); |
771 |
288719 |
break; |
|
772 |
default: |
||
773 |
throw std::logic_error("Invalid simplex rank"); |
||
774 |
} |
||
775 |
✗✓ | 68506817 |
assert(nfree + next_simplex.rank == 4); |
776 |
68506817 |
current = next; |
|
777 |
✓✓✓✗ |
68506817 |
if (!inside) rl = ray.norm(); |
778 |
✓✓✓✓ |
68506817 |
if (inside || rl == 0) { |
779 |
31243 |
status = Inside; |
|
780 |
31243 |
distance = -inflation - 1.; |
|
781 |
31243 |
break; |
|
782 |
} |
||
783 |
|||
784 |
✓✗ | 68475574 |
status = ((++iterations) < max_iterations) ? status : Failed; |
785 |
|||
786 |
✓✗ | 68547499 |
} while (status == Valid); |
787 |
|||
788 |
30118472 |
simplex = &simplices[current]; |
|
789 |
✓✗✓✗ |
30118472 |
assert(simplex->rank > 0 && simplex->rank < 5); |
790 |
30118472 |
return status; |
|
791 |
} |
||
792 |
|||
793 |
98599461 |
bool GJK::checkConvergence(const Vec3f& w, const FCL_REAL& rl, FCL_REAL& alpha, |
|
794 |
const FCL_REAL& omega) { |
||
795 |
FCL_REAL diff; |
||
796 |
bool check_passed; |
||
797 |
// x^* is the optimal solution (projection of origin onto the Minkowski |
||
798 |
// difference). |
||
799 |
// x^k is the current iterate (x^k = `ray` in the code). |
||
800 |
// Each criterion provides a different guarantee on the distance to the |
||
801 |
// optimal solution. |
||
802 |
✓✓✓✗ |
98599461 |
switch (convergence_criterion) { |
803 |
98564697 |
case VDB: |
|
804 |
// alpha is the distance to the best separating hyperplane found so far |
||
805 |
98564697 |
alpha = std::max(alpha, omega); |
|
806 |
// ||x^*|| - ||x^k|| <= diff |
||
807 |
98564697 |
diff = rl - alpha; |
|
808 |
✗✓✗ | 98564697 |
switch (convergence_criterion_type) { |
809 |
case Absolute: |
||
810 |
throw std::logic_error("VDB convergence criterion is relative."); |
||
811 |
break; |
||
812 |
98564697 |
case Relative: |
|
813 |
98564697 |
check_passed = (diff - tolerance * rl) <= 0; |
|
814 |
98564697 |
break; |
|
815 |
default: |
||
816 |
throw std::logic_error("Invalid convergence criterion type."); |
||
817 |
} |
||
818 |
98564697 |
break; |
|
819 |
|||
820 |
17388 |
case DualityGap: |
|
821 |
// ||x^* - x^k||^2 <= diff |
||
822 |
✓✗ | 17388 |
diff = 2 * ray.dot(ray - w); |
823 |
✓✓✗ | 17388 |
switch (convergence_criterion_type) { |
824 |
8560 |
case Absolute: |
|
825 |
8560 |
check_passed = (diff - tolerance) <= 0; |
|
826 |
8560 |
break; |
|
827 |
8828 |
case Relative: |
|
828 |
8828 |
check_passed = ((diff / tolerance * rl) - tolerance * rl) <= 0; |
|
829 |
8828 |
break; |
|
830 |
default: |
||
831 |
throw std::logic_error("Invalid convergence criterion type."); |
||
832 |
} |
||
833 |
17388 |
break; |
|
834 |
|||
835 |
17376 |
case Hybrid: |
|
836 |
// alpha is the distance to the best separating hyperplane found so far |
||
837 |
17376 |
alpha = std::max(alpha, omega); |
|
838 |
// ||x^* - x^k||^2 <= diff |
||
839 |
17376 |
diff = rl * rl - alpha * alpha; |
|
840 |
✓✓✗ | 17376 |
switch (convergence_criterion_type) { |
841 |
8552 |
case Absolute: |
|
842 |
8552 |
check_passed = (diff - tolerance) <= 0; |
|
843 |
8552 |
break; |
|
844 |
8824 |
case Relative: |
|
845 |
8824 |
check_passed = ((diff / tolerance * rl) - tolerance * rl) <= 0; |
|
846 |
8824 |
break; |
|
847 |
default: |
||
848 |
throw std::logic_error("Invalid convergence criterion type."); |
||
849 |
} |
||
850 |
17376 |
break; |
|
851 |
|||
852 |
default: |
||
853 |
throw std::logic_error("Invalid convergence criterion."); |
||
854 |
} |
||
855 |
98599461 |
return check_passed; |
|
856 |
} |
||
857 |
|||
858 |
30159131 |
inline void GJK::removeVertex(Simplex& simplex) { |
|
859 |
30159131 |
free_v[nfree++] = simplex.vertex[--simplex.rank]; |
|
860 |
30159131 |
} |
|
861 |
|||
862 |
98666072 |
inline void GJK::appendVertex(Simplex& simplex, const Vec3f& v, |
|
863 |
bool isNormalized, support_func_guess_t& hint) { |
||
864 |
98666072 |
simplex.vertex[simplex.rank] = free_v[--nfree]; // set the memory |
|
865 |
98666072 |
getSupport(v, isNormalized, *simplex.vertex[simplex.rank++], hint); |
|
866 |
98666072 |
} |
|
867 |
|||
868 |
694 |
bool GJK::encloseOrigin() { |
|
869 |
✓✗✓✗ |
694 |
Vec3f axis(Vec3f::Zero()); |
870 |
✓✗✓✗ |
694 |
support_func_guess_t hint = support_func_guess_t::Zero(); |
871 |
✗✓✓✓ ✗ |
694 |
switch (simplex->rank) { |
872 |
case 1: |
||
873 |
for (int i = 0; i < 3; ++i) { |
||
874 |
axis[i] = 1; |
||
875 |
appendVertex(*simplex, axis, true, hint); |
||
876 |
if (encloseOrigin()) return true; |
||
877 |
removeVertex(*simplex); |
||
878 |
axis[i] = -1; |
||
879 |
appendVertex(*simplex, -axis, true, hint); |
||
880 |
if (encloseOrigin()) return true; |
||
881 |
removeVertex(*simplex); |
||
882 |
axis[i] = 0; |
||
883 |
} |
||
884 |
break; |
||
885 |
45 |
case 2: { |
|
886 |
✓✗✓✗ |
45 |
Vec3f d = simplex->vertex[1]->w - simplex->vertex[0]->w; |
887 |
✓✗ | 84 |
for (int i = 0; i < 3; ++i) { |
888 |
✓✗ | 84 |
axis[i] = 1; |
889 |
✓✗ | 84 |
Vec3f p = d.cross(axis); |
890 |
✓✗✓✓ |
84 |
if (!p.isZero()) { |
891 |
✓✗ | 45 |
appendVertex(*simplex, p, false, hint); |
892 |
✓✗✓✗ |
45 |
if (encloseOrigin()) return true; |
893 |
removeVertex(*simplex); |
||
894 |
appendVertex(*simplex, -p, false, hint); |
||
895 |
if (encloseOrigin()) return true; |
||
896 |
removeVertex(*simplex); |
||
897 |
} |
||
898 |
✓✗ | 39 |
axis[i] = 0; |
899 |
} |
||
900 |
} break; |
||
901 |
77 |
case 3: |
|
902 |
✓✗ | 77 |
axis.noalias() = |
903 |
✓✗ | 77 |
(simplex->vertex[1]->w - simplex->vertex[0]->w) |
904 |
✓✗✓✗ ✓✗ |
154 |
.cross(simplex->vertex[2]->w - simplex->vertex[0]->w); |
905 |
✓✗✓✗ |
77 |
if (!axis.isZero()) { |
906 |
✓✗ | 77 |
appendVertex(*simplex, axis, false, hint); |
907 |
✓✗✓✗ |
77 |
if (encloseOrigin()) return true; |
908 |
removeVertex(*simplex); |
||
909 |
appendVertex(*simplex, -axis, false, hint); |
||
910 |
if (encloseOrigin()) return true; |
||
911 |
removeVertex(*simplex); |
||
912 |
} |
||
913 |
break; |
||
914 |
572 |
case 4: |
|
915 |
✓✗✓✗ |
572 |
if (std::abs(triple(simplex->vertex[0]->w - simplex->vertex[3]->w, |
916 |
✓✗ | 572 |
simplex->vertex[1]->w - simplex->vertex[3]->w, |
917 |
✓✗✓✗ |
1144 |
simplex->vertex[2]->w - simplex->vertex[3]->w)) > 0) |
918 |
572 |
return true; |
|
919 |
break; |
||
920 |
} |
||
921 |
|||
922 |
return false; |
||
923 |
} |
||
924 |
|||
925 |
25980570 |
inline void originToPoint(const GJK::Simplex& current, GJK::vertex_id_t a, |
|
926 |
const Vec3f& A, GJK::Simplex& next, Vec3f& ray) { |
||
927 |
// A is the closest to the origin |
||
928 |
25980570 |
ray = A; |
|
929 |
25980570 |
next.vertex[0] = current.vertex[a]; |
|
930 |
25980570 |
next.rank = 1; |
|
931 |
25980570 |
} |
|
932 |
|||
933 |
11698703 |
inline void originToSegment(const GJK::Simplex& current, GJK::vertex_id_t a, |
|
934 |
GJK::vertex_id_t b, const Vec3f& A, const Vec3f& B, |
||
935 |
const Vec3f& AB, const FCL_REAL& ABdotAO, |
||
936 |
GJK::Simplex& next, Vec3f& ray) { |
||
937 |
// ray = - ( AB ^ AO ) ^ AB = (AB.B) A + (-AB.A) B |
||
938 |
✓✗✓✗ ✓✗✓✗ |
11698703 |
ray = AB.dot(B) * A + ABdotAO * B; |
939 |
|||
940 |
11698703 |
next.vertex[0] = current.vertex[b]; |
|
941 |
11698703 |
next.vertex[1] = current.vertex[a]; |
|
942 |
11698703 |
next.rank = 2; |
|
943 |
|||
944 |
// To ensure backward compatibility |
||
945 |
✓✗ | 11698703 |
ray /= AB.squaredNorm(); |
946 |
11698703 |
} |
|
947 |
|||
948 |
677890 |
inline bool originToTriangle(const GJK::Simplex& current, GJK::vertex_id_t a, |
|
949 |
GJK::vertex_id_t b, GJK::vertex_id_t c, |
||
950 |
const Vec3f& ABC, const FCL_REAL& ABCdotAO, |
||
951 |
GJK::Simplex& next, Vec3f& ray) { |
||
952 |
677890 |
next.rank = 3; |
|
953 |
677890 |
next.vertex[2] = current.vertex[a]; |
|
954 |
|||
955 |
✓✓ | 677890 |
if (ABCdotAO == 0) { |
956 |
18 |
next.vertex[0] = current.vertex[c]; |
|
957 |
18 |
next.vertex[1] = current.vertex[b]; |
|
958 |
18 |
ray.setZero(); |
|
959 |
18 |
return true; |
|
960 |
} |
||
961 |
✓✓ | 677872 |
if (ABCdotAO > 0) { // Above triangle |
962 |
460983 |
next.vertex[0] = current.vertex[c]; |
|
963 |
460983 |
next.vertex[1] = current.vertex[b]; |
|
964 |
} else { |
||
965 |
216889 |
next.vertex[0] = current.vertex[b]; |
|
966 |
216889 |
next.vertex[1] = current.vertex[c]; |
|
967 |
} |
||
968 |
|||
969 |
// To ensure backward compatibility |
||
970 |
✓✗✓✗ |
677872 |
ray = -ABCdotAO / ABC.squaredNorm() * ABC; |
971 |
677872 |
return false; |
|
972 |
} |
||
973 |
|||
974 |
33932306 |
bool GJK::projectLineOrigin(const Simplex& current, Simplex& next) { |
|
975 |
33932306 |
const vertex_id_t a = 1, b = 0; |
|
976 |
// A is the last point we added. |
||
977 |
33932306 |
const Vec3f& A = current.vertex[a]->w; |
|
978 |
33932306 |
const Vec3f& B = current.vertex[b]->w; |
|
979 |
|||
980 |
✓✗✓✗ |
33932306 |
const Vec3f AB = B - A; |
981 |
✓✗✓✗ |
33932306 |
const FCL_REAL d = AB.dot(-A); |
982 |
✓✗✗✓ |
33932306 |
assert(d <= AB.squaredNorm()); |
983 |
|||
984 |
✓✓ | 33932306 |
if (d == 0) { |
985 |
// Two extremely unlikely cases: |
||
986 |
// - AB is orthogonal to A: should never happen because it means the support |
||
987 |
// function did not do any progress and GJK should have stopped. |
||
988 |
// - A == origin |
||
989 |
// In any case, A is the closest to the origin |
||
990 |
✓✗ | 3322 |
originToPoint(current, a, A, next, ray); |
991 |
3322 |
free_v[nfree++] = current.vertex[b]; |
|
992 |
✓✗ | 3322 |
return A.isZero(); |
993 |
✓✓ | 33928984 |
} else if (d < 0) { |
994 |
// A is the closest to the origin |
||
995 |
✓✗ | 25343039 |
originToPoint(current, a, A, next, ray); |
996 |
25343039 |
free_v[nfree++] = current.vertex[b]; |
|
997 |
} else |
||
998 |
✓✗ | 8585945 |
originToSegment(current, a, b, A, B, AB, d, next, ray); |
999 |
33928984 |
return false; |
|
1000 |
} |
||
1001 |
|||
1002 |
4167321 |
bool GJK::projectTriangleOrigin(const Simplex& current, Simplex& next) { |
|
1003 |
4167321 |
const vertex_id_t a = 2, b = 1, c = 0; |
|
1004 |
// A is the last point we added. |
||
1005 |
✓✗ | 4167321 |
const Vec3f &A = current.vertex[a]->w, B = current.vertex[b]->w, |
1006 |
✓✗ | 4167321 |
C = current.vertex[c]->w; |
1007 |
|||
1008 |
✓✗✓✗ ✓✗✓✗ ✓✗ |
4167321 |
const Vec3f AB = B - A, AC = C - A, ABC = AB.cross(AC); |
1009 |
|||
1010 |
✓✗✓✗ ✓✗ |
4167321 |
FCL_REAL edgeAC2o = ABC.cross(AC).dot(-A); |
1011 |
✓✓ | 4167321 |
if (edgeAC2o >= 0) { |
1012 |
✓✗✓✗ |
2072582 |
FCL_REAL towardsC = AC.dot(-A); |
1013 |
✓✓ | 2072582 |
if (towardsC >= 0) { // Region 1 |
1014 |
✓✗ | 401007 |
originToSegment(current, a, c, A, C, AC, towardsC, next, ray); |
1015 |
401007 |
free_v[nfree++] = current.vertex[b]; |
|
1016 |
} else { // Region 4 or 5 |
||
1017 |
✓✗✓✗ |
1671575 |
FCL_REAL towardsB = AB.dot(-A); |
1018 |
✓✓ | 1671575 |
if (towardsB < 0) { // Region 5 |
1019 |
// A is the closest to the origin |
||
1020 |
✓✗ | 633367 |
originToPoint(current, a, A, next, ray); |
1021 |
633367 |
free_v[nfree++] = current.vertex[b]; |
|
1022 |
} else // Region 4 |
||
1023 |
✓✗ | 1038208 |
originToSegment(current, a, b, A, B, AB, towardsB, next, ray); |
1024 |
1671575 |
free_v[nfree++] = current.vertex[c]; |
|
1025 |
} |
||
1026 |
} else { |
||
1027 |
✓✗✓✗ ✓✗ |
2094739 |
FCL_REAL edgeAB2o = AB.cross(ABC).dot(-A); |
1028 |
✓✓ | 2094739 |
if (edgeAB2o >= 0) { // Region 4 or 5 |
1029 |
✓✗✓✗ |
1648155 |
FCL_REAL towardsB = AB.dot(-A); |
1030 |
✓✓ | 1648155 |
if (towardsB < 0) { // Region 5 |
1031 |
// A is the closest to the origin |
||
1032 |
✓✗ | 158 |
originToPoint(current, a, A, next, ray); |
1033 |
158 |
free_v[nfree++] = current.vertex[b]; |
|
1034 |
} else // Region 4 |
||
1035 |
✓✗ | 1647997 |
originToSegment(current, a, b, A, B, AB, towardsB, next, ray); |
1036 |
1648155 |
free_v[nfree++] = current.vertex[c]; |
|
1037 |
} else { |
||
1038 |
✓✗✓✗ ✓✗ |
446584 |
return originToTriangle(current, a, b, c, ABC, ABC.dot(-A), next, ray); |
1039 |
} |
||
1040 |
} |
||
1041 |
3720737 |
return false; |
|
1042 |
} |
||
1043 |
|||
1044 |
288719 |
bool GJK::projectTetrahedraOrigin(const Simplex& current, Simplex& next) { |
|
1045 |
// The code of this function was generated using doc/gjk.py |
||
1046 |
288719 |
const vertex_id_t a = 3, b = 2, c = 1, d = 0; |
|
1047 |
288719 |
const Vec3f& A(current.vertex[a]->w); |
|
1048 |
288719 |
const Vec3f& B(current.vertex[b]->w); |
|
1049 |
288719 |
const Vec3f& C(current.vertex[c]->w); |
|
1050 |
288719 |
const Vec3f& D(current.vertex[d]->w); |
|
1051 |
✓✗ | 288719 |
const FCL_REAL aa = A.squaredNorm(); |
1052 |
✓✗ | 288719 |
const FCL_REAL da = D.dot(A); |
1053 |
✓✗ | 288719 |
const FCL_REAL db = D.dot(B); |
1054 |
✓✗ | 288719 |
const FCL_REAL dc = D.dot(C); |
1055 |
✓✗ | 288719 |
const FCL_REAL dd = D.dot(D); |
1056 |
288719 |
const FCL_REAL da_aa = da - aa; |
|
1057 |
✓✗ | 288719 |
const FCL_REAL ca = C.dot(A); |
1058 |
✓✗ | 288719 |
const FCL_REAL cb = C.dot(B); |
1059 |
✓✗ | 288719 |
const FCL_REAL cc = C.dot(C); |
1060 |
288719 |
const FCL_REAL& cd = dc; |
|
1061 |
288719 |
const FCL_REAL ca_aa = ca - aa; |
|
1062 |
✓✗ | 288719 |
const FCL_REAL ba = B.dot(A); |
1063 |
✓✗ | 288719 |
const FCL_REAL bb = B.dot(B); |
1064 |
288719 |
const FCL_REAL& bc = cb; |
|
1065 |
288719 |
const FCL_REAL& bd = db; |
|
1066 |
288719 |
const FCL_REAL ba_aa = ba - aa; |
|
1067 |
288719 |
const FCL_REAL ba_ca = ba - ca; |
|
1068 |
288719 |
const FCL_REAL ca_da = ca - da; |
|
1069 |
288719 |
const FCL_REAL da_ba = da - ba; |
|
1070 |
✓✗ | 288719 |
const Vec3f a_cross_b = A.cross(B); |
1071 |
✓✗ | 288719 |
const Vec3f a_cross_c = A.cross(C); |
1072 |
|||
1073 |
288719 |
const FCL_REAL dummy_precision = Eigen::NumTraits<FCL_REAL>::epsilon(); |
|
1074 |
HPP_FCL_UNUSED_VARIABLE(dummy_precision); |
||
1075 |
|||
1076 |
#define REGION_INSIDE() \ |
||
1077 |
ray.setZero(); \ |
||
1078 |
next.vertex[0] = current.vertex[d]; \ |
||
1079 |
next.vertex[1] = current.vertex[c]; \ |
||
1080 |
next.vertex[2] = current.vertex[b]; \ |
||
1081 |
next.vertex[3] = current.vertex[a]; \ |
||
1082 |
next.rank = 4; \ |
||
1083 |
return true; |
||
1084 |
|||
1085 |
✓✓ | 288719 |
if (ba_aa <= 0) { // if AB.AO >= 0 / a10 |
1086 |
✓✗✓✓ |
243268 |
if (-D.dot(a_cross_b) <= 0) { // if ADB.AO >= 0 / a10.a3 |
1087 |
✓✓ | 171822 |
if (ba * da_ba + bd * ba_aa - bb * da_aa <= |
1088 |
0) { // if (ADB ^ AB).AO >= 0 / a10.a3.a9 |
||
1089 |
✓✓ | 71581 |
if (da_aa <= 0) { // if AD.AO >= 0 / a10.a3.a9.a12 |
1090 |
✗✓ | 22349 |
assert(da * da_ba + dd * ba_aa - db * da_aa <= |
1091 |
dummy_precision); // (ADB ^ AD).AO >= 0 / a10.a3.a9.a12.a8 |
||
1092 |
✓✓ | 22349 |
if (ba * ba_ca + bb * ca_aa - bc * ba_aa <= |
1093 |
0) { // if (ABC ^ AB).AO >= 0 / a10.a3.a9.a12.a8.a4 |
||
1094 |
// Region ABC |
||
1095 |
✓✗✓✗ ✓✗ |
16319 |
originToTriangle(current, a, b, c, (B - A).cross(C - A), |
1096 |
✓✗✓✗ |
16319 |
-C.dot(a_cross_b), next, ray); |
1097 |
16319 |
free_v[nfree++] = current.vertex[d]; |
|
1098 |
} else { // not (ABC ^ AB).AO >= 0 / a10.a3.a9.a12.a8.!a4 |
||
1099 |
// Region AB |
||
1100 |
✓✗✓✗ ✓✗ |
6030 |
originToSegment(current, a, b, A, B, B - A, -ba_aa, next, ray); |
1101 |
6030 |
free_v[nfree++] = current.vertex[c]; |
|
1102 |
6030 |
free_v[nfree++] = current.vertex[d]; |
|
1103 |
} // end of (ABC ^ AB).AO >= 0 |
||
1104 |
} else { // not AD.AO >= 0 / a10.a3.a9.!a12 |
||
1105 |
✓✓ | 49232 |
if (ba * ba_ca + bb * ca_aa - bc * ba_aa <= |
1106 |
0) { // if (ABC ^ AB).AO >= 0 / a10.a3.a9.!a12.a4 |
||
1107 |
✓✓ | 42186 |
if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= |
1108 |
0) { // if (ABC ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.a5 |
||
1109 |
✓✓ | 1004 |
if (ca * ca_da + cc * da_aa - cd * ca_aa <= |
1110 |
0) { // if (ACD ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.a5.a6 |
||
1111 |
// Region ACD |
||
1112 |
✓✗✓✗ ✓✗ |
342 |
originToTriangle(current, a, c, d, (C - A).cross(D - A), |
1113 |
✓✗✓✗ |
342 |
-D.dot(a_cross_c), next, ray); |
1114 |
342 |
free_v[nfree++] = current.vertex[b]; |
|
1115 |
} else { // not (ACD ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.a5.!a6 |
||
1116 |
// Region AC |
||
1117 |
✓✗✓✗ ✓✗ |
662 |
originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray); |
1118 |
662 |
free_v[nfree++] = current.vertex[b]; |
|
1119 |
662 |
free_v[nfree++] = current.vertex[d]; |
|
1120 |
} // end of (ACD ^ AC).AO >= 0 |
||
1121 |
} else { // not (ABC ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.!a5 |
||
1122 |
// Region ABC |
||
1123 |
✓✗✓✗ ✓✗ |
41182 |
originToTriangle(current, a, b, c, (B - A).cross(C - A), |
1124 |
✓✗✓✗ |
41182 |
-C.dot(a_cross_b), next, ray); |
1125 |
41182 |
free_v[nfree++] = current.vertex[d]; |
|
1126 |
} // end of (ABC ^ AC).AO >= 0 |
||
1127 |
} else { // not (ABC ^ AB).AO >= 0 / a10.a3.a9.!a12.!a4 |
||
1128 |
// Region AB |
||
1129 |
✓✗✓✗ ✓✗ |
7046 |
originToSegment(current, a, b, A, B, B - A, -ba_aa, next, ray); |
1130 |
7046 |
free_v[nfree++] = current.vertex[c]; |
|
1131 |
7046 |
free_v[nfree++] = current.vertex[d]; |
|
1132 |
} // end of (ABC ^ AB).AO >= 0 |
||
1133 |
} // end of AD.AO >= 0 |
||
1134 |
} else { // not (ADB ^ AB).AO >= 0 / a10.a3.!a9 |
||
1135 |
✓✓ | 100241 |
if (da * da_ba + dd * ba_aa - db * da_aa <= |
1136 |
0) { // if (ADB ^ AD).AO >= 0 / a10.a3.!a9.a8 |
||
1137 |
// Region ADB |
||
1138 |
✓✗✓✗ ✓✗ |
97453 |
originToTriangle(current, a, d, b, (D - A).cross(B - A), |
1139 |
✓✗✓✗ |
97453 |
D.dot(a_cross_b), next, ray); |
1140 |
97453 |
free_v[nfree++] = current.vertex[c]; |
|
1141 |
} else { // not (ADB ^ AD).AO >= 0 / a10.a3.!a9.!a8 |
||
1142 |
✓✓ | 2788 |
if (ca * ca_da + cc * da_aa - cd * ca_aa <= |
1143 |
0) { // if (ACD ^ AC).AO >= 0 / a10.a3.!a9.!a8.a6 |
||
1144 |
✓✓ | 2735 |
if (da * ca_da + dc * da_aa - dd * ca_aa <= |
1145 |
0) { // if (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.a6.a7 |
||
1146 |
// Region AD |
||
1147 |
✓✗✓✗ ✓✗ |
1448 |
originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray); |
1148 |
1448 |
free_v[nfree++] = current.vertex[b]; |
|
1149 |
1448 |
free_v[nfree++] = current.vertex[c]; |
|
1150 |
} else { // not (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.a6.!a7 |
||
1151 |
// Region ACD |
||
1152 |
✓✗✓✗ ✓✗ |
1287 |
originToTriangle(current, a, c, d, (C - A).cross(D - A), |
1153 |
✓✗✓✗ |
1287 |
-D.dot(a_cross_c), next, ray); |
1154 |
1287 |
free_v[nfree++] = current.vertex[b]; |
|
1155 |
} // end of (ACD ^ AD).AO >= 0 |
||
1156 |
} else { // not (ACD ^ AC).AO >= 0 / a10.a3.!a9.!a8.!a6 |
||
1157 |
✓✗ | 53 |
if (da * ca_da + dc * da_aa - dd * ca_aa <= |
1158 |
0) { // if (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.!a6.a7 |
||
1159 |
// Region AD |
||
1160 |
✓✗✓✗ ✓✗ |
53 |
originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray); |
1161 |
53 |
free_v[nfree++] = current.vertex[b]; |
|
1162 |
53 |
free_v[nfree++] = current.vertex[c]; |
|
1163 |
} else { // not (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.!a6.!a7 |
||
1164 |
// Region AC |
||
1165 |
originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray); |
||
1166 |
free_v[nfree++] = current.vertex[b]; |
||
1167 |
free_v[nfree++] = current.vertex[d]; |
||
1168 |
} // end of (ACD ^ AD).AO >= 0 |
||
1169 |
} // end of (ACD ^ AC).AO >= 0 |
||
1170 |
} // end of (ADB ^ AD).AO >= 0 |
||
1171 |
} // end of (ADB ^ AB).AO >= 0 |
||
1172 |
} else { // not ADB.AO >= 0 / a10.!a3 |
||
1173 |
✓✗✓✓ |
71446 |
if (C.dot(a_cross_b) <= 0) { // if ABC.AO >= 0 / a10.!a3.a1 |
1174 |
✓✓ | 41489 |
if (ba * ba_ca + bb * ca_aa - bc * ba_aa <= |
1175 |
0) { // if (ABC ^ AB).AO >= 0 / a10.!a3.a1.a4 |
||
1176 |
✓✓ | 41479 |
if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= |
1177 |
0) { // if (ABC ^ AC).AO >= 0 / a10.!a3.a1.a4.a5 |
||
1178 |
✓✓ | 2211 |
if (ca * ca_da + cc * da_aa - cd * ca_aa <= |
1179 |
0) { // if (ACD ^ AC).AO >= 0 / a10.!a3.a1.a4.a5.a6 |
||
1180 |
// Region ACD |
||
1181 |
✓✗✓✗ ✓✗ |
1319 |
originToTriangle(current, a, c, d, (C - A).cross(D - A), |
1182 |
✓✗✓✗ |
1319 |
-D.dot(a_cross_c), next, ray); |
1183 |
1319 |
free_v[nfree++] = current.vertex[b]; |
|
1184 |
} else { // not (ACD ^ AC).AO >= 0 / a10.!a3.a1.a4.a5.!a6 |
||
1185 |
// Region AC |
||
1186 |
✓✗✓✗ ✓✗ |
892 |
originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray); |
1187 |
892 |
free_v[nfree++] = current.vertex[b]; |
|
1188 |
892 |
free_v[nfree++] = current.vertex[d]; |
|
1189 |
} // end of (ACD ^ AC).AO >= 0 |
||
1190 |
} else { // not (ABC ^ AC).AO >= 0 / a10.!a3.a1.a4.!a5 |
||
1191 |
// Region ABC |
||
1192 |
✓✗✓✗ ✓✗ |
39268 |
originToTriangle(current, a, b, c, (B - A).cross(C - A), |
1193 |
✓✗✓✗ |
39268 |
-C.dot(a_cross_b), next, ray); |
1194 |
39268 |
free_v[nfree++] = current.vertex[d]; |
|
1195 |
} // end of (ABC ^ AC).AO >= 0 |
||
1196 |
} else { // not (ABC ^ AB).AO >= 0 / a10.!a3.a1.!a4 |
||
1197 |
// Region AB |
||
1198 |
✓✗✓✗ ✓✗ |
10 |
originToSegment(current, a, b, A, B, B - A, -ba_aa, next, ray); |
1199 |
10 |
free_v[nfree++] = current.vertex[c]; |
|
1200 |
10 |
free_v[nfree++] = current.vertex[d]; |
|
1201 |
} // end of (ABC ^ AB).AO >= 0 |
||
1202 |
} else { // not ABC.AO >= 0 / a10.!a3.!a1 |
||
1203 |
✓✗✓✓ |
29957 |
if (D.dot(a_cross_c) <= 0) { // if ACD.AO >= 0 / a10.!a3.!a1.a2 |
1204 |
✓✗ | 1900 |
if (ca * ca_da + cc * da_aa - cd * ca_aa <= |
1205 |
0) { // if (ACD ^ AC).AO >= 0 / a10.!a3.!a1.a2.a6 |
||
1206 |
✗✓ | 1900 |
if (da * ca_da + dc * da_aa - dd * ca_aa <= |
1207 |
0) { // if (ACD ^ AD).AO >= 0 / a10.!a3.!a1.a2.a6.a7 |
||
1208 |
// Region AD |
||
1209 |
originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray); |
||
1210 |
free_v[nfree++] = current.vertex[b]; |
||
1211 |
free_v[nfree++] = current.vertex[c]; |
||
1212 |
} else { // not (ACD ^ AD).AO >= 0 / a10.!a3.!a1.a2.a6.!a7 |
||
1213 |
// Region ACD |
||
1214 |
✓✗✓✗ ✓✗ |
1900 |
originToTriangle(current, a, c, d, (C - A).cross(D - A), |
1215 |
✓✗✓✗ |
1900 |
-D.dot(a_cross_c), next, ray); |
1216 |
1900 |
free_v[nfree++] = current.vertex[b]; |
|
1217 |
} // end of (ACD ^ AD).AO >= 0 |
||
1218 |
} else { // not (ACD ^ AC).AO >= 0 / a10.!a3.!a1.a2.!a6 |
||
1219 |
if (ca_aa <= 0) { // if AC.AO >= 0 / a10.!a3.!a1.a2.!a6.a11 |
||
1220 |
// Region AC |
||
1221 |
originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray); |
||
1222 |
free_v[nfree++] = current.vertex[b]; |
||
1223 |
free_v[nfree++] = current.vertex[d]; |
||
1224 |
} else { // not AC.AO >= 0 / a10.!a3.!a1.a2.!a6.!a11 |
||
1225 |
// Region AD |
||
1226 |
originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray); |
||
1227 |
free_v[nfree++] = current.vertex[b]; |
||
1228 |
free_v[nfree++] = current.vertex[c]; |
||
1229 |
} // end of AC.AO >= 0 |
||
1230 |
} // end of (ACD ^ AC).AO >= 0 |
||
1231 |
} else { // not ACD.AO >= 0 / a10.!a3.!a1.!a2 |
||
1232 |
// Region Inside |
||
1233 |
✓✗ | 28057 |
REGION_INSIDE() |
1234 |
} // end of ACD.AO >= 0 |
||
1235 |
} // end of ABC.AO >= 0 |
||
1236 |
} // end of ADB.AO >= 0 |
||
1237 |
} else { // not AB.AO >= 0 / !a10 |
||
1238 |
✓✓ | 45451 |
if (ca_aa <= 0) { // if AC.AO >= 0 / !a10.a11 |
1239 |
✓✗✓✓ |
33328 |
if (D.dot(a_cross_c) <= 0) { // if ACD.AO >= 0 / !a10.a11.a2 |
1240 |
✓✓ | 29434 |
if (da_aa <= 0) { // if AD.AO >= 0 / !a10.a11.a2.a12 |
1241 |
✓✓ | 18819 |
if (ca * ca_da + cc * da_aa - cd * ca_aa <= |
1242 |
0) { // if (ACD ^ AC).AO >= 0 / !a10.a11.a2.a12.a6 |
||
1243 |
✓✓ | 17690 |
if (da * ca_da + dc * da_aa - dd * ca_aa <= |
1244 |
0) { // if (ACD ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.a7 |
||
1245 |
✓✓ | 1212 |
if (da * da_ba + dd * ba_aa - db * da_aa <= |
1246 |
0) { // if (ADB ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.a7.a8 |
||
1247 |
// Region ADB |
||
1248 |
✓✗✓✗ ✓✗ |
441 |
originToTriangle(current, a, d, b, (D - A).cross(B - A), |
1249 |
✓✗✓✗ |
441 |
D.dot(a_cross_b), next, ray); |
1250 |
441 |
free_v[nfree++] = current.vertex[c]; |
|
1251 |
} else { // not (ADB ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.a7.!a8 |
||
1252 |
// Region AD |
||
1253 |
✓✗✓✗ ✓✗ |
771 |
originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray); |
1254 |
771 |
free_v[nfree++] = current.vertex[b]; |
|
1255 |
771 |
free_v[nfree++] = current.vertex[c]; |
|
1256 |
} // end of (ADB ^ AD).AO >= 0 |
||
1257 |
} else { // not (ACD ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.!a7 |
||
1258 |
// Region ACD |
||
1259 |
✓✗✓✗ ✓✗ |
16478 |
originToTriangle(current, a, c, d, (C - A).cross(D - A), |
1260 |
✓✗✓✗ |
16478 |
-D.dot(a_cross_c), next, ray); |
1261 |
16478 |
free_v[nfree++] = current.vertex[b]; |
|
1262 |
} // end of (ACD ^ AD).AO >= 0 |
||
1263 |
} else { // not (ACD ^ AC).AO >= 0 / !a10.a11.a2.a12.!a6 |
||
1264 |
✗✓ | 1129 |
assert(!(da * ca_da + dc * da_aa - dd * ca_aa <= |
1265 |
dummy_precision)); // Not (ACD ^ AD).AO >= 0 / |
||
1266 |
// !a10.a11.a2.a12.!a6.!a7 |
||
1267 |
✓✓ | 1129 |
if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= |
1268 |
0) { // if (ABC ^ AC).AO >= 0 / !a10.a11.a2.a12.!a6.!a7.a5 |
||
1269 |
// Region AC |
||
1270 |
✓✗✓✗ ✓✗ |
701 |
originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray); |
1271 |
701 |
free_v[nfree++] = current.vertex[b]; |
|
1272 |
701 |
free_v[nfree++] = current.vertex[d]; |
|
1273 |
} else { // not (ABC ^ AC).AO >= 0 / !a10.a11.a2.a12.!a6.!a7.!a5 |
||
1274 |
// Region ABC |
||
1275 |
✓✗✓✗ ✓✗ |
428 |
originToTriangle(current, a, b, c, (B - A).cross(C - A), |
1276 |
✓✗✓✗ |
428 |
-C.dot(a_cross_b), next, ray); |
1277 |
428 |
free_v[nfree++] = current.vertex[d]; |
|
1278 |
} // end of (ABC ^ AC).AO >= 0 |
||
1279 |
} // end of (ACD ^ AC).AO >= 0 |
||
1280 |
} else { // not AD.AO >= 0 / !a10.a11.a2.!a12 |
||
1281 |
✓✓ | 10615 |
if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= |
1282 |
0) { // if (ABC ^ AC).AO >= 0 / !a10.a11.a2.!a12.a5 |
||
1283 |
✓✓ | 7438 |
if (ca * ca_da + cc * da_aa - cd * ca_aa <= |
1284 |
0) { // if (ACD ^ AC).AO >= 0 / !a10.a11.a2.!a12.a5.a6 |
||
1285 |
✗✓ | 3776 |
assert(!(da * ca_da + dc * da_aa - dd * ca_aa <= |
1286 |
-dummy_precision)); // Not (ACD ^ AD).AO >= 0 / |
||
1287 |
// !a10.a11.a2.!a12.a5.a6.!a7 |
||
1288 |
// Region ACD |
||
1289 |
✓✗✓✗ ✓✗ |
3776 |
originToTriangle(current, a, c, d, (C - A).cross(D - A), |
1290 |
✓✗✓✗ |
3776 |
-D.dot(a_cross_c), next, ray); |
1291 |
3776 |
free_v[nfree++] = current.vertex[b]; |
|
1292 |
} else { // not (ACD ^ AC).AO >= 0 / !a10.a11.a2.!a12.a5.!a6 |
||
1293 |
// Region AC |
||
1294 |
✓✗✓✗ ✓✗ |
3662 |
originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray); |
1295 |
3662 |
free_v[nfree++] = current.vertex[b]; |
|
1296 |
3662 |
free_v[nfree++] = current.vertex[d]; |
|
1297 |
} // end of (ACD ^ AC).AO >= 0 |
||
1298 |
} else { // not (ABC ^ AC).AO >= 0 / !a10.a11.a2.!a12.!a5 |
||
1299 |
✓✗✓✓ |
3177 |
if (C.dot(a_cross_b) <= |
1300 |
0) { // if ABC.AO >= 0 / !a10.a11.a2.!a12.!a5.a1 |
||
1301 |
✗✓ | 2693 |
assert(ba * ba_ca + bb * ca_aa - bc * ba_aa <= |
1302 |
dummy_precision); // (ABC ^ AB).AO >= 0 / |
||
1303 |
// !a10.a11.a2.!a12.!a5.a1.a4 |
||
1304 |
// Region ABC |
||
1305 |
✓✗✓✗ ✓✗ |
2693 |
originToTriangle(current, a, b, c, (B - A).cross(C - A), |
1306 |
✓✗✓✗ |
2693 |
-C.dot(a_cross_b), next, ray); |
1307 |
2693 |
free_v[nfree++] = current.vertex[d]; |
|
1308 |
} else { // not ABC.AO >= 0 / !a10.a11.a2.!a12.!a5.!a1 |
||
1309 |
✗✓ | 484 |
assert(!(da * ca_da + dc * da_aa - dd * ca_aa <= |
1310 |
-dummy_precision)); // Not (ACD ^ AD).AO >= 0 / |
||
1311 |
// !a10.a11.a2.!a12.!a5.!a1.!a7 |
||
1312 |
// Region ACD |
||
1313 |
✓✗✓✗ ✓✗ |
484 |
originToTriangle(current, a, c, d, (C - A).cross(D - A), |
1314 |
✓✗✓✗ |
484 |
-D.dot(a_cross_c), next, ray); |
1315 |
484 |
free_v[nfree++] = current.vertex[b]; |
|
1316 |
} // end of ABC.AO >= 0 |
||
1317 |
} // end of (ABC ^ AC).AO >= 0 |
||
1318 |
} // end of AD.AO >= 0 |
||
1319 |
} else { // not ACD.AO >= 0 / !a10.a11.!a2 |
||
1320 |
✓✗✓✓ |
3894 |
if (C.dot(a_cross_b) <= 0) { // if ABC.AO >= 0 / !a10.a11.!a2.a1 |
1321 |
✓✓ | 1593 |
if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= |
1322 |
0) { // if (ABC ^ AC).AO >= 0 / !a10.a11.!a2.a1.a5 |
||
1323 |
// Region AC |
||
1324 |
✓✗✓✗ ✓✗ |
77 |
originToSegment(current, a, c, A, C, C - A, -ca_aa, next, ray); |
1325 |
77 |
free_v[nfree++] = current.vertex[b]; |
|
1326 |
77 |
free_v[nfree++] = current.vertex[d]; |
|
1327 |
} else { // not (ABC ^ AC).AO >= 0 / !a10.a11.!a2.a1.!a5 |
||
1328 |
✗✓ | 1516 |
assert(ba * ba_ca + bb * ca_aa - bc * ba_aa <= |
1329 |
dummy_precision); // (ABC ^ AB).AO >= 0 / |
||
1330 |
// !a10.a11.!a2.a1.!a5.a4 |
||
1331 |
// Region ABC |
||
1332 |
✓✗✓✗ ✓✗ |
1516 |
originToTriangle(current, a, b, c, (B - A).cross(C - A), |
1333 |
✓✗✓✗ |
1516 |
-C.dot(a_cross_b), next, ray); |
1334 |
1516 |
free_v[nfree++] = current.vertex[d]; |
|
1335 |
} // end of (ABC ^ AC).AO >= 0 |
||
1336 |
} else { // not ABC.AO >= 0 / !a10.a11.!a2.!a1 |
||
1337 |
✓✗✓✓ |
2301 |
if (-D.dot(a_cross_b) <= 0) { // if ADB.AO >= 0 / !a10.a11.!a2.!a1.a3 |
1338 |
✓✗ | 18 |
if (da * da_ba + dd * ba_aa - db * da_aa <= |
1339 |
0) { // if (ADB ^ AD).AO >= 0 / !a10.a11.!a2.!a1.a3.a8 |
||
1340 |
// Region ADB |
||
1341 |
✓✗✓✗ ✓✗ |
18 |
originToTriangle(current, a, d, b, (D - A).cross(B - A), |
1342 |
✓✗✓✗ |
18 |
D.dot(a_cross_b), next, ray); |
1343 |
18 |
free_v[nfree++] = current.vertex[c]; |
|
1344 |
} else { // not (ADB ^ AD).AO >= 0 / !a10.a11.!a2.!a1.a3.!a8 |
||
1345 |
// Region AD |
||
1346 |
originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray); |
||
1347 |
free_v[nfree++] = current.vertex[b]; |
||
1348 |
free_v[nfree++] = current.vertex[c]; |
||
1349 |
} // end of (ADB ^ AD).AO >= 0 |
||
1350 |
} else { // not ADB.AO >= 0 / !a10.a11.!a2.!a1.!a3 |
||
1351 |
// Region Inside |
||
1352 |
✓✗ | 2283 |
REGION_INSIDE() |
1353 |
} // end of ADB.AO >= 0 |
||
1354 |
} // end of ABC.AO >= 0 |
||
1355 |
} // end of ACD.AO >= 0 |
||
1356 |
} else { // not AC.AO >= 0 / !a10.!a11 |
||
1357 |
✓✓ | 12123 |
if (da_aa <= 0) { // if AD.AO >= 0 / !a10.!a11.a12 |
1358 |
✓✗✓✓ |
11439 |
if (-D.dot(a_cross_b) <= 0) { // if ADB.AO >= 0 / !a10.!a11.a12.a3 |
1359 |
✓✓ | 9544 |
if (da * ca_da + dc * da_aa - dd * ca_aa <= |
1360 |
0) { // if (ACD ^ AD).AO >= 0 / !a10.!a11.a12.a3.a7 |
||
1361 |
✓✓ | 7084 |
if (da * da_ba + dd * ba_aa - db * da_aa <= |
1362 |
0) { // if (ADB ^ AD).AO >= 0 / !a10.!a11.a12.a3.a7.a8 |
||
1363 |
✗✓ | 2926 |
assert(!(ba * da_ba + bd * ba_aa - bb * da_aa <= |
1364 |
-dummy_precision)); // Not (ADB ^ AB).AO >= 0 / |
||
1365 |
// !a10.!a11.a12.a3.a7.a8.!a9 |
||
1366 |
// Region ADB |
||
1367 |
✓✗✓✗ ✓✗ |
2926 |
originToTriangle(current, a, d, b, (D - A).cross(B - A), |
1368 |
✓✗✓✗ |
2926 |
D.dot(a_cross_b), next, ray); |
1369 |
2926 |
free_v[nfree++] = current.vertex[c]; |
|
1370 |
} else { // not (ADB ^ AD).AO >= 0 / !a10.!a11.a12.a3.a7.!a8 |
||
1371 |
// Region AD |
||
1372 |
✓✗✓✗ ✓✗ |
4158 |
originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray); |
1373 |
4158 |
free_v[nfree++] = current.vertex[b]; |
|
1374 |
4158 |
free_v[nfree++] = current.vertex[c]; |
|
1375 |
} // end of (ADB ^ AD).AO >= 0 |
||
1376 |
} else { // not (ACD ^ AD).AO >= 0 / !a10.!a11.a12.a3.!a7 |
||
1377 |
✓✗✓✓ |
2460 |
if (D.dot(a_cross_c) <= |
1378 |
0) { // if ACD.AO >= 0 / !a10.!a11.a12.a3.!a7.a2 |
||
1379 |
✗✓ | 2389 |
assert(ca * ca_da + cc * da_aa - cd * ca_aa <= |
1380 |
dummy_precision); // (ACD ^ AC).AO >= 0 / |
||
1381 |
// !a10.!a11.a12.a3.!a7.a2.a6 |
||
1382 |
// Region ACD |
||
1383 |
✓✗✓✗ ✓✗ |
2389 |
originToTriangle(current, a, c, d, (C - A).cross(D - A), |
1384 |
✓✗✓✗ |
2389 |
-D.dot(a_cross_c), next, ray); |
1385 |
2389 |
free_v[nfree++] = current.vertex[b]; |
|
1386 |
} else { // not ACD.AO >= 0 / !a10.!a11.a12.a3.!a7.!a2 |
||
1387 |
✓✗✓✓ |
71 |
if (C.dot(a_cross_b) <= |
1388 |
0) { // if ABC.AO >= 0 / !a10.!a11.a12.a3.!a7.!a2.a1 |
||
1389 |
✗✓ | 46 |
assert(!(ba * ba_ca + bb * ca_aa - bc * ba_aa <= |
1390 |
-dummy_precision)); // Not (ABC ^ AB).AO >= 0 / |
||
1391 |
// !a10.!a11.a12.a3.!a7.!a2.a1.!a4 |
||
1392 |
// Region ADB |
||
1393 |
✓✗✓✗ ✓✗ |
46 |
originToTriangle(current, a, d, b, (D - A).cross(B - A), |
1394 |
✓✗✓✗ |
46 |
D.dot(a_cross_b), next, ray); |
1395 |
46 |
free_v[nfree++] = current.vertex[c]; |
|
1396 |
} else { // not ABC.AO >= 0 / !a10.!a11.a12.a3.!a7.!a2.!a1 |
||
1397 |
// Region ADB |
||
1398 |
✓✗✓✗ ✓✗ |
25 |
originToTriangle(current, a, d, b, (D - A).cross(B - A), |
1399 |
✓✗✓✗ |
25 |
D.dot(a_cross_b), next, ray); |
1400 |
25 |
free_v[nfree++] = current.vertex[c]; |
|
1401 |
} // end of ABC.AO >= 0 |
||
1402 |
} // end of ACD.AO >= 0 |
||
1403 |
} // end of (ACD ^ AD).AO >= 0 |
||
1404 |
} else { // not ADB.AO >= 0 / !a10.!a11.a12.!a3 |
||
1405 |
✓✗✓✓ |
1895 |
if (D.dot(a_cross_c) <= 0) { // if ACD.AO >= 0 / !a10.!a11.a12.!a3.a2 |
1406 |
✓✓ | 1052 |
if (da * ca_da + dc * da_aa - dd * ca_aa <= |
1407 |
0) { // if (ACD ^ AD).AO >= 0 / !a10.!a11.a12.!a3.a2.a7 |
||
1408 |
// Region AD |
||
1409 |
✓✗✓✗ ✓✗ |
36 |
originToSegment(current, a, d, A, D, D - A, -da_aa, next, ray); |
1410 |
36 |
free_v[nfree++] = current.vertex[b]; |
|
1411 |
36 |
free_v[nfree++] = current.vertex[c]; |
|
1412 |
} else { // not (ACD ^ AD).AO >= 0 / !a10.!a11.a12.!a3.a2.!a7 |
||
1413 |
✗✓ | 1016 |
assert(ca * ca_da + cc * da_aa - cd * ca_aa <= |
1414 |
dummy_precision); // (ACD ^ AC).AO >= 0 / |
||
1415 |
// !a10.!a11.a12.!a3.a2.!a7.a6 |
||
1416 |
// Region ACD |
||
1417 |
✓✗✓✗ ✓✗ |
1016 |
originToTriangle(current, a, c, d, (C - A).cross(D - A), |
1418 |
✓✗✓✗ |
1016 |
-D.dot(a_cross_c), next, ray); |
1419 |
1016 |
free_v[nfree++] = current.vertex[b]; |
|
1420 |
} // end of (ACD ^ AD).AO >= 0 |
||
1421 |
} else { // not ACD.AO >= 0 / !a10.!a11.a12.!a3.!a2 |
||
1422 |
// Region Inside |
||
1423 |
✓✗ | 843 |
REGION_INSIDE() |
1424 |
} // end of ACD.AO >= 0 |
||
1425 |
} // end of ADB.AO >= 0 |
||
1426 |
} else { // not AD.AO >= 0 / !a10.!a11.!a12 |
||
1427 |
// Region A |
||
1428 |
✓✗ | 684 |
originToPoint(current, a, A, next, ray); |
1429 |
684 |
free_v[nfree++] = current.vertex[b]; |
|
1430 |
684 |
free_v[nfree++] = current.vertex[c]; |
|
1431 |
684 |
free_v[nfree++] = current.vertex[d]; |
|
1432 |
} // end of AD.AO >= 0 |
||
1433 |
} // end of AC.AO >= 0 |
||
1434 |
} // end of AB.AO >= 0 |
||
1435 |
|||
1436 |
#undef REGION_INSIDE |
||
1437 |
257536 |
return false; |
|
1438 |
} |
||
1439 |
|||
1440 |
574 |
void EPA::initialize() { |
|
1441 |
✓✗✓✓ ✓✗ |
37310 |
sv_store = new SimplexV[max_vertex_num]; |
1442 |
✓✗✓✓ ✓✗ |
74046 |
fc_store = new SimplexF[max_face_num]; |
1443 |
574 |
status = Failed; |
|
1444 |
✓✗ | 574 |
normal = Vec3f(0, 0, 0); |
1445 |
574 |
depth = 0; |
|
1446 |
574 |
nextsv = 0; |
|
1447 |
✓✓ | 74046 |
for (size_t i = 0; i < max_face_num; ++i) |
1448 |
73472 |
stock.append(&fc_store[max_face_num - i - 1]); |
|
1449 |
574 |
} |
|
1450 |
|||
1451 |
74776 |
bool EPA::getEdgeDist(SimplexF* face, SimplexV* a, SimplexV* b, |
|
1452 |
FCL_REAL& dist) { |
||
1453 |
✓✗✓✗ |
74776 |
Vec3f ab = b->w - a->w; |
1454 |
✓✗ | 74776 |
Vec3f n_ab = ab.cross(face->n); |
1455 |
✓✗ | 74776 |
FCL_REAL a_dot_nab = a->w.dot(n_ab); |
1456 |
|||
1457 |
✓✓ | 74776 |
if (a_dot_nab < 0) // the origin is on the outside part of ab |
1458 |
{ |
||
1459 |
// following is similar to projectOrigin for two points |
||
1460 |
// however, as we dont need to compute the parameterization, dont need to |
||
1461 |
// compute 0 or 1 |
||
1462 |
✓✗ | 14932 |
FCL_REAL a_dot_ab = a->w.dot(ab); |
1463 |
✓✗ | 14932 |
FCL_REAL b_dot_ab = b->w.dot(ab); |
1464 |
|||
1465 |
✓✓ | 14932 |
if (a_dot_ab > 0) |
1466 |
✓✗ | 1176 |
dist = a->w.norm(); |
1467 |
✓✓ | 13756 |
else if (b_dot_ab < 0) |
1468 |
✓✗ | 1578 |
dist = b->w.norm(); |
1469 |
else { |
||
1470 |
12178 |
dist = std::sqrt(std::max( |
|
1471 |
✓✗✓✗ |
12178 |
a->w.squaredNorm() - a_dot_ab * a_dot_ab / ab.squaredNorm(), 0.)); |
1472 |
} |
||
1473 |
|||
1474 |
14932 |
return true; |
|
1475 |
} |
||
1476 |
|||
1477 |
59844 |
return false; |
|
1478 |
} |
||
1479 |
|||
1480 |
29644 |
EPA::SimplexF* EPA::newFace(SimplexV* a, SimplexV* b, SimplexV* c, |
|
1481 |
bool forced) { |
||
1482 |
✓✓ | 29644 |
if (stock.root) { |
1483 |
29618 |
SimplexF* face = stock.root; |
|
1484 |
29618 |
stock.remove(face); |
|
1485 |
29618 |
hull.append(face); |
|
1486 |
29618 |
face->pass = 0; |
|
1487 |
29618 |
face->vertex[0] = a; |
|
1488 |
29618 |
face->vertex[1] = b; |
|
1489 |
29618 |
face->vertex[2] = c; |
|
1490 |
✓✗✓✗ ✓✗ |
29618 |
face->n = (b->w - a->w).cross(c->w - a->w); |
1491 |
✓✗ | 29618 |
FCL_REAL l = face->n.norm(); |
1492 |
|||
1493 |
✓✗ | 29618 |
if (l > Eigen::NumTraits<FCL_REAL>::epsilon()) { |
1494 |
✓✗ | 29618 |
face->n /= l; |
1495 |
|||
1496 |
✓✗✓✓ ✓✓ |
55126 |
if (!(getEdgeDist(face, a, b, face->d) || |
1497 |
✓✗✓✓ |
25508 |
getEdgeDist(face, b, c, face->d) || |
1498 |
✓✗✓✓ |
19650 |
getEdgeDist(face, c, a, face->d))) { |
1499 |
✓✗ | 14686 |
face->d = a->w.dot(face->n); |
1500 |
} |
||
1501 |
|||
1502 |
✓✓✓✗ |
29618 |
if (forced || face->d >= -tolerance) |
1503 |
29618 |
return face; |
|
1504 |
else |
||
1505 |
status = NonConvex; |
||
1506 |
} else |
||
1507 |
status = Degenerated; |
||
1508 |
|||
1509 |
hull.remove(face); |
||
1510 |
stock.append(face); |
||
1511 |
return NULL; |
||
1512 |
} |
||
1513 |
|||
1514 |
✗✓ | 26 |
status = stock.root ? OutOfVertices : OutOfFaces; |
1515 |
26 |
return NULL; |
|
1516 |
} |
||
1517 |
|||
1518 |
/** @brief Find the best polytope face to split */ |
||
1519 |
6292 |
EPA::SimplexF* EPA::findBest() { |
|
1520 |
6292 |
SimplexF* minf = hull.root; |
|
1521 |
6292 |
FCL_REAL mind = minf->d * minf->d; |
|
1522 |
✓✓ | 189440 |
for (SimplexF* f = minf->l[1]; f; f = f->l[1]) { |
1523 |
183148 |
FCL_REAL sqd = f->d * f->d; |
|
1524 |
✓✓ | 183148 |
if (sqd < mind) { |
1525 |
12603 |
minf = f; |
|
1526 |
12603 |
mind = sqd; |
|
1527 |
} |
||
1528 |
} |
||
1529 |
6292 |
return minf; |
|
1530 |
} |
||
1531 |
|||
1532 |
574 |
EPA::Status EPA::evaluate(GJK& gjk, const Vec3f& guess) { |
|
1533 |
574 |
GJK::Simplex& simplex = *gjk.getSimplex(); |
|
1534 |
✓✗ | 574 |
support_func_guess_t hint(gjk.support_hint); |
1535 |
✓✓✓✗ ✓✗✓✓ |
574 |
if ((simplex.rank > 1) && gjk.encloseOrigin()) { |
1536 |
✗✓ | 572 |
while (hull.root) { |
1537 |
SimplexF* f = hull.root; |
||
1538 |
hull.remove(f); |
||
1539 |
stock.append(f); |
||
1540 |
} |
||
1541 |
|||
1542 |
572 |
status = Valid; |
|
1543 |
572 |
nextsv = 0; |
|
1544 |
|||
1545 |
✓✗ | 572 |
if ((simplex.vertex[0]->w - simplex.vertex[3]->w) |
1546 |
✓✗✓✗ |
1144 |
.dot((simplex.vertex[1]->w - simplex.vertex[3]->w) |
1547 |
✓✗✓✗ ✓✓ |
1144 |
.cross(simplex.vertex[2]->w - simplex.vertex[3]->w)) < 0) { |
1548 |
77 |
SimplexV* tmp = simplex.vertex[0]; |
|
1549 |
77 |
simplex.vertex[0] = simplex.vertex[1]; |
|
1550 |
77 |
simplex.vertex[1] = tmp; |
|
1551 |
} |
||
1552 |
|||
1553 |
SimplexF* tetrahedron[] = { |
||
1554 |
✓✗ | 572 |
newFace(simplex.vertex[0], simplex.vertex[1], simplex.vertex[2], true), |
1555 |
1144 |
newFace(simplex.vertex[1], simplex.vertex[0], simplex.vertex[3], true), |
|
1556 |
1144 |
newFace(simplex.vertex[2], simplex.vertex[1], simplex.vertex[3], true), |
|
1557 |
✓✗✓✗ ✓✗ |
572 |
newFace(simplex.vertex[0], simplex.vertex[2], simplex.vertex[3], true)}; |
1558 |
|||
1559 |
✓✗ | 572 |
if (hull.count == 4) { |
1560 |
✓✗ | 572 |
SimplexF* best = findBest(); // find the best face (the face with the |
1561 |
// minimum distance to origin) to split |
||
1562 |
✓✗ | 572 |
SimplexF outer = *best; |
1563 |
572 |
size_t pass = 0; |
|
1564 |
572 |
size_t iterations = 0; |
|
1565 |
|||
1566 |
// set the face connectivity |
||
1567 |
572 |
bind(tetrahedron[0], 0, tetrahedron[1], 0); |
|
1568 |
572 |
bind(tetrahedron[0], 1, tetrahedron[2], 0); |
|
1569 |
572 |
bind(tetrahedron[0], 2, tetrahedron[3], 0); |
|
1570 |
572 |
bind(tetrahedron[1], 1, tetrahedron[3], 2); |
|
1571 |
572 |
bind(tetrahedron[1], 2, tetrahedron[2], 1); |
|
1572 |
572 |
bind(tetrahedron[2], 2, tetrahedron[3], 1); |
|
1573 |
|||
1574 |
572 |
status = Valid; |
|
1575 |
✓✗ | 6292 |
for (; iterations < max_iterations; ++iterations) { |
1576 |
✗✓ | 6292 |
if (nextsv >= max_vertex_num) { |
1577 |
status = OutOfVertices; |
||
1578 |
572 |
break; |
|
1579 |
} |
||
1580 |
|||
1581 |
6292 |
SimplexHorizon horizon; |
|
1582 |
6292 |
SimplexV* w = &sv_store[nextsv++]; |
|
1583 |
6292 |
bool valid = true; |
|
1584 |
6292 |
best->pass = ++pass; |
|
1585 |
// At the moment, SimplexF.n is always normalized. This could be revised |
||
1586 |
// in the future... |
||
1587 |
✓✗ | 6292 |
gjk.getSupport(best->n, true, *w, hint); |
1588 |
✓✗ | 6292 |
FCL_REAL wdist = best->n.dot(w->w) - best->d; |
1589 |
✓✓ | 6292 |
if (wdist <= tolerance) { |
1590 |
536 |
status = AccuracyReached; |
|
1591 |
536 |
break; |
|
1592 |
} |
||
1593 |
✓✓✓✓ |
22990 |
for (size_t j = 0; (j < 3) && valid; ++j) |
1594 |
✓✗ | 17234 |
valid &= expand(pass, w, best->f[j], best->e[j], horizon); |
1595 |
|||
1596 |
✓✓✗✓ |
5756 |
if (!valid || horizon.nf < 3) { |
1597 |
// The status has already been set by the expand function. |
||
1598 |
✗✓ | 36 |
assert(!(status & Valid)); |
1599 |
36 |
break; |
|
1600 |
} |
||
1601 |
// need to add the edge connectivity between first and last faces |
||
1602 |
5720 |
bind(horizon.ff, 2, horizon.cf, 1); |
|
1603 |
5720 |
hull.remove(best); |
|
1604 |
5720 |
stock.append(best); |
|
1605 |
✓✗ | 5720 |
best = findBest(); |
1606 |
✓✗ | 5720 |
outer = *best; |
1607 |
} |
||
1608 |
|||
1609 |
✓✗ | 572 |
normal = outer.n; |
1610 |
572 |
depth = outer.d; |
|
1611 |
572 |
result.rank = 3; |
|
1612 |
572 |
result.vertex[0] = outer.vertex[0]; |
|
1613 |
572 |
result.vertex[1] = outer.vertex[1]; |
|
1614 |
572 |
result.vertex[2] = outer.vertex[2]; |
|
1615 |
572 |
return status; |
|
1616 |
} |
||
1617 |
} |
||
1618 |
|||
1619 |
// FallBack when the simplex given by GJK is of rank 1. |
||
1620 |
// Since the simplex only contains support points which convex |
||
1621 |
// combination describe the origin, the point in the simplex is actually |
||
1622 |
// the origin. |
||
1623 |
2 |
status = FallBack; |
|
1624 |
// TODO: define a better normal |
||
1625 |
✓✗✓✗ ✓✗ |
2 |
assert(simplex.rank == 1 && simplex.vertex[0]->w.isZero(gjk.getTolerance())); |
1626 |
✓✗✓✗ |
2 |
normal = -guess; |
1627 |
✓✗ | 2 |
FCL_REAL nl = normal.norm(); |
1628 |
✓✗ | 2 |
if (nl > 0) |
1629 |
✓✗ | 2 |
normal /= nl; |
1630 |
else |
||
1631 |
normal = Vec3f(1, 0, 0); |
||
1632 |
2 |
depth = 0; |
|
1633 |
2 |
result.rank = 1; |
|
1634 |
2 |
result.vertex[0] = simplex.vertex[0]; |
|
1635 |
2 |
return status; |
|
1636 |
} |
||
1637 |
|||
1638 |
/** @brief the goal is to add a face connecting vertex w and face edge f[e] */ |
||
1639 |
37536 |
bool EPA::expand(size_t pass, SimplexV* w, SimplexF* f, size_t e, |
|
1640 |
SimplexHorizon& horizon) { |
||
1641 |
static const size_t nexti[] = {1, 2, 0}; |
||
1642 |
static const size_t previ[] = {2, 0, 1}; |
||
1643 |
|||
1644 |
✓✓ | 37536 |
if (f->pass == pass) { |
1645 |
10 |
status = InvalidHull; |
|
1646 |
10 |
return false; |
|
1647 |
} |
||
1648 |
|||
1649 |
37526 |
const size_t e1 = nexti[e]; |
|
1650 |
|||
1651 |
// case 1: the new face is not degenerated, i.e., the new face is not coplanar |
||
1652 |
// with the old face f. |
||
1653 |
✓✗ | 37526 |
if (f->n.dot(w->w - f->vertex[e]->w) < |
1654 |
✓✓ | 37526 |
-Eigen::NumTraits<FCL_REAL>::epsilon()) { |
1655 |
27356 |
SimplexF* nf = newFace(f->vertex[e1], f->vertex[e], w, false); |
|
1656 |
✓✓ | 27356 |
if (nf) { |
1657 |
// add face-face connectivity |
||
1658 |
27330 |
bind(nf, 0, f, e); |
|
1659 |
|||
1660 |
// if there is last face in the horizon, then need to add another |
||
1661 |
// connectivity, i.e. the edge connecting the current new add edge and the |
||
1662 |
// last new add edge. This does not finish all the connectivities because |
||
1663 |
// the final face need to connect with the first face, this will be |
||
1664 |
// handled in the evaluate function. Notice the face is anti-clockwise, so |
||
1665 |
// the edges are 0 (bottom), 1 (right), 2 (left) |
||
1666 |
✓✓ | 27330 |
if (horizon.cf) |
1667 |
21578 |
bind(nf, 2, horizon.cf, 1); |
|
1668 |
else |
||
1669 |
5752 |
horizon.ff = nf; |
|
1670 |
|||
1671 |
27330 |
horizon.cf = nf; |
|
1672 |
27330 |
++horizon.nf; |
|
1673 |
27330 |
return true; |
|
1674 |
} |
||
1675 |
26 |
return false; |
|
1676 |
} |
||
1677 |
|||
1678 |
// case 2: the new face is coplanar with the old face f. We need to add two |
||
1679 |
// faces and delete the old face |
||
1680 |
10170 |
const size_t e2 = previ[e]; |
|
1681 |
10170 |
f->pass = pass; |
|
1682 |
✓✓✓✓ |
20302 |
if (expand(pass, w, f->f[e1], f->e[e1], horizon) && |
1683 |
✓✓ | 10132 |
expand(pass, w, f->f[e2], f->e[e2], horizon)) { |
1684 |
10068 |
hull.remove(f); |
|
1685 |
10068 |
stock.append(f); |
|
1686 |
10068 |
return true; |
|
1687 |
} |
||
1688 |
102 |
return false; |
|
1689 |
} |
||
1690 |
|||
1691 |
564 |
bool EPA::getClosestPoints(const MinkowskiDiff& shape, Vec3f& w0, Vec3f& w1) { |
|
1692 |
564 |
bool res = details::getClosestPoints(result, w0, w1); |
|
1693 |
✗✓ | 564 |
if (!res) return false; |
1694 |
564 |
details::inflate<false>(shape, w0, w1); |
|
1695 |
564 |
return true; |
|
1696 |
} |
||
1697 |
|||
1698 |
} // namespace details |
||
1699 |
|||
1700 |
} // namespace fcl |
||
1701 |
|||
1702 |
} // namespace hpp |
Generated by: GCOVR (Version 4.2) |