Directory: | ./ |
---|---|
File: | src/narrowphase/support_functions.cpp |
Date: | 2025-05-02 10:16:21 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 308 | 477 | 64.6% |
Branches: | 372 | 898 | 41.4% |
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 | * Copyright (c) 2021-2024, INRIA | ||
7 | * All rights reserved. | ||
8 | * | ||
9 | * Redistribution and use in source and binary forms, with or without | ||
10 | * modification, are permitted provided that the following conditions | ||
11 | * are met: | ||
12 | * | ||
13 | * * Redistributions of source code must retain the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer. | ||
15 | * * Redistributions in binary form must reproduce the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer in the documentation and/or other materials provided | ||
18 | * with the distribution. | ||
19 | * * Neither the name of Open Source Robotics Foundation nor the names of its | ||
20 | * contributors may be used to endorse or promote products derived | ||
21 | * from this software without specific prior written permission. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
27 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
28 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
29 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
30 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
31 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
33 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
34 | * POSSIBILITY OF SUCH DAMAGE. | ||
35 | */ | ||
36 | |||
37 | /** \authors Jia Pan, Florent Lamiraux, Josef Mirabel, Louis Montaut */ | ||
38 | |||
39 | #include "coal/narrowphase/support_functions.h" | ||
40 | |||
41 | #include <algorithm> | ||
42 | |||
43 | namespace coal { | ||
44 | namespace details { | ||
45 | |||
46 | // ============================================================================ | ||
47 | #define CALL_GET_SHAPE_SUPPORT(ShapeType) \ | ||
48 | getShapeSupport<_SupportOptions>(static_cast<const ShapeType*>(shape), dir, \ | ||
49 | support, hint, support_data) | ||
50 | |||
51 | template <int _SupportOptions> | ||
52 | 35076 | Vec3s getSupport(const ShapeBase* shape, const Vec3s& dir, int& hint) { | |
53 |
1/2✓ Branch 1 taken 17538 times.
✗ Branch 2 not taken.
|
35076 | Vec3s support; |
54 |
1/2✓ Branch 1 taken 17538 times.
✗ Branch 2 not taken.
|
35076 | ShapeSupportData support_data; |
55 |
9/12✓ Branch 1 taken 17538 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 170 times.
✓ Branch 4 taken 2711 times.
✓ Branch 5 taken 2695 times.
✓ Branch 6 taken 2592 times.
✓ Branch 7 taken 2775 times.
✓ Branch 8 taken 2799 times.
✓ Branch 9 taken 2800 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 996 times.
✗ Branch 12 not taken.
|
35076 | switch (shape->getNodeType()) { |
56 | 340 | case GEOM_TRIANGLE: | |
57 |
1/2✓ Branch 1 taken 170 times.
✗ Branch 2 not taken.
|
340 | CALL_GET_SHAPE_SUPPORT(TriangleP); |
58 | 340 | break; | |
59 | 5422 | case GEOM_BOX: | |
60 |
1/2✓ Branch 1 taken 2711 times.
✗ Branch 2 not taken.
|
5422 | CALL_GET_SHAPE_SUPPORT(Box); |
61 | 5422 | break; | |
62 | 5390 | case GEOM_SPHERE: | |
63 |
1/2✓ Branch 1 taken 2695 times.
✗ Branch 2 not taken.
|
5390 | CALL_GET_SHAPE_SUPPORT(Sphere); |
64 | 5390 | break; | |
65 | 5184 | case GEOM_ELLIPSOID: | |
66 |
1/2✓ Branch 1 taken 2592 times.
✗ Branch 2 not taken.
|
5184 | CALL_GET_SHAPE_SUPPORT(Ellipsoid); |
67 | 5184 | break; | |
68 | 5550 | case GEOM_CAPSULE: | |
69 |
1/2✓ Branch 1 taken 2775 times.
✗ Branch 2 not taken.
|
5550 | CALL_GET_SHAPE_SUPPORT(Capsule); |
70 | 5550 | break; | |
71 | 5598 | case GEOM_CONE: | |
72 |
1/2✓ Branch 1 taken 2799 times.
✗ Branch 2 not taken.
|
5598 | CALL_GET_SHAPE_SUPPORT(Cone); |
73 | 5598 | break; | |
74 | 5600 | case GEOM_CYLINDER: | |
75 |
1/2✓ Branch 1 taken 2800 times.
✗ Branch 2 not taken.
|
5600 | CALL_GET_SHAPE_SUPPORT(Cylinder); |
76 | 5600 | break; | |
77 | ✗ | case GEOM_CONVEX16: | |
78 | ✗ | CALL_GET_SHAPE_SUPPORT(ConvexBaseTpl<Triangle16::IndexType>); | |
79 | ✗ | break; | |
80 | 1992 | case GEOM_CONVEX32: | |
81 |
1/2✓ Branch 1 taken 996 times.
✗ Branch 2 not taken.
|
1992 | CALL_GET_SHAPE_SUPPORT(ConvexBaseTpl<Triangle32::IndexType>); |
82 | 1992 | break; | |
83 | ✗ | case GEOM_PLANE: | |
84 | case GEOM_HALFSPACE: | ||
85 | default: | ||
86 | ✗ | support.setZero(); | |
87 | ; // nothing | ||
88 | } | ||
89 | |||
90 | 70152 | return support; | |
91 | } | ||
92 | #undef CALL_GET_SHAPE_SUPPORT | ||
93 | |||
94 | // Explicit instantiation | ||
95 | // clang-format off | ||
96 | template COAL_DLLAPI Vec3s getSupport<SupportOptions::NoSweptSphere>(const ShapeBase*, const Vec3s&, int&); | ||
97 | |||
98 | template COAL_DLLAPI Vec3s getSupport<SupportOptions::WithSweptSphere>(const ShapeBase*, const Vec3s&, int&); | ||
99 | // clang-format on | ||
100 | |||
101 | // ============================================================================ | ||
102 | #define getShapeSupportTplInstantiation(ShapeType) \ | ||
103 | template COAL_DLLAPI void getShapeSupport<SupportOptions::NoSweptSphere>( \ | ||
104 | const ShapeType* shape_, const Vec3s& dir, Vec3s& support, int& hint, \ | ||
105 | ShapeSupportData& support_data); \ | ||
106 | \ | ||
107 | template COAL_DLLAPI void getShapeSupport<SupportOptions::WithSweptSphere>( \ | ||
108 | const ShapeType* shape_, const Vec3s& dir, Vec3s& support, int& hint, \ | ||
109 | ShapeSupportData& support_data); | ||
110 | |||
111 | // ============================================================================ | ||
112 | template <int _SupportOptions> | ||
113 | 272242094 | void getShapeSupport(const TriangleP* triangle, const Vec3s& dir, | |
114 | Vec3s& support, int& /*unused*/, | ||
115 | ShapeSupportData& /*unused*/) { | ||
116 | 272242094 | Scalar dota = dir.dot(triangle->a); | |
117 | 272242094 | Scalar dotb = dir.dot(triangle->b); | |
118 | 272242094 | Scalar dotc = dir.dot(triangle->c); | |
119 |
2/2✓ Branch 0 taken 73521453 times.
✓ Branch 1 taken 62599594 times.
|
272242094 | if (dota > dotb) { |
120 |
2/2✓ Branch 0 taken 31137824 times.
✓ Branch 1 taken 42383629 times.
|
147042906 | if (dotc > dota) { |
121 | 62275648 | support = triangle->c; | |
122 | } else { | ||
123 | 84767258 | support = triangle->a; | |
124 | } | ||
125 | } else { | ||
126 |
2/2✓ Branch 0 taken 19651552 times.
✓ Branch 1 taken 42948042 times.
|
125199188 | if (dotc > dotb) { |
127 | 39303104 | support = triangle->c; | |
128 | } else { | ||
129 | 85896084 | support = triangle->b; | |
130 | } | ||
131 | } | ||
132 | |||
133 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
134 |
2/4✓ Branch 3 taken 170 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 170 times.
✗ Branch 7 not taken.
|
340 | support += triangle->getSweptSphereRadius() * dir.normalized(); |
135 | } | ||
136 | 272242094 | } | |
137 | getShapeSupportTplInstantiation(TriangleP); | ||
138 | |||
139 | // ============================================================================ | ||
140 | template <int _SupportOptions> | ||
141 | 8169442 | void getShapeSupport(const Box* box, const Vec3s& dir, Vec3s& support, | |
142 | int& /*unused*/, ShapeSupportData& /*unused*/) { | ||
143 | // The inflate value is simply to make the specialized functions with box | ||
144 | // have a preferred side for edge cases. | ||
145 |
3/6✓ Branch 0 taken 27 times.
✓ Branch 1 taken 4084694 times.
✓ Branch 3 taken 27 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
8169496 | static const Scalar inflate = |
146 |
5/8✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 27 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 23 times.
✓ Branch 10 taken 4 times.
|
108 | (dir.array() == 0).any() ? 1 + Scalar(1e-10) : 1; |
147 | static const Scalar dummy_precision = | ||
148 | Eigen::NumTraits<Scalar>::dummy_precision(); | ||
149 |
4/8✓ Branch 1 taken 4084721 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4084721 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4084721 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 4084721 times.
✗ Branch 11 not taken.
|
8169442 | Vec3s support1 = (dir.array() > dummy_precision).select(box->halfSide, 0); |
150 |
3/6✓ Branch 1 taken 4084721 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4084721 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4084721 times.
✗ Branch 8 not taken.
|
16338884 | Vec3s support2 = |
151 |
2/4✓ Branch 1 taken 4084721 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4084721 times.
✗ Branch 5 not taken.
|
16338884 | (dir.array() < -dummy_precision).select(-inflate * box->halfSide, 0); |
152 |
3/6✓ Branch 1 taken 4084721 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4084721 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4084721 times.
✗ Branch 8 not taken.
|
8169442 | support.noalias() = support1 + support2; |
153 | |||
154 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
155 |
3/6✓ Branch 1 taken 36487 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 36487 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 36487 times.
✗ Branch 9 not taken.
|
72974 | support += box->getSweptSphereRadius() * dir.normalized(); |
156 | } | ||
157 | 8169442 | } | |
158 | getShapeSupportTplInstantiation(Box); | ||
159 | |||
160 | // ============================================================================ | ||
161 | template <int _SupportOptions> | ||
162 | 384924 | void getShapeSupport(const Sphere* sphere, const Vec3s& dir, Vec3s& support, | |
163 | int& /*unused*/, ShapeSupportData& /*unused*/) { | ||
164 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
165 |
2/4✓ Branch 2 taken 2695 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2695 times.
✗ Branch 6 not taken.
|
10780 | support.noalias() = |
166 |
1/2✓ Branch 2 taken 2695 times.
✗ Branch 3 not taken.
|
10780 | (sphere->radius + sphere->getSweptSphereRadius()) * dir.normalized(); |
167 | } else { | ||
168 | 379534 | support.setZero(); | |
169 | } | ||
170 | |||
171 | COAL_UNUSED_VARIABLE(sphere); | ||
172 | COAL_UNUSED_VARIABLE(dir); | ||
173 | 384924 | } | |
174 | getShapeSupportTplInstantiation(Sphere); | ||
175 | |||
176 | // ============================================================================ | ||
177 | template <int _SupportOptions> | ||
178 | 2192268 | void getShapeSupport(const Ellipsoid* ellipsoid, const Vec3s& dir, | |
179 | Vec3s& support, int& /*unused*/, | ||
180 | ShapeSupportData& /*unused*/) { | ||
181 |
2/4✓ Branch 1 taken 1096134 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1096134 times.
✗ Branch 5 not taken.
|
2192268 | Scalar a2 = ellipsoid->radii[0] * ellipsoid->radii[0]; |
182 |
2/4✓ Branch 1 taken 1096134 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1096134 times.
✗ Branch 5 not taken.
|
2192268 | Scalar b2 = ellipsoid->radii[1] * ellipsoid->radii[1]; |
183 |
2/4✓ Branch 1 taken 1096134 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1096134 times.
✗ Branch 5 not taken.
|
2192268 | Scalar c2 = ellipsoid->radii[2] * ellipsoid->radii[2]; |
184 | |||
185 |
4/8✓ Branch 1 taken 1096134 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1096134 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1096134 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1096134 times.
✗ Branch 11 not taken.
|
2192268 | Vec3s v(a2 * dir[0], b2 * dir[1], c2 * dir[2]); |
186 | |||
187 |
1/2✓ Branch 1 taken 1096134 times.
✗ Branch 2 not taken.
|
2192268 | Scalar d = std::sqrt(v.dot(dir)); |
188 | |||
189 |
2/4✓ Branch 1 taken 1096134 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1096134 times.
✗ Branch 5 not taken.
|
2192268 | support = v / d; |
190 | |||
191 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
192 |
3/6✓ Branch 1 taken 63356 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 63356 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 63356 times.
✗ Branch 9 not taken.
|
126712 | support += ellipsoid->getSweptSphereRadius() * dir.normalized(); |
193 | } | ||
194 | 2192268 | } | |
195 | getShapeSupportTplInstantiation(Ellipsoid); | ||
196 | |||
197 | // ============================================================================ | ||
198 | template <int _SupportOptions> | ||
199 | 1053698 | void getShapeSupport(const Capsule* capsule, const Vec3s& dir, Vec3s& support, | |
200 | int& /*unused*/, ShapeSupportData& /*unused*/) { | ||
201 | static const Scalar dummy_precision = | ||
202 | Eigen::NumTraits<Scalar>::dummy_precision(); | ||
203 | 1053698 | support.setZero(); | |
204 |
2/2✓ Branch 1 taken 287055 times.
✓ Branch 2 taken 239794 times.
|
1053698 | if (dir[2] > dummy_precision) { |
205 | 574110 | support[2] = capsule->halfLength; | |
206 |
2/2✓ Branch 1 taken 180904 times.
✓ Branch 2 taken 58890 times.
|
479588 | } else if (dir[2] < -dummy_precision) { |
207 | 361808 | support[2] = -capsule->halfLength; | |
208 | } | ||
209 | |||
210 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
211 |
1/2✓ Branch 2 taken 31366 times.
✗ Branch 3 not taken.
|
125464 | support += |
212 |
1/2✓ Branch 2 taken 31366 times.
✗ Branch 3 not taken.
|
62732 | (capsule->radius + capsule->getSweptSphereRadius()) * dir.normalized(); |
213 | } | ||
214 | 1053698 | } | |
215 | getShapeSupportTplInstantiation(Capsule); | ||
216 | |||
217 | // ============================================================================ | ||
218 | template <int _SupportOptions> | ||
219 | 140294 | void getShapeSupport(const Cone* cone, const Vec3s& dir, Vec3s& support, | |
220 | int& /*unused*/, ShapeSupportData& /*unused*/) { | ||
221 | static const Scalar dummy_precision = | ||
222 | Eigen::NumTraits<Scalar>::dummy_precision(); | ||
223 | |||
224 | // The cone radius is, for -h < z < h, (h - z) * r / (2*h) | ||
225 | // The inflate value is simply to make the specialized functions with cone | ||
226 | // have a preferred side for edge cases. | ||
227 | static const Scalar inflate = 1 + Scalar(1e-10); | ||
228 | 140294 | Scalar h = cone->halfLength; | |
229 | 140294 | Scalar r = cone->radius; | |
230 | |||
231 |
4/6✓ Branch 1 taken 70147 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 70147 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 172 times.
✓ Branch 7 taken 69975 times.
|
140294 | if (dir.head<2>().isZero(dummy_precision)) { |
232 |
2/4✓ Branch 1 taken 172 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 172 times.
✗ Branch 5 not taken.
|
344 | support.head<2>().setZero(); |
233 |
3/4✓ Branch 1 taken 172 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 52 times.
✓ Branch 4 taken 120 times.
|
344 | if (dir[2] > dummy_precision) { |
234 |
1/2✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
|
104 | support[2] = h; |
235 | } else { | ||
236 |
1/2✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
|
240 | support[2] = -inflate * h; |
237 | } | ||
238 | } else { | ||
239 |
4/8✓ Branch 1 taken 69975 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 69975 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 69975 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 69975 times.
✗ Branch 11 not taken.
|
139950 | Scalar zdist = dir[0] * dir[0] + dir[1] * dir[1]; |
240 |
2/4✓ Branch 1 taken 69975 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 69975 times.
✗ Branch 5 not taken.
|
139950 | Scalar len = zdist + dir[2] * dir[2]; |
241 | 139950 | zdist = std::sqrt(zdist); | |
242 | |||
243 |
3/4✓ Branch 1 taken 69975 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 35483 times.
✓ Branch 4 taken 34492 times.
|
139950 | if (dir[2] <= 0) { |
244 | 70966 | Scalar rad = r / zdist; | |
245 |
4/8✓ Branch 1 taken 35483 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 35483 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 35483 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 35483 times.
✗ Branch 11 not taken.
|
70966 | support.head<2>() = rad * dir.head<2>(); |
246 |
1/2✓ Branch 1 taken 35483 times.
✗ Branch 2 not taken.
|
70966 | support[2] = -h; |
247 | } else { | ||
248 | 68984 | len = std::sqrt(len); | |
249 | 68984 | Scalar sin_a = r / std::sqrt(r * r + 4 * h * h); | |
250 | |||
251 |
3/4✓ Branch 1 taken 34492 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9356 times.
✓ Branch 4 taken 25136 times.
|
68984 | if (dir[2] > len * sin_a) |
252 |
3/6✓ Branch 1 taken 9356 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9356 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 9356 times.
✗ Branch 8 not taken.
|
18712 | support << 0, 0, h; |
253 | else { | ||
254 | 50272 | Scalar rad = r / zdist; | |
255 |
4/8✓ Branch 1 taken 25136 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 25136 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 25136 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 25136 times.
✗ Branch 11 not taken.
|
50272 | support.head<2>() = rad * dir.head<2>(); |
256 |
1/2✓ Branch 1 taken 25136 times.
✗ Branch 2 not taken.
|
50272 | support[2] = -h; |
257 | } | ||
258 | } | ||
259 | } | ||
260 | |||
261 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
262 |
3/6✓ Branch 1 taken 39450 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 39450 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 39450 times.
✗ Branch 9 not taken.
|
78900 | support += cone->getSweptSphereRadius() * dir.normalized(); |
263 | } | ||
264 | 140294 | } | |
265 | getShapeSupportTplInstantiation(Cone); | ||
266 | |||
267 | // ============================================================================ | ||
268 | template <int _SupportOptions> | ||
269 | 3739390 | void getShapeSupport(const Cylinder* cylinder, const Vec3s& dir, Vec3s& support, | |
270 | int& /*unused*/, ShapeSupportData& /*unused*/) { | ||
271 | static const Scalar dummy_precision = | ||
272 | Eigen::NumTraits<Scalar>::dummy_precision(); | ||
273 | |||
274 | // The inflate value is simply to make the specialized functions with cylinder | ||
275 | // have a preferred side for edge cases. | ||
276 | static const Scalar inflate = 1 + Scalar(1e-10); | ||
277 | 3739390 | Scalar half_h = cylinder->halfLength; | |
278 | 3739390 | Scalar r = cylinder->radius; | |
279 | |||
280 |
2/4✓ Branch 1 taken 1869695 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1869695 times.
✗ Branch 5 not taken.
|
3739390 | const bool dir_is_aligned_with_z = dir.head<2>().isZero(dummy_precision); |
281 |
2/2✓ Branch 0 taken 510 times.
✓ Branch 1 taken 1869185 times.
|
3739390 | if (dir_is_aligned_with_z) half_h *= inflate; |
282 | |||
283 |
3/4✓ Branch 1 taken 1869695 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 771939 times.
✓ Branch 4 taken 1097756 times.
|
3739390 | if (dir[2] > dummy_precision) { |
284 |
1/2✓ Branch 1 taken 771939 times.
✗ Branch 2 not taken.
|
1543878 | support[2] = half_h; |
285 |
3/4✓ Branch 1 taken 1097756 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 781777 times.
✓ Branch 4 taken 315979 times.
|
2195512 | } else if (dir[2] < -dummy_precision) { |
286 |
1/2✓ Branch 1 taken 781777 times.
✗ Branch 2 not taken.
|
1563554 | support[2] = -half_h; |
287 | } else { | ||
288 |
1/2✓ Branch 1 taken 315979 times.
✗ Branch 2 not taken.
|
631958 | support[2] = 0; |
289 | 631958 | r *= inflate; | |
290 | } | ||
291 | |||
292 |
2/2✓ Branch 0 taken 510 times.
✓ Branch 1 taken 1869185 times.
|
3739390 | if (dir_is_aligned_with_z) { |
293 |
2/4✓ Branch 1 taken 510 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 510 times.
✗ Branch 5 not taken.
|
1020 | support.head<2>().setZero(); |
294 | } else { | ||
295 |
5/10✓ Branch 1 taken 1869185 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1869185 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1869185 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1869185 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1869185 times.
✗ Branch 14 not taken.
|
3738370 | support.head<2>() = dir.head<2>().normalized() * r; |
296 | } | ||
297 | |||
298 |
5/10✓ Branch 1 taken 1869695 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1869695 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1869695 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1869695 times.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 1869695 times.
|
3739390 | assert(fabs(support[0] * dir[1] - support[1] * dir[0]) < |
299 | sqrt(std::numeric_limits<Scalar>::epsilon())); | ||
300 | |||
301 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
302 |
3/6✓ Branch 1 taken 27196 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 27196 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 27196 times.
✗ Branch 9 not taken.
|
54392 | support += cylinder->getSweptSphereRadius() * dir.normalized(); |
303 | } | ||
304 | 3739390 | } | |
305 | getShapeSupportTplInstantiation(Cylinder); | ||
306 | |||
307 | // ============================================================================ | ||
308 | template <int _SupportOptions, typename IndexType> | ||
309 | ✗ | void getShapeSupportLog(const ConvexBaseTpl<IndexType>* convex, | |
310 | const Vec3s& dir, Vec3s& support, int& hint, | ||
311 | ShapeSupportData& support_data) { | ||
312 | ✗ | assert(convex->neighbors != nullptr && "Convex has no neighbors."); | |
313 | |||
314 | // Use warm start if current support direction is distant from last support | ||
315 | // direction. | ||
316 | ✗ | const Scalar use_warm_start_threshold = Scalar(0.9); | |
317 | ✗ | Vec3s dir_normalized = dir.normalized(); | |
318 | ✗ | if (!support_data.last_dir.isZero() && | |
319 | ✗ | !convex->support_warm_starts.points.empty() && | |
320 | ✗ | support_data.last_dir.dot(dir_normalized) < use_warm_start_threshold) { | |
321 | // Change hint if last dir is too far from current dir. | ||
322 | ✗ | Scalar maxdot = convex->support_warm_starts.points[0].dot(dir); | |
323 | ✗ | hint = int(convex->support_warm_starts.indices[0]); | |
324 | ✗ | for (size_t i = 1; i < convex->support_warm_starts.points.size(); ++i) { | |
325 | ✗ | Scalar dot = convex->support_warm_starts.points[i].dot(dir); | |
326 | ✗ | if (dot > maxdot) { | |
327 | ✗ | maxdot = dot; | |
328 | ✗ | hint = int(convex->support_warm_starts.indices[i]); | |
329 | } | ||
330 | } | ||
331 | } | ||
332 | ✗ | support_data.last_dir = dir_normalized; | |
333 | |||
334 | ✗ | const std::vector<Vec3s>& pts = *(convex->points); | |
335 | typedef typename ConvexBaseTpl<IndexType>::Neighbors Neighbors; | ||
336 | ✗ | const std::vector<Neighbors>& nn = *(convex->neighbors); | |
337 | |||
338 | ✗ | if (hint < 0 || hint >= (int)convex->num_points) { | |
339 | ✗ | hint = 0; | |
340 | } | ||
341 | ✗ | Scalar maxdot = pts[static_cast<size_t>(hint)].dot(dir); | |
342 | ✗ | std::vector<int8_t>& visited = support_data.visited; | |
343 | ✗ | if (support_data.visited.size() == convex->num_points) { | |
344 | ✗ | std::fill(visited.begin(), visited.end(), false); | |
345 | } else { | ||
346 | // std::vector::assign not only assigns the values of the vector but also | ||
347 | // resizes the vector. So if `visited` has not been set up yet, this makes | ||
348 | // sure the size convex's points and visited are identical. | ||
349 | ✗ | support_data.visited.assign(convex->num_points, false); | |
350 | } | ||
351 | ✗ | visited[static_cast<std::size_t>(hint)] = true; | |
352 | // When the first face is orthogonal to dir, all the dot products will be | ||
353 | // equal. Yet, the neighbors must be visited. | ||
354 | ✗ | bool found = true; | |
355 | ✗ | bool loose_check = true; | |
356 | ✗ | while (found) { | |
357 | ✗ | const Neighbors& n = nn[static_cast<size_t>(hint)]; | |
358 | ✗ | found = false; | |
359 | ✗ | IndexType current_vertex_idx = IndexType(hint); | |
360 | ✗ | for (IndexType in = 0; in < n.count; ++in) { | |
361 | ✗ | const IndexType ip = convex->neighbor(current_vertex_idx, in); | |
362 | ✗ | if (visited[ip]) continue; | |
363 | ✗ | visited[ip] = true; | |
364 | ✗ | const Scalar dot = pts[ip].dot(dir); | |
365 | ✗ | bool better = false; | |
366 | ✗ | if (dot > maxdot) { | |
367 | ✗ | better = true; | |
368 | ✗ | loose_check = false; | |
369 | ✗ | } else if (loose_check && dot == maxdot) | |
370 | ✗ | better = true; | |
371 | ✗ | if (better) { | |
372 | ✗ | maxdot = dot; | |
373 | ✗ | hint = static_cast<int>(ip); | |
374 | ✗ | found = true; | |
375 | } | ||
376 | } | ||
377 | } | ||
378 | |||
379 | ✗ | support = pts[static_cast<size_t>(hint)]; | |
380 | |||
381 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
382 | ✗ | support += convex->getSweptSphereRadius() * dir.normalized(); | |
383 | } | ||
384 | } | ||
385 | |||
386 | // ============================================================================ | ||
387 | template <int _SupportOptions, typename IndexType> | ||
388 | 1918502 | void getShapeSupportLinear(const ConvexBaseTpl<IndexType>* convex, | |
389 | const Vec3s& dir, Vec3s& support, int& hint, | ||
390 | ShapeSupportData& /*unused*/) { | ||
391 | 1918502 | const std::vector<Vec3s>& pts = *(convex->points); | |
392 | |||
393 | 1918502 | hint = 0; | |
394 | 1918502 | Scalar maxdot = pts[0].dot(dir); | |
395 |
2/2✓ Branch 0 taken 9353331 times.
✓ Branch 1 taken 959251 times.
|
20625164 | for (int i = 1; i < (int)convex->num_points; ++i) { |
396 | 18706662 | Scalar dot = pts[static_cast<size_t>(i)].dot(dir); | |
397 |
2/2✓ Branch 0 taken 1876494 times.
✓ Branch 1 taken 7476837 times.
|
18706662 | if (dot > maxdot) { |
398 | 3752988 | maxdot = dot; | |
399 | 3752988 | hint = i; | |
400 | } | ||
401 | } | ||
402 | |||
403 | 1918502 | support = pts[static_cast<size_t>(hint)]; | |
404 | |||
405 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
406 |
2/4✓ Branch 3 taken 31048 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 31048 times.
✗ Branch 7 not taken.
|
62096 | support += convex->getSweptSphereRadius() * dir.normalized(); |
407 | } | ||
408 | } | ||
409 | |||
410 | // ============================================================================ | ||
411 | template <int _SupportOptions, typename IndexType> | ||
412 | 2028 | void getShapeSupport(const ConvexBaseTpl<IndexType>* convex, const Vec3s& dir, | |
413 | Vec3s& support, int& hint, | ||
414 | ShapeSupportData& support_data) { | ||
415 | // TODO add benchmark to set a proper value for switching between linear and | ||
416 | // logarithmic. | ||
417 | 4056 | if (convex->num_points > | |
418 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 1014 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1014 times.
|
2028 | ConvexBaseTpl<IndexType>::num_vertices_large_convex_threshold && |
419 | ✗ | convex->neighbors != nullptr) { | |
420 | ✗ | getShapeSupportLog<_SupportOptions>(convex, dir, support, hint, | |
421 | support_data); | ||
422 | } else { | ||
423 | 2028 | getShapeSupportLinear<_SupportOptions>(convex, dir, support, hint, | |
424 | support_data); | ||
425 | } | ||
426 | } | ||
427 | getShapeSupportTplInstantiation(ConvexBaseTpl<Triangle16::IndexType>); | ||
428 | getShapeSupportTplInstantiation(ConvexBaseTpl<Triangle32::IndexType>); | ||
429 | |||
430 | // ============================================================================ | ||
431 | template <int _SupportOptions, typename IndexType> | ||
432 | 1916474 | void getShapeSupport(const SmallConvex<IndexType>* convex, const Vec3s& dir, | |
433 | Vec3s& support, int& hint, | ||
434 | ShapeSupportData& support_data) { | ||
435 | 1916474 | getShapeSupportLinear<_SupportOptions>( | |
436 | reinterpret_cast<const ConvexBaseTpl<IndexType>*>(convex), dir, support, | ||
437 | hint, support_data); | ||
438 | } | ||
439 | getShapeSupportTplInstantiation(SmallConvex<Triangle16::IndexType>); | ||
440 | getShapeSupportTplInstantiation(SmallConvex<Triangle32::IndexType>); | ||
441 | |||
442 | // ============================================================================ | ||
443 | template <int _SupportOptions, typename IndexType> | ||
444 | ✗ | void getShapeSupport(const LargeConvex<IndexType>* convex, const Vec3s& dir, | |
445 | Vec3s& support, int& hint, | ||
446 | ShapeSupportData& support_data) { | ||
447 | ✗ | getShapeSupportLog<_SupportOptions>( | |
448 | reinterpret_cast<const ConvexBaseTpl<IndexType>*>(convex), dir, support, | ||
449 | hint, support_data); | ||
450 | } | ||
451 | getShapeSupportTplInstantiation(LargeConvex<Triangle16::IndexType>); | ||
452 | getShapeSupportTplInstantiation(LargeConvex<Triangle32::IndexType>); | ||
453 | |||
454 | // ============================================================================ | ||
455 | #define CALL_GET_SHAPE_SUPPORT_SET(ShapeType) \ | ||
456 | getShapeSupportSet<_SupportOptions>(static_cast<const ShapeType*>(shape), \ | ||
457 | support_set, hint, support_data, \ | ||
458 | max_num_supports, tol) | ||
459 | |||
460 | template <int _SupportOptions> | ||
461 | ✗ | void getSupportSet(const ShapeBase* shape, SupportSet& support_set, int& hint, | |
462 | size_t max_num_supports, Scalar tol) { | ||
463 | ✗ | ShapeSupportData support_data; | |
464 | ✗ | switch (shape->getNodeType()) { | |
465 | ✗ | case GEOM_TRIANGLE: | |
466 | ✗ | CALL_GET_SHAPE_SUPPORT_SET(TriangleP); | |
467 | ✗ | break; | |
468 | ✗ | case GEOM_BOX: | |
469 | ✗ | CALL_GET_SHAPE_SUPPORT_SET(Box); | |
470 | ✗ | break; | |
471 | ✗ | case GEOM_SPHERE: | |
472 | ✗ | CALL_GET_SHAPE_SUPPORT_SET(Sphere); | |
473 | ✗ | break; | |
474 | ✗ | case GEOM_ELLIPSOID: | |
475 | ✗ | CALL_GET_SHAPE_SUPPORT_SET(Ellipsoid); | |
476 | ✗ | break; | |
477 | ✗ | case GEOM_CAPSULE: | |
478 | ✗ | CALL_GET_SHAPE_SUPPORT_SET(Capsule); | |
479 | ✗ | break; | |
480 | ✗ | case GEOM_CONE: | |
481 | ✗ | CALL_GET_SHAPE_SUPPORT_SET(Cone); | |
482 | ✗ | break; | |
483 | ✗ | case GEOM_CYLINDER: | |
484 | ✗ | CALL_GET_SHAPE_SUPPORT_SET(Cylinder); | |
485 | ✗ | break; | |
486 | ✗ | case GEOM_CONVEX16: | |
487 | ✗ | CALL_GET_SHAPE_SUPPORT_SET(ConvexBaseTpl<Triangle16::IndexType>); | |
488 | ✗ | break; | |
489 | ✗ | case GEOM_CONVEX32: | |
490 | ✗ | CALL_GET_SHAPE_SUPPORT_SET(ConvexBaseTpl<Triangle32::IndexType>); | |
491 | ✗ | break; | |
492 | ✗ | case GEOM_PLANE: | |
493 | case GEOM_HALFSPACE: | ||
494 | default:; // nothing | ||
495 | } | ||
496 | } | ||
497 | #undef CALL_GET_SHAPE_SUPPORT | ||
498 | |||
499 | // Explicit instantiation | ||
500 | // clang-format off | ||
501 | template COAL_DLLAPI void getSupportSet<SupportOptions::NoSweptSphere>(const ShapeBase*, SupportSet&, int&, size_t, Scalar); | ||
502 | |||
503 | template COAL_DLLAPI void getSupportSet<SupportOptions::WithSweptSphere>(const ShapeBase*, SupportSet&, int&, size_t, Scalar); | ||
504 | // clang-format on | ||
505 | |||
506 | // ============================================================================ | ||
507 | #define getShapeSupportSetTplInstantiation(ShapeType) \ | ||
508 | template COAL_DLLAPI void getShapeSupportSet<SupportOptions::NoSweptSphere>( \ | ||
509 | const ShapeType* shape_, SupportSet& support_set, int& hint, \ | ||
510 | ShapeSupportData& data, size_t num_sampled_supports, Scalar tol); \ | ||
511 | \ | ||
512 | template COAL_DLLAPI void \ | ||
513 | getShapeSupportSet<SupportOptions::WithSweptSphere>( \ | ||
514 | const ShapeType* shape_, SupportSet& support_set, int& hint, \ | ||
515 | ShapeSupportData& data, size_t num_sampled_supports, Scalar tol); | ||
516 | |||
517 | // ============================================================================ | ||
518 | template <int _SupportOptions> | ||
519 | ✗ | void getShapeSupportSet(const TriangleP* triangle, SupportSet& support_set, | |
520 | int& hint /*unused*/, | ||
521 | ShapeSupportData& support_data /*unused*/, | ||
522 | size_t /*unused*/, Scalar tol) { | ||
523 | ✗ | assert(tol > 0); | |
524 | ✗ | support_set.clear(); | |
525 | |||
526 | ✗ | Vec3s support; | |
527 | ✗ | const Vec3s& support_dir = support_set.getNormal(); | |
528 | // We simply want to compute the support value, no need to take the | ||
529 | // swept-sphere radius into account. | ||
530 | ✗ | getShapeSupport<SupportOptions::NoSweptSphere>(triangle, support_dir, support, | |
531 | hint, support_data); | ||
532 | ✗ | const Scalar support_value = support.dot(support_dir); | |
533 | |||
534 | ✗ | if (support_value - support_dir.dot(triangle->a) < tol) { | |
535 | // Note: at the moment, it's useless to take into account the | ||
536 | // swept-sphere radius, but in the future we might want to store the | ||
537 | // offsets to the plane in `SupportSet`. | ||
538 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
539 | ✗ | support_set.addPoint(triangle->a + | |
540 | ✗ | triangle->getSweptSphereRadius() * support_dir); | |
541 | } else { | ||
542 | ✗ | support_set.addPoint(triangle->a); | |
543 | } | ||
544 | } | ||
545 | ✗ | if (support_value - support_dir.dot(triangle->b) < tol) { | |
546 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
547 | ✗ | support_set.addPoint(triangle->b + | |
548 | ✗ | triangle->getSweptSphereRadius() * support_dir); | |
549 | } else { | ||
550 | ✗ | support_set.addPoint(triangle->b); | |
551 | } | ||
552 | } | ||
553 | ✗ | if (support_value - support_dir.dot(triangle->c) < tol) { | |
554 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
555 | ✗ | support_set.addPoint(triangle->c + | |
556 | ✗ | triangle->getSweptSphereRadius() * support_dir); | |
557 | } else { | ||
558 | ✗ | support_set.addPoint(triangle->c); | |
559 | } | ||
560 | } | ||
561 | } | ||
562 | getShapeSupportSetTplInstantiation(TriangleP); | ||
563 | |||
564 | // ============================================================================ | ||
565 | template <int _SupportOptions> | ||
566 | 12 | void getShapeSupportSet(const Box* box, SupportSet& support_set, | |
567 | int& hint /*unused*/, ShapeSupportData& support_data, | ||
568 | size_t /*unused*/, Scalar tol) { | ||
569 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
12 | assert(tol > 0); |
570 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
12 | Vec3s support; |
571 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
12 | const Vec3s& support_dir = support_set.getNormal(); |
572 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
12 | getShapeSupport<SupportOptions::NoSweptSphere>(box, support_dir, support, |
573 | hint, support_data); | ||
574 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
12 | const Scalar support_value = support.dot(support_dir); |
575 | |||
576 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
12 | const Scalar x = box->halfSide[0]; |
577 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
12 | const Scalar y = box->halfSide[1]; |
578 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
12 | const Scalar z = box->halfSide[2]; |
579 |
8/16✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 6 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 6 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 6 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 6 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 6 times.
✗ Branch 23 not taken.
|
12 | const std::array<Vec3s, 8> corners = { |
580 | Vec3s(x, y, z), Vec3s(-x, y, z), Vec3s(-x, -y, z), Vec3s(x, -y, z), | ||
581 | Vec3s(x, y, -z), Vec3s(-x, y, -z), Vec3s(-x, -y, -z), Vec3s(x, -y, -z), | ||
582 | }; | ||
583 | |||
584 | 12 | SupportSet::Polygon& polygon = support_data.polygon; | |
585 | 12 | polygon.clear(); | |
586 | 12 | const Transform3s& tf = support_set.tf; | |
587 |
2/2✓ Branch 2 taken 48 times.
✓ Branch 3 taken 6 times.
|
108 | for (const Vec3s& corner : corners) { |
588 |
1/2✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
|
96 | const Scalar val = corner.dot(support_dir); |
589 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
|
96 | if (support_value - val < tol) { |
590 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
591 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
16 | const Vec2s p = |
592 | tf.inverseTransform(corner + | ||
593 | 16 | box->getSweptSphereRadius() * support_dir) | |
594 |
4/8✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 8 times.
✗ Branch 11 not taken.
|
16 | .template head<2>(); |
595 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
16 | polygon.emplace_back(p); |
596 | } else { | ||
597 |
3/6✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 16 times.
✗ Branch 8 not taken.
|
32 | const Vec2s p = tf.inverseTransform(corner).template head<2>(); |
598 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
32 | polygon.emplace_back(p); |
599 | } | ||
600 | } | ||
601 | } | ||
602 |
1/2✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
12 | computeSupportSetConvexHull(polygon, support_set.points()); |
603 | 12 | } | |
604 | getShapeSupportSetTplInstantiation(Box); | ||
605 | |||
606 | // ============================================================================ | ||
607 | template <int _SupportOptions> | ||
608 | ✗ | void getShapeSupportSet(const Sphere* sphere, SupportSet& support_set, | |
609 | int& hint /*unused*/, | ||
610 | ShapeSupportData& support_data /*unused*/, | ||
611 | size_t /*unused*/, Scalar /*unused*/) { | ||
612 | ✗ | support_set.points().clear(); | |
613 | |||
614 | ✗ | Vec3s support; | |
615 | ✗ | const Vec3s& support_dir = support_set.getNormal(); | |
616 | ✗ | getShapeSupport<_SupportOptions>(sphere, support_dir, support, hint, | |
617 | support_data); | ||
618 | ✗ | support_set.addPoint(support); | |
619 | } | ||
620 | getShapeSupportSetTplInstantiation(Sphere); | ||
621 | |||
622 | // ============================================================================ | ||
623 | template <int _SupportOptions> | ||
624 | ✗ | void getShapeSupportSet(const Ellipsoid* ellipsoid, SupportSet& support_set, | |
625 | int& hint, ShapeSupportData& support_data /*unused*/, | ||
626 | size_t /*unused*/, Scalar /*unused*/) { | ||
627 | ✗ | support_set.points().clear(); | |
628 | |||
629 | ✗ | Vec3s support; | |
630 | ✗ | const Vec3s& support_dir = support_set.getNormal(); | |
631 | ✗ | getShapeSupport<_SupportOptions>(ellipsoid, support_dir, support, hint, | |
632 | support_data); | ||
633 | ✗ | support_set.addPoint(support); | |
634 | } | ||
635 | getShapeSupportSetTplInstantiation(Ellipsoid); | ||
636 | |||
637 | // ============================================================================ | ||
638 | template <int _SupportOptions> | ||
639 | 6 | void getShapeSupportSet(const Capsule* capsule, SupportSet& support_set, | |
640 | int& hint /*unused*/, | ||
641 | ShapeSupportData& support_data /*unused*/, | ||
642 | size_t /*unused*/, Scalar tol) { | ||
643 | // clang-format on | ||
644 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
6 | assert(tol > 0); |
645 | 6 | support_set.points().clear(); | |
646 | |||
647 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | Vec3s support; |
648 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | const Vec3s& support_dir = support_set.getNormal(); |
649 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | getShapeSupport<SupportOptions::NoSweptSphere>(capsule, support_dir, support, |
650 | hint, support_data); | ||
651 | const Scalar support_value = | ||
652 |
3/6✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
|
6 | support_dir.dot(support + capsule->radius * support_dir); |
653 | // The support set of a capsule has either 2 points or 1 point. | ||
654 | // The two candidate points lie at the frontier between the cylinder and | ||
655 | // sphere parts of the capsule. | ||
656 | 6 | const Scalar h = capsule->halfLength; | |
657 | 6 | const Scalar r = capsule->radius; | |
658 |
3/6✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
|
6 | const Vec3s p1(r * support_dir[0], r * support_dir[1], h); |
659 |
3/6✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
|
6 | const Vec3s p2(r * support_dir[0], r * support_dir[1], -h); |
660 |
5/6✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
|
8 | if ((support_value - support_dir.dot(p1) <= tol) && |
661 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
2 | (support_value - support_dir.dot(p2) <= tol)) { |
662 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
663 |
2/4✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
2 | const Vec3s ssr_vec = support_dir * capsule->getSweptSphereRadius(); |
664 |
3/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
|
2 | support_set.addPoint(p1 + ssr_vec); |
665 |
3/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
|
2 | support_set.addPoint(p2 + ssr_vec); |
666 | } else { | ||
667 | ✗ | support_set.addPoint(p1); | |
668 | ✗ | support_set.addPoint(p2); | |
669 | } | ||
670 | } else { | ||
671 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
672 |
2/4✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
|
4 | const Vec3s ssr_vec = support_dir * capsule->getSweptSphereRadius(); |
673 |
3/6✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
|
4 | support_set.addPoint(support + ssr_vec); |
674 | } else { | ||
675 | ✗ | support_set.addPoint(support); | |
676 | } | ||
677 | } | ||
678 | } | ||
679 | getShapeSupportSetTplInstantiation(Capsule); | ||
680 | |||
681 | // ============================================================================ | ||
682 | template <int _SupportOptions> | ||
683 | 6 | void getShapeSupportSet(const Cone* cone, SupportSet& support_set, | |
684 | int& hint /*unused*/, | ||
685 | ShapeSupportData& support_data /*unused*/, | ||
686 | size_t num_sampled_supports, Scalar tol) { | ||
687 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
6 | assert(tol > 0); |
688 | 6 | support_set.points().clear(); | |
689 | |||
690 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | Vec3s support; |
691 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | const Vec3s& support_dir = support_set.getNormal(); |
692 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | getShapeSupport<SupportOptions::NoSweptSphere>(cone, support_dir, support, |
693 | hint, support_data); | ||
694 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | const Scalar support_value = support.dot(support_dir); |
695 | |||
696 | // If the support direction is perpendicular to the cone's basis, there is an | ||
697 | // infinite amount of support points; otherwise there are up to two support | ||
698 | // points (two if direction is perpendicular to the side of the cone and one | ||
699 | // otherwise). | ||
700 | // | ||
701 | // To check this condition, we look at two points on the cone's basis; | ||
702 | // these two points are symmetrical w.r.t the center of the circle. If | ||
703 | // both these points are tol away from the support plane, then all the | ||
704 | // points of the circle are tol away from the support plane. | ||
705 | 6 | const Scalar r = cone->radius; | |
706 | 6 | const Scalar z = -cone->halfLength; | |
707 |
3/6✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
|
6 | const Vec3s p1(r * support_dir[0], r * support_dir[1], z); |
708 |
3/6✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
|
6 | const Vec3s p2(-r * support_dir[0], -r * support_dir[1], z); |
709 | |||
710 |
5/6✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
|
10 | if ((support_value - support_dir.dot(p1) <= tol) && |
711 |
3/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
|
4 | (support_value - support_dir.dot(p2) <= tol)) { |
712 | // If this check passed, support direction is considered perpendicular to | ||
713 | // the basis of the cone. We sample `num_sampled_supports` points on the | ||
714 | // base of the cone. We are guaranteed that these points like at a distance | ||
715 | // tol of the support plane. | ||
716 | 2 | const Scalar angle_increment = | |
717 | 2 | Scalar(2 * EIGEN_PI) / (Scalar(num_sampled_supports)); | |
718 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1 times.
|
26 | for (size_t i = 0; i < num_sampled_supports; ++i) { |
719 | 24 | const Scalar theta = (Scalar)(i)*angle_increment; | |
720 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
24 | Vec3s point_on_cone_base(r * std::cos(theta), r * std::sin(theta), z); |
721 |
3/6✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 12 times.
|
24 | assert(std::abs(support_dir.dot(support - point_on_cone_base)) <= tol); |
722 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
723 |
2/4✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
|
24 | point_on_cone_base += cone->getSweptSphereRadius() * support_dir; |
724 | } | ||
725 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
24 | support_set.addPoint(point_on_cone_base); |
726 | } | ||
727 | } else { | ||
728 | // There are two potential supports to add: the tip of the cone and a point | ||
729 | // on the basis of the cone. We compare each of these points to the support | ||
730 | // value. | ||
731 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
4 | Vec3s cone_tip(0, 0, cone->halfLength); |
732 |
3/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
|
4 | if (support_value - support_dir.dot(cone_tip) <= tol) { |
733 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
734 |
2/4✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
2 | cone_tip += cone->getSweptSphereRadius() * support_dir; |
735 | } | ||
736 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | support_set.addPoint(cone_tip); |
737 | } | ||
738 | |||
739 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
4 | Vec3s point_on_cone_base = Vec3s(cone->radius * support_dir[0], // |
740 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
4 | cone->radius * support_dir[1], // |
741 | z); | ||
742 |
3/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
|
4 | if (support_value - support_dir.dot(point_on_cone_base) <= tol) { |
743 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
744 |
2/4✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
2 | point_on_cone_base += cone->getSweptSphereRadius() * support_dir; |
745 | } | ||
746 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | support_set.addPoint(point_on_cone_base); |
747 | } | ||
748 | } | ||
749 | } | ||
750 | getShapeSupportSetTplInstantiation(Cone); | ||
751 | |||
752 | // ============================================================================ | ||
753 | template <int _SupportOptions> | ||
754 | 8 | void getShapeSupportSet(const Cylinder* cylinder, SupportSet& support_set, | |
755 | int& hint /*unused*/, | ||
756 | ShapeSupportData& support_data /*unused*/, | ||
757 | size_t num_sampled_supports, Scalar tol) { | ||
758 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
8 | assert(tol > 0); |
759 | 8 | support_set.points().clear(); | |
760 | |||
761 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
8 | Vec3s support; |
762 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
8 | const Vec3s& support_dir = support_set.getNormal(); |
763 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
8 | getShapeSupport<SupportOptions::NoSweptSphere>(cylinder, support_dir, support, |
764 | hint, support_data); | ||
765 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
8 | const Scalar support_value = support.dot(support_dir); |
766 | |||
767 | // The following is very similar to what is done for Cone's support set | ||
768 | // computation. | ||
769 | 8 | const Scalar r = cylinder->radius; | |
770 | 8 | const Scalar z = | |
771 |
3/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 1 times.
|
8 | support_dir[2] <= 0 ? -cylinder->halfLength : cylinder->halfLength; |
772 |
3/6✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
|
8 | const Vec3s p1(r * support_dir[0], r * support_dir[1], z); |
773 |
3/6✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
|
8 | const Vec3s p2(-r * support_dir[0], -r * support_dir[1], z); |
774 | |||
775 |
4/6✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 1 times.
|
16 | if ((support_value - support_dir.dot(p1) <= tol) && |
776 |
3/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 1 times.
|
8 | (support_value - support_dir.dot(p2) <= tol)) { |
777 | 6 | const Scalar angle_increment = | |
778 | 6 | Scalar(2 * EIGEN_PI) / (Scalar(num_sampled_supports)); | |
779 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 3 times.
|
78 | for (size_t i = 0; i < num_sampled_supports; ++i) { |
780 | 72 | const Scalar theta = (Scalar)(i)*angle_increment; | |
781 |
1/2✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
72 | Vec3s point_on_cone_base(r * std::cos(theta), r * std::sin(theta), z); |
782 |
3/6✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 36 times.
|
72 | assert(std::abs(support_dir.dot(support - point_on_cone_base)) <= tol); |
783 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
784 |
2/4✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 36 times.
✗ Branch 6 not taken.
|
72 | point_on_cone_base += cylinder->getSweptSphereRadius() * support_dir; |
785 | } | ||
786 |
1/2✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
72 | support_set.addPoint(point_on_cone_base); |
787 | } | ||
788 | } else { | ||
789 | // There are two potential supports to add: one on each circle bases of the | ||
790 | // cylinder. | ||
791 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | Vec3s point_on_lower_circle = Vec3s(cylinder->radius * support_dir[0], // |
792 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | cylinder->radius * support_dir[1], // |
793 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | -cylinder->halfLength); |
794 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
2 | if (support_value - support_dir.dot(point_on_lower_circle) <= tol) { |
795 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
796 |
2/4✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
2 | point_on_lower_circle += cylinder->getSweptSphereRadius() * support_dir; |
797 | } | ||
798 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | support_set.addPoint(point_on_lower_circle); |
799 | } | ||
800 | |||
801 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | Vec3s point_on_upper_circle = Vec3s(cylinder->radius * support_dir[0], // |
802 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | cylinder->radius * support_dir[1], // |
803 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | cylinder->halfLength); |
804 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
2 | if (support_value - support_dir.dot(point_on_upper_circle) <= tol) { |
805 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
806 |
2/4✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
2 | point_on_upper_circle += cylinder->getSweptSphereRadius() * support_dir; |
807 | } | ||
808 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | support_set.addPoint(point_on_upper_circle); |
809 | } | ||
810 | } | ||
811 | } | ||
812 | getShapeSupportSetTplInstantiation(Cylinder); | ||
813 | |||
814 | // ============================================================================ | ||
815 | template <int _SupportOptions, typename IndexType> | ||
816 | 36 | void getShapeSupportSetLinear(const ConvexBaseTpl<IndexType>* convex, | |
817 | SupportSet& support_set, int& hint /*unused*/, | ||
818 | ShapeSupportData& support_data, size_t /*unused*/, | ||
819 | Scalar tol) { | ||
820 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
36 | assert(tol > 0); |
821 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
36 | Vec3s support; |
822 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
36 | const Vec3s& support_dir = support_set.getNormal(); |
823 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
36 | getShapeSupport<SupportOptions::NoSweptSphere>(convex, support_dir, support, |
824 | hint, support_data); | ||
825 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
36 | const Scalar support_value = support_dir.dot(support); |
826 | |||
827 | 36 | const std::vector<Vec3s>& points = *(convex->points); | |
828 | 36 | SupportSet::Polygon& polygon = support_data.polygon; | |
829 | 36 | polygon.clear(); | |
830 | 36 | const Transform3s& tf = support_set.tf; | |
831 |
2/2✓ Branch 5 taken 88 times.
✓ Branch 6 taken 18 times.
|
212 | for (const Vec3s& point : points) { |
832 |
1/2✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
|
176 | const Scalar dot = support_dir.dot(point); |
833 |
2/2✓ Branch 0 taken 52 times.
✓ Branch 1 taken 36 times.
|
176 | if (support_value - dot <= tol) { |
834 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
835 | ✗ | const Vec2s p = | |
836 | tf.inverseTransform(point + | ||
837 | ✗ | convex->getSweptSphereRadius() * support_dir) | |
838 | ✗ | .template head<2>(); | |
839 | ✗ | polygon.emplace_back(p); | |
840 | } else { | ||
841 |
3/6✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 52 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 52 times.
✗ Branch 8 not taken.
|
104 | const Vec2s p = tf.inverseTransform(point).template head<2>(); |
842 |
1/2✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
|
104 | polygon.emplace_back(p); |
843 | } | ||
844 | } | ||
845 | } | ||
846 | |||
847 |
1/2✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
36 | computeSupportSetConvexHull(polygon, support_set.points()); |
848 | } | ||
849 | |||
850 | // ============================================================================ | ||
851 | template <int _SupportOptions, typename IndexType> | ||
852 | ✗ | void convexSupportSetRecurse(const ConvexBaseTpl<IndexType>* convex, | |
853 | const size_t vertex_idx, const Vec3s& support_dir, | ||
854 | const Scalar support_value, const Transform3s& tf, | ||
855 | std::vector<int8_t>& visited, | ||
856 | SupportSet::Polygon& polygon, Scalar tol) { | ||
857 | ✗ | if (visited[vertex_idx]) { | |
858 | ✗ | return; | |
859 | } | ||
860 | |||
861 | ✗ | visited[vertex_idx] = true; | |
862 | ✗ | const std::vector<Vec3s>& points = *(convex->points); | |
863 | ✗ | const Vec3s& point = points[vertex_idx]; | |
864 | ✗ | const Scalar val = point.dot(support_dir); | |
865 | ✗ | Scalar swept_sphere_radius = convex->getSweptSphereRadius(); | |
866 | ✗ | if (support_value - val <= tol) { | |
867 | if (_SupportOptions == SupportOptions::WithSweptSphere) { | ||
868 | ✗ | const Vec2s p = | |
869 | tf.inverseTransform(point + swept_sphere_radius * support_dir) | ||
870 | ✗ | .template head<2>(); | |
871 | ✗ | polygon.emplace_back(p); | |
872 | |||
873 | } else { | ||
874 | ✗ | const Vec2s p = tf.inverseTransform(point).template head<2>(); | |
875 | ✗ | polygon.emplace_back(p); | |
876 | } | ||
877 | |||
878 | typedef typename ConvexBaseTpl<IndexType>::Neighbors Neighbors; | ||
879 | ✗ | const std::vector<Neighbors>& neighbors = *(convex->neighbors); | |
880 | ✗ | const Neighbors& point_neighbors = neighbors[vertex_idx]; | |
881 | ✗ | for (IndexType i = 0; i < point_neighbors.count; ++i) { | |
882 | const IndexType neighbor_index = | ||
883 | ✗ | convex->neighbor(IndexType(vertex_idx), i); | |
884 | ✗ | convexSupportSetRecurse<_SupportOptions, IndexType>( | |
885 | convex, neighbor_index, support_dir, support_value, tf, visited, | ||
886 | polygon, tol); | ||
887 | } | ||
888 | } | ||
889 | } | ||
890 | |||
891 | // ============================================================================ | ||
892 | template <int _SupportOptions, typename IndexType> | ||
893 | ✗ | void getShapeSupportSetLog(const ConvexBaseTpl<IndexType>* convex, | |
894 | SupportSet& support_set, int& hint, | ||
895 | ShapeSupportData& support_data, size_t /*unused*/, | ||
896 | Scalar tol) { | ||
897 | ✗ | assert(tol > 0); | |
898 | ✗ | Vec3s support; | |
899 | ✗ | const Vec3s& support_dir = support_set.getNormal(); | |
900 | ✗ | getShapeSupportLog<SupportOptions::NoSweptSphere>( | |
901 | convex, support_dir, support, hint, support_data); | ||
902 | ✗ | const Scalar support_value = support.dot(support_dir); | |
903 | |||
904 | ✗ | std::vector<int8_t>& visited = support_data.visited; | |
905 | // `visited` is guaranteed to be of right size due to previous call to convex | ||
906 | // log support function. | ||
907 | ✗ | std::fill(support_data.visited.begin(), support_data.visited.end(), false); | |
908 | |||
909 | ✗ | SupportSet::Polygon& polygon = support_data.polygon; | |
910 | ✗ | polygon.clear(); | |
911 | ✗ | const Transform3s& tf = support_set.tf; | |
912 | |||
913 | ✗ | const size_t vertex_idx = (size_t)(hint); | |
914 | ✗ | convexSupportSetRecurse<_SupportOptions, IndexType>( | |
915 | convex, vertex_idx, support_dir, support_value, tf, visited, polygon, | ||
916 | tol); | ||
917 | |||
918 | ✗ | computeSupportSetConvexHull(polygon, support_set.points()); | |
919 | } | ||
920 | |||
921 | // ============================================================================ | ||
922 | template <int _SupportOptions, typename IndexType> | ||
923 | ✗ | void getShapeSupportSet(const ConvexBaseTpl<IndexType>* convex, | |
924 | SupportSet& support_set, int& hint, | ||
925 | ShapeSupportData& support_data, | ||
926 | size_t num_sampled_supports /*unused*/, Scalar tol) { | ||
927 | ✗ | if (convex->num_points > | |
928 | ✗ | ConvexBaseTpl<IndexType>::num_vertices_large_convex_threshold && | |
929 | ✗ | convex->neighbors != nullptr) { | |
930 | ✗ | getShapeSupportSetLog<_SupportOptions>( | |
931 | convex, support_set, hint, support_data, num_sampled_supports, tol); | ||
932 | } else { | ||
933 | ✗ | getShapeSupportSetLinear<_SupportOptions>( | |
934 | convex, support_set, hint, support_data, num_sampled_supports, tol); | ||
935 | } | ||
936 | } | ||
937 | getShapeSupportSetTplInstantiation(ConvexBaseTpl<Triangle16::IndexType>); | ||
938 | getShapeSupportSetTplInstantiation(ConvexBaseTpl<Triangle32::IndexType>); | ||
939 | |||
940 | // ============================================================================ | ||
941 | template <int _SupportOptions, typename IndexType> | ||
942 | 36 | void getShapeSupportSet(const SmallConvex<IndexType>* convex, | |
943 | SupportSet& support_set, int& hint /*unused*/, | ||
944 | ShapeSupportData& support_data /*unused*/, | ||
945 | size_t num_sampled_supports /*unused*/, Scalar tol) { | ||
946 | 36 | getShapeSupportSetLinear<_SupportOptions>( | |
947 | reinterpret_cast<const ConvexBaseTpl<IndexType>*>(convex), support_set, | ||
948 | hint, support_data, num_sampled_supports, tol); | ||
949 | } | ||
950 | getShapeSupportSetTplInstantiation(SmallConvex<Triangle16::IndexType>); | ||
951 | getShapeSupportSetTplInstantiation(SmallConvex<Triangle32::IndexType>); | ||
952 | |||
953 | // ============================================================================ | ||
954 | template <int _SupportOptions, typename IndexType> | ||
955 | ✗ | void getShapeSupportSet(const LargeConvex<IndexType>* convex, | |
956 | SupportSet& support_set, int& hint, | ||
957 | ShapeSupportData& support_data, | ||
958 | size_t num_sampled_supports /*unused*/, Scalar tol) { | ||
959 | ✗ | getShapeSupportSetLog<_SupportOptions>( | |
960 | reinterpret_cast<const ConvexBaseTpl<IndexType>*>(convex), support_set, | ||
961 | hint, support_data, num_sampled_supports, tol); | ||
962 | } | ||
963 | getShapeSupportSetTplInstantiation(LargeConvex<Triangle16::IndexType>); | ||
964 | getShapeSupportSetTplInstantiation(LargeConvex<Triangle32::IndexType>); | ||
965 | |||
966 | // ============================================================================ | ||
967 | 24 | COAL_DLLAPI void computeSupportSetConvexHull(SupportSet::Polygon& cloud, | |
968 | SupportSet::Polygon& cvx_hull) { | ||
969 | 24 | cvx_hull.clear(); | |
970 | |||
971 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 18 times.
|
24 | if (cloud.size() <= 2) { |
972 | // Point or segment, nothing to do. | ||
973 |
2/2✓ Branch 5 taken 12 times.
✓ Branch 6 taken 6 times.
|
18 | for (const Vec2s& point : cloud) { |
974 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | cvx_hull.emplace_back(point); |
975 | } | ||
976 | 14 | return; | |
977 | } | ||
978 | |||
979 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 10 times.
|
18 | if (cloud.size() == 3) { |
980 | // We have a triangle, we only need to arrange it in a counter clockwise | ||
981 | // fashion. | ||
982 | // | ||
983 | // Put the vector which has the lowest y coordinate first. | ||
984 |
4/6✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✓ Branch 9 taken 5 times.
|
8 | if (cloud[0](1) > cloud[1](1)) { |
985 | 3 | std::swap(cloud[0], cloud[1]); | |
986 | } | ||
987 |
4/6✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 7 times.
|
8 | if (cloud[0](1) > cloud[2](1)) { |
988 | 1 | std::swap(cloud[0], cloud[2]); | |
989 | } | ||
990 | 8 | const Vec2s& a = cloud[0]; | |
991 | 8 | const Vec2s& b = cloud[1]; | |
992 | 8 | const Vec2s& c = cloud[2]; | |
993 | const Scalar det = | ||
994 |
8/16✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 8 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 8 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 8 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 8 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 8 times.
✗ Branch 23 not taken.
|
8 | (b(0) - a(0)) * (c(1) - a(1)) - (b(1) - a(1)) * (c(0) - a(0)); |
995 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
8 | if (det < 0) { |
996 | 4 | std::swap(cloud[1], cloud[2]); | |
997 | } | ||
998 | |||
999 |
2/2✓ Branch 5 taken 24 times.
✓ Branch 6 taken 8 times.
|
32 | for (const Vec2s& point : cloud) { |
1000 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | cvx_hull.emplace_back(point); |
1001 | } | ||
1002 | 8 | return; | |
1003 | } | ||
1004 | |||
1005 | // The following is an implementation of the O(nlog(n)) graham scan | ||
1006 | // algorithm, used to compute convex-hulls in 2D. | ||
1007 | // See https://en.wikipedia.org/wiki/Graham_scan | ||
1008 | // | ||
1009 | // Step 1 - Compute first element of the convex-hull by computing the support | ||
1010 | // in the direction (0, -1) (take the element of the set which has the lowest | ||
1011 | // y coordinate). | ||
1012 | 10 | size_t support_idx = 0; | |
1013 |
1/2✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
10 | Scalar support_val = cloud[0](1); |
1014 |
2/2✓ Branch 1 taken 30 times.
✓ Branch 2 taken 10 times.
|
40 | for (size_t i = 1; i < cloud.size(); ++i) { |
1015 |
1/2✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
|
30 | const Scalar val = cloud[i](1); |
1016 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 20 times.
|
30 | if (val < support_val) { |
1017 | 10 | support_val = val; | |
1018 | 10 | support_idx = i; | |
1019 | } | ||
1020 | } | ||
1021 | 10 | std::swap(cloud[0], cloud[support_idx]); | |
1022 | 10 | cvx_hull.clear(); | |
1023 |
1/2✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
10 | cvx_hull.emplace_back(cloud[0]); |
1024 | 10 | const Vec2s& v = cvx_hull[0]; | |
1025 | |||
1026 | // Step 2 - Sort the rest of the point cloud according to the angle made with | ||
1027 | // v. Note: we use stable_sort instead of sort because sort can fail if two | ||
1028 | // values are identical. | ||
1029 |
1/2✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
|
20 | std::stable_sort( |
1030 | 10 | cloud.begin() + 1, cloud.end(), [&v](const Vec2s& p1, const Vec2s& p2) { | |
1031 | // p1 is "smaller" than p2 if det(p1 - v, p2 - v) >= 0 | ||
1032 | const Scalar det = | ||
1033 | 30 | (p1(0) - v(0)) * (p2(1) - v(1)) - (p1(1) - v(1)) * (p2(0) - v(0)); | |
1034 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 30 times.
|
30 | if (std::abs(det) <= Eigen::NumTraits<Scalar>::dummy_precision()) { |
1035 | // If two points are identical or (v, p1, p2) are colinear, p1 is | ||
1036 | // "smaller" if it is closer to v. | ||
1037 | ✗ | return ((p1 - v).squaredNorm() <= (p2 - v).squaredNorm()); | |
1038 | } | ||
1039 | 30 | return det > 0; | |
1040 | }); | ||
1041 | |||
1042 | // Step 3 - We iterate over the now ordered point of cloud and add the points | ||
1043 | // to the cvx-hull if they successively form "left turns" only. A left turn | ||
1044 | // is: considering the last three points of the cvx-hull, if they form a | ||
1045 | // right-hand basis (determinant > 0) then they make a left turn. | ||
1046 | 10 | auto isRightSided = [](const Vec2s& p1, const Vec2s& p2, const Vec2s& p3) { | |
1047 | // Checks if (p2 - p1, p3 - p1) forms a right-sided base based on | ||
1048 | // det(p2 - p1, p3 - p1) | ||
1049 | const Scalar det = | ||
1050 | 10 | (p2(0) - p1(0)) * (p3(1) - p1(1)) - (p2(1) - p1(1)) * (p3(0) - p1(0)); | |
1051 | // Note: we set a dummy precision threshold so that identical points or | ||
1052 | // colinear pionts are not added to the cvx-hull. | ||
1053 | 10 | return det > Eigen::NumTraits<Scalar>::dummy_precision(); | |
1054 | }; | ||
1055 | |||
1056 | // We initialize the cvx-hull algo by adding the first three | ||
1057 | // (distinct) points of the set. | ||
1058 | // These three points are guaranteed, due to the previous sorting, | ||
1059 | // to form a right sided basis, hence to form a left turn. | ||
1060 | 10 | size_t cloud_beginning_idx = 1; | |
1061 |
2/2✓ Branch 1 taken 20 times.
✓ Branch 2 taken 10 times.
|
30 | while (cvx_hull.size() < 3) { |
1062 | 20 | const Vec2s& vec = cloud[cloud_beginning_idx]; | |
1063 |
3/6✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
|
40 | if ((cvx_hull.back() - vec).squaredNorm() > |
1064 | 20 | Eigen::NumTraits<Scalar>::epsilon()) { | |
1065 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | cvx_hull.emplace_back(vec); |
1066 | } | ||
1067 | 20 | ++cloud_beginning_idx; | |
1068 | } | ||
1069 | // The convex-hull should wrap counter-clockwise, i.e. three successive | ||
1070 | // points should always form a right-sided basis. Every time we do a turn | ||
1071 | // in the wrong direction, we remove the last point of the convex-hull. | ||
1072 | // When we do a turn in the correct direction, we add a point to the | ||
1073 | // convex-hull. | ||
1074 |
2/2✓ Branch 1 taken 10 times.
✓ Branch 2 taken 10 times.
|
20 | for (size_t i = cloud_beginning_idx; i < cloud.size(); ++i) { |
1075 | 10 | const Vec2s& vec = cloud[i]; | |
1076 |
2/4✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
|
20 | while (cvx_hull.size() > 1 && |
1077 |
2/4✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
|
10 | !isRightSided(cvx_hull[cvx_hull.size() - 2], |
1078 | 10 | cvx_hull[cvx_hull.size() - 1], vec)) { | |
1079 | ✗ | cvx_hull.pop_back(); | |
1080 | } | ||
1081 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | cvx_hull.emplace_back(vec); |
1082 | } | ||
1083 | } | ||
1084 | |||
1085 | } // namespace details | ||
1086 | } // namespace coal | ||
1087 |