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