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