Directory: | ./ |
---|---|
File: | include/coal/shape/convex.hxx |
Date: | 2025-05-02 10:16:21 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 65 | 165 | 39.4% |
Branches: | 43 | 250 | 17.2% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Software License Agreement (BSD License) | ||
3 | * | ||
4 | * Copyright (c) 2019, CNRS - LAAS | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Redistribution and use in source and binary forms, with or without | ||
8 | * modification, are permitted provided that the following conditions | ||
9 | * are met: | ||
10 | * | ||
11 | * * Redistributions of source code must retain the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer. | ||
13 | * * Redistributions in binary form must reproduce the above | ||
14 | * copyright notice, this list of conditions and the following | ||
15 | * disclaimer in the documentation and/or other materials provided | ||
16 | * with the distribution. | ||
17 | * * Neither the name of Open Source Robotics Foundation nor the names of its | ||
18 | * contributors may be used to endorse or promote products derived | ||
19 | * from this software without specific prior written permission. | ||
20 | * | ||
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
25 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
31 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
32 | * POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | /** \author Joseph Mirabel */ | ||
36 | |||
37 | #ifndef COAL_SHAPE_CONVEX_HXX | ||
38 | #define COAL_SHAPE_CONVEX_HXX | ||
39 | |||
40 | #include <set> | ||
41 | #include <vector> | ||
42 | #include <iostream> | ||
43 | |||
44 | #include "coal/shape/convex.h" | ||
45 | |||
46 | namespace coal { | ||
47 | |||
48 | template <typename PolygonT> | ||
49 | 169 | ConvexTpl<PolygonT>::ConvexTpl(std::shared_ptr<std::vector<Vec3s>> points_, | |
50 | unsigned int num_points_, | ||
51 | std::shared_ptr<std::vector<PolygonT>> polygons_, | ||
52 | unsigned int num_polygons_) | ||
53 | 169 | : Base(), polygons(polygons_), num_polygons(num_polygons_) { | |
54 |
1/2✓ Branch 2 taken 135 times.
✗ Branch 3 not taken.
|
169 | this->initialize(points_, num_points_); |
55 |
1/2✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
|
169 | this->fillNeighbors(); |
56 |
1/2✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
|
169 | this->buildSupportWarmStart(); |
57 | 169 | } | |
58 | |||
59 | template <typename PolygonT> | ||
60 | 18 | ConvexTpl<PolygonT>& ConvexTpl<PolygonT>::operator=(const ConvexTpl& other) { | |
61 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | if (this != &other) { |
62 | // Copy the base | ||
63 | 18 | this->base() = other.base(); | |
64 | |||
65 | // Shallow copy the polygons | ||
66 | 18 | this->num_polygons = other.num_polygons; | |
67 | 18 | this->polygons = other.polygons; | |
68 | } | ||
69 | |||
70 | 18 | return *this; | |
71 | } | ||
72 | |||
73 | template <typename PolygonT> | ||
74 | template <typename OtherPolygonT> | ||
75 | 4 | void ConvexTpl<PolygonT>::deepcopy(const ConvexTpl<PolygonT>* source, | |
76 | ConvexTpl<OtherPolygonT>* copy) { | ||
77 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
4 | if (source == nullptr || copy == nullptr) { |
78 | ✗ | return; | |
79 | } | ||
80 | |||
81 | // Deep copy the base | ||
82 | 4 | Base::deepcopy(source, copy); | |
83 | |||
84 | // Deep copy the polygons | ||
85 | typedef typename OtherPolygonT::IndexType OtherIndexType; | ||
86 | 4 | copy->num_polygons = source->num_polygons; | |
87 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
4 | if (source->polygons != nullptr) { |
88 | 4 | const std::vector<PolygonT>& source_polygons = *(source->polygons); | |
89 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
8 | copy->polygons.reset( |
90 |
2/4✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
|
8 | new std::vector<OtherPolygonT>(source_polygons.size())); |
91 | 4 | std::vector<OtherPolygonT>& copy_polygons = *(copy->polygons); | |
92 |
2/2✓ Branch 1 taken 18 times.
✓ Branch 2 taken 2 times.
|
40 | for (std::size_t i = 0; i < source_polygons.size(); ++i) { |
93 |
1/2✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
36 | copy_polygons[i] = source_polygons[i].template cast<OtherIndexType>(); |
94 | } | ||
95 | } else { | ||
96 | ✗ | copy->polygons.reset(); | |
97 | } | ||
98 | } | ||
99 | |||
100 | template <typename PolygonT> | ||
101 | 61182 | void ConvexTpl<PolygonT>::set(std::shared_ptr<std::vector<Vec3s>> points_, | |
102 | unsigned int num_points_, | ||
103 | std::shared_ptr<std::vector<PolygonT>> polygons_, | ||
104 | unsigned int num_polygons_) { | ||
105 |
1/2✓ Branch 2 taken 61182 times.
✗ Branch 3 not taken.
|
61182 | Base::set(points_, num_points_); |
106 | |||
107 | 61182 | this->num_polygons = num_polygons_; | |
108 | 61182 | this->polygons = polygons_; | |
109 | |||
110 | 61182 | this->fillNeighbors(); | |
111 | 61182 | this->buildSupportWarmStart(); | |
112 | 61182 | } | |
113 | |||
114 | template <typename PolygonT> | ||
115 | ✗ | Matrix3s ConvexTpl<PolygonT>::computeMomentofInertia() const { | |
116 | typedef typename PolygonT::size_type size_type; | ||
117 | typedef typename PolygonT::IndexType IndexType; | ||
118 | |||
119 | ✗ | Matrix3s C = Matrix3s::Zero(); | |
120 | |||
121 | ✗ | Matrix3s C_canonical; | |
122 | ✗ | C_canonical << Scalar(1 / 60.0), // | |
123 | ✗ | Scalar(1 / 120.0), // | |
124 | ✗ | Scalar(1 / 120.0), // | |
125 | ✗ | Scalar(1 / 120.0), // | |
126 | ✗ | Scalar(1 / 60.0), // | |
127 | ✗ | Scalar(1 / 120.0), // | |
128 | ✗ | Scalar(1 / 120.0), // | |
129 | ✗ | Scalar(1 / 120.0), // | |
130 | ✗ | Scalar(1 / 60.0); | |
131 | |||
132 | ✗ | if (!(points.get())) { | |
133 | ✗ | std::cerr << "Error in `ConvexTpl::computeMomentofInertia`! ConvexTpl has " | |
134 | "no vertices." | ||
135 | ✗ | << std::endl; | |
136 | ✗ | return C; | |
137 | } | ||
138 | ✗ | const std::vector<Vec3s>& points_ = *points; | |
139 | ✗ | if (!(polygons.get())) { | |
140 | ✗ | std::cerr << "Error in `ConvexTpl::computeMomentofInertia`! ConvexTpl has " | |
141 | "no polygons." | ||
142 | ✗ | << std::endl; | |
143 | ✗ | return C; | |
144 | } | ||
145 | ✗ | const std::vector<PolygonT>& polygons_ = *polygons; | |
146 | ✗ | for (unsigned int i = 0; i < num_polygons; ++i) { | |
147 | ✗ | const PolygonT& polygon = polygons_[i]; | |
148 | |||
149 | // compute the center of the polygon | ||
150 | ✗ | Vec3s plane_center(0, 0, 0); | |
151 | ✗ | for (size_type j = 0; j < polygon.size(); ++j) | |
152 | ✗ | plane_center += points_[polygon[(IndexType)j]]; | |
153 | ✗ | plane_center /= Scalar(polygon.size()); | |
154 | |||
155 | // compute the volume of tetrahedron making by neighboring two points, the | ||
156 | // plane center and the reference point (zero) of the convex shape | ||
157 | ✗ | const Vec3s& v3 = plane_center; | |
158 | ✗ | for (size_type j = 0; j < polygon.size(); ++j) { | |
159 | ✗ | IndexType e_first = polygon[static_cast<IndexType>(j)]; | |
160 | IndexType e_second = | ||
161 | ✗ | polygon[static_cast<IndexType>((j + 1) % polygon.size())]; | |
162 | ✗ | const Vec3s& v1 = points_[e_first]; | |
163 | ✗ | const Vec3s& v2 = points_[e_second]; | |
164 | ✗ | Matrix3s A; | |
165 | ✗ | A << v1.transpose(), v2.transpose(), | |
166 | ✗ | v3.transpose(); // this is A' in the original document | |
167 | ✗ | C += A.transpose() * C_canonical * A * (v1.cross(v2)).dot(v3); | |
168 | } | ||
169 | } | ||
170 | |||
171 | ✗ | return C.trace() * Matrix3s::Identity() - C; | |
172 | } | ||
173 | |||
174 | template <typename PolygonT> | ||
175 | ✗ | Vec3s ConvexTpl<PolygonT>::computeCOM() const { | |
176 | typedef typename PolygonT::size_type size_type; | ||
177 | typedef typename PolygonT::IndexType IndexType; | ||
178 | |||
179 | ✗ | Vec3s com(0, 0, 0); | |
180 | ✗ | Scalar vol = 0; | |
181 | ✗ | if (!(points.get())) { | |
182 | ✗ | std::cerr << "Error in `ConvexTpl::computeCOM`! ConvexTpl has no vertices." | |
183 | ✗ | << std::endl; | |
184 | ✗ | return com; | |
185 | } | ||
186 | ✗ | const std::vector<Vec3s>& points_ = *points; | |
187 | ✗ | if (!(polygons.get())) { | |
188 | ✗ | std::cerr << "Error in `ConvexTpl::computeCOM`! ConvexTpl has no polygons." | |
189 | ✗ | << std::endl; | |
190 | ✗ | return com; | |
191 | } | ||
192 | ✗ | const std::vector<PolygonT>& polygons_ = *polygons; | |
193 | ✗ | for (unsigned int i = 0; i < num_polygons; ++i) { | |
194 | ✗ | const PolygonT& polygon = polygons_[i]; | |
195 | // compute the center of the polygon | ||
196 | ✗ | Vec3s plane_center(0, 0, 0); | |
197 | ✗ | for (size_type j = 0; j < polygon.size(); ++j) | |
198 | ✗ | plane_center += points_[polygon[(IndexType)j]]; | |
199 | ✗ | plane_center /= Scalar(polygon.size()); | |
200 | |||
201 | // compute the volume of tetrahedron making by neighboring two points, the | ||
202 | // plane center and the reference point (zero) of the convex shape | ||
203 | ✗ | const Vec3s& v3 = plane_center; | |
204 | ✗ | for (size_type j = 0; j < polygon.size(); ++j) { | |
205 | ✗ | IndexType e_first = polygon[static_cast<IndexType>(j)]; | |
206 | IndexType e_second = | ||
207 | ✗ | polygon[static_cast<IndexType>((j + 1) % polygon.size())]; | |
208 | ✗ | const Vec3s& v1 = points_[e_first]; | |
209 | ✗ | const Vec3s& v2 = points_[e_second]; | |
210 | ✗ | Scalar d_six_vol = (v1.cross(v2)).dot(v3); | |
211 | ✗ | vol += d_six_vol; | |
212 | ✗ | com += (points_[e_first] + points_[e_second] + plane_center) * d_six_vol; | |
213 | } | ||
214 | } | ||
215 | |||
216 | ✗ | return com / (vol * 4); // here we choose zero as the reference | |
217 | } | ||
218 | |||
219 | template <typename PolygonT> | ||
220 | ✗ | Scalar ConvexTpl<PolygonT>::computeVolume() const { | |
221 | typedef typename PolygonT::size_type size_type; | ||
222 | typedef typename PolygonT::IndexType IndexType; | ||
223 | |||
224 | ✗ | Scalar vol = 0; | |
225 | ✗ | if (!(points.get())) { | |
226 | std::cerr | ||
227 | ✗ | << "Error in `ConvexTpl::computeVolume`! ConvexTpl has no vertices." | |
228 | ✗ | << std::endl; | |
229 | ✗ | return vol; | |
230 | } | ||
231 | ✗ | const std::vector<Vec3s>& points_ = *points; | |
232 | ✗ | if (!(polygons.get())) { | |
233 | std::cerr | ||
234 | ✗ | << "Error in `ConvexTpl::computeVolume`! ConvexTpl has no polygons." | |
235 | ✗ | << std::endl; | |
236 | ✗ | return vol; | |
237 | } | ||
238 | ✗ | const std::vector<PolygonT>& polygons_ = *polygons; | |
239 | ✗ | for (unsigned int i = 0; i < num_polygons; ++i) { | |
240 | ✗ | const PolygonT& polygon = polygons_[i]; | |
241 | |||
242 | // compute the center of the polygon | ||
243 | ✗ | Vec3s plane_center(0, 0, 0); | |
244 | ✗ | for (size_type j = 0; j < polygon.size(); ++j) | |
245 | ✗ | plane_center += points_[polygon[(IndexType)j]]; | |
246 | ✗ | plane_center /= Scalar(polygon.size()); | |
247 | |||
248 | // compute the volume of tetrahedron making by neighboring two points, the | ||
249 | // plane center and the reference point (zero point) of the convex shape | ||
250 | ✗ | const Vec3s& v3 = plane_center; | |
251 | ✗ | for (size_type j = 0; j < polygon.size(); ++j) { | |
252 | ✗ | IndexType e_first = polygon[static_cast<IndexType>(j)]; | |
253 | IndexType e_second = | ||
254 | ✗ | polygon[static_cast<IndexType>((j + 1) % polygon.size())]; | |
255 | ✗ | const Vec3s& v1 = points_[e_first]; | |
256 | ✗ | const Vec3s& v2 = points_[e_second]; | |
257 | ✗ | Scalar d_six_vol = (v1.cross(v2)).dot(v3); | |
258 | ✗ | vol += d_six_vol; | |
259 | } | ||
260 | } | ||
261 | |||
262 | ✗ | return vol / 6; | |
263 | } | ||
264 | |||
265 | template <typename PolygonT> | ||
266 | 61420 | void ConvexTpl<PolygonT>::fillNeighbors() { | |
267 |
3/6✓ Branch 2 taken 61318 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 61318 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 61318 times.
✗ Branch 9 not taken.
|
61420 | neighbors.reset(new std::vector<Neighbors>(num_points)); |
268 | |||
269 | typedef typename PolygonT::size_type size_type; | ||
270 | typedef typename PolygonT::IndexType IndexType; | ||
271 | |||
272 |
1/2✓ Branch 2 taken 61318 times.
✗ Branch 3 not taken.
|
61420 | std::vector<std::set<IndexType>> nneighbors(num_points); |
273 | 61420 | unsigned int c_nneighbors = 0; | |
274 | |||
275 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 61318 times.
|
61420 | if (!(polygons.get())) { |
276 | std::cerr | ||
277 | ✗ | << "Error in `ConvexTpl::fillNeighbors`! ConvexTpl has no polygons." | |
278 | ✗ | << std::endl; | |
279 | } | ||
280 | 61420 | const std::vector<PolygonT>& polygons_ = *polygons; | |
281 |
2/2✓ Branch 0 taken 491805 times.
✓ Branch 1 taken 61318 times.
|
554366 | for (unsigned int l = 0; l < num_polygons; ++l) { |
282 | 492946 | const PolygonT& polygon = polygons_[l]; | |
283 | 492946 | const size_type n = polygon.size(); | |
284 | |||
285 |
2/2✓ Branch 1 taken 1475439 times.
✓ Branch 2 taken 491805 times.
|
1971832 | for (size_type j = 0; j < polygon.size(); ++j) { |
286 |
2/2✓ Branch 0 taken 491805 times.
✓ Branch 1 taken 983634 times.
|
1478886 | size_type i = (j == 0) ? n - 1 : j - 1; |
287 |
2/2✓ Branch 0 taken 983634 times.
✓ Branch 1 taken 491805 times.
|
1478886 | size_type k = (j == n - 1) ? 0 : j + 1; |
288 | 1478886 | IndexType pi = polygon[(IndexType)i], pj = polygon[(IndexType)j], | |
289 | 1478886 | pk = polygon[(IndexType)k]; | |
290 | // Update neighbors of pj; | ||
291 |
3/4✓ Branch 2 taken 1475439 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 768312 times.
✓ Branch 5 taken 707127 times.
|
1478886 | if (nneighbors[pj].count(pi) == 0) { |
292 | 770069 | c_nneighbors++; | |
293 |
1/2✓ Branch 2 taken 768312 times.
✗ Branch 3 not taken.
|
770069 | nneighbors[pj].insert(pi); |
294 | } | ||
295 |
3/4✓ Branch 2 taken 1475439 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 768312 times.
✓ Branch 5 taken 707127 times.
|
1478886 | if (nneighbors[pj].count(pk) == 0) { |
296 | 770069 | c_nneighbors++; | |
297 |
1/2✓ Branch 2 taken 768312 times.
✗ Branch 3 not taken.
|
770069 | nneighbors[pj].insert(pk); |
298 | } | ||
299 | } | ||
300 | } | ||
301 | |||
302 |
3/6✓ Branch 2 taken 61318 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 61318 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 61318 times.
✗ Branch 9 not taken.
|
61420 | nneighbors_.reset(new std::vector<IndexType>(c_nneighbors)); |
303 | |||
304 | 61420 | std::vector<Neighbors>& neighbors_ = *neighbors; | |
305 | 61420 | std::vector<IndexType>& nneighbors__ = *(nneighbors_); | |
306 | 61420 | IndexType begin_id = 0; | |
307 |
2/2✓ Branch 0 taken 368551 times.
✓ Branch 1 taken 61318 times.
|
430758 | for (unsigned int i = 0; i < num_points; ++i) { |
308 | 369338 | Neighbors& n = neighbors_[i]; | |
309 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 368551 times.
|
369338 | if (nneighbors[i].size() >= (std::numeric_limits<unsigned char>::max)()) |
310 | ✗ | COAL_THROW_PRETTY("Too many neighbors.", std::logic_error); | |
311 | 369338 | n.count = (unsigned char)nneighbors[i].size(); | |
312 | 369338 | n.begin_id = begin_id; | |
313 | 369338 | IndexType j = 0; | |
314 |
2/2✓ Branch 5 taken 1536624 times.
✓ Branch 6 taken 368551 times.
|
1909476 | for (IndexType idx : nneighbors[i]) { |
315 | 1540138 | nneighbors__[n.begin_id + j] = idx; | |
316 | 1540138 | j++; | |
317 | } | ||
318 | 369338 | begin_id += n.count; | |
319 | } | ||
320 | 61420 | } | |
321 | |||
322 | } // namespace coal | ||
323 | |||
324 | #endif | ||
325 |