| 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 | 35076 | } | |
| 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 |
3/6✓ Branch 1 taken 170 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 170 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 170 times.
✗ Branch 9 not taken.
|
340 | support += triangle->getSweptSphereRadius() * dir.normalized(); |
| 135 | } | ||
| 136 | 272242094 | } | |
| 137 | getShapeSupportTplInstantiation(TriangleP); | ||
| 138 | |||
| 139 | // ============================================================================ | ||
| 140 | template <int _SupportOptions> | ||
| 141 | 8169536 | 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 4084741 times.
✓ Branch 3 taken 27 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
8169590 | 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 4084768 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4084768 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4084768 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 4084768 times.
✗ Branch 11 not taken.
|
8169536 | Vec3s support1 = (dir.array() > dummy_precision).select(box->halfSide, 0); |
| 150 |
3/6✓ Branch 1 taken 4084768 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4084768 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4084768 times.
✗ Branch 8 not taken.
|
16339072 | Vec3s support2 = |
| 151 |
2/4✓ Branch 1 taken 4084768 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4084768 times.
✗ Branch 5 not taken.
|
16339072 | (dir.array() < -dummy_precision).select(-inflate * box->halfSide, 0); |
| 152 |
3/6✓ Branch 1 taken 4084768 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4084768 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4084768 times.
✗ Branch 8 not taken.
|
8169536 | 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 | 8169536 | } | |
| 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 |
3/6✓ Branch 1 taken 2695 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2695 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2695 times.
✗ Branch 8 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 |
2/4✓ Branch 1 taken 31366 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 31366 times.
✗ Branch 5 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 | 3739496 | 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 | 3739496 | Scalar half_h = cylinder->halfLength; | |
| 278 | 3739496 | Scalar r = cylinder->radius; | |
| 279 | |||
| 280 |
2/4✓ Branch 1 taken 1869748 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1869748 times.
✗ Branch 5 not taken.
|
3739496 | const bool dir_is_aligned_with_z = dir.head<2>().isZero(dummy_precision); |
| 281 |
2/2✓ Branch 0 taken 510 times.
✓ Branch 1 taken 1869238 times.
|
3739496 | if (dir_is_aligned_with_z) half_h *= inflate; |
| 282 | |||
| 283 |
3/4✓ Branch 1 taken 1869748 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 771982 times.
✓ Branch 4 taken 1097766 times.
|
3739496 | if (dir[2] > dummy_precision) { |
| 284 |
1/2✓ Branch 1 taken 771982 times.
✗ Branch 2 not taken.
|
1543964 | support[2] = half_h; |
| 285 |
3/4✓ Branch 1 taken 1097766 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 781787 times.
✓ Branch 4 taken 315979 times.
|
2195532 | } else if (dir[2] < -dummy_precision) { |
| 286 |
1/2✓ Branch 1 taken 781787 times.
✗ Branch 2 not taken.
|
1563574 | 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 1869238 times.
|
3739496 | 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 1869238 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1869238 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1869238 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1869238 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1869238 times.
✗ Branch 14 not taken.
|
3738476 | support.head<2>() = dir.head<2>().normalized() * r; |
| 296 | } | ||
| 297 | |||
| 298 |
5/10✓ Branch 1 taken 1869748 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1869748 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1869748 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1869748 times.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 1869748 times.
|
3739496 | 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 | 3739496 | } | |
| 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 |
3/6✓ Branch 1 taken 31048 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 31048 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 31048 times.
✗ Branch 9 not taken.
|
62096 | support += convex->getSweptSphereRadius() * dir.normalized(); |
| 407 | } | ||
| 408 | 1918502 | } | |
| 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 | 2028 | } | |
| 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 | 1916474 | } | |
| 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 | 6 | } | |
| 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 | 6 | } | |
| 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 | 8 | } | |
| 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 | 36 | } | |
| 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 | 36 | } | |
| 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 |