1 // =============================================================================
2 // PROJECT CHRONO - http://projectchrono.org
3 //
4 // Copyright (c) 2014 projectchrono.org
5 // All rights reserved.
6 //
7 // Use of this source code is governed by a BSD-style license that can be found
8 // in the LICENSE file at the top level of the distribution and at
9 // http://projectchrono.org/license-chrono.txt.
10 //
11 // =============================================================================
12 // Authors: Radu Serban, Hammad Mazhar, Arman Pazouki
13 // =============================================================================
14 //
15 // =============================================================================
16
17 #include "chrono/utils/ChUtilsCreators.h"
18
19 #include "chrono/assets/ChBoxShape.h"
20 #include "chrono/assets/ChCapsuleShape.h"
21 #include "chrono/assets/ChConeShape.h"
22 #include "chrono/assets/ChCylinderShape.h"
23 #include "chrono/assets/ChEllipsoidShape.h"
24 #include "chrono/assets/ChRoundedBoxShape.h"
25 #include "chrono/assets/ChRoundedCylinderShape.h"
26 #include "chrono/assets/ChSphereShape.h"
27 #include "chrono/assets/ChTriangleMeshShape.h"
28
29 #include "chrono_thirdparty/tinyobjloader/tiny_obj_loader.h"
30
31 namespace chrono {
32 using namespace geometry;
33 using namespace collision;
34 namespace utils {
35
36 // -----------------------------------------------------------------------------
37
AddSphereGeometry(ChBody * body,std::shared_ptr<ChMaterialSurface> material,double radius,const ChVector<> & pos,const ChQuaternion<> & rot,bool visualization)38 void AddSphereGeometry(ChBody* body,
39 std::shared_ptr<ChMaterialSurface> material,
40 double radius,
41 const ChVector<>& pos,
42 const ChQuaternion<>& rot,
43 bool visualization) {
44 body->GetCollisionModel()->AddSphere(material, radius, pos);
45
46 if (visualization) {
47 auto sphere = chrono_types::make_shared<ChSphereShape>();
48 sphere->GetSphereGeometry().rad = radius;
49 sphere->Pos = pos;
50 sphere->Rot = rot;
51 body->GetAssets().push_back(sphere);
52 }
53 }
54
55 // -----------------------------------------------------------------------------
56
AddEllipsoidGeometry(ChBody * body,std::shared_ptr<ChMaterialSurface> material,const ChVector<> & size,const ChVector<> & pos,const ChQuaternion<> & rot,bool visualization)57 void AddEllipsoidGeometry(ChBody* body,
58 std::shared_ptr<ChMaterialSurface> material,
59 const ChVector<>& size,
60 const ChVector<>& pos,
61 const ChQuaternion<>& rot,
62 bool visualization) {
63 body->GetCollisionModel()->AddEllipsoid(material, size.x(), size.y(), size.z(), pos, rot);
64
65 if (visualization) {
66 auto ellipsoid = chrono_types::make_shared<ChEllipsoidShape>();
67 ellipsoid->GetEllipsoidGeometry().rad = size;
68 ellipsoid->Pos = pos;
69 ellipsoid->Rot = rot;
70 body->GetAssets().push_back(ellipsoid);
71 }
72 }
73
74 // -----------------------------------------------------------------------------
75
AddBoxGeometry(ChBody * body,std::shared_ptr<ChMaterialSurface> material,const ChVector<> & size,const ChVector<> & pos,const ChQuaternion<> & rot,bool visualization)76 void AddBoxGeometry(ChBody* body,
77 std::shared_ptr<ChMaterialSurface> material,
78 const ChVector<>& size,
79 const ChVector<>& pos,
80 const ChQuaternion<>& rot,
81 bool visualization) {
82 body->GetCollisionModel()->AddBox(material, size.x(), size.y(), size.z(), pos, rot);
83
84 if (visualization) {
85 auto box = chrono_types::make_shared<ChBoxShape>();
86 box->GetBoxGeometry().Size = size;
87 box->Pos = pos;
88 box->Rot = rot;
89 body->GetAssets().push_back(box);
90 }
91 }
92
93 // -----------------------------------------------------------------------------
94
AddBiSphereGeometry(ChBody * body,std::shared_ptr<ChMaterialSurface> material,double radius,double cDist,const ChVector<> & pos,const ChQuaternion<> & rot,bool visualization)95 void AddBiSphereGeometry(ChBody* body,
96 std::shared_ptr<ChMaterialSurface> material,
97 double radius,
98 double cDist,
99 const ChVector<>& pos,
100 const ChQuaternion<>& rot,
101 bool visualization) {
102 ChFrame<> frame;
103 frame = ChFrame<>(pos, rot);
104 if (ChBodyAuxRef* body_ar = dynamic_cast<ChBodyAuxRef*>(body)) {
105 frame = frame >> body_ar->GetFrame_REF_to_COG();
106 }
107 const ChVector<>& position = frame.GetPos();
108
109 AddSphereGeometry(body, material, radius, position + ChVector<>(0, 0.5 * cDist, 0), rot, visualization);
110 AddSphereGeometry(body, material, radius, position - ChVector<>(0, 0.5 * cDist, 0), rot, visualization);
111 }
112
113 // -----------------------------------------------------------------------------
114
AddCapsuleGeometry(ChBody * body,std::shared_ptr<ChMaterialSurface> material,double radius,double hlen,const ChVector<> & pos,const ChQuaternion<> & rot,bool visualization)115 void AddCapsuleGeometry(ChBody* body,
116 std::shared_ptr<ChMaterialSurface> material,
117 double radius,
118 double hlen,
119 const ChVector<>& pos,
120 const ChQuaternion<>& rot,
121 bool visualization) {
122 body->GetCollisionModel()->AddCapsule(material, radius, hlen, pos, rot);
123
124 if (visualization) {
125 auto capsule = chrono_types::make_shared<ChCapsuleShape>();
126 capsule->GetCapsuleGeometry().rad = radius;
127 capsule->GetCapsuleGeometry().hlen = hlen;
128 capsule->Pos = pos;
129 capsule->Rot = rot;
130 body->GetAssets().push_back(capsule);
131 }
132 }
133
134 // -----------------------------------------------------------------------------
135
AddCylinderGeometry(ChBody * body,std::shared_ptr<ChMaterialSurface> material,double radius,double hlen,const ChVector<> & pos,const ChQuaternion<> & rot,bool visualization)136 void AddCylinderGeometry(ChBody* body,
137 std::shared_ptr<ChMaterialSurface> material,
138 double radius,
139 double hlen,
140 const ChVector<>& pos,
141 const ChQuaternion<>& rot,
142 bool visualization) {
143 body->GetCollisionModel()->AddCylinder(material, radius, radius, hlen, pos, rot);
144
145 if (visualization) {
146 auto cylinder = chrono_types::make_shared<ChCylinderShape>();
147 cylinder->GetCylinderGeometry().rad = radius;
148 cylinder->GetCylinderGeometry().p1 = ChVector<>(0, hlen, 0);
149 cylinder->GetCylinderGeometry().p2 = ChVector<>(0, -hlen, 0);
150 cylinder->Pos = pos;
151 cylinder->Rot = rot;
152 body->GetAssets().push_back(cylinder);
153 }
154 }
155
156 // -----------------------------------------------------------------------------
157
AddConeGeometry(ChBody * body,std::shared_ptr<ChMaterialSurface> material,double radius,double height,const ChVector<> & pos,const ChQuaternion<> & rot,bool visualization)158 void AddConeGeometry(ChBody* body,
159 std::shared_ptr<ChMaterialSurface> material,
160 double radius,
161 double height,
162 const ChVector<>& pos,
163 const ChQuaternion<>& rot,
164 bool visualization) {
165 ChFrame<> frame;
166 frame = ChFrame<>(pos, rot);
167 if (ChBodyAuxRef* body_ar = dynamic_cast<ChBodyAuxRef*>(body)) {
168 frame = frame >> body_ar->GetFrame_REF_to_COG();
169 }
170 const ChVector<>& position = frame.GetPos();
171
172 ChVector<> posCollisionModel = position + ChVector<>(0, 0.25 * height, 0);
173
174 body->GetCollisionModel()->AddCone(material, radius, radius, height, posCollisionModel, rot);
175
176 if (visualization) {
177 auto cone = chrono_types::make_shared<ChConeShape>();
178 cone->GetConeGeometry().rad = ChVector<>(radius, height, radius);
179 cone->Pos = posCollisionModel;
180 cone->Rot = rot;
181 body->GetAssets().push_back(cone);
182 }
183 }
184
185 // -----------------------------------------------------------------------------
186
AddTriangleMeshGeometry(ChBody * body,std::shared_ptr<ChMaterialSurface> material,const std::string & obj_filename,const std::string & name,const ChVector<> & pos,const ChQuaternion<> & rot,bool visualization)187 bool AddTriangleMeshGeometry(ChBody* body,
188 std::shared_ptr<ChMaterialSurface> material,
189 const std::string& obj_filename,
190 const std::string& name,
191 const ChVector<>& pos,
192 const ChQuaternion<>& rot,
193 bool visualization) {
194 auto trimesh = chrono_types::make_shared<geometry::ChTriangleMeshConnected>();
195 if (!trimesh->LoadWavefrontMesh(obj_filename, false, false))
196 return false;
197
198 for (int i = 0; i < trimesh->m_vertices.size(); i++)
199 trimesh->m_vertices[i] = pos + rot.Rotate(trimesh->m_vertices[i]);
200
201 body->GetCollisionModel()->AddTriangleMesh(material, trimesh, false, false);
202
203 if (visualization) {
204 auto trimesh_shape = chrono_types::make_shared<ChTriangleMeshShape>();
205 trimesh_shape->SetMesh(trimesh);
206 trimesh_shape->SetName(name);
207 trimesh_shape->Pos = ChVector<>(0, 0, 0);
208 trimesh_shape->Rot = ChQuaternion<>(1, 0, 0, 0);
209 body->GetAssets().push_back(trimesh_shape);
210 }
211
212 return true;
213 }
214
215 // -----------------------------------------------------------------------------
216
AddTriangleMeshConvexDecomposition(ChBody * body,std::shared_ptr<ChMaterialSurface> material,const std::string & obj_filename,const std::string & name,const ChVector<> & pos,const ChQuaternion<> & rot,float skin_thickness,bool use_original_asset)217 bool AddTriangleMeshConvexDecomposition(ChBody* body,
218 std::shared_ptr<ChMaterialSurface> material,
219 const std::string& obj_filename,
220 const std::string& name,
221 const ChVector<>& pos,
222 const ChQuaternion<>& rot,
223 float skin_thickness,
224 bool use_original_asset) {
225 auto trimesh = chrono_types::make_shared<geometry::ChTriangleMeshConnected>();
226 if (!trimesh->LoadWavefrontMesh(obj_filename, true, false))
227 return false;
228
229 for (int i = 0; i < trimesh->m_vertices.size(); i++) {
230 trimesh->m_vertices[i] = pos + rot.Rotate(trimesh->m_vertices[i]);
231 }
232 collision::ChConvexDecompositionHACDv2 decomposition;
233
234 int hacd_maxhullcount = 512;
235 int hacd_maxhullmerge = 256;
236 int hacd_maxhullvertexes = 64;
237 float hacd_concavity = 0.2f;
238 float hacd_smallclusterthreshold = 0.0f;
239 float hacd_fusetolerance = 1e-9f;
240
241 decomposition.Reset();
242 decomposition.AddTriangleMesh(*trimesh);
243
244 decomposition.SetParameters(hacd_maxhullcount, hacd_maxhullmerge, hacd_maxhullvertexes, hacd_concavity,
245 hacd_smallclusterthreshold, hacd_fusetolerance);
246 decomposition.ComputeConvexDecomposition();
247
248 int hull_count = decomposition.GetHullCount();
249 std::vector<ChVector<double>> convexhull;
250 for (int c = 0; c < hull_count; c++) {
251 decomposition.GetConvexHullResult(c, convexhull);
252
253 body->GetCollisionModel()->AddConvexHull(material, convexhull, pos, rot);
254 if (!use_original_asset) {
255 std::stringstream ss;
256 ss << name << "_" << c;
257 auto trimesh_convex = chrono_types::make_shared<geometry::ChTriangleMeshConnected>();
258 if (!decomposition.GetConvexHullResult(c, *trimesh_convex))
259 return false;
260
261 auto trimesh_shape = chrono_types::make_shared<ChTriangleMeshShape>();
262 trimesh_shape->SetMesh(trimesh_convex);
263 trimesh_shape->SetName(ss.str());
264 trimesh_shape->Pos = ChVector<>(0, 0, 0);
265 trimesh_shape->Rot = ChQuaternion<>(1, 0, 0, 0);
266
267 body->GetAssets().push_back(trimesh_shape);
268 }
269 }
270
271 if (use_original_asset) {
272 auto trimesh_shape = chrono_types::make_shared<ChTriangleMeshShape>();
273 trimesh_shape->SetMesh(trimesh);
274 trimesh_shape->SetName(name);
275 trimesh_shape->Pos = ChVector<>(0, 0, 0);
276 trimesh_shape->Rot = ChQuaternion<>(1, 0, 0, 0);
277 body->GetAssets().push_back(trimesh_shape);
278 }
279
280 return true;
281 }
282
283 // -----------------------------------------------------------------------------
284
AddTriangleMeshConvexDecompositionV2(ChBody * body,std::shared_ptr<ChMaterialSurface> material,const std::string & obj_filename,const std::string & name,const ChVector<> & pos,const ChQuaternion<> & rot,bool use_original_asset)285 bool AddTriangleMeshConvexDecompositionV2(ChBody* body,
286 std::shared_ptr<ChMaterialSurface> material,
287 const std::string& obj_filename,
288 const std::string& name,
289 const ChVector<>& pos,
290 const ChQuaternion<>& rot,
291 bool use_original_asset) {
292 auto trimesh = chrono_types::make_shared<geometry::ChTriangleMeshConnected>();
293 if (!trimesh->LoadWavefrontMesh(obj_filename, true, false))
294 return false;
295
296 for (int i = 0; i < trimesh->m_vertices.size(); i++) {
297 trimesh->m_vertices[i] = pos + rot.Rotate(trimesh->m_vertices[i]);
298 }
299 collision::ChConvexDecompositionHACDv2 mydecompositionHACDv2;
300
301 int hacd_maxhullcount = 1024;
302 int hacd_maxhullmerge = 256;
303 int hacd_maxhullvertexes = 64;
304 double hacd_concavity = 0.01;
305 double hacd_smallclusterthreshold = 0.0;
306 double hacd_fusetolerance = 1e-6;
307
308 mydecompositionHACDv2.Reset();
309 mydecompositionHACDv2.AddTriangleMesh(*trimesh);
310
311 mydecompositionHACDv2.SetParameters(hacd_maxhullcount, hacd_maxhullmerge, hacd_maxhullvertexes,
312 (float)hacd_concavity, (float)hacd_smallclusterthreshold,
313 (float)hacd_fusetolerance);
314 mydecompositionHACDv2.ComputeConvexDecomposition();
315 collision::ChConvexDecomposition* used_decomposition = &mydecompositionHACDv2;
316
317 int hull_count = used_decomposition->GetHullCount();
318
319 for (int c = 0; c < hull_count; c++) {
320 std::vector<ChVector<double>> convexhull;
321 if (!used_decomposition->GetConvexHullResult(c, convexhull))
322 return false;
323
324 body->GetCollisionModel()->AddConvexHull(material, convexhull, pos, rot);
325 if (!use_original_asset) {
326 std::stringstream ss;
327 ss << name << "_" << c;
328 auto trimesh_convex = chrono_types::make_shared<geometry::ChTriangleMeshConnected>();
329 if (!used_decomposition->GetConvexHullResult(c, *trimesh_convex))
330 return false;
331
332 auto trimesh_shape = chrono_types::make_shared<ChTriangleMeshShape>();
333 trimesh_shape->SetMesh(trimesh_convex);
334 trimesh_shape->SetName(ss.str());
335 trimesh_shape->Pos = ChVector<>(0, 0, 0);
336 trimesh_shape->Rot = ChQuaternion<>(1, 0, 0, 0);
337 body->GetAssets().push_back(trimesh_shape);
338 }
339 }
340 if (use_original_asset) {
341 auto trimesh_shape = chrono_types::make_shared<ChTriangleMeshShape>();
342 trimesh_shape->SetMesh(trimesh);
343 trimesh_shape->SetName(name);
344 trimesh_shape->Pos = ChVector<>(0, 0, 0);
345 trimesh_shape->Rot = ChQuaternion<>(1, 0, 0, 0);
346 body->GetAssets().push_back(trimesh_shape);
347 }
348
349 return true;
350 }
351
352 // -----------------------------------------------------------------------------
353
354 //// TODO: extend this to also work for smooth (penalty) contact systems.
355
AddTriangleMeshConvexDecompositionSplit(ChSystem * system,std::shared_ptr<ChMaterialSurface> material,const std::string & obj_filename,const std::string & name,const ChVector<> & pos,const ChQuaternion<> & rot,double total_mass)356 bool AddTriangleMeshConvexDecompositionSplit(ChSystem* system,
357 std::shared_ptr<ChMaterialSurface> material,
358 const std::string& obj_filename,
359 const std::string& name,
360 const ChVector<>& pos,
361 const ChQuaternion<>& rot,
362 double total_mass) {
363 assert(material->GetContactMethod() == system->GetContactMethod());
364
365 geometry::ChTriangleMeshConnected trimesh;
366 if (!trimesh.LoadWavefrontMesh(obj_filename, true, false))
367 return false;
368
369 for (int i = 0; i < trimesh.m_vertices.size(); i++) {
370 trimesh.m_vertices[i] = pos + rot.Rotate(trimesh.m_vertices[i]);
371 }
372 collision::ChConvexDecompositionHACDv2 mydecompositionHACDv2;
373
374 int hacd_maxhullcount = 1024;
375 int hacd_maxhullmerge = 256;
376 int hacd_maxhullvertexes = 64;
377 double hacd_concavity = 0.01;
378 double hacd_smallclusterthreshold = 0.1;
379 double hacd_fusetolerance = 1e-6;
380
381 mydecompositionHACDv2.Reset();
382 mydecompositionHACDv2.AddTriangleMesh(trimesh);
383
384 mydecompositionHACDv2.SetParameters(hacd_maxhullcount, hacd_maxhullmerge, hacd_maxhullvertexes,
385 (float)hacd_concavity, (float)hacd_smallclusterthreshold,
386 (float)hacd_fusetolerance);
387 mydecompositionHACDv2.ComputeConvexDecomposition();
388 collision::ChConvexDecomposition* used_decomposition = &mydecompositionHACDv2;
389
390 int hull_count = used_decomposition->GetHullCount();
391
392 std::shared_ptr<ChBody> body;
393 double mass;
394 ChVector<> center;
395 ChMatrix33<> inertia;
396 double sum = 0;
397 for (int c = 0; c < hull_count; c++) {
398 geometry::ChTriangleMeshConnected trimesh_convex;
399 if (!used_decomposition->GetConvexHullResult(c, trimesh_convex))
400 return false;
401 trimesh_convex.ComputeMassProperties(true, mass, center, inertia);
402 sum += mass;
403 }
404
405 double scale = 1.0 / sum;
406
407 for (int c = 0; c < hull_count; c++) {
408 auto trimesh_convex = chrono_types::make_shared<geometry::ChTriangleMeshConnected>();
409 if (!used_decomposition->GetConvexHullResult(c, *trimesh_convex))
410 return false;
411 trimesh_convex->ComputeMassProperties(true, mass, center, inertia);
412
413 body = std::shared_ptr<ChBody>(system->NewBody());
414 body->SetMass(mass);
415 body->SetPos(pos);
416 body->SetRot(rot);
417 body->SetCollide(true);
418 body->SetBodyFixed(false);
419
420 std::vector<ChVector<double>> convexhull;
421 if (!used_decomposition->GetConvexHullResult(c, convexhull))
422 return false;
423 for (size_t v = 0; v < convexhull.size(); v++) {
424 convexhull[v] = convexhull[v] - center;
425 }
426
427 body->GetCollisionModel()->ClearModel();
428 body->GetCollisionModel()->AddConvexHull(material, convexhull, pos, rot);
429 body->GetCollisionModel()->BuildModel();
430
431 std::stringstream ss;
432 ss << name << "_" << c;
433 // geometry::ChTriangleMeshConnected trimesh_convex;
434 // used_decomposition->GetConvexHullResult(c, trimesh_convex);
435
436 auto trimesh_shape = chrono_types::make_shared<ChTriangleMeshShape>();
437 trimesh_shape->SetMesh(trimesh_convex);
438 trimesh_shape->SetName(ss.str());
439 trimesh_shape->Pos = -center;
440 trimesh_shape->Rot = ChQuaternion<>(1, 0, 0, 0);
441
442 body->GetAssets().push_back(trimesh_shape);
443
444 // std::cout << mass << " " << scale * mass* total_mass << " " <<
445 // inertia(0, 0) << " " << inertia(1, 1) << " " << inertia(2, 2) << std::endl;
446 body->SetInertiaXX(ChVector<>(inertia(0, 0) * scale * total_mass, inertia(1, 1) * scale * total_mass,
447 inertia(2, 2) * scale * total_mass));
448
449 system->AddBody(body);
450 }
451
452 return true;
453 }
454
455 // -----------------------------------------------------------------------------
456
AddTriangleGeometry(ChBody * body,std::shared_ptr<ChMaterialSurface> material,const ChVector<> & vertA,const ChVector<> & vertB,const ChVector<> & vertC,const std::string & name,const ChVector<> & pos,const ChQuaternion<> & rot,bool visualization)457 void AddTriangleGeometry(ChBody* body,
458 std::shared_ptr<ChMaterialSurface> material,
459 const ChVector<>& vertA,
460 const ChVector<>& vertB,
461 const ChVector<>& vertC,
462 const std::string& name,
463 const ChVector<>& pos,
464 const ChQuaternion<>& rot,
465 bool visualization) {
466 auto trimesh = chrono_types::make_shared<geometry::ChTriangleMeshConnected>();
467 trimesh->m_vertices.clear();
468 trimesh->m_face_v_indices.clear();
469 trimesh->m_vertices.push_back(vertA);
470 trimesh->m_vertices.push_back(vertB);
471 trimesh->m_vertices.push_back(vertC);
472 trimesh->m_face_v_indices.push_back(ChVector<int>(0, 1, 2));
473
474 for (int i = 0; i < trimesh->m_vertices.size(); i++)
475 trimesh->m_vertices[i] = pos + rot.Rotate(trimesh->m_vertices[i]);
476
477 body->GetCollisionModel()->AddTriangleMesh(material, trimesh, false, false);
478
479 if (visualization) {
480 auto trimesh_shape = chrono_types::make_shared<ChTriangleMeshShape>();
481 trimesh_shape->SetMesh(trimesh);
482 trimesh_shape->SetName(name);
483 trimesh_shape->Pos = ChVector<>(0, 0, 0);
484 trimesh_shape->Rot = ChQuaternion<>(1, 0, 0, 0);
485 body->GetAssets().push_back(trimesh_shape);
486 }
487 }
488
489 // -----------------------------------------------------------------------------
490
AddRoundedBoxGeometry(ChBody * body,std::shared_ptr<ChMaterialSurface> material,const ChVector<> & size,double srad,const ChVector<> & pos,const ChQuaternion<> & rot,bool visualization)491 void AddRoundedBoxGeometry(ChBody* body,
492 std::shared_ptr<ChMaterialSurface> material,
493 const ChVector<>& size,
494 double srad,
495 const ChVector<>& pos,
496 const ChQuaternion<>& rot,
497 bool visualization) {
498 body->GetCollisionModel()->AddRoundedBox(material, size.x(), size.y(), size.z(), srad, pos, rot);
499
500 if (visualization) {
501 auto box = chrono_types::make_shared<ChRoundedBoxShape>();
502 box->GetRoundedBoxGeometry().Size = size;
503 box->GetRoundedBoxGeometry().radsphere = srad;
504 box->Pos = pos;
505 box->Rot = rot;
506 body->GetAssets().push_back(box);
507 }
508 }
509
510 // -----------------------------------------------------------------------------
511
AddRoundedCylinderGeometry(ChBody * body,std::shared_ptr<ChMaterialSurface> material,double radius,double hlen,double srad,const ChVector<> & pos,const ChQuaternion<> & rot,bool visualization)512 void AddRoundedCylinderGeometry(ChBody* body,
513 std::shared_ptr<ChMaterialSurface> material,
514 double radius,
515 double hlen,
516 double srad,
517 const ChVector<>& pos,
518 const ChQuaternion<>& rot,
519 bool visualization) {
520 body->GetCollisionModel()->AddRoundedCylinder(material, radius, radius, hlen, srad, pos, rot);
521
522 if (visualization) {
523 auto rcyl = chrono_types::make_shared<ChRoundedCylinderShape>();
524 rcyl->GetRoundedCylinderGeometry().rad = radius;
525 rcyl->GetRoundedCylinderGeometry().hlen = hlen;
526 rcyl->GetRoundedCylinderGeometry().radsphere = srad;
527 rcyl->Pos = pos;
528 rcyl->Rot = rot;
529 body->GetAssets().push_back(rcyl);
530 }
531 }
532
533 // -----------------------------------------------------------------------------
534
AddTorusGeometry(ChBody * body,std::shared_ptr<ChMaterialSurface> material,double radius,double thickness,int segments,int angle,const ChVector<> & pos,const ChQuaternion<> & rot,bool visualization)535 void AddTorusGeometry(ChBody* body,
536 std::shared_ptr<ChMaterialSurface> material,
537 double radius,
538 double thickness,
539 int segments,
540 int angle,
541 const ChVector<>& pos,
542 const ChQuaternion<>& rot,
543 bool visualization) {
544 for (int i = 0; i < angle; i += angle / segments) {
545 double alpha = i * CH_C_PI / 180.0;
546 double x = cos(alpha) * radius;
547 double z = sin(alpha) * radius;
548 Quaternion q = chrono::Q_from_AngAxis(-alpha, VECT_Y) % chrono::Q_from_AngAxis(CH_C_PI / 2.0, VECT_X);
549 double outer_circ = 2 * CH_C_PI * (radius + thickness);
550
551 AddCapsuleGeometry(body, material, thickness, outer_circ / segments * .5, ChVector<>(x, 0, z) + pos, q,
552 visualization);
553 }
554 }
555
556 // -----------------------------------------------------------------------------
557 // CreateBoxContainer
558 //
559 // Create a fixed body with contact and asset geometry representing a box with 5
560 // walls (no top).
561 // -----------------------------------------------------------------------------
CreateBoxContainer(ChSystem * system,int id,std::shared_ptr<ChMaterialSurface> mat,const ChVector<> & hdim,double hthick,const ChVector<> & pos,const ChQuaternion<> & rot,bool collide,bool y_up,bool overlap,bool closed)562 std::shared_ptr<ChBody> CreateBoxContainer(ChSystem* system,
563 int id,
564 std::shared_ptr<ChMaterialSurface> mat,
565 const ChVector<>& hdim,
566 double hthick,
567 const ChVector<>& pos,
568 const ChQuaternion<>& rot,
569 bool collide,
570 bool y_up,
571 bool overlap,
572 bool closed) {
573 // Verify consistency of input arguments.
574 assert(mat->GetContactMethod() == system->GetContactMethod());
575
576 // Create the body and set material
577 std::shared_ptr<ChBody> body(system->NewBody());
578
579 // Set body properties and geometry.
580 body->SetIdentifier(id);
581 body->SetMass(1);
582 body->SetPos(pos);
583 body->SetRot(rot);
584 body->SetCollide(collide);
585 body->SetBodyFixed(true);
586 double o_lap = 0;
587 if (overlap) {
588 o_lap = hthick * 2;
589 }
590 body->GetCollisionModel()->ClearModel();
591 if (y_up) {
592 AddBoxGeometry(body.get(), mat, ChVector<>(hdim.x() + o_lap, hthick, hdim.y() + o_lap),
593 ChVector<>(0, -hthick, 0));
594 AddBoxGeometry(body.get(), mat, ChVector<>(hthick, hdim.z() + o_lap, hdim.y() + o_lap),
595 ChVector<>(-hdim.x() - hthick, hdim.z(), 0));
596 AddBoxGeometry(body.get(), mat, ChVector<>(hthick, hdim.z() + o_lap, hdim.y() + o_lap),
597 ChVector<>(hdim.x() + hthick, hdim.z(), 0));
598 AddBoxGeometry(body.get(), mat, ChVector<>(hdim.x() + o_lap, hdim.z() + o_lap, hthick),
599 ChVector<>(0, hdim.z(), -hdim.y() - hthick));
600 AddBoxGeometry(body.get(), mat, ChVector<>(hdim.x() + o_lap, hdim.z() + o_lap, hthick),
601 ChVector<>(0, hdim.z(), hdim.y() + hthick));
602 if (closed) {
603 AddBoxGeometry(body.get(), mat, ChVector<>(hdim.x() + o_lap, hthick, hdim.y() + o_lap),
604 ChVector<>(0, hdim.z() * 2 + hthick, 0));
605 }
606 } else {
607 AddBoxGeometry(body.get(), mat, ChVector<>(hdim.x() + o_lap, hdim.y() + o_lap, hthick),
608 ChVector<>(0, 0, -hthick));
609 AddBoxGeometry(body.get(), mat, ChVector<>(hthick, hdim.y() + o_lap, hdim.z() + o_lap),
610 ChVector<>(-hdim.x() - hthick, 0, hdim.z()));
611 AddBoxGeometry(body.get(), mat, ChVector<>(hthick, hdim.y() + o_lap, hdim.z() + o_lap),
612 ChVector<>(hdim.x() + hthick, 0, hdim.z()));
613 AddBoxGeometry(body.get(), mat, ChVector<>(hdim.x() + o_lap, hthick, hdim.z() + o_lap),
614 ChVector<>(0, -hdim.y() - hthick, hdim.z()));
615 AddBoxGeometry(body.get(), mat, ChVector<>(hdim.x() + o_lap, hthick, hdim.z() + o_lap),
616 ChVector<>(0, hdim.y() + hthick, hdim.z()));
617 if (closed) {
618 AddBoxGeometry(body.get(), mat, ChVector<>(hdim.x() + o_lap, hdim.y() + o_lap, hthick),
619 ChVector<>(0, 0, hdim.z() * 2 + hthick));
620 }
621 }
622 body->GetCollisionModel()->BuildModel();
623
624 // Attach the body to the system.
625 system->AddBody(body);
626 return body;
627 }
628
629 // -----------------------------------------------------------------------------
630 // CreateCylindricalContainerFromBoxes
631 //
632 // Create a fixed body with contact and asset geometry representing a cylindrical
633 // container with no top.
634 // hdim = (rad, rad, height) (the second and the third components are the same)
635 // by default, it is z_up
636 // -----------------------------------------------------------------------------
CreateCylindricalContainerFromBoxes(ChSystem * system,int id,std::shared_ptr<ChMaterialSurface> mat,const ChVector<> & hdim,double hthick,int numBoxes,const ChVector<> & pos,const ChQuaternion<> & rot,bool collide,bool overlap,bool closed,bool isBoxBase,bool partialVisualization)637 std::shared_ptr<ChBody> CreateCylindricalContainerFromBoxes(ChSystem* system,
638 int id,
639 std::shared_ptr<ChMaterialSurface> mat,
640 const ChVector<>& hdim,
641 double hthick,
642 int numBoxes,
643 const ChVector<>& pos,
644 const ChQuaternion<>& rot,
645 bool collide,
646 bool overlap,
647 bool closed,
648 bool isBoxBase,
649 bool partialVisualization) {
650 // Verify consistency of input arguments.
651 assert(mat->GetContactMethod() == system->GetContactMethod());
652
653 // Create the body and set material
654 std::shared_ptr<ChBody> body(system->NewBody());
655
656 // Set body properties and geometry.
657 body->SetIdentifier(id);
658 // body->SetMass(1);
659 body->SetPos(pos);
660 body->SetRot(rot);
661 body->SetCollide(collide);
662 body->SetBodyFixed(true);
663
664 double box_side = hdim.x() * 2.0 * tan(CH_C_PI / numBoxes); // side length of cyl
665 double o_lap = 0;
666 if (overlap) {
667 o_lap = hthick * 2;
668 }
669 double ang = 2.0 * CH_C_PI / numBoxes;
670 ChVector<> p_boxSize = ChVector<>((box_side + hthick) / 2.0, hthick, hdim.z() + o_lap); // size of plates
671 ChVector<> p_pos; // position of each plate
672 ChQuaternion<> p_quat = QUNIT; // rotation of each plate
673 body->GetCollisionModel()->ClearModel();
674
675 for (int i = 0; i < numBoxes; i++) {
676 p_pos = pos + ChVector<>(sin(ang * i) * (hthick + hdim.x()), cos(ang * i) * (hthick + hdim.x()), hdim.z());
677
678 p_quat = Angle_to_Quat(AngleSet::RXYZ, ChVector<>(0, 0, ang * i));
679
680 // this is here to make half the cylinder invisible.
681 bool m_visualization = true;
682 if ((ang * i > CH_C_PI && ang * i < 3.0 * CH_C_PI / 2.0) && partialVisualization) {
683 m_visualization = false;
684 }
685 utils::AddBoxGeometry(body.get(), mat, p_boxSize, p_pos, p_quat, m_visualization);
686 }
687
688 // Add ground piece
689 if (isBoxBase) {
690 utils::AddBoxGeometry(body.get(), mat, Vector(hdim.x() + 2 * hthick, hdim.x() + 2 * hthick, hthick),
691 Vector(0, 0, -hthick), QUNIT, true);
692 } else {
693 utils::AddCylinderGeometry(body.get(), mat, hdim.x() + 2 * hthick, hthick, ChVector<>(0, 0, -hthick),
694 Q_from_AngAxis(CH_C_PI / 2, VECT_X));
695 }
696
697 if (closed) {
698 if (isBoxBase) {
699 utils::AddBoxGeometry(body.get(), mat, Vector(hdim.x() + 2 * hthick, hdim.x() + 2 * hthick, hthick),
700 Vector(0, 0, 2 * hdim.z() + hthick), QUNIT, true);
701 } else {
702 utils::AddCylinderGeometry(body.get(), mat, hdim.x() + 2 * hthick, hthick,
703 ChVector<>(0, 0, 2 * hdim.z() + hthick), Q_from_AngAxis(CH_C_PI / 2, VECT_X));
704 }
705 }
706
707 body->GetCollisionModel()->SetEnvelope(0.2 * hthick);
708 body->GetCollisionModel()->BuildModel();
709
710 system->AddBody(body);
711 return body;
712 }
713
714 // -----------------------------------------------------------------------------
715
LoadConvexMesh(const std::string & file_name,ChTriangleMeshConnected & convex_mesh,ChConvexDecompositionHACDv2 & convex_shape,const ChVector<> & pos,const ChQuaternion<> & rot,int hacd_maxhullcount,int hacd_maxhullmerge,int hacd_maxhullvertexes,float hacd_concavity,float hacd_smallclusterthreshold,float hacd_fusetolerance)716 bool LoadConvexMesh(const std::string& file_name,
717 ChTriangleMeshConnected& convex_mesh,
718 ChConvexDecompositionHACDv2& convex_shape,
719 const ChVector<>& pos,
720 const ChQuaternion<>& rot,
721 int hacd_maxhullcount,
722 int hacd_maxhullmerge,
723 int hacd_maxhullvertexes,
724 float hacd_concavity,
725 float hacd_smallclusterthreshold,
726 float hacd_fusetolerance) {
727 if(!convex_mesh.LoadWavefrontMesh(file_name, true, false))
728 return false;
729
730 for (int i = 0; i < convex_mesh.m_vertices.size(); i++) {
731 convex_mesh.m_vertices[i] = pos + rot.Rotate(convex_mesh.m_vertices[i]);
732 }
733
734 convex_shape.Reset();
735 convex_shape.AddTriangleMesh(convex_mesh);
736 convex_shape.SetParameters(hacd_maxhullcount, hacd_maxhullmerge, hacd_maxhullvertexes, hacd_concavity,
737 hacd_smallclusterthreshold, hacd_fusetolerance);
738 convex_shape.ComputeConvexDecomposition();
739
740 return true;
741 }
742
743 // -----------------------------------------------------------------------------
LoadConvexHulls(const std::string & file_name,geometry::ChTriangleMeshConnected & convex_mesh,std::vector<std::vector<ChVector<double>>> & convex_hulls)744 bool LoadConvexHulls(const std::string& file_name,
745 geometry::ChTriangleMeshConnected& convex_mesh,
746 std::vector<std::vector<ChVector<double>>>& convex_hulls) {
747 convex_mesh.LoadWavefrontMesh(file_name, true, false);
748
749 std::vector<tinyobj::shape_t> shapes;
750 tinyobj::attrib_t att;
751 std::vector<tinyobj::material_t> materials;
752 std::string warn;
753 std::string err;
754
755 if (!tinyobj::LoadObj(&att, &shapes, &materials, &warn, &err, file_name.c_str()))
756 return false;
757
758 convex_hulls.resize(shapes.size());
759
760 for (size_t i = 0; i < shapes.size(); i++) {
761 convex_hulls[i].clear();
762
763 // hold onto unique ids temporarily
764 std::vector<int> ids;
765
766 for (int j = 0; j < shapes[i].mesh.indices.size(); j++) {
767 int id = shapes[i].mesh.indices[j].vertex_index;
768
769 // if vertex not already added, add new vertex
770 if (std::find(ids.begin(), ids.end(), id) == ids.end()) {
771 ChVector<double> pos(att.vertices[id * 3 + 0], //
772 att.vertices[id * 3 + 1], //
773 att.vertices[id * 3 + 2]);
774 convex_hulls[i].push_back(pos);
775 ids.push_back(id);
776 }
777 }
778 }
779
780 return true;
781 }
782 // -----------------------------------------------------------------------------
783
AddConvexCollisionModel(std::shared_ptr<ChBody> body,std::shared_ptr<ChMaterialSurface> material,std::shared_ptr<ChTriangleMeshConnected> convex_mesh,ChConvexDecompositionHACDv2 & convex_shape,const ChVector<> & pos,const ChQuaternion<> & rot,bool use_original_asset)784 void AddConvexCollisionModel(std::shared_ptr<ChBody> body,
785 std::shared_ptr<ChMaterialSurface> material,
786 std::shared_ptr<ChTriangleMeshConnected> convex_mesh,
787 ChConvexDecompositionHACDv2& convex_shape,
788 const ChVector<>& pos,
789 const ChQuaternion<>& rot,
790 bool use_original_asset) {
791 ChConvexDecomposition* used_decomposition = &convex_shape;
792
793 int hull_count = used_decomposition->GetHullCount();
794
795 for (int c = 0; c < hull_count; c++) {
796 std::vector<ChVector<double>> convexhull;
797 used_decomposition->GetConvexHullResult(c, convexhull);
798
799 body->GetCollisionModel()->AddConvexHull(material, convexhull, pos, rot);
800 // Add each convex chunk as a new asset
801 if (!use_original_asset) {
802 std::stringstream ss;
803 ss << convex_mesh->GetFileName() << "_" << c;
804 auto trimesh_convex = chrono_types::make_shared<geometry::ChTriangleMeshConnected>();
805 used_decomposition->GetConvexHullResult(c, *trimesh_convex);
806
807 auto trimesh_shape = chrono_types::make_shared<ChTriangleMeshShape>();
808 trimesh_shape->SetMesh(trimesh_convex);
809 trimesh_shape->SetName(ss.str());
810 trimesh_shape->Pos = pos;
811 trimesh_shape->Rot = rot;
812 body->GetAssets().push_back(trimesh_shape);
813 }
814 }
815 // Add the original triangle mesh as asset
816 if (use_original_asset) {
817 auto trimesh_shape = chrono_types::make_shared<ChTriangleMeshShape>();
818 trimesh_shape->SetMesh(convex_mesh);
819 trimesh_shape->SetName(convex_mesh->GetFileName());
820 trimesh_shape->Pos = VNULL;
821 trimesh_shape->Rot = QUNIT;
822 body->GetAssets().push_back(trimesh_shape);
823 }
824 }
825
826 // -----------------------------------------------------------------------------
827
AddConvexCollisionModel(std::shared_ptr<ChBody> body,std::shared_ptr<ChMaterialSurface> material,std::shared_ptr<ChTriangleMeshConnected> convex_mesh,std::vector<std::vector<ChVector<double>>> & convex_hulls,const ChVector<> & pos,const ChQuaternion<> & rot)828 void AddConvexCollisionModel(std::shared_ptr<ChBody> body,
829 std::shared_ptr<ChMaterialSurface> material,
830 std::shared_ptr<ChTriangleMeshConnected> convex_mesh,
831 std::vector<std::vector<ChVector<double>>>& convex_hulls,
832 const ChVector<>& pos,
833 const ChQuaternion<>& rot) {
834 for (int c = 0; c < convex_hulls.size(); c++) {
835 body->GetCollisionModel()->AddConvexHull(material, convex_hulls[c], pos, rot);
836 }
837 // Add the original triangle mesh as asset
838 auto trimesh_shape = chrono_types::make_shared<ChTriangleMeshShape>();
839 trimesh_shape->SetMesh(convex_mesh);
840 trimesh_shape->SetName(convex_mesh->GetFileName());
841 trimesh_shape->Pos = pos;
842 trimesh_shape->Rot = rot;
843 body->GetAssets().push_back(trimesh_shape);
844 }
845
846 } // namespace utils
847 } // namespace chrono
848