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: Hammad Mazhar
13 // =============================================================================
14 //
15 // Demo code about advanced contact feature: cohesion (using complementarity
16 // contact method)
17 //
18 // =============================================================================
19 
20 #ifdef __EMSCRIPTEN__
21 #include <emscripten.h>
22 #endif
23 
24 #include "chrono/physics/ChBodyEasy.h"
25 #include "chrono/physics/ChLinkMotorRotationSpeed.h"
26 #include "chrono/physics/ChSystemNSC.h"
27 #include "chrono_opengl/ChOpenGLWindow.h"
28 
29 // Use the namespace of Chrono
30 
31 using namespace chrono;
32 using namespace chrono::collision;
33 
34 // Static values valid through the entire program (bad
35 // programming practice, but enough for quick tests)
36 
37 float GLOBAL_friction = 0.3f;
38 float GLOBAL_cohesion = 0;
39 float GLOBAL_compliance = 0;
40 float GLOBAL_dampingf = 0.1f;
41 
42 // Define a MyEventReceiver class which will be used to manage input
43 // from the GUI graphical user interface
44 
create_some_falling_items(ChSystemNSC & mphysicalSystem)45 void create_some_falling_items(ChSystemNSC& mphysicalSystem) {
46     // From now on, all created collision models will have a large outward envelope (needed
47     // to allow some compliance with the plastic deformation of cohesive bounds
48     ChCollisionModel::SetDefaultSuggestedEnvelope(0.3);
49 
50     // contact material shared by all falling objects
51     auto mat = chrono_types::make_shared<ChMaterialSurfaceNSC>();
52     mat->SetFriction(0.3f);
53 
54     // Create falling bodies
55     for (int bi = 0; bi < 400; bi++) {
56         auto mrigidBody = chrono_types::make_shared<ChBodyEasySphere>(0.81,  // radius
57                                                                       1000,  // density
58                                                                       true,  // visualization?
59                                                                       true,  // collision?
60                                                                       mat);  // contact material
61         mrigidBody->SetPos(ChVector<>(-5 + ChRandom() * 10, 4 + bi * 0.05, -5 + ChRandom() * 10));
62         mphysicalSystem.Add(mrigidBody);
63     }
64 
65     // Create the five walls of the rectangular container, using fixed rigid bodies of 'box' type:
66 
67     auto floor_mat = chrono_types::make_shared<ChMaterialSurfaceNSC>();
68 
69     auto floorBody = chrono_types::make_shared<ChBodyEasyBox>(20, 1, 20,   // x,y,z size
70                                                               1000,        // density
71                                                               true,        // visualization?
72                                                               true,        // collision?
73                                                               floor_mat);  // contact material
74     floorBody->SetPos(ChVector<>(0, -5, 0));
75     floorBody->SetBodyFixed(true);
76     mphysicalSystem.Add(floorBody);
77 
78     auto wallBody1 = chrono_types::make_shared<ChBodyEasyBox>(1, 10, 20.99,  // x,y,z size
79                                                               1000,          // density
80                                                               true,          // visualization?
81                                                               true,          // collision?
82                                                               floor_mat);    // contact material
83     wallBody1->SetPos(ChVector<>(-10, 0, 0));
84     wallBody1->SetBodyFixed(true);
85     mphysicalSystem.Add(wallBody1);
86 
87     auto wallBody2 = chrono_types::make_shared<ChBodyEasyBox>(1, 10, 20.99,  // x,y,z size
88                                                               1000,          // density
89                                                               true,          // visualization?
90                                                               true,          // collision?
91                                                               floor_mat);    // contact material
92     wallBody2->SetPos(ChVector<>(10, 0, 0));
93     wallBody2->SetBodyFixed(true);
94     mphysicalSystem.Add(wallBody2);
95 
96     auto wallBody3 = chrono_types::make_shared<ChBodyEasyBox>(20.99, 10, 1,  // x,y,z size
97                                                               1000,          // density
98                                                               true,          // visualization?
99                                                               true,          // collision?
100                                                               floor_mat);    // contact material
101     wallBody3->SetPos(ChVector<>(0, 0, -10));
102     wallBody3->SetBodyFixed(true);
103     mphysicalSystem.Add(wallBody3);
104 
105     auto wallBody4 = chrono_types::make_shared<ChBodyEasyBox>(20.99, 10, 1,  // x,y,z size
106                                                               1000,          // density
107                                                               true,          // visualization?
108                                                               true,          // collision?
109                                                               floor_mat);    // contact material
110     wallBody4->SetPos(ChVector<>(0, 0, 10));
111     wallBody4->SetBodyFixed(true);
112     mphysicalSystem.Add(wallBody4);
113 
114     // Add the rotating mixer
115     auto mixer_mat = chrono_types::make_shared<ChMaterialSurfaceNSC>();
116     mixer_mat->SetFriction(0.4f);
117 
118     auto rotatingBody = chrono_types::make_shared<ChBodyEasyBox>(10, 5, 1,    // x,y,z size
119                                                                  4000,        // density
120                                                                  true,        // visualization?
121                                                                  true,        // collision?
122                                                                  mixer_mat);  // contact material
123     rotatingBody->SetPos(ChVector<>(0, -1.6, 0));
124     mphysicalSystem.Add(rotatingBody);
125 
126     // .. a motor between mixer and truss
127     auto motor = chrono_types::make_shared<ChLinkMotorRotationSpeed>();
128     motor->Initialize(rotatingBody, floorBody, ChFrame<>(ChVector<>(0, 0, 0), Q_from_AngAxis(CH_C_PI_2, VECT_X)));
129     motor->SetSpeedFunction(chrono_types::make_shared<ChFunction_Const>(CH_C_PI / 2.0));
130     mphysicalSystem.AddLink(motor);
131 }
132 
main(int argc,char * argv[])133 int main(int argc, char* argv[]) {
134     GetLog() << "Copyright (c) 2017 projectchrono.org\nChrono version: " << CHRONO_VERSION << "\n\n";
135 
136     // Create a Chrono physical system
137     ChSystemNSC mphysicalSystem;
138 
139     // Create all the rigid bodies.
140 
141     create_some_falling_items(mphysicalSystem);
142 
143     // Modify some setting of the physical system for the simulation, if you want
144 
145     mphysicalSystem.SetSolverType(ChSolver::Type::PSOR);
146     mphysicalSystem.SetSolverMaxIterations(20);
147 
148     // Cohesion in a contact depends on the cohesion in the surface property of
149     // the touching bodies, but the user can override this value when each contact is created,
150     // by instancing a callback as in the following example:
151 
152     class MyContactCallback : public ChContactContainer::AddContactCallback {
153       public:
154         virtual void OnAddContact(const collision::ChCollisionInfo& contactinfo,
155                                   ChMaterialComposite* const material) override {
156             // Downcast to appropriate composite material type
157             auto mat = static_cast<ChMaterialCompositeNSC* const>(material);
158 
159             // Set friction according to user setting:
160             mat->static_friction = GLOBAL_friction;
161 
162             // Set compliance (normal and tangential at once)
163             mat->compliance = GLOBAL_compliance;
164             mat->complianceT = GLOBAL_compliance;
165             mat->dampingf = GLOBAL_dampingf;
166 
167             // Set cohesion according to user setting:
168             // Note that we must scale the cohesion force value by time step, because
169             // the material 'cohesion' value has the dimension of an impulse.
170             float my_cohesion_force = GLOBAL_cohesion;
171             mat->cohesion = (float)msystem->GetStep() * my_cohesion_force;  //<- all contacts will have this cohesion!
172 
173             if (contactinfo.distance > 0.12)
174                 mat->cohesion = 0;
175 
176             // Note that here you might decide to modify the cohesion
177             // depending on object sizes, type, time, position, etc. etc.
178             // For example, after some time disable cohesion at all, just
179             // add here:
180             //    if (msystem->GetChTime() > 10) mat->cohesion = 0;
181         };
182         ChSystemNSC* msystem;
183     };
184 
185     auto mycontact_callback = chrono_types::make_shared<MyContactCallback>();  // create the callback object
186     mycontact_callback->msystem = &mphysicalSystem;                            // will be used by callback
187 
188     // Use the above callback to process each contact as it is created.
189     mphysicalSystem.GetContactContainer()->RegisterAddContactCallback(mycontact_callback);
190 
191     //
192     // THE SOFT-REAL-TIME CYCLE
193     //
194 
195     opengl::ChOpenGLWindow& gl_window = opengl::ChOpenGLWindow::getInstance();
196     gl_window.Initialize(1280, 720, "Demo_Cohesion_GL", &mphysicalSystem);
197     gl_window.SetCamera(ChVector<>(0, 0, -10), ChVector<>(0, 0, 0), ChVector<>(0, 1, 0));
198     gl_window.Pause();
199 
200     std::function<void()> step_iter = [&]() {
201         if (gl_window.DoStepDynamics(0.01)) {
202             // Add code here that will only run after a step is taken
203         }
204         gl_window.Render();
205     };
206 
207 #ifdef __EMSCRIPTEN__
208     emscripten_set_main_loop_arg(&opengl::ChOpenGLWindow::WrapRenderStep, (void*)&step_iter, 50, true);
209 #else
210     while (gl_window.Active()) {
211         step_iter();
212     }
213 #endif
214 
215     return 0;
216 }
217